From a49077d3655e0c24c358ade6d448e9e977e6a84e Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Tue, 5 Feb 2019 22:53:36 +0000 Subject: [PATCH] Add quirk for Sansisk X400 drives Certain versions of Sandisk x400 firmware can hang under extremely heavly load of large I/Os for prolonged periods of time. Newer / current versions work fine, and should be used where possible. Where not possible, this quirk ensures that I/O requests are limited to 128k to avoids the bug, even under extreme load. Since MAXPHYS is 128k, only users with custom kernels are at risk on the older firmware. Once all known users of the older firmware have upgraded, this quirk will be removed. Sponsored by: Netflix, Inc. --- sys/cam/ata/ata_da.c | 13 +++++++++++-- sys/cam/scsi/scsi_da.c | 13 +++++++++++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/sys/cam/ata/ata_da.c b/sys/cam/ata/ata_da.c index d6fcdeddc5f6..200b855a0e59 100644 --- a/sys/cam/ata/ata_da.c +++ b/sys/cam/ata/ata_da.c @@ -119,7 +119,8 @@ typedef enum { ADA_Q_NCQ_TRIM_BROKEN = 0x02, ADA_Q_LOG_BROKEN = 0x04, ADA_Q_SMR_DM = 0x08, - ADA_Q_NO_TRIM = 0x10 + ADA_Q_NO_TRIM = 0x10, + ADA_Q_128KB = 0x20 } ada_quirks; #define ADA_Q_BIT_STRING \ @@ -128,7 +129,8 @@ typedef enum { "\002NCQ_TRIM_BROKEN" \ "\003LOG_BROKEN" \ "\004SMR_DM" \ - "\005NO_TRIM" + "\005NO_TRIM" \ + "\006128KB" typedef enum { ADA_CCB_RAHEAD = 0x01, @@ -276,6 +278,11 @@ struct ada_quirk_entry { static struct ada_quirk_entry ada_quirk_table[] = { + { + /* Sandisk X400 */ + { T_DIRECT, SIP_MEDIA_FIXED, "*", "SanDisk?SD8SB8U1T00*", "X4162000*" }, + /*quirks*/ADA_Q_128KB + }, { /* Hitachi Advanced Format (4k) drives */ { T_DIRECT, SIP_MEDIA_FIXED, "*", "Hitachi H??????????E3*", "*" }, @@ -1815,6 +1822,8 @@ adaregister(struct cam_periph *periph, void *arg) maxio = min(maxio, 65536 * softc->params.secsize); else /* 28bit ATA command limit */ maxio = min(maxio, 256 * softc->params.secsize); + if (softc->quirks & ADA_Q_128KB) + maxio = min(maxio, 128 * 1024); softc->disk->d_maxsize = maxio; softc->disk->d_unit = periph->unit_number; softc->disk->d_flags = DISKFLAG_DIRECT_COMPLETION | DISKFLAG_CANZONE; diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c index c8be3a01f851..d7c6b30fca93 100644 --- a/sys/cam/scsi/scsi_da.c +++ b/sys/cam/scsi/scsi_da.c @@ -130,7 +130,8 @@ typedef enum { DA_Q_NO_UNMAP = 0x20, DA_Q_RETRY_BUSY = 0x40, DA_Q_SMR_DM = 0x80, - DA_Q_STRICT_UNMAP = 0x100 + DA_Q_STRICT_UNMAP = 0x100, + DA_Q_128KB = 0x200 } da_quirks; #define DA_Q_BIT_STRING \ @@ -143,7 +144,8 @@ typedef enum { "\006NO_UNMAP" \ "\007RETRY_BUSY" \ "\010SMR_DM" \ - "\011STRICT_UNMAP" + "\011STRICT_UNMAP" \ + "\012128KB" typedef enum { DA_CCB_PROBE_RC = 0x01, @@ -870,6 +872,11 @@ static struct da_quirk_entry da_quirk_table[] = "1.00"}, /*quirks*/ DA_Q_NO_RC16 }, /* ATA/SATA devices over SAS/USB/... */ + { + /* Sandisk X400 */ + { T_DIRECT, SIP_MEDIA_FIXED, "ATA", "SanDisk SD8SB8U1*", "*" }, + /*quirks*/DA_Q_128KB + }, { /* Hitachi Advanced Format (4k) drives */ { T_DIRECT, SIP_MEDIA_FIXED, "Hitachi", "H??????????E3*", "*" }, @@ -2825,6 +2832,8 @@ daregister(struct cam_periph *periph, void *arg) softc->maxio = MAXPHYS; /* for safety */ else softc->maxio = cpi.maxio; + if (softc->quirks & DA_Q_128KB) + softc->maxio = min(softc->maxio, 128 * 1024); softc->disk->d_maxsize = softc->maxio; softc->disk->d_unit = periph->unit_number; softc->disk->d_flags = DISKFLAG_DIRECT_COMPLETION | DISKFLAG_CANZONE;