summaryrefslogtreecommitdiff
path: root/drivers/scsi/scsi_sysfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/scsi_sysfs.c')
-rw-r--r--drivers/scsi/scsi_sysfs.c170
1 files changed, 79 insertions, 91 deletions
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 981d1bab2120..99eb0a30df61 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -27,7 +27,7 @@
#include "scsi_priv.h"
#include "scsi_logging.h"
-static struct device_type scsi_dev_type;
+static const struct device_type scsi_dev_type;
static const struct {
enum scsi_device_state value;
@@ -265,7 +265,7 @@ show_shost_supported_mode(struct device *dev, struct device_attribute *attr,
return show_shost_mode(supported_mode, buf);
}
-static DEVICE_ATTR(supported_mode, S_IRUGO | S_IWUSR, show_shost_supported_mode, NULL);
+static DEVICE_ATTR(supported_mode, S_IRUGO, show_shost_supported_mode, NULL);
static ssize_t
show_shost_active_mode(struct device *dev,
@@ -279,7 +279,7 @@ show_shost_active_mode(struct device *dev,
return show_shost_mode(shost->active_mode, buf);
}
-static DEVICE_ATTR(active_mode, S_IRUGO | S_IWUSR, show_shost_active_mode, NULL);
+static DEVICE_ATTR(active_mode, S_IRUGO, show_shost_active_mode, NULL);
static int check_reset_type(const char *str)
{
@@ -296,7 +296,7 @@ store_host_reset(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct Scsi_Host *shost = class_to_shost(dev);
- struct scsi_host_template *sht = shost->hostt;
+ const struct scsi_host_template *sht = shost->hostt;
int ret = -EINVAL;
int type;
@@ -449,8 +449,11 @@ static void scsi_device_dev_release(struct device *dev)
struct scsi_vpd *vpd_pg80 = NULL, *vpd_pg83 = NULL;
struct scsi_vpd *vpd_pg0 = NULL, *vpd_pg89 = NULL;
struct scsi_vpd *vpd_pgb0 = NULL, *vpd_pgb1 = NULL, *vpd_pgb2 = NULL;
+ struct scsi_vpd *vpd_pgb7 = NULL;
unsigned long flags;
+ might_sleep();
+
scsi_dh_release_device(sdev);
parent = sdev->sdev_gendev.parent;
@@ -492,6 +495,8 @@ static void scsi_device_dev_release(struct device *dev)
lockdep_is_held(&sdev->inquiry_mutex));
vpd_pgb2 = rcu_replace_pointer(sdev->vpd_pgb2, vpd_pgb2,
lockdep_is_held(&sdev->inquiry_mutex));
+ vpd_pgb7 = rcu_replace_pointer(sdev->vpd_pgb7, vpd_pgb7,
+ lockdep_is_held(&sdev->inquiry_mutex));
mutex_unlock(&sdev->inquiry_mutex);
if (vpd_pg0)
@@ -508,6 +513,8 @@ static void scsi_device_dev_release(struct device *dev)
kfree_rcu(vpd_pgb1, rcu);
if (vpd_pgb2)
kfree_rcu(vpd_pgb2, rcu);
+ if (vpd_pgb7)
+ kfree_rcu(vpd_pgb7, rcu);
kfree(sdev->inquiry);
kfree(sdev);
@@ -521,7 +528,7 @@ static struct class sdev_class = {
};
/* all probing is done in the individual ->probe routines */
-static int scsi_bus_match(struct device *dev, struct device_driver *gendrv)
+static int scsi_bus_match(struct device *dev, const struct device_driver *gendrv)
{
struct scsi_device *sdp;
@@ -534,9 +541,9 @@ static int scsi_bus_match(struct device *dev, struct device_driver *gendrv)
return (sdp->inq_periph_qual == SCSI_INQ_PQ_CON)? 1: 0;
}
-static int scsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int scsi_bus_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct scsi_device *sdev;
+ const struct scsi_device *sdev;
if (dev->type != &scsi_dev_type)
return 0;
@@ -547,7 +554,7 @@ static int scsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
return 0;
}
-struct bus_type scsi_bus_type = {
+const struct bus_type scsi_bus_type = {
.name = "scsi",
.match = scsi_bus_match,
.uevent = scsi_bus_uevent,
@@ -598,68 +605,6 @@ sdev_show_##field (struct device *dev, struct device_attribute *attr, \
sdev_show_function(field, format_string) \
static DEVICE_ATTR(field, S_IRUGO, sdev_show_##field, NULL);
-
-/*
- * sdev_rw_attr: create a function and attribute variable for a
- * read/write field.
- */
-#define sdev_rw_attr(field, format_string) \
- sdev_show_function(field, format_string) \
- \
-static ssize_t \
-sdev_store_##field (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- struct scsi_device *sdev; \
- sdev = to_scsi_device(dev); \
- sscanf (buf, format_string, &sdev->field); \
- return count; \
-} \
-static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, sdev_show_##field, sdev_store_##field);
-
-/* Currently we don't export bit fields, but we might in future,
- * so leave this code in */
-#if 0
-/*
- * sdev_rd_attr: create a function and attribute variable for a
- * read/write bit field.
- */
-#define sdev_rw_attr_bit(field) \
- sdev_show_function(field, "%d\n") \
- \
-static ssize_t \
-sdev_store_##field (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- int ret; \
- struct scsi_device *sdev; \
- ret = scsi_sdev_check_buf_bit(buf); \
- if (ret >= 0) { \
- sdev = to_scsi_device(dev); \
- sdev->field = ret; \
- ret = count; \
- } \
- return ret; \
-} \
-static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, sdev_show_##field, sdev_store_##field);
-
-/*
- * scsi_sdev_check_buf_bit: return 0 if buf is "0", return 1 if buf is "1",
- * else return -EINVAL.
- */
-static int scsi_sdev_check_buf_bit(const char *buf)
-{
- if ((buf[1] == '\0') || ((buf[1] == '\n') && (buf[2] == '\0'))) {
- if (buf[0] == '1')
- return 1;
- else if (buf[0] == '0')
- return 0;
- else
- return -EINVAL;
- } else
- return -EINVAL;
-}
-#endif
/*
* Create the actual show/store functions and data structures.
*/
@@ -668,6 +613,7 @@ sdev_rd_attr (scsi_level, "%d\n");
sdev_rd_attr (vendor, "%.8s\n");
sdev_rd_attr (model, "%.16s\n");
sdev_rd_attr (rev, "%.4s\n");
+sdev_rd_attr (cdl_supported, "%d\n");
static ssize_t
sdev_show_device_busy(struct device *dev, struct device_attribute *attr,
@@ -702,10 +648,14 @@ static ssize_t
sdev_store_timeout (struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct scsi_device *sdev;
- int timeout;
- sdev = to_scsi_device(dev);
- sscanf (buf, "%d\n", &timeout);
+ struct scsi_device *sdev = to_scsi_device(dev);
+ int ret, timeout;
+
+ ret = kstrtoint(buf, 0, &timeout);
+ if (ret)
+ return ret;
+ if (timeout <= 0)
+ return -EINVAL;
blk_queue_rq_timeout(sdev->request_queue, timeout * HZ);
return count;
}
@@ -744,7 +694,7 @@ static ssize_t
store_rescan_field (struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- scsi_rescan_device(dev);
+ scsi_rescan_device(to_scsi_device(dev));
return count;
}
static DEVICE_ATTR(rescan, S_IWUSR, NULL, store_rescan_field);
@@ -837,7 +787,7 @@ store_state_field(struct device *dev, struct device_attribute *attr,
* waiting for pending I/O to finish.
*/
blk_mq_run_hw_queues(sdev->request_queue, true);
- scsi_rescan_device(dev);
+ scsi_rescan_device(sdev);
}
return ret == 0 ? count : -EINVAL;
@@ -878,7 +828,7 @@ store_queue_type_field(struct device *dev, struct device_attribute *attr,
if (!sdev->tagged_supported)
return -EINVAL;
-
+
sdev_printk(KERN_INFO, sdev,
"ignoring write to deprecated queue_type attribute");
return count;
@@ -890,7 +840,7 @@ static DEVICE_ATTR(queue_type, S_IRUGO | S_IWUSR, show_queue_type_field,
#define sdev_vpd_pg_attr(_page) \
static ssize_t \
show_vpd_##_page(struct file *filp, struct kobject *kobj, \
- struct bin_attribute *bin_attr, \
+ const struct bin_attribute *bin_attr, \
char *buf, loff_t off, size_t count) \
{ \
struct device *dev = kobj_to_dev(kobj); \
@@ -906,7 +856,7 @@ show_vpd_##_page(struct file *filp, struct kobject *kobj, \
rcu_read_unlock(); \
return ret; \
} \
-static struct bin_attribute dev_attr_vpd_##_page = { \
+static const struct bin_attribute dev_attr_vpd_##_page = { \
.attr = {.name = __stringify(vpd_##_page), .mode = S_IRUGO }, \
.size = 0, \
.read = show_vpd_##_page, \
@@ -918,10 +868,11 @@ sdev_vpd_pg_attr(pg89);
sdev_vpd_pg_attr(pgb0);
sdev_vpd_pg_attr(pgb1);
sdev_vpd_pg_attr(pgb2);
+sdev_vpd_pg_attr(pgb7);
sdev_vpd_pg_attr(pg0);
static ssize_t show_inquiry(struct file *filep, struct kobject *kobj,
- struct bin_attribute *bin_attr,
+ const struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
struct device *dev = kobj_to_dev(kobj);
@@ -934,7 +885,7 @@ static ssize_t show_inquiry(struct file *filep, struct kobject *kobj,
sdev->inquiry_len);
}
-static struct bin_attribute dev_attr_inquiry = {
+static const struct bin_attribute dev_attr_inquiry = {
.attr = {
.name = "inquiry",
.mode = S_IRUGO,
@@ -1023,7 +974,7 @@ sdev_store_queue_depth(struct device *dev, struct device_attribute *attr,
{
int depth, retval;
struct scsi_device *sdev = to_scsi_device(dev);
- struct scsi_host_template *sht = sdev->host->hostt;
+ const struct scsi_host_template *sht = sdev->host->hostt;
if (!sht->change_queue_depth)
return -EINVAL;
@@ -1219,6 +1170,33 @@ static DEVICE_ATTR(queue_ramp_up_period, S_IRUGO | S_IWUSR,
sdev_show_queue_ramp_up_period,
sdev_store_queue_ramp_up_period);
+static ssize_t sdev_show_cdl_enable(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+
+ return sysfs_emit(buf, "%d\n", (int)sdev->cdl_enable);
+}
+
+static ssize_t sdev_store_cdl_enable(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ bool v;
+
+ if (kstrtobool(buf, &v))
+ return -EINVAL;
+
+ ret = scsi_cdl_enable(to_scsi_device(dev), v);
+ if (ret)
+ return ret;
+
+ return count;
+}
+static DEVICE_ATTR(cdl_enable, S_IRUGO | S_IWUSR,
+ sdev_show_cdl_enable, sdev_store_cdl_enable);
+
static umode_t scsi_sdev_attr_is_visible(struct kobject *kobj,
struct attribute *attr, int i)
{
@@ -1238,7 +1216,7 @@ static umode_t scsi_sdev_attr_is_visible(struct kobject *kobj,
}
static umode_t scsi_sdev_bin_attr_is_visible(struct kobject *kobj,
- struct bin_attribute *attr, int i)
+ const struct bin_attribute *attr, int i)
{
struct device *dev = kobj_to_dev(kobj);
struct scsi_device *sdev = to_scsi_device(dev);
@@ -1265,6 +1243,9 @@ static umode_t scsi_sdev_bin_attr_is_visible(struct kobject *kobj,
if (attr == &dev_attr_vpd_pgb2 && !sdev->vpd_pgb2)
return 0;
+ if (attr == &dev_attr_vpd_pgb7 && !sdev->vpd_pgb7)
+ return 0;
+
return S_IRUGO;
}
@@ -1298,6 +1279,8 @@ static struct attribute *scsi_sdev_attrs[] = {
&dev_attr_preferred_path.attr,
#endif
&dev_attr_queue_ramp_up_period.attr,
+ &dev_attr_cdl_supported.attr,
+ &dev_attr_cdl_enable.attr,
REF_EVT(media_change),
REF_EVT(inquiry_change_reported),
REF_EVT(capacity_change_reported),
@@ -1307,7 +1290,7 @@ static struct attribute *scsi_sdev_attrs[] = {
NULL
};
-static struct bin_attribute *scsi_sdev_bin_attrs[] = {
+static const struct bin_attribute *const scsi_sdev_bin_attrs[] = {
&dev_attr_vpd_pg0,
&dev_attr_vpd_pg83,
&dev_attr_vpd_pg80,
@@ -1315,12 +1298,13 @@ static struct bin_attribute *scsi_sdev_bin_attrs[] = {
&dev_attr_vpd_pgb0,
&dev_attr_vpd_pgb1,
&dev_attr_vpd_pgb2,
+ &dev_attr_vpd_pgb7,
&dev_attr_inquiry,
NULL
};
static struct attribute_group scsi_sdev_attr_group = {
.attrs = scsi_sdev_attrs,
- .bin_attrs = scsi_sdev_bin_attrs,
+ .bin_attrs = scsi_sdev_bin_attrs,
.is_visible = scsi_sdev_attr_is_visible,
.is_bin_visible = scsi_sdev_bin_attr_is_visible,
};
@@ -1364,6 +1348,9 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
int error;
struct scsi_target *starget = sdev->sdev_target;
+ if (WARN_ON_ONCE(scsi_device_is_pseudo_dev(sdev)))
+ return -EINVAL;
+
error = scsi_target_add(starget);
if (error)
return error;
@@ -1471,8 +1458,8 @@ void __scsi_remove_device(struct scsi_device *sdev)
kref_put(&sdev->host->tagset_refcnt, scsi_mq_free_tags);
cancel_work_sync(&sdev->requeue_work);
- if (sdev->host->hostt->slave_destroy)
- sdev->host->hostt->slave_destroy(sdev);
+ if (!scsi_device_is_pseudo_dev(sdev) && sdev->host->hostt->sdev_destroy)
+ sdev->host->hostt->sdev_destroy(sdev);
transport_destroy_device(dev);
/*
@@ -1567,13 +1554,14 @@ restart:
}
EXPORT_SYMBOL(scsi_remove_target);
-int scsi_register_driver(struct device_driver *drv)
+int __scsi_register_driver(struct device_driver *drv, struct module *owner)
{
drv->bus = &scsi_bus_type;
+ drv->owner = owner;
return driver_register(drv);
}
-EXPORT_SYMBOL(scsi_register_driver);
+EXPORT_SYMBOL(__scsi_register_driver);
int scsi_register_interface(struct class_interface *intf)
{
@@ -1594,7 +1582,7 @@ int scsi_sysfs_add_host(struct Scsi_Host *shost)
return 0;
}
-static struct device_type scsi_dev_type = {
+static const struct device_type scsi_dev_type = {
.name = "scsi_device",
.release = scsi_device_dev_release,
.groups = scsi_sdev_attr_groups,
@@ -1604,7 +1592,7 @@ void scsi_sysfs_device_initialize(struct scsi_device *sdev)
{
unsigned long flags;
struct Scsi_Host *shost = sdev->host;
- struct scsi_host_template *hostt = shost->hostt;
+ const struct scsi_host_template *hostt = shost->hostt;
struct scsi_target *starget = sdev->sdev_target;
device_initialize(&sdev->sdev_gendev);