Loading drivers/scsi/ufs/ufs-debugfs.c +8 −2 Original line number Diff line number Diff line Loading @@ -1412,8 +1412,10 @@ static ssize_t ufsdbg_reset_controller_write(struct file *filp, struct ufs_hba *hba = filp->f_mapping->host->i_private; unsigned long flags; spin_lock_irqsave(hba->host->host_lock, flags); pm_runtime_get_sync(hba->dev); ufshcd_hold(hba, false); spin_lock_irqsave(hba->host->host_lock, flags); /* * simulating a dummy error in order to "convince" * eh_work to actually reset the controller Loading @@ -1421,9 +1423,13 @@ static ssize_t ufsdbg_reset_controller_write(struct file *filp, hba->saved_err |= INT_FATAL_ERRORS; hba->silence_err_logs = true; schedule_work(&hba->eh_work); spin_unlock_irqrestore(hba->host->host_lock, flags); flush_work(&hba->eh_work); ufshcd_release(hba, false); pm_runtime_put_sync(hba->dev); return cnt; } Loading drivers/scsi/ufs/ufshcd.c +82 −53 Original line number Diff line number Diff line Loading @@ -2576,6 +2576,13 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) return SCSI_MLQUEUE_HOST_BUSY; spin_lock_irqsave(hba->host->host_lock, flags); /* if error handling is in progress, return host busy */ if (ufshcd_eh_in_progress(hba)) { err = SCSI_MLQUEUE_HOST_BUSY; goto out_unlock; } switch (hba->ufshcd_state) { case UFSHCD_STATE_OPERATIONAL: break; Loading @@ -2593,13 +2600,6 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) cmd->scsi_done(cmd); goto out_unlock; } /* if error handling is in progress, don't issue commands */ if (ufshcd_eh_in_progress(hba)) { set_host_byte(cmd, DID_ERROR); cmd->scsi_done(cmd); goto out_unlock; } spin_unlock_irqrestore(hba->host->host_lock, flags); hba->req_abort_count = 0; Loading Loading @@ -3972,31 +3972,49 @@ out: static int ufshcd_link_recovery(struct ufs_hba *hba) { int ret; int ret = 0; unsigned long flags; /* * Check if there is any race with fatal error handling. * If so, wait for it to complete. Even though fatal error * handling does reset and restore in some cases, don't assume * anything out of it. We are just avoiding race here. */ do { spin_lock_irqsave(hba->host->host_lock, flags); hba->ufshcd_state = UFSHCD_STATE_RESET; ufshcd_set_eh_in_progress(hba); if (!(work_pending(&hba->eh_work) || hba->ufshcd_state == UFSHCD_STATE_RESET)) break; spin_unlock_irqrestore(hba->host->host_lock, flags); dev_dbg(hba->dev, "%s: reset in progress\n", __func__); flush_work(&hba->eh_work); } while (1); ret = ufshcd_vops_full_reset(hba); if (ret) dev_warn(hba->dev, "full reset returned %d, trying to recover the link\n", ret); ret = ufshcd_host_reset_and_restore(hba); spin_lock_irqsave(hba->host->host_lock, flags); if (ret) /* * we don't know if previous reset had really reset the host controller * or not. So let's force reset here to be sure. */ hba->ufshcd_state = UFSHCD_STATE_ERROR; ufshcd_clear_eh_in_progress(hba); hba->force_host_reset = true; schedule_work(&hba->eh_work); /* wait for the reset work to finish */ do { if (!(work_pending(&hba->eh_work) || hba->ufshcd_state == UFSHCD_STATE_RESET)) break; spin_unlock_irqrestore(hba->host->host_lock, flags); dev_dbg(hba->dev, "%s: reset in progress\n", __func__); flush_work(&hba->eh_work); spin_lock_irqsave(hba->host->host_lock, flags); } while (1); if (ret) dev_err(hba->dev, "%s: link recovery failed, err %d", __func__, ret); if (!((hba->ufshcd_state == UFSHCD_STATE_OPERATIONAL) && ufshcd_is_link_active(hba))) ret = -ENOLINK; spin_unlock_irqrestore(hba->host->host_lock, flags); return ret; } Loading @@ -4020,8 +4038,7 @@ static int __ufshcd_uic_hibern8_enter(struct ufs_hba *hba) * If link recovery fails then return error so that caller * don't retry the hibern8 enter again. */ if (ufshcd_link_recovery(hba)) ret = -ENOLINK; ret = ufshcd_link_recovery(hba); } else { dev_dbg(hba->dev, "%s: Hibern8 Enter at %lld us", __func__, ktime_to_us(ktime_get())); Loading Loading @@ -5553,11 +5570,9 @@ static void ufshcd_err_handler(struct work_struct *work) hba = container_of(work, struct ufs_hba, eh_work); spin_lock_irqsave(hba->host->host_lock, flags); ufsdbg_set_err_state(hba); pm_runtime_get_sync(hba->dev); ufshcd_hold_all(hba); spin_lock_irqsave(hba->host->host_lock, flags); if (hba->ufshcd_state == UFSHCD_STATE_RESET) goto out; Loading Loading @@ -5593,7 +5608,8 @@ static void ufshcd_err_handler(struct work_struct *work) } } if ((hba->saved_err & INT_FATAL_ERRORS) || hba->saved_ce_err || if ((hba->saved_err & INT_FATAL_ERRORS) || hba->saved_ce_err || hba->force_host_reset || ((hba->saved_err & UIC_ERROR) && (hba->saved_uic_err & (UFSHCD_UIC_DL_PA_INIT_ERROR | UFSHCD_UIC_DL_NAC_RECEIVED_ERROR | Loading Loading @@ -5681,6 +5697,7 @@ skip_pending_xfer_clear: hba->saved_err = 0; hba->saved_uic_err = 0; hba->saved_ce_err = 0; hba->force_host_reset = false; } skip_err_handling: Loading @@ -5692,12 +5709,9 @@ skip_err_handling: } hba->silence_err_logs = false; ufshcd_clear_eh_in_progress(hba); out: ufshcd_clear_eh_in_progress(hba); spin_unlock_irqrestore(hba->host->host_lock, flags); ufshcd_scsi_unblock_requests(hba); ufshcd_release_all(hba); pm_runtime_put_sync(hba->dev); } static void ufshcd_update_uic_reg_hist(struct ufs_uic_err_reg_hist *reg_hist, Loading Loading @@ -5798,8 +5812,11 @@ static void ufshcd_check_errors(struct ufs_hba *hba) /* handle fatal errors only when link is functional */ if (hba->ufshcd_state == UFSHCD_STATE_OPERATIONAL) { /* block commands from scsi mid-layer */ __ufshcd_scsi_block_requests(hba); /* * Set error handling in progress flag early so that we * don't issue new requests any more. */ ufshcd_set_eh_in_progress(hba); hba->ufshcd_state = UFSHCD_STATE_ERROR; schedule_work(&hba->eh_work); Loading Loading @@ -6303,6 +6320,11 @@ static int ufshcd_reset_and_restore(struct ufs_hba *hba) int retries = MAX_HOST_RESET_RETRIES; do { err = ufshcd_vops_full_reset(hba); if (err) dev_warn(hba->dev, "%s: full reset returned %d\n", __func__, err); err = ufshcd_host_reset_and_restore(hba); } while (err && --retries); Loading @@ -6326,13 +6348,12 @@ static int ufshcd_reset_and_restore(struct ufs_hba *hba) */ static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd) { int err; int err = SUCCESS; unsigned long flags; struct ufs_hba *hba; hba = shost_priv(cmd->device->host); ufshcd_hold_all(hba); /* * Check if there is any race with fatal error handling. * If so, wait for it to complete. Even though fatal error Loading @@ -6345,29 +6366,37 @@ static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd) hba->ufshcd_state == UFSHCD_STATE_RESET)) break; spin_unlock_irqrestore(hba->host->host_lock, flags); dev_dbg(hba->dev, "%s: reset in progress\n", __func__); dev_err(hba->dev, "%s: reset in progress - 1\n", __func__); flush_work(&hba->eh_work); } while (1); hba->ufshcd_state = UFSHCD_STATE_RESET; ufshcd_set_eh_in_progress(hba); spin_unlock_irqrestore(hba->host->host_lock, flags); ufshcd_update_error_stats(hba, UFS_ERR_EH); err = ufshcd_reset_and_restore(hba); /* * we don't know if previous reset had really reset the host controller * or not. So let's force reset here to be sure. */ hba->ufshcd_state = UFSHCD_STATE_ERROR; hba->force_host_reset = true; schedule_work(&hba->eh_work); /* wait for the reset work to finish */ do { if (!(work_pending(&hba->eh_work) || hba->ufshcd_state == UFSHCD_STATE_RESET)) break; spin_unlock_irqrestore(hba->host->host_lock, flags); dev_err(hba->dev, "%s: reset in progress - 2\n", __func__); flush_work(&hba->eh_work); spin_lock_irqsave(hba->host->host_lock, flags); if (!err) { err = SUCCESS; hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL; } else { } while (1); if (!((hba->ufshcd_state == UFSHCD_STATE_OPERATIONAL) && ufshcd_is_link_active(hba))) { err = FAILED; hba->ufshcd_state = UFSHCD_STATE_ERROR; } ufshcd_clear_eh_in_progress(hba); spin_unlock_irqrestore(hba->host->host_lock, flags); ufshcd_release_all(hba); return err; } Loading drivers/scsi/ufs/ufshcd.h +1 −0 Original line number Diff line number Diff line Loading @@ -807,6 +807,7 @@ struct ufs_hba { u32 saved_uic_err; u32 saved_ce_err; bool silence_err_logs; bool force_host_reset; /* Device management request data */ struct ufs_dev_cmd dev_cmd; Loading Loading
drivers/scsi/ufs/ufs-debugfs.c +8 −2 Original line number Diff line number Diff line Loading @@ -1412,8 +1412,10 @@ static ssize_t ufsdbg_reset_controller_write(struct file *filp, struct ufs_hba *hba = filp->f_mapping->host->i_private; unsigned long flags; spin_lock_irqsave(hba->host->host_lock, flags); pm_runtime_get_sync(hba->dev); ufshcd_hold(hba, false); spin_lock_irqsave(hba->host->host_lock, flags); /* * simulating a dummy error in order to "convince" * eh_work to actually reset the controller Loading @@ -1421,9 +1423,13 @@ static ssize_t ufsdbg_reset_controller_write(struct file *filp, hba->saved_err |= INT_FATAL_ERRORS; hba->silence_err_logs = true; schedule_work(&hba->eh_work); spin_unlock_irqrestore(hba->host->host_lock, flags); flush_work(&hba->eh_work); ufshcd_release(hba, false); pm_runtime_put_sync(hba->dev); return cnt; } Loading
drivers/scsi/ufs/ufshcd.c +82 −53 Original line number Diff line number Diff line Loading @@ -2576,6 +2576,13 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) return SCSI_MLQUEUE_HOST_BUSY; spin_lock_irqsave(hba->host->host_lock, flags); /* if error handling is in progress, return host busy */ if (ufshcd_eh_in_progress(hba)) { err = SCSI_MLQUEUE_HOST_BUSY; goto out_unlock; } switch (hba->ufshcd_state) { case UFSHCD_STATE_OPERATIONAL: break; Loading @@ -2593,13 +2600,6 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) cmd->scsi_done(cmd); goto out_unlock; } /* if error handling is in progress, don't issue commands */ if (ufshcd_eh_in_progress(hba)) { set_host_byte(cmd, DID_ERROR); cmd->scsi_done(cmd); goto out_unlock; } spin_unlock_irqrestore(hba->host->host_lock, flags); hba->req_abort_count = 0; Loading Loading @@ -3972,31 +3972,49 @@ out: static int ufshcd_link_recovery(struct ufs_hba *hba) { int ret; int ret = 0; unsigned long flags; /* * Check if there is any race with fatal error handling. * If so, wait for it to complete. Even though fatal error * handling does reset and restore in some cases, don't assume * anything out of it. We are just avoiding race here. */ do { spin_lock_irqsave(hba->host->host_lock, flags); hba->ufshcd_state = UFSHCD_STATE_RESET; ufshcd_set_eh_in_progress(hba); if (!(work_pending(&hba->eh_work) || hba->ufshcd_state == UFSHCD_STATE_RESET)) break; spin_unlock_irqrestore(hba->host->host_lock, flags); dev_dbg(hba->dev, "%s: reset in progress\n", __func__); flush_work(&hba->eh_work); } while (1); ret = ufshcd_vops_full_reset(hba); if (ret) dev_warn(hba->dev, "full reset returned %d, trying to recover the link\n", ret); ret = ufshcd_host_reset_and_restore(hba); spin_lock_irqsave(hba->host->host_lock, flags); if (ret) /* * we don't know if previous reset had really reset the host controller * or not. So let's force reset here to be sure. */ hba->ufshcd_state = UFSHCD_STATE_ERROR; ufshcd_clear_eh_in_progress(hba); hba->force_host_reset = true; schedule_work(&hba->eh_work); /* wait for the reset work to finish */ do { if (!(work_pending(&hba->eh_work) || hba->ufshcd_state == UFSHCD_STATE_RESET)) break; spin_unlock_irqrestore(hba->host->host_lock, flags); dev_dbg(hba->dev, "%s: reset in progress\n", __func__); flush_work(&hba->eh_work); spin_lock_irqsave(hba->host->host_lock, flags); } while (1); if (ret) dev_err(hba->dev, "%s: link recovery failed, err %d", __func__, ret); if (!((hba->ufshcd_state == UFSHCD_STATE_OPERATIONAL) && ufshcd_is_link_active(hba))) ret = -ENOLINK; spin_unlock_irqrestore(hba->host->host_lock, flags); return ret; } Loading @@ -4020,8 +4038,7 @@ static int __ufshcd_uic_hibern8_enter(struct ufs_hba *hba) * If link recovery fails then return error so that caller * don't retry the hibern8 enter again. */ if (ufshcd_link_recovery(hba)) ret = -ENOLINK; ret = ufshcd_link_recovery(hba); } else { dev_dbg(hba->dev, "%s: Hibern8 Enter at %lld us", __func__, ktime_to_us(ktime_get())); Loading Loading @@ -5553,11 +5570,9 @@ static void ufshcd_err_handler(struct work_struct *work) hba = container_of(work, struct ufs_hba, eh_work); spin_lock_irqsave(hba->host->host_lock, flags); ufsdbg_set_err_state(hba); pm_runtime_get_sync(hba->dev); ufshcd_hold_all(hba); spin_lock_irqsave(hba->host->host_lock, flags); if (hba->ufshcd_state == UFSHCD_STATE_RESET) goto out; Loading Loading @@ -5593,7 +5608,8 @@ static void ufshcd_err_handler(struct work_struct *work) } } if ((hba->saved_err & INT_FATAL_ERRORS) || hba->saved_ce_err || if ((hba->saved_err & INT_FATAL_ERRORS) || hba->saved_ce_err || hba->force_host_reset || ((hba->saved_err & UIC_ERROR) && (hba->saved_uic_err & (UFSHCD_UIC_DL_PA_INIT_ERROR | UFSHCD_UIC_DL_NAC_RECEIVED_ERROR | Loading Loading @@ -5681,6 +5697,7 @@ skip_pending_xfer_clear: hba->saved_err = 0; hba->saved_uic_err = 0; hba->saved_ce_err = 0; hba->force_host_reset = false; } skip_err_handling: Loading @@ -5692,12 +5709,9 @@ skip_err_handling: } hba->silence_err_logs = false; ufshcd_clear_eh_in_progress(hba); out: ufshcd_clear_eh_in_progress(hba); spin_unlock_irqrestore(hba->host->host_lock, flags); ufshcd_scsi_unblock_requests(hba); ufshcd_release_all(hba); pm_runtime_put_sync(hba->dev); } static void ufshcd_update_uic_reg_hist(struct ufs_uic_err_reg_hist *reg_hist, Loading Loading @@ -5798,8 +5812,11 @@ static void ufshcd_check_errors(struct ufs_hba *hba) /* handle fatal errors only when link is functional */ if (hba->ufshcd_state == UFSHCD_STATE_OPERATIONAL) { /* block commands from scsi mid-layer */ __ufshcd_scsi_block_requests(hba); /* * Set error handling in progress flag early so that we * don't issue new requests any more. */ ufshcd_set_eh_in_progress(hba); hba->ufshcd_state = UFSHCD_STATE_ERROR; schedule_work(&hba->eh_work); Loading Loading @@ -6303,6 +6320,11 @@ static int ufshcd_reset_and_restore(struct ufs_hba *hba) int retries = MAX_HOST_RESET_RETRIES; do { err = ufshcd_vops_full_reset(hba); if (err) dev_warn(hba->dev, "%s: full reset returned %d\n", __func__, err); err = ufshcd_host_reset_and_restore(hba); } while (err && --retries); Loading @@ -6326,13 +6348,12 @@ static int ufshcd_reset_and_restore(struct ufs_hba *hba) */ static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd) { int err; int err = SUCCESS; unsigned long flags; struct ufs_hba *hba; hba = shost_priv(cmd->device->host); ufshcd_hold_all(hba); /* * Check if there is any race with fatal error handling. * If so, wait for it to complete. Even though fatal error Loading @@ -6345,29 +6366,37 @@ static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd) hba->ufshcd_state == UFSHCD_STATE_RESET)) break; spin_unlock_irqrestore(hba->host->host_lock, flags); dev_dbg(hba->dev, "%s: reset in progress\n", __func__); dev_err(hba->dev, "%s: reset in progress - 1\n", __func__); flush_work(&hba->eh_work); } while (1); hba->ufshcd_state = UFSHCD_STATE_RESET; ufshcd_set_eh_in_progress(hba); spin_unlock_irqrestore(hba->host->host_lock, flags); ufshcd_update_error_stats(hba, UFS_ERR_EH); err = ufshcd_reset_and_restore(hba); /* * we don't know if previous reset had really reset the host controller * or not. So let's force reset here to be sure. */ hba->ufshcd_state = UFSHCD_STATE_ERROR; hba->force_host_reset = true; schedule_work(&hba->eh_work); /* wait for the reset work to finish */ do { if (!(work_pending(&hba->eh_work) || hba->ufshcd_state == UFSHCD_STATE_RESET)) break; spin_unlock_irqrestore(hba->host->host_lock, flags); dev_err(hba->dev, "%s: reset in progress - 2\n", __func__); flush_work(&hba->eh_work); spin_lock_irqsave(hba->host->host_lock, flags); if (!err) { err = SUCCESS; hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL; } else { } while (1); if (!((hba->ufshcd_state == UFSHCD_STATE_OPERATIONAL) && ufshcd_is_link_active(hba))) { err = FAILED; hba->ufshcd_state = UFSHCD_STATE_ERROR; } ufshcd_clear_eh_in_progress(hba); spin_unlock_irqrestore(hba->host->host_lock, flags); ufshcd_release_all(hba); return err; } Loading
drivers/scsi/ufs/ufshcd.h +1 −0 Original line number Diff line number Diff line Loading @@ -807,6 +807,7 @@ struct ufs_hba { u32 saved_uic_err; u32 saved_ce_err; bool silence_err_logs; bool force_host_reset; /* Device management request data */ struct ufs_dev_cmd dev_cmd; Loading