All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Yaniv Gardi" <ygardi@codeaurora.org>
To: 'Dolev Raviv' <draviv@codeaurora.org>
Cc: 'Vinayak Holikatti' <vinholikatti@gmail.com>,
	'Santosh Y' <santoshsy@gmail.com>,
	"'James E.J. Bottomley'" <jbottomley@parallels.com>,
	linux-scsi@vger.kernel.org,
	'Sujit Reddy Thumma' <sthumma@codeaurora.org>,
	linux-arm-msm@vger.kernel.org
Subject: RE: [PATCH V5 1/4] scsi: ufs: Fix broken task management command implementation
Date: Tue, 13 Aug 2013 17:57:55 +0300	[thread overview]
Message-ID: <006f01ce9835$7fea8e50$7fbfaaf0$@codeaurora.org> (raw)
In-Reply-To: <15d1232c76204bd3d9e7131a3371a1bc.squirrel@www.codeaurora.org>

Reviewed-by: Yaniv Gardi <ygardi@codeaurora.org>

QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation


= > -----Original Message-----
= > From: linux-scsi-owner@vger.kernel.org [mailto:linux-scsi-
= > owner@vger.kernel.org] On Behalf Of Dolev Raviv
= > Sent: Monday, August 12, 2013 4:01 PM
= > To: Sujit Reddy Thumma
= > Cc: Vinayak Holikatti; Santosh Y; James E.J. Bottomley; linux-
= > scsi@vger.kernel.org; Sujit Reddy Thumma; linux-arm-
= > msm@vger.kernel.org
= > Subject: Re: [PATCH V5 1/4] scsi: ufs: Fix broken task management
= > command implementation
= > 
= > Tested-by: Dolev Raviv <draviv@codeaurora.org>
= > 
= > > Currently, sending Task Management (TM) command to the card might
= > be
= > > broken in some scenarios as listed below:
= > >
= > > Problem: If there are more than 8 TM commands the implementation
= > >          returns error to the caller.
= > > Fix:     Wait for one of the slots to be emptied and send the command.
= > >
= > > Problem: Sometimes it is necessary for the caller to know the TM
service
= > >          response code to determine the task status.
= > > Fix:     Propogate the service response to the caller.
= > >
= > > Problem: If the TM command times out no proper error recovery is
= > >          implemented.
= > > Fix:     Clear the command in the controller door-bell register, so
that
= > >          further commands for the same slot don't fail.
= > >
= > > Problem: While preparing the TM command descriptor, the task tag used
= > >          should be unique across SCSI/NOP/QUERY/TM commands and not
= > the
= > > 	 task tag of the command which the TM command is trying to
= > manage.
= > > Fix:     Use a unique task tag instead of task tag of SCSI command.
= > >
= > > Problem: Since the TM command involves H/W communication, abruptly
= > ending
= > >          the request on kill interrupt signal might cause h/w
malfunction.
= > > Fix:     Wait for hardware completion interrupt with
= > TASK_UNINTERRUPTIBLE
= > >          set.
= > >
= > > Signed-off-by: Sujit Reddy Thumma <sthumma@codeaurora.org>
= > > ---
= > >  drivers/scsi/ufs/ufshcd.c |  173
= > > ++++++++++++++++++++++++++++++---------------
= > >  drivers/scsi/ufs/ufshcd.h |    8 ++-
= > >  2 files changed, 122 insertions(+), 59 deletions(-)
= > >
= > > diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
= > > index b36ca9a..d7f3746 100644
= > > --- a/drivers/scsi/ufs/ufshcd.c
= > > +++ b/drivers/scsi/ufs/ufshcd.c
= > > @@ -53,6 +53,9 @@
= > >  /* Query request timeout */
= > >  #define QUERY_REQ_TIMEOUT 30 /* msec */
= > >
= > > +/* Task management command timeout */
= > > +#define TM_CMD_TIMEOUT	100 /* msecs */
= > > +
= > >  /* Expose the flag value from utp_upiu_query.value */  #define
= > > MASK_QUERY_UPIU_FLAG_LOC 0xFF
= > >
= > > @@ -183,13 +186,35 @@ ufshcd_get_tmr_ocs(struct utp_task_req_desc
= > > *task_req_descp)
= > >  /**
= > >   * ufshcd_get_tm_free_slot - get a free slot for task management
= > request
= > >   * @hba: per adapter instance
= > > + * @free_slot: pointer to variable with available slot value
= > >   *
= > > - * Returns maximum number of task management request slots in case
= > of
= > > - * task management queue full or returns the free slot number
= > > + * Get a free tag and lock it until ufshcd_put_tm_slot() is called.
= > > + * Returns 0 if free slot is not available, else return 1 with tag
= > > + value
= > > + * in @free_slot.
= > >   */
= > > -static inline int ufshcd_get_tm_free_slot(struct ufs_hba *hba)
= > > +static bool ufshcd_get_tm_free_slot(struct ufs_hba *hba, int
= > > +*free_slot)
= > >  {
= > > -	return find_first_zero_bit(&hba->outstanding_tasks, hba->nutmrs);
= > > +	int tag;
= > > +	bool ret = false;
= > > +
= > > +	if (!free_slot)
= > > +		goto out;
= > > +
= > > +	do {
= > > +		tag = find_first_zero_bit(&hba->tm_slots_in_use, hba-
= > >nutmrs);
= > > +		if (tag >= hba->nutmrs)
= > > +			goto out;
= > > +	} while (test_and_set_bit_lock(tag, &hba->tm_slots_in_use));
= > > +
= > > +	*free_slot = tag;
= > > +	ret = true;
= > > +out:
= > > +	return ret;
= > > +}
= > > +
= > > +static inline void ufshcd_put_tm_slot(struct ufs_hba *hba, int slot)
= > > +{
= > > +	clear_bit_unlock(slot, &hba->tm_slots_in_use);
= > >  }
= > >
= > >  /**
= > > @@ -1700,10 +1725,11 @@ static void ufshcd_slave_destroy(struct
= > > scsi_device *sdev)
= > >   * ufshcd_task_req_compl - handle task management request
= > completion
= > >   * @hba: per adapter instance
= > >   * @index: index of the completed request
= > > + * @resp: task management service response
= > >   *
= > > - * Returns SUCCESS/FAILED
= > > + * Returns non-zero value on error, zero on success
= > >   */
= > > -static int ufshcd_task_req_compl(struct ufs_hba *hba, u32 index)
= > > +static int ufshcd_task_req_compl(struct ufs_hba *hba, u32 index, u8
= > > *resp)
= > >  {
= > >  	struct utp_task_req_desc *task_req_descp;
= > >  	struct utp_upiu_task_rsp *task_rsp_upiup; @@ -1724,19 +1750,15
= > @@
= > > static int ufshcd_task_req_compl(struct ufs_hba *hba, u32 index)
= > >  				task_req_descp[index].task_rsp_upiu;
= > >  		task_result = be32_to_cpu(task_rsp_upiup-
= > >header.dword_1);
= > >  		task_result = ((task_result & MASK_TASK_RESPONSE) >> 8);
= > > -
= > > -		if (task_result !=
= > UPIU_TASK_MANAGEMENT_FUNC_COMPL &&
= > > -		    task_result !=
= > UPIU_TASK_MANAGEMENT_FUNC_SUCCEEDED)
= > > -			task_result = FAILED;
= > > -		else
= > > -			task_result = SUCCESS;
= > > +		if (resp)
= > > +			*resp = (u8)task_result;
= > >  	} else {
= > > -		task_result = FAILED;
= > > -		dev_err(hba->dev,
= > > -			"trc: Invalid ocs = %x\n", ocs_value);
= > > +		dev_err(hba->dev, "%s: failed, ocs = 0x%x\n",
= > > +				__func__, ocs_value);
= > >  	}
= > >  	spin_unlock_irqrestore(hba->host->host_lock, flags);
= > > -	return task_result;
= > > +
= > > +	return ocs_value;
= > >  }
= > >
= > >  /**
= > > @@ -2237,7 +2259,7 @@ static void ufshcd_tmc_handler(struct ufs_hba
= > > *hba)
= > >
= > >  	tm_doorbell = ufshcd_readl(hba,
= > REG_UTP_TASK_REQ_DOOR_BELL);
= > >  	hba->tm_condition = tm_doorbell ^ hba->outstanding_tasks;
= > > -	wake_up_interruptible(&hba->ufshcd_tm_wait_queue);
= > > +	wake_up(&hba->tm_wq);
= > >  }
= > >
= > >  /**
= > > @@ -2287,38 +2309,58 @@ static irqreturn_t ufshcd_intr(int irq, void
= > > *__hba)
= > >  	return retval;
= > >  }
= > >
= > > +static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag) {
= > > +	int err = 0;
= > > +	u32 mask = 1 << tag;
= > > +	unsigned long flags;
= > > +
= > > +	if (!test_bit(tag, &hba->outstanding_reqs))
= > > +		goto out;
= > > +
= > > +	spin_lock_irqsave(hba->host->host_lock, flags);
= > > +	ufshcd_writel(hba, ~(1 << tag), REG_UTP_TASK_REQ_LIST_CLEAR);
= > > +	spin_unlock_irqrestore(hba->host->host_lock, flags);
= > > +
= > > +	/* poll for max. 1 sec to clear door bell register by h/w */
= > > +	err = ufshcd_wait_for_register(hba,
= > > +			REG_UTP_TASK_REQ_DOOR_BELL,
= > > +			mask, 0, 1000, 1000);
= > > +out:
= > > +	return err;
= > > +}
= > > +
= > >  /**
= > >   * ufshcd_issue_tm_cmd - issues task management commands to
= > controller
= > >   * @hba: per adapter instance
= > > - * @lrbp: pointer to local reference block
= > > + * @lun_id: LUN ID to which TM command is sent
= > > + * @task_id: task ID to which the TM command is applicable
= > > + * @tm_function: task management function opcode
= > > + * @tm_response: task management service response return value
= > >   *
= > > - * Returns SUCCESS/FAILED
= > > + * Returns non-zero value on error, zero on success.
= > >   */
= > > -static int
= > > -ufshcd_issue_tm_cmd(struct ufs_hba *hba,
= > > -		    struct ufshcd_lrb *lrbp,
= > > -		    u8 tm_function)
= > > +static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int
= > > task_id,
= > > +		u8 tm_function, u8 *tm_response)
= > >  {
= > >  	struct utp_task_req_desc *task_req_descp;
= > >  	struct utp_upiu_task_req *task_req_upiup;
= > >  	struct Scsi_Host *host;
= > >  	unsigned long flags;
= > > -	int free_slot = 0;
= > > +	int free_slot;
= > >  	int err;
= > > +	int task_tag;
= > >
= > >  	host = hba->host;
= > >
= > > -	spin_lock_irqsave(host->host_lock, flags);
= > > -
= > > -	/* If task management queue is full */
= > > -	free_slot = ufshcd_get_tm_free_slot(hba);
= > > -	if (free_slot >= hba->nutmrs) {
= > > -		spin_unlock_irqrestore(host->host_lock, flags);
= > > -		dev_err(hba->dev, "Task management queue full\n");
= > > -		err = FAILED;
= > > -		goto out;
= > > -	}
= > > +	/*
= > > +	 * Get free slot, sleep if slots are unavailable.
= > > +	 * Even though we use wait_event() which sleeps indefinitely,
= > > +	 * the maximum wait time is bounded by %TM_CMD_TIMEOUT.
= > > +	 */
= > > +	wait_event(hba->tm_tag_wq, ufshcd_get_tm_free_slot(hba,
= > > +&free_slot));
= > >
= > > +	spin_lock_irqsave(host->host_lock, flags);
= > >  	task_req_descp = hba->utmrdl_base_addr;
= > >  	task_req_descp += free_slot;
= > >
= > > @@ -2330,18 +2372,15 @@ ufshcd_issue_tm_cmd(struct ufs_hba *hba,
= > >  	/* Configure task request UPIU */
= > >  	task_req_upiup =
= > >  		(struct utp_upiu_task_req *) task_req_descp-
= > >task_req_upiu;
= > > +	task_tag = hba->nutrs + free_slot;
= > >  	task_req_upiup->header.dword_0 =
= > >  		UPIU_HEADER_DWORD(UPIU_TRANSACTION_TASK_REQ,
= > 0,
= > > -					      lrbp->lun, lrbp->task_tag);
= > > +				lun_id, task_tag);
= > >  	task_req_upiup->header.dword_1 =
= > >  		UPIU_HEADER_DWORD(0, tm_function, 0, 0);
= > >
= > > -	task_req_upiup->input_param1 = lrbp->lun;
= > > -	task_req_upiup->input_param1 =
= > > -		cpu_to_be32(task_req_upiup->input_param1);
= > > -	task_req_upiup->input_param2 = lrbp->task_tag;
= > > -	task_req_upiup->input_param2 =
= > > -		cpu_to_be32(task_req_upiup->input_param2);
= > > +	task_req_upiup->input_param1 = cpu_to_be32(lun_id);
= > > +	task_req_upiup->input_param2 = cpu_to_be32(task_id);
= > >
= > >  	/* send command to the controller */
= > >  	__set_bit(free_slot, &hba->outstanding_tasks); @@ -2350,20
= > +2389,24
= > > @@ ufshcd_issue_tm_cmd(struct ufs_hba *hba,
= > >  	spin_unlock_irqrestore(host->host_lock, flags);
= > >
= > >  	/* wait until the task management command is completed */
= > > -	err =
= > > -	wait_event_interruptible_timeout(hba->ufshcd_tm_wait_queue,
= > > -					 (test_bit(free_slot,
= > > -					 &hba->tm_condition) != 0),
= > > -					 60 * HZ);
= > > +	err = wait_event_timeout(hba->tm_wq,
= > > +			test_bit(free_slot, &hba->tm_condition),
= > > +			msecs_to_jiffies(TM_CMD_TIMEOUT));
= > >  	if (!err) {
= > > -		dev_err(hba->dev,
= > > -			"Task management command timed-out\n");
= > > -		err = FAILED;
= > > -		goto out;
= > > +		dev_err(hba->dev, "%s: task management cmd 0x%.2x
= > timed-out\n",
= > > +				__func__, tm_function);
= > > +		if (ufshcd_clear_tm_cmd(hba, free_slot))
= > > +			dev_WARN(hba->dev, "%s: unable clear tm cmd
= > (slot %d) after
= > > timeout\n",
= > > +					__func__, free_slot);
= > > +		err = -ETIMEDOUT;
= > > +	} else {
= > > +		err = ufshcd_task_req_compl(hba, free_slot,
= > tm_response);
= > >  	}
= > > +
= > >  	clear_bit(free_slot, &hba->tm_condition);
= > > -	err = ufshcd_task_req_compl(hba, free_slot);
= > > -out:
= > > +	ufshcd_put_tm_slot(hba, free_slot);
= > > +	wake_up(&hba->tm_tag_wq);
= > > +
= > >  	return err;
= > >  }
= > >
= > > @@ -2380,14 +2423,21 @@ static int ufshcd_device_reset(struct
= > > scsi_cmnd
= > > *cmd)
= > >  	unsigned int tag;
= > >  	u32 pos;
= > >  	int err;
= > > +	u8 resp = 0xF;
= > > +	struct ufshcd_lrb *lrbp;
= > >
= > >  	host = cmd->device->host;
= > >  	hba = shost_priv(host);
= > >  	tag = cmd->request->tag;
= > >
= > > -	err = ufshcd_issue_tm_cmd(hba, &hba->lrb[tag],
= > UFS_LOGICAL_RESET);
= > > -	if (err == FAILED)
= > > +	lrbp = &hba->lrb[tag];
= > > +	err = ufshcd_issue_tm_cmd(hba, lrbp->lun, 0,
= > UFS_LOGICAL_RESET, &resp);
= > > +	if (err || resp != UPIU_TASK_MANAGEMENT_FUNC_COMPL) {
= > > +		err = FAILED;
= > >  		goto out;
= > > +	} else {
= > > +		err = SUCCESS;
= > > +	}
= > >
= > >  	for (pos = 0; pos < hba->nutrs; pos++) {
= > >  		if (test_bit(pos, &hba->outstanding_reqs) && @@ -2444,6
= > +2494,8 @@
= > > static int ufshcd_abort(struct scsi_cmnd *cmd)
= > >  	unsigned long flags;
= > >  	unsigned int tag;
= > >  	int err;
= > > +	u8 resp = 0xF;
= > > +	struct ufshcd_lrb *lrbp;
= > >
= > >  	host = cmd->device->host;
= > >  	hba = shost_priv(host);
= > > @@ -2459,9 +2511,15 @@ static int ufshcd_abort(struct scsi_cmnd
= > *cmd)
= > >  	}
= > >  	spin_unlock_irqrestore(host->host_lock, flags);
= > >
= > > -	err = ufshcd_issue_tm_cmd(hba, &hba->lrb[tag],
= > UFS_ABORT_TASK);
= > > -	if (err == FAILED)
= > > +	lrbp = &hba->lrb[tag];
= > > +	err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp->task_tag,
= > > +			UFS_ABORT_TASK, &resp);
= > > +	if (err || resp != UPIU_TASK_MANAGEMENT_FUNC_COMPL) {
= > > +		err = FAILED;
= > >  		goto out;
= > > +	} else {
= > > +		err = SUCCESS;
= > > +	}
= > >
= > >  	scsi_dma_unmap(cmd);
= > >
= > > @@ -2682,7 +2740,8 @@ int ufshcd_init(struct device *dev, struct
= > > ufs_hba **hba_handle,
= > >  	host->max_cmd_len = MAX_CDB_SIZE;
= > >
= > >  	/* Initailize wait queue for task management */
= > > -	init_waitqueue_head(&hba->ufshcd_tm_wait_queue);
= > > +	init_waitqueue_head(&hba->tm_wq);
= > > +	init_waitqueue_head(&hba->tm_tag_wq);
= > >
= > >  	/* Initialize work queues */
= > >  	INIT_WORK(&hba->feh_workq, ufshcd_fatal_err_handler); diff --
= > git
= > > a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index
= > > 59c9c48..fe7c947 100644
= > > --- a/drivers/scsi/ufs/ufshcd.h
= > > +++ b/drivers/scsi/ufs/ufshcd.h
= > > @@ -174,8 +174,10 @@ struct ufs_dev_cmd {
= > >   * @irq: Irq number of the controller
= > >   * @active_uic_cmd: handle of active UIC command
= > >   * @uic_cmd_mutex: mutex for uic command
= > > - * @ufshcd_tm_wait_queue: wait queue for task management
= > > + * @tm_wq: wait queue for task management
= > > + * @tm_tag_wq: wait queue for free task management slots
= > >   * @tm_condition: condition variable for task management
= > > + * @tm_slots_in_use: bit map of task management request slots in use
= > >   * @ufshcd_state: UFSHCD states
= > >   * @intr_mask: Interrupt Mask Bits
= > >   * @ee_ctrl_mask: Exception event control mask @@ -216,8 +218,10
= > @@
= > > struct ufs_hba {
= > >  	struct uic_command *active_uic_cmd;
= > >  	struct mutex uic_cmd_mutex;
= > >
= > > -	wait_queue_head_t ufshcd_tm_wait_queue;
= > > +	wait_queue_head_t tm_wq;
= > > +	wait_queue_head_t tm_tag_wq;
= > >  	unsigned long tm_condition;
= > > +	unsigned long tm_slots_in_use;
= > >
= > >  	u32 ufshcd_state;
= > >  	u32 intr_mask;
= > > --
= > > QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a
= > > member of Code Aurora Forum, hosted by The Linux Foundation.
= > >
= > > --
= > > To unsubscribe from this list: send the line "unsubscribe linux-scsi"
= > > in the body of a message to majordomo@vger.kernel.org More
= > majordomo
= > > info at  http://vger.kernel.org/majordomo-info.html
= > >
= > 
= > 
= > --
= > QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a
= > member of Code Aurora Forum, hosted by The Linux Foundation
= > 
= > --
= > To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the
= > body of a message to majordomo@vger.kernel.org More majordomo info
= > at  http://vger.kernel.org/majordomo-info.html


  reply	other threads:[~2013-08-13 14:57 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-07-30  5:45 [PATCH V5 0/4] scsi: ufs: Improve UFS error handling Sujit Reddy Thumma
2013-07-30  5:45 ` [PATCH V5 1/4] scsi: ufs: Fix broken task management command implementation Sujit Reddy Thumma
2013-08-12 13:01   ` Dolev Raviv
2013-08-13 14:57     ` Yaniv Gardi [this message]
2013-07-30  5:45 ` [PATCH V5 2/4] scsi: ufs: Fix hardware race conditions while aborting a command Sujit Reddy Thumma
2013-08-12 13:01   ` Dolev Raviv
2013-08-13 14:56     ` Yaniv Gardi
2013-07-30  5:45 ` [PATCH V5 3/4] scsi: ufs: Fix device and host reset methods Sujit Reddy Thumma
2013-08-12 13:02   ` Dolev Raviv
2013-08-13 14:55     ` Yaniv Gardi
2013-07-30  5:45 ` [PATCH V5 4/4] scsi: ufs: Improve UFS fatal error handling Sujit Reddy Thumma
2013-08-12 13:02   ` Dolev Raviv
2013-08-13 14:58     ` Yaniv Gardi
2013-08-12 12:59 ` [PATCH V5 0/4] scsi: ufs: Improve UFS " Dolev Raviv

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='006f01ce9835$7fea8e50$7fbfaaf0$@codeaurora.org' \
    --to=ygardi@codeaurora.org \
    --cc=draviv@codeaurora.org \
    --cc=jbottomley@parallels.com \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-scsi@vger.kernel.org \
    --cc=santoshsy@gmail.com \
    --cc=sthumma@codeaurora.org \
    --cc=vinholikatti@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.