From 944d927f3ef8ddedc21a4eef3e42473e0a104bcb Mon Sep 17 00:00:00 2001 From: hgchu Date: Fri, 12 Jan 2018 17:34:41 +0900 Subject: [PATCH] scsi: ufs: Add UFS fatal error handling Change-Id: I42fc3930f74c571a34d487b2511dd0a1916a430b Signed-off-by: hgchu --- drivers/scsi/ufs/ufshcd.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index b56a56f97e8b..6bf6f10900fa 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -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 -- 2.20.1