]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/ata/libata-core.c
Merge remote-tracking branches 'spi/topic/spidev', 'spi/topic/sunxi', 'spi/topic...
[linux.git] / drivers / ata / libata-core.c
index 55e257c268ddde37677cf4ff85472f65e9a63c97..31c183aed368c69c9544c92ecb19853548fb8784 100644 (file)
@@ -66,6 +66,7 @@
 #include <scsi/scsi_host.h>
 #include <linux/libata.h>
 #include <asm/byteorder.h>
+#include <asm/unaligned.h>
 #include <linux/cdrom.h>
 #include <linux/ratelimit.h>
 #include <linux/pm_runtime.h>
@@ -695,7 +696,7 @@ static int ata_rwcmd_protocol(struct ata_taskfile *tf, struct ata_device *dev)
  *     RETURNS:
  *     Block address read from @tf.
  */
-u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev)
+u64 ata_tf_read_block(const struct ata_taskfile *tf, struct ata_device *dev)
 {
        u64 block = 0;
 
@@ -720,7 +721,7 @@ u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev)
                if (!sect) {
                        ata_dev_warn(dev,
                                     "device reported invalid CHS sector 0\n");
-                       sect = 1; /* oh well */
+                       return U64_MAX;
                }
 
                block = (cyl * dev->heads + head) * dev->sectors + sect - 1;
@@ -884,7 +885,7 @@ unsigned long ata_pack_xfermask(unsigned long pio_mask,
  *     @udma_mask: resulting udma_mask
  *
  *     Unpack @xfer_mask into @pio_mask, @mwdma_mask and @udma_mask.
- *     Any NULL distination masks will be ignored.
+ *     Any NULL destination masks will be ignored.
  */
 void ata_unpack_xfermask(unsigned long xfer_mask, unsigned long *pio_mask,
                         unsigned long *mwdma_mask, unsigned long *udma_mask)
@@ -2079,6 +2080,81 @@ static inline u8 ata_dev_knobble(struct ata_device *dev)
        return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id)));
 }
 
