lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20260123-ledtrig_disk_-v1-4-07004756467b@posteo.de>
Date: Fri, 23 Jan 2026 19:05:10 +0000
From: Markus Probst <markus.probst@...teo.de>
To: Lee Jones <lee@...nel.org>, Pavel Machek <pavel@...nel.org>, 
 Rob Herring <robh@...nel.org>, Krzysztof Kozlowski <krzk+dt@...nel.org>, 
 Conor Dooley <conor+dt@...nel.org>, 
 Jacek Anaszewski <jacek.anaszewski@...il.com>, 
 Damien Le Moal <dlemoal@...nel.org>, Niklas Cassel <cassel@...nel.org>, 
 John Garry <john.g.garry@...cle.com>, Jason Yan <yanaijie@...wei.com>, 
 "James E.J. Bottomley" <James.Bottomley@...senPartnership.com>, 
 "Martin K. Petersen" <martin.petersen@...cle.com>
Cc: Pavel Machek <pavel@....cz>, linux-leds@...r.kernel.org, 
 devicetree@...r.kernel.org, linux-kernel@...r.kernel.org, 
 linux-ide@...r.kernel.org, linux-scsi@...r.kernel.org, 
 Markus Probst <markus.probst@...teo.de>
Subject: [PATCH RFC 4/4] leds: add disk trigger for each ata port

Register a disk trigger for each ata port. This trigger will only show
the activity for the ata port it has been registered for.

This allows individual leds to be mapped to one ata port.
This is especially useful for NAS devices, which have an own led for each
disk slot.

Signed-off-by: Markus Probst <markus.probst@...teo.de>
---
 drivers/ata/libata-core.c           |  22 +++++-
 drivers/leds/trigger/ledtrig-disk.c | 144 ++++++++++++++++++++++++++++++------
 drivers/scsi/libsas/sas_ata.c       |   3 +-
 include/linux/leds.h                |  16 +++-
 include/linux/libata.h              |   6 +-
 5 files changed, 161 insertions(+), 30 deletions(-)

diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 09d8c035fcdf..796c46449298 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -4921,8 +4921,10 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
 	struct ata_device *dev = qc->dev;
 	struct ata_eh_info *ehi = &dev->link->eh_info;
 
+#ifdef CONFIG_LEDS_TRIGGER_DISK
 	/* Trigger the LED (if available) */
-	ledtrig_disk_activity(!!(qc->tf.flags & ATA_TFLAG_WRITE));
+	ledtrig_disk_activity(ap->led_trigger, !!(qc->tf.flags & ATA_TFLAG_WRITE));
+#endif
 
 	/*
 	 * In order to synchronize EH with the regular execution path, a qc that
@@ -5538,10 +5540,13 @@ int sata_link_init_spd(struct ata_link *link)
  *	LOCKING:
  *	Inherited from calling layer (may sleep).
  */
-struct ata_port *ata_port_alloc(struct ata_host *host)
+struct ata_port *ata_port_alloc(struct ata_host *host, int port_no)
 {
 	struct ata_port *ap;
 	int id;
+#ifdef CONFIG_LEDS_TRIGGER_DISK
+	char name[32];
+#endif
 
 	ap = kzalloc(sizeof(*ap), GFP_KERNEL);
 	if (!ap)
@@ -5557,6 +5562,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
 	ap->print_id = id;
 	ap->host = host;
 	ap->dev = host->dev;
+	ap->port_no = port_no;
 
 	mutex_init(&ap->scsi_scan_mutex);
 	INIT_DELAYED_WORK(&ap->hotplug_task, ata_scsi_hotplug);
@@ -5579,6 +5585,11 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
 
 	ata_force_pflags(ap);
 
+#ifdef CONFIG_LEDS_TRIGGER_DISK
+	if (snprintf(name, sizeof(name), "%s-ata%d", dev_name(host->dev), port_no) < sizeof(name))
+		ap->led_trigger = ledtrig_disk_trigger_register(name);
+#endif
+
 	return ap;
 }
 EXPORT_SYMBOL_GPL(ata_port_alloc);
@@ -5588,6 +5599,10 @@ void ata_port_free(struct ata_port *ap)
 	if (!ap)
 		return;
 
+#ifdef CONFIG_LEDS_TRIGGER_DISK
+	ledtrig_disk_trigger_unregister(ap->led_trigger);
+#endif
+
 	kfree(ap->pmp_link);
 	kfree(ap->slave_link);
 	ida_free(&ata_ida, ap->print_id);
@@ -5690,11 +5705,10 @@ struct ata_host *ata_host_alloc(struct device *dev, int n_ports)
 	for (i = 0; i < n_ports; i++) {
 		struct ata_port *ap;
 
-		ap = ata_port_alloc(host);
+		ap = ata_port_alloc(host, i);
 		if (!ap)
 			goto err_out;
 
-		ap->port_no = i;
 		host->ports[i] = ap;
 	}
 
