ricardgb opened a new issue, #19435:
URL: https://github.com/apache/nuttx/issues/19435

   ## Description
   
   On a composite USB device that includes USBMSC (tested: CDC-ACM + CDC-NCM + 
USBMSC on
   RP2350 / Raspberry Pi Pico 2 W), the Mass-Storage class control requests 
**GET MAX LUN** and
   **Bulk-Only Mass Storage Reset** are answered with an **EP0 STALL** instead 
of the expected
   response. macOS retries GET MAX LUN ~6 times over ~4 s and then, critically, 
reads a
   **garbage LUN count** off the failed control transfer and probes phantom 
LUNs — after which
   the drive never mounts. Linux tolerates the stall (assumes a single LUN) but 
the stall is
   still wrong and observable.
   
   This is **not** rp23xx/rp2040-specific — it is a generic bug in 
`drivers/usbdev/usbmsc.c`
   that affects any composite configuration where the USBMSC interface number 
is not zero.
   
   ## Root cause
   
   `usbmsc_setup()` in `drivers/usbdev/usbmsc.c` validates the target interface 
of the
   class/interface requests by comparing the request's `wIndex` against the 
**compile-time
   constant** `USBMSC_INTERFACEID`:
   
   ```c
   #define USBMSC_INTERFACEID (CONFIG_USBMSC_IFNOBASE + 0)   /* usbmsc.h, == 0 
by default */
   ```
   
   But in composite mode the USBMSC interface number is **assigned 
dynamically** by the
   composite core and stored in `priv->devinfo.ifnobase`. The configuration 
descriptor is built
   from that dynamic value:
   
   ```c
   /* usbmsc_desc.c */
   dest->ifno = devinfo->ifnobase;   /* interface descriptor advertises the 
real ifno */
   ```
   
   So the host correctly directs GET MAX LUN / MS-RESET / GET&SET-INTERFACE to
   `wIndex == devinfo.ifnobase` (interface 4 in my composite layout), but 
`usbmsc_setup()`
   checks `index != USBMSC_INTERFACEID` (4 != 0) → `ret = -EDOM` → the USB 
driver stalls EP0.
   
   Four comparisons in `usbmsc_setup()` are affected (SET_INTERFACE, 
GET_INTERFACE, MSRESET,
   GETMAXLUN); all use `USBMSC_INTERFACEID` where they should use 
`priv->devinfo.ifnobase`.
   
   In the standalone (non-composite) case `ifnobase == CONFIG_USBMSC_IFNOBASE`, 
so the two are
   equal and the bug is invisible — which is why it has gone unnoticed.
   
   ## Fix
   
   ```diff
   -                if (index != USBMSC_INTERFACEID)
   +                if (index != priv->devinfo.ifnobase)
   ```
   
   applied to the MSRESET and GETMAXLUN handlers (and the matching `==` test in 
the
   GET/SET_INTERFACE handlers). Full diff below.
   
   ## Reproduction and validation (RP2350, Raspberry Pi Pico 2 W, silicon; 
Linux host, usbmon)
   
   Composite layout places USBMSC at interface 4. Forcing a fresh SCSI probe on 
Linux
   (`echo 3-4:1.4 > /sys/bus/usb/drivers/usb-storage/unbind`, then `bind`) and 
capturing usbmon:
   
   **Before the fix** — GET MAX LUN stalls:
   ```
   S Ci:3:007:0 s a1 fe 0000 0004 0001 1 <     # GET MAX LUN, bmRequestType a1, 
wIndex=4
   C Ci:3:007:0 -32 0                           # -EPIPE / EP0 STALL, 0 bytes
   ```
   
   **After the fix** — GET MAX LUN succeeds:
   ```
   S Ci:3:010:0 s a1 fe 0000 0004 0001 1 <
   C Ci:3:010:0 0 1 = 00                         # 1 byte returned, value 0x00 
= 1 LUN
   ```
   
   No regression: the FAT drive still mounts/reads, CDC-NCM and CDC-ACM are 
unaffected, and
   cold re-enumeration is clean.
   
   ## macOS impact (the motivating symptom)
   
   On macOS the composite's network + serial come up but **no disk device is 
ever created**.
   The kernel log shows GET MAX LUN stalling (`endpoint 0x00: status 0xe0005000 
(pipe stalled)`)
   6×, then `Max LUNs reported as 28 with 0xe0005000` — macOS reads a junk LUN 
count from the
   stalled transfer — after which a bulk-IN **babble error** on `0x87` right 
after READ CAPACITY
   sends IOUSBMassStorageDriver into a reset/retry loop that gives up. The 
babble does not
   reproduce on Linux (Linux never mis-reads the LUN count). The working 
hypothesis is that the
   babble is downstream of the phantom-LUN probing caused by the GET MAX LUN 
stall; a Mac
   re-test of the fixed image is in progress. Either way the GET MAX LUN stall 
is a real,
   independently-confirmed bug and the correct first fix.
   
   ## Related
   
   Same driver family and hardware as #19434 (rp2040/rp23xx cold-plug pull-up 
loss). This one
   is in the generic `drivers/usbdev/usbmsc.c` layer rather than the arch USB 
driver.
   
   ## Environment
   
   - NuttX board branch tracking recent master; `drivers/usbdev/usbmsc.c`, 
`usbmsc_desc.c`,
     `usbmsc.h`.
   - RP2350, Raspberry Pi Pico 2 W, composite CDC-ACM + CDC-NCM + USBMSC 
(USBMSC at interface 4).
   - Hosts: Linux (usbmon/sg_raw, reproduced + fix-validated), macOS 
(motivating symptom).
   
   ## Disclosure
   
   This investigation, root-cause analysis, and the tested fix were performed 
by an AI agent
   (Claude Code), operated and directed by the submitter, and the results were 
reviewed by the
   submitter before posting. Happy to provide the full usbmon captures, the 
macOS kernel-log
   excerpts, or test any proposed alternative fix on hardware.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to