ricardgb opened a new pull request, #19452:
URL: https://github.com/apache/nuttx/pull/19452

   # PR 3 — rp2040/rp23xx: implement stall queueing and GET STATUS responses
   
   Branch: `rp2040-rp23xx-stallqueue-getstatus` (worktree 
`~/nuttxspace/wt-pr-stallq`)
   Base: apache/nuttx master (1b6f918c3f)
   References: #19435 (bugs 5 and 6 of that report)
   
   ## Summary
   
   Two device-controller (DCD) defects in `rp2040_usbdev.c` / `rp23xx_usbdev.c`
   that break standard host error recovery. Either one alone is fatal to macOS
   mass-storage mounting; both are invisible to Linux hosts, whose SCSI stack
   neither sends the triggering requests nor recovers with the triggering
   timing.
   
   ## Fix 1: stall queueing (the lost-CSW race)
   
   `epsubmit()` aborted (-EBUSY) any IN request submitted while the endpoint was
   halted. The mass-storage class halts bulk-IN for a failed device-to-host
   command (BOT-legal) and then submits the CSW — which was silently dropped, so
   after the host's Clear-Halt the endpoint NAKed forever and the host timed out
   (macOS: 30 s, then a Bulk-Only-reset/device-reset spiral until it disables
   the port). This is exactly the race documented for years in the
   `usbmsc_scsi.c` header comment (David Hewson's analysis: "the subsequent
   transfer for the CSW would be dropped on the floor (by the epsubmit()
   function) if the end point was still stalled"). The `USBMSC_STALL_RACEWAR`
   sleep workaround only survives hosts that clear the halt within its 100 ms
   window — Linux does, macOS does not.
   
   This PR implements the stall-queueing contract that
   `CONFIG_ARCH_USBDEV_STALLQUEUE` documents (and that `usbmsc_scsi.c` has been
   waiting on):
   
   - `epsubmit()`: requests submitted while an endpoint is halted are queued
     without arming the hardware (IN and OUT — arming an OUT endpoint rewrites
     the DPSRAM buffer-control word and would silently clear the STALL bit).
   - `epstall(stall)`: cancels any in-flight IN transfer (its hardware buffer is
     disarmed by the STALL write and would otherwise never complete).
   - `epstall(resume)`: resets the data toggle (USB 2.0 9.4.5) and re-arms the
     head of the request queue — this is what delivers the queued CSW.
   - Buffer-status IRQ: completions latched for transfers aborted by a halt are
     ignored instead of being attributed to post-halt queued requests.
   - `arch/arm/Kconfig`: RP2040/RP23XX now `select ARCH_USBDEV_STALLQUEUE`,
     which retires the RACEWAR's two 100 ms sleeps per failed command.
   - The now-unused `*_abortrequest()` helpers are removed.
   
   ## Fix 2: GET STATUS was never answered
   
   The `USB_REQ_GETSTATUS` case in `*_ep0setup()` validated the request but
   never queued the two-byte response — for all three recipients
   (device/interface/endpoint). EP0 then NAKs the host's data-IN stage forever
   and every GET STATUS times out. macOS issues GetPipeStatus = GET
   STATUS(endpoint) on a halted pipe ~50 ms after the stall, before Clear-Halt,
   and hit this on every probe; `lsusb -v`'s device-status query hangs on it
   too. The handler now sends the response (endpoint: halt bit; device:
   self-powered; interface: zeros) via `epwrite(ep0, response, 2)`, with the
   status stage armed by `handle_zlp()` exactly as for class-dispatched IN
   transfers.
   
   ## Validation
   
   - **RP2350 (Raspberry Pi Pico 2 W) hardware, composite CDC-ACM + CDC-NCM +
     USBMSC, Linux host, raw-usbfs replay of macOS's exact commands and
     timing:**
     - Pre-fix repro, deterministic: CBW (failing MODE SENSE page 0) → data-IN
       stall → wait 1 s → clear-halt → **CSW read ETIMEDOUT** (fix 1); all five
       GET STATUS variants **ETIMEDOUT after 1.5 s** (fix 2).
     - Post-fix: CSW survives the halt and is delivered after Clear-Halt with
       correct tag/status/residue across a **post-stall delay sweep of
       0/30/50/80/150/500/1000 ms** in macOS's recovery order (GetPipeStatus →
       clear-halt → GET STATUS → CSW), with the halt bit correctly reported as
       1 before and 0 after the clear; all GET STATUS variants answer in <1 ms.
     - Full macOS-equivalent BOT probe replay ×5 cycles: zero failures. No
       regressions: exact-length SCSI suite, GET MAX LUN + Bulk-Only reset
       10/10, FAT mount + full reads, CDC-NCM/ACM, warm reboots.
     - **End-to-end: macOS now mounts the volume** (together with the companion
       usbmsc fixes in the separate class-driver PR). The success log shows the
       expected one-time transient bulk-IN halts each cleanly recovered, and no
       EP0 timeouts/resets/port-disable.
   - **RP2040:** identical shared code, identical fix; build-tested
     (raspberrypi-pico:usbnsh and raspberrypi-pico:composite, the latter
     compiling usbmsc with ARCH_USBDEV_STALLQUEUE in effect). No RP2040
     hardware validation performed.
   
   Full failure chronology, host traces, and the silicon A/B evidence are in
   #19435.
   
   ## Impact
   
   Any class driver that stalls an endpoint and expects queued requests to
   survive (mass storage is the canonical case). GET STATUS affects every
   configuration — any host or tool that sends it got a control timeout.
   With ARCH_USBDEV_STALLQUEUE selected, usbmsc also stops sleeping 200 ms per
   failed command (RACEWAR retired).
   
   ## AI disclosure
   
   This investigation and the fixes were performed by an AI agent (Claude Code),
   operated and directed by the submitter, and reviewed by the submitter before
   posting.
   


-- 
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