Skip to content

Commit deca423

Browse files
committed
ata: libata-core: Add 'external' to the libata.force kernel parameter
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 <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Niklas Cassel <[email protected]>
1 parent 2014c95 commit deca423

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
@@ -3116,6 +3116,8 @@
31163116
* max_sec_lba48: Set or clear transfer size limit to
31173117
65535 sectors.
31183118

3119+
* external: Mark port as external (hotplug-capable).
3120+
31193121
* [no]lpm: Enable or disable link power management.
31203122

31213123
* [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) { }
@@ -5456,6 +5487,8 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
54565487
#endif
54575488
ata_sff_port_init(ap);
54585489

5490+
ata_force_pflags(ap);
5491+
54595492
return ap;
54605493
}
54615494
EXPORT_SYMBOL_GPL(ata_port_alloc);
@@ -6268,6 +6301,9 @@ EXPORT_SYMBOL_GPL(ata_platform_remove_one);
62686301
{ "no" #name, .lflags_on = (flags) }, \
62696302
{ #name, .lflags_off = (flags) }
62706303

6304+
#define force_pflag_on(name, flags) \
6305+
{ #name, .pflags_on = (flags) }
6306+
62716307
#define force_quirk_on(name, flag) \
62726308
{ #name, .quirk_on = (flag) }
62736309

@@ -6327,6 +6363,8 @@ static const struct ata_force_param force_tbl[] __initconst = {
63276363
force_lflag_on(rstonce, ATA_LFLAG_RST_ONCE),
63286364
force_lflag_onoff(dbdelay, ATA_LFLAG_NO_DEBOUNCE_DELAY),
63296365

6366+
force_pflag_on(external, ATA_PFLAG_EXTERNAL),
6367+
63306368
force_quirk_onoff(ncq, ATA_QUIRK_NONCQ),
63316369
force_quirk_onoff(ncqtrim, ATA_QUIRK_NO_NCQ_TRIM),
63326370
force_quirk_onoff(ncqati, ATA_QUIRK_NO_NCQ_ON_ATI),

0 commit comments

Comments
 (0)