X-Git-Url: https://git.karo-electronics.de/?a=blobdiff_plain;f=drivers%2Fscsi%2Fscsi_sysfs.c;h=d16441961f3ab0d5c97f6e42dd171fbe69fa6f47;hb=5a6b7e53d035db7941b27122365cca9f2e912596;hp=00bc7218a7f80f06a139a7743b5a2c51331f68f0;hpb=905373b6377394ae6819574ed3c170632c8bab59;p=karo-tx-linux.git diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 00bc7218a7f8..d16441961f3a 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -81,6 +81,33 @@ const char *scsi_host_state_name(enum scsi_host_state state) return name; } +static const struct { + unsigned char value; + char *name; +} sdev_access_states[] = { + { SCSI_ACCESS_STATE_OPTIMAL, "active/optimized" }, + { SCSI_ACCESS_STATE_ACTIVE, "active/non-optimized" }, + { SCSI_ACCESS_STATE_STANDBY, "standby" }, + { SCSI_ACCESS_STATE_UNAVAILABLE, "unavailable" }, + { SCSI_ACCESS_STATE_LBA, "lba-dependent" }, + { SCSI_ACCESS_STATE_OFFLINE, "offline" }, + { SCSI_ACCESS_STATE_TRANSITIONING, "transitioning" }, +}; + +const char *scsi_access_state_name(unsigned char state) +{ + int i; + char *name = NULL; + + for (i = 0; i < ARRAY_SIZE(sdev_access_states); i++) { + if (sdev_access_states[i].value == state) { + name = sdev_access_states[i].name; + break; + } + } + return name; +} + static int check_set(unsigned long long *val, char *src) { char *last; @@ -973,6 +1000,43 @@ sdev_store_dh_state(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR(dh_state, S_IRUGO | S_IWUSR, sdev_show_dh_state, sdev_store_dh_state); + +static ssize_t +sdev_show_access_state(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct scsi_device *sdev = to_scsi_device(dev); + unsigned char access_state; + const char *access_state_name; + + if (!sdev->handler) + return -EINVAL; + + access_state = (sdev->access_state & SCSI_ACCESS_STATE_MASK); + access_state_name = scsi_access_state_name(access_state); + + return sprintf(buf, "%s\n", + access_state_name ? access_state_name : "unknown"); +} +static DEVICE_ATTR(access_state, S_IRUGO, sdev_show_access_state, NULL); + +static ssize_t +sdev_show_preferred_path(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct scsi_device *sdev = to_scsi_device(dev); + + if (!sdev->handler) + return -EINVAL; + + if (sdev->access_state & SCSI_ACCESS_STATE_PREFERRED) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} +static DEVICE_ATTR(preferred_path, S_IRUGO, sdev_show_preferred_path, NULL); #endif static ssize_t @@ -1020,9 +1084,33 @@ static umode_t scsi_sdev_attr_is_visible(struct kobject *kobj, !sdev->host->hostt->change_queue_depth) return 0; +#ifdef CONFIG_SCSI_DH + if (attr == &dev_attr_access_state.attr && + !sdev->handler) + return 0; + if (attr == &dev_attr_preferred_path.attr && + !sdev->handler) + return 0; +#endif return attr->mode; } +static umode_t scsi_sdev_bin_attr_is_visible(struct kobject *kobj, + struct bin_attribute *attr, int i) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct scsi_device *sdev = to_scsi_device(dev); + + + if (attr == &dev_attr_vpd_pg80 && !sdev->vpd_pg80) + return 0; + + if (attr == &dev_attr_vpd_pg83 && sdev->vpd_pg83) + return 0; + + return S_IRUGO; +} + /* Default template for device attributes. May NOT be modified */ static struct attribute *scsi_sdev_attrs[] = { &dev_attr_device_blocked.attr, @@ -1047,6 +1135,8 @@ static struct attribute *scsi_sdev_attrs[] = { &dev_attr_wwid.attr, #ifdef CONFIG_SCSI_DH &dev_attr_dh_state.attr, + &dev_attr_access_state.attr, + &dev_attr_preferred_path.attr, #endif &dev_attr_queue_ramp_up_period.attr, REF_EVT(media_change), @@ -1068,6 +1158,7 @@ static struct attribute_group scsi_sdev_attr_group = { .attrs = scsi_sdev_attrs, .bin_attrs = scsi_sdev_bin_attrs, .is_visible = scsi_sdev_attr_is_visible, + .is_bin_visible = scsi_sdev_bin_attr_is_visible, }; static const struct attribute_group *scsi_sdev_attr_groups[] = { @@ -1129,13 +1220,6 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) scsi_autopm_get_device(sdev); - error = device_add(&sdev->sdev_gendev); - if (error) { - sdev_printk(KERN_INFO, sdev, - "failed to add device: %d\n", error); - return error; - } - error = scsi_dh_add_device(sdev); if (error) /* @@ -1144,6 +1228,14 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) sdev_printk(KERN_INFO, sdev, "failed to add device handler: %d\n", error); + error = device_add(&sdev->sdev_gendev); + if (error) { + sdev_printk(KERN_INFO, sdev, + "failed to add device: %d\n", error); + scsi_dh_remove_device(sdev); + return error; + } + device_enable_async_suspend(&sdev->sdev_dev); error = device_add(&sdev->sdev_dev); if (error) {