Artemis Milestone 2g (partial): bulk endpoint discovery + 2e disconnect teardown
Picked up from a crashed session: xhci_driver.h/xhci.h already had the bulk_in/out_ep_addr/max_packet fields and Endpoint-descriptor offset macros scaffolded, but the actual walk that populates them was never written. Added it: after 2f confirms a Mass Storage/SCSI/BOT interface, a nested walk continues through the Endpoint descriptors that follow it (bDescriptorType==5, stopping at the next Interface descriptor or end of stream), keeping only Bulk-type endpoints and splitting IN/OUT by bEndpointAddress bit 7. Also reset the four new fields in xhci_bringup(), which the scaffolding had missed. Also completed 2e's disconnect teardown, which was fully implemented this session (not scaffolded): a Disable Slot command is now submitted on a real disconnect, with the port's tracked slot ID captured and cleared from port_slot_id[] immediately (before the command completes) so a fresh connect on the same port isn't confused for one already in progress, and DCBAA[slot_id] cleared only on a successful completion. Verified live via QMP hotplug (deliberate device_add/device_del against freshly launched, individually-tracked instances -- not whatever happened to be attached at boot), all three architectures, byte-identical: bulk IN endpoint=0x81, bulk OUT endpoint=0x02, then a clean disconnect -> disable slot succeeded, no wedge. Caught and fixed a documentation near-miss in the same pass: an initial draft cited the probe-free three-arch acceptance boots as this feature's verification evidence, but a stale leftover log directory from a pre-crash orphaned QEMU process had been picked up by an `ls -dt | head -1` glob during monitoring and mistaken for this session's own result -- the real acceptance logs never had a device attached at all. Re-verified against real PIDs and real log paths before writing FABRIC-2.md's final writeup. FABRIC-2.md Section X Milestone 2 updated: 2e's disconnect-teardown checklist item marked done, 2g's endpoint-identification item marked partially done (identification only -- Configure Endpoint / EP Context wiring is still open). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R4VMX6VSKCten8nGgaMkq4
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
b4bbd043d0
commit
96d55fcd87
+74
-6
@@ -3211,9 +3211,10 @@ Final three-arch acceptance (probe-free, `clean qemu`): all three boot to `ok>`
|
||||
the device (Address Device command) — **both done 2026-08-22**, see writeup below.
|
||||
Device descriptor read is 2f's job and depends on this (not the reverse — an earlier
|
||||
version of this note had the dependency backwards)
|
||||
- [ ] On disconnect: tear down the corresponding device slot and signal to whatever higher-
|
||||
level code (Section U's identity/VM logic) that the device is gone — **this is the
|
||||
first point where Section U/V's design actually gets a real trigger to hang off**
|
||||
- [x] On disconnect: tear down the corresponding device slot — **done 2026-08-25**, see
|
||||
writeup below. Signaling to Section U's higher-level code is still open — a real
|
||||
callback surface doesn't exist yet, this item only covers the xHCI-side teardown
|
||||
(Disable Slot command, DCBAA entry clear)
|
||||
- [ ] Decide and implement where the hotplug event surfaces to the rest of the kernel —
|
||||
likely a callback registered by whatever owns the home-blocks logic, not xHCI code
|
||||
calling into block_subsystem.c directly (matching the existing "kernel/Artemis
|
||||
@@ -3319,8 +3320,43 @@ no debugging needed. `logs/20260822-113852/amd64/`, `logs/20260822-114043/aarch6
|
||||
|
||||
Still open: correlating Command Completion Events via the real Command TRB Pointer (not needed
|
||||
yet, see above), device descriptor read (2f), USB2 port-reset handling (untested — this
|
||||
increment's test device was SuperSpeed and self-enabled), disconnect teardown (Disable Slot
|
||||
command, DCBAA entry clear), and the callback surface into Section U's higher-level code.
|
||||
increment's test device was SuperSpeed and self-enabled), and the callback surface into
|
||||
Section U's higher-level code.
|
||||
|
||||
**Disconnect teardown (Disable Slot command, DCBAA entry clear), done 2026-08-25.** New
|
||||
`XHCI_CONN_AWAIT_DISABLE_SLOT` state and `dev->pending_disable_slot_id`, same
|
||||
single-outstanding-command pattern as Enable Slot/Address Device above. On a real disconnect
|
||||
(`PORTSC.CCS` clear), `port_slot_id[port_id-1]` is captured into
|
||||
`pending_disable_slot_id` and cleared from the tracking array *immediately* — before the
|
||||
Disable Slot command's completion is known — so a fresh connect on the same port during the
|
||||
brief in-flight window isn't confused for one already in progress; the command's own
|
||||
completion handler is the only thing that later touches `DCBAA[slot_id]`, zeroing it on
|
||||
success only (a failure completion leaves it alone rather than zeroing a context pointer the
|
||||
controller might still consider live). If a disconnect arrives while another Command Ring
|
||||
command is already outstanding, the Disable Slot is dropped rather than queued — same
|
||||
documented limitation as Enable Slot's "already pending" case, not a new gap.
|
||||
|
||||
Verified live via QMP hotplug, all three architectures — a real connect→full-enumeration→
|
||||
disconnect cycle exercised the new teardown path directly, not a synthetic disconnect: `xhci:
|
||||
port status change -- device connected` through `xhci: device configured` (full 2f sequence)
|
||||
followed immediately by `xhci: port status change -- device disconnected`, `xhci: disable slot
|
||||
command submitted`, `xhci: disable slot succeeded`, no wedge. `logs/20260825-081058/amd64/`,
|
||||
`logs/20260825-081300/aarch64/`, `logs/20260825-081517/riscv64/`.
|
||||
|
||||
**A documentation near-miss caught before commit, worth recording.** The first draft of this
|
||||
writeup cited the probe-free three-arch acceptance boots (`logs/20260825-075759/amd64/` etc.)
|
||||
as the verification evidence for this feature — those boots never had a USB device attached at
|
||||
all (`grep xhci` on them shows only the four controller-bring-up lines, nothing past that), so
|
||||
the claim was false. The mixup came from an earlier monitoring mistake in-session: a
|
||||
leftover, still-running QEMU process from before a session crash left a *stale* log directory
|
||||
on disk, and a `ls -dt | head -1` glob picked that stale directory instead of the freshly
|
||||
launched run's — the stale log happened to already contain a full connect/enumerate/disconnect
|
||||
sequence from whatever testing produced it originally, which read as this session's own result
|
||||
until checked against the actual PID and the actual new log path. Caught by re-grepping the
|
||||
three acceptance logs directly before writing this paragraph and finding them empty of device
|
||||
activity; fixed by re-running the verification as a real, deliberate QMP hotplug (not relying
|
||||
on whatever happened to be attached at boot) against freshly launched, individually-tracked
|
||||
instances.
|
||||
|
||||
**2f. USB device enumeration (post-connect, before it's usable as storage)**
|
||||
- [x] Request and parse the device descriptor — **done 2026-08-22**, see writeup below.
|
||||
@@ -3415,7 +3451,11 @@ arch afterward, no wedge. `logs/20260825-073235/amd64/`, `logs/20260825-073417/a
|
||||
`logs/20260825-073728/riscv64/`.
|
||||
|
||||
**2g. Bulk-Only Transport (BOT) — the actual read/write path**
|
||||
- [ ] Identify and configure the device's bulk IN and bulk OUT endpoints
|
||||
- [~] Identify the device's bulk IN and bulk OUT endpoints — **identification done
|
||||
2026-08-25**, see writeup below; *configuring* them (a Configure Endpoint command,
|
||||
wiring their EP Contexts/DCIs so the controller will actually run transfers on them)
|
||||
is still open — this increment only reads the addresses out of the descriptor, it
|
||||
doesn't yet act on them
|
||||
- [ ] Implement CBW (Command Block Wrapper) construction and send, for a SCSI READ(10)
|
||||
- [ ] Implement CSW (Command Status Wrapper) receive and status check
|
||||
- [ ] Get one real SCSI READ(10) working end to end — first proof the whole stack works,
|
||||
@@ -3425,6 +3465,34 @@ arch afterward, no wedge. `logs/20260825-073235/amd64/`, `logs/20260825-073417/a
|
||||
- [ ] Implement basic error/stall recovery (CSW failure status, endpoint stall clear) — at
|
||||
minimum enough to not wedge the controller on a single bad transfer
|
||||
|
||||
**Bulk endpoint identification, done 2026-08-25.** Extends the Interface-descriptor walk
|
||||
already built in 2f: once a Mass Storage/SCSI/BOT interface is confirmed, a second, nested
|
||||
walk continues forward from that interface's own offset through the Endpoint descriptors that
|
||||
follow it (`bDescriptorType == 5`, USB 2.0 spec table 9-13), stopping at the next Interface
|
||||
descriptor or end of the concatenated descriptor stream — matching the same "found by type,
|
||||
not assumed at a fixed offset" discipline the outer walk already uses. Only endpoints whose
|
||||
`bmAttributes` bits 1:0 read Bulk (`0x02`) are kept; `bEndpointAddress` bit 7 picks IN vs. OUT.
|
||||
Four new `xhci_dev_t` fields (`bulk_in_ep_addr`/`bulk_in_max_packet`/`bulk_out_ep_addr`/
|
||||
`bulk_out_max_packet`) hold the result — address `0` doubles as the "not found yet" sentinel
|
||||
for both, since endpoint address 0 is always EP0 and can never legitimately be a bulk
|
||||
endpoint's own address. A device confirmed BOT but missing either direction logs a warning
|
||||
rather than failing silently.
|
||||
|
||||
This work was already scaffolded — the four struct fields, the descriptor-offset macros, and
|
||||
their doc comments were all written and uncommitted before an earlier session ended abruptly
|
||||
mid-edit — but the walk itself, the piece that actually populates them, hadn't been written
|
||||
yet; this increment is that missing piece (plus resetting the four fields in
|
||||
`xhci_bringup()`, which the scaffolding had also missed).
|
||||
|
||||
Verified live via QMP hotplug (deliberate `device_add`/`device_del` against a freshly booted,
|
||||
individually-tracked instance — see the disconnect-teardown writeup above for why this
|
||||
matters), all three architectures, byte-identical results everywhere: `bulk IN
|
||||
endpoint=0x81`, `bulk OUT endpoint=0x02`, immediately followed by the existing `set
|
||||
configuration submitted` → `device configured` chain, unaffected. `logs/20260825-081058/amd64/`,
|
||||
`logs/20260825-081300/aarch64/`, `logs/20260825-081517/riscv64/`. *Configuring* these
|
||||
endpoints (a Configure Endpoint command, EP Context setup) is the next open item in this
|
||||
milestone — this increment only identifies them.
|
||||
|
||||
**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
|
||||
|
||||
Reference in New Issue
Block a user