Re: [PATCH V3 3/4] scsi: ufs: Fix device and host reset methods

2013-07-29 Thread Sujit Reddy Thumma
On 7/24/2013 7:09 PM, Seungwon Jeon wrote:
 On Wed, July 24, 2013, Sujit Reddy Thumma wrote:
 On 7/23/2013 1:57 PM, Seungwon Jeon wrote:
 On Sat, July 20, 2013, Sujit Reddy Thumma wrote:
 On 7/19/2013 7:27 PM, Seungwon Jeon wrote:
 On Tue, July 09, 2013, Sujit Reddy Thumma wrote:
 As of now SCSI initiated error handling is broken because,
 the reset APIs don't try to bring back the device initialized and
 ready for further transfers.

 In case of timeouts, the scsi error handler takes care of handling aborts
 and resets. Improve the error handling in such scenario by resetting the
 device and host and re-initializing them in proper manner.

 Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org
 ---
 drivers/scsi/ufs/ufshcd.c |  467 
 +++--
 drivers/scsi/ufs/ufshcd.h |2 +
 2 files changed, 411 insertions(+), 58 deletions(-)

 diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
 index 51ce096..b4c9910 100644
 --- a/drivers/scsi/ufs/ufshcd.c
 +++ b/drivers/scsi/ufs/ufshcd.c
 @@ -69,9 +69,15 @@ enum {

 /* UFSHCD states */
 enum {
 -UFSHCD_STATE_OPERATIONAL,
  UFSHCD_STATE_RESET,
  UFSHCD_STATE_ERROR,
 +UFSHCD_STATE_OPERATIONAL,
 +};
 +
 +/* UFSHCD error handling flags */
 +enum {
 +UFSHCD_EH_HOST_RESET_PENDING = (1  0),
 +UFSHCD_EH_DEVICE_RESET_PENDING = (1  1),
 };

 /* Interrupt configuration options */
 @@ -87,6 +93,22 @@ enum {
  INT_AGGR_CONFIG,
 };

 +#define ufshcd_set_device_reset_pending(h) \
 +(h-eh_flags |= UFSHCD_EH_DEVICE_RESET_PENDING)
 +#define ufshcd_set_host_reset_pending(h) \
 +(h-eh_flags |= UFSHCD_EH_HOST_RESET_PENDING)
 +#define ufshcd_device_reset_pending(h) \
 +(h-eh_flags  UFSHCD_EH_DEVICE_RESET_PENDING)
 +#define ufshcd_host_reset_pending(h) \
 +(h-eh_flags  UFSHCD_EH_HOST_RESET_PENDING)
 +#define ufshcd_clear_device_reset_pending(h) \
 +(h-eh_flags = ~UFSHCD_EH_DEVICE_RESET_PENDING)
 +#define ufshcd_clear_host_reset_pending(h) \
 +(h-eh_flags = ~UFSHCD_EH_HOST_RESET_PENDING)
 +
 +static void ufshcd_tmc_handler(struct ufs_hba *hba);
 +static void ufshcd_async_scan(void *data, async_cookie_t cookie);
 +
 /*
  * ufshcd_wait_for_register - wait for register value to change
  * @hba - per-adapter interface
 @@ -851,9 +873,22 @@ static int ufshcd_queuecommand(struct Scsi_Host 
 *host, struct scsi_cmnd *cmd)

  tag = cmd-request-tag;

 -if (hba-ufshcd_state != UFSHCD_STATE_OPERATIONAL) {
 +switch (hba-ufshcd_state) {
 Lock is no needed for ufshcd_state?
 Please check?

 Yes, it is needed. Thanks for catching this.



 +case UFSHCD_STATE_OPERATIONAL:
 +break;
 +case UFSHCD_STATE_RESET:
  err = SCSI_MLQUEUE_HOST_BUSY;
  goto out;
 +case UFSHCD_STATE_ERROR:
 +set_host_byte(cmd, DID_ERROR);
 +cmd-scsi_done(cmd);
 +goto out;
 +default:
 +dev_WARN_ONCE(hba-dev, 1, %s: invalid state %d\n,
 +__func__, hba-ufshcd_state);
 +set_host_byte(cmd, DID_BAD_TARGET);
 +cmd-scsi_done(cmd);
 +goto out;
  }

  /* acquire the tag to make sure device cmds don't use it */
 @@ -1573,8 +1608,6 @@ static int ufshcd_make_hba_operational(struct 
 ufs_hba *hba)
  if (hba-ufshcd_state == UFSHCD_STATE_RESET)
  scsi_unblock_requests(hba-host);

 -hba-ufshcd_state = UFSHCD_STATE_OPERATIONAL;
 -
 out:
  return err;
 }
 @@ -2273,6 +2306,106 @@ out:
 }

 /**
 + * ufshcd_utrl_is_rsr_enabled - check if run-stop register is enabled
 + * @hba: per-adapter instance
 + */
 +static bool ufshcd_utrl_is_rsr_enabled(struct ufs_hba *hba)
 +{
 +return ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_LIST_RUN_STOP)  
 0x1;
 +}
 +
 +/**
 + * ufshcd_utmrl_is_rsr_enabled - check if run-stop register is enabled
 + * @hba: per-adapter instance
 + */
 +static bool ufshcd_utmrl_is_rsr_enabled(struct ufs_hba *hba)
 +{
 +return ufshcd_readl(hba, REG_UTP_TASK_REQ_LIST_RUN_STOP)  0x1;
 +}
 +
 +/**
 + * ufshcd_complete_pending_tasks - complete outstanding tasks
 + * @hba: per adapter instance
 + *
 + * Abort in-progress task management commands and wakeup
 + * waiting threads.
 + *
 + * Returns non-zero error value when failed to clear all the commands.
 + */
 +static int ufshcd_complete_pending_tasks(struct ufs_hba *hba)
 +{
 +u32 reg;
 +int err = 0;
 +unsigned long flags;
 +
 +if (!hba-outstanding_tasks)
 +goto out;
 +
 +/* Clear UTMRL only when run-stop is enabled */
 +if (ufshcd_utmrl_is_rsr_enabled(hba))
 +ufshcd_writel(hba, ~hba-outstanding_tasks,
 +REG_UTP_TASK_REQ_LIST_CLEAR);
 +
 +/* poll for max. 

RE: [PATCH V3 3/4] scsi: ufs: Fix device and host reset methods

2013-07-24 Thread Seungwon Jeon
On Wed, July 24, 2013, Sujit Reddy Thumma wrote:
 On 7/23/2013 1:57 PM, Seungwon Jeon wrote:
  On Sat, July 20, 2013, Sujit Reddy Thumma wrote:
  On 7/19/2013 7:27 PM, Seungwon Jeon wrote:
  On Tue, July 09, 2013, Sujit Reddy Thumma wrote:
  As of now SCSI initiated error handling is broken because,
  the reset APIs don't try to bring back the device initialized and
  ready for further transfers.
 
  In case of timeouts, the scsi error handler takes care of handling aborts
  and resets. Improve the error handling in such scenario by resetting the
  device and host and re-initializing them in proper manner.
 
  Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org
  ---
 drivers/scsi/ufs/ufshcd.c |  467 
  +++--
 drivers/scsi/ufs/ufshcd.h |2 +
 2 files changed, 411 insertions(+), 58 deletions(-)
 
  diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
  index 51ce096..b4c9910 100644
  --- a/drivers/scsi/ufs/ufshcd.c
  +++ b/drivers/scsi/ufs/ufshcd.c
  @@ -69,9 +69,15 @@ enum {
 
 /* UFSHCD states */
 enum {
  -UFSHCD_STATE_OPERATIONAL,
   UFSHCD_STATE_RESET,
   UFSHCD_STATE_ERROR,
  +UFSHCD_STATE_OPERATIONAL,
  +};
  +
  +/* UFSHCD error handling flags */
  +enum {
  +UFSHCD_EH_HOST_RESET_PENDING = (1  0),
  +UFSHCD_EH_DEVICE_RESET_PENDING = (1  1),
 };
 
 /* Interrupt configuration options */
  @@ -87,6 +93,22 @@ enum {
   INT_AGGR_CONFIG,
 };
 
  +#define ufshcd_set_device_reset_pending(h) \
  +(h-eh_flags |= UFSHCD_EH_DEVICE_RESET_PENDING)
  +#define ufshcd_set_host_reset_pending(h) \
  +(h-eh_flags |= UFSHCD_EH_HOST_RESET_PENDING)
  +#define ufshcd_device_reset_pending(h) \
  +(h-eh_flags  UFSHCD_EH_DEVICE_RESET_PENDING)
  +#define ufshcd_host_reset_pending(h) \
  +(h-eh_flags  UFSHCD_EH_HOST_RESET_PENDING)
  +#define ufshcd_clear_device_reset_pending(h) \
  +(h-eh_flags = ~UFSHCD_EH_DEVICE_RESET_PENDING)
  +#define ufshcd_clear_host_reset_pending(h) \
  +(h-eh_flags = ~UFSHCD_EH_HOST_RESET_PENDING)
  +
  +static void ufshcd_tmc_handler(struct ufs_hba *hba);
  +static void ufshcd_async_scan(void *data, async_cookie_t cookie);
  +
 /*
  * ufshcd_wait_for_register - wait for register value to change
  * @hba - per-adapter interface
  @@ -851,9 +873,22 @@ static int ufshcd_queuecommand(struct Scsi_Host 
  *host, struct scsi_cmnd *cmd)
 
   tag = cmd-request-tag;
 
  -if (hba-ufshcd_state != UFSHCD_STATE_OPERATIONAL) {
  +switch (hba-ufshcd_state) {
  Lock is no needed for ufshcd_state?
  Please check?
 
 Yes, it is needed. Thanks for catching this.
 
 
 
  +case UFSHCD_STATE_OPERATIONAL:
  +break;
  +case UFSHCD_STATE_RESET:
   err = SCSI_MLQUEUE_HOST_BUSY;
   goto out;
  +case UFSHCD_STATE_ERROR:
  +set_host_byte(cmd, DID_ERROR);
  +cmd-scsi_done(cmd);
  +goto out;
  +default:
  +dev_WARN_ONCE(hba-dev, 1, %s: invalid state %d\n,
  +__func__, hba-ufshcd_state);
  +set_host_byte(cmd, DID_BAD_TARGET);
  +cmd-scsi_done(cmd);
  +goto out;
   }
 
   /* acquire the tag to make sure device cmds don't use it */
  @@ -1573,8 +1608,6 @@ static int ufshcd_make_hba_operational(struct 
  ufs_hba *hba)
   if (hba-ufshcd_state == UFSHCD_STATE_RESET)
   scsi_unblock_requests(hba-host);
 
  -hba-ufshcd_state = UFSHCD_STATE_OPERATIONAL;
  -
 out:
   return err;
 }
  @@ -2273,6 +2306,106 @@ out:
 }
 
 /**
  + * ufshcd_utrl_is_rsr_enabled - check if run-stop register is enabled
  + * @hba: per-adapter instance
  + */
  +static bool ufshcd_utrl_is_rsr_enabled(struct ufs_hba *hba)
  +{
  +return ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_LIST_RUN_STOP)  
  0x1;
  +}
  +
  +/**
  + * ufshcd_utmrl_is_rsr_enabled - check if run-stop register is enabled
  + * @hba: per-adapter instance
  + */
  +static bool ufshcd_utmrl_is_rsr_enabled(struct ufs_hba *hba)
  +{
  +return ufshcd_readl(hba, REG_UTP_TASK_REQ_LIST_RUN_STOP)  0x1;
  +}
  +
  +/**
  + * ufshcd_complete_pending_tasks - complete outstanding tasks
  + * @hba: per adapter instance
  + *
  + * Abort in-progress task management commands and wakeup
  + * waiting threads.
  + *
  + * Returns non-zero error value when failed to clear all the commands.
  + */
  +static int ufshcd_complete_pending_tasks(struct ufs_hba *hba)
  +{
  +u32 reg;
  +int err = 0;
  +unsigned long flags;
  +
  +if (!hba-outstanding_tasks)
  +goto out;
  +
  +/* Clear UTMRL only when run-stop is enabled */
  +if (ufshcd_utmrl_is_rsr_enabled(hba))
  +ufshcd_writel(hba, ~hba-outstanding_tasks,
  +

RE: [PATCH V3 3/4] scsi: ufs: Fix device and host reset methods

2013-07-23 Thread Seungwon Jeon
On Sat, July 20, 2013, Sujit Reddy Thumma wrote:
 On 7/19/2013 7:27 PM, Seungwon Jeon wrote:
  On Tue, July 09, 2013, Sujit Reddy Thumma wrote:
  As of now SCSI initiated error handling is broken because,
  the reset APIs don't try to bring back the device initialized and
  ready for further transfers.
 
  In case of timeouts, the scsi error handler takes care of handling aborts
  and resets. Improve the error handling in such scenario by resetting the
  device and host and re-initializing them in proper manner.
 
  Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org
  ---
drivers/scsi/ufs/ufshcd.c |  467 
  +++--
drivers/scsi/ufs/ufshcd.h |2 +
2 files changed, 411 insertions(+), 58 deletions(-)
 
  diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
  index 51ce096..b4c9910 100644
  --- a/drivers/scsi/ufs/ufshcd.c
  +++ b/drivers/scsi/ufs/ufshcd.c
  @@ -69,9 +69,15 @@ enum {
 
/* UFSHCD states */
enum {
  -  UFSHCD_STATE_OPERATIONAL,
 UFSHCD_STATE_RESET,
 UFSHCD_STATE_ERROR,
  +  UFSHCD_STATE_OPERATIONAL,
  +};
  +
  +/* UFSHCD error handling flags */
  +enum {
  +  UFSHCD_EH_HOST_RESET_PENDING = (1  0),
  +  UFSHCD_EH_DEVICE_RESET_PENDING = (1  1),
};
 
/* Interrupt configuration options */
  @@ -87,6 +93,22 @@ enum {
 INT_AGGR_CONFIG,
};
 
  +#define ufshcd_set_device_reset_pending(h) \
  +  (h-eh_flags |= UFSHCD_EH_DEVICE_RESET_PENDING)
  +#define ufshcd_set_host_reset_pending(h) \
  +  (h-eh_flags |= UFSHCD_EH_HOST_RESET_PENDING)
  +#define ufshcd_device_reset_pending(h) \
  +  (h-eh_flags  UFSHCD_EH_DEVICE_RESET_PENDING)
  +#define ufshcd_host_reset_pending(h) \
  +  (h-eh_flags  UFSHCD_EH_HOST_RESET_PENDING)
  +#define ufshcd_clear_device_reset_pending(h) \
  +  (h-eh_flags = ~UFSHCD_EH_DEVICE_RESET_PENDING)
  +#define ufshcd_clear_host_reset_pending(h) \
  +  (h-eh_flags = ~UFSHCD_EH_HOST_RESET_PENDING)
  +
  +static void ufshcd_tmc_handler(struct ufs_hba *hba);
  +static void ufshcd_async_scan(void *data, async_cookie_t cookie);
  +
/*
 * ufshcd_wait_for_register - wait for register value to change
 * @hba - per-adapter interface
  @@ -851,9 +873,22 @@ static int ufshcd_queuecommand(struct Scsi_Host 
  *host, struct scsi_cmnd *cmd)
 
 tag = cmd-request-tag;
 
  -  if (hba-ufshcd_state != UFSHCD_STATE_OPERATIONAL) {
  +  switch (hba-ufshcd_state) {
  Lock is no needed for ufshcd_state?
Please check?

 
  +  case UFSHCD_STATE_OPERATIONAL:
  +  break;
  +  case UFSHCD_STATE_RESET:
 err = SCSI_MLQUEUE_HOST_BUSY;
 goto out;
  +  case UFSHCD_STATE_ERROR:
  +  set_host_byte(cmd, DID_ERROR);
  +  cmd-scsi_done(cmd);
  +  goto out;
  +  default:
  +  dev_WARN_ONCE(hba-dev, 1, %s: invalid state %d\n,
  +  __func__, hba-ufshcd_state);
  +  set_host_byte(cmd, DID_BAD_TARGET);
  +  cmd-scsi_done(cmd);
  +  goto out;
 }
 
 /* acquire the tag to make sure device cmds don't use it */
  @@ -1573,8 +1608,6 @@ static int ufshcd_make_hba_operational(struct 
  ufs_hba *hba)
 if (hba-ufshcd_state == UFSHCD_STATE_RESET)
 scsi_unblock_requests(hba-host);
 
  -  hba-ufshcd_state = UFSHCD_STATE_OPERATIONAL;
  -
out:
 return err;
}
  @@ -2273,6 +2306,106 @@ out:
}
 
/**
  + * ufshcd_utrl_is_rsr_enabled - check if run-stop register is enabled
  + * @hba: per-adapter instance
  + */
  +static bool ufshcd_utrl_is_rsr_enabled(struct ufs_hba *hba)
  +{
  +  return ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_LIST_RUN_STOP)  0x1;
  +}
  +
  +/**
  + * ufshcd_utmrl_is_rsr_enabled - check if run-stop register is enabled
  + * @hba: per-adapter instance
  + */
  +static bool ufshcd_utmrl_is_rsr_enabled(struct ufs_hba *hba)
  +{
  +  return ufshcd_readl(hba, REG_UTP_TASK_REQ_LIST_RUN_STOP)  0x1;
  +}
  +
  +/**
  + * ufshcd_complete_pending_tasks - complete outstanding tasks
  + * @hba: per adapter instance
  + *
  + * Abort in-progress task management commands and wakeup
  + * waiting threads.
  + *
  + * Returns non-zero error value when failed to clear all the commands.
  + */
  +static int ufshcd_complete_pending_tasks(struct ufs_hba *hba)
  +{
  +  u32 reg;
  +  int err = 0;
  +  unsigned long flags;
  +
  +  if (!hba-outstanding_tasks)
  +  goto out;
  +
  +  /* Clear UTMRL only when run-stop is enabled */
  +  if (ufshcd_utmrl_is_rsr_enabled(hba))
  +  ufshcd_writel(hba, ~hba-outstanding_tasks,
  +  REG_UTP_TASK_REQ_LIST_CLEAR);
  +
  +  /* poll for max. 1 sec to clear door bell register by h/w */
  +  reg = ufshcd_wait_for_register(hba,
  +  REG_UTP_TASK_REQ_DOOR_BELL,
  +  hba-outstanding_tasks, 0, 1000, 1000);
  +  if (reg  hba-outstanding_tasks)
  +  err = -ETIMEDOUT;
  +
  +  spin_lock_irqsave(hba-host-host_lock, flags);
  +  /* complete commands that were cleared out */
  

Re: [PATCH V3 3/4] scsi: ufs: Fix device and host reset methods

2013-07-23 Thread Sujit Reddy Thumma
On 7/23/2013 1:57 PM, Seungwon Jeon wrote:
 On Sat, July 20, 2013, Sujit Reddy Thumma wrote:
 On 7/19/2013 7:27 PM, Seungwon Jeon wrote:
 On Tue, July 09, 2013, Sujit Reddy Thumma wrote:
 As of now SCSI initiated error handling is broken because,
 the reset APIs don't try to bring back the device initialized and
 ready for further transfers.

 In case of timeouts, the scsi error handler takes care of handling aborts
 and resets. Improve the error handling in such scenario by resetting the
 device and host and re-initializing them in proper manner.

 Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org
 ---
drivers/scsi/ufs/ufshcd.c |  467 
 +++--
drivers/scsi/ufs/ufshcd.h |2 +
2 files changed, 411 insertions(+), 58 deletions(-)

 diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
 index 51ce096..b4c9910 100644
 --- a/drivers/scsi/ufs/ufshcd.c
 +++ b/drivers/scsi/ufs/ufshcd.c
 @@ -69,9 +69,15 @@ enum {

/* UFSHCD states */
enum {
 -  UFSHCD_STATE_OPERATIONAL,
UFSHCD_STATE_RESET,
UFSHCD_STATE_ERROR,
 +  UFSHCD_STATE_OPERATIONAL,
 +};
 +
 +/* UFSHCD error handling flags */
 +enum {
 +  UFSHCD_EH_HOST_RESET_PENDING = (1  0),
 +  UFSHCD_EH_DEVICE_RESET_PENDING = (1  1),
};

/* Interrupt configuration options */
 @@ -87,6 +93,22 @@ enum {
INT_AGGR_CONFIG,
};

 +#define ufshcd_set_device_reset_pending(h) \
 +  (h-eh_flags |= UFSHCD_EH_DEVICE_RESET_PENDING)
 +#define ufshcd_set_host_reset_pending(h) \
 +  (h-eh_flags |= UFSHCD_EH_HOST_RESET_PENDING)
 +#define ufshcd_device_reset_pending(h) \
 +  (h-eh_flags  UFSHCD_EH_DEVICE_RESET_PENDING)
 +#define ufshcd_host_reset_pending(h) \
 +  (h-eh_flags  UFSHCD_EH_HOST_RESET_PENDING)
 +#define ufshcd_clear_device_reset_pending(h) \
 +  (h-eh_flags = ~UFSHCD_EH_DEVICE_RESET_PENDING)
 +#define ufshcd_clear_host_reset_pending(h) \
 +  (h-eh_flags = ~UFSHCD_EH_HOST_RESET_PENDING)
 +
 +static void ufshcd_tmc_handler(struct ufs_hba *hba);
 +static void ufshcd_async_scan(void *data, async_cookie_t cookie);
 +
/*
 * ufshcd_wait_for_register - wait for register value to change
 * @hba - per-adapter interface
 @@ -851,9 +873,22 @@ static int ufshcd_queuecommand(struct Scsi_Host 
 *host, struct scsi_cmnd *cmd)

tag = cmd-request-tag;

 -  if (hba-ufshcd_state != UFSHCD_STATE_OPERATIONAL) {
 +  switch (hba-ufshcd_state) {
 Lock is no needed for ufshcd_state?
 Please check?

Yes, it is needed. Thanks for catching this.

 

 +  case UFSHCD_STATE_OPERATIONAL:
 +  break;
 +  case UFSHCD_STATE_RESET:
err = SCSI_MLQUEUE_HOST_BUSY;
goto out;
 +  case UFSHCD_STATE_ERROR:
 +  set_host_byte(cmd, DID_ERROR);
 +  cmd-scsi_done(cmd);
 +  goto out;
 +  default:
 +  dev_WARN_ONCE(hba-dev, 1, %s: invalid state %d\n,
 +  __func__, hba-ufshcd_state);
 +  set_host_byte(cmd, DID_BAD_TARGET);
 +  cmd-scsi_done(cmd);
 +  goto out;
}

/* acquire the tag to make sure device cmds don't use it */
 @@ -1573,8 +1608,6 @@ static int ufshcd_make_hba_operational(struct 
 ufs_hba *hba)
if (hba-ufshcd_state == UFSHCD_STATE_RESET)
scsi_unblock_requests(hba-host);

 -  hba-ufshcd_state = UFSHCD_STATE_OPERATIONAL;
 -
out:
return err;
}
 @@ -2273,6 +2306,106 @@ out:
}

