scsi: squash of multiple fixes for msm-4.4 kernel
This change is the squash of following commits from msm-4.4 kernel:
<36c183b7> ("scsi: Adjust DBD setting in mode sense for caching mode page per LLD")
<d2e7a77a> ("scsi: sd: reduce log level for suspend/resume log messages")
<c6b82e8b> ("scsi: Allow auto suspend override by low-level driver")
<edf4a84a> ("scsi: pm: fix null pointer access during sg_open")
<d8a84438> ("scsi: pm: fix deadlock condition")
<2b80aee4> ("scsi: pm: keep request queue and scsi device runtime status in sync")
<628aaf1b> ("scsi: reduce the informational log messages during initial probe")
<fe64842c> ("scsi: sd: remove check_events callback")
<2f82ca7b> ("scsi: pm: Remove use of CONFIG_PM_RUNTIME")
Change-Id: Ia8430f5c42dd66dbb044733eaa30d0ccd097b3c9
Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c
index b44c1bb..af17066 100644
--- a/drivers/scsi/scsi_pm.c
+++ b/drivers/scsi/scsi_pm.c
@@ -16,6 +16,9 @@
#include "scsi_priv.h"
+static int do_scsi_runtime_resume(struct device *dev,
+ const struct dev_pm_ops *pm);
+
#ifdef CONFIG_PM_SLEEP
static int do_scsi_suspend(struct device *dev, const struct dev_pm_ops *pm)
@@ -77,10 +80,22 @@
scsi_device_resume(to_scsi_device(dev));
dev_dbg(dev, "scsi resume: %d\n", err);
- if (err == 0) {
+ if (err == 0 && (cb != do_scsi_runtime_resume)) {
pm_runtime_disable(dev);
- pm_runtime_set_active(dev);
+ err = pm_runtime_set_active(dev);
pm_runtime_enable(dev);
+
+ if (!err && scsi_is_sdev_device(dev)) {
+ struct scsi_device *sdev = to_scsi_device(dev);
+
+ /*
+ * If scsi device runtime PM is managed by block layer
+ * then we should update request queue's runtime status
+ * as well.
+ */
+ if (sdev->request_queue->dev)
+ blk_post_runtime_resume(sdev->request_queue, 0);
+ }
}
return err;
@@ -223,12 +238,32 @@
#endif /* CONFIG_PM_SLEEP */
+static int do_scsi_runtime_suspend(struct device *dev,
+ const struct dev_pm_ops *pm)
+{
+ return pm && pm->runtime_suspend ? pm->runtime_suspend(dev) : 0;
+}
+
+static int do_scsi_runtime_resume(struct device *dev,
+ const struct dev_pm_ops *pm)
+{
+ return pm && pm->runtime_resume ? pm->runtime_resume(dev) : 0;
+}
+
static int sdev_runtime_suspend(struct device *dev)
{
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
struct scsi_device *sdev = to_scsi_device(dev);
int err = 0;
+ if (!sdev->request_queue->dev) {
+ err = scsi_dev_type_suspend(dev, do_scsi_runtime_suspend);
+ if (err == -EAGAIN)
+ pm_schedule_suspend(dev, jiffies_to_msecs(
+ round_jiffies_up_relative(HZ/10)));
+ return err;
+ }
+
err = blk_pre_runtime_suspend(sdev->request_queue);
if (err)
return err;
@@ -258,6 +293,9 @@
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
int err = 0;
+ if (!sdev->request_queue->dev)
+ return scsi_dev_type_resume(dev, do_scsi_runtime_resume);
+
blk_pre_runtime_resume(sdev->request_queue);
if (pm && pm->runtime_resume)
err = pm->runtime_resume(dev);
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index e0a78f5..3f683a5 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -827,13 +827,8 @@
* well-known logical units. Force well-known type
* to enumerate them correctly.
*/
- if (scsi_is_wlun(sdev->lun) && sdev->type != TYPE_WLUN) {
- sdev_printk(KERN_WARNING, sdev,
- "%s: correcting incorrect peripheral device type 0x%x for W-LUN 0x%16xhN\n",
- __func__, sdev->type, (unsigned int)sdev->lun);
+ if (scsi_is_wlun(sdev->lun) && sdev->type != TYPE_WLUN)
sdev->type = TYPE_WLUN;
- }
-
}
if (sdev->type == TYPE_RBC || sdev->type == TYPE_ROM) {
@@ -981,6 +976,10 @@
transport_configure_device(&sdev->sdev_gendev);
+ /* The LLD can override auto suspend tunables in ->slave_configure() */
+ sdev->use_rpm_auto = 0;
+ sdev->autosuspend_delay = SCSI_DEFAULT_AUTOSUSPEND_DELAY;
+
if (sdev->host->hostt->slave_configure) {
ret = sdev->host->hostt->slave_configure(sdev);
if (ret) {
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 0734927..a72bfde 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -1217,7 +1217,8 @@
device_enable_async_suspend(&sdev->sdev_gendev);
scsi_autopm_get_target(starget);
pm_runtime_set_active(&sdev->sdev_gendev);
- pm_runtime_forbid(&sdev->sdev_gendev);
+ if (!sdev->use_rpm_auto)
+ pm_runtime_forbid(&sdev->sdev_gendev);
pm_runtime_enable(&sdev->sdev_gendev);
scsi_autopm_put_target(starget);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index d3e852a..0605931 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1393,86 +1393,6 @@
return 0;
}
-/**
- * sd_check_events - check media events
- * @disk: kernel device descriptor
- * @clearing: disk events currently being cleared
- *
- * Returns mask of DISK_EVENT_*.
- *
- * Note: this function is invoked from the block subsystem.
- **/
-static unsigned int sd_check_events(struct gendisk *disk, unsigned int clearing)
-{
- struct scsi_disk *sdkp = scsi_disk_get(disk);
- struct scsi_device *sdp;
- struct scsi_sense_hdr *sshdr = NULL;
- int retval;
-
- if (!sdkp)
- return 0;
-
- sdp = sdkp->device;
- SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_check_events\n"));
-
- /*
- * If the device is offline, don't send any commands - just pretend as
- * if the command failed. If the device ever comes back online, we
- * can deal with it then. It is only because of unrecoverable errors
- * that we would ever take a device offline in the first place.
- */
- if (!scsi_device_online(sdp)) {
- set_media_not_present(sdkp);
- goto out;
- }
-
- /*
- * Using TEST_UNIT_READY enables differentiation between drive with
- * no cartridge loaded - NOT READY, drive with changed cartridge -
- * UNIT ATTENTION, or with same cartridge - GOOD STATUS.
- *
- * Drives that auto spin down. eg iomega jaz 1G, will be started
- * by sd_spinup_disk() from sd_revalidate_disk(), which happens whenever
- * sd_revalidate() is called.
- */
- retval = -ENODEV;
-
- if (scsi_block_when_processing_errors(sdp)) {
- sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL);
- retval = scsi_test_unit_ready(sdp, SD_TIMEOUT, SD_MAX_RETRIES,
- sshdr);
- }
-
- /* failed to execute TUR, assume media not present */
- if (host_byte(retval)) {
- set_media_not_present(sdkp);
- goto out;
- }
-
- if (media_not_present(sdkp, sshdr))
- goto out;
-
- /*
- * For removable scsi disk we have to recognise the presence
- * of a disk in the drive.
- */
- if (!sdkp->media_present)
- sdp->changed = 1;
- sdkp->media_present = 1;
-out:
- /*
- * sdp->changed is set under the following conditions:
- *
- * Medium present state has changed in either direction.
- * Device has indicated UNIT_ATTENTION.
- */
- kfree(sshdr);
- retval = sdp->changed ? DISK_EVENT_MEDIA_CHANGE : 0;
- sdp->changed = 0;
- scsi_disk_put(sdkp);
- return retval;
-}
-
static int sd_sync_cache(struct scsi_disk *sdkp)
{
int retries, res;
@@ -1664,7 +1584,6 @@
#ifdef CONFIG_COMPAT
.compat_ioctl = sd_compat_ioctl,
#endif
- .check_events = sd_check_events,
.revalidate_disk = sd_revalidate_disk,
.unlock_native_capacity = sd_unlock_native_capacity,
.pr_ops = &sd_pr_ops,
@@ -2333,11 +2252,6 @@
sizeof(cap_str_10));
if (sdkp->first_scan || old_capacity != sdkp->capacity) {
- sd_printk(KERN_NOTICE, sdkp,
- "%llu %d-byte logical blocks: (%s/%s)\n",
- (unsigned long long)sdkp->capacity,
- sector_size, cap_str_10, cap_str_2);
-
if (sdkp->physical_block_size != sector_size)
sd_printk(KERN_NOTICE, sdkp,
"%u-byte physical blocks\n",
@@ -2374,7 +2288,6 @@
int res;
struct scsi_device *sdp = sdkp->device;
struct scsi_mode_data data;
- int old_wp = sdkp->write_prot;
set_disk_ro(sdkp->disk, 0);
if (sdp->skip_ms_page_3f) {
@@ -2415,13 +2328,6 @@
} else {
sdkp->write_prot = ((data.device_specific & 0x80) != 0);
set_disk_ro(sdkp->disk, sdkp->write_prot);
- if (sdkp->first_scan || old_wp != sdkp->write_prot) {
- sd_printk(KERN_NOTICE, sdkp, "Write Protect is %s\n",
- sdkp->write_prot ? "on" : "off");
- sd_printk(KERN_DEBUG, sdkp,
- "Mode Sense: %02x %02x %02x %02x\n",
- buffer[0], buffer[1], buffer[2], buffer[3]);
- }
}
}
@@ -2434,16 +2340,13 @@
{
int len = 0, res;
struct scsi_device *sdp = sdkp->device;
+ struct Scsi_Host *host = sdp->host;
int dbd;
int modepage;
int first_len;
struct scsi_mode_data data;
struct scsi_sense_hdr sshdr;
- int old_wce = sdkp->WCE;
- int old_rcd = sdkp->RCD;
- int old_dpofua = sdkp->DPOFUA;
-
if (sdkp->cache_override)
return;
@@ -2465,7 +2368,10 @@
dbd = 8;
} else {
modepage = 8;
- dbd = 0;
+ if (host->set_dbd_for_caching)
+ dbd = 8;
+ else
+ dbd = 0;
}
/* cautiously ask */
@@ -2565,15 +2471,6 @@
if (sdkp->WCE && sdkp->write_prot)
sdkp->WCE = 0;
- if (sdkp->first_scan || old_wce != sdkp->WCE ||
- old_rcd != sdkp->RCD || old_dpofua != sdkp->DPOFUA)
- sd_printk(KERN_NOTICE, sdkp,
- "Write cache: %s, read cache: %s, %s\n",
- sdkp->WCE ? "enabled" : "disabled",
- sdkp->RCD ? "disabled" : "enabled",
- sdkp->DPOFUA ? "supports DPO and FUA"
- : "doesn't support DPO or FUA");
-
return;
}
@@ -3000,14 +2897,15 @@
}
blk_pm_runtime_init(sdp->request_queue, dev);
+ if (sdp->autosuspend_delay >= 0)
+ pm_runtime_set_autosuspend_delay(dev, sdp->autosuspend_delay);
+
device_add_disk(dev, gd);
if (sdkp->capacity)
sd_dif_config_host(sdkp);
sd_revalidate_disk(gd);
- sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
- sdp->removable ? "removable " : "");
scsi_autopm_put_device(sdp);
put_device(&sdkp->dev);
}
@@ -3252,7 +3150,6 @@
return 0;
if (sdkp->WCE && sdkp->media_present) {
- sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n");
ret = sd_sync_cache(sdkp);
if (ret) {
/* ignore OFFLINE device */
@@ -3263,7 +3160,7 @@
}
if (sdkp->device->manage_start_stop) {
- sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n");
+ sd_printk(KERN_DEBUG, sdkp, "Stopping disk\n");
/* an error is not worth aborting a system sleep */
ret = sd_start_stop_device(sdkp, 0);
if (ignore_stop_errors)
@@ -3294,7 +3191,7 @@
if (!sdkp->device->manage_start_stop)
return 0;
- sd_printk(KERN_NOTICE, sdkp, "Starting disk\n");
+ sd_printk(KERN_DEBUG, sdkp, "Starting disk\n");
return sd_start_stop_device(sdkp, 1);
}
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index ae7d9bd..77b2da2 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -1516,9 +1516,6 @@
} else
pr_warn("%s: sg_sys Invalid\n", __func__);
- sdev_printk(KERN_NOTICE, scsidp, "Attached scsi generic sg%d "
- "type %d\n", sdp->index, scsidp->type);
-
dev_set_drvdata(cl_dev, sdp);
return 0;
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index 8a95631..ec38516 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -182,6 +182,10 @@
unsigned broken_fua:1; /* Don't set FUA bit */
unsigned lun_in_cdb:1; /* Store LUN bits in CDB[1] */
unsigned synchronous_alua:1; /* Synchronous ALUA commands */
+ unsigned use_rpm_auto:1; /* Enable runtime PM auto suspend */
+
+#define SCSI_DEFAULT_AUTOSUSPEND_DELAY -1
+ int autosuspend_delay;
atomic_t disk_events_disable_depth; /* disable depth for disk events */
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index 0dee7af..dfac2dc 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -669,6 +669,12 @@
unsigned short_inquiry:1;
/*
+ * Set "DBD" field in mode_sense caching mode page in case it is
+ * mandatory by LLD standard.
+ */
+ unsigned set_dbd_for_caching:1;
+
+ /*
* Optional work queue to be utilized by the transport
*/
char work_q_name[20];