diff options
author | Christoph Hellwig <hch@lst.de> | 2017-06-04 14:42:20 +0200 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2017-06-05 15:29:21 -0400 |
commit | f01f62c257cc343246a5a9b2df8135f01fc044ab (patch) | |
tree | 8285f948ac2c78ff7d01c7d987d6da841856b2a5 /drivers/ata/libata-core.c | |
parent | 0cee73f751ceb507d052f1a45d5f5f38bc33b25a (diff) | |
download | linux-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.c | 64 |
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); |