From: "Ewan D. Milne" <emilne@xxxxxxxxxx> Added support for additional scsi_device events in sysfs, as well as support for scsi_target events. Also added "rescan" node in scsi_target sysfs to permit targets to be rescanned from udev rules in a more straightforward way. Signed-off-by: Ewan D. Milne <emilne@xxxxxxxxxx> --- drivers/scsi/scsi_priv.h | 4 +- drivers/scsi/scsi_scan.c | 29 +--------- drivers/scsi/scsi_sysfs.c | 141 ++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 136 insertions(+), 38 deletions(-) diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index ddd2d31..21a73f2 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -136,7 +136,9 @@ extern int scsi_sysfs_add_host(struct Scsi_Host *); extern int scsi_sysfs_register(void); extern void scsi_sysfs_unregister(void); extern void scsi_sysfs_device_initialize(struct scsi_device *); -extern int scsi_sysfs_target_initialize(struct scsi_device *); +extern void scsi_sysfs_target_initialize(struct scsi_target *, + struct Scsi_Host *, + struct device *parent); extern struct scsi_transport_template blank_transport_template; extern void __scsi_remove_device(struct scsi_device *); diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index f252c14..274de44 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -346,25 +346,6 @@ static void scsi_target_destroy(struct scsi_target *starget) put_device(dev); } -static void scsi_target_dev_release(struct device *dev) -{ - struct device *parent = dev->parent; - struct scsi_target *starget = to_scsi_target(dev); - - kfree(starget); - put_device(parent); -} - -static struct device_type scsi_target_type = { - .name = "scsi_target", - .release = scsi_target_dev_release, -}; - -int scsi_is_target_device(const struct device *dev) -{ - return dev->type == &scsi_target_type; -} -EXPORT_SYMBOL(scsi_is_target_device); static struct scsi_target *__scsi_find_target(struct device *parent, int channel, uint id) @@ -416,15 +397,11 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, printk(KERN_ERR "%s: allocation failure\n", __func__); return NULL; } - dev = &starget->dev; - device_initialize(dev); - starget->reap_ref = 1; - dev->parent = get_device(parent); - dev_set_name(dev, "target%d:%d:%d", shost->host_no, channel, id); - dev->bus = &scsi_bus_type; - dev->type = &scsi_target_type; starget->id = id; starget->channel = channel; + scsi_sysfs_target_initialize(starget, shost, parent); + dev = &starget->dev; + starget->reap_ref = 1; starget->can_queue = 0; INIT_LIST_HEAD(&starget->siblings); INIT_LIST_HEAD(&starget->devices); diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index aff1e29..363e29f 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -502,7 +502,7 @@ sdev_store_##field (struct device *dev, struct device_attribute *attr, \ { \ int ret; \ struct scsi_device *sdev; \ - ret = scsi_sdev_check_buf_bit(buf); \ + ret = scsi_sysfs_check_buf_bit(buf); \ if (ret >= 0) { \ sdev = to_scsi_device(dev); \ sdev->field = ret; \ @@ -513,10 +513,10 @@ sdev_store_##field (struct device *dev, struct device_attribute *attr, \ 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", + * scsi_sysfs_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) +static int scsi_sysfs_check_buf_bit(const char *buf) { if ((buf[1] == '\0') || ((buf[1] == '\n') && (buf[2] == '\0'))) { if (buf[0] == '1') @@ -650,7 +650,8 @@ show_queue_type_field(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR(queue_type, S_IRUGO, show_queue_type_field, NULL); static ssize_t -show_iostat_counterbits(struct device *dev, struct device_attribute *attr, char *buf) +show_iostat_counterbits(struct device *dev, struct device_attribute *attr, + char *buf) { return snprintf(buf, 20, "%d\n", (int)sizeof(atomic_t) * 8); } @@ -681,7 +682,7 @@ sdev_show_modalias(struct device *dev, struct device_attribute *attr, char *buf) } static DEVICE_ATTR(modalias, S_IRUGO, sdev_show_modalias, NULL); -#define DECLARE_EVT_SHOW(name, Cap_name) \ +#define DECLARE_SDEV_EVT_SHOW(name, Cap_name) \ static ssize_t \ sdev_show_evt_##name(struct device *dev, struct device_attribute *attr, \ char *buf) \ @@ -691,7 +692,7 @@ sdev_show_evt_##name(struct device *dev, struct device_attribute *attr, \ return snprintf(buf, 20, "%d\n", val); \ } -#define DECLARE_EVT_STORE(name, Cap_name) \ +#define DECLARE_SDEV_EVT_STORE(name, Cap_name) \ static ssize_t \ sdev_store_evt_##name(struct device *dev, struct device_attribute *attr,\ const char *buf, size_t count) \ @@ -707,15 +708,20 @@ sdev_store_evt_##name(struct device *dev, struct device_attribute *attr,\ return count; \ } -#define DECLARE_EVT(name, Cap_name) \ - DECLARE_EVT_SHOW(name, Cap_name) \ - DECLARE_EVT_STORE(name, Cap_name) \ +#define DECLARE_SDEV_EVT(name, Cap_name) \ + DECLARE_SDEV_EVT_SHOW(name, Cap_name) \ + DECLARE_SDEV_EVT_STORE(name, Cap_name) \ static DEVICE_ATTR(evt_##name, S_IRUGO, sdev_show_evt_##name, \ sdev_store_evt_##name); #define REF_EVT(name) &dev_attr_evt_##name.attr -DECLARE_EVT(media_change, MEDIA_CHANGE) -DECLARE_EVT(capacity_change, CAPACITY_CHANGE) +DECLARE_SDEV_EVT(media_change, MEDIA_CHANGE) +DECLARE_SDEV_EVT(capacity_change, CAPACITY_CHANGE) +#ifdef CONFIG_SCSI_ENHANCED_UA +DECLARE_SDEV_EVT(capacity_change_reported, CAPACITY_CHANGE_REPORTED) +DECLARE_SDEV_EVT(soft_threshold_reached, SOFT_THRESHOLD_REACHED) +DECLARE_SDEV_EVT(mode_parameter_change_reported, MODE_PARAMETER_CHANGE_REPORTED) +#endif /* Default template for device attributes. May NOT be modified */ static struct attribute *scsi_sdev_attrs[] = { @@ -736,6 +742,11 @@ static struct attribute *scsi_sdev_attrs[] = { &dev_attr_modalias.attr, REF_EVT(media_change), REF_EVT(capacity_change), +#ifdef CONFIG_SCSI_ENHANCED_UA + REF_EVT(capacity_change_reported), + REF_EVT(soft_threshold_reached), + REF_EVT(mode_parameter_change_reported), +#endif NULL }; @@ -1126,6 +1137,114 @@ int scsi_is_sdev_device(const struct device *dev) } EXPORT_SYMBOL(scsi_is_sdev_device); +static ssize_t +starget_store_rescan_field(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct scsi_target *starget = to_scsi_target(dev); + + scsi_scan_target(starget->dev.parent, starget->channel, starget->id, + SCAN_WILD_CARD, 1); + return count; +} +/* DEVICE_ATTR(rescan) clashes with dev_attr_rescan for sdev */ +struct device_attribute dev_attr_trescan = + __ATTR(rescan, S_IWUSR, NULL, starget_store_rescan_field); + +#define DECLARE_STARGET_EVT_SHOW(name, Cap_name) \ +static ssize_t \ +starget_show_evt_##name(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct scsi_target *starget = to_scsi_target(dev); \ + int val = test_bit(STARGET_EVT_##Cap_name, \ + starget->supported_events); \ + return snprintf(buf, 20, "%d\n", val); \ +} + +#define DECLARE_STARGET_EVT_STORE(name, Cap_name) \ +static ssize_t \ +starget_store_evt_##name(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + struct scsi_target *starget = to_scsi_target(dev); \ + unsigned int val; \ + int err = kstrtouint(buf, 10, &val); \ + if (err != 0) \ + return err; \ + if (val == 0) \ + clear_bit(STARGET_EVT_##Cap_name, \ + starget->supported_events); \ + else if (val == 1) \ + set_bit(STARGET_EVT_##Cap_name, \ + starget->supported_events); \ + else \ + return -EINVAL; \ + return count; \ +} + +#define DECLARE_STARGET_EVT(name, Cap_name) \ + DECLARE_STARGET_EVT_SHOW(name, Cap_name) \ + DECLARE_STARGET_EVT_STORE(name, Cap_name) \ + static DEVICE_ATTR(evt_##name, S_IRUGO, \ + starget_show_evt_##name, \ + starget_store_evt_##name); + +#ifdef CONFIG_SCSI_ENHANCED_UA +DECLARE_STARGET_EVT(lun_change_reported, LUN_CHANGE_REPORTED) +#endif + +static struct attribute *scsi_target_attrs[] = { + &dev_attr_trescan.attr, +#ifdef CONFIG_SCSI_ENHANCED_UA + REF_EVT(lun_change_reported), +#endif + NULL +}; + +static struct attribute_group scsi_target_attr_group = { + .attrs = scsi_target_attrs, +}; + +static const struct attribute_group *scsi_target_attr_groups[] = { + &scsi_target_attr_group, + NULL +}; + +static void scsi_target_dev_release(struct device *dev) +{ + struct device *parent = dev->parent; + struct scsi_target *starget = to_scsi_target(dev); + + kfree(starget); + put_device(parent); +} + +static struct device_type scsi_target_type = { + .name = "scsi_target", + .release = scsi_target_dev_release, + .groups = scsi_target_attr_groups, +}; + +int scsi_is_target_device(const struct device *dev) +{ + return dev->type == &scsi_target_type; +} +EXPORT_SYMBOL(scsi_is_target_device); + +void scsi_sysfs_target_initialize(struct scsi_target *starget, + struct Scsi_Host *shost, + struct device *parent) +{ + device_initialize(&starget->dev); + starget->dev.parent = get_device(parent); + starget->dev.bus = &scsi_bus_type; + starget->dev.type = &scsi_target_type; + dev_set_name(&starget->dev, "target%d:%d:%d", shost->host_no, + starget->channel, starget->id); +} + /* A blank transport template that is used in drivers that don't * yet implement Transport Attributes */ struct scsi_transport_template blank_transport_template = { { { {NULL, }, }, }, }; -- 1.7.11.7 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html