USB Endpoint Halt Recovery: Reset Protocol State as Well as the Pipe

Clearing an endpoint halt repairs a USB transport condition. It does not by itself restore the device’s command parser, identify the outcome of the interrupted operation, or select the next legal protocol phase. Recovery must follow the endpoint type and the device class or vendor protocol.

Applicability: Linux v6.12 host-driver APIs provide the implementation boundary. USB Mass Storage Bulk-Only Transport revision 1.0 provides a concrete class-specific example. This is not a recovery recipe for UAS, arbitrary vendor endpoints, or every USB device. Use disposable test media or a protocol simulator for fault injection.

Three ordered BOT Reset Recovery steps lead from class reset to Bulk-In and Bulk-Out halt clearing, with protocol and operation outcomes kept separate.
The sequence applies to USB Mass Storage Bulk-Only Transport phase-error recovery, not to every USB interface or every stall.

1. Classify the stall before choosing recovery

Record endpoint address, direction, transfer type, interface protocol, request phase, completion status, and actual transferred length. The same error label can obscure different situations. A bulk endpoint halted during command transport requires a different interpretation from an unsupported control request.

The Linux USB host API scopes usb_clear_halt() to bulk and interrupt endpoint halts. Control endpoints can report a protocol stall without having the same persistent halt condition; isochronous endpoints do not halt. Do not call a generic “clear everything” handler for every transfer failure.

Preserve the first error and the protocol phase that produced it. If a subsequent recovery request fails because the device disconnected, report both events. Replacing the original cause with the last cleanup status makes it difficult to distinguish a protocol defect from removal during recovery.

2. Quiesce the affected request stream

Stop new submissions for the affected protocol owner before changing pipe state. Account for already queued transfers and their completions. The host API recommends unlinking queued URBs before clearing a halted endpoint, and the clear operation itself can sleep. Coordinate it with disconnect and the driver’s lifetime rules.

Use one recovery owner. If every failed completion independently clears the endpoint and restarts its request, several callbacks can race to redefine the same transport state. A request queue should enter a controlled recovery state and let one path decide when a new exchange may begin.

Define the scope carefully. A recovery action affecting an interface or whole device can disrupt other outstanding operations. Do not assume that repairing one pipe leaves every related state machine synchronized. Consult the class protocol and device documentation before escalating from an endpoint operation to a broader reset.

3. Follow the Bulk-Only Transport state machine

Bulk-Only Transport separates command, optional data, and status transport. Its revision 1.0 specification distinguishes a command failure from a phase error. A phase-error status requires Reset Recovery. Clearing a pipe alone is insufficient for that case.

The specified Reset Recovery order is a Bulk-Only Mass Storage Reset, then clearing HALT on Bulk-In, then clearing HALT on Bulk-Out. This sequence belongs to this class protocol. It is not a universal USB reset sequence and must not be sent to an unrelated interface.

Status transport has its own rules. When the command status wrapper (CSW) read stalls, the prescribed algorithm clears Bulk-In and retries status reception. A second stall requires Reset Recovery. An invalid CSW also requires Reset Recovery; a valid but non-meaningful CSW permits Reset Recovery. Do not simplify every data-stage or status-stage stall into “reissue the original command.”

4. Validate the status before declaring synchronization

Retain the expected command tag, data direction, transfer length, and current phase. A returned status wrapper must belong to the outstanding command and satisfy the protocol’s validity rules. A successful USB read carrying unrelated or malformed status is not a successful command completion.

The v6.12 usb-storage transport implementation checks status-wrapper structure and tag association, distinguishes transport errors from command failures, and implements class recovery. Its device quirks and implementation details are additional reasons to use the established class driver rather than invent an application-level reset loop.

For a hypothetical diagnostic trace, suppose a command’s data phase stops and a later read returns bytes that look like a status wrapper but carry the previous command’s tag. Under the base BOT contract, the tag mismatch makes the CSW invalid and requires Reset Recovery. Preserve the raw wrapper and expected tag for analysis. Linux compatibility quirks are implementation-specific exceptions, not changes to that base requirement.

5. Keep transport recovery separate from operation outcome

Record three results independently: whether the pipe is usable, whether the class protocol is synchronized, and whether the interrupted command’s outcome is known. Restoring the first two does not retroactively prove the third.

For storage, do not infer durable application data merely from transport recovery. The command set, cache policy, filesystem, and application transaction rules determine that meaning. For a vendor-specific device, a documented status query or operation identifier may resolve an uncertain result; without such a mechanism, expose uncertainty rather than blindly replaying an action.

A retry policy should identify which layer owns retries and which operations are safe to repeat. Avoid multiplying retries in a library, driver, and application simultaneously. This article’s USB-specific contribution is the endpoint and class-phase recovery contract; it does not claim a new exactly-once operation guarantee.

6. Build phase-specific fault cases

  1. Command transport stall: verify the class-required recovery rather than merely clearing Bulk-Out and continuing with data.
  2. Status read stall: follow the specified status-retry path and bound repeated failure.
  3. Phase-error status: require ordered class reset, Bulk-In clear, and Bulk-Out clear before a new command.
  4. Wrong or malformed status: reject it before reporting success or advancing the command queue.
  5. Disconnect during recovery: terminate recovery without late submissions or use of retired device state.

Use a controllable simulator or approved test device so each error is injected at a known phase. Capture host requests, endpoint directions, class reset operations, status association, and the first valid post-recovery exchange. A generic cable pull cannot exercise every halt-recovery branch.

No USB exchange or storage command was executed for this article. The release artifact is a phase-to-recovery table, an ordered request trace, and separate transport/protocol/operation outcomes. Pass only when the selected class protocol is re-established and callers receive an honest result for the interrupted operation.

Similar Posts