Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

libata: Fall back to unqueued READ LOG EXT if the DMA variant fails

Some devices advertise support for the READ/WRITE LOG DMA EXT commands
but fail when we try to issue them. This can lead to queued TRIM being
unintentionally disabled since the relevant feature flag is located in a
general purpose log page.

Fall back to unqueued READ LOG EXT if the DMA variant fails while
reading a log page.

Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Tejun Heo <tj@kernel.org>

authored by

Martin K. Petersen and committed by
Tejun Heo
5d3abf8f 406c057c

+12 -1
+11 -1
drivers/ata/libata-eh.c
··· 1507 1507 { 1508 1508 struct ata_taskfile tf; 1509 1509 unsigned int err_mask; 1510 + bool dma = false; 1510 1511 1511 1512 DPRINTK("read log page - log 0x%x, page 0x%x\n", log, page); 1512 1513 1514 + retry: 1513 1515 ata_tf_init(dev, &tf); 1514 - if (dev->dma_mode && ata_id_has_read_log_dma_ext(dev->id)) { 1516 + if (dev->dma_mode && ata_id_has_read_log_dma_ext(dev->id) && 1517 + !(dev->horkage & ATA_HORKAGE_NO_NCQ_LOG)) { 1515 1518 tf.command = ATA_CMD_READ_LOG_DMA_EXT; 1516 1519 tf.protocol = ATA_PROT_DMA; 1520 + dma = true; 1517 1521 } else { 1518 1522 tf.command = ATA_CMD_READ_LOG_EXT; 1519 1523 tf.protocol = ATA_PROT_PIO; ··· 1530 1526 1531 1527 err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, 1532 1528 buf, sectors * ATA_SECT_SIZE, 0); 1529 + 1530 + if (err_mask && dma) { 1531 + dev->horkage |= ATA_HORKAGE_NO_NCQ_LOG; 1532 + ata_dev_warn(dev, "READ LOG DMA EXT failed, trying unqueued\n"); 1533 + goto retry; 1534 + } 1533 1535 1534 1536 DPRINTK("EXIT, err_mask=%x\n", err_mask); 1535 1537 return err_mask;
+1
include/linux/libata.h
··· 424 424 ATA_HORKAGE_NOLPM = (1 << 20), /* don't use LPM */ 425 425 ATA_HORKAGE_WD_BROKEN_LPM = (1 << 21), /* some WDs have broken LPM */ 426 426 ATA_HORKAGE_ZERO_AFTER_TRIM = (1 << 22),/* guarantees zero after trim */ 427 + ATA_HORKAGE_NO_NCQ_LOG = (1 << 23), /* don't use NCQ for log read */ 427 428 428 429 /* DMA mask for user DMA control: User visible values; DO NOT 429 430 renumber */