The sensors answer on the host's own bus, and the bus had been there all along¶
Measured on an XGS 3300, 2026-10-13, OPNsense 26.7.5, for
issue 164. The appliance's temperatures,
fan speeds and flags are a register bank on its CPLD, behind an 8-bit SMBus face at slave 0x60.
Where that face was wired had been looked for since 2026-10-02: not the coprocessor's two I2C
buses, not the CPLD's SPI face, and on the host every face that FreeBSD could drive came back empty
- the main controller's four multiplexed ports on 2026-10-12, and this morning the FCH's auxiliary
controller, found at
0x0b20by i2c-piix4's own arithmetic, running transactions onto a bus with nothing on it.
What was in the way¶
FreeBSD's intsmb(4) and smbmsg(8) were the instrument, and the instrument was wrong for this
FCH. Every data protocol through them answered ENXIO, and a receive-byte answered 0x02 from
every address - which reads as an undriven bus and was recorded as one. The same controller - the
main one, at 0x0b00, the port the firmware leaves selected - driven directly through its
PIIX4-style register block over /dev/io acknowledges 0x60 alone (0x61, 0x66, 0x08,
0x20, 0x40: no device) and answers read-byte-data register by register. That is the exact
transaction the vendor's own library makes through /dev/i2c-0 (I2C_SMBUS_READ, BYTE_DATA),
and nothing else: no GPIO gate is set for this device - the library's gate is the SFP EEPROMs', not
the sensors'.
The bank¶
Two passes a few seconds apart, read-byte-data at 0x60, registers 0x00 to 0x3c:
05 00 08 02 b0 55 aa 00 36 45 05 1c 00 16 16 00 00 00 00 01 00 00 02 02 02 ... 02
05 00 08 02 b0 55 aa 00 32 45 05 1c 00 17 17 00 00 00 00 01 00 00 02 02 02 ... 02
| register | what | read |
|---|---|---|
0x00-0x02 |
the CPLD version's bytes, 0x05000008 on the SPI face |
05 00 08 |
0x03-0x04 |
the block id, 0xb002 |
02 b0 |
0x05-0x06 |
a fixed pair, as the SPI face has at 0x02/0x03 |
55 aa |
0x07 lo, 0x08 hi |
CPU temperature, hi + lo / 8 | 54.0 C, 50.0 C; 43.0 C a minute earlier |
0x09 hi, 0x0a lo |
NPU temperature | 69.625 C |
0x0b hi, 0x0c lo |
inlet temperature | 28.0 C |
0x0d, 0x0e |
fan 0, fan 1, in units of 300 rpm | 6,600 and 6,900 rpm |
0x14 |
fan 0 under-speed flag | clear |
0x16 |
the minimum fan speed | 600 rpm |
0x17 and up |
not there: 0x02 from every one, this face's 0xfeedbeef |
The arithmetic is the vendor's (hi + lo * 0.125, byte * 300), and the numbers are the ones its
own tool printed under its firmware on 2026-10-02 - 45, 64, 26 and 6900 - a day's drift apart.
What it gives¶
A reader that runs on OPNsense: tools/sensors/xgs3300-sensors.c,
built with cc on the appliance, prints the decoded readings, the raw bank, or one register. The
host's own die sensor, amdtemp, reads beside it. What this is not: a kernel path. That would be
intsmb(4) made to pass byte-data on this FCH, which is a FreeBSD driver question and not this
board's, and until then the port select (PMIO 0x02) is left as found and the tool and the driver
share the controller without a lock - one reading at a time, by hand or from a cron entry, is the
honest use.
Lessons¶
- A bus is not empty until it has been driven by two instruments. One driver's
ENXIOwas taken for the hardware's answer for a day; the controller's own registers said otherwise in an hour. - Read the vendor's library before deriving a protocol. The transaction, the slave, the
arithmetic and the absence of a gate were all in
xgs_1us_sensors.candxgs_eeprom.c.
The discussion of this page is held in the project's GitHub Discussions. Showing it here loads giscus from giscus.app and GitHub, and writing in it needs a GitHub account - what that means.