G.1: xHCI bulk-endpoint stall recovery (per F.14), built + verified

Full BOT-spec stall recovery per FABRIC-3.md F.14: new STALL_ERROR handling,
Reset Endpoint + Set TR Dequeue Pointer commands, CLEAR_FEATURE(ENDPOINT_HALT),
escalating to Bulk-Only Mass Storage Reset, capped retries
(XHCI_BOT_STALL_MAX_RECOVERIES=2) mirroring bot_tur_retries, clean terminal
failure via xhci_stall_fail().

Purely additive recovery path off the non-success transfer-event branch; the
normal path is unchanged. Builds clean on amd64/aarch64/riscv64. QEMU amd64
boot regression passes: zero stalls, BOT attach (READ CAPACITY10 -> READ10 ->
home-blocks) completes, normal-path xHCI trace identical to baseline. Live
stall injection is not provable under qemu-xhci; deferred to v2.5.0 hardware.

FABRIC-3.md G.1 documented; ROADMAP release-versioning policy folded in.
This commit is contained in:
Robert Allan James
2026-08-29 00:58:59 -04:00
parent 5689c397fc
commit 49a3faa331
7 changed files with 730 additions and 5 deletions
+38
View File
@@ -196,6 +196,8 @@ typedef struct {
#define XHCI_TRB_TYPE_DISABLE_SLOT_CMD 10
#define XHCI_TRB_TYPE_ADDRESS_DEVICE_CMD 11
#define XHCI_TRB_TYPE_CONFIGURE_ENDPOINT_CMD 12
#define XHCI_TRB_TYPE_RESET_ENDPOINT_CMD 14
#define XHCI_TRB_TYPE_SET_TR_DEQUEUE_POINTER_CMD 16
#define XHCI_TRB_TYPE_SETUP_STAGE 2 /* Transfer Ring, control transfers only */
#define XHCI_TRB_TYPE_DATA_STAGE 3
#define XHCI_TRB_TYPE_STATUS_STAGE 4
@@ -234,11 +236,32 @@ typedef struct {
#define USB_REQ_GET_DESCRIPTOR 6u
#define USB_REQ_SET_CONFIGURATION 9u
#define USB_REQ_CLEAR_FEATURE 1u
#define USB_DESC_TYPE_DEVICE 1u
#define USB_DESC_TYPE_CONFIG 2u
#define USB_DIR_DEVICE_TO_HOST 0x80u
#define USB_DIR_HOST_TO_DEVICE 0x00u
/* Standard USB Device/Endpoint feature selectors (USB 2.0 spec table 9-6) --
* ENDPOINT_HALT (0) is the halt condition on a specific endpoint, cleared
* (and the endpoint's data toggle reset) by a CLEAR_FEATURE request whose
* wValue is this selector and whose wIndex is the endpoint's own address --
* the USB-level half of G.1's stall recovery (xHCI Reset Endpoint +
* SET_TR_DEQUEUE_POINTER clear the xHC-side state; this clears the device-
* side halt so the endpoint will actually drive new transfers again).
* bmRequestType type field (bits 6:5 of the request type) -- 0 = standard,
* 1 = class, and the recipient field (bits 4:0) -- 0 = device, 2 = endpoint.
* BOT Mass Storage Reset (USB Mass Storage Class Bulk-Only Transport spec
* section 3.1) is a class, interface-recipient (recipient 1) request, the
* BOT-spec-mandated full teardown + restart of a stalled command sequence. */
#define USB_REQ_TYPE_STANDARD 0u
#define USB_REQ_TYPE_CLASS 1u
#define USB_RECIP_DEVICE 0u
#define USB_RECIP_INTERFACE 1u
#define USB_RECIP_ENDPOINT 2u
#define USB_FEATURE_ENDPOINT_HALT 0u
#define USB_BOT_MASS_STORAGE_RESET 0xFFu
/* Standard USB Interface descriptor field offsets (9 bytes, USB 2.0 spec
* table 9-12) -- Mass Storage class detection reads these three fields.
* Not decoded via a struct like usb_setup_packet_t: the Interface
@@ -328,6 +351,20 @@ typedef struct {
* xhci_dev_t's bot_tur_retries doc comment. */
#define XHCI_BOT_TUR_MAX_RETRIES 3u
/* Bounded recovery count for a stalled bulk endpoint before giving up on
* it -- see xhci_dev_t's bot_stall_recoveries doc comment (G.1 / §F.14).
* Mirrors the shape of XHCI_BOT_TUR_MAX_RETRIES: a small fixed budget of
* full recoveries, each of which is itself the multi-step xHCI Reset
* Endpoint -> Set TR Dequeue Pointer -> CLEAR_FEATURE(ENDPOINT_HALT)
* sequence (escalating to a BOT Mass Storage Reset on the last try),
* after which the original SCSI command is retried from scratch. Two
* full recoveries, then escalation and terminal failure, is a deliberately
* tight bound chosen to match this driver's "recover or fail clean, never
* wedge the controller, never loop forever" contract -- a genuinely
* wedged device gets two chances to clear, then the block layer sees a
* clean BOT_STATUS_FAILED. */
#define XHCI_BOT_STALL_MAX_RECOVERIES 2u
/* SCSI READ CAPACITY(10) (SBC-3 section 5.14) -- 10-byte CDB, opcode 0x25,
* every other CDB byte reserved/zero for the standard "report capacity"
* form (LBA field left 0, PMI bit left clear). 8-byte Data-In reply:
@@ -368,6 +405,7 @@ typedef struct {
#define XHCI_EVT_COMPLETION_CODE(status) (((uint32_t)(status) >> 24) & 0xFFu)
#define XHCI_EVT_SLOT_ID(control) (((uint32_t)(control) >> 24) & 0xFFu)
#define XHCI_COMPLETION_CODE_SUCCESS 1u
#define XHCI_COMPLETION_CODE_STALL_ERROR 6u
/* Port Status Change Event TRB layout (xHCI 1.2 spec table 6-34):
* parameter[31:24] = Port ID (1-based, matches PORTSC array indexing