From 45c4c5a6156a5ab450a7595dd1c8985e2d459403 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Tue, 2 Dec 2025 13:21:34 +0100 Subject: [PATCH] ata: libata: Add support to parse equal sign in libata.force Currently, 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. Signed-off-by: Niklas Cassel Reviewed-by: Martin K. Petersen Reviewed-by: Damien Le Moal Signed-off-by: Damien Le Moal --- drivers/ata/libata-core.c | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index cf7b57d048a3c..cd1ebdbe659bd 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6490,6 +6490,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), @@ -6577,8 +6584,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 */ @@ -6621,10 +6629,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 the parameter value. */ 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; -- 2.47.3