scsi: ufs: Add UFS fatal error handling
authorhgchu <hg.chu@samsung.com>
Fri, 12 Jan 2018 08:34:41 +0000 (17:34 +0900)
committerJaeHun Jung <jh0801.jung@samsung.com>
Tue, 8 May 2018 08:20:47 +0000 (17:20 +0900)
Change-Id: I42fc3930f74c571a34d487b2511dd0a1916a430b
Signed-off-by: hgchu <hg.chu@samsung.com>
drivers/scsi/ufs/ufshcd.c

index b56a56f97e8bc1ce3f3aa7eb716f12a1d470dd3a..6bf6f10900fafaca10c58b5b85c1dee83f45f461 100644 (file)
@@ -5006,7 +5006,7 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, int reason,
  * ufshcd_transfer_req_compl - handle SCSI and query command completion
  * @hba: per adapter instance
  */
-static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
+static void ufshcd_transfer_req_compl(struct ufs_hba *hba, int reason)
 {
        unsigned long completed_reqs;
        u32 tr_doorbell;
@@ -5024,7 +5024,7 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
        tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
        completed_reqs = tr_doorbell ^ hba->outstanding_reqs;
 
-       __ufshcd_transfer_req_compl(hba, completed_reqs);
+       __ufshcd_transfer_req_compl(hba, reason, completed_reqs);
 }
 
 /**
@@ -5333,7 +5333,7 @@ out:
 /* Complete requests that have door-bell cleared */
 static void ufshcd_complete_requests(struct ufs_hba *hba)
 {
-       ufshcd_transfer_req_compl(hba);
+       ufshcd_transfer_req_compl(hba, 0);
        ufshcd_tmc_handler(hba);
 }
 
@@ -5507,10 +5507,20 @@ skip_pending_xfer_clear:
                 * slot forcefully.
                 */
                if (hba->outstanding_reqs == max_doorbells)
-                       __ufshcd_transfer_req_compl(hba,
+                       __ufshcd_transfer_req_compl(hba, 0,
                                                    (1UL << (hba->nutrs - 1)));
 
                spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+               /* Fatal errors need reset */
+               if (err_xfer || err_tm || (hba->saved_err & INT_FATAL_ERRORS) ||
+                               ((hba->saved_err & UIC_ERROR) &&
+                               ((hba->saved_uic_err & UFSHCD_UIC_DL_PA_INIT_ERROR) ||
+                                (hba->saved_uic_err & UFSHCD_UIC_DL_ERROR))))
+                                       dev_err(hba->dev,
+                                       "%s: saved_err:0x%x, saved_uic_err:0x%x\n",
+                                       __func__, hba->saved_err, hba->saved_uic_err);
+
                err = ufshcd_reset_and_restore(hba);
                spin_lock_irqsave(hba->host->host_lock, flags);
                if (err) {
@@ -5711,7 +5721,7 @@ static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
                ufshcd_tmc_handler(hba);
 
        if (intr_status & UTP_TRANSFER_REQ_COMPL)
-               ufshcd_transfer_req_compl(hba);
+               ufshcd_transfer_req_compl(hba, 0);
 }
 
 /**
@@ -5904,7 +5914,7 @@ static int ufshcd_eh_device_reset_handler(struct scsi_cmnd *cmd)
                }
        }
        spin_lock_irqsave(host->host_lock, flags);
-       ufshcd_transfer_req_compl(hba);
+       ufshcd_transfer_req_compl(hba, DID_RESET);
        spin_unlock_irqrestore(host->host_lock, flags);
 
 out:
@@ -6211,7 +6221,7 @@ static int ufshcd_reset_and_restore(struct ufs_hba *hba)
         * outstanding requests in s/w here.
         */
        spin_lock_irqsave(hba->host->host_lock, flags);
-       ufshcd_transfer_req_compl(hba);
+       ufshcd_transfer_req_compl(hba, DID_RESET);
        ufshcd_tmc_handler(hba);
        spin_unlock_irqrestore(hba->host->host_lock, flags);
 
@@ -6833,7 +6843,9 @@ retry:
        }
 
        /* set the state as operational after switching to desired gear */
+       spin_lock_irqsave(hba->host->host_lock, flags);
        hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
+       spin_unlock_irqrestore(hba->host->host_lock, flags);
 
        /*
         * If we are in error handling context or in power management callbacks