Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
[safe/jmp/linux-2.6] / drivers / ata / libata-scsi.c
index f3b4b15..59fe051 100644 (file)
@@ -183,6 +183,105 @@ DEVICE_ATTR(link_power_management_policy, S_IRUGO | S_IWUSR,
                ata_scsi_lpm_show, ata_scsi_lpm_put);
 EXPORT_SYMBOL_GPL(dev_attr_link_power_management_policy);
 
+static ssize_t ata_scsi_park_show(struct device *device,
+                                 struct device_attribute *attr, char *buf)
+{
+       struct scsi_device *sdev = to_scsi_device(device);
+       struct ata_port *ap;
+       struct ata_link *link;
+       struct ata_device *dev;
+       unsigned long flags;
+       unsigned int uninitialized_var(msecs);
+       int rc = 0;
+
+       ap = ata_shost_to_port(sdev->host);
+
+       spin_lock_irqsave(ap->lock, flags);
+       dev = ata_scsi_find_dev(ap, sdev);
+       if (!dev) {
+               rc = -ENODEV;
+               goto unlock;
+       }
+       if (dev->flags & ATA_DFLAG_NO_UNLOAD) {
+               rc = -EOPNOTSUPP;
+               goto unlock;
+       }
+
+       link = dev->link;
+       if (ap->pflags & ATA_PFLAG_EH_IN_PROGRESS &&
+           link->eh_context.unloaded_mask & (1 << dev->devno) &&
+           time_after(dev->unpark_deadline, jiffies))
+               msecs = jiffies_to_msecs(dev->unpark_deadline - jiffies);
+       else
+               msecs = 0;
+
+unlock:
+       spin_unlock_irq(ap->lock);
+
+       return rc ? rc : snprintf(buf, 20, "%u\n", msecs);
+}
+
+static ssize_t ata_scsi_park_store(struct device *device,
+                                  struct device_attribute *attr,
+                                  const char *buf, size_t len)
+{
+       struct scsi_device *sdev = to_scsi_device(device);
+       struct ata_port *ap;
+       struct ata_device *dev;
+       long int input;
+       unsigned long flags;
+       int rc;
+
+       rc = strict_strtol(buf, 10, &input);
+       if (rc || input < -2)
+               return -EINVAL;
+       if (input > ATA_TMOUT_MAX_PARK) {
+               rc = -EOVERFLOW;
+               input = ATA_TMOUT_MAX_PARK;
+       }
+
+       ap = ata_shost_to_port(sdev->host);
+
+       spin_lock_irqsave(ap->lock, flags);
+       dev = ata_scsi_find_dev(ap, sdev);
+       if (unlikely(!dev)) {
+               rc = -ENODEV;
+               goto unlock;
+       }
+       if (dev->class != ATA_DEV_ATA) {
+               rc = -EOPNOTSUPP;
+               goto unlock;
+       }
+
+       if (input >= 0) {
+               if (dev->flags & ATA_DFLAG_NO_UNLOAD) {
+                       rc = -EOPNOTSUPP;
+                       goto unlock;
+               }
+
+               dev->unpark_deadline = ata_deadline(jiffies, input);
+               dev->link->eh_info.dev_action[dev->devno] |= ATA_EH_PARK;
+               ata_port_schedule_eh(ap);
+               complete(&ap->park_req_pending);
+       } else {
+               switch (input) {
+               case -1:
+                       dev->flags &= ~ATA_DFLAG_NO_UNLOAD;
+                       break;
+               case -2:
+                       dev->flags |= ATA_DFLAG_NO_UNLOAD;
+                       break;
+               }
+       }
+unlock:
+       spin_unlock_irqrestore(ap->lock, flags);
+
+       return rc ? rc : len;
+}
+DEVICE_ATTR(unload_heads, S_IRUGO | S_IWUSR,
+           ata_scsi_park_show, ata_scsi_park_store);
+EXPORT_SYMBOL_GPL(dev_attr_unload_heads);
+
 static void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq)
 {
        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,
                        ata_scsi_activity_store);
 EXPORT_SYMBOL_GPL(dev_attr_sw_activity);
 
+struct device_attribute *ata_common_sdev_attrs[] = {
+       &dev_attr_unload_heads,
+       NULL
+};
+EXPORT_SYMBOL_GPL(ata_common_sdev_attrs);
+
 static void ata_scsi_invalid_field(struct scsi_cmnd *cmd,
                                   void (*done)(struct scsi_cmnd *))
 {
@@ -954,6 +1059,9 @@ static int atapi_drain_needed(struct request *rq)
 static int ata_scsi_dev_config(struct scsi_device *sdev,
                               struct ata_device *dev)
 {
+       if (!ata_id_has_unload(dev->id))
+               dev->flags |= ATA_DFLAG_NO_UNLOAD;
+
        /* configure max sectors */
        blk_queue_max_sectors(sdev->request_queue, dev->max_sectors);
 
@@ -977,6 +1085,10 @@ static int ata_scsi_dev_config(struct scsi_device *sdev,
 
                blk_queue_dma_drain(q, atapi_drain_needed, buf, ATAPI_MAX_DRAIN);
        } else {
+               if (ata_id_is_ssd(dev->id))
+                       queue_flag_set_unlocked(QUEUE_FLAG_NONROT,
+                                               sdev->request_queue);
+
                /* ATA devices must be sector aligned */
                blk_queue_update_dma_alignment(sdev->request_queue,
                                               ATA_SECT_SIZE - 1);
@@ -2551,36 +2663,6 @@ static struct ata_device *__ata_scsi_find_dev(struct ata_port *ap,
 }
 
 /**
- *     ata_scsi_dev_enabled - determine if device is enabled
- *     @dev: ATA device
- *
- *     Determine if commands should be sent to the specified device.
- *
- *     LOCKING:
- *     spin_lock_irqsave(host lock)
- *
- *     RETURNS:
- *     0 if commands are not allowed / 1 if commands are allowed
- */
-
-static int ata_scsi_dev_enabled(struct ata_device *dev)
-{
-       if (unlikely(!ata_dev_enabled(dev)))
-               return 0;
-
-       if (!atapi_enabled || (dev->link->ap->flags & ATA_FLAG_NO_ATAPI)) {
-               if (unlikely(dev->class == ATA_DEV_ATAPI)) {
-                       ata_dev_printk(dev, KERN_WARNING,
-                                      "WARNING: ATAPI is %s, device ignored.\n",
-                                      atapi_enabled ? "not supported with this driver" : "disabled");
-                       return 0;
-               }
-       }
-
-       return 1;
-}
-
-/**
  *     ata_scsi_find_dev - lookup ata_device from scsi_cmnd
  *     @ap: ATA port to which the device is attached
  *     @scsidev: SCSI device from which we derive the ATA device
@@ -2601,7 +2683,7 @@ ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev)
 {
        struct ata_device *dev = __ata_scsi_find_dev(ap, scsidev);
 
-       if (unlikely(!dev || !ata_scsi_dev_enabled(dev)))
+       if (unlikely(!dev || !ata_dev_enabled(dev)))
                return NULL;
 
        return dev;
@@ -3622,7 +3704,7 @@ int ata_sas_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *),
 
        ata_scsi_dump_cdb(ap, cmd);
 
-       if (likely(ata_scsi_dev_enabled(ap->link.device)))
+       if (likely(ata_dev_enabled(ap->link.device)))
                rc = __ata_scsi_queuecmd(cmd, done, ap->link.device);
        else {
                cmd->result = (DID_BAD_TARGET << 16);