+static void ata_dev_config_ncq_send_recv(struct ata_device *dev)
+{
+       struct ata_port *ap = dev->link->ap;
+       unsigned int err_mask;
+       int log_index = ATA_LOG_NCQ_SEND_RECV * 2;
+       u16 log_pages;
+
+       err_mask = ata_read_log_page(dev, ATA_LOG_DIRECTORY,
+                                    0, ap->sector_buf, 1);
+       if (err_mask) {
+               ata_dev_dbg(dev,
+                           "failed to get Log Directory Emask 0x%x\n",
+                           err_mask);
+               return;
+       }
+       log_pages = get_unaligned_le16(&ap->sector_buf[log_index]);
+       if (!log_pages) {
+               ata_dev_warn(dev,
+                            "NCQ Send/Recv Log not supported\n");
+               return;
+       }
+       err_mask = ata_read_log_page(dev, ATA_LOG_NCQ_SEND_RECV,
+                                    0, ap->sector_buf, 1);
+       if (err_mask) {
+               ata_dev_dbg(dev,
+                           "failed to get NCQ Send/Recv Log Emask 0x%x\n",
+                           err_mask);
+       } else {
+               u8 *cmds = dev->ncq_send_recv_cmds;
+
+               dev->flags |= ATA_DFLAG_NCQ_SEND_RECV;
+               memcpy(cmds, ap->sector_buf, ATA_LOG_NCQ_SEND_RECV_SIZE);
+
+               if (dev->horkage & ATA_HORKAGE_NO_NCQ_TRIM) {
+                       ata_dev_dbg(dev, "disabling queued TRIM support\n");
+                       cmds[ATA_LOG_NCQ_SEND_RECV_DSM_OFFSET] &=
+                               ~ATA_LOG_NCQ_SEND_RECV_DSM_TRIM;
+               }
+       }
+}
+
+static void ata_dev_config_ncq_non_data(struct ata_device *dev)
+{
+       struct ata_port *ap = dev->link->ap;
+       unsigned int err_mask;
+       int log_index = ATA_LOG_NCQ_NON_DATA * 2;
+       u16 log_pages;
+
+       err_mask = ata_read_log_page(dev, ATA_LOG_DIRECTORY,
+                                    0, ap->sector_buf, 1);
+       if (err_mask) {
+               ata_dev_dbg(dev,
+                           "failed to get Log Directory Emask 0x%x\n",
+                           err_mask);
+               return;
+       }
+       log_pages = get_unaligned_le16(&ap->sector_buf[log_index]);
+       if (!log_pages) {
+               ata_dev_warn(dev,
+                            "NCQ Send/Recv Log not supported\n");
+               return;
+       }
+       err_mask = ata_read_log_page(dev, ATA_LOG_NCQ_NON_DATA,
+                                    0, ap->sector_buf, 1);
+       if (err_mask) {
+               ata_dev_dbg(dev,
+                           "failed to get NCQ Non-Data Log Emask 0x%x\n",
+                           err_mask);
+       } else {
+               u8 *cmds = dev->ncq_non_data_cmds;
+
+               memcpy(cmds, ap->sector_buf, ATA_LOG_NCQ_NON_DATA_SIZE);
+       }
+}
+
 static int ata_dev_config_ncq(struct ata_device *dev,
                               char *desc, size_t desc_sz)
 {
@@ -2123,29 +2199,125 @@ static int ata_dev_config_ncq(struct ata_device *dev,
                snprintf(desc, desc_sz, "NCQ (depth %d/%d)%s", hdepth,
                        ddepth, aa_desc);
 
-       if ((ap->flags & ATA_FLAG_FPDMA_AUX) &&
-           ata_id_has_ncq_send_and_recv(dev->id)) {
-               err_mask = ata_read_log_page(dev, ATA_LOG_NCQ_SEND_RECV,
-                                            0, ap->sector_buf, 1);
-               if (err_mask) {
-                       ata_dev_dbg(dev,
-                                   "failed to get NCQ Send/Recv Log Emask 0x%x\n",
-                                   err_mask);
-               } else {
-                       u8 *cmds = dev->ncq_send_recv_cmds;
+       if ((ap->flags & ATA_FLAG_FPDMA_AUX)) {
+               if (ata_id_has_ncq_send_and_recv(dev->id))
+                       ata_dev_config_ncq_send_recv(dev);
+               if (ata_id_has_ncq_non_data(dev->id))
+                       ata_dev_config_ncq_non_data(dev);
+       }
+
+       return 0;
+}
 
-                       dev->flags |= ATA_DFLAG_NCQ_SEND_RECV;
-                       memcpy(cmds, ap->sector_buf, ATA_LOG_NCQ_SEND_RECV_SIZE);
+static void ata_dev_config_sense_reporting(struct ata_device *dev)
+{
+       unsigned int err_mask;
 
-                       if (dev->horkage & ATA_HORKAGE_NO_NCQ_TRIM) {
-                               ata_dev_dbg(dev, "disabling queued TRIM support\n");
-                               cmds[ATA_LOG_NCQ_SEND_RECV_DSM_OFFSET] &=
-                                       ~ATA_LOG_NCQ_SEND_RECV_DSM_TRIM;
-                       }
+       if (!ata_id_has_sense_reporting(dev->id))
+               return;
+
+       if (ata_id_sense_reporting_enabled(dev->id))
+               return;
+
+       err_mask = ata_dev_set_feature(dev, SETFEATURE_SENSE_DATA, 0x1);
+       if (err_mask) {
+               ata_dev_dbg(dev,
+                           "failed to enable Sense Data Reporting, Emask 0x%x\n",
+                           err_mask);
+       }
+}
+
+static void ata_dev_config_zac(struct ata_device *dev)
+{
+       struct ata_port *ap = dev->link->ap;
+       unsigned int err_mask;
+       u8 *identify_buf = ap->sector_buf;
+       int log_index = ATA_LOG_SATA_ID_DEV_DATA * 2, i, found = 0;
+       u16 log_pages;
+
+       dev->zac_zones_optimal_open = U32_MAX;
+       dev->zac_zones_optimal_nonseq = U32_MAX;
+       dev->zac_zones_max_open = U32_MAX;
+
+       /*
+        * Always set the 'ZAC' flag for Host-managed devices.
+        */
+       if (dev->class == ATA_DEV_ZAC)
+               dev->flags |= ATA_DFLAG_ZAC;
+       else if (ata_id_zoned_cap(dev->id) == 0x01)
+               /*
+                * Check for host-aware devices.
+                */
+               dev->flags |= ATA_DFLAG_ZAC;
+
+       if (!(dev->flags & ATA_DFLAG_ZAC))
+               return;
+
+       /*
+        * Read Log Directory to figure out if IDENTIFY DEVICE log
+        * is supported.
+        */
+       err_mask = ata_read_log_page(dev, ATA_LOG_DIRECTORY,
+                                    0, ap->sector_buf, 1);
+       if (err_mask) {
+               ata_dev_info(dev,
+                            "failed to get Log Directory Emask 0x%x\n",
+                            err_mask);
+               return;
+       }
+       log_pages = get_unaligned_le16(&ap->sector_buf[log_index]);
+       if (log_pages == 0) {
+               ata_dev_warn(dev,
+                            "ATA Identify Device Log not supported\n");
+               return;
+       }
+       /*
+        * Read IDENTIFY DEVICE data log, page 0, to figure out
+        * if page 9 is supported.
+        */
+       err_mask = ata_read_log_page(dev, ATA_LOG_SATA_ID_DEV_DATA, 0,
+                                    identify_buf, 1);
+       if (err_mask) {
+               ata_dev_info(dev,
+                            "failed to get Device Identify Log Emask 0x%x\n",
+                            err_mask);
+               return;
+       }
+       log_pages = identify_buf[8];
+       for (i = 0; i < log_pages; i++) {
+               if (identify_buf[9 + i] == ATA_LOG_ZONED_INFORMATION) {
+                       found++;
+                       break;
                }
        }
+       if (!found) {
+               ata_dev_warn(dev,
+                            "ATA Zoned Information Log not supported\n");
+               return;
+       }
 
-       return 0;
+       /*
+        * Read IDENTIFY DEVICE data log, page 9 (Zoned-device information)
+        */
+       err_mask = ata_read_log_page(dev, ATA_LOG_SATA_ID_DEV_DATA,
+                                    ATA_LOG_ZONED_INFORMATION,
+                                    identify_buf, 1);
+       if (!err_mask) {
+               u64 zoned_cap, opt_open, opt_nonseq, max_open;
+
+               zoned_cap = get_unaligned_le64(&identify_buf[8]);
+               if ((zoned_cap >> 63))
+                       dev->zac_zoned_cap = (zoned_cap & 1);
+               opt_open = get_unaligned_le64(&identify_buf[24]);
+               if ((opt_open >> 63))
+                       dev->zac_zones_optimal_open = (u32)opt_open;
+               opt_nonseq = get_unaligned_le64(&identify_buf[32]);
+               if ((opt_nonseq >> 63))
+                       dev->zac_zones_optimal_nonseq = (u32)opt_nonseq;
+               max_open = get_unaligned_le64(&identify_buf[40]);
+               if ((max_open >> 63))
+                       dev->zac_zones_max_open = (u32)max_open;
+       }
 }
 
 /**
@@ -2370,7 +2542,8 @@ int ata_dev_configure(struct ata_device *dev)
                                        dev->devslp_timing[i] = sata_setting[j];
                                }
                }
-
+               ata_dev_config_sense_reporting(dev);
+               ata_dev_config_zac(dev);
                dev->cdb_len = 16;
        }
 
@@ -3399,7 +3572,7 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
  *     EH context.
  *
  *     RETURNS:
- *     0 if @linke is ready before @deadline; otherwise, -errno.
+ *     0 if @link is ready before @deadline; otherwise, -errno.
  */
 int ata_wait_ready(struct ata_link *link, unsigned long deadline,
                   int (*check_ready)(struct ata_link *link))
@@ -3480,7 +3653,7 @@ int ata_wait_ready(struct ata_link *link, unsigned long deadline,
  *     EH context.
  *
  *     RETURNS:
- *     0 if @linke is ready before @deadline; otherwise, -errno.
+ *     0 if @link is ready before @deadline; otherwise, -errno.
  */
 int ata_wait_after_reset(struct ata_link *link, unsigned long deadline,
                                int (*check_ready)(struct ata_link *link))
@@ -3493,7 +3666,7 @@ int ata_wait_after_reset(struct ata_link *link, unsigned long deadline,
 /**
  *     sata_link_debounce - debounce SATA phy status
  *     @link: ATA link to debounce SATA phy status for
- *     @params: timing parameters { interval, duratinon, timeout } in msec
+ *     @params: timing parameters { interval, duration, timeout } in msec
  *     @deadline: deadline jiffies for the operation
  *
  *     Make sure SStatus of @link reaches stable state, determined by
@@ -3563,7 +3736,7 @@ int sata_link_debounce(struct ata_link *link, const unsigned long *params,
 /**
  *     sata_link_resume - resume SATA link
  *     @link: ATA link to resume SATA
- *     @params: timing parameters { interval, duratinon, timeout } in msec
+ *     @params: timing parameters { interval, duration, timeout } in msec
  *     @deadline: deadline jiffies for the operation
  *
  *     Resume SATA phy @link and debounce it.
@@ -3746,7 +3919,7 @@ int ata_std_prereset(struct ata_link *link, unsigned long deadline)
 /**
  *     sata_link_hardreset - reset link via SATA phy reset
  *     @link: link to reset
- *     @timing: timing parameters { interval, duratinon, timeout } in msec
+ *     @timing: timing parameters { interval, duration, timeout } in msec
  *     @deadline: deadline jiffies for the operation
  *     @online: optional out parameter indicating link onlineness
  *     @check_ready: optional callback to check link readiness
@@ -4141,6 +4314,12 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
         */
        { "ST380013AS",         "3.20",         ATA_HORKAGE_MAX_SEC_1024 },
 
+       /*
+        * Device times out with higher max sects.
+        * https://bugzilla.kernel.org/show_bug.cgi?id=121671
+        */
+       { "LITEON CX1-JB256-HP", NULL,          ATA_HORKAGE_MAX_SEC_1024 },
+
        /* Devices we expect to fail diagnostics */
 
        /* Devices where NCQ should be avoided */
@@ -4528,6 +4707,7 @@ unsigned int ata_dev_set_feature(struct ata_device *dev, u8 enable, u8 feature)
 {
        struct ata_taskfile tf;
        unsigned int err_mask;
+       unsigned long timeout = 0;
 
        /* set up set-features taskfile */
        DPRINTK("set features - SATA features\n");
@@ -4539,7 +4719,10 @@ unsigned int ata_dev_set_feature(struct ata_device *dev, u8 enable, u8 feature)
        tf.protocol = ATA_PROT_NODATA;
        tf.nsect = feature;
 
-       err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
+       if (enable == SETFEATURES_SPINUP)
+               timeout = ata_probe_timeout ?
+                         ata_probe_timeout * 1000 : SETFEATURES_SPINUP_TIMEOUT;
+       err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, timeout);
 
        DPRINTK("EXIT, err_mask=%x\n", err_mask);
        return err_mask;
@@ -6208,7 +6391,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
  *
  *     After allocating an ATA host and initializing it, most libata
  *     LLDs perform three steps to activate the host - start host,
- *     request IRQ and register it.  This helper takes necessasry
+ *     request IRQ and register it.  This helper takes necessary
  *     arguments and performs the three steps in one go.
  *
  *     An invalid IRQ skips the IRQ registration and expects the host to
@@ -6261,7 +6444,7 @@ int ata_host_activate(struct ata_host *host, int irq,
 }
 
 /**
- *     ata_port_detach - Detach ATA port in prepration of device removal
+ *     ata_port_detach - Detach ATA port in preparation of device removal
  *     @ap: ATA port to be detached
  *
  *     Detach all ATA devices and the associated SCSI devices of @ap;