@@ -81,6 +81,34 @@ const char *scsi_host_state_name(enum scsi_host_state state)
return name;
}
+static const struct {
+ enum scsi_access_state value;
+ char *name;
+} sdev_access_states[] = {
+ { SCSI_ACCESS_STATE_UNKNOWN, "unknown" },
+ { SCSI_ACCESS_STATE_OPTIMAL, "optimal" },
+ { SCSI_ACCESS_STATE_ACTIVE, "active" },
+ { SCSI_ACCESS_STATE_PASSIVE, "passive" },
+ { SCSI_ACCESS_STATE_UNAVAILABLE, "unavailable" },
+ { SCSI_ACCESS_STATE_LBA, "lba-dependent" },
+ { SCSI_ACCESS_STATE_OFFLINE, "offline" },
+ { SCSI_ACCESS_STATE_TRANSITIONING, "transitioning" },
+ { SCSI_ACCESS_STATE_PREFERRED, "preferred" },
+};
+const char *scsi_access_state_name(enum scsi_access_state 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;
@@ -934,6 +962,30 @@ 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);
+ enum scsi_access_state access_state = SCSI_ACCESS_STATE_UNKNOWN;
+ bool pref = false;
+
+ if (sdev->handler && sdev->handler->state) {
+ int state = sdev->handler->state(sdev);
+
+ if (state & SCSI_ACCESS_STATE_PREFERRED)
+ pref = true;
+
+ access_state = (state & SCSI_ACCESS_STATE_MASK);
+ }
+
+ return snprintf(buf, 32, "%s%s\n",
+ scsi_access_state_name(access_state),
+ pref ? " preferred" :"");
+}
+static DEVICE_ATTR(access_state, S_IRUGO, sdev_show_access_state, NULL);
#endif
static ssize_t
@@ -1007,6 +1059,7 @@ static struct attribute *scsi_sdev_attrs[] = {
&dev_attr_queue_type.attr,
#ifdef CONFIG_SCSI_DH
&dev_attr_dh_state.attr,
+ &dev_attr_access_state.attr,
#endif
&dev_attr_queue_ramp_up_period.attr,
REF_EVT(media_change),
@@ -50,6 +50,19 @@ enum scsi_device_state {
SDEV_CREATED_BLOCK, /* same as above but for created devices */
};
+enum scsi_access_state {
+ SCSI_ACCESS_STATE_UNKNOWN = 0,
+ SCSI_ACCESS_STATE_OPTIMAL,
+ SCSI_ACCESS_STATE_ACTIVE,
+ SCSI_ACCESS_STATE_PASSIVE,
+ SCSI_ACCESS_STATE_UNAVAILABLE,
+ SCSI_ACCESS_STATE_LBA,
+ SCSI_ACCESS_STATE_OFFLINE,
+ SCSI_ACCESS_STATE_TRANSITIONING,
+ SCSI_ACCESS_STATE_PREFERRED = 0x80
+};
+#define SCSI_ACCESS_STATE_MASK 0x7f
+
enum scsi_device_event {
SDEV_EVT_MEDIA_CHANGE = 1, /* media has changed */
SDEV_EVT_INQUIRY_CHANGE_REPORTED, /* 3F 03 UA reported */
@@ -71,6 +71,7 @@ struct scsi_device_handler {
int (*prep_fn)(struct scsi_device *, struct request *);
int (*set_params)(struct scsi_device *, const char *);
void (*rescan)(struct scsi_device *);
+ int (*state)(struct scsi_device *);
};
#ifdef CONFIG_SCSI_DH
Add an 'access_state' attribute to display the LUN access state. Signed-off-by: Hannes Reinecke <hare@suse.de> --- drivers/scsi/scsi_sysfs.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++ include/scsi/scsi_device.h | 13 ++++++++++++ include/scsi/scsi_dh.h | 1 + 3 files changed, 67 insertions(+)