libata: implement ATA_HORKAGE_NO_NCQ_TRIM and apply it to Micro M500 SSDs
authorMarc Carino <marc.ceeeee@gmail.com>
Tue, 17 Dec 2013 02:15:53 +0000 (18:15 -0800)
committerTejun Heo <tj@kernel.org>
Tue, 17 Dec 2013 12:03:14 +0000 (07:03 -0500)
Certain drives cannot handle queued TRIM commands properly, even
though support is indicated in the IDENTIFY DEVICE buffer.  This patch
allows for disabling the commands for the affected drives and apply it
to the Micron/Crucial M500 SSDs which exhibit incorrect protocol
behavior when issued queued TRIM commands, which could lead to silent
data corruption.

tj: Merged two unnecessarily split patches and made minor edits
    including shortening horkage name.

Signed-off-by: Marc Carino <marc.ceeeee@gmail.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Link: http://lkml.kernel.org/g/1387246554-7311-1-git-send-email-marc.ceeeee@gmail.com
Cc: stable@vger.kernel.org # 3.12+
drivers/ata/libata-core.c
include/linux/libata.h

index ff0158481d53c9c9cc7133b0463a8c665fe7a015..1393a5890ed5356e5ef36965ea74e49e226c0a29 100644 (file)
@@ -2149,9 +2149,16 @@ static int ata_dev_config_ncq(struct ata_device *dev,
                                    "failed to get NCQ Send/Recv Log Emask 0x%x\n",
                                    err_mask);
                } else {
+                       u8 *cmds = dev->ncq_send_recv_cmds;
+
                        dev->flags |= ATA_DFLAG_NCQ_SEND_RECV;
-                       memcpy(dev->ncq_send_recv_cmds, ap->sector_buf,
-                               ATA_LOG_NCQ_SEND_RECV_SIZE);
+                       memcpy(cmds, ap->sector_buf, ATA_LOG_NCQ_SEND_RECV_SIZE);
+
+                       if (dev->horkage & ATA_HORKAGE_NO_NCQ_TRIM) {
+                               ata_dev_dbg(dev, "disabling queued TRIM support\n");
+                               cmds[ATA_LOG_NCQ_SEND_RECV_DSM_OFFSET] &=
+                                       ~ATA_LOG_NCQ_SEND_RECV_DSM_TRIM;
+                       }
                }
        }
 
@@ -4205,6 +4212,10 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        { "PIONEER DVD-RW  DVR-212D",   NULL,   ATA_HORKAGE_NOSETXFER },
        { "PIONEER DVD-RW  DVR-216D",   NULL,   ATA_HORKAGE_NOSETXFER },
 
+       /* devices that don't properly handle queued TRIM commands */
+       { "Micron_M500*",               NULL,   ATA_HORKAGE_NO_NCQ_TRIM, },
+       { "Crucial_CT???M500SSD1",      NULL,   ATA_HORKAGE_NO_NCQ_TRIM, },
+
        /* End Marker */
        { }
 };
index 0e23c26485f457cf2380818a18b00c1175bc02ae..9b503376738fac8e25e9fa71b286b4c341295d76 100644 (file)
@@ -418,6 +418,7 @@ enum {
        ATA_HORKAGE_DUMP_ID     = (1 << 16),    /* dump IDENTIFY data */
        ATA_HORKAGE_MAX_SEC_LBA48 = (1 << 17),  /* Set max sects to 65535 */
        ATA_HORKAGE_ATAPI_DMADIR = (1 << 18),   /* device requires dmadir */
+       ATA_HORKAGE_NO_NCQ_TRIM = (1 << 19),    /* don't use queued TRIM */
 
         /* DMA mask for user DMA control: User visible values; DO NOT
            renumber */