電源供應器 FRU EEPROM 解析:MultiRecord、Power Supply Information 與 DC Output
CRPS / RPS 電源的 IPMI FRU EEPROM 怎麼看?逐位元組解析 MultiRecord Area 的記錄標頭、Power Supply Information(00h)與 DC Output(01h)記錄:額定功率、輸入電壓範圍、Hold-up、輸出電壓與電流,附單位換算陷阱、65 A 電流上限問題與 Python 解析程式。
最後更新:
還不熟悉 FRU 基本結構(Common Header、×8 偏移、Type/Length、Checksum)的話,建議先看 IPMI FRU 資料格式完整解析。
電源 FRU EEPROM 的位置與內容
CRPS 這類冗餘電源,常見的設計是 PMBus 控制器和 FRU EEPROM 掛在同一條 SMBus 上。BMC 透過同一條匯流排,既能用 PMBus 讀即時量測,也能讀 FRU 取得型號與規格。
FRU EEPROM 的位址,規格書上通常寫成 A0h、A2h、A4h、A6h,依電源插槽位置決定。這是 8 位元寫入位址的寫法,在 Linux 等使用 7 位元位址的工具中,要換成 0x50、0x51、0x52、0x53:
| 規格書(8 位元) | Linux / i2c-tools(7 位元) |
|---|---|
A0h | 0x50 |
A2h | 0x51 |
A4h | 0x52 |
A6h | 0x53 |
7 位元與 8 位元位址的差別,詳見 PMBus 常見問題除錯。實際位址、EEPROM 容量與寫入保護方式,請以電源的產品規格書為準。
| 區域 | 電源 FRU 中的用途 |
|---|---|
| Board Info Area | 電源模組的製造商、型號、序號、料號、製造日期 |
| Product Info Area | 產品名稱、版本、序號 |
| MultiRecord Area | 電源規格:額定功率、輸入範圍、每一路輸出的電壓與電流 |
範例資料
以下是一顆 800 W 電源的 FRU 資料(169 Bytes),重點放在 68h 開始的 MultiRecord Area:
0000: 01 00 00 01 07 0D 00 EA 01 06 00 F0 71 F7 C4 41 ← Common Header + Board Area
… (Board / Product Info Area 省略)
0060: 30 31 C0 C0 C1 00 00 06 00 02 18 D1 15 20 03 E8
0070: 03 28 0A 28 23 20 67 00 00 00 00 2F 3F 0A 0E 84
0080: 13 00 00 00 00 01 02 0D 62 8E 01 C4 04 3C 00 3C
0090: 00 78 00 00 00 E8 FD 01 82 0D 0D 63 82 B0 04 3C
00A0: 00 3C 00 78 00 00 00 C4 09
Common Header 的第 5 個 Byte 是 0Dh,所以 MultiRecord Area 從 0Dh × 8 = 68h 開始。
MultiRecord Area 的結構
MultiRecord Area 是一串記錄,每筆記錄 = 5 Bytes 標頭 + 資料,一筆接一筆,直到標頭中的 End of List 位元為 1。
範例中的三筆記錄:
| 位置 | 標頭 | Type | Byte 1 | 長度 | 意義 |
|---|---|---|---|---|---|
68h | 00 02 18 D1 15 | 00h | 02h | 24 | Power Supply Information,還有下一筆 |
85h | 01 02 0D 62 8E | 01h | 02h | 13 | DC Output,還有下一筆 |
97h | 01 82 0D 0D 63 | 01h | 82h | 13 | DC Output,最後一筆(b7 = 1) |
下一筆記錄的位置 = 目前位置 + 5 + 資料長度:68h + 5 + 24 = 85h、85h + 5 + 13 = 97h。
常見的 Record Type:
| Type | 名稱 | 電源 FRU 是否常用 |
|---|---|---|
00h | Power Supply Information | ✅ 幾乎必備 |
01h | DC Output | ✅ 每一路輸出一筆 |
02h | DC Load | 用電端(例如主機板)描述需求時使用 |
03h | Management Access | 管理介面資訊 |
04h / 05h | Base / Extended Compatibility | 相容性資訊 |
C0h ~ FFh | OEM | 廠商自訂 |
Power Supply Information(Record Type 00h)
固定 24 Bytes,所有多位元組欄位都是低位元組在前。
006D: 20 03 E8 03 28 0A 28 23 20 67 00 00 00 00 2F 3F 0A 0E 84 13 00 00 00 00
| Offset | 長度 | 欄位 | 範例 | 解讀 |
|---|---|---|---|---|
| 0 | 2 | Overall Capacity | 20 03 | 0320h = 800 W(b[11:0]) |
| 2 | 2 | Peak VA | E8 03 | 1000 VA(FFFFh = 未指定) |
| 4 | 1 | Inrush Current | 28 | 40 A(FFh = 未指定) |
| 5 | 1 | Inrush Interval | 0A | 10 ms |
| 6 | 2 | Input Voltage Range 1 Low | 28 23 | 2328h = 9000 → 90.00 V |
| 8 | 2 | Input Voltage Range 1 High | 20 67 | 6720h = 26400 → 264.00 V |
| 10 | 2 | Input Voltage Range 2 Low | 00 00 | 只有一個輸入範圍時填 0 |
| 12 | 2 | Input Voltage Range 2 High | 00 00 | 同上 |
| 14 | 1 | Input Frequency Low | 2F | 47 Hz |
| 15 | 1 | Input Frequency High | 3F | 63 Hz |
| 16 | 1 | A/C Dropout Tolerance | 0A | 10 ms:AC 中斷多久內輸出仍能維持 |
| 17 | 1 | Binary Flags | 0E | 見下表 |
| 18 | 2 | Peak Wattage | 84 13 | 1384h:b[15:12] = 1 秒、b[11:0] = 900 W |
| 20 | 1 | Combined Wattage 電壓 | 00 | b[7:4] 電壓 1、b[3:0] 電壓 2 |
| 21 | 2 | Combined Wattage | 00 00 | 0 = 未指定 |
| 23 | 1 | Predictive Fail Tach Threshold | 00 | 風扇轉速下限(RPS) |
Binary Flags(Offset 17)
| Bit | 意義 | 範例 0Eh |
|---|---|---|
| 0 | Predictive Fail 訊號支援 | 0 |
| 1 | Power Factor Correction(PFC) | 1 |
| 2 | Autoswitch(自動切換輸入電壓範圍) | 1 |
| 3 | Hot Swap 支援 | 1 |
| 4 | 搭配 Predictive Fail 使用的訊號形式設定 | 0 |
| 7:5 | 保留 | 0 |
Peak Wattage 與 Hold-up
Offset 18 的 2 Bytes 塞了兩個值:
代表電源可以輸出 900 W 的峰值功率,維持 1 秒。
Combined Wattage
有些電源的多路輸出共用功率預算(例如 12 V 和 5 V 合計不能超過某個值),就用這 3 Bytes 描述。電壓代碼:0 = +12 V、1 = −12 V、2 = +5 V、3 = +3.3 V。CRPS 這類以 12 V 為主的電源,通常填 0(未指定)。
DC Output(Record Type 01h)
每一路輸出一筆,固定 13 Bytes。範例有兩筆:主輸出 12 V 和待機輸出 12 VSB。
008A: 01 C4 04 3C 00 3C 00 78 00 00 00 E8 FD ← 第 1 路:主輸出
009C: 82 B0 04 3C 00 3C 00 78 00 00 00 C4 09 ← 第 2 路:待機輸出
| Offset | 長度 | 欄位 | 單位 | 主輸出 | 待機輸出 |
|---|---|---|---|---|---|
| 0 | 1 | Output Info | — | 01h:第 1 路 | 82h:b7 = 1 待機、第 2 路 |
| 1 | 2 | Nominal Voltage | 10 mV(有號數) | 04C4h = 12.20 V | 04B0h = 12.00 V |
| 3 | 2 | Max Negative Deviation | 10 mV | 0.60 V | 0.60 V |
| 5 | 2 | Max Positive Deviation | 10 mV | 0.60 V | 0.60 V |
| 7 | 2 | Ripple & Noise(pk-pk) | mV | 120 mV | 120 mV |
| 9 | 2 | Minimum Current Draw | mA | 0 A | 0 A |
| 11 | 2 | Maximum Current Draw | mA | FDE8h = 65.000 A | 09C4h = 2.500 A |
Output Info 的 b7 是待機輸出旗標,b[3:0] 是輸出編號。
大電流電源的限制:16 位元只能到 65 A
DC Output 的電流欄位是 16 位元、單位 mA,最大只能表示 65.535 A。一顆 1600 W 的 12 V 電源,主輸出電流超過 130 A,根本塞不進這個欄位。
| 額定功率(12 V 輸出) | 最大電流 | DC Output(01h)能否表示 |
|---|---|---|
| 500 W | 約 42 A | ✅ |
| 800 W | 約 66 A | ⚠️ 剛好在上限附近 |
| 1600 W | 約 133 A | ❌ |
| 3000 W | 約 250 A | ❌ |
實務上,大多數電源的 FRU 只使用 DC Output(01h)。規格中另外有兩種做法可以處理大電流,遇到時知道它們是什麼即可:
| 做法 | 說明 |
|---|---|
| Extended DC Output(09h) | FRU 規格 Rev 1.3 新增的記錄類型,結構和 DC Output 類似,目的就是支援更大的電流。ipmitool 等工具不一定都能解析 |
| OEM 記錄(C0h ~ FFh) | Record Type C0h 以上保留給廠商自訂,內容格式由廠商或客戶的規格定義,只有對方的工具看得懂 |
所以主輸出電流超過 65.535 A 時,該怎麼填,要以客戶或平台的 FRU 規格為準。拿到別家電源的 FRU 時,如果 DC Output 的電流看起來不合理,或看到 09h、C0h 以上的記錄,就是上面這兩種情況。
用 ipmitool 查看
在 BMC 上執行 ipmitool fru print,MultiRecord 會被解析成類似以下的內容(實際格式依 ipmitool 版本略有不同):
Capacity : 800 W
Peak VA : 1000 VA
Inrush Current : 40 A
Inrush Interval : 10 ms
Input Voltage Range 1 : 90-264 V
Input Voltage Range 2 : 0-0 V
Input Frequency Range : 47-63 Hz
A/C Dropout Tolerance : 10 ms
Flags : 'Power factor correction' 'Autoswitch voltage' 'Hot swap'
Peak capacity : 900 W
Peak capacity holdup : 1 s
Combined capacity : not specified
Output Number : 1
Standby power : No
Nominal voltage : 12.20 V
Max negative deviation : 0.60 V
Max positive deviation : 0.60 V
Ripple and noise pk-pk : 120 mV
Minimum current draw : 0.000 A
Maximum current draw : 65.000 A
用 Python 解析 MultiRecord
以下程式解析 MultiRecord Area,驗證每筆記錄的兩個 Checksum,並解碼 Power Supply Information 與 DC Output:
#!/usr/bin/env python3
"""psu_fru.py:解析電源 FRU 的 MultiRecord Area(Power Supply Information、DC Output)"""
import struct
import sys
RECORD_NAMES = {
0x00: "Power Supply Information", 0x01: "DC Output", 0x02: "DC Load",
0x03: "Management Access", 0x04: "Base Compatibility", 0x05: "Extended Compatibility",
}
FLAG_NAMES = ["Predictive Fail", "Power Factor Correction", "Autoswitch", "Hot Swap"]
COMBINED_V = {0: "+12V", 1: "-12V", 2: "+5V", 3: "+3.3V"}
def zero_sum(data):
return sum(data) & 0xFF == 0
def parse_multirecords(data):
"""從 Common Header 的 MultiRecord 位置開始,讀到 End of List 為止"""
offset = data[5] * 8
records = []
while offset:
header = data[offset:offset + 5]
if not zero_sum(header):
raise ValueError(f"記錄標頭 Checksum 錯誤(位置 {offset:#06x})")
rtype, fmt, length, record_cs, _ = header
body = data[offset + 5:offset + 5 + length]
if (sum(body) + record_cs) & 0xFF:
raise ValueError(f"記錄資料 Checksum 錯誤(位置 {offset:#06x})")
records.append((rtype, body))
offset = 0 if fmt & 0x80 else offset + 5 + length
return records
def decode_power_supply(b):
(cap, peak_va, inrush, inrush_ms, lo1, hi1, lo2, hi2, f_lo, f_hi,
dropout, flags, peak, comb_v, comb_w, rps) = struct.unpack("<HHBBHHHHBBBBHBHB", b[:24])
return {
"Overall Capacity": f"{cap & 0x0FFF} W",
"Peak VA": "未指定" if peak_va == 0xFFFF else f"{peak_va} VA",
"Inrush Current": "未指定" if inrush == 0xFF else f"{inrush} A",
"Inrush Interval": f"{inrush_ms} ms",
"Input Voltage Range 1": f"{lo1 / 100:.2f} ~ {hi1 / 100:.2f} V",
"Input Voltage Range 2": "無" if lo2 == hi2 == 0 else f"{lo2 / 100:.2f} ~ {hi2 / 100:.2f} V",
"Input Frequency": f"{f_lo} ~ {f_hi} Hz",
"A/C Dropout Tolerance": f"{dropout} ms",
"Flags": ", ".join(n for bit, n in enumerate(FLAG_NAMES) if flags >> bit & 1) or "無",
"Peak Wattage": f"{peak & 0x0FFF} W(維持 {peak >> 12} 秒)",
"Combined Wattage": "未指定" if comb_w == 0 else
f"{comb_w} W({COMBINED_V.get(comb_v >> 4, '?')} + {COMBINED_V.get(comb_v & 0x0F, '?')})",
}
def decode_dc_output(b):
info, nominal, neg, pos, ripple, i_min, i_max = struct.unpack("<BhhhHHH", b[:13])
return {
"Output Number": info & 0x0F,
"Standby": "Yes" if info & 0x80 else "No",
"Nominal Voltage": f"{nominal / 100:.2f} V",
"Max Negative Deviation": f"{neg / 100:.2f} V",
"Max Positive Deviation": f"{pos / 100:.2f} V",
"Ripple & Noise (pk-pk)": f"{ripple} mV",
"Current Draw": f"{i_min / 1000:.3f} ~ {i_max / 1000:.3f} A",
}
DECODERS = {0x00: decode_power_supply, 0x01: decode_dc_output}
if __name__ == "__main__":
with open(sys.argv[1], "rb") as f:
data = f.read()
for rtype, body in parse_multirecords(data):
print(f"[{RECORD_NAMES.get(rtype, 'OEM / 其他')} ({rtype:02X}h)]")
decoder = DECODERS.get(rtype)
if decoder is None:
print(" " + body.hex(" ").upper())
continue
for k, v in decoder(body).items():
print(f" {k:<24}: {v}")
執行結果:
$ python3 psu_fru.py psu_fru.bin
[Power Supply Information (00h)]
Overall Capacity : 800 W
Peak VA : 1000 VA
Inrush Current : 40 A
Inrush Interval : 10 ms
Input Voltage Range 1 : 90.00 ~ 264.00 V
Input Voltage Range 2 : 無
Input Frequency : 47 ~ 63 Hz
A/C Dropout Tolerance : 10 ms
Flags : Power Factor Correction, Autoswitch, Hot Swap
Peak Wattage : 900 W(維持 1 秒)
Combined Wattage : 未指定
[DC Output (01h)]
Output Number : 1
Standby : No
Nominal Voltage : 12.20 V
Max Negative Deviation : 0.60 V
Max Positive Deviation : 0.60 V
Ripple & Noise (pk-pk) : 120 mV
Current Draw : 0.000 ~ 65.000 A
[DC Output (01h)]
Output Number : 2
Standby : Yes
Nominal Voltage : 12.00 V
Max Negative Deviation : 0.60 V
Max Positive Deviation : 0.60 V
Ripple & Noise (pk-pk) : 120 mV
Current Draw : 0.000 ~ 2.500 A
Board / Product Info Area 可以用上一篇的 fru_decode.py 解析,兩支程式讀同一個檔案即可。
新手常見錯誤
| 錯誤 | 正確觀念 |
|---|---|
| 把 Record Length 乘 8 | MultiRecord 的長度是實際 Byte 數,和 Info Area 不同 |
| 只驗證一個 Checksum | 每筆記錄有標頭和資料兩個 Checksum |
| 讀到 End of List 後繼續往下讀 | Byte 1 的 b7 = 1 就是最後一筆 |
把 2328h 讀成 9000 V | 輸入電壓與輸出電壓的單位是 10 mV,要除以 100 |
| 把電流單位當成 A 或 10 mA | DC Output 的電流單位是 mA,最大 65.535 A |
| 把 Peak Wattage 整個當成功率 | 高 4 位元是 Hold-up 秒數,低 12 位元才是瓦數 |
| 用大端序讀多位元組欄位 | FRU 的多位元組欄位一律低位元組在前 |
| 修改 FRU 後沒有更新兩個 Checksum | ipmitool 會回報錯誤或略過該筆記錄 |
結論
- 電源 FRU 的規格資料放在 MultiRecord Area,位置記在 Common Header 的第 5 Byte(×8)。
- 每筆記錄 = 5 Bytes 標頭 + 資料;標頭 Byte 1 的 b7 標示最後一筆,兩個 Checksum 都要驗證。
- Power Supply Information(00h):24 Bytes,記錄額定功率、輸入範圍(10 mV)、Hold-up 等。
- DC Output(01h):每一路一筆,13 Bytes,電壓 10 mV、電流 mA(上限 65.535 A)。
- 多數電源只用 DC Output;主輸出超過 65.535 A 時,依客戶或平台的 FRU 規格處理(Extended DC Output
09h或 OEM 記錄)。
延伸閱讀: