]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/ata/libata-core.c
libata-core: Allow translation setting to fail
[mirror_ubuntu-artful-kernel.git] / drivers / ata / libata-core.c
index 39a8e986a4ea0c2d1296bd15a46ef8512f88a1cb..9cf46bf8c8d2c4e3c1511fe2a2c66efd5eb3642e 100644 (file)
@@ -1723,7 +1723,7 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
                tf.protocol = ATA_PROT_NODATA;
                tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
                err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
-               if (err_mask) {
+               if (err_mask && id[2] != 0x738c) {
                        rc = -EIO;
                        reason = "SPINUP failed";
                        goto err_out;
@@ -2389,21 +2389,35 @@ int sata_down_spd_limit(struct ata_port *ap)
        u32 sstatus, spd, mask;
        int rc, highbit;
 
+       if (!sata_scr_valid(ap))
+               return -EOPNOTSUPP;
+
+       /* If SCR can be read, use it to determine the current SPD.
+        * If not, use cached value in ap->sata_spd.
+        */
        rc = sata_scr_read(ap, SCR_STATUS, &sstatus);
-       if (rc)
-               return rc;
+       if (rc == 0)
+               spd = (sstatus >> 4) & 0xf;
+       else
+               spd = ap->sata_spd;
 
        mask = ap->sata_spd_limit;
        if (mask <= 1)
                return -EINVAL;
+
+       /* unconditionally mask off the highest bit */
        highbit = fls(mask) - 1;
        mask &= ~(1 << highbit);
 
-       spd = (sstatus >> 4) & 0xf;
-       if (spd <= 1)
-               return -EINVAL;
-       spd--;
-       mask &= (1 << spd) - 1;
+       /* Mask off all speeds higher than or equal to the current
+        * one.  Force 1.5Gbps if current SPD is not available.
+        */
+       if (spd > 1)
+               mask &= (1 << (spd - 1)) - 1;
+       else
+               mask &= 1;
+
+       /* were we already at the bottom? */
        if (!mask)
                return -EINVAL;
 
@@ -3253,9 +3267,11 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params,
                last = cur;
                last_jiffies = jiffies;
 
-               /* check deadline */
+               /* Check deadline.  If debouncing failed, return
+                * -EPIPE to tell upper layer to lower link speed.
+                */
                if (time_after(jiffies, deadline))
-                       return -EBUSY;
+                       return -EPIPE;
        }
 }
 
@@ -3684,11 +3700,16 @@ int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags)
                goto fail;
 
        /* verify n_sectors hasn't changed */
-       if (dev->class == ATA_DEV_ATA && dev->n_sectors != n_sectors) {
+       if (dev->class == ATA_DEV_ATA && n_sectors &&
+           dev->n_sectors != n_sectors) {
                ata_dev_printk(dev, KERN_INFO, "n_sectors mismatch "
                               "%llu != %llu\n",
                               (unsigned long long)n_sectors,
                               (unsigned long long)dev->n_sectors);
+
+               /* restore original n_sectors */
+               dev->n_sectors = n_sectors;
+
                rc = -ENODEV;
                goto fail;
        }
@@ -3772,6 +3793,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        { "WDC WD740ADFD-00NLR1", NULL,         ATA_HORKAGE_NONCQ, },
        { "FUJITSU MHV2080BH",  "00840028",     ATA_HORKAGE_NONCQ, },
        { "ST9160821AS",        "3.CLF",        ATA_HORKAGE_NONCQ, },
+       { "SAMSUNG HD401LJ",    "ZZ100-15",     ATA_HORKAGE_NONCQ, },
 
        /* Devices with NCQ limits */
 
@@ -3963,6 +3985,11 @@ static unsigned int ata_dev_init_params(struct ata_device *dev,
        tf.device |= (heads - 1) & 0x0f; /* max head = num. of heads - 1 */
 
        err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+       /* A clean abort indicates an original or just out of spec drive
+          and we should continue as we issue the setup based on the
+          drive reported working geometry */
+       if (err_mask == AC_ERR_DEV && (tf.feature & ATA_ABORTED))
+               err_mask = 0;
 
        DPRINTK("EXIT, err_mask=%x\n", err_mask);
        return err_mask;
@@ -5732,10 +5759,8 @@ int sata_scr_valid(struct ata_port *ap)
  */
 int sata_scr_read(struct ata_port *ap, int reg, u32 *val)
 {
-       if (sata_scr_valid(ap)) {
-               *val = ap->ops->scr_read(ap, reg);
-               return 0;
-       }
+       if (sata_scr_valid(ap))
+               return ap->ops->scr_read(ap, reg, val);
        return -EOPNOTSUPP;
 }
 
@@ -5757,10 +5782,8 @@ int sata_scr_read(struct ata_port *ap, int reg, u32 *val)
  */
 int sata_scr_write(struct ata_port *ap, int reg, u32 val)
 {
-       if (sata_scr_valid(ap)) {
-               ap->ops->scr_write(ap, reg, val);
-               return 0;
-       }
+       if (sata_scr_valid(ap))
+               return ap->ops->scr_write(ap, reg, val);
        return -EOPNOTSUPP;
 }
 
@@ -5781,10 +5804,13 @@ int sata_scr_write(struct ata_port *ap, int reg, u32 val)
  */
 int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val)
 {
+       int rc;
+
        if (sata_scr_valid(ap)) {
-               ap->ops->scr_write(ap, reg, val);
-               ap->ops->scr_read(ap, reg);
-               return 0;
+               rc = ap->ops->scr_write(ap, reg, val);
+               if (rc == 0)
+                       rc = ap->ops->scr_read(ap, reg, &val);
+               return rc;
        }
        return -EOPNOTSUPP;
 }
@@ -5996,6 +6022,7 @@ void ata_dev_init(struct ata_device *dev)
 
        /* SATA spd limit is bound to the first device */
        ap->sata_spd_limit = ap->hw_sata_spd_limit;
+       ap->sata_spd = 0;
 
        /* High bits of dev->flags are used to record warm plug
         * requests which occur asynchronously.  Synchronize using
@@ -6061,6 +6088,9 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
        INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan);
        INIT_LIST_HEAD(&ap->eh_done_q);
        init_waitqueue_head(&ap->eh_wait_q);
+       init_timer_deferrable(&ap->fastdrain_timer);
+       ap->fastdrain_timer.function = ata_eh_fastdrain_timerfn;
+       ap->fastdrain_timer.data = (unsigned long)ap;
 
        ap->cbl = ATA_CBL_NONE;
 
@@ -6437,7 +6467,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
        for (i = 0; i < host->n_ports; i++) {
                struct ata_port *ap = host->ports[i];
 
-               ata_scsi_scan_host(ap);
+               ata_scsi_scan_host(ap, 1);
        }
 
        return 0;
@@ -6945,6 +6975,9 @@ EXPORT_SYMBOL_GPL(ata_pci_default_filter);
 EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
 #endif /* CONFIG_PCI */
 
+EXPORT_SYMBOL_GPL(__ata_ehi_push_desc);
+EXPORT_SYMBOL_GPL(ata_ehi_push_desc);
+EXPORT_SYMBOL_GPL(ata_ehi_clear_desc);
 EXPORT_SYMBOL_GPL(ata_eng_timeout);
 EXPORT_SYMBOL_GPL(ata_port_schedule_eh);
 EXPORT_SYMBOL_GPL(ata_port_abort);