Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ed02bfa4 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull SCSI fixes from James Bottomley:
 "This is a set of ten fixes: 8 for UFS including four static checker
  warnings, a potential null deref in the voltage regulator code, a race
  on module unload, a ref counting fix on the well known LUNs which made
  it impossible to remove the ufs module and fix to correct the
  information in pwr_info.

  In addition to UFS, there's a blacklist for the Intel Multi-Flex array
  which chokes on report supported operation codes and a fix to an oops
  in bnx2fc caused by shared skbs"

[ For us non-SCSI people: "UFS" here is "Universal Flash Storage" not
  the filesystem.  - Linus ]

* tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi:
  ufs: fix NULL dereference when no regulators are defined
  ufs: ensure clk gating work is finished before module unloading
  scsi: ufs: fix static checker warning in ufshcd_parse_clock_info
  scsi: ufs: fix static checker warning in __ufshcd_setup_clocks
  scsi: ufs: fix static checker warning in ufshcd_populate_vreg
  scsi: ufs: fix static checker errors in ufshcd_system_suspend
  ufs: fix power info after link start-up
  ufs: fix reference counting of W-LUs
  scsi: add Intel Multi-Flex to scsi scan blacklist
  bnx2fc: do not add shared skbs to the fcoe_rx_list
parents 88910638 3e660fbe
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -412,6 +412,7 @@ static int bnx2fc_rcv(struct sk_buff *skb, struct net_device *dev,
	struct fc_frame_header *fh;
	struct fcoe_rcv_info *fr;
	struct fcoe_percpu_s *bg;
	struct sk_buff *tmp_skb;
	unsigned short oxid;

	interface = container_of(ptype, struct bnx2fc_interface,
@@ -424,6 +425,12 @@ static int bnx2fc_rcv(struct sk_buff *skb, struct net_device *dev,
		goto err;
	}

	tmp_skb = skb_share_check(skb, GFP_ATOMIC);
	if (!tmp_skb)
		goto err;

	skb = tmp_skb;

	if (unlikely(eth_hdr(skb)->h_proto != htons(ETH_P_FCOE))) {
		printk(KERN_ERR PFX "bnx2fc_rcv: Wrong FC type frame\n");
		goto err;
+1 −0
Original line number Diff line number Diff line
@@ -202,6 +202,7 @@ static struct {
	{"IOMEGA", "Io20S         *F", NULL, BLIST_KEY},
	{"INSITE", "Floptical   F*8I", NULL, BLIST_KEY},
	{"INSITE", "I325VM", NULL, BLIST_KEY},
	{"Intel", "Multi-Flex", NULL, BLIST_NO_RSOC},
	{"iRiver", "iFP Mass Driver", NULL, BLIST_NOT_LOCKABLE | BLIST_INQUIRY_36},
	{"LASOUND", "CDX7405", "3.10", BLIST_MAX5LUN | BLIST_SINGLELUN},
	{"MATSHITA", "PD-1", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+5 −10
Original line number Diff line number Diff line
@@ -102,7 +102,6 @@ static int ufshcd_parse_clock_info(struct ufs_hba *hba)
	clkfreq = devm_kzalloc(dev, sz * sizeof(*clkfreq),
			GFP_KERNEL);
	if (!clkfreq) {
		dev_err(dev, "%s: no memory\n", "freq-table-hz");
		ret = -ENOMEM;
		goto out;
	}
@@ -112,19 +111,19 @@ static int ufshcd_parse_clock_info(struct ufs_hba *hba)
	if (ret && (ret != -EINVAL)) {
		dev_err(dev, "%s: error reading array %d\n",
				"freq-table-hz", ret);
		goto free_clkfreq;
		return ret;
	}

	for (i = 0; i < sz; i += 2) {
		ret = of_property_read_string_index(np,
				"clock-names", i/2, (const char **)&name);
		if (ret)
			goto free_clkfreq;
			goto out;

		clki = devm_kzalloc(dev, sizeof(*clki), GFP_KERNEL);
		if (!clki) {
			ret = -ENOMEM;
			goto free_clkfreq;
			goto out;
		}

		clki->min_freq = clkfreq[i];
@@ -134,8 +133,6 @@ static int ufshcd_parse_clock_info(struct ufs_hba *hba)
				clki->min_freq, clki->max_freq, clki->name);
		list_add_tail(&clki->list, &hba->clk_list_head);
	}
free_clkfreq:
	kfree(clkfreq);
out:
	return ret;
}
@@ -162,10 +159,8 @@ static int ufshcd_populate_vreg(struct device *dev, const char *name,
	}

	vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
	if (!vreg) {
		dev_err(dev, "No memory for %s regulator\n", name);
		goto out;
	}
	if (!vreg)
		return -ENOMEM;

	vreg->name = kstrdup(name, GFP_KERNEL);

+64 −40
Original line number Diff line number Diff line
@@ -744,6 +744,8 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba)
	if (!ufshcd_is_clkgating_allowed(hba))
		return;
	device_remove_file(hba->dev, &hba->clk_gating.delay_attr);
	cancel_work_sync(&hba->clk_gating.ungate_work);
	cancel_delayed_work_sync(&hba->clk_gating.gate_work);
}

/* Must be called with host lock acquired */
@@ -2246,6 +2248,22 @@ static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba)
	return ret;
}

 /**
 * ufshcd_init_pwr_info - setting the POR (power on reset)
 * values in hba power info
 * @hba: per-adapter instance
 */
