diff options
author | Hannes Reinecke <hare@suse.de> | 2016-03-03 01:54:07 -0500 |
---|---|---|
committer | Martin K. Petersen <martin.petersen@oracle.com> | 2016-03-05 17:14:37 -0500 |
commit | 77c9df9644d7c35516770a21cb56b413e8547d8f (patch) | |
tree | bb7303df95797e5b6d2b3a6961b079a6725c24e6 /drivers/scsi/scsi_sysfs.c | |
parent | 7e47976bcff23cbe011635e8931855cd3fb3aa6f (diff) |
scsi: Add 'access_state' and 'preferred_path' attribute
Add an 'access_state' field to struct scsi_device and display them in
sysfs as 'access_state' and 'preferred_path' attribute.
Signed-off-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
Reviewed-by: Bart van Assche <bart.vanassche@sandisk.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi/scsi_sysfs.c')
-rw-r--r-- | drivers/scsi/scsi_sysfs.c | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 7e57800684e8..c5ac1719d89d 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) | |||
81 | return name; | 81 | return name; |
82 | } | 82 | } |
83 | 83 | ||
84 | static const struct { | ||
85 | unsigned char value; | ||
86 | char *name; | ||
87 | } sdev_access_states[] = { | ||
88 | { SCSI_ACCESS_STATE_OPTIMAL, "active/optimized" }, | ||
89 | { SCSI_ACCESS_STATE_ACTIVE, "active/non-optimized" }, | ||
90 | { SCSI_ACCESS_STATE_STANDBY, "standby" }, | ||
91 | { SCSI_ACCESS_STATE_UNAVAILABLE, "unavailable" }, | ||
92 | { SCSI_ACCESS_STATE_LBA, "lba-dependent" }, | ||
93 | { SCSI_ACCESS_STATE_OFFLINE, "offline" }, | ||
94 | { SCSI_ACCESS_STATE_TRANSITIONING, "transitioning" }, | ||
95 | }; | ||
96 | |||
97 | const char *scsi_access_state_name(unsigned char state) | ||
98 | { | ||
99 | int i; | ||
100 | char *name = NULL; | ||
101 | |||
102 | for (i = 0; i < ARRAY_SIZE(sdev_access_states); i++) { | ||
103 | if (sdev_access_states[i].value == state) { | ||
104 | name = sdev_access_states[i].name; | ||
105 | break; | ||
106 | } | ||
107 | } | ||
108 | return name; | ||
109 | } | ||
110 | |||
84 | static int check_set(unsigned long long *val, char *src) | 111 | static int check_set(unsigned long long *val, char *src) |
85 | { | 112 | { |
86 | char *last; | 113 | char *last; |
@@ -973,6 +1000,43 @@ sdev_store_dh_state(struct device *dev, struct device_attribute *attr, | |||
973 | 1000 | ||
974 | static DEVICE_ATTR(dh_state, S_IRUGO | S_IWUSR, sdev_show_dh_state, | 1001 | static DEVICE_ATTR(dh_state, S_IRUGO | S_IWUSR, sdev_show_dh_state, |
975 | sdev_store_dh_state); | 1002 | sdev_store_dh_state); |
1003 | |||
1004 | static ssize_t | ||
1005 | sdev_show_access_state(struct device *dev, | ||
1006 | struct device_attribute *attr, | ||
1007 | char *buf) | ||
1008 | { | ||
1009 | struct scsi_device *sdev = to_scsi_device(dev); | ||
1010 | unsigned char access_state; | ||
1011 | const char *access_state_name; | ||
1012 | |||
1013 | if (!sdev->handler) | ||
1014 | return -EINVAL; | ||
1015 | |||
1016 | access_state = (sdev->access_state & SCSI_ACCESS_STATE_MASK); | ||
1017 | access_state_name = scsi_access_state_name(access_state); | ||
1018 | |||
1019 | return sprintf(buf, "%s\n", | ||
1020 | access_state_name ? access_state_name : "unknown"); | ||
1021 | } | ||
1022 | static DEVICE_ATTR(access_state, S_IRUGO, sdev_show_access_state, NULL); | ||
1023 | |||
1024 | static ssize_t | ||
1025 | sdev_show_preferred_path(struct device *dev, | ||
1026 | struct device_attribute *attr, | ||
1027 | char *buf) | ||
1028 | { | ||
1029 | struct scsi_device *sdev = to_scsi_device(dev); | ||
1030 | |||
1031 | if (!sdev->handler) | ||
1032 | return -EINVAL; | ||
1033 | |||
1034 | if (sdev->access_state & SCSI_ACCESS_STATE_PREFERRED) | ||
1035 | return sprintf(buf, "1\n"); | ||
1036 | else | ||
1037 | return sprintf(buf, "0\n"); | ||
1038 | } | ||
1039 | static DEVICE_ATTR(preferred_path, S_IRUGO, sdev_show_preferred_path, NULL); | ||
976 | #endif | 1040 | #endif |
977 | 1041 | ||
978 | static ssize_t | 1042 | static ssize_t |
@@ -1020,6 +1084,14 @@ static umode_t scsi_sdev_attr_is_visible(struct kobject *kobj, | |||
1020 | !sdev->host->hostt->change_queue_depth) | 1084 | !sdev->host->hostt->change_queue_depth) |
1021 | return 0; | 1085 | return 0; |
1022 | 1086 | ||
1087 | #ifdef CONFIG_SCSI_DH | ||
1088 | if (attr == &dev_attr_access_state.attr && | ||
1089 | !sdev->handler) | ||
1090 | return 0; | ||
1091 | if (attr == &dev_attr_preferred_path.attr && | ||
1092 | !sdev->handler) | ||
1093 | return 0; | ||
1094 | #endif | ||
1023 | return attr->mode; | 1095 | return attr->mode; |
1024 | } | 1096 | } |
1025 | 1097 | ||
@@ -1063,6 +1135,8 @@ static struct attribute *scsi_sdev_attrs[] = { | |||
1063 | &dev_attr_wwid.attr, | 1135 | &dev_attr_wwid.attr, |
1064 | #ifdef CONFIG_SCSI_DH | 1136 | #ifdef CONFIG_SCSI_DH |
1065 | &dev_attr_dh_state.attr, | 1137 | &dev_attr_dh_state.attr, |
1138 | &dev_attr_access_state.attr, | ||
1139 | &dev_attr_preferred_path.attr, | ||
1066 | #endif | 1140 | #endif |
1067 | &dev_attr_queue_ramp_up_period.attr, | 1141 | &dev_attr_queue_ramp_up_period.attr, |
1068 | REF_EVT(media_change), | 1142 | REF_EVT(media_change), |