SANBlaze I3C Controller Platform

Version 1530 User Guide

Release Date: April 2026


Table of Contents

  1. Introduction

  2. Installation

  3. Quick Start

  4. Linux i2c-tools Interface

  5. IBI Behavior

  6. MCTP Operations

  7. Private Transfers

  8. Burst Write System

  9. Ring Buffer Integration

  10. Diagnostics

  11. Command Reference

  12. Test Suite

  13. Troubleshooting

  14. Support


1. Introduction

V1530 fixes a critical SMBus multi-chunk read bug where mi commands requesting more than 56 bytes via the SMBus path returned the first 56 bytes repeated to fill the requested length. VPD Read (256 bytes) now returns complete, correct data via both I3C and SMBus paths. This release also includes a coordinated update to the SANBlaze i2c-tiny-usb kernel module required to support the fix. All V1529 features and fixes are preserved and unchanged.


2. Installation

Package Contents

The release package i3c_v1530_release.gz contains firmware, tools, and documentation. Extract with the -P flag to install system binaries:

mkdir /tmp/sb_i3c
cp i3c_v1530_release.gz /tmp/sb_i3c
cd /tmp/sb_i3c
tar -xzvPf i3c_v1530_release.gz

Key package contents:

Path

Description

sb_i3c

Host CLI tool

sanblaze_firmware.uf2

Firmware image (UF2 format)

tools/sb_i3c_bind

Bind device to i2c-tiny-usb driver

tools/sb_i3c_unbind

Unbind device from driver

tools/sb_i3c_find

Find device by slot

tools/sb_i3c_find_all

List all I3C devices

tools/sb_i3c_update

Firmware update utility

tools/sb_i3c_test

Automated test suite

After extraction, all tools are installed system-wide and available without a path prefix.

Firmware Update

sb_i3c_update -d <slot> /etc/iRiser/sanblaze_i3c_fw_v1530.uf2

The device reboots automatically. Wait 3 seconds before issuing commands.

Verify the update:

sb_i3c -d 2 status
# Expected output includes:
#   Version: 1530

Hardware Requirement: Bus Termination

V1529 requires correct bus termination on the drive side of the I2C mux. A missing jumper on the drive-side mux leaves the bus unterminated, causing pattern-sensitive ACK failures that are difficult to distinguish from firmware bugs. Symptom: intermittent SMBus errors on specific byte values that pass consistently on the FT260 path.

Verify the drive-side mux jumper is installed before diagnosing SMBus reliability issues.


3. Quick Start

Discover and Configure Drive

# Reset bus and discover drive at address 0x1D
sb_i3c -d 2 targetreset
sleep 0.5
sb_i3c -d 2 entdaa 0x1d

# Enable IBI events (required for MCTP)
sb_i3c -d 2 enec 0x1d

# Set maximum write and read length to 69 (required before MCTP traffic)
sb_i3c -d 2 setmwl 0x1d 69
sb_i3c -d 2 setmrl 0x1d 69

# Verify drive is present
sb_i3c -d 2 getpid 0x1d
# Expected: PID: 0x02 0x02 0x16 0x00 0x12 0x34

Quick MCTP Health Check

# Buffer the Identify Controller command (2 MCTP packets)
sb_i3c -d 2 private_write --hold 0x1d \
  0x01 0x00 0x00 0x8d 0x84 0x10 0x00 0x00 0x06 0x03 0x01 \
  0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 \
  0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 \
  0x00 0x00 0x00 0x00 0x00 0x10 0x00 0x00 0x00 0x00 0x00 \
  0x00 0x00 0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x00 0x00 \
  0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 \
  0x00 0x00 0xf2

sb_i3c -d 2 private_write --hold 0x1d \
  0x01 0x00 0x00 0x5d 0x00 0x00 0x00 0x00 0x04 0x4d 0x64 0x69 0x7d

# Fire command and read response
sb_i3c -d 2 mctp_command 0x1d
# Expected: MCTP_COMMAND: 4445 total response bytes
#           65 decoded packets with serial number, model, firmware revision

4. Linux i2c-tools Interface

The SANBlaze I3C device presents a standard i2c-tiny-usb interface to Linux, enabling use of standard i2c-tools (i2cdetect, i2cget, i2cset, i2ctransfer).