/**
 + * ufshcd_utrl_is_rsr_enabled - check if run-stop register is enabled
 + * @hba: per-adapter instance
 + */
 +static bool ufshcd_utrl_is_rsr_enabled(struct ufs_hba *hba)
 +{
 +  return ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_LIST_RUN_STOP)  0x1;
 +}
 +
 +/**
 + * ufshcd_utmrl_is_rsr_enabled - check if run-stop register is enabled
 + * @hba: per-adapter instance
 + */
 +static bool ufshcd_utmrl_is_rsr_enabled(struct ufs_hba *hba)
 +{
 +  return ufshcd_readl(hba, REG_UTP_TASK_REQ_LIST_RUN_STOP)  0x1;
 +}
 +
 +/**
 + * ufshcd_complete_pending_tasks - complete outstanding tasks
 + * @hba: per adapter instance
 + *
 + * Abort in-progress task management commands and wakeup
 + * waiting threads.
 + *
 + * Returns non-zero error value when failed to clear all the commands.
 + */
 +static int ufshcd_complete_pending_tasks(struct ufs_hba *hba)
 +{
 +  u32 reg;
 +  int err = 0;
 +  unsigned long flags;
 +
 +  if (!hba-outstanding_tasks)
 +  goto out;
 +
 +  /* Clear UTMRL only when run-stop is enabled */
 +  if (ufshcd_utmrl_is_rsr_enabled(hba))
 +  ufshcd_writel(hba, ~hba-outstanding_tasks,
 +  REG_UTP_TASK_REQ_LIST_CLEAR);
 +
 +  /* poll for max. 1 sec to clear door bell register by h/w */
 +  reg = ufshcd_wait_for_register(hba,
 +  REG_UTP_TASK_REQ_DOOR_BELL,
 +  hba-outstanding_tasks, 0, 1000, 1000);
 +  if (reg  hba-outstanding_tasks)
 +  err = -ETIMEDOUT;
 +
 +  spin_lock_irqsave(hba-host-host_lock, flags);
 +  /* 

RE: [PATCH V3 3/4] scsi: ufs: Fix device and host reset methods

2013-07-19 Thread Seungwon Jeon
On Tue, July 09, 2013, Sujit Reddy Thumma wrote:
 As of now SCSI initiated error handling is broken because,
 the reset APIs don't try to bring back the device initialized and
 ready for further transfers.
 
 In case of timeouts, the scsi error handler takes care of handling aborts
 and resets. Improve the error handling in such scenario by resetting the
 device and host and re-initializing them in proper manner.
 
 Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org
 ---
  drivers/scsi/ufs/ufshcd.c |  467 
 +++--
  drivers/scsi/ufs/ufshcd.h |2 +
  2 files changed, 411 insertions(+), 58 deletions(-)
 
 diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
 index 51ce096..b4c9910 100644
 --- a/drivers/scsi/ufs/ufshcd.c
 +++ b/drivers/scsi/ufs/ufshcd.c
 @@ -69,9 +69,15 @@ enum {
 
  /* UFSHCD states */
  enum {
 - UFSHCD_STATE_OPERATIONAL,
   UFSHCD_STATE_RESET,
   UFSHCD_STATE_ERROR,
 + UFSHCD_STATE_OPERATIONAL,
 +};
 +
 +/* UFSHCD error handling flags */
 +enum {
 + UFSHCD_EH_HOST_RESET_PENDING = (1  0),
 + UFSHCD_EH_DEVICE_RESET_PENDING = (1  1),
  };
 
  /* Interrupt configuration options */
 @@ -87,6 +93,22 @@ enum {
   INT_AGGR_CONFIG,
  };
 
 +#define ufshcd_set_device_reset_pending(h) \
 + (h-eh_flags |= UFSHCD_EH_DEVICE_RESET_PENDING)
 +#define ufshcd_set_host_reset_pending(h) \
 + (h-eh_flags |= UFSHCD_EH_HOST_RESET_PENDING)
 +#define ufshcd_device_reset_pending(h) \
 + (h-eh_flags  UFSHCD_EH_DEVICE_RESET_PENDING)
 +#define ufshcd_host_reset_pending(h) \
 + (h-eh_flags  UFSHCD_EH_HOST_RESET_PENDING)
 +#define ufshcd_clear_device_reset_pending(h) \
 + (h-eh_flags = ~UFSHCD_EH_DEVICE_RESET_PENDING)
 +#define ufshcd_clear_host_reset_pending(h) \
 + (h-eh_flags = ~UFSHCD_EH_HOST_RESET_PENDING)
 +
 +static void ufshcd_tmc_handler(struct ufs_hba *hba);
 +static void ufshcd_async_scan(void *data, async_cookie_t cookie);
 +
  /*
   * ufshcd_wait_for_register - wait for register value to change
   * @hba - per-adapter interface
 @@ -851,9 +873,22 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, 
 struct scsi_cmnd *cmd)
 
   tag = cmd-request-tag;
 
 - if (hba-ufshcd_state != UFSHCD_STATE_OPERATIONAL) {
 + switch (hba-ufshcd_state) {
Lock is no needed for ufshcd_state?

 + case UFSHCD_STATE_OPERATIONAL:
 + break;
 + case UFSHCD_STATE_RESET:
   err = SCSI_MLQUEUE_HOST_BUSY;
   goto out;
 + case UFSHCD_STATE_ERROR:
 + set_host_byte(cmd, DID_ERROR);
 + cmd-scsi_done(cmd);
 + goto out;
 + default:
 + dev_WARN_ONCE(hba-dev, 1, %s: invalid state %d\n,
 + __func__, hba-ufshcd_state);
 + set_host_byte(cmd, DID_BAD_TARGET);
 + cmd-scsi_done(cmd);
 + goto out;
   }
 
   /* acquire the tag to make sure device cmds don't use it */
 @@ -1573,8 +1608,6 @@ static int ufshcd_make_hba_operational(struct ufs_hba 
 *hba)
   if (hba-ufshcd_state == UFSHCD_STATE_RESET)
   scsi_unblock_requests(hba-host);
 
 - hba-ufshcd_state = UFSHCD_STATE_OPERATIONAL;
 -
  out:
   return err;
  }
 @@ -2273,6 +2306,106 @@ out:
  }
 
  /**
 + * ufshcd_utrl_is_rsr_enabled - check if run-stop register is enabled
 + * @hba: per-adapter instance
 + */
 +static bool ufshcd_utrl_is_rsr_enabled(struct ufs_hba *hba)
 +{
 + return ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_LIST_RUN_STOP)  0x1;
 +}
 +
 +/**
 + * ufshcd_utmrl_is_rsr_enabled - check if run-stop register is enabled
 + * @hba: per-adapter instance
 + */
 +static bool ufshcd_utmrl_is_rsr_enabled(struct ufs_hba *hba)
 +{
 + return ufshcd_readl(hba, REG_UTP_TASK_REQ_LIST_RUN_STOP)  0x1;
 +}
 +
 +/**
 + * ufshcd_complete_pending_tasks - complete outstanding tasks
 + * @hba: per adapter instance
 + *
 + * Abort in-progress task management commands and wakeup
 + * waiting threads.
 + *
 + * Returns non-zero error value when failed to clear all the commands.
 + */
 +static int ufshcd_complete_pending_tasks(struct ufs_hba *hba)
 +{
 + u32 reg;
 + int err = 0;
 + unsigned long flags;
 +
 + if (!hba-outstanding_tasks)
 + goto out;
 +
 + /* Clear UTMRL only when run-stop is enabled */
 + if (ufshcd_utmrl_is_rsr_enabled(hba))
 + ufshcd_writel(hba, ~hba-outstanding_tasks,
 + REG_UTP_TASK_REQ_LIST_CLEAR);
 +
 + /* poll for max. 1 sec to clear door bell register by h/w */
 + reg = ufshcd_wait_for_register(hba,
 + REG_UTP_TASK_REQ_DOOR_BELL,
 + hba-outstanding_tasks, 0, 1000, 1000);
 + if (reg  hba-outstanding_tasks)
 + err = -ETIMEDOUT;
 +
 + spin_lock_irqsave(hba-host-host_lock, flags);
 + /* complete commands that were cleared out */
 + ufshcd_tmc_handler(hba);
 + spin_unlock_irqrestore(hba-host-host_lock, flags);
 +out:
 

Re: [PATCH V3 3/4] scsi: ufs: Fix device and host reset methods

2013-07-19 Thread Sujit Reddy Thumma
On 7/19/2013 7:27 PM, Seungwon Jeon wrote:
 On Tue, July 09, 2013, Sujit Reddy Thumma wrote:
 As of now SCSI initiated error handling is broken because,
 the reset APIs don't try to bring back the device initialized and
 ready for further transfers.

 In case of timeouts, the scsi error handler takes care of handling aborts
 and resets. Improve the error handling in such scenario by resetting the
 device and host and re-initializing them in proper manner.

 Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org
 ---
   drivers/scsi/ufs/ufshcd.c |  467 
 +++--
   drivers/scsi/ufs/ufshcd.h |2 +
   2 files changed, 411 insertions(+), 58 deletions(-)

 diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
 index 51ce096..b4c9910 100644
 --- a/drivers/scsi/ufs/ufshcd.c
 +++ b/drivers/scsi/ufs/ufshcd.c
 @@ -69,9 +69,15 @@ enum {

   /* UFSHCD states */
   enum {
 -UFSHCD_STATE_OPERATIONAL,
  UFSHCD_STATE_RESET,
  UFSHCD_STATE_ERROR,
 +UFSHCD_STATE_OPERATIONAL,
 +};
 +
 +/* UFSHCD error handling flags */
 +enum {
 +UFSHCD_EH_HOST_RESET_PENDING = (1  0),
 +UFSHCD_EH_DEVICE_RESET_PENDING = (1  1),
   };

   /* Interrupt configuration options */
 @@ -87,6 +93,22 @@ enum {
  INT_AGGR_CONFIG,
   };

 +#define ufshcd_set_device_reset_pending(h) \
 +(h-eh_flags |= UFSHCD_EH_DEVICE_RESET_PENDING)
 +#define ufshcd_set_host_reset_pending(h) \
 +(h-eh_flags |= UFSHCD_EH_HOST_RESET_PENDING)
 +#define ufshcd_device_reset_pending(h) \
 +(h-eh_flags  UFSHCD_EH_DEVICE_RESET_PENDING)
 +#define ufshcd_host_reset_pending(h) \
 +(h-eh_flags  UFSHCD_EH_HOST_RESET_PENDING)
 +#define ufshcd_clear_device_reset_pending(h) \
 +(h-eh_flags = ~UFSHCD_EH_DEVICE_RESET_PENDING)
 +#define ufshcd_clear_host_reset_pending(h) \
 +(h-eh_flags = ~UFSHCD_EH_HOST_RESET_PENDING)
 +
 +static void ufshcd_tmc_handler(struct ufs_hba *hba);
 +static void ufshcd_async_scan(void *data, async_cookie_t cookie);
 +
   /*
* ufshcd_wait_for_register - wait for register value to change
* @hba - per-adapter interface
 @@ -851,9 +873,22 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, 
 struct scsi_cmnd *cmd)

  tag = cmd-request-tag;

 -if (hba-ufshcd_state != UFSHCD_STATE_OPERATIONAL) {
 +switch (hba-ufshcd_state) {
 Lock is no needed for ufshcd_state?
 
 +case UFSHCD_STATE_OPERATIONAL:
 +break;
 +case UFSHCD_STATE_RESET:
  err = SCSI_MLQUEUE_HOST_BUSY;
  goto out;
 +case UFSHCD_STATE_ERROR:
 +set_host_byte(cmd, DID_ERROR);
 +cmd-scsi_done(cmd);
 +goto out;
 +default:
 +dev_WARN_ONCE(hba-dev, 1, %s: invalid state %d\n,
 +__func__, hba-ufshcd_state);
 +set_host_byte(cmd, DID_BAD_TARGET);
 +cmd-scsi_done(cmd);
 +goto out;
  }

  /* acquire the tag to make sure device cmds don't use it */
 @@ -1573,8 +1608,6 @@ static int ufshcd_make_hba_operational(struct ufs_hba 
 *hba)
  if (hba-ufshcd_state == UFSHCD_STATE_RESET)
  scsi_unblock_requests(hba-host);

 -hba-ufshcd_state = UFSHCD_STATE_OPERATIONAL;
 -
   out:
  return err;
   }
 @@ -2273,6 +2306,106 @@ out:
   }

   /**
 + * ufshcd_utrl_is_rsr_enabled - check if run-stop register is enabled
 + * @hba: per-adapter instance
 + */
 +static bool ufshcd_utrl_is_rsr_enabled(struct ufs_hba *hba)
 +{
 +return ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_LIST_RUN_STOP)  0x1;
 +}
 +
 +/**
 + * ufshcd_utmrl_is_rsr_enabled - check if run-stop register is enabled
 + * @hba: per-adapter instance
 + */
 +static bool ufshcd_utmrl_is_rsr_enabled(struct ufs_hba *hba)
 +{
 +return ufshcd_readl(hba, REG_UTP_TASK_REQ_LIST_RUN_STOP)  0x1;
 +}
 +
 +/**
 + * ufshcd_complete_pending_tasks - complete outstanding tasks
 + * @hba: per adapter instance
 + *
 + * Abort in-progress task management commands and wakeup
 + * waiting threads.
 + *
 + * Returns non-zero error value when failed to clear all the commands.
 + */
 +static int ufshcd_complete_pending_tasks(struct ufs_hba *hba)
 +{
 +u32 reg;
 +int err = 0;
 +unsigned long flags;
 +
 +if (!hba-outstanding_tasks)
 +goto out;
 +
 +/* Clear UTMRL only when run-stop is enabled */
 +if (ufshcd_utmrl_is_rsr_enabled(hba))
 +ufshcd_writel(hba, ~hba-outstanding_tasks,
 +REG_UTP_TASK_REQ_LIST_CLEAR);
 +
 +/* poll for max. 1 sec to clear door bell register by h/w */
 +reg = ufshcd_wait_for_register(hba,
 +REG_UTP_TASK_REQ_DOOR_BELL,
 +hba-outstanding_tasks, 0, 1000, 1000);
 +if (reg  hba-outstanding_tasks)
 +err = -ETIMEDOUT;
 +
 +spin_lock_irqsave(hba-host-host_lock, flags);
 +/* complete commands that were cleared out */
 +ufshcd_tmc_handler(hba);
 +spin_unlock_irqrestore(hba-host-host_lock, flags);
 +out:
 +if 

[PATCH V3 3/4] scsi: ufs: Fix device and host reset methods

2013-07-09 Thread Sujit Reddy Thumma
As of now SCSI initiated error handling is broken because,
the reset APIs don't try to bring back the device initialized and
ready for further transfers.

In case of timeouts, the scsi error handler takes care of handling aborts
and resets. Improve the error handling in such scenario by resetting the
device and host and re-initializing them in proper manner.

Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org
---
 drivers/scsi/ufs/ufshcd.c |  467 +++--
 drivers/scsi/ufs/ufshcd.h |2 +
 2 files changed, 411 insertions(+), 58 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 51ce096..b4c9910 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -69,9 +69,15 @@ enum {
 
 /* UFSHCD states */
 enum {
-   UFSHCD_STATE_OPERATIONAL,
UFSHCD_STATE_RESET,
UFSHCD_STATE_ERROR,
+   UFSHCD_STATE_OPERATIONAL,
+};
+
+/* UFSHCD error handling flags */
+enum {
+   UFSHCD_EH_HOST_RESET_PENDING = (1  0),
+   UFSHCD_EH_DEVICE_RESET_PENDING = (1  1),
 };
 
 /* Interrupt configuration options */
@@ -87,6 +93,22 @@ enum {
INT_AGGR_CONFIG,
 };
 
+#define ufshcd_set_device_reset_pending(h) \
+   (h-eh_flags |= UFSHCD_EH_DEVICE_RESET_PENDING)
+#define ufshcd_set_host_reset_pending(h) \
+   (h-eh_flags |= UFSHCD_EH_HOST_RESET_PENDING)
+#define ufshcd_device_reset_pending(h) \
+   (h-eh_flags  UFSHCD_EH_DEVICE_RESET_PENDING)
+#define ufshcd_host_reset_pending(h) \
+   (h-eh_flags  UFSHCD_EH_HOST_RESET_PENDING)
+#define ufshcd_clear_device_reset_pending(h) \
+   (h-eh_flags = ~UFSHCD_EH_DEVICE_RESET_PENDING)
+#define ufshcd_clear_host_reset_pending(h) \
+   (h-eh_flags = ~UFSHCD_EH_HOST_RESET_PENDING)
+
+static void ufshcd_tmc_handler(struct ufs_hba *hba);
+static void ufshcd_async_scan(void *data, async_cookie_t cookie);
+
 /*
  * ufshcd_wait_for_register - wait for register value to change
  * @hba - per-adapter interface
@@ -851,9 +873,22 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, 
struct scsi_cmnd *cmd)
 
tag = cmd-request-tag;
 
-   if (hba-ufshcd_state != UFSHCD_STATE_OPERATIONAL) {
+   switch (hba-ufshcd_state) {
+   case UFSHCD_STATE_OPERATIONAL:
+   break;
+   case UFSHCD_STATE_RESET:
err = SCSI_MLQUEUE_HOST_BUSY;
goto out;
+   case UFSHCD_STATE_ERROR:
+   set_host_byte(cmd, DID_ERROR);
+   cmd-scsi_done(cmd);
+   goto out;
+   default:
+   dev_WARN_ONCE(hba-dev, 1, %s: invalid state %d\n,
+   __func__, hba-ufshcd_state);
+   set_host_byte(cmd, DID_BAD_TARGET);
+   cmd-scsi_done(cmd);
+   goto out;
}
 
/* acquire the tag to make sure device cmds don't use it */
@@ -1573,8 +1608,6 @@ static int ufshcd_make_hba_operational(struct ufs_hba 
*hba)
if (hba-ufshcd_state == UFSHCD_STATE_RESET)
scsi_unblock_requests(hba-host);
 
-   hba-ufshcd_state = UFSHCD_STATE_OPERATIONAL;
-
 out:
return err;
 }
@@ -2273,6 +2306,106 @@ out:
 }
 
 /**
+ * ufshcd_utrl_is_rsr_enabled - check if run-stop register is enabled
+ * @hba: per-adapter instance
+ */
+static bool ufshcd_utrl_is_rsr_enabled(struct ufs_hba *hba)
+{
+   return ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_LIST_RUN_STOP)  0x1;
+}
+
+/**
+ * ufshcd_utmrl_is_rsr_enabled - check if run-stop register is enabled
+ * @hba: per-adapter instance
+ */
+static bool ufshcd_utmrl_is_rsr_enabled(struct ufs_hba *hba)
+{
+   return ufshcd_readl(hba, REG_UTP_TASK_REQ_LIST_RUN_STOP)  0x1;
+}
+
+/**
+ * ufshcd_complete_pending_tasks - complete outstanding tasks
+ * @hba: per adapter instance
+ *
+ * Abort in-progress task management commands and wakeup
+ * waiting threads.
+ *
+ * Returns non-zero error value when failed to clear all the commands.
+ */
+static int ufshcd_complete_pending_tasks(struct ufs_hba *hba)
+{
+   u32 reg;
+   int err = 0;
+   unsigned long flags;
+
+   if (!hba-outstanding_tasks)
+   goto out;
+
+   /* Clear UTMRL only when run-stop is enabled */
+   if (ufshcd_utmrl_is_rsr_enabled(hba))
+   ufshcd_writel(hba, ~hba-outstanding_tasks,
+   REG_UTP_TASK_REQ_LIST_CLEAR);
+
+   /* poll for max. 1 sec to clear door bell register by h/w */
+   reg = ufshcd_wait_for_register(hba,
+   REG_UTP_TASK_REQ_DOOR_BELL,
+   hba-outstanding_tasks, 0, 1000, 1000);
+   if (reg  hba-outstanding_tasks)
+   err = -ETIMEDOUT;
+
+   spin_lock_irqsave(hba-host-host_lock, flags);
+   /* complete commands that were cleared out */
+   ufshcd_tmc_handler(hba);
+   spin_unlock_irqrestore(hba-host-host_lock, flags);
+out:
+   if (err)
+   dev_err(hba-dev, %s: failed, still pending = 0x%.8x\n,
+  

Re: [PATCH V3 3/4] scsi: ufs: Fix device and host reset methods

2013-07-09 Thread merez
Tested with error injection.

Tested-by: Maya Erez me...@codeaurora.org

 As of now SCSI initiated error handling is broken because,
 the reset APIs don't try to bring back the device initialized and
 ready for further transfers.

 In case of timeouts, the scsi error handler takes care of handling aborts
 and resets. Improve the error handling in such scenario by resetting the
 device and host and re-initializing them in proper manner.

 Signed-off-by: Sujit Reddy Thumma sthu...@codeaurora.org
 ---
  drivers/scsi/ufs/ufshcd.c |  467
 +++--
  drivers/scsi/ufs/ufshcd.h |2 +
  2 files changed, 411 insertions(+), 58 deletions(-)

 diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
 index 51ce096..b4c9910 100644
 --- a/drivers/scsi/ufs/ufshcd.c
 +++ b/drivers/scsi/ufs/ufshcd.c
 @@ -69,9 +69,15 @@ enum {

  /* UFSHCD states */
  enum {
 - UFSHCD_STATE_OPERATIONAL,
   UFSHCD_STATE_RESET,
   UFSHCD_STATE_ERROR,
 + UFSHCD_STATE_OPERATIONAL,
 +};
 +
 +/* UFSHCD error handling flags */
 +enum {
 + UFSHCD_EH_HOST_RESET_PENDING = (1  0),
 + UFSHCD_EH_DEVICE_RESET_PENDING = (1  1),
  };

  /* Interrupt configuration options */
 @@ -87,6 +93,22 @@ enum {
   INT_AGGR_CONFIG,
  };

 +#define ufshcd_set_device_reset_pending(h) \
 + (h-eh_flags |= UFSHCD_EH_DEVICE_RESET_PENDING)
 +#define ufshcd_set_host_reset_pending(h) \
 + (h-eh_flags |= UFSHCD_EH_HOST_RESET_PENDING)
 +#define ufshcd_device_reset_pending(h) \
 + (h-eh_flags  UFSHCD_EH_DEVICE_RESET_PENDING)
 +#define ufshcd_host_reset_pending(h) \
 + (h-eh_flags  UFSHCD_EH_HOST_RESET_PENDING)
 +#define ufshcd_clear_device_reset_pending(h) \
 + (h-eh_flags = ~UFSHCD_EH_DEVICE_RESET_PENDING)
 +#define ufshcd_clear_host_reset_pending(h) \
 + (h-eh_flags = ~UFSHCD_EH_HOST_RESET_PENDING)
 +
 +static void ufshcd_tmc_handler(struct ufs_hba *hba);
 +static void ufshcd_async_scan(void *data, async_cookie_t cookie);
 +
  /*
   * ufshcd_wait_for_register - wait for register value to change
   * @hba - per-adapter interface
 @@ -851,9 +873,22 @@ static int ufshcd_queuecommand(struct Scsi_Host
 *host, struct scsi_cmnd *cmd)

   tag = cmd-request-tag;

 - if (hba-ufshcd_state != UFSHCD_STATE_OPERATIONAL) {
 + switch (hba-ufshcd_state) {
 + case UFSHCD_STATE_OPERATIONAL:
 + break;
 + case UFSHCD_STATE_RESET:
   err = SCSI_MLQUEUE_HOST_BUSY;
   goto out;
 + case UFSHCD_STATE_ERROR:
 + set_host_byte(cmd, DID_ERROR);
 + cmd-scsi_done(cmd);
 + goto out;
 + default:
 + dev_WARN_ONCE(hba-dev, 1, %s: invalid state %d\n,
 + __func__, hba-ufshcd_state);
 + set_host_byte(cmd, DID_BAD_TARGET);
 + cmd-scsi_done(cmd);
 + goto out;
   }

   /* acquire the tag to make sure device cmds don't use it */
 @@ -1573,8 +1608,6 @@ static int ufshcd_make_hba_operational(struct
 ufs_hba *hba)
   if (hba-ufshcd_state == UFSHCD_STATE_RESET)
   scsi_unblock_requests(hba-host);

 - hba-ufshcd_state = UFSHCD_STATE_OPERATIONAL;
 -
  out:
   return err;
  }
 @@ -2273,6 +2306,106 @@ out:
  }

  /**
 + * ufshcd_utrl_is_rsr_enabled - check if run-stop register is enabled
 + * @hba: per-adapter instance
 + */
 +static bool ufshcd_utrl_is_rsr_enabled(struct ufs_hba *hba)
 +{
 + return ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_LIST_RUN_STOP)  0x1;
 +}
 +
 +/**
 + * ufshcd_utmrl_is_rsr_enabled - check if run-stop register is enabled
 + * @hba: per-adapter instance
 + */
 +static bool ufshcd_utmrl_is_rsr_enabled(struct ufs_hba *hba)
 +{
 + return ufshcd_readl(hba, REG_UTP_TASK_REQ_LIST_RUN_STOP)  0x1;
 +}
 +
 +/**
 + * ufshcd_complete_pending_tasks - complete outstanding tasks
 + * @hba: per adapter instance
 + *
 + * Abort in-progress task management commands and wakeup
 + * waiting threads.
 + *
 + * Returns non-zero error value when failed to clear all the commands.
 + */
 +static int ufshcd_complete_pending_tasks(struct ufs_hba *hba)
 +{
 + u32 reg;
 + int err = 0;
 + unsigned long flags;
 +
 + if (!hba-outstanding_tasks)
 + goto out;
 +
 + /* Clear UTMRL only when run-stop is enabled */
 + if (ufshcd_utmrl_is_rsr_enabled(hba))
 + ufshcd_writel(hba, ~hba-outstanding_tasks,
 + REG_UTP_TASK_REQ_LIST_CLEAR);
 +
 + /* poll for max. 1 sec to clear door bell register by h/w */
 + reg = ufshcd_wait_for_register(hba,
 + REG_UTP_TASK_REQ_DOOR_BELL,
 + hba-outstanding_tasks, 0, 1000, 1000);
 + if (reg  hba-outstanding_tasks)
 + err = -ETIMEDOUT;
 +
 + spin_lock_irqsave(hba-host-host_lock, flags);
 + /* complete commands that were cleared out */
 + ufshcd_tmc_handler(hba);
 + spin_unlock_irqrestore(hba-host-host_lock, flags);
 +out:
 + if (err)
 +