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

2013-07-03 Thread Sujit Reddy Thumma

On 7/3/2013 11:19 AM, Santosh Y wrote:

+
+/**
+ * ufshcd_eh_device_reset_handler - device reset handler registered to
+ *scsi layer.
+ * @cmd - SCSI command pointer
+ *
+ * Returns SUCCESS/FAILED
+ */
+static int ufshcd_eh_device_reset_handler(struct scsi_cmnd *cmd)
+{
+   struct ufs_hba *hba;
+   int err;
+   unsigned long flags;
+
+   hba = shost_priv(cmd-device-host);
+
+   spin_lock_irqsave(hba-host-host_lock, flags);
+   if (hba-ufshcd_state == UFSHCD_STATE_RESET) {
+   dev_warn(hba-dev, %s: reset in progress\n, __func__);
+   err = SUCCESS;
+   spin_unlock_irqrestore(hba-host-host_lock, flags);
+   goto out;

It is better to wait here until the state changes to 'operational' or
'error' before returning success.


Okay. Sounds good.

--
Regards,
Sujit
--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

2013-07-02 Thread Santosh Y
 +
 +/**
 + * ufshcd_eh_device_reset_handler - device reset handler registered to
 + *scsi layer.
 + * @cmd - SCSI command pointer
 + *
 + * Returns SUCCESS/FAILED
 + */
 +static int ufshcd_eh_device_reset_handler(struct scsi_cmnd *cmd)
 +{
 +   struct ufs_hba *hba;
 +   int err;
 +   unsigned long flags;
 +
 +   hba = shost_priv(cmd-device-host);
 +
 +   spin_lock_irqsave(hba-host-host_lock, flags);
 +   if (hba-ufshcd_state == UFSHCD_STATE_RESET) {
 +   dev_warn(hba-dev, %s: reset in progress\n, __func__);
 +   err = SUCCESS;
 +   spin_unlock_irqrestore(hba-host-host_lock, flags);
 +   goto out;

It is better to wait here until the state changes to 'operational' or
'error' before returning success.

 +   }
 +
 +   hba-ufshcd_state = UFSHCD_STATE_RESET;
 +   ufshcd_set_device_reset_pending(hba);
 +   spin_unlock_irqrestore(hba-host-host_lock, flags);
 +
 +   err = ufshcd_reset_and_restore(hba);
 +
 +   spin_lock_irqsave(hba-host-host_lock, flags);
 +   if (!err) {
 +   err = SUCCESS;
 +   hba-ufshcd_state = UFSHCD_STATE_OPERATIONAL;
 +   } else {
 +   err = FAILED;
 +   hba-ufshcd_state = UFSHCD_STATE_ERROR;
 +   }
 +   spin_unlock_irqrestore(hba-host-host_lock, flags);
 +out:
 +   return err;
 +}
 +
 +/**
 + * ufshcd_eh_host_reset_handler - host reset handler registered to scsi layer
 + * @cmd - SCSI command pointer
 + *
 + * Returns SUCCESS/FAILED
 + */
 +static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd)
 +{
 +   struct ufs_hba *hba;
 +   int err;
 +   unsigned long flags;
 +
 +   hba = shost_priv(cmd-device-host);
 +
 +   spin_lock_irqsave(hba-host-host_lock, flags);
 +   if (hba-ufshcd_state == UFSHCD_STATE_RESET) {
 +   dev_warn(hba-dev, %s: reset in progress\n, __func__);
 +   err = SUCCESS;
 +   spin_unlock_irqrestore(hba-host-host_lock, flags);
 +   goto out;

same in this case also.

 +   }
 +
 +   hba-ufshcd_state = UFSHCD_STATE_RESET;
 +   ufshcd_set_host_reset_pending(hba);
 +   spin_unlock_irqrestore(hba-host-host_lock, flags);
 +
 +   err = ufshcd_reset_and_restore(hba);
 +
 +   spin_lock_irqsave(hba-host-host_lock, flags);
 +   if (!err) {
 +   err = SUCCESS;
 +   hba-ufshcd_state = UFSHCD_STATE_OPERATIONAL;
 +   } else {
 +   err = FAILED;
 +   hba-ufshcd_state = UFSHCD_STATE_ERROR;
 +   }
 +   spin_unlock_irqrestore(hba-host-host_lock, flags);
 +out:
 +   return err;
 +}
 +
 +/**

-- 
~Santosh
--
To unsubscribe from this list: send the line unsubscribe linux-scsi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

2013-06-28 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 |  446 +++--
 drivers/scsi/ufs/ufshcd.h |2 +
 2 files changed, 393 insertions(+), 55 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 6bfe927..2829a42 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
@@ -883,9 +905,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 */
@@ -1604,8 +1639,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;
 }
@@ -2302,6 +2335,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,
+