This repository contains an out-of-tree Linux SCSI workaround and the operational procedure used to make a Framework MicroSD (2nd Gen) Expansion Card reliable as the root filesystem across suspend and resume.
Caution
The patch gives the matching reader fixed-media semantics for one specific media-change response. Never remove or replace the root card while Linux is running or suspended. Keep a current backup, rescue media, and a known-good fallback kernel.
The workaround has been exercised on this exact path:
| Component | Tested value |
|---|---|
| Computer | Framework Laptop 12, Intel, x86_64 |
| Expansion card | Framework MicroSD (2nd Gen) |
| USB identity | 32ac:0026 |
| SCSI inquiry | vendor FRMW, model MicroSD(2nd Gen), revision 0001 |
| Transport | USB Bulk-Only (usb-storage), not MMC and not UAS |
| Root filesystem | XFS on a partition of the reader's SCSI disk |
| Kernel | 6.18.33-gentoo-r1-fw12-sdroot1 |
| Firmware observed | Framework Laptop 12 BIOS 3.07 |
| Suspend path | s2idle (rtcwake --mode mem) |
The device-table match covers every revision reporting the exact SCSI vendor and model above. Other Framework readers, other inquiry strings, hibernation, and S3/deep sleep have not been validated.
On 2026-07-18, the patched kernel completed 20 suspend/resume transitions in the same session that remained in use afterward. The current boot contained:
- 20 kernel suspend entries and 20 exits;
- all four expected SCSI flags:
INQUIRY_36,IGN_MEDIA_CHANGE,SKIP_IO_HINTS, andRETRY_MEDIA_CHANGE; - no
UNIT ATTENTION 28/00, block I/O, changed-device, or XFS shutdown errors; - a successful read-only online
xfs_scrub -n -k /with no corruption or repair requirement.
Six RTC cycles remained asleep for approximately the requested 15 seconds; 14 woke early because of another wake source. All 20 still crossed the kernel suspend/resume path. Use real lid-close tests and longer sleeps in addition to the automated test.
Read the Gentoo procedure completely before changing a bootable kernel. The condensed flow is:
./scripts/install-gentoo-patches.sh --show-config
sudo ./scripts/install-gentoo-patches.shThe tested identities are defaults, not fixed installer inputs. Use the shared
profile and --usb-slot guard when the reader must remain in a particular
Framework expansion bay; see device and slot configuration.
Let a fresh sys-kernel/gentoo-sources install or reinstall apply the files
from /etc/portage/patches/sys-kernel/gentoo-sources/. Configure a uniquely
named kernel with the USB, SCSI, root-filesystem, and suspend drivers built in
or guaranteed in its initramfs. Build and install without overwriting the
fallback kernel, reboot, then check the live quirk flags:
uname -r
for device in /sys/class/scsi_device/*/device; do
printf '%s / %s / %s: ' \
"$(tr -d ' ' < "$device/vendor")" \
"$(sed 's/[[:space:]]*$//' < "$device/model")" \
"$(tr -d ' ' < "$device/rev")"
cat "$device/blacklist"
doneAfter confirming that the Framework reader has all four flags, run the guarded test from a local or otherwise persistent session:
sudo ./scripts/validate-resume.sh 20 15The command needs bash, util-linux (findmnt, lsblk, flock, and
rtcwake), coreutils, and a readable systemd kernel journal. It writes and
fsyncs a temporary probe on / after every resume. A profile that constrains
usb_path also requires udevadm. The test does not exercise lid policy or
desktop suspend hooks.
The reader stays enumerated over suspend, but after some resumes reports SCSI
UNIT ATTENTION, ASC/ASCQ 28/00: not-ready to ready transition, medium may
have changed. Linux normally gives removable media real media-change
semantics. It fails the first request, marks the device changed, and rejects
following I/O until polling clears that state. That is destructive when the
device contains the mounted root filesystem and can make XFS shut down.
The three-patch series applies in order:
- Extend the existing
BLIST_IGN_MEDIA_CHANGEsense clear into the system resume path. - Add
BLIST_RETRY_MEDIA_CHANGE. The normal I/O completion path retries only current-senseUNIT_ATTENTION 28/00; removable-media polling suppresses the changed flag for the same normalized sense tuple. - Opt in the configured SCSI inquiry vendor/model while preserving
SKIP_IO_HINTS. The installer renders this match from the shared profile.
The eager resume clear handles an already-present condition before tasks thaw. The narrowly scoped completion retry handles the observed race where the reader produces the condition about half a second later. Other devices and other sense codes keep their normal behavior.
See the root-cause analysis for the evidence and code path, and the patch notes for applicability limits.
The successful test retained this conservative command-line setup:
rootwait rootfstype=xfs usbcore.autosuspend=-1 \
usb-storage.quirks=32ac:0026:u usbcore.quirks=32ac:0026:k
These flags are not substitutes for the SCSI patches. rootwait covers
asynchronous root-device discovery. Disabling USB autosuspend and link power
management can remove other power-state variables. The u flag disables UAS,
but this reader already uses Bulk-Only transport. Keep the tested command line
for initial validation, then change one variable at a time if simplifying it.
For another reader identity, substitute its configured usb_id; the boot
parameters cannot be constrained to a physical ID_PATH.
patches/contains the ordered kernel patches and checksums.config/device.confcontains the tested device profile.docs/CONFIGURATION.mddocuments every device, physical-bay, target, RTC, and Gentoo package-slot option.docs/GENTOO.mdis the tested Gentoo installation path.docs/GENERIC-LINUX.mdcovers distro-neutral build and early-boot requirements.docs/ROOT-CAUSE.mdrecords the investigation and patch mechanics.docs/TROUBLESHOOTING.mdcovers mismatches, upgrade conflicts, and validation failures.docs/RECOVERY.mdcovers fallback boot and XFS recovery.scripts/collect-diagnostics.shcollects relevant state without intentionally printing storage serial numbers.scripts/install-gentoo-patches.shrenders and installs a profile-specific three-patch series.scripts/validate-resume.shruns guarded resume and root-write tests.
Documentation and helper scripts are covered by the repository's MIT
LICENSE. The kernel patches contain and modify Linux kernel code
and are provided under GPL-2.0-only; see LICENSES/GPL-2.0.