board
OCuLink Riser for the Supermicro AIOM Slot
Public Unreviewedby John Lauer
Passive OCP NIC 3.0 SFF card that breaks a Supermicro AIOM slot's PCIe x16 into four OCuLink 4i ports (4 x4, Gen4): 6-layer, 85 ohm, length-matched, DRC-clean KiCad project with Gerbers, BOM and CPL.
← Commit history
design/gen/fru.pydeleted−103@@ -1,103 +0,0 @@-#!/usr/bin/env python3-"""FRU EEPROM image for the riser (OCP NIC 3.0 v1.6.0 section 5.10, IPMI Platform Management FRU Information-Storage Definition v1.0): common header, board info area, product info area, multirecord area with the OCP-Base OEM record 0xC0 (Table 66). Writes design/fru.bin (8 KiB, 0xFF padded) and design/fru.txt."""-import os, struct--ROOT = os.path.join(os.path.dirname(__file__), "..")---def tl(s):- b = s.encode("ascii")- assert len(b) < 64- return bytes([0xC0 | len(b)]) + b---def area(body):- body = bytes(body) + b"\xC1"- n = len(body) + 1- pad = (-n) % 8- body += b"\x00" * pad- body = bytes([body[0], (len(body) + 1) // 8]) + body[2:] if False else body- return body---def finish(fixed_head, fields):- raw = bytearray(fixed_head) + b"".join(fields) + b"\xC1"- while (len(raw) + 1) % 8:- raw += b"\x00"- raw[1] = (len(raw) + 1) // 8 # area length in multiples of 8- raw += bytes([(-sum(raw)) & 0xFF])- return bytes(raw)---def build():- MFG = "Adom (open hardware)"- NAME = "OCP3 SFF to 4x OCuLink x4"- PN = "OCP3-OCULINK4-A"- SER = "0000000001"- # board info: version 1, length (patched), language 0 (English), mfg time = minutes since 1996-01-01- import datetime- mins = int((datetime.datetime(2026, 10, 12) - datetime.datetime(1996, 1, 1)).total_seconds() // 60)- board = finish(bytes([1, 0, 0]) + struct.pack("<I", mins)[:3],- [tl(MFG), tl(NAME), tl(SER), tl(PN), tl("fru-v1")])- product = finish(bytes([1, 0, 0]),- [tl(MFG), tl(NAME), tl(PN), tl("A"), tl(SER), tl(""), tl("fru-v1")])- # OCP Base OEM record 0xC0, OEM record version 0x06 (spec 1.6.0)- rec = bytes([- 0x7F, 0xA6, 0x00, # OCP IANA 42623, LSB first- 0x06, # record version: 1.6.0- 0x01, 0x01, # max power main / aux: under 1 W (logic + two LEDs), rounded up- 0x01, 0x01, # hot / cold aisle cooling tier with passive cables: tier 1- 0x00, # passive cooling (no fan)- 0x00, 0x00, # hot aisle airflow with active cables: passive cables only- 0x00, 0x00, # cold aisle airflow with active cables: passive cables only- 0x00, 0x00, # UART config 1/2 (SFF: 0x00)- 0x00, # no USB on the card edge- 0x00, # manageability: none- 0x04, # FRU write protection: mechanical jumper (JP1)- 0x00, # programming mode not supported- 0x00, 0x00, # active-cable tiers: passive cables only- 0x00, 0x00, # transceiver reference power / temperature: passive cable- 0x00, # thermal tier with fan fail: same (no fan)- 0x00, # aux power supported ports: none (passive riser)- 0x00, 0x00, # hot aisle standby airflow, passive cables- 0x00, 0x00, # cold aisle standby airflow, passive cables- 0x00, # maximum supported transceiver power- 0xFF, # reserved- 0x00, # number of physical (SMBus) controllers N = 0: last byte- ])- assert len(rec) == 32- hdr = bytes([0xC0, 0x82, len(rec), (-sum(rec)) & 0xFF]) # type 0xC0, format 2 | end of list- hdr += bytes([(-sum(hdr)) & 0xFF])- multi = hdr + rec- # common header: offsets in 8-byte units- off_board = 1- off_product = off_board + len(board) // 8- off_multi = off_product + len(product) // 8- common = bytes([1, 0, 0, off_board, off_product, off_multi, 0])- common += bytes([(-sum(common)) & 0xFF])- img = common + board + product + multi- img += b"\xFF" * (8192 - len(img))- return img, dict(board=board, product=product, multi=multi, common=common)---if __name__ == "__main__":- img, parts = build()- open(os.path.join(ROOT, "design", "fru.bin"), "wb").write(img)- used = sum(len(v) for v in parts.values())- with open(os.path.join(ROOT, "design", "fru.txt"), "w") as fh:- fh.write("FRU EEPROM image for the OCP NIC 3.0 SFF to 4x OCuLink riser (BR24H64, 8 KiB, 2-byte addressing)\n")- fh.write(f"used {used} bytes; common header {parts['common'].hex(' ')}\n")- fh.write(f"board area {len(parts['board'])} B, product area {len(parts['product'])} B, multirecord {len(parts['multi'])} B\n")- fh.write("OCP Base OEM record 0xC0: " + parts["multi"][5:].hex(" ") + "\n")- fh.write("Program (JP1 bridged, card in the slot, Linux host): i2ctransfer with 2-byte addressing at 0x50 + SLOT_ID,\n"- "or ipmitool fru write <id> fru.bin from the BMC. Remove JP1 afterwards to write-protect.\n")- print(f"fru.bin {len(img)} bytes, {used} used")- # self-check: every area checksum sums to zero- for k, v in parts.items():- if k == "multi": # multirecord: 5-byte header sums to zero; data sums to zero with the header's record checksum- ok = sum(v[:5]) % 256 == 0 and (sum(v[5:]) + v[3]) % 256 == 0- else:- ok = sum(v) % 256 == 0- print(k, "checksum ok" if ok else "BAD", len(v))