Commit c745dfc5 authored by Tyler Erickson's avatar Tyler Erickson Committed by Damien Le Moal

libata: fix reading concurrent positioning ranges log

The concurrent positioning ranges log is not a fixed size and may depend
on how many ranges are supported by the device. This patch uses the size
reported in the GPL directory to determine the number of pages supported
by the device before attempting to read this log page.

This resolves this error from the dmesg output:
    ata6.00: Read log 0x47 page 0x00 failed, Emask 0x1

Cc: stable@vger.kernel.org
Fixes: fe22e1c2 ("libata: support concurrent positioning ranges log")
Signed-off-by: default avatarTyler Erickson <tyler.erickson@seagate.com>
Reviewed-by: default avatarMuhammad Ahmad <muhammad.ahmad@seagate.com>
Tested-by: default avatarMichael English <michael.english@seagate.com>
Signed-off-by: default avatarDamien Le Moal <damien.lemoal@opensource.wdc.com>
parent 10d6bdf5
...@@ -2010,16 +2010,16 @@ unsigned int ata_read_log_page(struct ata_device *dev, u8 log, ...@@ -2010,16 +2010,16 @@ unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
return err_mask; return err_mask;
} }
static bool ata_log_supported(struct ata_device *dev, u8 log) static int ata_log_supported(struct ata_device *dev, u8 log)
{ {
struct ata_port *ap = dev->link->ap; struct ata_port *ap = dev->link->ap;
if (dev->horkage & ATA_HORKAGE_NO_LOG_DIR) if (dev->horkage & ATA_HORKAGE_NO_LOG_DIR)
return false; return 0;
if (ata_read_log_page(dev, ATA_LOG_DIRECTORY, 0, ap->sector_buf, 1)) if (ata_read_log_page(dev, ATA_LOG_DIRECTORY, 0, ap->sector_buf, 1))
return false; return 0;
return get_unaligned_le16(&ap->sector_buf[log * 2]) ? true : false; return get_unaligned_le16(&ap->sector_buf[log * 2]);
} }
static bool ata_identify_page_supported(struct ata_device *dev, u8 page) static bool ata_identify_page_supported(struct ata_device *dev, u8 page)
...@@ -2455,15 +2455,20 @@ static void ata_dev_config_cpr(struct ata_device *dev) ...@@ -2455,15 +2455,20 @@ static void ata_dev_config_cpr(struct ata_device *dev)
struct ata_cpr_log *cpr_log = NULL; struct ata_cpr_log *cpr_log = NULL;
u8 *desc, *buf = NULL; u8 *desc, *buf = NULL;
if (ata_id_major_version(dev->id) < 11 || if (ata_id_major_version(dev->id) < 11)
!ata_log_supported(dev, ATA_LOG_CONCURRENT_POSITIONING_RANGES)) goto out;
buf_len = ata_log_supported(dev, ATA_LOG_CONCURRENT_POSITIONING_RANGES);
if (buf_len == 0)
goto out; goto out;
/* /*
* Read the concurrent positioning ranges log (0x47). We can have at * Read the concurrent positioning ranges log (0x47). We can have at
* most 255 32B range descriptors plus a 64B header. * most 255 32B range descriptors plus a 64B header. This log varies in
* size, so use the size reported in the GPL directory. Reading beyond
* the supported length will result in an error.
*/ */
buf_len = (64 + 255 * 32 + 511) & ~511; buf_len <<= 9;
buf = kzalloc(buf_len, GFP_KERNEL); buf = kzalloc(buf_len, GFP_KERNEL);
if (!buf) if (!buf)
goto out; goto out;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment