Skip to content

rockusb: erase carries no data phase, so its CBW must declare zero length - #133

Merged
widgetii merged 1 commit into
masterfrom
fix/rockusb-erase-cbw-zero-transfer
Sep 7, 2026
Merged

rockusb: erase carries no data phase, so its CBW must declare zero length#133
widgetii merged 1 commit into
masterfrom
fix/rockusb-erase-cbw-zero-transfer

Conversation

@widgetii

@widgetii widgetii commented Sep 7, 2026

Copy link
Copy Markdown
Member

What

build_cbw() defaulted the CBW's dCBWDataTransferLength to
count * SECTOR_SIZE whenever a count was given. That is correct for
READ_LBA/WRITE_LBA, but ERASE_LBA and ERASE_NORMAL carry their sector
count in the CDB while moving no data.

With a nonzero transfer length declared for an erase, the usbplug waits for a
data phase that never arrives. On an RV1106 this surfaces as:

moved -1024 of 0 bytes (residue 1024)

and the erase never lands — which blocks erase-before-write flows (e.g. clearing
stale UBI PEBs before writing a fresh image).

Fix

Exclude ERASE_LBA/ERASE_NORMAL from the count * SECTOR_SIZE default, so
their CBW declares a zero-length transfer. Read/write are unchanged.

Test

Added TestBuildCbwEraseTransfer:

  • erase opcodes produce a CBW with dCBWDataTransferLength == 0
  • READ_LBA/WRITE_LBA still declare count * SECTOR_SIZE
744 passed, 2 skipped

Verified on hardware: with this fix, ERASE_LBA clears the target region
(reads back 0xff) on an RV1106 SPI-NAND, where before it failed with the
residue error above.

…ngth

build_cbw() defaulted the CBW's dCBWDataTransferLength to count*SECTOR_SIZE
whenever a count was given. That is right for READ_LBA/WRITE_LBA, but ERASE_LBA
and ERASE_NORMAL carry their sector count in the CDB while moving no data. With
a nonzero length declared, the usbplug waits for a data phase that never comes;
on an RV1106 this surfaces as "moved -1024 of 0 bytes (residue 1024)" and the
erase never lands. Exclude the erase opcodes from the default so their CBW
declares a zero-length transfer.
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider

Great, no issues found!

Qodo reviewed your code and found no material issues that require review

Grey Divider

Tip of the day
💡 Did you know, you can copy the agent prompt from any finding and feed it to your IDE agent

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Fix zero-length RockUSB erase CBWs

🐞 Bug fix 🧪 Tests 🕐 10-20 Minutes

Grey Divider

AI Description

• Prevent erase CBWs from advertising a data phase that Rockchip usbplugs await indefinitely.
• Preserve sector-sized transfer defaults for LBA reads and writes.
• Add regression coverage for erase opcodes and unchanged read/write framing.
Diagram

graph TD
  A["CBW Builder"] --> B{"Erase opcode?"} -- Yes --> C["Zero length"] --> F["CBW Wrapper"]
  B -- No --> D{"Count present?"} -- Yes --> E["Sector bytes"] --> F
  D -- No --> C
Loading
High-Level Assessment

The targeted opcode exclusion is the lowest-risk approach because it fixes erase framing without changing established defaults for read, write, or unknown integer opcodes. Restricting inference exclusively to read/write opcodes or changing the API to distinguish an omitted transfer length from explicit zero would be more invasive without improving this fix.

Files changed (2) +42 / -2

Bug fix (1) +11 / -2
protocol.pyDeclare zero-length data phases for erase CBWs +11/-2

Declare zero-length data phases for erase CBWs

• Excludes ERASE_LBA and ERASE_NORMAL from count-based transfer-length inference because their counts live only in the CDB. This prevents usbplugs from waiting for nonexistent erase payloads while preserving existing read/write behavior.

src/defib/rockusb/protocol.py

Tests (1) +31 / -0
test_rockusb_device.pyCover erase and block-transfer CBW lengths +31/-0

Cover erase and block-transfer CBW lengths

• Adds regression tests confirming both erase opcodes advertise zero transferred bytes. It also verifies READ_LBA and WRITE_LBA still derive their transfer lengths from sector count.

tests/test_rockusb_device.py

@widgetii
widgetii merged commit 7526169 into master Sep 7, 2026
13 checks passed
@widgetii
widgetii deleted the fix/rockusb-erase-cbw-zero-transfer branch September 7, 2026 19:21
widgetii added a commit that referenced this pull request Sep 8, 2026
)

## What

Adds `defib dump-flash` reading over the RockUSB path, so a board whose
boot ROM
only answers on USB (e.g. RV1106) can be backed up — the one thing
missing
before any USB write can be attempted safely.

```
defib dump-flash -c rv1106 --ddr ... --usbplug ... \
                 --partition rootfs -o rootfs.bin
```

- `--chip` is optional; the serial path is untouched for chips that
already
  worked. For a USB-only profile, `-p` isn't consulted.
- Capacity comes from `READ_FLASH_INFO`, not a guess or flag. A reply
claiming
zero capacity is refused (loader up but flash not brought up → a file
full of
nothing), and a range past the reported end is refused (the LBA commands
just
  stall there).
- `--partition` reads one region from the profile; the usbplug's LBA
space maps
directly onto the kernel's mtd partitions, so it compares byte-for-byte
with
  `cat /dev/mtdN` on a booted board.
- Reads stream to disk rather than buffering in memory.

## Evidence

Exercised on an RV1106 (Luckfox Pico Max, 256 MB SPI-NAND) this session:
`READ_FLASH_INFO` reported `255.5 MiB (523264 sectors), block 128 KiB,
page
2048 B` — the 0.5 MiB gap being the FTL reserve, and the block/page
matching
`/proc/mtd` on the same board booted. Partition reads matched
byte-for-byte.

Tests: `tests/test_rockusb_flashinfo.py` (flash-info parse,
zero-capacity and
out-of-range refusal). Full suite **755 passed, 2 skipped**.

## Notes

Rebased onto current master (post #133). Depends on nothing outside it.
A
separate return-to-MaskROM recovery enhancement (handling a stale
usbplug a
prior run left running) is still WIP on my side and not included here.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant