Artemis Milestone 2g: TEST UNIT READY unit-init sequence -- READ(10) now PASSes

Roots out the CSW status FAILED left unexplained in the prior increment: a
freshly attached SCSI target's standing UNIT ATTENTION condition, which a
bare READ(10) with no retry can never clear. xhci_bot_send_test_unit_ready()
sends SCSI TEST UNIT READY (SPC-4 6.33) ahead of the real command; the CSW
handler now tags command kind (bot_cmd_kind) to distinguish a TUR completion
from a READ10 completion, chains TUR PASS into the real READ(10), and
bounded-retries TUR on FAILED/PHASE ERROR (bot_tur_retries, capped at
XHCI_BOT_TUR_MAX_RETRIES). xhci_bot_read_block() is the new intended entry
point tying lba/num_blocks/block_size + the TUR-first sequencing together.

Verified live via a temporary probe (hot-attached disk/usb-thumbdrive-test.img
through the running instance's QMP socket), captured on amd64: full chain
CBW(TUR) -> FAILED -> retry -> PASS -> CBW(READ10) -> Data-In -> CSW PASS.
Probe reverted after capture; all three architectures re-verified clean,
probe-free boot to ok>. FABRIC-2.md Section X 2g updated with the writeup.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CXjAPTEKrgY2Mrk25KoLDn
This commit is contained in:
Robert Allan James
2026-08-25 11:46:55 -04:00
co-authored by Claude Sonnet 5
parent c54ea24aaf
commit 65effbd1ba
13 changed files with 36463 additions and 10 deletions
+53 -5
View File
@@ -3460,11 +3460,10 @@ arch afterward, no wedge. `logs/20260825-073235/amd64/`, `logs/20260825-073417/a
split between this item and "identify/configure endpoints" above didn't leave a
separate line for it, but it's new work, not folded silently into either neighbor —
see writeup)
- [ ] Get one real SCSI READ(10) working end to end — first proof the whole stack works,
before write. **Partially exercised, not satisfied**: the CBW→Data-In→CSW mechanism
itself is confirmed working (see writeup below), but the SCSI command itself returns
CSW status FAILED against the current test fixture -- this item stays open until a
READ(10) actually returns PASS with real data, not just a well-formed CSW
- [x] Get one real SCSI READ(10) working end to end — first proof the whole stack works,
before write. **Done 2026-08-25**: the earlier CSW status FAILED was exactly the
UNIT ATTENTION condition flagged (not root-caused) in the prior writeup — a TEST UNIT
READY unit-init sequence ahead of READ(10) was the fix, see writeup below
- [ ] Implement CBW/data/CSW for SCSI WRITE(10) — this is where the earlier "read/write,
unquestionable" requirement actually gets satisfied
- [ ] Implement basic error/stall recovery (CSW failure status, endpoint stall clear) — at
@@ -3650,6 +3649,55 @@ the SET_CONFIGURATION completion handler) was removed after capture; only
Re-verified probe-free afterward, all three architectures, clean boots with no BOT activity:
`logs/20260825-092701/amd64/`, `logs/20260825-092842/aarch64/`, `logs/20260825-093048/riscv64/`.
**TEST UNIT READY unit-init sequence, done 2026-08-25 — READ(10) now returns PASS.** Root-causes
the CSW status FAILED flagged but not chased down in the previous increment: SBC-3/SPC-4 give a
freshly attached SCSI target's first command a standing UNIT ATTENTION (media-change/reset
notice), cleared once any command is issued and answered — a bare READ(10) with no retry, which
is all the previous probe sent, was always going to eat that condition rather than clear it.
`xhci_bot_send_test_unit_ready()` builds and sends the CBW for SCSI TEST UNIT READY (SPC-4
section 6.33, opcode `0x00`, 6-byte all-zero CDB, no data stage) — mirrors
`xhci_bot_send_read10()`'s CBW-build shape but sets `dCBWDataTransferLength = 0` /
`bot_expected_data_len = 0`, which the existing `XHCI_XFER_CBW_SENT` completion handler now
checks to skip straight to CSW receive rather than a Data-In stage that would never arrive (BOT
spec section 6.3: zero-length command means no data phase).
A new `bot_cmd_kind` field (`BOT_CMD_NONE`/`BOT_CMD_TEST_UNIT_READY`/`BOT_CMD_READ10`) tags which
SCSI command a given CBW→CSW round trip actually is, since `XHCI_XFER_CSW_RECEIVED` alone can't
tell a TUR completion from a READ10 completion — both take the identical CBW→(Data-In)→CSW
shape. The CSW-receive handler now branches on it: a TUR CSW PASS chains into the real READ(10)
(`XHCI_NEXT_ACTION_BOT_SEND_READ10`, same deferred-dispatch pattern as every other chained
request in this driver); a TUR FAILED/PHASE ERROR retries TUR itself
(`XHCI_NEXT_ACTION_BOT_SEND_TUR`), bounded by a new `bot_tur_retries` counter against
`XHCI_BOT_TUR_MAX_RETRIES` (3) so a target that's never going to clear UNIT ATTENTION can't spin
the driver forever; a READ10 CSW completion is unchanged (terminal, logged only — 2h's problem
per the prior increment's own doc comment, still true).
`xhci_bot_read_block()` is the new intended entry point tying this together — latches
lba/num_blocks/block_size, resets the retry counter, and kicks off with TUR rather than a bare
READ10, so callers get the UNIT ATTENTION handling for free instead of reimplementing it.
`xhci_bot_send_read10()` itself is unchanged in behavior, just now also reachable via this
chain (low-level primitive, most callers should prefer `xhci_bot_read_block()`).
Verified live via a temporary probe (written, run once, log captured, then reverted per this
project's own probe convention) hot-attaching `disk/usb-thumbdrive-test.img` through the running
instance's QMP socket (`blockdev-add` + `device_add usb-storage,bus=xhci0.0`) rather than at
QEMU launch — exercises the same live-hotplug path 2e/2f's own writeups already use, and avoids
needing the `-device usb-storage` flag added to any of the three `qemu` Makefile targets. Full
chain, byte-identical to the design: `device configured``CBW (TEST UNIT READY) submitted`
`CSW status = FAILED``unit not ready -- retrying TEST UNIT READY` → `CBW (TEST UNIT READY)
submitted` → `CSW status = PASS` → `unit ready -- issuing READ10` → `CBW (READ10) submitted` →
`BOT Data-In read submitted``BOT Data-In read completed``CSW status = PASS`, data
residue 0 throughout. Captured on amd64 only this increment (`logs/20260825-112924/amd64/`) —
unlike 2g's own writeups, the other two architectures were not separately hotplug-verified with
the probe active, since the mechanism itself (CBW/CSW dispatch, deferred `next_action` chaining)
is architecture-independent code already proven identical across all three arches by every
earlier BOT increment; only the probe-removed acceptance boot was re-run on all three. The probe
(`XHCI_NEXT_ACTION_BOT_PROBE_READ_BLOCK` and its trigger in the SET_CONFIGURATION completion
handler) was removed after capture; only `xhci_bot_send_test_unit_ready()`/
`xhci_bot_read_block()` and their Transfer Event handling remain. Re-verified probe-free
afterward, all three architectures, clean boots with no BOT activity: `logs/20260825-113813/amd64/`,
`logs/20260825-114114/aarch64/`, `logs/20260825-114321/riscv64/`.
**2h. Integration with the existing block subsystem**
- [ ] Wire a working USB MSC device into `blk_subsys_attach_device()` (or
`blk_subsys_add_raw_device()`, whichever fits — confirm which, since USB is