ata: libata: Quirk DELLBOSS VD max_sectors
Subsystems (2)
Niklas Cassel
maintainerv2 cover ata: libata: Quirk DELLBOSS VD max_sectors
Hello there,
a recent change:
commit 9b8b84879d4a ("block: Increase BLK_DEF_MAX_SECTORS_CAP")
bumped the default max_sectors_kb from 1280 to 4096.
It seems like a lot for SATA controllers are buggy and don't really like this, see:
https://bugzilla.kernel.org/show_bug.cgi?id=220693
For now, we only add a DELLBOSS VD max_sectors quirk, but surely we will need to quirk additional controllers.
Changes since v1:
-Introduced a generic quirk (ATA_QUIRK_MAX_SEC) that also has a value. -Added libata.force parameter max_sec=<sectors>.
-Use the correct model string for DELLBOSS VD.
Niklas Cassel (8):
ata: libata: Move quirk flags to their own enum
ata: libata: Add ATA_QUIRK_MAX_SEC and convert all device quirks
ata: libata: Add ata_force_get_fe_for_dev() helper
ata: libata: Change libata.force to use the generic ATA_QUIRK_MAX_SEC
quirk
ata: libata-core: Quirk DELLBOSS VD max_sectors
ata: libata: Add support to parse equal sign in libata.force
ata: libata: Add libata.force parameter max_sec
ata: libata: Allow more quirks
.../admin-guide/kernel-parameters.txt | 4 + drivers/ata/libata-core.c | 203 ++++++++++++++---- include/linux/ata.h | 2 - include/linux/libata.h | 80 +++---- 4 files changed, 202 insertions(+), 87 deletions(-)
Signature · 1 line
2.52.0
Niklas Cassel
maintainerPATCH v2 1/8 ata: libata: Move quirk flags to their own enum
The anonymous enum in include/linux/libata.h that is used to store various global constants can currently be backed by type int. (It contains both negative and positive constants.)
__ATA_QUIRK_MAX is currently 31.
The quirk flags in the various global constants enum are defined as "1U << quirk_flag_bit".
Thus if we simply add an additional quirk, the quirk flag will be 1 << 31, which is a value that is too large to be represented by a signed int. The various global constants enum will thus therefore be backed by type long.
This will lead to error prints like e.g.:
ata_port_err(ap, "EH pending after %d tries, giving up\n",
ATA_EH_MAX_TRIES);
now failing to build, with build error:
error: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘long int’ [-Werror=format=]
This is because all constants in the various global constants enum now has to be printed as a long, as that is now the backing type of the enum.
Since the compiler will use the smallest possible backing type for an enum, it is good practice to not mix unrelated things in a single enum.
Move the quirk flags to a separate enum, so that we don't need to change the printf specifier for all other constants in the "various global constants" enum when adding an additional quirk.
--- include/linux/libata.h | 74 ++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 36 deletions(-)
include/linux/libata.h +38 -36
@@ -85,6 +85,44 @@ enum ata_quirks { __ATA_QUIRK_MAX, }; +/* +* Quirk flags: may be set by libata or controller drivers on drives. +* Some quirks may be drive/controller pair dependent. +*/ +enum { +ATA_QUIRK_DIAGNOSTIC = (1U << __ATA_QUIRK_DIAGNOSTIC), +ATA_QUIRK_NODMA = (1U << __ATA_QUIRK_NODMA), +ATA_QUIRK_NONCQ = (1U << __ATA_QUIRK_NONCQ), +ATA_QUIRK_MAX_SEC_128 = (1U << __ATA_QUIRK_MAX_SEC_128), +ATA_QUIRK_BROKEN_HPA = (1U << __ATA_QUIRK_BROKEN_HPA), +ATA_QUIRK_DISABLE = (1U << __ATA_QUIRK_DISABLE), +ATA_QUIRK_HPA_SIZE = (1U << __ATA_QUIRK_HPA_SIZE), +ATA_QUIRK_IVB = (1U << __ATA_QUIRK_IVB), +ATA_QUIRK_STUCK_ERR = (1U << __ATA_QUIRK_STUCK_ERR), +ATA_QUIRK_BRIDGE_OK = (1U << __ATA_QUIRK_BRIDGE_OK), +ATA_QUIRK_ATAPI_MOD16_DMA = (1U << __ATA_QUIRK_ATAPI_MOD16_DMA), +ATA_QUIRK_FIRMWARE_WARN = (1U << __ATA_QUIRK_FIRMWARE_WARN), +ATA_QUIRK_1_5_GBPS = (1U << __ATA_QUIRK_1_5_GBPS), +ATA_QUIRK_NOSETXFER = (1U << __ATA_QUIRK_NOSETXFER), +ATA_QUIRK_BROKEN_FPDMA_AA = (1U << __ATA_QUIRK_BROKEN_FPDMA_AA), +ATA_QUIRK_DUMP_ID = (1U << __ATA_QUIRK_DUMP_ID), +ATA_QUIRK_MAX_SEC_LBA48 = (1U << __ATA_QUIRK_MAX_SEC_LBA48), +ATA_QUIRK_ATAPI_DMADIR = (1U << __ATA_QUIRK_ATAPI_DMADIR), +ATA_QUIRK_NO_NCQ_TRIM = (1U << __ATA_QUIRK_NO_NCQ_TRIM), +ATA_QUIRK_NOLPM = (1U << __ATA_QUIRK_NOLPM), +ATA_QUIRK_WD_BROKEN_LPM = (1U << __ATA_QUIRK_WD_BROKEN_LPM), +ATA_QUIRK_ZERO_AFTER_TRIM = (1U << __ATA_QUIRK_ZERO_AFTER_TRIM), +ATA_QUIRK_NO_DMA_LOG = (1U << __ATA_QUIRK_NO_DMA_LOG), +ATA_QUIRK_NOTRIM = (1U << __ATA_QUIRK_NOTRIM), +ATA_QUIRK_MAX_SEC_1024 = (1U << __ATA_QUIRK_MAX_SEC_1024), +ATA_QUIRK_MAX_TRIM_128M = (1U << __ATA_QUIRK_MAX_TRIM_128M), +ATA_QUIRK_NO_NCQ_ON_ATI = (1U << __ATA_QUIRK_NO_NCQ_ON_ATI), +ATA_QUIRK_NO_LPM_ON_ATI = (1U << __ATA_QUIRK_NO_LPM_ON_ATI), +ATA_QUIRK_NO_ID_DEV_LOG = (1U << __ATA_QUIRK_NO_ID_DEV_LOG), +ATA_QUIRK_NO_LOG_DIR = (1U << __ATA_QUIRK_NO_LOG_DIR), +ATA_QUIRK_NO_FUA = (1U << __ATA_QUIRK_NO_FUA), +}; +enum {/* various global constants */ LIBATA_MAX_PRD =ATA_MAX_PRD /2 ,
@@ -390,42 +428,6 @@ enum {*/ ATA_EH_CMD_TIMEOUT_TABLE_SIZE =8 , -/* -* Quirk flags: may be set by libata or controller drivers on drives. -* Some quirks may be drive/controller pair dependent. -*/ -ATA_QUIRK_DIAGNOSTIC = (1U << __ATA_QUIRK_DIAGNOSTIC), -ATA_QUIRK_NODMA = (1U << __ATA_QUIRK_NODMA), -ATA_QUIRK_NONCQ = (1U << __ATA_QUIRK_NONCQ), -ATA_QUIRK_MAX_SEC_128 = (1U << __ATA_QUIRK_MAX_SEC_128), -ATA_QUIRK_BROKEN_HPA = (1U << __ATA_QUIRK_BROKEN_HPA), -ATA_QUIRK_DISABLE = (1U << __ATA_QUIRK_DISABLE), -ATA_QUIRK_HPA_SIZE = (1U << __ATA_QUIRK_HPA_SIZE), -ATA_QUIRK_IVB = (1U << __ATA_QUIRK_IVB), -ATA_QUIRK_STUCK_ERR = (1U << __ATA_QUIRK_STUCK_ERR), -ATA_QUIRK_BRIDGE_OK = (1U << __ATA_QUIRK_BRIDGE_OK), -ATA_QUIRK_ATAPI_MOD16_DMA = (1U << __ATA_QUIRK_ATAPI_MOD16_DMA), -ATA_QUIRK_FIRMWARE_WARN = (1U << __ATA_QUIRK_FIRMWARE_WARN), -ATA_QUIRK_1_5_GBPS = (1U << __ATA_QUIRK_1_5_GBPS), -ATA_QUIRK_NOSETXFER = (1U << __ATA_QUIRK_NOSETXFER), -ATA_QUIRK_BROKEN_FPDMA_AA = (1U << __ATA_QUIRK_BROKEN_FPDMA_AA), -ATA_QUIRK_DUMP_ID = (1U << __ATA_QUIRK_DUMP_ID), -ATA_QUIRK_MAX_SEC_LBA48 = (1U << __ATA_QUIRK_MAX_SEC_LBA48), -ATA_QUIRK_ATAPI_DMADIR = (1U << __ATA_QUIRK_ATAPI_DMADIR), -ATA_QUIRK_NO_NCQ_TRIM = (1U << __ATA_QUIRK_NO_NCQ_TRIM), -ATA_QUIRK_NOLPM = (1U << __ATA_QUIRK_NOLPM), -ATA_QUIRK_WD_BROKEN_LPM = (1U << __ATA_QUIRK_WD_BROKEN_LPM), -ATA_QUIRK_ZERO_AFTER_TRIM = (1U << __ATA_QUIRK_ZERO_AFTER_TRIM), -ATA_QUIRK_NO_DMA_LOG = (1U << __ATA_QUIRK_NO_DMA_LOG), -ATA_QUIRK_NOTRIM = (1U << __ATA_QUIRK_NOTRIM), -ATA_QUIRK_MAX_SEC_1024 = (1U << __ATA_QUIRK_MAX_SEC_1024), -ATA_QUIRK_MAX_TRIM_128M = (1U << __ATA_QUIRK_MAX_TRIM_128M), -ATA_QUIRK_NO_NCQ_ON_ATI = (1U << __ATA_QUIRK_NO_NCQ_ON_ATI), -ATA_QUIRK_NO_LPM_ON_ATI = (1U << __ATA_QUIRK_NO_LPM_ON_ATI), -ATA_QUIRK_NO_ID_DEV_LOG = (1U << __ATA_QUIRK_NO_ID_DEV_LOG), -ATA_QUIRK_NO_LOG_DIR = (1U << __ATA_QUIRK_NO_LOG_DIR), -ATA_QUIRK_NO_FUA = (1U << __ATA_QUIRK_NO_FUA), -/* User visible DMA mask for DMA control. DO NOT renumber. */ ATA_DMA_MASK_ATA = (1 <<0 ),/* DMA on ATA Disk */ ATA_DMA_MASK_ATAPI = (1 << 1), /* DMA on ATAPI */
Signature · 1 line
2.52.0
Niklas Cassel
maintainerPATCH v2 2/8 ata: libata: Add ATA_QUIRK_MAX_SEC and convert all device quirks
In reply to Niklas CasselAdd a new quirk ATA_QUIRK_MAX_SEC, which has a separate table with device specific values.
Convert all existing device quirks in __ata_dev_quirks to the new format.
Quirks ATA_QUIRK_MAX_SEC_128 and ATA_QUIRK_MAX_SEC_1024 cannot be removed yet, since they are also used by libata.force, which functionally, is a separate user of the quirks. The quirks will be removed once all users have been converted to use the new format.
--- drivers/ata/libata-core.c | 62 ++++++++++++++++++++++++++++++++++++--- include/linux/libata.h | 2 ++ 2 files changed, 60 insertions(+), 4 deletions(-)
drivers/ata/libata-core.c +58 -4
@@ -77,6 +77,7 @@ static unsigned int ata_dev_init_params(struct ata_device *dev,static unsigned int ata_dev_set_xfermode (struct ata_device *dev);static void ata_dev_xfermask (struct ata_device *dev);static unsigned int ata_dev_quirks (const struct ata_device *dev); +static u64 ata_dev_get_quirk_value (struct ata_device *dev,unsigned int quirk);static DEFINE_IDA (ata_ida);
@@ -3146,6 +3147,11 @@ int ata_dev_configure(struct ata_device *dev) dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_1024, dev->max_sectors); +if (dev->quirks &ATA_QUIRK_MAX_SEC ) + dev->max_sectors = min_t(unsigned int, dev->max_sectors, +ata_dev_get_quirk_value (dev, +ATA_QUIRK_MAX_SEC )); +if (dev->quirks &ATA_QUIRK_MAX_SEC_LBA48 ) dev->max_sectors =ATA_MAX_SECTORS_LBA48 ;
@@ -3998,6 +4004,7 @@ static const char * const ata_quirk_names[] = { [__ATA_QUIRK_NO_DMA_LOG] = "nodmalog", [__ATA_QUIRK_NOTRIM] = "notrim", [__ATA_QUIRK_MAX_SEC_1024] = "maxsec1024", + [__ATA_QUIRK_MAX_SEC] = "maxsec", [__ATA_QUIRK_MAX_TRIM_128M] = "maxtrim128m", [__ATA_QUIRK_NO_NCQ_ON_ATI] = "noncqonati", [__ATA_QUIRK_NO_LPM_ON_ATI] = "nolpmonati",
@@ -4042,6 +4049,20 @@ static void ata_dev_print_quirks(const struct ata_device *dev,kfree (str); } +struct ata_dev_quirk_value { +const char *model_num; +const char *model_rev; +u64 val; +}; + +static const struct ata_dev_quirk_value __ata_dev_max_sec_quirks[] = { + {"TORiSAN DVD-ROM DRD-N216" ,NULL ,128 }, + {"ST380013AS" ,"3.20" ,1024 }, + {"LITEON CX1-JB*-HP" ,NULL ,1024 }, + {"LITEON EP1-*" ,NULL ,1024 }, + { }, +}; +struct ata_dev_quirks_entry {const char *model_num;const char *model_rev;
@@ -4086,7 +4107,7 @@ static const struct ata_dev_quirks_entry __ata_dev_quirks[] = { { "ASMT109x- Config", NULL, ATA_QUIRK_DISABLE },/* Weird ATAPI devices */ - { "TORiSAN DVD-ROM DRD-N216", NULL, ATA_QUIRK_MAX_SEC_128 }, + { "TORiSAN DVD-ROM DRD-N216", NULL, ATA_QUIRK_MAX_SEC }, { "QUANTUM DAT DAT72-000", NULL, ATA_QUIRK_ATAPI_MOD16_DMA }, { "Slimtype DVD A DS8A8SH", NULL, ATA_QUIRK_MAX_SEC_LBA48 }, { "Slimtype DVD A DS8A9SH", NULL, ATA_QUIRK_MAX_SEC_LBA48 },
@@ -4095,14 +4116,14 @@ static const struct ata_dev_quirks_entry __ata_dev_quirks[] = {* Causes silent data corruption with higher max sects. * http://lkml.kernel.org/g/[email protected] */ - { "ST380013AS", "3.20", ATA_QUIRK_MAX_SEC_1024 }, + { "ST380013AS", "3.20", ATA_QUIRK_MAX_SEC },/* * These devices time out with higher max sects. * https://bugzilla.kernel.org/show_bug.cgi?id=121671 */ - { "LITEON CX1-JB*-HP", NULL, ATA_QUIRK_MAX_SEC_1024 }, - { "LITEON EP1-*", NULL, ATA_QUIRK_MAX_SEC_1024 }, + { "LITEON CX1-JB*-HP", NULL, ATA_QUIRK_MAX_SEC }, + { "LITEON EP1-*", NULL, ATA_QUIRK_MAX_SEC }, /* Devices we expect to fail diagnostics */
@@ -4348,6 +4369,39 @@ static unsigned int ata_dev_quirks(const struct ata_device *dev)return 0 ; } +static u64 ata_dev_get_max_sec_quirk_value (struct ata_device *dev) +{ +unsigned char model_num[ATA_ID_PROD_LEN +1 ]; +unsigned char model_rev[ATA_ID_FW_REV_LEN +1 ]; +const struct ata_dev_quirk_value *ad = __ata_dev_max_sec_quirks; +u64 val =0 ; + +ata_id_c_string (dev->id, model_num,ATA_ID_PROD ,sizeof (model_num)); +ata_id_c_string (dev->id, model_rev,ATA_ID_FW_REV ,sizeof (model_rev)); + +while (ad->model_num) { +if (glob_match (ad->model_num, model_num) && + (!ad->model_rev ||glob_match (ad->model_rev, model_rev))) { + val = ad->val; +break ; + } + ad++; + } + +ata_dev_warn (dev,"%s quirk is using value: %llu\n" , + ata_quirk_names[__ATA_QUIRK_MAX_SEC], val); + +return val; +} + +static u64 ata_dev_get_quirk_value (struct ata_device *dev,unsigned int quirk) +{ +if (quirk ==ATA_QUIRK_MAX_SEC ) +return ata_dev_get_max_sec_quirk_value (dev); + +return 0 ; +} +static bool ata_dev_nodma (const struct ata_device *dev) {/*
include/linux/libata.h +2 -0
@@ -75,6 +75,7 @@ enum ata_quirks { __ATA_QUIRK_NO_DMA_LOG,/* Do not use DMA for log read */ __ATA_QUIRK_NOTRIM,/* Do not use TRIM */ __ATA_QUIRK_MAX_SEC_1024,/* Limit max sects to 1024 */ + __ATA_QUIRK_MAX_SEC,/* Limit max sectors */ __ATA_QUIRK_MAX_TRIM_128M,/* Limit max trim size to 128M */ __ATA_QUIRK_NO_NCQ_ON_ATI,/* Disable NCQ on ATI chipset */ __ATA_QUIRK_NO_LPM_ON_ATI, /* Disable LPM on ATI chipset */
@@ -115,6 +116,7 @@ enum {ATA_QUIRK_NO_DMA_LOG = (1U << __ATA_QUIRK_NO_DMA_LOG),ATA_QUIRK_NOTRIM = (1U << __ATA_QUIRK_NOTRIM),ATA_QUIRK_MAX_SEC_1024 = (1U << __ATA_QUIRK_MAX_SEC_1024), +ATA_QUIRK_MAX_SEC = (1U << __ATA_QUIRK_MAX_SEC),ATA_QUIRK_MAX_TRIM_128M = (1U << __ATA_QUIRK_MAX_TRIM_128M),ATA_QUIRK_NO_NCQ_ON_ATI = (1U << __ATA_QUIRK_NO_NCQ_ON_ATI), ATA_QUIRK_NO_LPM_ON_ATI = (1U << __ATA_QUIRK_NO_LPM_ON_ATI),
Signature · 1 line
2.52.0
Niklas Cassel
maintainerPATCH v2 3/8 ata: libata: Add ata_force_get_fe_for_dev() helper
In reply to Niklas CasselAdd ata_force_get_fe_for_dev() helper to get the struct ata_force_ent for a struct ata_device.
Use the helper in ata_force_quirks().
The helper will also be used in follow up commits.
No functional change intended.
--- drivers/ata/libata-core.c | 55 ++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 21 deletions(-)
drivers/ata/libata-core.c +34 -21
@@ -474,29 +474,20 @@ static void ata_force_xfermask(struct ata_device *dev) } } -/** -* ata_force_quirks - force quirks according to libata.force -* @dev: ATA device of interest -* -* Force quirks according to libata.force and whine about it. -* For consistency with link selection, device number 15 selects -* the first device connected to the host link. -* -* LOCKING: -* EH context. -*/ -static void ata_force_quirks (struct ata_device *dev) +static const struct ata_force_ent +*ata_force_get_fe_for_dev (struct ata_device *dev) {int devno = dev->link->pmp + dev->devno;int alt_devno = devno;int i; +const struct ata_force_ent *fe;/* allow n.15/16 for devices attached to host port */ if (ata_is_host_link (dev->link)) alt_devno +=15 ;for (i =0 ; i < ata_force_tbl_size; i++) { -const struct ata_force_ent *fe = &ata_force_tbl[i]; + fe = &ata_force_tbl[i];if (fe->port !=-1 && fe->port != dev->link->ap->print_id)continue ;
@@ -505,16 +496,38 @@ static void ata_force_quirks(struct ata_device *dev) fe->device != alt_devno)continue ; -if (!(~dev->quirks & fe->param.quirk_on) && - !(dev->quirks & fe->param.quirk_off)) -continue ; + return fe; + } - dev->quirks |= fe->param.quirk_on; - dev->quirks &= ~fe->param.quirk_off; +return NULL ; +} -ata_dev_notice (dev,"FORCE: modified (%s)\n" , - fe->param.name); - } +/** +* ata_force_quirks - force quirks according to libata.force +* @dev: ATA device of interest +* +* Force quirks according to libata.force and whine about it. +* For consistency with link selection, device number 15 selects +* the first device connected to the host link. +* +* LOCKING: +* EH context. +*/ +static void ata_force_quirks (struct ata_device *dev) +{ +const struct ata_force_ent *fe =ata_force_get_fe_for_dev (dev); + +if (!fe) +return ; + +if (!(~dev->quirks & fe->param.quirk_on) && + !(dev->quirks & fe->param.quirk_off)) +return ; + + dev->quirks |= fe->param.quirk_on; + dev->quirks &= ~fe->param.quirk_off; + +ata_dev_notice (dev,"FORCE: modified (%s)\n" , fe->param.name); }#else static inline void ata_force_pflags (struct ata_port *ap) { }
Signature · 1 line
2.52.0
Niklas Cassel
maintainerPATCH v2 4/8 ata: libata: Change libata.force to use the generic ATA_QUIRK_MAX_SEC quirk
In reply to Niklas CasselModify the existing libata.force parameters "max_sec_128" and "max_sec_1024" to use the generic ATA_QUIRK_MAX_SEC quirk rather than individual quirks.
This also allows us to remove the individual quirks ATA_QUIRK_MAX_SEC_128 and ATA_QUIRK_MAX_SEC_1024.
--- drivers/ata/libata-core.c | 28 ++++++++++++++++------------ include/linux/ata.h | 2 -- include/linux/libata.h | 4 ---- 3 files changed, 16 insertions(+), 18 deletions(-)
drivers/ata/libata-core.c +16 -12
@@ -84,6 +84,7 @@ static DEFINE_IDA(ata_ida); #ifdef CONFIG_ATA_FORCE struct ata_force_param { const char *name; + u64 value; u8 cbl; u8 spd_limit; unsigned int xfer_mask;
@@ -3152,14 +3153,6 @@ int ata_dev_configure(struct ata_device *dev) dev->quirks |=ATA_QUIRK_STUCK_ERR ; } -if (dev->quirks &ATA_QUIRK_MAX_SEC_128 ) - dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_128, - dev->max_sectors); - -if (dev->quirks &ATA_QUIRK_MAX_SEC_1024 ) - dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_1024, - dev->max_sectors); -if (dev->quirks &ATA_QUIRK_MAX_SEC ) dev->max_sectors = min_t(unsigned int, dev->max_sectors, ata_dev_get_quirk_value(dev,
@@ -3995,7 +3988,6 @@ static const char * const ata_quirk_names[] = { [__ATA_QUIRK_DIAGNOSTIC] = "diagnostic", [__ATA_QUIRK_NODMA] = "nodma", [__ATA_QUIRK_NONCQ] = "noncq", - [__ATA_QUIRK_MAX_SEC_128] = "maxsec128", [__ATA_QUIRK_BROKEN_HPA] = "brokenhpa", [__ATA_QUIRK_DISABLE] = "disable", [__ATA_QUIRK_HPA_SIZE] = "hpasize",
@@ -4016,7 +4008,6 @@ static const char * const ata_quirk_names[] = { [__ATA_QUIRK_ZERO_AFTER_TRIM] = "zeroaftertrim", [__ATA_QUIRK_NO_DMA_LOG] = "nodmalog", [__ATA_QUIRK_NOTRIM] = "notrim", - [__ATA_QUIRK_MAX_SEC_1024] = "maxsec1024", [__ATA_QUIRK_MAX_SEC] = "maxsec", [__ATA_QUIRK_MAX_TRIM_128M] = "maxtrim128m", [__ATA_QUIRK_NO_NCQ_ON_ATI] = "noncqonati",
@@ -4389,6 +4380,14 @@ static u64 ata_dev_get_max_sec_quirk_value(struct ata_device *dev)const struct ata_dev_quirk_value *ad = __ata_dev_max_sec_quirks;u64 val =0 ; +#ifdef CONFIG_ATA_FORCE +const struct ata_force_ent *fe =ata_force_get_fe_for_dev (dev); +if (fe && (fe->param.quirk_on &ATA_QUIRK_MAX_SEC ) && fe->param.value) + val = fe->param.value; +#endif +if (val) + goto out; +ata_id_c_string (dev->id, model_num,ATA_ID_PROD ,sizeof (model_num));ata_id_c_string (dev->id, model_rev,ATA_ID_FW_REV ,sizeof (model_rev));
@@ -4401,6 +4400,7 @@ static u64 ata_dev_get_max_sec_quirk_value(struct ata_device *dev) ad++; } +out:ata_dev_warn (dev,"%s quirk is using value: %llu\n" , ata_quirk_names[__ATA_QUIRK_MAX_SEC], val);
@@ -6446,6 +6446,10 @@ EXPORT_SYMBOL_GPL(ata_platform_remove_one);#define force_quirk_on (name, flag) \ { #name, .quirk_on = (flag) } +#define force_quirk_val (name, flag, val) \ + { #name, .quirk_on = (flag), \ + .value = (val) } +#define force_quirk_onoff (name, flag) \ { "no" #name, .quirk_on = (flag) }, \ { #name, .quirk_off = (flag) }
@@ -6520,8 +6524,8 @@ static const struct ata_force_param force_tbl[] __initconst = {force_quirk_onoff (iddevlog,ATA_QUIRK_NO_ID_DEV_LOG ),force_quirk_onoff (logdir,ATA_QUIRK_NO_LOG_DIR ), -force_quirk_on (max_sec_128,ATA_QUIRK_MAX_SEC_128 ), -force_quirk_on (max_sec_1024,ATA_QUIRK_MAX_SEC_1024 ), +force_quirk_val (max_sec_128,ATA_QUIRK_MAX_SEC ,128 ), +force_quirk_val (max_sec_1024,ATA_QUIRK_MAX_SEC ,1024 ),force_quirk_on (max_sec_lba48,ATA_QUIRK_MAX_SEC_LBA48 ), force_quirk_onoff(lpm, ATA_QUIRK_NOLPM),
include/linux/ata.h +0 -2
@@ -26,9 +26,7 @@ enum {ATA_MAX_DEVICES =2 ,/* per bus/port */ ATA_MAX_PRD =256 ,/* we could make these 256/256 */ ATA_SECT_SIZE =512 , -ATA_MAX_SECTORS_128 =128 ,ATA_MAX_SECTORS =256 , -ATA_MAX_SECTORS_1024 =1024 ,ATA_MAX_SECTORS_LBA48 =65535 ,/* avoid count to be 0000h */ ATA_MAX_SECTORS_TAPE =65535 , ATA_MAX_TRIM_RNUM = 64, /* 512-byte payload / (6-byte LBA + 2-byte range per entry) */
include/linux/libata.h +0 -4
@@ -52,7 +52,6 @@ enum ata_quirks { __ATA_QUIRK_DIAGNOSTIC,/* Failed boot diag */ __ATA_QUIRK_NODMA,/* DMA problems */ __ATA_QUIRK_NONCQ,/* Don't use NCQ */ - __ATA_QUIRK_MAX_SEC_128,/* Limit max sects to 128 */ __ATA_QUIRK_BROKEN_HPA,/* Broken HPA */ __ATA_QUIRK_DISABLE,/* Disable it */ __ATA_QUIRK_HPA_SIZE, /* Native size off by one */
@@ -74,7 +73,6 @@ enum ata_quirks { __ATA_QUIRK_ZERO_AFTER_TRIM,/* Guarantees zero after trim */ __ATA_QUIRK_NO_DMA_LOG,/* Do not use DMA for log read */ __ATA_QUIRK_NOTRIM,/* Do not use TRIM */ - __ATA_QUIRK_MAX_SEC_1024,/* Limit max sects to 1024 */ __ATA_QUIRK_MAX_SEC,/* Limit max sectors */ __ATA_QUIRK_MAX_TRIM_128M,/* Limit max trim size to 128M */ __ATA_QUIRK_NO_NCQ_ON_ATI, /* Disable NCQ on ATI chipset */
@@ -94,7 +92,6 @@ enum {ATA_QUIRK_DIAGNOSTIC = (1U << __ATA_QUIRK_DIAGNOSTIC),ATA_QUIRK_NODMA = (1U << __ATA_QUIRK_NODMA),ATA_QUIRK_NONCQ = (1U << __ATA_QUIRK_NONCQ), -ATA_QUIRK_MAX_SEC_128 = (1U << __ATA_QUIRK_MAX_SEC_128),ATA_QUIRK_BROKEN_HPA = (1U << __ATA_QUIRK_BROKEN_HPA),ATA_QUIRK_DISABLE = (1U << __ATA_QUIRK_DISABLE), ATA_QUIRK_HPA_SIZE = (1U << __ATA_QUIRK_HPA_SIZE),
@@ -115,7 +112,6 @@ enum {ATA_QUIRK_ZERO_AFTER_TRIM = (1U << __ATA_QUIRK_ZERO_AFTER_TRIM),ATA_QUIRK_NO_DMA_LOG = (1U << __ATA_QUIRK_NO_DMA_LOG),ATA_QUIRK_NOTRIM = (1U << __ATA_QUIRK_NOTRIM), -ATA_QUIRK_MAX_SEC_1024 = (1U << __ATA_QUIRK_MAX_SEC_1024),ATA_QUIRK_MAX_SEC = (1U << __ATA_QUIRK_MAX_SEC),ATA_QUIRK_MAX_TRIM_128M = (1U << __ATA_QUIRK_MAX_TRIM_128M), ATA_QUIRK_NO_NCQ_ON_ATI = (1U << __ATA_QUIRK_NO_NCQ_ON_ATI),
Signature · 1 line
2.52.0
Niklas Cassel
maintainerPATCH v2 5/8 ata: libata-core: Quirk DELLBOSS VD max_sectors
In reply to Niklas CasselCommit 9b8b84879d4a ("block: Increase BLK_DEF_MAX_SECTORS_CAP") increased the default max_sectors_kb from 1280 KiB to 4096 KiB.
DELLBOSS VD with FW rev MV.R00-0 times out when sending I/Os of size 4096 KiB.
Enable ATA_QUIRK_MAX_SEC, with value 8191 (sectors) for this device, since any I/O with more sectors than leads to I/O timeouts.
With this, the DELLBOSS VD SATA controller is usable again.
--- drivers/ata/libata-core.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/ata/libata-core.c +7 -0
@@ -4064,6 +4064,7 @@ static const struct ata_dev_quirk_value __ata_dev_max_sec_quirks[] = { { "ST380013AS", "3.20", 1024 }, { "LITEON CX1-JB*-HP", NULL, 1024 }, { "LITEON EP1-*", NULL, 1024 }, + { "DELLBOSS VD", "MV.R00-0", 8191 }, { }, };
@@ -4129,6 +4130,12 @@ static const struct ata_dev_quirks_entry __ata_dev_quirks[] = { { "LITEON CX1-JB*-HP", NULL, ATA_QUIRK_MAX_SEC }, { "LITEON EP1-*", NULL, ATA_QUIRK_MAX_SEC }, +/* +* These devices time out with higher max sects. +* https://bugzilla.kernel.org/show_bug.cgi?id=220693 +*/ + { "DELLBOSS VD", "MV.R00-0", ATA_QUIRK_MAX_SEC }, +/* Devices we expect to fail diagnostics */ /* Devices where NCQ should be avoided */
Signature · 1 line
2.52.0
Niklas Cassel
maintainerRe: [PATCH v2 5/8] ata: libata-core: Quirk DELLBOSS VD max_sectors
Quoted 8 lines · Niklas Cassel
Commit
9b8b84879d4a("block: IncreaseBLK_DEF_MAX_SECTORS_CAP") increased the defaultmax_sectors_kbfrom 1280 KiB to 4096 KiB.DELLBOSS VD with FW rev MV.R00-0 times out when sending I/Os of size 4096 KiB.
Enable
ATA_QUIRK_MAX_SEC, with value 8191 (sectors) for this device, since any I/O with more sectors than leads to I/O timeouts.
"since any I/O with more sectors than that lead to I/O timeouts."
Could fixup while applying (unless there will be other major review comments).
Kind regards,
Niklas
Niklas Cassel
maintainerPATCH v2 6/8 ata: libata: Add support to parse equal sign in libata.force
In reply to Niklas CasselCurrently, no libata.force parameter supports an arbitrary value.
All allowed values, e.g. udma/16, udma/25, udma/33, udma/44, udma/66, udma/100, udma/133 have hardcoded entries in the force_tbl table.
Add code to allow a libata.force param with the format libata.force=param=param_value, where param_value can be an arbitrary value.
This code will be used in a follow up commit.
--- drivers/ata/libata-core.c | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-)
drivers/ata/libata-core.c +36 -2
@@ -6461,6 +6461,13 @@ EXPORT_SYMBOL_GPL(ata_platform_remove_one); { "no" #name, .quirk_on = (flag) }, \ { #name, .quirk_off = (flag) } +/* +* If the ata_force_param struct member 'name' ends with '=', then the value +* after the equal sign will be parsed as an u64, and will be saved in the +* ata_force_param struct member 'value'. This works because each libata.force +* entry (struct ata_force_ent) is separated by commas, so each entry represents +* a single quirk, and can thus only have a single value. +*/ static const struct ata_force_param force_tbl[]__initconst = { force_cbl(40c, ATA_CBL_PATA40), force_cbl(80c, ATA_CBL_PATA80),
@@ -6548,8 +6555,9 @@ static int __init ata_parse_force_one(char **cur, const char **reason) {char *start = *cur, *p = *cur; -char *id, *val, *endp; +char *id, *val, *endp, *equalsign, *char_after_equalsign;const struct ata_force_param *match_fp =NULL ; +u64 val_after_equalsign;int nr_matches =0 , i;/* find where this param ends and update *cur */
@@ -6592,10 +6600,36 @@ static int __init ata_parse_force_one(char **cur, } parse_val: -/* parse val, allow shortcuts so that both 1.5 and 1.5Gbps work */ + equalsign =strchr (val,'=' ); +if (equalsign) { + char_after_equalsign = equalsign +1 ; +if (!strlen (char_after_equalsign) || +kstrtoull (char_after_equalsign,10 , &val_after_equalsign)) { + *reason ="invalid value after equal sign" ; +return -EINVAL ; + } + } + +/* parse val */ for (i =0 ; i <ARRAY_SIZE (force_tbl); i++) {const struct ata_force_param *fp = &force_tbl[i]; +/* +* If val contains equal sign, match has to be exact, i.e. +* shortcuts are not supported. +*/ +if (equalsign && + (strncasecmp (val, fp->name, + char_after_equalsign - val) ==0 )) { + force_ent->param = *fp; + force_ent->param.value = val_after_equalsign; +return 0 ; + } + +/* +* If val does not contain equal sign, allow shortcuts so that +* both 1.5 and 1.5Gbps work. +*/ if (strncasecmp (val, fp->name,strlen (val)))continue ;
Signature · 1 line
2.52.0
Niklas Cassel
maintainerPATCH v2 7/8 ata: libata: Add libata.force parameter max_sec
In reply to Niklas CasselAdd a new libata.force parameter called max_sec.
The parameter can take an arbitrary value using the format:
libata.force=max_sec=<param_value>
e.g. libata.force=max_sec=8191
or
libata.force=max_sec=2048
This will allow the user to set an arbitrary max_sectors value using libata.force.
We cannot remove the existing libata.force parameters "max_sec_128" and "max_sec_1024", as these are a part of the exising user facing API.
--- Documentation/admin-guide/kernel-parameters.txt | 4 ++++ drivers/ata/libata-core.c | 1 + 2 files changed, 5 insertions(+)
Documentation/admin-guide/kernel-parameters.txt +4 -0
@@ -3294,6 +3294,10 @@ * [no]logdir: Enable or disable access to the general purpose log directory. + * max_sec=<sectors>: Set the transfer size limit, in + sectors, to the value specified in <sectors>. The + value specified in <sectors> has to be an integer. + * max_sec_128: Set transfer size limit to 128 sectors. * max_sec_1024: Set or clear transfer size limit to
drivers/ata/libata-core.c +1 -0
@@ -6540,6 +6540,7 @@ static const struct ata_force_param force_tbl[] __initconst = {force_quirk_val (max_sec_128,ATA_QUIRK_MAX_SEC ,128 ),force_quirk_val (max_sec_1024,ATA_QUIRK_MAX_SEC ,1024 ), + force_quirk_on(max_sec=, ATA_QUIRK_MAX_SEC),force_quirk_on (max_sec_lba48,ATA_QUIRK_MAX_SEC_LBA48 ), force_quirk_onoff(lpm, ATA_QUIRK_NOLPM),
Signature · 1 line
2.52.0
Niklas Cassel
maintainerPATCH v2 8/8 ata: libata: Allow more quirks
In reply to Niklas CasselWe have currently used up 30 out of the 32-bits in the struct ata_device struct member quirks. Thus, it is only possible to add two more quirks.
Change the struct ata_device struct member quirks from an unsigned int to an u64.
Doing this core level change now, will make it easier for us now, as we will not need to also do core level changes once the final two bits are used as well.
--- drivers/ata/libata-core.c | 18 +++++------ include/linux/libata.h | 64 +++++++++++++++++++-------------------- 2 files changed, 41 insertions(+), 41 deletions(-)
drivers/ata/libata-core.c +9 -9
@@ -76,8 +76,8 @@ static unsigned int ata_dev_init_params(struct ata_device *dev, u16 heads, u16 sectors);static unsigned int ata_dev_set_xfermode (struct ata_device *dev);static void ata_dev_xfermask (struct ata_device *dev); -static unsigned int ata_dev_quirks (const struct ata_device *dev); -static u64 ata_dev_get_quirk_value (struct ata_device *dev,unsigned int quirk); +static u64 ata_dev_quirks (const struct ata_device *dev); +static u64 ata_dev_get_quirk_value (struct ata_device *dev,u64 quirk);static DEFINE_IDA (ata_ida);
@@ -88,8 +88,8 @@ struct ata_force_param {u8 cbl;u8 spd_limit;unsigned int xfer_mask; -unsigned int quirk_on; -unsigned int quirk_off; +u64 quirk_on; +u64 quirk_off;unsigned int pflags_on;u16 lflags_on;u16 lflags_off;
@@ -4071,7 +4071,7 @@ static const struct ata_dev_quirk_value __ata_dev_max_sec_quirks[] = {struct ata_dev_quirks_entry {const char *model_num;const char *model_rev; -unsigned int quirks; +u64 quirks; };static const struct ata_dev_quirks_entry __ata_dev_quirks[] = {
@@ -4356,14 +4356,14 @@ static const struct ata_dev_quirks_entry __ata_dev_quirks[] = { { } }; -static unsigned int ata_dev_quirks (const struct ata_device *dev) +static u64 ata_dev_quirks (const struct ata_device *dev) {unsigned char model_num[ATA_ID_PROD_LEN +1 ];unsigned char model_rev[ATA_ID_FW_REV_LEN +1 ];const struct ata_dev_quirks_entry *ad = __ata_dev_quirks; -/* dev->quirks is an unsigned int. */ -BUILD_BUG_ON (__ATA_QUIRK_MAX >32 ); +/* dev->quirks is an u64. */ +BUILD_BUG_ON (__ATA_QUIRK_MAX >64 );ata_id_c_string (dev->id, model_num,ATA_ID_PROD ,sizeof (model_num));ata_id_c_string (dev->id, model_rev,ATA_ID_FW_REV ,sizeof (model_rev));
@@ -4414,7 +4414,7 @@ static u64 ata_dev_get_max_sec_quirk_value(struct ata_device *dev)return val; } -static u64 ata_dev_get_quirk_value (struct ata_device *dev,unsigned int quirk) +static u64 ata_dev_get_quirk_value (struct ata_device *dev,u64 quirk) {if (quirk ==ATA_QUIRK_MAX_SEC )return ata_dev_get_max_sec_quirk_value (dev);
include/linux/libata.h +32 -32
82 lines not on this page · raw message
Signature · 1 line
2.52.0
Niklas,
Quoted 5 lines
It seems like a lot for SATA controllers are buggy and don't really like this, see: https://bugzilla.kernel.org/show_bug.cgi?id=220693
For now, we only add a DELLBOSS VD
max_sectorsquirk, but surely we will need to quirk additional controllers.
Looks OK to me.
Signature · 1 line
Martin K. Petersen