Skip to contentSkip to conversation

UFS driver fixes for v3.18

PATCH In review Akinobu Mita 4 participants 7 messages Nov 18, 2014 – Nov 22, 2014 SCSI

lore
Share & tools
lore
#0 lore raw

cover UFS driver fixes for v3.18

This patch series includes two fixes for UFS driver.

The first patch already got reviewed and it was a part of Dolev's various fixes for UFS-PM series (http://marc.info/?l=linux-scsi&m=141405993104015),
but they are not merged scsi-queue yet. So this series also includes it.

The second one is a fix which I have already reported and Dolev agreed with that in http://marc.info/?l=linux-scsi&m=141164131404767

Akinobu Mita (2):
scsi: ufs: fix reference counting of W-LUs
scsi: ufs: fix NULL dereference when no regulators are defined

 drivers/scsi/ufs/ufshcd.c | 80 +++++++++++++++++++++++++----------------------
 drivers/scsi/ufs/ufshcd.h |  2 --
 2 files changed, 42 insertions(+), 40 deletions(-)
Cc Vinayak Holikatti <[email protected]>
Cc Dolev Raviv <[email protected]>
Cc Subhash Jadavani <[email protected]>
Cc Yaniv Gardi <[email protected]>
Cc Sujit Reddy Thumma <[email protected]>
Cc Christoph Hellwig <[email protected]>
Cc "James E.J. Bottomley" <[email protected]>
Signature · 1 line
1.9.1
#1 lore raw

PATCH 1/2 scsi: ufs: fix reference counting of W-LUs

UFS driver adds three well known LUs in the initialization, but those reference counts are not decremented, so it makes ufshcd module impossible to unload.

This fixes it by putting scsi_device_put() in the initalization, and in order to protect concurrent access to hba->sdev_ufs_device (UFS Device W-LU) from manual delete, increment the reference count while requesting device power mode setting.

The rest of W-LUs (hba->sdev_boot and hba->sdev_rpmb) are not directly used from driver, so these references in struct ufs_hba are removed.

Cc Vinayak Holikatti <[email protected]>
Cc Dolev Raviv <[email protected]>
Cc Subhash Jadavani <[email protected]>
Cc Yaniv Gardi <[email protected]>
Cc Sujit Reddy Thumma <[email protected]>
Cc Christoph Hellwig <[email protected]>
Cc "James E.J. Bottomley" <[email protected]>
---
 drivers/scsi/ufs/ufshcd.c | 74 +++++++++++++++++++++++------------------------
 drivers/scsi/ufs/ufshcd.h |  2 --
 2 files changed, 36 insertions(+), 40 deletions(-)
