shared/usb: correctly report the SD LUN as removable media by mikeysklar · Pull Request #10967 · adafruit/circuitpython · GitHub
Skip to content

shared/usb: correctly report the SD LUN as removable media#10967

Open
mikeysklar wants to merge 2 commits intoadafruit:mainfrom
mikeysklar:pr-msc-prevent-allow
Open

shared/usb: correctly report the SD LUN as removable media#10967
mikeysklar wants to merge 2 commits intoadafruit:mainfrom
mikeysklar:pr-msc-prevent-allow

Conversation

@mikeysklar
Copy link
Copy Markdown

@mikeysklar mikeysklar commented Apr 22, 2026

What was wrong

The SD card exposed as a USB MSC LUN doesn't mount on macOS. ioreg shows the SCSI nub appears but never progresses to publishing an IOMedia. Linux handles the same firmware fine.

Why: CircuitPython was telling the host "this LUN's medium is always present" for every LUN, including the SD card. On macOS that means "skip TEST_UNIT_READY polling" — so if the SD wasn't ready at the one-shot enumeration probe, macOS never re-checked and gave up on the LUN. Linux ignored the hint and kept polling, which is why it worked there.

@hathach documented this exact macOS behavior back in #6555; the per-LUN distinction wasn't applied at the time.

What changed

Report the SD LUN as removable media, report internal flash and SAVES as non-removable. macOS now keeps polling TUR on the SD LUN and correctly picks up card insertion and removal.

~10 lines in supervisor/shared/usb/usb_msc_flash.c — per-LUN branch on the existing PREVENT_ALLOW_MEDIUM_REMOVAL handler. No RAM or flash cost.

Tested on

Board Result
Feather RP2040 Adalogger (with SD pin defines from #10968) SD mounts first try on macOS 26.x
Metro RP2040 (with SD pin defines from #10968) SD mounts
Metro RP2350 SD mounts, no regression
Fruit Jam (3-LUN: flash + CPSAVES + SD) All three mount; CPSAVES correctly stays non-removable
Linux (Ubuntu 24.04) /dev/sdc + /dev/sdd correct sizes, no regression

Windows not tested.

Related

Credit to @dhalbert for pointing at #6555 and @hathach for the original analysis.

Respond with "unsupported" for the SD LUN (removable media) and OK for
internal flash / SAVES LUNs (non-removable). Responding OK for a
removable LUN tells macOS the medium is always present, and macOS then
skips TEST_UNIT_READY polling. If the SD isn't ready at the single
enumeration probe, macOS never re-checks and LUN 1 fails to publish an
IOMedia node.

Hathach documented this behavior back in adafruit#6555; the SD case wasn't
differentiated at the time.

Fixes adafruit#10965.
Copy link
Copy Markdown
Member

@tannewt tannewt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we want them all removable.

Comment thread supervisor/shared/usb/usb_msc_flash.c Outdated
Per @tannewt review on adafruit#10967: tinyusb advertises is_removable=1 for
every LUN in its default INQUIRY response (msc_device.c line 781), so
the per-LUN branch was inconsistent with what the host already sees.
Collapse to a single unconditional ILLEGAL_REQUEST reply — host keeps
polling TUR on all LUNs, so eject/re-mount works uniformly across
CIRCUITPY, SAVES, and SD.
@mikeysklar
Copy link
Copy Markdown
Author

You're right, thanks — simplifying to apply the unsupported reply to all LUNs.

@mikeysklar
Copy link
Copy Markdown
Author

mikeysklar commented Apr 23, 2026

Quick cross-board, cross-OS regression test of this PR combined with #10963 on main (which already has #10968 merged as a37aaaf).

Board Arch Host OS LUNs enumerated CIRCUITPY mounts SD mounts Readable Regression?
Metro RP2040 (onboard SD) RP2040 macOS 26.x 2 ✅ (ADALOGGER) None
Metro RP2040 (onboard SD) RP2040 Ubuntu 24.04 2 ✅ (ADALOGGER) None
Metro RP2350 (onboard SD) RP2350 macOS 26.x 2 ✅ (ADALOGGER) None
Metro RP2350 (onboard SD) RP2350 Ubuntu 24.04 2 ✅ (ADALOGGER) None

Notes:

@dhalbert
Copy link
Copy Markdown
Collaborator

It would be good to test on Windows as well, and also on boards that are not RP2xxx, such as a PyPortal, and a Metro ESP32-S3 (onboard SD socket), etc. I'm assuming you don't have a Windows box or you would have done so. I could test some of these on Windows.

@bablokb
Copy link
Copy Markdown

bablokb commented Apr 23, 2026

I don't think that reporting /saves as removable is a good idea. Host polling seems to considerable slow down CircuitPython (see #10733). This is why I usually disable CIRCUITPY_SDCARD_USB. I never had problems with the saves-partition though. And from a logical perspective, I don't think it should be removable (of course you can umount it, but there are better ways to shoot yourself in the foot).

@dhalbert
Copy link
Copy Markdown
Collaborator

I don't think that reporting /saves as removable is a good idea.

I agree with this.

@mikeysklar
Copy link
Copy Markdown
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Metro RP2040: SD card LUN never probed by macOS via USB MSC (works on RP2350)

4 participants