X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=drivers%2Fscsi%2Fscsi_transport_spi.c;h=b29360ed0bdc9f0c2dd6a80c06cd4ef09a5cee66;hb=afd2fc02ab7bae6062671c5ca80dd34c34a63fb7;hp=4df21c92ff1ede9931772f36ec7aa3ac77255bb9;hpb=6abd2c860e34add677de50e8b134f5af6f4b0893;p=cascardo%2Flinux.git diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index 4df21c92ff1e..b29360ed0bdc 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "scsi_priv.h" #include @@ -52,13 +53,6 @@ struct spi_internal { struct scsi_transport_template t; struct spi_function_template *f; - /* The actual attributes */ - struct class_device_attribute private_attrs[SPI_NUM_ATTRS]; - /* The array of null terminated pointers to attributes - * needed by scsi_sysfs.c */ - struct class_device_attribute *attrs[SPI_NUM_ATTRS + SPI_OTHER_ATTRS + 1]; - struct class_device_attribute private_host_attrs[SPI_HOST_ATTRS]; - struct class_device_attribute *host_attrs[SPI_HOST_ATTRS + 1]; }; #define to_spi_internal(tmpl) container_of(tmpl, struct spi_internal, t) @@ -165,7 +159,7 @@ static inline enum spi_signal_type spi_signal_to_value(const char *name) } static int spi_host_setup(struct transport_container *tc, struct device *dev, - struct class_device *cdev) + struct device *cdev) { struct Scsi_Host *shost = dev_to_shost(dev); @@ -174,17 +168,20 @@ static int spi_host_setup(struct transport_container *tc, struct device *dev, return 0; } +static int spi_host_configure(struct transport_container *tc, + struct device *dev, + struct device *cdev); + static DECLARE_TRANSPORT_CLASS(spi_host_class, "spi_host", spi_host_setup, NULL, - NULL); + spi_host_configure); static int spi_host_match(struct attribute_container *cont, struct device *dev) { struct Scsi_Host *shost; - struct spi_internal *i; if (!scsi_is_host_device(dev)) return 0; @@ -194,14 +191,16 @@ static int spi_host_match(struct attribute_container *cont, != &spi_host_class.class) return 0; - i = to_spi_internal(shost->transportt); - - return &i->t.host_attrs.ac == cont; + return &shost->transportt->host_attrs.ac == cont; } +static int spi_target_configure(struct transport_container *tc, + struct device *dev, + struct device *cdev); + static int spi_device_configure(struct transport_container *tc, struct device *dev, - struct class_device *cdev) + struct device *cdev) { struct scsi_device *sdev = to_scsi_device(dev); struct scsi_target *starget = sdev->sdev_target; @@ -221,7 +220,7 @@ static int spi_device_configure(struct transport_container *tc, static int spi_setup_transport_attrs(struct transport_container *tc, struct device *dev, - struct class_device *cdev) + struct device *cdev) { struct scsi_target *starget = to_scsi_target(dev); @@ -250,9 +249,10 @@ static int spi_setup_transport_attrs(struct transport_container *tc, #define spi_transport_show_simple(field, format_string) \ \ static ssize_t \ -show_spi_transport_##field(struct class_device *cdev, char *buf) \ +show_spi_transport_##field(struct device *dev, \ + struct device_attribute *attr, char *buf) \ { \ - struct scsi_target *starget = transport_class_to_starget(cdev); \ + struct scsi_target *starget = transport_class_to_starget(dev); \ struct spi_transport_attrs *tp; \ \ tp = (struct spi_transport_attrs *)&starget->starget_data; \ @@ -262,11 +262,12 @@ show_spi_transport_##field(struct class_device *cdev, char *buf) \ #define spi_transport_store_simple(field, format_string) \ \ static ssize_t \ -store_spi_transport_##field(struct class_device *cdev, const char *buf, \ - size_t count) \ +store_spi_transport_##field(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ { \ int val; \ - struct scsi_target *starget = transport_class_to_starget(cdev); \ + struct scsi_target *starget = transport_class_to_starget(dev); \ struct spi_transport_attrs *tp; \ \ tp = (struct spi_transport_attrs *)&starget->starget_data; \ @@ -278,9 +279,10 @@ store_spi_transport_##field(struct class_device *cdev, const char *buf, \ #define spi_transport_show_function(field, format_string) \ \ static ssize_t \ -show_spi_transport_##field(struct class_device *cdev, char *buf) \ +show_spi_transport_##field(struct device *dev, \ + struct device_attribute *attr, char *buf) \ { \ - struct scsi_target *starget = transport_class_to_starget(cdev); \ + struct scsi_target *starget = transport_class_to_starget(dev); \ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \ struct spi_transport_attrs *tp; \ struct spi_internal *i = to_spi_internal(shost->transportt); \ @@ -292,31 +294,37 @@ show_spi_transport_##field(struct class_device *cdev, char *buf) \ #define spi_transport_store_function(field, format_string) \ static ssize_t \ -store_spi_transport_##field(struct class_device *cdev, const char *buf, \ - size_t count) \ +store_spi_transport_##field(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ { \ int val; \ - struct scsi_target *starget = transport_class_to_starget(cdev); \ + struct scsi_target *starget = transport_class_to_starget(dev); \ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \ struct spi_internal *i = to_spi_internal(shost->transportt); \ \ + if (!i->f->set_##field) \ + return -EINVAL; \ val = simple_strtoul(buf, NULL, 0); \ - i->f->set_##field(starget, val); \ + i->f->set_##field(starget, val); \ return count; \ } #define spi_transport_store_max(field, format_string) \ static ssize_t \ -store_spi_transport_##field(struct class_device *cdev, const char *buf, \ - size_t count) \ +store_spi_transport_##field(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ { \ int val; \ - struct scsi_target *starget = transport_class_to_starget(cdev); \ + struct scsi_target *starget = transport_class_to_starget(dev); \ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \ struct spi_internal *i = to_spi_internal(shost->transportt); \ struct spi_transport_attrs *tp \ = (struct spi_transport_attrs *)&starget->starget_data; \ \ + if (i->f->set_##field) \ + return -EINVAL; \ val = simple_strtoul(buf, NULL, 0); \ if (val > tp->max_##field) \ val = tp->max_##field; \ @@ -327,24 +335,24 @@ store_spi_transport_##field(struct class_device *cdev, const char *buf, \ #define spi_transport_rd_attr(field, format_string) \ spi_transport_show_function(field, format_string) \ spi_transport_store_function(field, format_string) \ -static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR, \ - show_spi_transport_##field, \ - store_spi_transport_##field); +static DEVICE_ATTR(field, S_IRUGO, \ + show_spi_transport_##field, \ + store_spi_transport_##field); #define spi_transport_simple_attr(field, format_string) \ spi_transport_show_simple(field, format_string) \ spi_transport_store_simple(field, format_string) \ -static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR, \ - show_spi_transport_##field, \ - store_spi_transport_##field); +static DEVICE_ATTR(field, S_IRUGO, \ + show_spi_transport_##field, \ + store_spi_transport_##field); #define spi_transport_max_attr(field, format_string) \ spi_transport_show_function(field, format_string) \ spi_transport_store_max(field, format_string) \ spi_transport_simple_attr(max_##field, format_string) \ -static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR, \ - show_spi_transport_##field, \ - store_spi_transport_##field); +static DEVICE_ATTR(field, S_IRUGO, \ + show_spi_transport_##field, \ + store_spi_transport_##field); /* The Parallel SCSI Tranport Attributes: */ spi_transport_max_attr(offset, "%d\n"); @@ -358,24 +366,27 @@ spi_transport_rd_attr(rti, "%d\n"); spi_transport_rd_attr(pcomp_en, "%d\n"); spi_transport_rd_attr(hold_mcs, "%d\n"); -/* we only care about the first child device so we return 1 */ +/* we only care about the first child device that's a real SCSI device + * so we return 1 to terminate the iteration when we find it */ static int child_iter(struct device *dev, void *data) { - struct scsi_device *sdev = to_scsi_device(dev); + if (!scsi_is_sdev_device(dev)) + return 0; - spi_dv_device(sdev); + spi_dv_device(to_scsi_device(dev)); return 1; } static ssize_t -store_spi_revalidate(struct class_device *cdev, const char *buf, size_t count) +store_spi_revalidate(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { - struct scsi_target *starget = transport_class_to_starget(cdev); + struct scsi_target *starget = transport_class_to_starget(dev); device_for_each_child(&starget->dev, NULL, child_iter); return count; } -static CLASS_DEVICE_ATTR(revalidate, S_IWUSR, NULL, store_spi_revalidate); +static DEVICE_ATTR(revalidate, S_IWUSR, NULL, store_spi_revalidate); /* Translate the period into ns according to the current spec * for SDTR/PPR messages */ @@ -410,7 +421,7 @@ show_spi_transport_period_helper(char *buf, int period) } static ssize_t -store_spi_transport_period_helper(struct class_device *cdev, const char *buf, +store_spi_transport_period_helper(struct device *dev, const char *buf, size_t count, int *periodp) { int j, picosec, period = -1; @@ -447,9 +458,10 @@ store_spi_transport_period_helper(struct class_device *cdev, const char *buf, } static ssize_t -show_spi_transport_period(struct class_device *cdev, char *buf) +show_spi_transport_period(struct device *dev, + struct device_attribute *attr, char *buf) { - struct scsi_target *starget = transport_class_to_starget(cdev); + struct scsi_target *starget = transport_class_to_starget(dev); struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); struct spi_internal *i = to_spi_internal(shost->transportt); struct spi_transport_attrs *tp = @@ -462,8 +474,8 @@ show_spi_transport_period(struct class_device *cdev, char *buf) } static ssize_t -store_spi_transport_period(struct class_device *cdev, const char *buf, - size_t count) +store_spi_transport_period(struct device *cdev, struct device_attribute *attr, + const char *buf, size_t count) { struct scsi_target *starget = transport_class_to_starget(cdev); struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); @@ -472,6 +484,9 @@ store_spi_transport_period(struct class_device *cdev, const char *buf, (struct spi_transport_attrs *)&starget->starget_data; int period, retval; + if (!i->f->set_period) + return -EINVAL; + retval = store_spi_transport_period_helper(cdev, buf, count, &period); if (period < tp->min_period) @@ -482,23 +497,30 @@ store_spi_transport_period(struct class_device *cdev, const char *buf, return retval; } -static CLASS_DEVICE_ATTR(period, S_IRUGO | S_IWUSR, - show_spi_transport_period, - store_spi_transport_period); +static DEVICE_ATTR(period, S_IRUGO, + show_spi_transport_period, + store_spi_transport_period); static ssize_t -show_spi_transport_min_period(struct class_device *cdev, char *buf) +show_spi_transport_min_period(struct device *cdev, + struct device_attribute *attr, char *buf) { struct scsi_target *starget = transport_class_to_starget(cdev); + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct spi_internal *i = to_spi_internal(shost->transportt); struct spi_transport_attrs *tp = (struct spi_transport_attrs *)&starget->starget_data; + if (!i->f->set_period) + return -EINVAL; + return show_spi_transport_period_helper(buf, tp->min_period); } static ssize_t -store_spi_transport_min_period(struct class_device *cdev, const char *buf, - size_t count) +store_spi_transport_min_period(struct device *cdev, + struct device_attribute *attr, + const char *buf, size_t count) { struct scsi_target *starget = transport_class_to_starget(cdev); struct spi_transport_attrs *tp = @@ -509,12 +531,14 @@ store_spi_transport_min_period(struct class_device *cdev, const char *buf, } -static CLASS_DEVICE_ATTR(min_period, S_IRUGO | S_IWUSR, - show_spi_transport_min_period, - store_spi_transport_min_period); +static DEVICE_ATTR(min_period, S_IRUGO, + show_spi_transport_min_period, + store_spi_transport_min_period); -static ssize_t show_spi_host_signalling(struct class_device *cdev, char *buf) +static ssize_t show_spi_host_signalling(struct device *cdev, + struct device_attribute *attr, + char *buf) { struct Scsi_Host *shost = transport_class_to_shost(cdev); struct spi_internal *i = to_spi_internal(shost->transportt); @@ -524,21 +548,25 @@ static ssize_t show_spi_host_signalling(struct class_device *cdev, char *buf) return sprintf(buf, "%s\n", spi_signal_to_string(spi_signalling(shost))); } -static ssize_t store_spi_host_signalling(struct class_device *cdev, +static ssize_t store_spi_host_signalling(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { - struct Scsi_Host *shost = transport_class_to_shost(cdev); + struct Scsi_Host *shost = transport_class_to_shost(dev); struct spi_internal *i = to_spi_internal(shost->transportt); enum spi_signal_type type = spi_signal_to_value(buf); + if (!i->f->set_signalling) + return -EINVAL; + if (type != SPI_SIGNAL_UNKNOWN) i->f->set_signalling(shost, type); return count; } -static CLASS_DEVICE_ATTR(signalling, S_IRUGO | S_IWUSR, - show_spi_host_signalling, - store_spi_host_signalling); +static DEVICE_ATTR(signalling, S_IRUGO, + show_spi_host_signalling, + store_spi_host_signalling); #define DV_SET(x, y) \ if(i->f->set_##x) \ @@ -1262,35 +1290,6 @@ int spi_print_msg(const unsigned char *msg) EXPORT_SYMBOL(spi_print_msg); #endif /* ! CONFIG_SCSI_CONSTANTS */ -#define SETUP_ATTRIBUTE(field) \ - i->private_attrs[count] = class_device_attr_##field; \ - if (!i->f->set_##field) { \ - i->private_attrs[count].attr.mode = S_IRUGO; \ - i->private_attrs[count].store = NULL; \ - } \ - i->attrs[count] = &i->private_attrs[count]; \ - if (i->f->show_##field) \ - count++ - -#define SETUP_RELATED_ATTRIBUTE(field, rel_field) \ - i->private_attrs[count] = class_device_attr_##field; \ - if (!i->f->set_##rel_field) { \ - i->private_attrs[count].attr.mode = S_IRUGO; \ - i->private_attrs[count].store = NULL; \ - } \ - i->attrs[count] = &i->private_attrs[count]; \ - if (i->f->show_##rel_field) \ - count++ - -#define SETUP_HOST_ATTRIBUTE(field) \ - i->private_host_attrs[count] = class_device_attr_##field; \ - if (!i->f->set_##field) { \ - i->private_host_attrs[count].attr.mode = S_IRUGO; \ - i->private_host_attrs[count].store = NULL; \ - } \ - i->host_attrs[count] = &i->private_host_attrs[count]; \ - count++ - static int spi_device_match(struct attribute_container *cont, struct device *dev) { @@ -1343,16 +1342,139 @@ static DECLARE_TRANSPORT_CLASS(spi_transport_class, "spi_transport", spi_setup_transport_attrs, NULL, - NULL); + spi_target_configure); static DECLARE_ANON_TRANSPORT_CLASS(spi_device_class, spi_device_match, spi_device_configure); +static struct attribute *host_attributes[] = { + &dev_attr_signalling.attr, + NULL +}; + +static struct attribute_group host_attribute_group = { + .attrs = host_attributes, +}; + +static int spi_host_configure(struct transport_container *tc, + struct device *dev, + struct device *cdev) +{ + struct kobject *kobj = &cdev->kobj; + struct Scsi_Host *shost = transport_class_to_shost(cdev); + struct spi_internal *si = to_spi_internal(shost->transportt); + struct attribute *attr = &dev_attr_signalling.attr; + int rc = 0; + + if (si->f->set_signalling) + rc = sysfs_chmod_file(kobj, attr, attr->mode | S_IWUSR); + + return rc; +} + +/* returns true if we should be showing the variable. Also + * overloads the return by setting 1<<1 if the attribute should + * be writeable */ +#define TARGET_ATTRIBUTE_HELPER(name) \ + (si->f->show_##name ? S_IRUGO : 0) | \ + (si->f->set_##name ? S_IWUSR : 0) + +static mode_t target_attribute_is_visible(struct kobject *kobj, + struct attribute *attr, int i) +{ + struct device *cdev = container_of(kobj, struct device, kobj); + struct scsi_target *starget = transport_class_to_starget(cdev); + struct Scsi_Host *shost = transport_class_to_shost(cdev); + struct spi_internal *si = to_spi_internal(shost->transportt); + + if (attr == &dev_attr_period.attr && + spi_support_sync(starget)) + return TARGET_ATTRIBUTE_HELPER(period); + else if (attr == &dev_attr_min_period.attr && + spi_support_sync(starget)) + return TARGET_ATTRIBUTE_HELPER(period); + else if (attr == &dev_attr_offset.attr && + spi_support_sync(starget)) + return TARGET_ATTRIBUTE_HELPER(offset); + else if (attr == &dev_attr_max_offset.attr && + spi_support_sync(starget)) + return TARGET_ATTRIBUTE_HELPER(offset); + else if (attr == &dev_attr_width.attr && + spi_support_wide(starget)) + return TARGET_ATTRIBUTE_HELPER(width); + else if (attr == &dev_attr_max_width.attr && + spi_support_wide(starget)) + return TARGET_ATTRIBUTE_HELPER(width); + else if (attr == &dev_attr_iu.attr && + spi_support_ius(starget)) + return TARGET_ATTRIBUTE_HELPER(iu); + else if (attr == &dev_attr_dt.attr && + spi_support_dt(starget)) + return TARGET_ATTRIBUTE_HELPER(dt); + else if (attr == &dev_attr_qas.attr && + spi_support_qas(starget)) + return TARGET_ATTRIBUTE_HELPER(qas); + else if (attr == &dev_attr_wr_flow.attr && + spi_support_ius(starget)) + return TARGET_ATTRIBUTE_HELPER(wr_flow); + else if (attr == &dev_attr_rd_strm.attr && + spi_support_ius(starget)) + return TARGET_ATTRIBUTE_HELPER(rd_strm); + else if (attr == &dev_attr_rti.attr && + spi_support_ius(starget)) + return TARGET_ATTRIBUTE_HELPER(rti); + else if (attr == &dev_attr_pcomp_en.attr && + spi_support_ius(starget)) + return TARGET_ATTRIBUTE_HELPER(pcomp_en); + else if (attr == &dev_attr_hold_mcs.attr && + spi_support_ius(starget)) + return TARGET_ATTRIBUTE_HELPER(hold_mcs); + else if (attr == &dev_attr_revalidate.attr) + return S_IWUSR; + + return 0; +} + +static struct attribute *target_attributes[] = { + &dev_attr_period.attr, + &dev_attr_min_period.attr, + &dev_attr_offset.attr, + &dev_attr_max_offset.attr, + &dev_attr_width.attr, + &dev_attr_max_width.attr, + &dev_attr_iu.attr, + &dev_attr_dt.attr, + &dev_attr_qas.attr, + &dev_attr_wr_flow.attr, + &dev_attr_rd_strm.attr, + &dev_attr_rti.attr, + &dev_attr_pcomp_en.attr, + &dev_attr_hold_mcs.attr, + &dev_attr_revalidate.attr, + NULL +}; + +static struct attribute_group target_attribute_group = { + .attrs = target_attributes, + .is_visible = target_attribute_is_visible, +}; + +static int spi_target_configure(struct transport_container *tc, + struct device *dev, + struct device *cdev) +{ + struct kobject *kobj = &cdev->kobj; + + /* force an update based on parameters read from the device */ + sysfs_update_group(kobj, &target_attribute_group); + + return 0; +} + struct scsi_transport_template * spi_attach_transport(struct spi_function_template *ft) { - int count = 0; struct spi_internal *i = kzalloc(sizeof(struct spi_internal), GFP_KERNEL); @@ -1360,47 +1482,17 @@ spi_attach_transport(struct spi_function_template *ft) return NULL; i->t.target_attrs.ac.class = &spi_transport_class.class; - i->t.target_attrs.ac.attrs = &i->attrs[0]; + i->t.target_attrs.ac.grp = &target_attribute_group; i->t.target_attrs.ac.match = spi_target_match; transport_container_register(&i->t.target_attrs); i->t.target_size = sizeof(struct spi_transport_attrs); i->t.host_attrs.ac.class = &spi_host_class.class; - i->t.host_attrs.ac.attrs = &i->host_attrs[0]; + i->t.host_attrs.ac.grp = &host_attribute_group; i->t.host_attrs.ac.match = spi_host_match; transport_container_register(&i->t.host_attrs); i->t.host_size = sizeof(struct spi_host_attrs); i->f = ft; - SETUP_ATTRIBUTE(period); - SETUP_RELATED_ATTRIBUTE(min_period, period); - SETUP_ATTRIBUTE(offset); - SETUP_RELATED_ATTRIBUTE(max_offset, offset); - SETUP_ATTRIBUTE(width); - SETUP_RELATED_ATTRIBUTE(max_width, width); - SETUP_ATTRIBUTE(iu); - SETUP_ATTRIBUTE(dt); - SETUP_ATTRIBUTE(qas); - SETUP_ATTRIBUTE(wr_flow); - SETUP_ATTRIBUTE(rd_strm); - SETUP_ATTRIBUTE(rti); - SETUP_ATTRIBUTE(pcomp_en); - SETUP_ATTRIBUTE(hold_mcs); - - /* if you add an attribute but forget to increase SPI_NUM_ATTRS - * this bug will trigger */ - BUG_ON(count > SPI_NUM_ATTRS); - - i->attrs[count++] = &class_device_attr_revalidate; - - i->attrs[count] = NULL; - - count = 0; - SETUP_HOST_ATTRIBUTE(signalling); - - BUG_ON(count > SPI_HOST_ATTRS); - - i->host_attrs[count] = NULL; - return &i->t; } EXPORT_SYMBOL(spi_attach_transport);