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 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, 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); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 7e33e200aae5..b70bcf6d2914 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1487,70 +1487,6 @@ static const char *ata_err_string(unsigned int err_mask) return "unknown error"; } -/** - * 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; -} - /** * ata_eh_read_log_10h - Read log page 10h for NCQ error details * @dev: Device to read log page 10h from diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 5afe35baf61b..839d487394b7 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -98,6 +98,8 @@ extern struct ata_port *ata_port_alloc(struct ata_host *host); extern const char *sata_spd_string(unsigned int spd); extern int ata_port_probe(struct ata_port *ap); extern void __ata_port_probe(struct ata_port *ap); +extern unsigned int ata_read_log_page(struct ata_device *dev, u8 log, + u8 page, void *buf, unsigned int sectors); #define to_ata_port(d) container_of(d, struct ata_port, tdev) @@ -160,8 +162,6 @@ extern void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev, unsigned int action); extern void ata_eh_done(struct ata_link *link, struct ata_device *dev, unsigned int action); -extern unsigned int ata_read_log_page(struct ata_device *dev, u8 log, - u8 page, void *buf, unsigned int sectors); extern void ata_eh_autopsy(struct ata_port *ap); const char *ata_get_cmd_descript(u8 command); extern void ata_eh_report(struct ata_port *ap);