summaryrefslogtreecommitdiffstats
path: root/drivers/ata/libata-core.c
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2017-06-04 14:42:20 +0200
committerTejun Heo <tj@kernel.org>2017-06-05 15:29:21 -0400
commitf01f62c257cc343246a5a9b2df8135f01fc044ab (patch)
tree8285f948ac2c78ff7d01c7d987d6da841856b2a5 /drivers/ata/libata-core.c
parent0cee73f751ceb507d052f1a45d5f5f38bc33b25a (diff)
downloadlinux-f01f62c257cc343246a5a9b2df8135f01fc044ab.tar.bz2
libata: move ata_read_log_page to libata-core.c
It is core functionality, and only one of the users is in the EH code. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'drivers/ata/libata-core.c')
-rw-r--r--drivers/ata/libata-core.c64
1 files changed, 64 insertions, 0 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 55aaa2e4c683..f84419f0d209 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -2047,6 +2047,70 @@ retry:
return rc;
}
+/**
+ * ata_read_log_page - read a specific log page
+ * @dev: target device
+ * @log: log to read
+ * @page: page to read
+ * @buf: buffer to store read page
+ * @sectors: number of sectors to read
+ *
+ * Read log page using READ_LOG_EXT command.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, AC_ERR_* mask otherwise.
+ */
+unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
+ u8 page, void *buf, unsigned int sectors)
+{
+ unsigned long ap_flags = dev->link->ap->flags;
+ struct ata_taskfile tf;
+ unsigned int err_mask;
+ bool dma = false;
+
+ DPRINTK("read log page - log 0x%x, page 0x%x\n", log, page);
+
+ /*
+ * Return error without actually issuing the command on controllers
+ * which e.g. lockup on a read log page.
+ */
+ if (ap_flags & ATA_FLAG_NO_LOG_PAGE)
+ return AC_ERR_DEV;
+
+retry:
+ ata_tf_init(dev, &tf);
+ if (dev->dma_mode && ata_id_has_read_log_dma_ext(dev->id) &&
+ !(dev->horkage & ATA_HORKAGE_NO_NCQ_LOG)) {
+ tf.command = ATA_CMD_READ_LOG_DMA_EXT;
+ tf.protocol = ATA_PROT_DMA;
+ dma = true;
+ } else {
+ tf.command = ATA_CMD_READ_LOG_EXT;
+ tf.protocol = ATA_PROT_PIO;
+ dma = false;
+ }
+ tf.lbal = log;
+ tf.lbam = page;
+ tf.nsect = sectors;
+ tf.hob_nsect = sectors >> 8;
+ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_LBA48 | ATA_TFLAG_DEVICE;
+
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
+ buf, sectors * ATA_SECT_SIZE, 0);
+
+ if (err_mask && dma) {
+ dev->horkage |= ATA_HORKAGE_NO_NCQ_LOG;
+ ata_dev_warn(dev, "READ LOG DMA EXT failed, trying unqueued\n");
+ goto retry;
+ }
+
+ DPRINTK("EXIT, err_mask=%x\n", err_mask);
+ return err_mask;
+}
+
static int ata_do_link_spd_horkage(struct ata_device *dev)
{
struct ata_link *plink = ata_dev_phys_link(dev);