Finding Your Device

Use sb_i3c_find to discover the USB path, TTY, and I2C bus number for a slot:

sb_i3c_find -d 2
#   USB Path: 1-5.2.7.4
#   TTY:      /dev/ttyACM6
#   Version:  1530
#   I2C Dev:  /dev/i2c-15

Use sb_i3c_find_all to list all slots with I3C capability:

sb_i3c_find_all
# slot=2  usb=1-5.2.7.4  tty=/dev/ttyACM6  ver=1530  i2c=/dev/i2c-15

Driver Binding

If the i2c-tiny-usb driver is not automatically bound:

sb_i3c_bind -d 2      # Bind
sb_i3c_unbind -d 2    # Unbind

Common i2c-tools Commands

# Scan for devices on the TinyUSB I2C bus
i2cdetect -y 15

# Read a single byte from address 0x53
i2cget -y 15 0x53

# Write to address 0x71
i2cset -y 15 0x71 0x00

# Write-restart-read (required for devices that need an offset before reading)
i2ctransfer -y 15 w1@0x6a 0x00 r16

# Write multiple bytes
i2ctransfer -y 15 w4@0x24 0x01 0x02 0x03 0x04

Note: Devices that require a write-restart-read sequence will hold SDA low if a plain read is attempted without first writing the offset. Clear with: sb_i3c -d 2 i3c_poll


5. IBI Behavior

IBI (In-Band Interrupt) is the I3C mechanism by which a target device signals the controller that it needs attention. Understanding IBI behavior is important for reliable operation.

When IBI Is Asserted

I3C targets commonly assert IBI after:

  • Initial power-on

  • First CCC command after a power cycle

  • Completion of certain operations (device-specific)

When IBI is asserted, the target holds SDA low. This is normal device behavior. While IBI is pending, i2cdetect will show no devices — this does not indicate a firmware problem.

Polling and Clearing IBI

sb_i3c -d 2 i3c_poll

Example output when IBI is pending:

IBI: 0xFF 0xFF 0xFF 0xFF ...

Example output when bus is clear:

No IBI Bytes Found

Poll until “No IBI Bytes Found” before proceeding with bus operations. After clearing IBI, i2cdetect will show devices normally.

Quick Target Mode Verification

After firmware update, verify the local target is working:

sb_i3c -d 2 i3c_target_enable
sb_i3c -d 2 i3c_sdr_write 0x24 0xAA 0xBB 0xCC 0xDD
sb_i3c -d 2 i3c_data_read
# Expected: DATA(4): 0xAA 0xBB 0xCC 0xDD

6. MCTP Operations

Overview

MCTP (Management Component Transport Protocol) over I3C enables communication with drive management interfaces. The firmware supports three MCTP read paths with increasing levels of autonomy:

Path

Command

Use Case

Manual

private_write + i3c_poll + mctp_read

Step-by-step debugging

Autonomous

mctp_command

CLI-based testing and development

Ring buffer

mctp_to_ring

Customer application integration

Required before any MCTP traffic: After ENTDAA and ENEC, send SETMWL and SETMRL to establish the maximum transfer unit. Most I3C MCTP targets require this before accepting MCTP commands:

sb_i3c -d 2 setmwl 0x1d 69
sb_i3c -d 2 setmrl 0x1d 69

Multi-Packet MCTP over SMBus (V1529)

In I2C/SMBus mode, drives may return responses as multiple sequential SMBus frames, each addressed to the local target (0x24). V1529 firmware ACKs all packets and commits each complete frame to the ring buffer atomically. The mi tool reads packets one at a time, using the MCTP SOM/EOM flags to determine when the response is complete.

Commands returning large responses (VPD Read, Identify Controller) will produce multiple committed frames in sequence. The ring buffer reports 0 bytes until a complete frame is committed; mi polls and reads each frame individually.

Manual Path (Debugging)

For detailed visibility into each phase:

# 1. Send MCTP command packets
sb_i3c -d 2 private_write --hold 0x1d <pkt1_bytes>
sb_i3c -d 2 private_write 0x1d <pkt2_bytes>    # no --hold = fires burst

# 2. Poll for IBI (drive signals response ready)
sb_i3c -d 2 i3c_poll

# 3. Read all response packets
sb_i3c -d 2 mctp_read 0x1d
# Output: packet-by-packet hex dump with MCTP headers decoded

Autonomous Path (mctp_command)

Single command handles burst fire, IBI polling, and multi-packet read:

sb_i3c -d 2 private_write --hold 0x1d <pkt1_bytes>
sb_i3c -d 2 private_write --hold 0x1d <pkt2_bytes>
sb_i3c -d 2 mctp_command 0x1d

Ring Buffer Path (mctp_to_ring)

Routes the complete MCTP response into the target ring buffer for customer application integration:

sb_i3c -d 2 private_write --hold 0x1d <pkt1_bytes>
sb_i3c -d 2 private_write --hold 0x1d <pkt2_bytes>
sb_i3c -d 2 mctp_to_ring 0x1d

# Read via existing TARGET_CMD_DATA_READ path
sb_i3c -d 2 i3c_data_read

7. Private Transfers

I3C Private Transfers use a 0x7E broadcast + Repeated START preamble before the addressed transaction. Required for MCTP communication with most NVMe drives.

# Single private write
sb_i3c -d 2 private_write 0x1d 0x01 0x02 0x03 ...

# Buffered (held) private write for burst
sb_i3c -d 2 private_write --hold 0x1d 0x01 0x02 ...

# Private read
sb_i3c -d 2 private_read 0x1d 64

8. Burst Write System

The burst write system buffers multiple private_write --hold packets in firmware and transmits them back-to-back as a single burst when mctp_command or mctp_to_ring is called. This eliminates USB latency between packets and is required for multi-packet MCTP commands.

# Buffer packet 1 (69 bytes) — not sent yet
sb_i3c -d 2 private_write --hold 0x1d <pkt1_bytes>
# Output: PRIVATE_WRITE HELD: 69 bytes to 0x1D

# Buffer packet 2 (13 bytes) — not sent yet
sb_i3c -d 2 private_write --hold 0x1d <pkt2_bytes>
# Output: PRIVATE_WRITE HELD: 13 bytes to 0x1D

# Fire all buffered packets in one burst
sb_i3c -d 2 mctp_command 0x1d
# or
sb_i3c -d 2 mctp_to_ring 0x1d

The burst buffer holds up to 512 bytes across multiple packets. Each packet is sent as a complete I3C Private Write transaction with START and STOP.


9. Ring Buffer Integration

Customer Application Flow

The ring buffer path (mctp_to_ring) is designed for production use. Customer applications read MCTP data using the same TARGET_CMD_DATA_READ (0x52) USB command they already use for target-mode data. No application code changes needed.

Driver integration steps:

  1. Buffer MCTP packets via HOST_CMD_I3C_SDR_WRITE_CHUNK (0x40) with HOLD flag

  2. Trigger HOST_CMD_MCTP_TO_RING (0x62) — firmware runs entire bus transaction

  3. Poll HOST_CMD_MCTP_TO_RING (0x62) IN until committed bytes > 0

  4. Read data via TARGET_CMD_DATA_READ (0x52) — existing path

See the separate MCTP Ring Buffer Integration Guide for complete USB command details, byte-level packet formats, and error handling.

Ring Buffer Constraints

  • Buffer size: 8192 bytes

  • Reset at start of each mctp_to_ring command

  • Reports 0 bytes until entire response is committed (atomic visibility)

  • Data consumed on read (single-read semantics)

  • Backpressure NAK is disabled in I2C mode; mi polling rate determines throughput


10. Diagnostics

PIO Dump

Comprehensive bus and PIO state machine diagnostic:

sb_i3c -d 2 pio_dump

Output includes:

  • Bus state: SDA/SCL levels and GPIO function assignments

  • PIO0 SM1 (Initiator): program counter, enabled, FIFO state, stall flags

  • PIO1 SM0 (Target): state and GPIO configuration

  • PIO2 SM0 (Target 0x7E): state for Private transfer monitoring

  • IRQ flags for all PIO blocks

  • Diagnosis line (e.g., “All OK - bus idle” or specific fault identification)

  • Disassembled PIO instructions at current program counter

The test suite automatically runs pio_dump on any test failure.

Debug Levels