diff --git a/drivers/leds/trigger/ledtrig-disk.c b/drivers/leds/trigger/ledtrig-disk.c
index ed5ef83a5b35..fd25b4e45fb4 100644
--- a/drivers/leds/trigger/ledtrig-disk.c
+++ b/drivers/leds/trigger/ledtrig-disk.c
@@ -159,20 +159,22 @@ static int ledtrig_disk_activate(struct led_classdev *led_cdev)
 	return 0;
 }
 
-static struct led_trigger ledtrig_disk = {
-	.name = "disk-activity",
-	.activate = ledtrig_disk_activate,
-	.groups = ledtrig_disk_groups,
-};
-static struct led_trigger ledtrig_disk_read = {
-	.name = "disk-read",
-	.activate = ledtrig_disk_activate,
-	.groups = ledtrig_disk_groups,
-};
-static struct led_trigger ledtrig_disk_write = {
-	.name = "disk-write",
-	.activate = ledtrig_disk_activate,
-	.groups = ledtrig_disk_groups,
+static struct ledtrig_disk_trigger ledtrig_disk = {
+	.all = {
+		.name = "disk-activity",
+		.activate = ledtrig_disk_activate,
+		.groups = ledtrig_disk_groups,
+	},
+	.read = {
+		.name = "disk-read",
+		.activate = ledtrig_disk_activate,
+		.groups = ledtrig_disk_groups,
+	},
+	.write = {
+		.name = "disk-write",
+		.activate = ledtrig_disk_activate,
+		.groups = ledtrig_disk_groups,
+	},
 };
 
 static void ledtrig_disk_blink_oneshot(struct led_trigger *trig)
@@ -189,21 +191,121 @@ static void ledtrig_disk_blink_oneshot(struct led_trigger *trig)
 	rcu_read_unlock();
 }
 
-void ledtrig_disk_activity(bool write)
+static void ledtrig_disk_trigger_activity(struct ledtrig_disk_trigger *trig, bool write)
 {
-	ledtrig_disk_blink_oneshot(&ledtrig_disk);
+	if (IS_ERR_OR_NULL(trig))
+		return;
+	ledtrig_disk_blink_oneshot(&trig->all);
 	if (write)
-		ledtrig_disk_blink_oneshot(&ledtrig_disk_write);
+		ledtrig_disk_blink_oneshot(&trig->write);
 	else
-		ledtrig_disk_blink_oneshot(&ledtrig_disk_read);
+		ledtrig_disk_blink_oneshot(&trig->read);
+}
+
+void ledtrig_disk_activity(struct ledtrig_disk_trigger *port, bool write)
+{
+	ledtrig_disk_trigger_activity(&ledtrig_disk, write);
+	ledtrig_disk_trigger_activity(port, write);
 }
 EXPORT_SYMBOL(ledtrig_disk_activity);
 
+struct ledtrig_disk_trigger *ledtrig_disk_trigger_register(const char *name)
+{
+	struct ledtrig_disk_trigger *trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
+	int ret, n;
+
+	if (!trigger)
+		return ERR_PTR(-ENOMEM);
+
+	trigger->all.name = kzalloc(TRIG_NAME_MAX, GFP_KERNEL);
+	if (!trigger->all.name) {
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	n = snprintf((char *)trigger->all.name, TRIG_NAME_MAX, "%s-disk-activity", name);
+	if (n >= TRIG_NAME_MAX) {
+		ret = -E2BIG;
+		goto err1;
+	}
+
+	trigger->all.activate = ledtrig_disk_activate;
+	trigger->all.groups = ledtrig_disk_groups;
+
+	ret = led_trigger_register(&trigger->all);
+	if (ret)
+		goto err1;
+
+	trigger->read.name = kzalloc(TRIG_NAME_MAX, GFP_KERNEL);
+	if (!trigger->read.name) {
+		ret = -ENOMEM;
+		goto err2;
+	}
+
+	n = snprintf((char *)trigger->read.name, TRIG_NAME_MAX, "%s-disk-read", name);
+	if (n >= TRIG_NAME_MAX) {
+		ret = -E2BIG;
+		goto err2;
+	}
+
+	trigger->read.activate = ledtrig_disk_activate;
+	trigger->read.groups = ledtrig_disk_groups;
+
+	ret = led_trigger_register(&trigger->read);
+	if (ret)
+		goto err2;
+
+	trigger->write.name = kzalloc(TRIG_NAME_MAX, GFP_KERNEL);
+	if (!trigger->write.name) {
+		ret = -ENOMEM;
+		goto err3;
+	}
+
+	n = snprintf((char *)trigger->write.name, TRIG_NAME_MAX, "%s-disk-write", name);
+	if (n >= TRIG_NAME_MAX) {
+		ret = -E2BIG;
+		goto err3;
+	}
+
+	trigger->write.activate = ledtrig_disk_activate;
+	trigger->write.groups = ledtrig_disk_groups;
+
+	ret = led_trigger_register(&trigger->write);
+	if (ret)
+		goto err3;
+
+	return trigger;
+
+err3:
+	led_trigger_unregister(&trigger->read);
+err2:
+	led_trigger_unregister(&trigger->all);
+err1:
+	kfree(trigger->all.name);
+	kfree(trigger->read.name);
+	kfree(trigger->write.name);
+	kfree(trigger);
+
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(ledtrig_disk_trigger_register);
+
+void ledtrig_disk_trigger_unregister(struct ledtrig_disk_trigger *trig)
+{
+	if (IS_ERR_OR_NULL(trig))
+		return;
+
+	led_trigger_unregister(&trig->all);
+	led_trigger_unregister(&trig->read);
+	led_trigger_unregister(&trig->write);
+}
+EXPORT_SYMBOL(ledtrig_disk_trigger_unregister);
+
 static int __init ledtrig_disk_init(void)
 {
-	led_trigger_register(&ledtrig_disk);
-	led_trigger_register(&ledtrig_disk_read);
-	led_trigger_register(&ledtrig_disk_write);
+	led_trigger_register(&ledtrig_disk.all);
+	led_trigger_register(&ledtrig_disk.read);
+	led_trigger_register(&ledtrig_disk.write);
 
 	return 0;
 }
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index bcecb4911da9..8841850684f7 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -587,14 +587,13 @@ int sas_ata_init(struct domain_device *found_dev)
 
 	ata_host_init(ata_host, ha->dev, &sas_sata_ops);
 
-	ap = ata_port_alloc(ata_host);
+	ap = ata_port_alloc(ata_host, 0);
 	if (!ap) {
 		pr_err("ata_port_alloc failed.\n");
 		rc = -ENODEV;
 		goto free_host;
 	}
 
-	ap->port_no = 0;
 	ap->pio_mask = ATA_PIO4;
 	ap->mwdma_mask = ATA_MWDMA2;
 	ap->udma_mask = ATA_UDMA6;
diff --git a/include/linux/leds.h b/include/linux/leds.h
index b16b803cc1ac..3221be97e9c0 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -619,10 +619,22 @@ enum led_trigger_netdev_modes {
 };
 
 /* Trigger specific functions */
+struct ledtrig_disk_trigger {
+	struct led_trigger all;
+	struct led_trigger read;
+	struct led_trigger write;
+};
 #ifdef CONFIG_LEDS_TRIGGER_DISK
-void ledtrig_disk_activity(bool write);
+struct ledtrig_disk_trigger *ledtrig_disk_trigger_register(const char *name);
+void ledtrig_disk_trigger_unregister(struct ledtrig_disk_trigger *trig);
+void ledtrig_disk_activity(struct ledtrig_disk_trigger *port, bool write);
 #else
-static inline void ledtrig_disk_activity(bool write) {}
+static inline struct ledtrig_disk_trigger *ledtrig_disk_trigger_register(const char *name)
+{
+	return ERR_PTR(-EOPNOTSUPP);
+}
+static inline void ledtrig_disk_trigger_unregister(struct ledtrig_disk_trigger *trig) {}
+static inline void ledtrig_disk_activity(struct ledtrig_disk_trigger *port, bool write) {}
 #endif
 
 #ifdef CONFIG_LEDS_TRIGGER_MTD
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 39534fafa36a..50124d170d13 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -940,6 +940,10 @@ struct ata_port {
 #ifdef CONFIG_ATA_ACPI
 	struct ata_acpi_gtm	__acpi_init_gtm; /* use ata_acpi_init_gtm() */
 #endif
+
+#ifdef CONFIG_LEDS_TRIGGER_DISK
+	struct ledtrig_disk_trigger *led_trigger;
+#endif
 };
 
 /* The following initializer overrides a method to NULL whether one of
@@ -1307,7 +1311,7 @@ extern int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy,
 			     bool spm_wakeup);
 extern int ata_slave_link_init(struct ata_port *ap);
 extern void ata_port_probe(struct ata_port *ap);
-extern struct ata_port *ata_port_alloc(struct ata_host *host);
+extern struct ata_port *ata_port_alloc(struct ata_host *host, int port_no);
 extern void ata_port_free(struct ata_port *ap);
 extern int ata_tport_add(struct device *parent, struct ata_port *ap);
 extern void ata_tport_delete(struct ata_port *ap);

-- 
2.52.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