From: Louis Sautier <sautier.louis@gmail.com>
To: "Martin K. Petersen" <martin.petersen@oracle.com>,
"James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>,
Sathya Prakash <sathya.prakash@broadcom.com>,
Sreekanth Reddy <sreekanth.reddy@broadcom.com>,
Suganath Prabu Subramani <suganath-prabu.subramani@broadcom.com>,
Ranjan Kumar <ranjan.kumar@broadcom.com>
Cc: Guenter Roeck <linux@roeck-us.net>,
Jonathan Corbet <corbet@lwn.net>,
Shuah Khan <skhan@linuxfoundation.org>,
MPT-FusionLinux.pdl@broadcom.com, linux-scsi@vger.kernel.org,
linux-hwmon@vger.kernel.org, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: [PATCH 2/2] scsi: mpt3sas: add hwmon support
Date: Tue, 12 May 2026 23:47:03 +0200 [thread overview]
Message-ID: <20260512214703.655633-3-sautier.louis@gmail.com> (raw)
In-Reply-To: <20260512214703.655633-1-sautier.louis@gmail.com>
Expose the IOC and board temperature sensors of LSI / Broadcom SAS
HBAs through hwmon. Readings come from MPI IO Unit Page 7 via the
accessor added in the preceding patch.
The same fields are exposed by Broadcom's userspace tooling
through the /dev/mpt[23]ctl ioctl path (typically root-only):
IOCTemperature and BoardTemperature in lsiutil; ROC and Controller
in storcli. With this driver, sensors(1) shows them unprivileged:
$ sensors mpt3sas-pci-0200
mpt3sas-pci-0200
Adapter: PCI adapter
IOC: +42.0°C
Each channel is gated independently by its *TemperatureUnits field
through is_visible(); cards that populate only one sensor expose
only one input file, and cards that populate neither do not register
an hwmon device.
Built into mpt3sas.ko under a new CONFIG_SCSI_MPT3SAS_HWMON Kconfig
option.
Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Louis Sautier <sautier.louis@gmail.com>
---
Documentation/hwmon/index.rst | 1 +
Documentation/hwmon/mpt3sas.rst | 57 ++++++++
MAINTAINERS | 1 +
drivers/scsi/mpt3sas/Kconfig | 9 ++
drivers/scsi/mpt3sas/Makefile | 2 +
drivers/scsi/mpt3sas/mpt3sas_base.h | 17 +++
drivers/scsi/mpt3sas/mpt3sas_hwmon.c | 200 +++++++++++++++++++++++++++
drivers/scsi/mpt3sas/mpt3sas_scsih.c | 6 +
8 files changed, 293 insertions(+)
create mode 100644 Documentation/hwmon/mpt3sas.rst
create mode 100644 drivers/scsi/mpt3sas/mpt3sas_hwmon.c
diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst
index 8b655e5d6b68..106f87fa8b18 100644
--- a/Documentation/hwmon/index.rst
+++ b/Documentation/hwmon/index.rst
@@ -193,6 +193,7 @@ Hardware Monitoring Kernel Drivers
mp9941
mp9945
mpq8785
+ mpt3sas
nct6683
nct6775
nct7363
diff --git a/Documentation/hwmon/mpt3sas.rst b/Documentation/hwmon/mpt3sas.rst
new file mode 100644
index 000000000000..3a260a389d6d
--- /dev/null
+++ b/Documentation/hwmon/mpt3sas.rst
@@ -0,0 +1,57 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Kernel driver mpt3sas
+=====================
+
+Supported chips:
+
+ * LSI / Broadcom / Avago SAS HBAs handled by the mpt3sas driver,
+ such as the 9300, 9400, and 9500 series.
+
+ Prefix: ``mpt3sas``
+
+
+Description
+-----------
+
+The mpt3sas driver exposes the IOC and board temperature sensors of
+LSI / Broadcom SAS HBAs through the hwmon interface.
+Either or both sensors may be absent depending on the card; the
+corresponding sysfs files only appear when the firmware reports the
+sensor as present, and cards that report neither sensor do not
+register an hwmon device at all.
+
+
+Sysfs entries
+-------------
+
+============ ======================
+Name Description
+============ ======================
+temp1_input IOC temperature (mC)
+temp1_label "IOC"
+temp2_input Board temperature (mC)
+temp2_label "Board"
+============ ======================
+
+
+Cross-reference with vendor tooling
+-----------------------------------
+
+The hwmon channels correspond to fields reported by Broadcom's
+proprietary tools as follows:
+
+================= ========================== ===============================
+hwmon label lsiutil storcli
+================= ========================== ===============================
+``IOC`` (temp1) ``IOCTemperature`` ``ROC temperature``
+``Board`` (temp2) ``BoardTemperature`` ``Controller temperature``
+================= ========================== ===============================
+
+With lsiutil::
+
+ lsiutil -pN -a 25,2,0,0
+
+With storcli::
+
+ storcli /cN show temperature
diff --git a/MAINTAINERS b/MAINTAINERS
index b2040011a386..e084f710f436 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15154,6 +15154,7 @@ L: MPT-FusionLinux.pdl@broadcom.com
L: linux-scsi@vger.kernel.org
S: Supported
W: http://www.avagotech.com/support/
+F: Documentation/hwmon/mpt3sas.rst
F: drivers/message/fusion/
F: drivers/scsi/mpt3sas/
diff --git a/drivers/scsi/mpt3sas/Kconfig b/drivers/scsi/mpt3sas/Kconfig
index c299f7e078fb..638acd2c6623 100644
--- a/drivers/scsi/mpt3sas/Kconfig
+++ b/drivers/scsi/mpt3sas/Kconfig
@@ -73,6 +73,15 @@ config SCSI_MPT3SAS_MAX_SGE
can be 256. However, it may decreased down to 16. Decreasing this
parameter will reduce memory requirements on a per controller instance.
+config SCSI_MPT3SAS_HWMON
+ bool "LSI MPT Fusion SAS hwmon support"
+ depends on SCSI_MPT3SAS && HWMON
+ depends on !(SCSI_MPT3SAS=y && HWMON=m)
+ help
+ Say Y here to expose the IOC and board temperature sensors of
+ LSI / Broadcom SAS HBAs (such as the 9300, 9400, and 9500 series)
+ through hwmon. See Documentation/hwmon/mpt3sas.rst for details.
+
config SCSI_MPT2SAS
tristate "Legacy MPT2SAS config option"
default n
diff --git a/drivers/scsi/mpt3sas/Makefile b/drivers/scsi/mpt3sas/Makefile
index e76d994dbed3..9a2f3ce4158a 100644
--- a/drivers/scsi/mpt3sas/Makefile
+++ b/drivers/scsi/mpt3sas/Makefile
@@ -9,3 +9,5 @@ mpt3sas-y += mpt3sas_base.o \
mpt3sas_trigger_diag.o \
mpt3sas_warpdrive.o \
mpt3sas_debugfs.o \
+
+mpt3sas-$(CONFIG_SCSI_MPT3SAS_HWMON) += mpt3sas_hwmon.o
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h
index c655742d0dde..63252f30343b 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.h
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.h
@@ -1629,6 +1629,7 @@ struct MPT3SAS_ADAPTER {
u8 is_aero_ioc;
struct dentry *debugfs_root;
struct dentry *ioc_dump;
+ struct mpt3sas_hwmon *hwmon;
PUT_SMID_IO_FP_HIP put_smid_scsi_io;
PUT_SMID_IO_FP_HIP put_smid_fast_path;
PUT_SMID_IO_FP_HIP put_smid_hi_priority;
@@ -2049,6 +2050,22 @@ void mpt3sas_destroy_debugfs(struct MPT3SAS_ADAPTER *ioc);
void mpt3sas_init_debugfs(void);
void mpt3sas_exit_debugfs(void);
+#if IS_ENABLED(CONFIG_SCSI_MPT3SAS_HWMON)
+int mpt3sas_hwmon_register(struct MPT3SAS_ADAPTER *ioc);
+void mpt3sas_hwmon_unregister(struct MPT3SAS_ADAPTER *ioc);
+#else
+static inline int
+mpt3sas_hwmon_register(struct MPT3SAS_ADAPTER *ioc)
+{
+ return 0;
+}
+
+static inline void
+mpt3sas_hwmon_unregister(struct MPT3SAS_ADAPTER *ioc)
+{
+}
+#endif
+
/**
* _scsih_is_pcie_scsi_device - determines if device is an pcie scsi device
* @device_info: bitfield providing information about the device.
diff --git a/drivers/scsi/mpt3sas/mpt3sas_hwmon.c b/drivers/scsi/mpt3sas/mpt3sas_hwmon.c
new file mode 100644
index 000000000000..26227a992f35
--- /dev/null
+++ b/drivers/scsi/mpt3sas/mpt3sas_hwmon.c
@@ -0,0 +1,200 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Hardware monitoring (hwmon) support for the LSI / Broadcom mpt3sas
+ * SAS HBA driver. Exposes the IOC and board temperature sensors by
+ * reading MPI IO Unit Page 7.
+ */
+
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include "mpt3sas_base.h"
+
+struct mpt3sas_hwmon {
+ struct MPT3SAS_ADAPTER *ioc;
+ struct device *hwmon_dev;
+ bool ioc_present;
+ bool board_present;
+};
+
+/*
+ * Convert a (raw, units) reading to millidegrees Celsius.
+ * Returns -ENODATA when the sensor reports "not present" or
+ * unknown units. Temperature values are interpreted as signed
+ * two's-complement integers.
+ *
+ * The MPI2_IOUNITPAGE7_IOC_TEMP_* and MPI2_IOUNITPAGE7_BOARD_TEMP_*
+ * defines in mpi2_cnfg.h share the same values; the IOC ones are
+ * used for both channels.
+ */
+static int
+_hwmon_to_mdegc(s16 raw, u8 units, long *out)
+{
+ switch (units) {
+ case MPI2_IOUNITPAGE7_IOC_TEMP_CELSIUS:
+ *out = (long)raw * 1000;
+ return 0;
+ case MPI2_IOUNITPAGE7_IOC_TEMP_FAHRENHEIT:
+ /* (F - 32) * 5 / 9, expressed in milli-units */
+ *out = ((long)raw - 32) * 5000 / 9;
+ return 0;
+ default:
+ return -ENODATA;
+ }
+}
+
+static umode_t
+_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ const struct mpt3sas_hwmon *h = drvdata;
+
+ if (type != hwmon_temp)
+ return 0;
+ if (attr != hwmon_temp_input && attr != hwmon_temp_label)
+ return 0;
+ if (channel == 0 && h->ioc_present)
+ return 0444;
+ if (channel == 1 && h->board_present)
+ return 0444;
+ return 0;
+}
+
+static int
+_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ struct mpt3sas_hwmon *h = dev_get_drvdata(dev);
+ Mpi2ConfigReply_t mpi_reply;
+ Mpi2IOUnitPage7_t page;
+ int r;
+
+ if (type != hwmon_temp || attr != hwmon_temp_input)
+ return -EOPNOTSUPP;
+
+ r = mpt3sas_config_get_iounit_pg7(h->ioc, &mpi_reply, &page);
+ if (r)
+ return r;
+
+ if (channel == 0)
+ return _hwmon_to_mdegc((s16)le16_to_cpu(page.IOCTemperature),
+ page.IOCTemperatureUnits, val);
+ if (channel == 1)
+ return _hwmon_to_mdegc((s16)le16_to_cpu(page.BoardTemperature),
+ page.BoardTemperatureUnits, val);
+ return -EOPNOTSUPP;
+}
+
+static const char * const mpt3sas_hwmon_temp_labels[] = {
+ "IOC",
+ "Board",
+};
+
+static int
+_hwmon_read_string(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, const char **str)
+{
+ if (type != hwmon_temp || attr != hwmon_temp_label)
+ return -EOPNOTSUPP;
+ *str = mpt3sas_hwmon_temp_labels[channel];
+ return 0;
+}
+
+static const struct hwmon_channel_info * const mpt3sas_hwmon_info[] = {
+ HWMON_CHANNEL_INFO(temp,
+ HWMON_T_INPUT | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_LABEL),
+ NULL,
+};
+
+static const struct hwmon_ops mpt3sas_hwmon_ops = {
+ .is_visible = _hwmon_is_visible,
+ .read = _hwmon_read,
+ .read_string = _hwmon_read_string,
+};
+
+static const struct hwmon_chip_info mpt3sas_hwmon_chip_info = {
+ .ops = &mpt3sas_hwmon_ops,
+ .info = mpt3sas_hwmon_info,
+};
+
+/**
+ * mpt3sas_hwmon_register - register an hwmon device for the IOC
+ * @ioc: per adapter object
+ * Context: sleep.
+ *
+ * Succeeds without registering when no temperature sensors are present,
+ * so cards without thermal monitoring do not expose an empty hwmon node.
+ * Paired with mpt3sas_hwmon_unregister() from the driver's remove path.
+ *
+ * Return: 0 for success, non-zero for failure.
+ */
+int
+mpt3sas_hwmon_register(struct MPT3SAS_ADAPTER *ioc)
+{
+ struct device *parent = &ioc->pdev->dev;
+ struct mpt3sas_hwmon *h;
+ struct device *hwdev;
+ Mpi2ConfigReply_t mpi_reply;
+ Mpi2IOUnitPage7_t page;
+ int r;
+
+ h = kzalloc_obj(*h);
+ if (!h)
+ return -ENOMEM;
+
+ h->ioc = ioc;
+
+ r = mpt3sas_config_get_iounit_pg7(ioc, &mpi_reply, &page);
+ if (r) {
+ kfree(h);
+ return r;
+ }
+
+ h->ioc_present = page.IOCTemperatureUnits != MPI2_IOUNITPAGE7_IOC_TEMP_NOT_PRESENT;
+ h->board_present = page.BoardTemperatureUnits != MPI2_IOUNITPAGE7_BOARD_TEMP_NOT_PRESENT;
+
+ /*
+ * A page where both *TemperatureUnits are NOT_PRESENT covers
+ * two cases: cards that genuinely lack sensors, and firmware
+ * errors that left the page zero-filled (the accessor mirrors
+ * _config_request() behaviour). Either way: skip registration.
+ */
+ if (!h->ioc_present && !h->board_present) {
+ kfree(h);
+ return 0;
+ }
+
+ hwdev = hwmon_device_register_with_info(parent, "mpt3sas", h,
+ &mpt3sas_hwmon_chip_info,
+ NULL);
+ if (IS_ERR(hwdev)) {
+ kfree(h);
+ return PTR_ERR(hwdev);
+ }
+
+ h->hwmon_dev = hwdev;
+ ioc->hwmon = h;
+ return 0;
+}
+
+/**
+ * mpt3sas_hwmon_unregister - tear down the hwmon device, if any
+ * @ioc: per adapter object
+ *
+ * Safe to call when registration was skipped (no sensors) or
+ * failed; in those cases ioc->hwmon is NULL and this is a no-op.
+ */
+void
+mpt3sas_hwmon_unregister(struct MPT3SAS_ADAPTER *ioc)
+{
+ struct mpt3sas_hwmon *h = ioc->hwmon;
+
+ if (!h)
+ return;
+ hwmon_device_unregister(h->hwmon_dev);
+ kfree(h);
+ ioc->hwmon = NULL;
+}
diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
index 12caffeed3a0..dea78688cc9b 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
@@ -12562,6 +12562,7 @@ static void scsih_remove(struct pci_dev *pdev)
/* release all the volumes */
_scsih_ir_shutdown(ioc);
mpt3sas_destroy_debugfs(ioc);
+ mpt3sas_hwmon_unregister(ioc);
sas_remove_host(shost);
list_for_each_entry_safe(raid_device, next, &ioc->raid_device_list,
list) {
@@ -13651,6 +13652,11 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
}
scsi_scan_host(shost);
+
+ if (mpt3sas_hwmon_register(ioc))
+ ioc_warn(ioc,
+ "hwmon registration failed; temperatures not exposed\n");
+
mpt3sas_setup_debugfs(ioc);
return 0;
out_add_shost_fail:
--
2.54.0
next prev parent reply other threads:[~2026-05-12 21:47 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-12 21:47 [PATCH 0/2] scsi: mpt3sas: add hwmon support Louis Sautier
2026-05-12 21:47 ` [PATCH 1/2] scsi: mpt3sas: add IO Unit Page 7 config accessor Louis Sautier
2026-05-12 21:47 ` Louis Sautier [this message]
2026-05-13 3:57 ` [PATCH 2/2] scsi: mpt3sas: add hwmon support Guenter Roeck
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260512214703.655633-3-sautier.louis@gmail.com \
--to=sautier.louis@gmail.com \
--cc=James.Bottomley@HansenPartnership.com \
--cc=MPT-FusionLinux.pdl@broadcom.com \
--cc=corbet@lwn.net \
--cc=linux-doc@vger.kernel.org \
--cc=linux-hwmon@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-scsi@vger.kernel.org \
--cc=linux@roeck-us.net \
--cc=martin.petersen@oracle.com \
--cc=ranjan.kumar@broadcom.com \
--cc=sathya.prakash@broadcom.com \
--cc=skhan@linuxfoundation.org \
--cc=sreekanth.reddy@broadcom.com \
--cc=suganath-prabu.subramani@broadcom.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox