]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/scsi/scsi_transport_spi.c
[SCSI] scsi_transport_spi: fix the attribute settings
[linux-2.6-omap-h63xx.git] / drivers / scsi / scsi_transport_spi.c
index 6f56f8750635eca0e44ec6af2914a40f54b7c123..3a26f7489b4862e58bec50ee273f638852e51038 100644 (file)
 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 +158,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 +167,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 +190,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 +219,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 +248,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 +261,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 +278,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 +293,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 +334,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");
@@ -368,14 +375,15 @@ static int child_iter(struct device *dev, void *data)
 }
 
 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 +418,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 +455,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 +471,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 +481,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 +494,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 +528,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 +545,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)               \
@@ -787,10 +812,12 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer)
        struct scsi_target *starget = sdev->sdev_target;
        struct Scsi_Host *shost = sdev->host;
        int len = sdev->inquiry_len;
+       int min_period = spi_min_period(starget);
+       int max_width = spi_max_width(starget);
        /* first set us up for narrow async */
        DV_SET(offset, 0);
        DV_SET(width, 0);
-       
+
        if (spi_dv_device_compare_inquiry(sdev, buffer, buffer, DV_LOOPS)
            != SPI_COMPARE_SUCCESS) {
                starget_printk(KERN_ERR, starget, "Domain Validation Initial Inquiry Failed\n");
@@ -798,9 +825,13 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer)
                return;
        }
 
+       if (!scsi_device_wide(sdev)) {
+               spi_max_width(starget) = 0;
+               max_width = 0;
+       }
+
        /* test width */
-       if (i->f->set_width && spi_max_width(starget) &&
-           scsi_device_wide(sdev)) {
+       if (i->f->set_width && max_width) {
                i->f->set_width(starget, 1);
 
                if (spi_dv_device_compare_inquiry(sdev, buffer,
@@ -809,6 +840,11 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer)
                    != SPI_COMPARE_SUCCESS) {
                        starget_printk(KERN_ERR, starget, "Wide Transfers Fail\n");
                        i->f->set_width(starget, 0);
+                       /* Make sure we don't force wide back on by asking
+                        * for a transfer period that requires it */
+                       max_width = 0;
+                       if (min_period < 10)
+                               min_period = 10;
                }
        }
 
@@ -828,7 +864,8 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer)
 
        /* now set up to the maximum */
        DV_SET(offset, spi_max_offset(starget));
-       DV_SET(period, spi_min_period(starget));
+       DV_SET(period, min_period);
+
        /* try QAS requests; this should be harmless to set if the
         * target supports it */
        if (scsi_device_qas(sdev)) {
@@ -837,14 +874,14 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer)
                DV_SET(qas, 0);
        }
 
-       if (scsi_device_ius(sdev) && spi_min_period(starget) < 9) {
+       if (scsi_device_ius(sdev) && min_period < 9) {
                /* This u320 (or u640). Set IU transfers */
                DV_SET(iu, 1);
                /* Then set the optional parameters */
                DV_SET(rd_strm, 1);
                DV_SET(wr_flow, 1);
                DV_SET(rti, 1);
-               if (spi_min_period(starget) == 8)
+               if (min_period == 8)
                        DV_SET(pcomp_en, 1);
        } else {
                DV_SET(iu, 0);
@@ -862,6 +899,10 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer)
        } else {
                DV_SET(dt, 1);
        }
+       /* set width last because it will pull all the other
+        * parameters down to required values */
+       DV_SET(width, max_width);
+
        /* Do the read only INQUIRY tests */
        spi_dv_retrain(sdev, buffer, buffer + sdev->inquiry_len,
                       spi_dv_device_compare_inquiry);
@@ -1246,35 +1287,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)
 {
@@ -1327,16 +1339,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);
 
@@ -1344,47 +1479,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);