diff options
Diffstat (limited to 'drivers/ata/libata-scsi.c')
| -rw-r--r-- | drivers/ata/libata-scsi.c | 108 | 
1 files changed, 108 insertions, 0 deletions
| diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index b9d3ba423cb2..fccd5e496c62 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c | |||
| @@ -183,6 +183,105 @@ DEVICE_ATTR(link_power_management_policy, S_IRUGO | S_IWUSR, | |||
| 183 | ata_scsi_lpm_show, ata_scsi_lpm_put); | 183 | ata_scsi_lpm_show, ata_scsi_lpm_put); | 
| 184 | EXPORT_SYMBOL_GPL(dev_attr_link_power_management_policy); | 184 | EXPORT_SYMBOL_GPL(dev_attr_link_power_management_policy); | 
| 185 | 185 | ||
| 186 | static ssize_t ata_scsi_park_show(struct device *device, | ||
| 187 | struct device_attribute *attr, char *buf) | ||
| 188 | { | ||
| 189 | struct scsi_device *sdev = to_scsi_device(device); | ||
| 190 | struct ata_port *ap; | ||
| 191 | struct ata_link *link; | ||
| 192 | struct ata_device *dev; | ||
| 193 | unsigned long flags; | ||
| 194 | unsigned int uninitialized_var(msecs); | ||
| 195 | int rc = 0; | ||
| 196 | |||
| 197 | ap = ata_shost_to_port(sdev->host); | ||
| 198 | |||
| 199 | spin_lock_irqsave(ap->lock, flags); | ||
| 200 | dev = ata_scsi_find_dev(ap, sdev); | ||
| 201 | if (!dev) { | ||
| 202 | rc = -ENODEV; | ||
| 203 | goto unlock; | ||
| 204 | } | ||
| 205 | if (dev->flags & ATA_DFLAG_NO_UNLOAD) { | ||
| 206 | rc = -EOPNOTSUPP; | ||
| 207 | goto unlock; | ||
| 208 | } | ||
| 209 | |||
| 210 | link = dev->link; | ||
| 211 | if (ap->pflags & ATA_PFLAG_EH_IN_PROGRESS && | ||
| 212 | link->eh_context.unloaded_mask & (1 << dev->devno) && | ||
| 213 | time_after(dev->unpark_deadline, jiffies)) | ||
| 214 | msecs = jiffies_to_msecs(dev->unpark_deadline - jiffies); | ||
| 215 | else | ||
| 216 | msecs = 0; | ||
| 217 | |||
| 218 | unlock: | ||
| 219 | spin_unlock_irq(ap->lock); | ||
| 220 | |||
| 221 | return rc ? rc : snprintf(buf, 20, "%u\n", msecs); | ||
| 222 | } | ||
| 223 | |||
| 224 | static ssize_t ata_scsi_park_store(struct device *device, | ||
| 225 | struct device_attribute *attr, | ||
| 226 | const char *buf, size_t len) | ||
| 227 | { | ||
| 228 | struct scsi_device *sdev = to_scsi_device(device); | ||
| 229 | struct ata_port *ap; | ||
| 230 | struct ata_device *dev; | ||
| 231 | long int input; | ||
| 232 | unsigned long flags; | ||
| 233 | int rc; | ||
| 234 | |||
| 235 | rc = strict_strtol(buf, 10, &input); | ||
| 236 | if (rc || input < -2) | ||
| 237 | return -EINVAL; | ||
| 238 | if (input > ATA_TMOUT_MAX_PARK) { | ||
| 239 | rc = -EOVERFLOW; | ||
| 240 | input = ATA_TMOUT_MAX_PARK; | ||
| 241 | } | ||
| 242 | |||
| 243 | ap = ata_shost_to_port(sdev->host); | ||
| 244 | |||
| 245 | spin_lock_irqsave(ap->lock, flags); | ||
| 246 | dev = ata_scsi_find_dev(ap, sdev); | ||
| 247 | if (unlikely(!dev)) { | ||
| 248 | rc = -ENODEV; | ||
| 249 | goto unlock; | ||
| 250 | } | ||
| 251 | if (dev->class != ATA_DEV_ATA) { | ||
| 252 | rc = -EOPNOTSUPP; | ||
| 253 | goto unlock; | ||
| 254 | } | ||
| 255 | |||
| 256 | if (input >= 0) { | ||
| 257 | if (dev->flags & ATA_DFLAG_NO_UNLOAD) { | ||
| 258 | rc = -EOPNOTSUPP; | ||
| 259 | goto unlock; | ||
| 260 | } | ||
| 261 | |||
| 262 | dev->unpark_deadline = ata_deadline(jiffies, input); | ||
| 263 | dev->link->eh_info.dev_action[dev->devno] |= ATA_EH_PARK; | ||
| 264 | ata_port_schedule_eh(ap); | ||
| 265 | complete(&ap->park_req_pending); | ||
| 266 | } else { | ||
| 267 | switch (input) { | ||
| 268 | case -1: | ||
| 269 | dev->flags &= ~ATA_DFLAG_NO_UNLOAD; | ||
| 270 | break; | ||
| 271 | case -2: | ||
| 272 | dev->flags |= ATA_DFLAG_NO_UNLOAD; | ||
| 273 | break; | ||
| 274 | } | ||
| 275 | } | ||
| 276 | unlock: | ||
| 277 | spin_unlock_irqrestore(ap->lock, flags); | ||
| 278 | |||
| 279 | return rc ? rc : len; | ||
| 280 | } | ||
| 281 | DEVICE_ATTR(unload_heads, S_IRUGO | S_IWUSR, | ||
| 282 | ata_scsi_park_show, ata_scsi_park_store); | ||
| 283 | EXPORT_SYMBOL_GPL(dev_attr_unload_heads); | ||
| 284 | |||
| 186 | static void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq) | 285 | static void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq) | 
| 187 | { | 286 | { | 
| 188 | cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; | 287 | cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; | 
| @@ -269,6 +368,12 @@ DEVICE_ATTR(sw_activity, S_IWUGO | S_IRUGO, ata_scsi_activity_show, | |||
| 269 | ata_scsi_activity_store); | 368 | ata_scsi_activity_store); | 
| 270 | EXPORT_SYMBOL_GPL(dev_attr_sw_activity); | 369 | EXPORT_SYMBOL_GPL(dev_attr_sw_activity); | 
| 271 | 370 | ||
| 371 | struct device_attribute *ata_common_sdev_attrs[] = { | ||
| 372 | &dev_attr_unload_heads, | ||
| 373 | NULL | ||
| 374 | }; | ||
| 375 | EXPORT_SYMBOL_GPL(ata_common_sdev_attrs); | ||
| 376 | |||
| 272 | static void ata_scsi_invalid_field(struct scsi_cmnd *cmd, | 377 | static void ata_scsi_invalid_field(struct scsi_cmnd *cmd, | 
| 273 | void (*done)(struct scsi_cmnd *)) | 378 | void (*done)(struct scsi_cmnd *)) | 
| 274 | { | 379 | { | 
| @@ -954,6 +1059,9 @@ static int atapi_drain_needed(struct request *rq) | |||
| 954 | static int ata_scsi_dev_config(struct scsi_device *sdev, | 1059 | static int ata_scsi_dev_config(struct scsi_device *sdev, | 
| 955 | struct ata_device *dev) | 1060 | struct ata_device *dev) | 
| 956 | { | 1061 | { | 
| 1062 | if (!ata_id_has_unload(dev->id)) | ||
| 1063 | dev->flags |= ATA_DFLAG_NO_UNLOAD; | ||
| 1064 | |||
| 957 | /* configure max sectors */ | 1065 | /* configure max sectors */ | 
| 958 | blk_queue_max_sectors(sdev->request_queue, dev->max_sectors); | 1066 | blk_queue_max_sectors(sdev->request_queue, dev->max_sectors); | 
| 959 | 1067 | ||