drivers/scsi/ufs/ufshcd.c +36 -38
index 497c38a..59b6544 100644
@@ -2844,8 +2844,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 +4067,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,26 +4077,27 @@ 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:
@@ -4097,30 +4105,6 @@ out:
 }
 
 /**
- * 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
  *
@@ -4675,11 +4659,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 +4716,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;
 }
@@ -5231,7 +5230,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);
drivers/scsi/ufs/ufshcd.h +0 -2
index 58ecdff..4a574aa 100644
@@ -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;
Signature · 1 line
1.9.1
Reviewed-by on v1 1/2
#2 lore raw

RE: [PATCH 1/2] scsi: ufs: fix reference counting of W-LUs

Looks good to me,

-----Original Message-----
From: Akinobu Mita [mailto:[email protected]]
Sent: Tuesday, November 18, 2014 6:03 AM
To: [email protected]
Cc: Akinobu Mita; Akinobu Mita; Vinayak Holikatti; Dolev Raviv; Subhash Jadavani; Yaniv Gardi; Sujit Reddy Thumma; Christoph Hellwig; James E.J. Bottomley
Subject: [PATCH 1/2] scsi: ufs: fix reference counting of W-LUs

UFS driver adds three well known LUs in the initialization, but those reference counts are not decremented, so it makes ufshcd module impossible to unload.

This fixes it by putting scsi_device_put() in the initalization, and in order to protect concurrent access to hba->sdev_ufs_device (UFS Device W-LU) from manual delete, increment the reference count while requesting device power mode setting.

The rest of W-LUs (hba->sdev_boot and hba->sdev_rpmb) are not directly used from driver, so these references in struct ufs_hba are removed.

Cc Vinayak Holikatti <[email protected]>
Cc Dolev Raviv <[email protected]>
Cc Subhash Jadavani <[email protected]>
Cc Yaniv Gardi <[email protected]>
Cc Sujit Reddy Thumma <[email protected]>
Cc Christoph Hellwig <[email protected]>
Cc "James E.J. Bottomley" <[email protected]>
---
 drivers/scsi/ufs/ufshcd.c | 74
+++++++++++++++++++++++------------------------
 drivers/scsi/ufs/ufshcd.h |  2 --
 2 files changed, 36 insertions(+), 40 deletions(-)
drivers/scsi/ufs/ufshcd.c index renamed from drivers/scsi/ufs/ufshcd.c +0 -0

497c38a..59b6544 100644

drivers/scsi/ufs/ufshcd.c +0 -0
@@ -2844,8 +2844,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 +4067,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,26 +4077,27 @@ 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:
@@ -4097,30 +4105,6 @@ out:
}

/**
- * 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
*
@@ -4675,11 +4659,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 +4716,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;
}
@@ -5231,7 +5230,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);

drivers/scsi/ufs/ufshcd.h index renamed from drivers/scsi/ufs/ufshcd.h +0 -0

58ecdff..4a574aa 100644

drivers/scsi/ufs/ufshcd.h +0 -2
@@ -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;

--
1.9.1

#3 lore raw

PATCH 2/2 scsi: ufs: fix NULL dereference when no regulators are defined

In reply to Akinobu Mita

If no voltage supply regulators are defined for the UFS devices (assumed they are always-on), ufshcd_config_vreg_load() can be called on suspend/resume paths with vreg == NULL as hba->vreg_info.vcc* equal to NULL, and it causes NULL pointer dereference.

This fixes it by making ufshcd_config_vreg_{h,l}pm noop when no regulators are defined.

Cc Vinayak Holikatti <[email protected]>
Cc Subhash Jadavani <[email protected]>
Cc Dolev Raviv <[email protected]>
Cc Sujit Reddy Thumma <[email protected]>
Cc Yaniv Gardi <[email protected]>
Cc Christoph Hellwig <[email protected]>
Cc "James E.J. Bottomley" <[email protected]>
---
 drivers/scsi/ufs/ufshcd.c | 6 ++++++
 1 file changed, 6 insertions(+)
drivers/scsi/ufs/ufshcd.c +6 -0
index 59b6544..d18adc4 100644
@@ -4248,12 +4248,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);
 }
 
Signature · 1 line
1.9.1
Reviewed-by on v1 2/2
#4 lore raw

RE: [PATCH 2/2] scsi: ufs: fix NULL dereference when no regulators are defined

-----Original Message-----
From: Akinobu Mita [mailto:[email protected]]
Sent: Tuesday, November 18, 2014 6:03 AM
To: [email protected]
Cc: Akinobu Mita; Akinobu Mita; Vinayak Holikatti; Subhash Jadavani; Dolev Raviv; Sujit Reddy Thumma; Yaniv Gardi; Christoph Hellwig; James E.J. Bottomley
Subject: [PATCH 2/2] scsi: ufs: fix NULL dereference when no regulators are defined

If no voltage supply regulators are defined for the UFS devices (assumed they are always-on), ufshcd_config_vreg_load() can be called on suspend/resume paths with vreg == NULL as hba->vreg_info.vcc* equal to NULL, and it causes NULL pointer dereference.

This fixes it by making ufshcd_config_vreg_{h,l}pm noop when no regulators are defined.

Cc Vinayak Holikatti <[email protected]>
Cc Subhash Jadavani <[email protected]>
Cc Dolev Raviv <[email protected]>
Cc Sujit Reddy Thumma <[email protected]>
Cc Yaniv Gardi <[email protected]>
Cc Christoph Hellwig <[email protected]>
Cc "James E.J. Bottomley" <[email protected]>
---
 drivers/scsi/ufs/ufshcd.c | 6 ++++++
 1 file changed, 6 insertions(+)
drivers/scsi/ufs/ufshcd.c index renamed from drivers/scsi/ufs/ufshcd.c +0 -0

59b6544..d18adc4 100644

drivers/scsi/ufs/ufshcd.c +0 -0
@@ -4248,12 +4248,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); }

--
1.9.1

#5 lore raw
In reply to Akinobu Mita
Quoted 5 lines · Akinobu Mita

This patch series includes two fixes for UFS driver.

The first patch already got reviewed and it was a part of Dolev's various fixes for UFS-PM series (http://marc.info/?l=linux-scsi&m=141405993104015),
but they are not merged scsi-queue yet. So this series also includes it.

Actually that series is missing reviews for this and mother other patches.

Can the UFS community please start reviewing each others patches? Thanks!

#6 lore raw

Hi Chris and Mita,

We will review and test the below patches early next week.

Thanks,
Maya

Quoted 21 lines · Akinobu Mita
Quoted 8 lines

This patch series includes two fixes for UFS driver.

The first patch already got reviewed and it was a part of Dolev's various
fixes for UFS-PM series
(http://marc.info/?l=linux-scsi&m=141405993104015),
but they are not merged scsi-queue yet. So this series also includes it.

Actually that series is missing reviews for this and mother other patches.

Can the UFS community please start reviewing each others patches? Thanks!

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Signature · 5 lines
Maya Erez
Qualcomm Israel, on behalf of Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
Collaborative Project