diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-06 09:41:58 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-06 09:41:58 -0700 |
commit | 109a5db5042c035ded330b948a710b9a0c20934d (patch) | |
tree | 5ebd38a4e36ea740a3de6edbc7b6a3250a776ef5 /drivers/ata/libata-core.c | |
parent | a4c20b9a574b9720acf6c647eaff5e7e1e688086 (diff) | |
parent | d80210f25ff0050245556bb8ce84d280d8fa4ca7 (diff) | |
download | talos-op-linux-109a5db5042c035ded330b948a710b9a0c20934d.tar.gz talos-op-linux-109a5db5042c035ded330b948a710b9a0c20934d.zip |
Merge branch 'for-4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata
Pull libata updates from Tejun Heo:
- Christoph added support for TCG OPAL self encrypting disks
- Minwoo added support for ATA PASS-THROUGH(32)
- Linus Walleij removed spurious drvdata assignments in some drivers
- Support for a few new device and other fixes
* 'for-4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata: (33 commits)
sd: add support for TCG OPAL self encrypting disks
libata: fix build warning from unused goto label
libata: Support for an ATA PASS-THROUGH(32) command.
ahci: Add Device ID for ASMedia 1061R and 1062R
sata_via: Enable optional hotplug on VT6420
ata: ahci_brcm: Avoid writing to read-only registers
libata: Add the AHCI_HFLAG_NO_WRITE_TO_RO flag
libata: Add the AHCI_HFLAG_YES_ALPM flag
ata: ftide010: fix resource printing
libata: make the function name in comment match the actual function
ata: sata_rcar: make of_device_ids const.
ata: pata_octeon_cf: make of_device_ids const.
libata: Convert bare printks to pr_cont
libahci: wrong comments in ahci_do_softreset()
ata: declare ata_port_info structures as const
ata: Add driver for Faraday Technology FTIDE010
ata: Add DT bindings for the Gemini SATA bridge
ata: Add DT bindings for Faraday Technology FTIDE010
libata: implement SECURITY PROTOCOL IN/OUT
libata: factor out a ata_identify_page_supported helper
...
Diffstat (limited to 'drivers/ata/libata-core.c')
-rw-r--r-- | drivers/ata/libata-core.c | 214 |
1 files changed, 144 insertions, 70 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index b82d6bb88d27..8453f9a4682f 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2047,6 +2047,110 @@ 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 bool ata_log_supported(struct ata_device *dev, u8 log) +{ + struct ata_port *ap = dev->link->ap; + + if (ata_read_log_page(dev, ATA_LOG_DIRECTORY, 0, ap->sector_buf, 1)) + return false; + return get_unaligned_le16(&ap->sector_buf[log * 2]) ? true : false; +} + +static bool ata_identify_page_supported(struct ata_device *dev, u8 page) +{ + struct ata_port *ap = dev->link->ap; + unsigned int err, i; + + if (!ata_log_supported(dev, ATA_LOG_IDENTIFY_DEVICE)) { + ata_dev_warn(dev, "ATA Identify Device Log not supported\n"); + return false; + } + + /* + * Read IDENTIFY DEVICE data log, page 0, to figure out if the page is + * supported. + */ + err = ata_read_log_page(dev, ATA_LOG_IDENTIFY_DEVICE, 0, ap->sector_buf, + 1); + if (err) { + ata_dev_info(dev, + "failed to get Device Identify Log Emask 0x%x\n", + err); + return false; + } + + for (i = 0; i < ap->sector_buf[8]; i++) { + if (ap->sector_buf[9 + i] == page) + return true; + } + + return false; +} + static int ata_do_link_spd_horkage(struct ata_device *dev) { struct ata_link *plink = ata_dev_phys_link(dev); @@ -2094,21 +2198,9 @@ 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"); + if (!ata_log_supported(dev, ATA_LOG_NCQ_SEND_RECV)) { + ata_dev_warn(dev, "NCQ Send/Recv Log not supported\n"); return; } err_mask = ata_read_log_page(dev, ATA_LOG_NCQ_SEND_RECV, @@ -2135,19 +2227,8 @@ 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) { + if (!ata_log_supported(dev, ATA_LOG_NCQ_NON_DATA)) { ata_dev_warn(dev, "NCQ Send/Recv Log not supported\n"); return; @@ -2176,7 +2257,7 @@ static void ata_dev_config_ncq_prio(struct ata_device *dev) } err_mask = ata_read_log_page(dev, - ATA_LOG_SATA_ID_DEV_DATA, + ATA_LOG_IDENTIFY_DEVICE, ATA_LOG_SATA_SETTINGS, ap->sector_buf, 1); @@ -2275,8 +2356,6 @@ 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; @@ -2296,44 +2375,7 @@ static void ata_dev_config_zac(struct ata_device *dev) 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) { + if (!ata_identify_page_supported(dev, ATA_LOG_ZONED_INFORMATION)) { ata_dev_warn(dev, "ATA Zoned Information Log not supported\n"); return; @@ -2342,7 +2384,7 @@ static void ata_dev_config_zac(struct ata_device *dev) /* * Read IDENTIFY DEVICE data log, page 9 (Zoned-device information) */ - err_mask = ata_read_log_page(dev, ATA_LOG_SATA_ID_DEV_DATA, + err_mask = ata_read_log_page(dev, ATA_LOG_IDENTIFY_DEVICE, ATA_LOG_ZONED_INFORMATION, identify_buf, 1); if (!err_mask) { @@ -2363,6 +2405,37 @@ static void ata_dev_config_zac(struct ata_device *dev) } } +static void ata_dev_config_trusted(struct ata_device *dev) +{ + struct ata_port *ap = dev->link->ap; + u64 trusted_cap; + unsigned int err; + + if (!ata_identify_page_supported(dev, ATA_LOG_SECURITY)) { + ata_dev_warn(dev, + "Security Log not supported\n"); + return; + } + + err = ata_read_log_page(dev, ATA_LOG_IDENTIFY_DEVICE, ATA_LOG_SECURITY, + ap->sector_buf, 1); + if (err) { + ata_dev_dbg(dev, + "failed to read Security Log, Emask 0x%x\n", err); + return; + } + + trusted_cap = get_unaligned_le64(&ap->sector_buf[40]); + if (!(trusted_cap & (1ULL << 63))) { + ata_dev_dbg(dev, + "Trusted Computing capability qword not valid!\n"); + return; + } + + if (trusted_cap & (1 << 0)) + dev->flags |= ATA_DFLAG_TRUSTED; +} + /** * ata_dev_configure - Configure the specified ATA/ATAPI device * @dev: Target device to configure @@ -2571,7 +2644,7 @@ int ata_dev_configure(struct ata_device *dev) dev->flags |= ATA_DFLAG_DEVSLP; err_mask = ata_read_log_page(dev, - ATA_LOG_SATA_ID_DEV_DATA, + ATA_LOG_IDENTIFY_DEVICE, ATA_LOG_SATA_SETTINGS, sata_setting, 1); @@ -2587,7 +2660,8 @@ int ata_dev_configure(struct ata_device *dev) } ata_dev_config_sense_reporting(dev); ata_dev_config_zac(dev); - dev->cdb_len = 16; + ata_dev_config_trusted(dev); + dev->cdb_len = 32; } /* ATAPI-specific feature tests */ |