aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSujit Reddy Thumma <sthumma@codeaurora.org>2014-05-26 01:29:14 -0400
committerChristoph Hellwig <hch@lst.de>2014-05-28 06:25:13 -0400
commit3441da7ddbdedf91bfd5cc8609c571ffc24942dd (patch)
tree0f947767abed6bed588d8de42bd71238fdcaa008
parentf20810d8d0bbe70dc6bb526213c31171f7e54751 (diff)
scsi: ufs: Fix device and host reset methods
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 <sthumma@codeaurora.org> Reviewed-by: Yaniv Gardi <ygardi@codeaurora.org> Tested-by: Dolev Raviv <draviv@codeaurora.org> Acked-by: Vinayak Holikatti <vinholikatti@gmail.com> Signed-off-by: Christoph Hellwig <hch@lst.de>
-rw-r--r--drivers/scsi/ufs/ufshcd.c240
-rw-r--r--drivers/scsi/ufs/ufshcd.h2
2 files changed, 189 insertions, 53 deletions
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 52f66e4c8b47..54623104f262 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -74,9 +74,14 @@ enum {
74 74
75/* UFSHCD states */ 75/* UFSHCD states */
76enum { 76enum {
77 UFSHCD_STATE_OPERATIONAL,
78 UFSHCD_STATE_RESET, 77 UFSHCD_STATE_RESET,
79 UFSHCD_STATE_ERROR, 78 UFSHCD_STATE_ERROR,
79 UFSHCD_STATE_OPERATIONAL,
80};
81
82/* UFSHCD error handling flags */
83enum {
84 UFSHCD_EH_IN_PROGRESS = (1 << 0),
80}; 85};
81 86
82/* Interrupt configuration options */ 87/* Interrupt configuration options */
@@ -86,6 +91,16 @@ enum {
86 UFSHCD_INT_CLEAR, 91 UFSHCD_INT_CLEAR,
87}; 92};
88 93
94#define ufshcd_set_eh_in_progress(h) \
95 (h->eh_flags |= UFSHCD_EH_IN_PROGRESS)
96#define ufshcd_eh_in_progress(h) \
97 (h->eh_flags & UFSHCD_EH_IN_PROGRESS)
98#define ufshcd_clear_eh_in_progress(h) \
99 (h->eh_flags &= ~UFSHCD_EH_IN_PROGRESS)
100
101static void ufshcd_tmc_handler(struct ufs_hba *hba);
102static void ufshcd_async_scan(void *data, async_cookie_t cookie);
103
89/* 104/*
90 * ufshcd_wait_for_register - wait for register value to change 105 * ufshcd_wait_for_register - wait for register value to change
91 * @hba - per-adapter interface 106 * @hba - per-adapter interface
@@ -856,10 +871,25 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
856 871
857 tag = cmd->request->tag; 872 tag = cmd->request->tag;
858 873
859 if (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL) { 874 spin_lock_irqsave(hba->host->host_lock, flags);
875 switch (hba->ufshcd_state) {
876 case UFSHCD_STATE_OPERATIONAL:
877 break;
878 case UFSHCD_STATE_RESET:
860 err = SCSI_MLQUEUE_HOST_BUSY; 879 err = SCSI_MLQUEUE_HOST_BUSY;
861 goto out; 880 goto out_unlock;
881 case UFSHCD_STATE_ERROR:
882 set_host_byte(cmd, DID_ERROR);
883 cmd->scsi_done(cmd);
884 goto out_unlock;
885 default:
886 dev_WARN_ONCE(hba->dev, 1, "%s: invalid state %d\n",
887 __func__, hba->ufshcd_state);
888 set_host_byte(cmd, DID_BAD_TARGET);
889 cmd->scsi_done(cmd);
890 goto out_unlock;
862 } 891 }
892 spin_unlock_irqrestore(hba->host->host_lock, flags);
863 893
864 /* acquire the tag to make sure device cmds don't use it */ 894 /* acquire the tag to make sure device cmds don't use it */
865 if (test_and_set_bit_lock(tag, &hba->lrb_in_use)) { 895 if (test_and_set_bit_lock(tag, &hba->lrb_in_use)) {
@@ -896,6 +926,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
896 /* issue command to the controller */ 926 /* issue command to the controller */
897 spin_lock_irqsave(hba->host->host_lock, flags); 927 spin_lock_irqsave(hba->host->host_lock, flags);
898 ufshcd_send_command(hba, tag); 928 ufshcd_send_command(hba, tag);
929out_unlock:
899 spin_unlock_irqrestore(hba->host->host_lock, flags); 930 spin_unlock_irqrestore(hba->host->host_lock, flags);
900out: 931out:
901 return err; 932 return err;
@@ -1707,8 +1738,6 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba)
1707 if (hba->ufshcd_state == UFSHCD_STATE_RESET) 1738 if (hba->ufshcd_state == UFSHCD_STATE_RESET)
1708 scsi_unblock_requests(hba->host); 1739 scsi_unblock_requests(hba->host);
1709 1740
1710 hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
1711
1712out: 1741out:
1713 return err; 1742 return err;
1714} 1743}
@@ -2455,8 +2484,12 @@ static void ufshcd_err_handler(struct ufs_hba *hba)
2455 } 2484 }
2456 return; 2485 return;
2457fatal_eh: 2486fatal_eh:
2458 hba->ufshcd_state = UFSHCD_STATE_ERROR; 2487 /* handle fatal errors only when link is functional */
2459 schedule_work(&hba->feh_workq); 2488 if (hba->ufshcd_state == UFSHCD_STATE_OPERATIONAL) {
2489 /* block commands at driver layer until error is handled */
2490 hba->ufshcd_state = UFSHCD_STATE_ERROR;
2491 schedule_work(&hba->feh_workq);
2492 }
2460} 2493}
2461 2494
2462/** 2495/**
@@ -2621,12 +2654,13 @@ static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id,
2621} 2654}
2622 2655
2623/** 2656/**
2624 * ufshcd_device_reset - reset device and abort all the pending commands 2657 * ufshcd_eh_device_reset_handler - device reset handler registered to
2658 * scsi layer.
2625 * @cmd: SCSI command pointer 2659 * @cmd: SCSI command pointer
2626 * 2660 *
2627 * Returns SUCCESS/FAILED 2661 * Returns SUCCESS/FAILED
2628 */ 2662 */
2629static int ufshcd_device_reset(struct scsi_cmnd *cmd) 2663static int ufshcd_eh_device_reset_handler(struct scsi_cmnd *cmd)
2630{ 2664{
2631 struct Scsi_Host *host; 2665 struct Scsi_Host *host;
2632 struct ufs_hba *hba; 2666 struct ufs_hba *hba;
@@ -2635,6 +2669,7 @@ static int ufshcd_device_reset(struct scsi_cmnd *cmd)
2635 int err; 2669 int err;
2636 u8 resp = 0xF; 2670 u8 resp = 0xF;
2637 struct ufshcd_lrb *lrbp; 2671 struct ufshcd_lrb *lrbp;
2672 unsigned long flags;
2638 2673
2639 host = cmd->device->host; 2674 host = cmd->device->host;
2640 hba = shost_priv(host); 2675 hba = shost_priv(host);
@@ -2643,55 +2678,33 @@ static int ufshcd_device_reset(struct scsi_cmnd *cmd)
2643 lrbp = &hba->lrb[tag]; 2678 lrbp = &hba->lrb[tag];
2644 err = ufshcd_issue_tm_cmd(hba, lrbp->lun, 0, UFS_LOGICAL_RESET, &resp); 2679 err = ufshcd_issue_tm_cmd(hba, lrbp->lun, 0, UFS_LOGICAL_RESET, &resp);
2645 if (err || resp != UPIU_TASK_MANAGEMENT_FUNC_COMPL) { 2680 if (err || resp != UPIU_TASK_MANAGEMENT_FUNC_COMPL) {
2646 err = FAILED; 2681 if (!err)
2682 err = resp;
2647 goto out; 2683 goto out;
2648 } else {
2649 err = SUCCESS;
2650 } 2684 }
2651 2685
2652 for (pos = 0; pos < hba->nutrs; pos++) { 2686 /* clear the commands that were pending for corresponding LUN */
2653 if (test_bit(pos, &hba->outstanding_reqs) && 2687 for_each_set_bit(pos, &hba->outstanding_reqs, hba->nutrs) {
2654 (hba->lrb[tag].lun == hba->lrb[pos].lun)) { 2688 if (hba->lrb[pos].lun == lrbp->lun) {
2655 2689 err = ufshcd_clear_cmd(hba, pos);
2656 /* clear the respective UTRLCLR register bit */ 2690 if (err)
2657 ufshcd_utrl_clear(hba, pos); 2691 break;
2658
2659 clear_bit(pos, &hba->outstanding_reqs);
2660
2661 if (hba->lrb[pos].cmd) {
2662 scsi_dma_unmap(hba->lrb[pos].cmd);
2663 hba->lrb[pos].cmd->result =
2664 DID_ABORT << 16;
2665 hba->lrb[pos].cmd->scsi_done(cmd);
2666 hba->lrb[pos].cmd = NULL;
2667 clear_bit_unlock(pos, &hba->lrb_in_use);
2668 wake_up(&hba->dev_cmd.tag_wq);
2669 }
2670 } 2692 }
2671 } /* end of for */ 2693 }
2694 spin_lock_irqsave(host->host_lock, flags);
2695 ufshcd_transfer_req_compl(hba);
2696 spin_unlock_irqrestore(host->host_lock, flags);
2672out: 2697out:
2698 if (!err) {
2699 err = SUCCESS;
2700 } else {
2701 dev_err(hba->dev, "%s: failed with err %d\n", __func__, err);
2702 err = FAILED;
2703 }
2673 return err; 2704 return err;
2674} 2705}
2675 2706
2676/** 2707/**
2677 * ufshcd_host_reset - Main reset function registered with scsi layer
2678 * @cmd: SCSI command pointer
2679 *
2680 * Returns SUCCESS/FAILED
2681 */
2682static int ufshcd_host_reset(struct scsi_cmnd *cmd)
2683{
2684 struct ufs_hba *hba;
2685
2686 hba = shost_priv(cmd->device->host);
2687
2688 if (hba->ufshcd_state == UFSHCD_STATE_RESET)
2689 return SUCCESS;
2690
2691 return ufshcd_do_reset(hba);
2692}
2693
2694/**
2695 * ufshcd_abort - abort a specific command 2708 * ufshcd_abort - abort a specific command
2696 * @cmd: SCSI command pointer 2709 * @cmd: SCSI command pointer
2697 * 2710 *
@@ -2789,6 +2802,122 @@ out:
2789} 2802}
2790 2803
2791/** 2804/**
2805 * ufshcd_host_reset_and_restore - reset and restore host controller
2806 * @hba: per-adapter instance
2807 *
2808 * Note that host controller reset may issue DME_RESET to
2809 * local and remote (device) Uni-Pro stack and the attributes
2810 * are reset to default state.
2811 *
2812 * Returns zero on success, non-zero on failure
2813 */
2814static int ufshcd_host_reset_and_restore(struct ufs_hba *hba)
2815{
2816 int err;
2817 async_cookie_t cookie;
2818 unsigned long flags;
2819
2820 /* Reset the host controller */
2821 spin_lock_irqsave(hba->host->host_lock, flags);
2822 ufshcd_hba_stop(hba);
2823 spin_unlock_irqrestore(hba->host->host_lock, flags);
2824
2825 err = ufshcd_hba_enable(hba);
2826 if (err)
2827 goto out;
2828
2829 /* Establish the link again and restore the device */
2830 cookie = async_schedule(ufshcd_async_scan, hba);
2831 /* wait for async scan to be completed */
2832 async_synchronize_cookie(++cookie);
2833 if (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL)
2834 err = -EIO;
2835out:
2836 if (err)
2837 dev_err(hba->dev, "%s: Host init failed %d\n", __func__, err);
2838
2839 return err;
2840}
2841
2842/**
2843 * ufshcd_reset_and_restore - reset and re-initialize host/device
2844 * @hba: per-adapter instance
2845 *
2846 * Reset and recover device, host and re-establish link. This
2847 * is helpful to recover the communication in fatal error conditions.
2848 *
2849 * Returns zero on success, non-zero on failure
2850 */
2851static int ufshcd_reset_and_restore(struct ufs_hba *hba)
2852{
2853 int err = 0;
2854 unsigned long flags;
2855
2856 err = ufshcd_host_reset_and_restore(hba);
2857
2858 /*
2859 * After reset the door-bell might be cleared, complete
2860 * outstanding requests in s/w here.
2861 */
2862 spin_lock_irqsave(hba->host->host_lock, flags);
2863 ufshcd_transfer_req_compl(hba);
2864 ufshcd_tmc_handler(hba);
2865 spin_unlock_irqrestore(hba->host->host_lock, flags);
2866
2867 return err;
2868}
2869
2870/**
2871 * ufshcd_eh_host_reset_handler - host reset handler registered to scsi layer
2872 * @cmd - SCSI command pointer
2873 *
2874 * Returns SUCCESS/FAILED
2875 */
2876static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd)
2877{
2878 int err;
2879 unsigned long flags;
2880 struct ufs_hba *hba;
2881
2882 hba = shost_priv(cmd->device->host);
2883
2884 /*
2885 * Check if there is any race with fatal error handling.
2886 * If so, wait for it to complete. Even though fatal error
2887 * handling does reset and restore in some cases, don't assume
2888 * anything out of it. We are just avoiding race here.
2889 */
2890 do {
2891 spin_lock_irqsave(hba->host->host_lock, flags);
2892 if (!(work_pending(&hba->feh_workq) ||
2893 hba->ufshcd_state == UFSHCD_STATE_RESET))
2894 break;
2895 spin_unlock_irqrestore(hba->host->host_lock, flags);
2896 dev_dbg(hba->dev, "%s: reset in progress\n", __func__);
2897 flush_work(&hba->feh_workq);
2898 } while (1);
2899
2900 hba->ufshcd_state = UFSHCD_STATE_RESET;
2901 ufshcd_set_eh_in_progress(hba);
2902 spin_unlock_irqrestore(hba->host->host_lock, flags);
2903
2904 err = ufshcd_reset_and_restore(hba);
2905
2906 spin_lock_irqsave(hba->host->host_lock, flags);
2907 if (!err) {
2908 err = SUCCESS;
2909 hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
2910 } else {
2911 err = FAILED;
2912 hba->ufshcd_state = UFSHCD_STATE_ERROR;
2913 }
2914 ufshcd_clear_eh_in_progress(hba);
2915 spin_unlock_irqrestore(hba->host->host_lock, flags);
2916
2917 return err;
2918}
2919
2920/**
2792 * ufshcd_async_scan - asynchronous execution for link startup 2921 * ufshcd_async_scan - asynchronous execution for link startup
2793 * @data: data pointer to pass to this function 2922 * @data: data pointer to pass to this function
2794 * @cookie: cookie data 2923 * @cookie: cookie data
@@ -2813,8 +2942,13 @@ static void ufshcd_async_scan(void *data, async_cookie_t cookie)
2813 goto out; 2942 goto out;
2814 2943
2815 ufshcd_force_reset_auto_bkops(hba); 2944 ufshcd_force_reset_auto_bkops(hba);
2816 scsi_scan_host(hba->host); 2945 hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
2817 pm_runtime_put_sync(hba->dev); 2946
2947 /* If we are in error handling context no need to scan the host */
2948 if (!ufshcd_eh_in_progress(hba)) {
2949 scsi_scan_host(hba->host);
2950 pm_runtime_put_sync(hba->dev);
2951 }
2818out: 2952out:
2819 return; 2953 return;
2820} 2954}
@@ -2827,8 +2961,8 @@ static struct scsi_host_template ufshcd_driver_template = {
2827 .slave_alloc = ufshcd_slave_alloc, 2961 .slave_alloc = ufshcd_slave_alloc,
2828 .slave_destroy = ufshcd_slave_destroy, 2962 .slave_destroy = ufshcd_slave_destroy,
2829 .eh_abort_handler = ufshcd_abort, 2963 .eh_abort_handler = ufshcd_abort,
2830 .eh_device_reset_handler = ufshcd_device_reset, 2964 .eh_device_reset_handler = ufshcd_eh_device_reset_handler,
2831 .eh_host_reset_handler = ufshcd_host_reset, 2965 .eh_host_reset_handler = ufshcd_eh_host_reset_handler,
2832 .this_id = -1, 2966 .this_id = -1,
2833 .sg_tablesize = SG_ALL, 2967 .sg_tablesize = SG_ALL,
2834 .cmd_per_lun = UFSHCD_CMD_PER_LUN, 2968 .cmd_per_lun = UFSHCD_CMD_PER_LUN,
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 84d09d1ae881..48c7d9b587f7 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -180,6 +180,7 @@ struct ufs_dev_cmd {
180 * @pwr_done: completion for power mode change 180 * @pwr_done: completion for power mode change
181 * @tm_condition: condition variable for task management 181 * @tm_condition: condition variable for task management
182 * @ufshcd_state: UFSHCD states 182 * @ufshcd_state: UFSHCD states
183 * @eh_flags: Error handling flags
183 * @intr_mask: Interrupt Mask Bits 184 * @intr_mask: Interrupt Mask Bits
184 * @ee_ctrl_mask: Exception event control mask 185 * @ee_ctrl_mask: Exception event control mask
185 * @feh_workq: Work queue for fatal controller error handling 186 * @feh_workq: Work queue for fatal controller error handling
@@ -227,6 +228,7 @@ struct ufs_hba {
227 struct completion *pwr_done; 228 struct completion *pwr_done;
228 229
229 u32 ufshcd_state; 230 u32 ufshcd_state;
231 u32 eh_flags;
230 u32 intr_mask; 232 u32 intr_mask;
231 u16 ee_ctrl_mask; 233 u16 ee_ctrl_mask;
232 234