June 22, 20242 yr Hi All. Can I please request LSI controller card temperature monitoring be considered for a future release so we can monitor this from the dashboard. Some of the LSI series get very hot and would be a benefit to have this displayed and monitored if possible. Might need storcli64 to be included to allow for this to work (in my case anyways having an LSI9305). root@Tower:/bin# ./storcli64 /c0 show temperature CLI Version = 007.2707.0000.0000 Dec 18, 2023 Operating system = Linux 6.1.79-Unraid Controller = 0 Status = Success Description = None Controller Properties : ===================== -------------------------------------- Ctrl_Prop Value -------------------------------------- ROC temperature(Degree Celsius) 48 -------------------------------------- Thanks, Hal
June 23, 20242 yr 7 hours ago, hallamnet said: Hi All. Can I please request LSI controller card temperature monitoring be considered for a future release so we can monitor this from the dashboard. Some of the LSI series get very hot and would be a benefit to have this displayed and monitored if possible. Might need storcli64 to be included to allow for this to work (in my case anyways having an LSI9305). root@Tower:/bin# ./storcli64 /c0 show temperature CLI Version = 007.2707.0000.0000 Dec 18, 2023 Operating system = Linux 6.1.79-Unraid Controller = 0 Status = Success Description = None Controller Properties : ===================== -------------------------------------- Ctrl_Prop Value -------------------------------------- ROC temperature(Degree Celsius) 48 -------------------------------------- Thanks, Hal Does it show if you run sensors on cmdline?
July 5, 20242 yr Author Thanks very much for the reply and sorry for the delay. I have checked with running the command sensors and this does not show my LSI 9305 HBA. This is what is shown though. Any idea if this can be incorporated in to a future build or if I can get this on the home screen with a plugin? root@HAL-UNRAID:~# sensors coretemp-isa-0000 Adapter: ISA adapter CPU Temp: +40.0°C (high = +80.0°C, crit = +100.0°C) Core 0: +32.0°C (high = +80.0°C, crit = +100.0°C) Core 4: +40.0°C (high = +80.0°C, crit = +100.0°C) Core 8: +30.0°C (high = +80.0°C, crit = +100.0°C) Core 12: +33.0°C (high = +80.0°C, crit = +100.0°C) Core 16: +31.0°C (high = +80.0°C, crit = +100.0°C) Core 20: +31.0°C (high = +80.0°C, crit = +100.0°C) Core 24: +31.0°C (high = +80.0°C, crit = +100.0°C) Core 28: +29.0°C (high = +80.0°C, crit = +100.0°C) Core 32: +34.0°C (high = +80.0°C, crit = +100.0°C) Core 33: +34.0°C (high = +80.0°C, crit = +100.0°C) Core 34: +34.0°C (high = +80.0°C, crit = +100.0°C) Core 35: +34.0°C (high = +80.0°C, crit = +100.0°C) Core 36: +34.0°C (high = +80.0°C, crit = +100.0°C) Core 37: +34.0°C (high = +80.0°C, crit = +100.0°C) Core 38: +34.0°C (high = +80.0°C, crit = +100.0°C) Core 39: +34.0°C (high = +80.0°C, crit = +100.0°C) nvme-pci-0100 Adapter: PCI adapter Composite: +36.9°C (low = -273.1°C, high = +83.8°C) (crit = +84.8°C) Sensor 1: +36.9°C (low = -273.1°C, high = +65261.8°C) Sensor 2: +37.9°C (low = -273.1°C, high = +65261.8°C) acpitz-acpi-0 Adapter: ACPI interface MB Temp: +27.8°C (crit = +105.0°C) nct6798-isa-0290 Adapter: ISA adapter in0: 840.00 mV (min = +0.00 V, max = +1.74 V) in1: 992.00 mV (min = +0.00 V, max = +0.00 V) ALARM in2: 3.39 V (min = +0.00 V, max = +0.00 V) ALARM in3: 3.33 V (min = +0.00 V, max = +0.00 V) ALARM in4: 1000.00 mV (min = +0.00 V, max = +0.00 V) ALARM in5: 1.02 V (min = +0.00 V, max = +0.00 V) ALARM in6: 0.00 V (min = +0.00 V, max = +0.00 V) in7: 3.39 V (min = +0.00 V, max = +0.00 V) ALARM in8: 3.15 V (min = +0.00 V, max = +0.00 V) ALARM in9: 520.00 mV (min = +0.00 V, max = +0.00 V) ALARM in10: 584.00 mV (min = +0.00 V, max = +0.00 V) ALARM in11: 544.00 mV (min = +0.00 V, max = +0.00 V) ALARM in12: 1.05 V (min = +0.00 V, max = +0.00 V) ALARM in13: 568.00 mV (min = +0.00 V, max = +0.00 V) ALARM in14: 888.00 mV (min = +0.00 V, max = +0.00 V) ALARM fan1: 631 RPM (min = 0 RPM) fan2: 695 RPM (min = 0 RPM) fan3: 704 RPM (min = 0 RPM) Array Fan: 704 RPM (min = 0 RPM) SYSTIN: +29.0°C (high = +80.0°C, hyst = +75.0°C) sensor = thermistor CPUTIN: +33.5°C (high = +80.0°C, hyst = +75.0°C) sensor = thermistor AUXTIN0: +127.5°C sensor = thermistor AUXTIN1: +17.0°C sensor = thermistor AUXTIN2: +73.0°C sensor = thermistor AUXTIN3: +32.0°C sensor = thermistor PECI Agent 0 Calibration: +32.0°C PCH_CHIP_TEMP: +69.0°C intrusion0: ALARM intrusion1: ALARM beep_enable: disabled nvme-pci-0400 Adapter: PCI adapter Composite: +27.9°C (low = -273.1°C, high = +74.8°C) (crit = +84.8°C) Sensor 1: +52.9°C (low = -273.1°C, high = +65261.8°C) Sensor 2: +51.9°C (low = -273.1°C, high = +65261.8°C) ERROR: Can't get value of subfeature temp4_min: I/O error ERROR: Can't get value of subfeature temp4_max: I/O error Sensor 3: +27.9°C (low = +0.0°C, high = +0.0°C) nvme-pci-0200 Adapter: PCI adapter Composite: +26.9°C (low = -0.1°C, high = +82.8°C) (crit = +89.8°C)
July 6, 20242 yr It's Broadcom proprietary software that's not allowed to be re-distributed under their EULA. So I personally don't see any possibility of this making it into a plugin or the base OS in the future.
May 6May 6 Hello,If it helps porting to a plugin or the base OS, the following script reads controller temperatures directly via ioctl without needing lsiutil or storcli. It talks to the device node created by the mpt3sas kernel module. I could only test with mpt3sas (9305-16i) as I don't have hardware using the older mpt/mpt2 drivers.Created with the help of generative AI, use at your own risk!#!/usr/bin/env python3 """Read LSI SAS IOC temperature directly via ioctl (no lsiutil needed).""" import ctypes import fcntl import os import struct import sys # MPI constants MPI_FUNCTION_CONFIG = 0x04 MPI_CONFIG_ACTION_PAGE_HEADER = 0x00 MPI_CONFIG_ACTION_PAGE_READ_CURRENT = 0x01 MPI_CONFIG_PAGETYPE_IO_UNIT = 0x00 IO_UNIT_PAGE_NUMBER = 7 # Temperature unit constants TEMP_NOT_PRESENT = 0x00 TEMP_FAHRENHEIT = 0x01 TEMP_CELSIUS = 0x02 # ioctl numbers: _IOC(_IOC_READ|_IOC_WRITE, magic, nr, size) # mptctl uses magic 'm' (0x6D), mpt2/3 use 'L' (0x4C), both nr=20 # sizeof(struct mpt_ioctl_command) = 72 on 64-bit (same for mpt2/mpt3 variants) STRUCT_SIZE = 72 DEVICES = [ ("/dev/mpt3ctl", ord("L"), 20), ("/dev/mpt2ctl", ord("L"), 20), ("/dev/mptctl", ord("m"), 20), ] def _ioctl_number(magic, nr): """Compute ioctl request number: _IOWR(magic, nr, struct_size).""" # _IOC(direction=3, type, nr, size) on Linux: # direction bits [31:30], size [29:16], type [15:8], nr [7:0] return (3 << 30) | (STRUCT_SIZE << 16) | (magic << 8) | nr def _build_config_msg(action, page_length=0, page_number=IO_UNIT_PAGE_NUMBER, page_type=MPI_CONFIG_PAGETYPE_IO_UNIT): """Build a Config request message (28 bytes, no SGE).""" # Config_t layout (28 bytes): # Action(1) AliasIndex(1) ChainOffset(1) Function(1) # ExtPageLength(2) ExtPageType(1) MsgFlags(1) # MsgContext(4) # Reserved2(8) # Header: PageVersion(1) PageLength(1) PageNumber(1) PageType(1) # PageAddress(4) msg = struct.pack( "<BBBB HBB I 8s BBBB I", action, # Action 0, # AliasIndex 0, # ChainOffset MPI_FUNCTION_CONFIG, # Function 0, # ExtPageLength 0, # ExtPageType 0, # MsgFlags 0, # MsgContext b"\x00" * 8, # Reserved2 0, # Header.PageVersion page_length, # Header.PageLength (in dwords) page_number, # Header.PageNumber page_type, # Header.PageType 0, # PageAddress ) return msg def _do_config_ioctl(fd, ioctl_nr, iocnum, action, page_length=0, data_in_size=0): """Issue an MPTCOMMAND config ioctl. Returns (reply_bytes, data_in_bytes).""" mf = _build_config_msg(action, page_length=page_length) reply_buf = ctypes.create_string_buffer(128) data_in_buf = ctypes.create_string_buffer(data_in_size) if data_in_size else None # Build mpt_ioctl_command struct (manual packing for 64-bit): # hdr.iocnum(4) hdr.port(4) hdr.maxDataSize(4) timeout(4) # replyFrameBufPtr(8) dataInBufPtr(8) dataOutBufPtr(8) senseDataPtr(8) # maxReplyBytes(4) dataInSize(4) dataOutSize(4) maxSenseBytes(4) # dataSgeOffset(4) mf[28] data_in_ptr = ctypes.addressof(data_in_buf) if data_in_buf else 0 cmd = struct.pack( "<IIII QQQQ IIIII", iocnum, # hdr.iocnum 0, # hdr.port 0, # hdr.maxDataSize 10, # timeout (seconds) ctypes.addressof(reply_buf), # replyFrameBufPtr data_in_ptr, # dataInBufPtr 0, # dataOutBufPtr (NULL - no writes!) 0, # senseDataPtr 128, # maxReplyBytes data_in_size, # dataInSize 0, # dataOutSize (0 - no writes!) 0, # maxSenseBytes 7, # dataSgeOffset (dwords into mf where SGE goes) ) cmd += mf cmd_buf = ctypes.create_string_buffer(cmd, len(cmd)) try: fcntl.ioctl(fd, ioctl_nr, cmd_buf) except OSError as e: return None, None reply_bytes = bytes(reply_buf) data_in_bytes = bytes(data_in_buf) if data_in_buf else b"" return reply_bytes, data_in_bytes def read_ioc_temperature(fd, ioctl_nr, iocnum): """Read IO Unit Page 7 and return temperature in Celsius, or None.""" # Step 1: Get page header to learn page length reply, _ = _do_config_ioctl(fd, ioctl_nr, iocnum, MPI_CONFIG_ACTION_PAGE_HEADER) if reply is None: return None # ConfigReply: IOCStatus at offset 0x0E, Header at offset 0x14 ioc_status = struct.unpack_from("<H", reply, 0x0E)[0] & 0x7FFF if ioc_status != 0: return None # Header: PageVersion(1) PageLength(1) PageNumber(1) PageType(1) page_length = reply[0x15] # in 32-bit dwords if page_length == 0: return None # Step 2: Read the actual page data data_in_size = page_length * 4 reply, data = _do_config_ioctl( fd, ioctl_nr, iocnum, MPI_CONFIG_ACTION_PAGE_READ_CURRENT, page_length=page_length, data_in_size=data_in_size, ) if reply is None or data is None: return None ioc_status = struct.unpack_from("<H", reply, 0x0E)[0] & 0x7FFF if ioc_status != 0: return None # IO Unit Page 7: IOCTemperature at offset 0x10 (U16), IOCTemperatureUnits at 0x12 (U8) if len(data) < 0x13: return None raw_temp = struct.unpack_from("<H", data, 0x10)[0] units = data[0x12] if units == TEMP_NOT_PRESENT: return None elif units == TEMP_FAHRENHEIT: celsius = (raw_temp - 32) * 5 // 9 elif units == TEMP_CELSIUS: celsius = raw_temp else: celsius = raw_temp # unknown units, return raw return celsius def main(): if os.geteuid() != 0: print("Error: must run as root", file=sys.stderr) sys.exit(1) found_any = False for dev_path, magic, nr in DEVICES: if not os.path.exists(dev_path): continue ioctl_nr = _ioctl_number(magic, nr) try: fd = os.open(dev_path, os.O_RDWR) except OSError: continue for iocnum in range(16): temp = read_ioc_temperature(fd, ioctl_nr, iocnum) if temp is not None: print(f"ioc{iocnum}: {temp}C") found_any = True os.close(fd) if not found_any: print("No LSI IOC temperature sensors found", file=sys.stderr) sys.exit(1) if __name__ == "__main__": main()
May 31May 31 Hi @salsify , I wanted to say that your above script worked great for me on my 9207-8i (mpt2sas). I used un-get to install python3 and the script worked just like that. My card is apparently running at a very toasty 84 C so I think it's time I get a fan for it. 🥲
May 31May 31 Thanks for the feedback @blucobalt!I set up a 92 mm fan below mine with https://makerworld.com/en/models/393956-single-92mm-fan-pcie-mount#profileId-295072It's not perfectly aligned with the LSI's heatsink but it helped the temperature go from ~ 90 °C to ~ 50 °C.
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.