static void ufshcd_init_pwr_info(struct ufs_hba *hba)
{
	hba->pwr_info.gear_rx = UFS_PWM_G1;
	hba->pwr_info.gear_tx = UFS_PWM_G1;
	hba->pwr_info.lane_rx = 1;
	hba->pwr_info.lane_tx = 1;
	hba->pwr_info.pwr_rx = SLOWAUTO_MODE;
	hba->pwr_info.pwr_tx = SLOWAUTO_MODE;
	hba->pwr_info.hs_rate = 0;
}

/**
 * ufshcd_get_max_pwr_mode - reads the max power mode negotiated with device
 * @hba: per-adapter instance
@@ -2844,8 +2862,13 @@ static void ufshcd_slave_destroy(struct scsi_device *sdev)
	hba = shost_priv(sdev->host);
	scsi_deactivate_tcq(sdev, hba->nutrs);
	/* Drop the reference as it won't be needed anymore */
	if (ufshcd_scsi_to_upiu_lun(sdev->lun) == UFS_UPIU_UFS_DEVICE_WLUN)
	if (ufshcd_scsi_to_upiu_lun(sdev->lun) == UFS_UPIU_UFS_DEVICE_WLUN) {
		unsigned long flags;

		spin_lock_irqsave(hba->host->host_lock, flags);
		hba->sdev_ufs_device = NULL;
		spin_unlock_irqrestore(hba->host->host_lock, flags);
	}
}

/**
@@ -4062,6 +4085,8 @@ static void ufshcd_init_icc_levels(struct ufs_hba *hba)
static int ufshcd_scsi_add_wlus(struct ufs_hba *hba)
{
	int ret = 0;
	struct scsi_device *sdev_rpmb;
	struct scsi_device *sdev_boot;

	hba->sdev_ufs_device = __scsi_add_device(hba->host, 0, 0,
		ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_UFS_DEVICE_WLUN), NULL);
@@ -4070,56 +4095,33 @@ static int ufshcd_scsi_add_wlus(struct ufs_hba *hba)
		hba->sdev_ufs_device = NULL;
		goto out;
	}
	scsi_device_put(hba->sdev_ufs_device);

	hba->sdev_boot = __scsi_add_device(hba->host, 0, 0,
	sdev_boot = __scsi_add_device(hba->host, 0, 0,
		ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_BOOT_WLUN), NULL);
	if (IS_ERR(hba->sdev_boot)) {
		ret = PTR_ERR(hba->sdev_boot);
		hba->sdev_boot = NULL;
	if (IS_ERR(sdev_boot)) {
		ret = PTR_ERR(sdev_boot);
		goto remove_sdev_ufs_device;
	}
	scsi_device_put(sdev_boot);

	hba->sdev_rpmb = __scsi_add_device(hba->host, 0, 0,
	sdev_rpmb = __scsi_add_device(hba->host, 0, 0,
		ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_RPMB_WLUN), NULL);
	if (IS_ERR(hba->sdev_rpmb)) {
		ret = PTR_ERR(hba->sdev_rpmb);
		hba->sdev_rpmb = NULL;
	if (IS_ERR(sdev_rpmb)) {
		ret = PTR_ERR(sdev_rpmb);
		goto remove_sdev_boot;
	}
	scsi_device_put(sdev_rpmb);
	goto out;

remove_sdev_boot:
	scsi_remove_device(hba->sdev_boot);
	scsi_remove_device(sdev_boot);
remove_sdev_ufs_device:
	scsi_remove_device(hba->sdev_ufs_device);
out:
	return ret;
}

/**
 * ufshcd_scsi_remove_wlus - Removes the W-LUs which were added by
 *			     ufshcd_scsi_add_wlus()
 * @hba: per-adapter instance
 *
 */
static void ufshcd_scsi_remove_wlus(struct ufs_hba *hba)
{
	if (hba->sdev_ufs_device) {
		scsi_remove_device(hba->sdev_ufs_device);
		hba->sdev_ufs_device = NULL;
	}

	if (hba->sdev_boot) {
		scsi_remove_device(hba->sdev_boot);
		hba->sdev_boot = NULL;
	}

	if (hba->sdev_rpmb) {
		scsi_remove_device(hba->sdev_rpmb);
		hba->sdev_rpmb = NULL;
	}
}

/**
 * ufshcd_probe_hba - probe hba to detect device and initialize
 * @hba: per-adapter instance
@@ -4134,6 +4136,8 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
	if (ret)
		goto out;

	ufshcd_init_pwr_info(hba);

	/* UniPro link is active now */
	ufshcd_set_link_active(hba);

@@ -4264,12 +4268,18 @@ static int ufshcd_config_vreg_load(struct device *dev, struct ufs_vreg *vreg,
static inline int ufshcd_config_vreg_lpm(struct ufs_hba *hba,
					 struct ufs_vreg *vreg)
{
	if (!vreg)
		return 0;

	return ufshcd_config_vreg_load(hba->dev, vreg, UFS_VREG_LPM_LOAD_UA);
}

static inline int ufshcd_config_vreg_hpm(struct ufs_hba *hba,
					 struct ufs_vreg *vreg)
{
	if (!vreg)
		return 0;

	return ufshcd_config_vreg_load(hba->dev, vreg, vreg->max_uA);
}

@@ -4471,7 +4481,7 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on,
			if (!IS_ERR_OR_NULL(clki->clk) && clki->enabled)
				clk_disable_unprepare(clki->clk);
		}
	} else if (!ret && on) {
	} else if (on) {
		spin_lock_irqsave(hba->host->host_lock, flags);
		hba->clk_gating.state = CLKS_ON;
		spin_unlock_irqrestore(hba->host->host_lock, flags);
@@ -4675,11 +4685,25 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba,
{
	unsigned char cmd[6] = { START_STOP };
	struct scsi_sense_hdr sshdr;
	struct scsi_device *sdp = hba->sdev_ufs_device;
	struct scsi_device *sdp;
	unsigned long flags;
	int ret;

	if (!sdp || !scsi_device_online(sdp))
		return -ENODEV;
	spin_lock_irqsave(hba->host->host_lock, flags);
	sdp = hba->sdev_ufs_device;
	if (sdp) {
		ret = scsi_device_get(sdp);
		if (!ret && !scsi_device_online(sdp)) {
			ret = -ENODEV;
			scsi_device_put(sdp);
		}
	} else {
		ret = -ENODEV;
	}
	spin_unlock_irqrestore(hba->host->host_lock, flags);

	if (ret)
		return ret;

	/*
	 * If scsi commands fail, the scsi mid-layer schedules scsi error-
@@ -4718,6 +4742,7 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba,
	if (!ret)
		hba->curr_dev_pwr_mode = pwr_mode;
out:
	scsi_device_put(sdp);
	hba->host->eh_noresume = 0;
	return ret;
}
@@ -5087,7 +5112,7 @@ int ufshcd_system_suspend(struct ufs_hba *hba)
	int ret = 0;

	if (!hba || !hba->is_powered)
		goto out;
		return 0;

	if (pm_runtime_suspended(hba->dev)) {
		if (hba->rpm_lvl == hba->spm_lvl)
@@ -5231,7 +5256,6 @@ EXPORT_SYMBOL(ufshcd_shutdown);
void ufshcd_remove(struct ufs_hba *hba)
{
	scsi_remove_host(hba->host);
	ufshcd_scsi_remove_wlus(hba);
	/* disable interrupts */
	ufshcd_disable_intr(hba, hba->intr_mask);
	ufshcd_hba_stop(hba);
+0 −2
Original line number Diff line number Diff line
@@ -392,8 +392,6 @@ struct ufs_hba {
	 * "UFS device" W-LU.
	 */
	struct scsi_device *sdev_ufs_device;
	struct scsi_device *sdev_rpmb;
	struct scsi_device *sdev_boot;

	enum ufs_dev_pwr_mode curr_dev_pwr_mode;
	enum uic_link_state uic_link_state;