sb_i3c -d 2 debug 0     # Quiet (default)
sb_i3c -d 2 debug 1     # Key events (MCTP packet summaries, IBI, errors)
sb_i3c -d 2 debug 2     # Verbose (ring buffer commits, PIO state, SMBus trim, linger)

Debug level 2 shows the full ring-buffer and SMBus path trace including: [PIO] START/was_init, [XFER_END], [CCC] complete, [LINGER] SCL low, [IRQ3], and SMBus trim events. Use level 2 when diagnosing SMBus frame assembly or multi-packet MCTP issues.

Debug output goes to the USB CDC serial console (typically /dev/ttyACM0):

screen /dev/ttyACM0 115200

11. Command Reference

New in V1528 (carried forward)

Command

Description

private_write [--hold] <da7> <bytes>

I3C Private Write; –hold buffers for burst

private_read <da7> <nbytes>

I3C Private Read (up to 128 bytes)

mctp_read <da7> [pkt_size]

Read all MCTP response packets from drive

mctp_command <da7> [pkt_size]

Burst fire + IBI poll + read (autonomous)

mctp_to_ring <da7> [pkt_size]

Burst fire + IBI poll + read → ring buffer

private_force <on|off>

Force Private mode for all transfers

pio_dump

PIO/bus diagnostic dump

setmwl <da7> <bytes>

Set Maximum Write Length (CCC 0x89, direct, 2-byte BE)

setmrl <da7> <bytes>

Set Maximum Read Length (CCC 0x8A, direct, 2-byte BE)

i3c_data_dump [N]

Binary ring buffer read; pipe to hexdump -C -v for inspection

Modified in V1528 (carried forward)

Command

Change

i2c_clk <khz>

Writes to persistent storage only; applied by set_mode

i3c_clk <khz>

Writes to persistent storage only; applied by set_mode

set_mode <i2c|i3c>

Reads and applies stored per-mode clock automatically

Existing Commands (unchanged)

Command

Description

status

Firmware version and device info

targetreset

Reset I3C bus

entdaa <da7>

Dynamic address assignment

getpid <da7>

Get Provisional ID

getbcr <da7>

Get Bus Characteristics Register

getdcr <da7>

Get Device Characteristics Register

getstatus <da7>

Get device status

enec <da7>

Enable events (IBI)

disec <da7>

Disable events

debug <0|1|2>

Set debug level

i3c_data_read [nbytes]

Read from target ring buffer

i3c_sdr_write <da7> <bytes>

SDR write

i3c_sdr_read <da7> <nbytes>

SDR read

i3c_sdr_writeread <da7> <byte> <len>

Write-restart-read (no STOP between phases)

i3c_poll

Poll for IBI events

i3c_err_get

Get error log

i3c_err_clear

Clear error log

scan_i2c

Scan for I2C devices

scan_i3c

Scan for I3C devices

set_termination <0-3>

Set bus termination

set_drive_strength <mA>

Set output drive strength (2–12 mA)

i3c_target_enable

Enable local target mode

i3c_target_disable

Disable local target mode

i3c_target_set_addr <addr>

Set local target address

i3c_target_status

Show local target state

i3c_target_buf_reset

Clear local target ring buffer


12. Test Suite

Run the full test suite:

./sb_i3c_test.sh -d 2

Options:

./sb_i3c_test.sh -d 2 -t 41        # Run single test
./sb_i3c_test.sh -d 2 -t 30-52     # Run test range
./sb_i3c_test.sh -d 2 -v           # Verbose output
./sb_i3c_test.sh -d 2 -N           # Skip hardware init (caller ensures drive present)

V1530: TEST40 and TEST41 now run correctly on V1530 firmware. The version gate that previously skipped these tests on versions beyond V1529 has been updated. When -N is used, HAS_DRIVE defaults to 1 and the i3c_capable cache is cleared, allowing I3C-mode tests to probe fresh rather than skip on a stale result.

MCTP Tests

Test

Description

38

SETMWL 69 — direct CCC 0x89 to drive after ENTDAA/ENEC

39

SETMRL 69 — direct CCC 0x8A to drive after ENTDAA/ENEC

41

MCTP 4K Identify via manual burst write + IBI + mctp_read

50

