Commit 1c8ac1c4 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi

Pull SCSI fixes from James Bottomley:
 "Four fixes, three in drivers.

  The two biggest fixes are ufs and the remaining driver and core fix
  are small and obvious (and the core fix is low risk)"

* tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi:
  scsi: ufs: core: Fix a race condition related to device management
  scsi: core: Fix warning in scsi_alloc_sgtables()
  scsi: ufs: host: Hold reference returned by of_parse_phandle()
  scsi: mpt3sas: Stop fw fault watchdog work item during system shutdown
parents bb83c99d f5c2976e
...@@ -11386,6 +11386,7 @@ scsih_shutdown(struct pci_dev *pdev) ...@@ -11386,6 +11386,7 @@ scsih_shutdown(struct pci_dev *pdev)
_scsih_ir_shutdown(ioc); _scsih_ir_shutdown(ioc);
_scsih_nvme_shutdown(ioc); _scsih_nvme_shutdown(ioc);
mpt3sas_base_mask_interrupts(ioc); mpt3sas_base_mask_interrupts(ioc);
mpt3sas_base_stop_watchdog(ioc);
ioc->shost_recovery = 1; ioc->shost_recovery = 1;
mpt3sas_base_make_ioc_ready(ioc, SOFT_RESET); mpt3sas_base_make_ioc_ready(ioc, SOFT_RESET);
ioc->shost_recovery = 0; ioc->shost_recovery = 0;
......
...@@ -450,7 +450,7 @@ static int sg_io(struct scsi_device *sdev, struct sg_io_hdr *hdr, fmode_t mode) ...@@ -450,7 +450,7 @@ static int sg_io(struct scsi_device *sdev, struct sg_io_hdr *hdr, fmode_t mode)
goto out_put_request; goto out_put_request;
ret = 0; ret = 0;
if (hdr->iovec_count) { if (hdr->iovec_count && hdr->dxfer_len) {
struct iov_iter i; struct iov_iter i;
struct iovec *iov = NULL; struct iovec *iov = NULL;
......
...@@ -2953,37 +2953,59 @@ ufshcd_dev_cmd_completion(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) ...@@ -2953,37 +2953,59 @@ ufshcd_dev_cmd_completion(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
static int ufshcd_wait_for_dev_cmd(struct ufs_hba *hba, static int ufshcd_wait_for_dev_cmd(struct ufs_hba *hba,
struct ufshcd_lrb *lrbp, int max_timeout) struct ufshcd_lrb *lrbp, int max_timeout)
{ {
int err = 0; unsigned long time_left = msecs_to_jiffies(max_timeout);
unsigned long time_left;
unsigned long flags; unsigned long flags;
bool pending;
int err;
retry:
time_left = wait_for_completion_timeout(hba->dev_cmd.complete, time_left = wait_for_completion_timeout(hba->dev_cmd.complete,
msecs_to_jiffies(max_timeout)); time_left);
spin_lock_irqsave(hba->host->host_lock, flags);
hba->dev_cmd.complete = NULL;
if (likely(time_left)) { if (likely(time_left)) {
/*
* The completion handler called complete() and the caller of
* this function still owns the @lrbp tag so the code below does
* not trigger any race conditions.
*/
hba->dev_cmd.complete = NULL;
err = ufshcd_get_tr_ocs(lrbp); err = ufshcd_get_tr_ocs(lrbp);
if (!err) if (!err)
err = ufshcd_dev_cmd_completion(hba, lrbp); err = ufshcd_dev_cmd_completion(hba, lrbp);
} } else {
spin_unlock_irqrestore(hba->host->host_lock, flags);
if (!time_left) {
err = -ETIMEDOUT; err = -ETIMEDOUT;
dev_dbg(hba->dev, "%s: dev_cmd request timedout, tag %d\n", dev_dbg(hba->dev, "%s: dev_cmd request timedout, tag %d\n",
__func__, lrbp->task_tag); __func__, lrbp->task_tag);
if (!ufshcd_clear_cmds(hba, 1U << lrbp->task_tag)) if (ufshcd_clear_cmds(hba, 1U << lrbp->task_tag) == 0) {
/* successfully cleared the command, retry if needed */ /* successfully cleared the command, retry if needed */
err = -EAGAIN; err = -EAGAIN;
/* /*
* in case of an error, after clearing the doorbell, * Since clearing the command succeeded we also need to
* we also need to clear the outstanding_request * clear the task tag bit from the outstanding_reqs
* field in hba * variable.
*/ */
spin_lock_irqsave(&hba->outstanding_lock, flags); spin_lock_irqsave(&hba->outstanding_lock, flags);
__clear_bit(lrbp->task_tag, &hba->outstanding_reqs); pending = test_bit(lrbp->task_tag,
&hba->outstanding_reqs);
if (pending) {
hba->dev_cmd.complete = NULL;
__clear_bit(lrbp->task_tag,
&hba->outstanding_reqs);
}
spin_unlock_irqrestore(&hba->outstanding_lock, flags); spin_unlock_irqrestore(&hba->outstanding_lock, flags);
if (!pending) {
/*
* The completion handler ran while we tried to
* clear the command.
*/
time_left = 1;
goto retry;
}
} else {
dev_err(hba->dev, "%s: failed to clear tag %d\n",
__func__, lrbp->task_tag);
}
} }
return err; return err;
......
...@@ -108,6 +108,17 @@ static int ufshcd_parse_clock_info(struct ufs_hba *hba) ...@@ -108,6 +108,17 @@ static int ufshcd_parse_clock_info(struct ufs_hba *hba)
return ret; return ret;
} }
static bool phandle_exists(const struct device_node *np,
const char *phandle_name, int index)
{
struct device_node *parse_np = of_parse_phandle(np, phandle_name, index);
if (parse_np)
of_node_put(parse_np);
return parse_np != NULL;
}
#define MAX_PROP_SIZE 32 #define MAX_PROP_SIZE 32
static int ufshcd_populate_vreg(struct device *dev, const char *name, static int ufshcd_populate_vreg(struct device *dev, const char *name,
struct ufs_vreg **out_vreg) struct ufs_vreg **out_vreg)
...@@ -122,7 +133,7 @@ static int ufshcd_populate_vreg(struct device *dev, const char *name, ...@@ -122,7 +133,7 @@ static int ufshcd_populate_vreg(struct device *dev, const char *name,
} }
snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", name); snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", name);
if (!of_parse_phandle(np, prop_name, 0)) { if (!phandle_exists(np, prop_name, 0)) {
dev_info(dev, "%s: Unable to find %s regulator, assuming enabled\n", dev_info(dev, "%s: Unable to find %s regulator, assuming enabled\n",
__func__, prop_name); __func__, prop_name);
goto out; goto out;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment