Artemis Milestone 2g: CBW construction and send for SCSI READ(10)

First real use of the bulk Transfer Rings Configure Endpoint wired up.
xhci_bot_send_read10() builds a 31-byte Command Block Wrapper (USB Mass
Storage Class Bulk-Only Transport spec section 5.1) and submits it as a
single Normal TRB on the bulk OUT ring via a new
xhci_bulk_out_enqueue_and_ring() helper -- a CBW is always exactly one
TRB, so unlike the EP0 helper this one rings its own doorbell rather
than leaving that to a caller assembling a group.

usb_bot_cbw_t is a real struct (every field up to the CDB array is
naturally aligned, and this driver's targets are all little-endian
already assumed everywhere else), but its DMA length is the explicit
USB_BOT_CBW_LENGTH (31) constant, never sizeof(*cbw), since the
compiler may pad the struct to 32 bytes. The SCSI READ(10) CDB itself
is written byte-by-byte since its LBA/Transfer Length fields are
big-endian on the wire, unlike everything else in this driver -- the
one place two byte orders are both live in the same function.

Completion is correlated via the existing pending_transfer_slot_id/
transfer_purpose gate (new XHCI_XFER_CBW_SENT purpose) -- no
ring-specific dispatch needed, since this driver's single-outstanding-
transfer scope already implies which ring produced an event.

This covers construction and send only (one third of a full READ(10):
CBW -> Data-In stage -> CSW) -- reading the Data-In stage and CSW
receive/validation are separate, explicitly not-yet-implemented items.

Verified live via a temporary probe (written, run once, log captured,
reverted per this project's own probe convention) -- all three
architectures, byte-identical: CBW submitted -> CBW send completed,
then a clean disconnect even with the Data-In stage never drained
(confirms no wedge on a dangling BOT transaction). Probe-free
re-verification afterward on all three architectures.

FABRIC-2.md Section X Milestone 2g's CBW checklist item marked done.
Also records a monitoring gotcha hit three times this session: `ls -t`
over the logs/ tree can return a stale leftover log from an earlier
run in the same session -- fixed going forward by reading the log path
off the actual running QEMU process's own command line instead, and a
memory note added so it doesn't recur next session.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R4VMX6VSKCten8nGgaMkq4
This commit is contained in:
Robert Allan James
2026-08-25 09:07:33 -04:00
co-authored by Claude Sonnet 5
parent 92ce1f85dd
commit a88c004ecb
18 changed files with 54562 additions and 3 deletions
+31
View File
@@ -190,6 +190,7 @@ typedef struct {
#define XHCI_TRB_TYPE(ctrl) (((ctrl) & XHCI_TRB_CONTROL_TYPE_MASK) >> XHCI_TRB_CONTROL_TYPE_SHIFT)
/* TRB types used by this driver (subset — xHCI defines many more) */
#define XHCI_TRB_TYPE_NORMAL 1 /* Transfer Ring, bulk/interrupt/isoch -- not EP0 */
#define XHCI_TRB_TYPE_LINK 6 /* ring-wraparound marker, Command/Transfer Rings only */
#define XHCI_TRB_TYPE_ENABLE_SLOT_CMD 9
#define XHCI_TRB_TYPE_DISABLE_SLOT_CMD 10
@@ -275,6 +276,36 @@ typedef struct {
#define USB_EP_ATTR_TYPE_MASK 0x03u
#define USB_EP_TYPE_BULK 0x02u
/* Bulk-Only Transport Command Block Wrapper (USB Mass Storage Class Bulk-
* Only Transport spec, section 5.1) -- sent host-to-device on the bulk OUT
* endpoint ahead of every SCSI command's data phase. Fixed 31-byte wire
* layout; every multi-byte field is little-endian, which this driver's
* targets (amd64/aarch64/riscv64, all little-endian) already assume
* throughout (no htole32-style conversions anywhere in this codebase) --
* direct field assignment is wire-correct as-is. sizeof() is NOT used as
* this struct's DMA length anywhere (may be padded to 32 by the compiler
* to satisfy the uint32_t members' alignment) -- USB_BOT_CBW_LENGTH (31)
* is the correct, explicit wire length, matching the same
* offset-constant-not-sizeof discipline already used for the USB
* descriptor field offsets above. */
typedef struct {
uint32_t dCBWSignature;
uint32_t dCBWTag;
uint32_t dCBWDataTransferLength;
uint8_t bmCBWFlags;
uint8_t bCBWLUN;
uint8_t bCBWCBLength;
uint8_t CBWCB[16];
} usb_bot_cbw_t;
#define USB_BOT_CBW_SIGNATURE 0x43425355u /* "USBC", wire byte order U,S,B,C as an LE dword */
#define USB_BOT_CBW_LENGTH 31u
#define USB_BOT_CBW_FLAG_DATA_IN 0x80u /* bmCBWFlags: device-to-host data stage */
#define USB_BOT_CBW_LUN_DEFAULT 0u /* no multi-LUN support -- single-LUN devices only */
#define SCSI_CMD_READ10 0x28u
#define SCSI_CDB_LEN_READ10 10u
/* Command Completion Event TRB layout (xHCI 1.2 spec table 6-32):
* parameter[63:4] = Command TRB Pointer, status[31:24] = Completion Code,
* status[23:0] = unused here, control[31:24] = Slot ID (Enable Slot's