diff options
Diffstat (limited to 'drivers/ata/libata-scsi.c')
| -rw-r--r-- | drivers/ata/libata-scsi.c | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index f752eddc19ed..93bd36c19690 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c | |||
| @@ -110,6 +110,74 @@ static struct scsi_transport_template ata_scsi_transport_template = { | |||
| 110 | }; | 110 | }; |
| 111 | 111 | ||
| 112 | 112 | ||
| 113 | static const struct { | ||
| 114 | enum link_pm value; | ||
| 115 | const char *name; | ||
| 116 | } link_pm_policy[] = { | ||
| 117 | { NOT_AVAILABLE, "max_performance" }, | ||
| 118 | { MIN_POWER, "min_power" }, | ||
| 119 | { MAX_PERFORMANCE, "max_performance" }, | ||
| 120 | { MEDIUM_POWER, "medium_power" }, | ||
| 121 | }; | ||
| 122 | |||
| 123 | const char *ata_scsi_lpm_get(enum link_pm policy) | ||
| 124 | { | ||
| 125 | int i; | ||
| 126 | |||
| 127 | for (i = 0; i < ARRAY_SIZE(link_pm_policy); i++) | ||
| 128 | if (link_pm_policy[i].value == policy) | ||
| 129 | return link_pm_policy[i].name; | ||
| 130 | |||
| 131 | return NULL; | ||
| 132 | } | ||
| 133 | |||
| 134 | static ssize_t ata_scsi_lpm_put(struct class_device *class_dev, | ||
| 135 | const char *buf, size_t count) | ||
| 136 | { | ||
| 137 | struct Scsi_Host *shost = class_to_shost(class_dev); | ||
| 138 | struct ata_port *ap = ata_shost_to_port(shost); | ||
| 139 | enum link_pm policy = 0; | ||
| 140 | int i; | ||
| 141 | |||
| 142 | /* | ||
| 143 | * we are skipping array location 0 on purpose - this | ||
| 144 | * is because a value of NOT_AVAILABLE is displayed | ||
| 145 | * to the user as max_performance, but when the user | ||
| 146 | * writes "max_performance", they actually want the | ||
| 147 | * value to match MAX_PERFORMANCE. | ||
| 148 | */ | ||
| 149 | for (i = 1; i < ARRAY_SIZE(link_pm_policy); i++) { | ||
| 150 | const int len = strlen(link_pm_policy[i].name); | ||
| 151 | if (strncmp(link_pm_policy[i].name, buf, len) == 0 && | ||
| 152 | buf[len] == '\n') { | ||
| 153 | policy = link_pm_policy[i].value; | ||
| 154 | break; | ||
| 155 | } | ||
| 156 | } | ||
| 157 | if (!policy) | ||
| 158 | return -EINVAL; | ||
| 159 | |||
| 160 | ata_lpm_schedule(ap, policy); | ||
| 161 | return count; | ||
| 162 | } | ||
| 163 | |||
| 164 | static ssize_t | ||
| 165 | ata_scsi_lpm_show(struct class_device *class_dev, char *buf) | ||
| 166 | { | ||
| 167 | struct Scsi_Host *shost = class_to_shost(class_dev); | ||
| 168 | struct ata_port *ap = ata_shost_to_port(shost); | ||
| 169 | const char *policy = | ||
| 170 | ata_scsi_lpm_get(ap->pm_policy); | ||
| 171 | |||
| 172 | if (!policy) | ||
| 173 | return -EINVAL; | ||
| 174 | |||
| 175 | return snprintf(buf, 23, "%s\n", policy); | ||
| 176 | } | ||
| 177 | CLASS_DEVICE_ATTR(link_power_management_policy, S_IRUGO | S_IWUSR, | ||
| 178 | ata_scsi_lpm_show, ata_scsi_lpm_put); | ||
| 179 | EXPORT_SYMBOL_GPL(class_device_attr_link_power_management_policy); | ||
| 180 | |||
| 113 | static void ata_scsi_invalid_field(struct scsi_cmnd *cmd, | 181 | static void ata_scsi_invalid_field(struct scsi_cmnd *cmd, |
| 114 | void (*done)(struct scsi_cmnd *)) | 182 | void (*done)(struct scsi_cmnd *)) |
| 115 | { | 183 | { |
