{bp-19451} usbmsc: fix composite-mode class requests and Hi>Di stall behavior - #19624
Merged
Merged
Conversation
Three defects that together prevented macOS from ever mounting a composite USBMSC function (Linux was mostly unaffected because its probe sequence and recovery timing never exercised these paths): 1. usbmsc_setup() compared the class-request wIndex against the compile-time constant USBMSC_INTERFACEID (= CONFIG_USBMSC_IFNOBASE, i.e. 0) instead of the composite-assigned priv->devinfo.ifnobase. In composite mode the MSC interface number is nonzero, so GET MAX LUN, Bulk-Only Mass Storage Reset, and GET/SET INTERFACE all failed the index check and stalled EP0. Standalone MSC is unaffected (ifnobase == 0), which is why this went unnoticed. 2. usbmsc_deferredresponse() has its entire body inside #ifndef CONFIG_USBMSC_COMPOSITE, so the deferred EP0 status stage for MSRESET/SETINTERFACE was never sent in composite mode and the host's Bulk-Only reset timed out. (Unreachable before fix 1 -- MSRESET used to stall at the wrong-interface check.) Compile the body in composite mode too, but suppress the worker's deferred response for SETCONFIGURATION there: the composite driver answers that request itself, and a duplicate zero-length packet corrupts the EP0 state. 3. usbmsc_cmdfinishstate() stalled the bulk IN endpoint whenever a device-to-host command left a residue, even when the response had already been sent and terminated by a short packet (or ZLP). The stall is BOT-legal (USB MSC BOT 6.7.2) but gratuitous: the short packet already ended the data phase and the residue is reported in dCSWDataResidue. Hosts such as macOS answer any bulk-IN halt during device probing with a full Bulk-Only reset sequence, which costs seconds per command or aborts the probe entirely (macOS probes MODE SENSE(6) with allocation lengths that exceed the response; Linux's probe does not). Only halt the endpoint when nothing terminated the data phase. Root-cause analysis and host traces in apache#19435. Validated on RP2350 silicon (Raspberry Pi Pico 2 W, composite CDC-ACM + CDC-NCM + USBMSC): GET MAX LUN answers 1 LUN (previously EP0 stall and a garbage LUN count on macOS), MSRESET completes 10/10 (previously ETIMEDOUT), MODE SENSE(6) alloc=0xC0 returns short data plus a CSW with dCSWDataResidue and zero bulk-IN stalls across the exact-length suite, and macOS now mounts the volume (together with the companion DCD fixes). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Ricard Rosson <ricard@groundbits.com>
jerpelea
requested review from
acassis,
cederom,
linguini1,
lupyuen and
xiaoxiang781216
August 3, 2026 08:32
xiaoxiang781216
approved these changes
Aug 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Three defects that together prevented macOS from ever mounting a composite USBMSC function (Linux was mostly unaffected because its probe sequence and recovery timing never exercised these paths):
usbmsc_setup() compared the class-request wIndex against the compile-time constant USBMSC_INTERFACEID (= CONFIG_USBMSC_IFNOBASE, i.e. 0) instead of the composite-assigned priv->devinfo.ifnobase. In composite mode the MSC interface number is nonzero, so GET MAX LUN, Bulk-Only Mass Storage Reset, and GET/SET INTERFACE all failed the index check and stalled EP0. Standalone MSC is unaffected (ifnobase == 0), which is why this went unnoticed.
usbmsc_deferredresponse() has its entire body inside #ifndef CONFIG_USBMSC_COMPOSITE, so the deferred EP0 status stage for MSRESET/SETINTERFACE was never sent in composite mode and the host's Bulk-Only reset timed out. (Unreachable before fix 1 -- MSRESET used to stall at the wrong-interface check.) Compile the body in composite mode too, but suppress the worker's deferred response for SETCONFIGURATION there: the composite driver answers that request itself, and a duplicate zero-length packet corrupts the EP0 state.
usbmsc_cmdfinishstate() stalled the bulk IN endpoint whenever a device-to-host command left a residue, even when the response had already been sent and terminated by a short packet (or ZLP). The stall is BOT-legal (USB MSC BOT 6.7.2) but gratuitous: the short packet already ended the data phase and the residue is reported in dCSWDataResidue. Hosts such as macOS answer any bulk-IN halt during device probing with a full Bulk-Only reset sequence, which costs seconds per command or aborts the probe entirely (macOS probes MODE SENSE(6) with allocation lengths that exceed the response; Linux's probe does not). Only halt the endpoint when nothing terminated the data phase.
Root-cause analysis and host traces in #19435.
Validated on RP2350 silicon (Raspberry Pi Pico 2 W, composite CDC-ACM + CDC-NCM + USBMSC): GET MAX LUN answers 1 LUN (previously EP0 stall and a garbage LUN count on macOS), MSRESET completes 10/10 (previously ETIMEDOUT), MODE SENSE(6) alloc=0xC0 returns short data plus a CSW with dCSWDataResidue and zero bulk-IN stalls across the exact-length suite, and macOS now mounts the volume (together with the companion DCD fixes).
Impact
RELEASE
Testing
CI