Skip to content

Commit b1e0b4f

Browse files
floatiousgregkh
authored andcommitted
ata: libata-core: Add 'external' to the libata.force kernel parameter
[ Upstream commit deca423 ] Commit ae1f3db ("ata: ahci: do not enable LPM on external ports") changed so that LPM is not enabled on external ports (hotplug-capable or eSATA ports). This is because hotplug and LPM are mutually exclusive, see 7.3.1 Hot Plug Removal Detection and Power Management Interaction in AHCI 1.3.1. This does require that firmware has set the appropate bits (HPCP or ESP) in PxCMD (which is a per port register in the AHCI controller). If the firmware has failed to mark a port as hotplug-capable or eSATA in PxCMD, then there is currently not much a user can do. If LPM is enabled on the port, hotplug insertions and removals will not be detected on that port. In order to allow a user to fix up broken firmware, add 'external' to the libata.force kernel parameter. libata.force can be specified either on the kernel command line, or as a kernel module parameter. For more information, see Documentation/admin-guide/kernel-parameters.txt. Reviewed-by: Damien Le Moal <dlemoal@kernel.org> Link: https://lore.kernel.org/r/20250130133544.219297-4-cassel@kernel.org Signed-off-by: Niklas Cassel <cassel@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 535b666 commit b1e0b4f

File tree

2 files changed

+40
-0
lines changed

2 files changed

+40
-0
lines changed

Documentation/admin-guide/kernel-parameters.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3028,6 +3028,8 @@
30283028
* max_sec_lba48: Set or clear transfer size limit to
30293029
65535 sectors.
30303030

3031+
* external: Mark port as external (hotplug-capable).
3032+
30313033
* [no]lpm: Enable or disable link power management.
30323034

30333035
* [no]setxfer: Indicate if transfer speed mode setting

drivers/ata/libata-core.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ struct ata_force_param {
8888
unsigned int xfer_mask;
8989
unsigned int quirk_on;
9090
unsigned int quirk_off;
91+
unsigned int pflags_on;
9192
u16 lflags_on;
9293
u16 lflags_off;
9394
};
@@ -331,6 +332,35 @@ void ata_force_cbl(struct ata_port *ap)
331332
}
332333
}
333334

335+
/**
336+
* ata_force_pflags - force port flags according to libata.force
337+
* @ap: ATA port of interest
338+
*
339+
* Force port flags according to libata.force and whine about it.
340+
*
341+
* LOCKING:
342+
* EH context.
343+
*/
344+
static void ata_force_pflags(struct ata_port *ap)
345+
{
346+
int i;
347+
348+
for (i = ata_force_tbl_size - 1; i >= 0; i--) {
349+
const struct ata_force_ent *fe = &ata_force_tbl[i];
350+
351+
if (fe->port != -1 && fe->port != ap->print_id)
352+
continue;
353+
354+
/* let pflags stack */
355+
if (fe->param.pflags_on) {
356+
ap->pflags |= fe->param.pflags_on;
357+
ata_port_notice(ap,
358+
"FORCE: port flag 0x%x forced -> 0x%x\n",
359+
fe->param.pflags_on, ap->pflags);
360+
}
361+
}
362+
}
363+
334364
/**
335365
* ata_force_link_limits - force link limits according to libata.force
336366
* @link: ATA link of interest
@@ -486,6 +516,7 @@ static void ata_force_quirks(struct ata_device *dev)
486516
}
487517
}
488518
#else
519+
static inline void ata_force_pflags(struct ata_port *ap) { }
489520
static inline void ata_force_link_limits(struct ata_link *link) { }
490521
static inline void ata_force_xfermask(struct ata_device *dev) { }
491522
static inline void ata_force_quirks(struct ata_device *dev) { }
@@ -5460,6 +5491,8 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
54605491
#endif
54615492
ata_sff_port_init(ap);
54625493

5494+
ata_force_pflags(ap);
5495+
54635496
return ap;
54645497
}
54655498
EXPORT_SYMBOL_GPL(ata_port_alloc);
@@ -6272,6 +6305,9 @@ EXPORT_SYMBOL_GPL(ata_platform_remove_one);
62726305
{ "no" #name, .lflags_on = (flags) }, \
62736306
{ #name, .lflags_off = (flags) }
62746307

6308+
#define force_pflag_on(name, flags) \
6309+
{ #name, .pflags_on = (flags) }
6310+
62756311
#define force_quirk_on(name, flag) \
62766312
{ #name, .quirk_on = (flag) }
62776313

@@ -6331,6 +6367,8 @@ static const struct ata_force_param force_tbl[] __initconst = {
63316367
force_lflag_on(rstonce, ATA_LFLAG_RST_ONCE),
63326368
force_lflag_onoff(dbdelay, ATA_LFLAG_NO_DEBOUNCE_DELAY),
63336369

6370+
force_pflag_on(external, ATA_PFLAG_EXTERNAL),
6371+
63346372
force_quirk_onoff(ncq, ATA_QUIRK_NONCQ),
63356373
force_quirk_onoff(ncqtrim, ATA_QUIRK_NO_NCQ_TRIM),
63366374
force_quirk_onoff(ncqati, ATA_QUIRK_NO_NCQ_ON_ATI),

0 commit comments

Comments
 (0)