MCTP discovery (Get Endpoint ID) via mctp_command

51

MCTP 4K Identify via mctp_command (autonomous)

52

MCTP 4K Identify via mctp_to_ring (ring buffer path)

Test 52 verifies the complete customer path: burst write → mctp_to_ring → i3c_data_read → verify byte count → confirm ring drains to empty.

All MCTP tests (41–52) issue SETMWL/SETMRL 69 as part of their setup preamble.


13. Troubleshooting

Intermittent SMBus Errors on Specific Byte Values

If SMBus commands fail intermittently on byte values such as 0xD3, 0xF5, or 0xC1 (even-popcount bytes) but pass consistently on the FT260 path, suspect missing bus termination. Check the drive-side mux jumper. Unterminated bus causes pattern-sensitive ACK failures that mimic firmware bugs.

Drive Not Responding After MCTP Read

After a 4K MCTP transaction, the drive’s MCTP state machine is exhausted. Use double targetreset to recover:

sb_i3c -d 2 targetreset
sleep 0.5
sb_i3c -d 2 targetreset
sleep 0.5
sb_i3c -d 2 entdaa 0x1d
sb_i3c -d 2 enec 0x1d
sb_i3c -d 2 setmwl 0x1d 69
sb_i3c -d 2 setmrl 0x1d 69

I3C Tests Skipping Unexpectedly with -N Flag

If Python test wrappers show “Drive not available in I3C mode” when the drive is present, the i3c_drive_unavailable flag file from a previous failed run may be stale. The V1529 setup_i3c() fix clears this file automatically. If running an older wrapper, clear manually:

rm -f /path/to/luns/1/i3c_drive_unavailable
rm -f /path/to/luns/1/i3c_drive_ready

i2cdetect Shows No Devices

Check for a pending IBI first — this is the most common cause:

sb_i3c -d 2 i3c_poll
# Poll repeatedly until: No IBI Bytes Found

If IBI is clear, check bus state:

sb_i3c -d 2 status
# Look for: Bus State: SDA=1, SCL=1  (both high = idle)

If the bus is stuck, power cycle the target device.

Bus Stuck After Operation

If SDA or SCL is held low after an operation:

sb_i3c -d 2 i3c_poll     # Clear any pending IBI
sb_i3c -d 2 targetreset  # Reset bus state
sb_i3c -d 2 pio_dump     # Inspect PIO state if still stuck

Local Target Tests Fail

# Ensure target is enabled
sb_i3c -d 2 i3c_target_enable

# Verify target address
sb_i3c -d 2 i3c_target_set_addr 0x24

# Flush stale data from buffer
sb_i3c -d 2 i3c_target_buf_reset

MCTP_COMMAND Returns “No response data”

The CLI polls too fast before firmware finishes the bus transaction. V1528+ CLI includes automatic retry (100ms intervals, up to 30 seconds). If still failing, verify the drive was discovered and IBI enabled.

Short MCTP Response (< 4000 bytes)

Drive sent an error packet (SOM=EOM=1 in a single packet). Check byte 3 bit 6 for EOM flag. Common cause: drive MCTP state not reset from previous transaction.

Watchdog Reboot at Idle

V1528 resolved idle watchdog crashes present in intermediate builds. If this recurs, verify firmware version matches the release binary (not an intermediate build). Expected version: 1530.

PIO Dump Shows Stall

If pio_dump shows tx_stall=1 with tx_empty=0, the PIO state machine is blocked waiting for the bus. Run targetreset to clear.

Error Log

Read and clear the firmware error log:

sb_i3c -d 2 i3c_err_get    # Read error log
sb_i3c -d 2 i3c_err_clear  # Clear after review

14. Support

When reporting an issue, please include:

  • Firmware version: sb_i3c -d <slot> status

  • Test script output if applicable

  • Error log: sb_i3c -d <slot> i3c_err_get

  • PIO dump if bus behavior is unexpected: sb_i3c -d <slot> pio_dump

  • Debug level 2 log from ttyACM if SMBus frame assembly is suspected

  • The exact command sequence that reproduces the issue

  • Whether the issue reproduces on the FT260 path (slot 2 vs slot 1)


SANBlaze Technology Inc. — Confidential Copyright 2024-2026 SANBlaze