v2026.04.19-dev
Pre-release
Pre-release
·
81 commits
to main
since this release
BlueSCSI-v2 Release Notes — v2026.04.19-dev (prerelease)
This release brings a new build system, a much simpler firmware update flow, broader SCSI command coverage, and a long list of fixes across CD-ROM, CD audio, tape, DaynaPORT, initiator mode, and the Ultra/Ultra Wide hardware.
Important
Users should use the uf2 update method for this release to get the latest boot loader improvements.
New Features
Firmware update & logging
- Universal firmware ZIP —
firmware_update()scans the SD card root forBlueSCSI_v*.zip, extracts the target-specific.bin, and hands it to the bootloader. Same ZIP works for every board. (cb61c37 — @erichelgeson) - Shared bootloader log — a 2 KB NOLOAD region at the top of RAM survives the reset from bootloader into main firmware, so firmware-update log lines are no longer lost. (cb61c37 — @erichelgeson)
lastlog.txt— previous session'slog.txtis renamed tolastlog.txton first boot before the new log starts, so the prior run is always recoverable. (cb61c37 — @erichelgeson)
BlueSCSI Toolbox
SET_WORKING_DIR(subcommand 0x02) — Toolbox clients can point file operations at the SD card root (or any directory) for firmware uploads and file management. (24bbc20 — @erichelgeson)GET_WORKING_DIR(subcommand 0x03) — returns the currently effective directory as a null-terminated string so clients can display it. (25fdaa6 — @erichelgeson)- New capability flag
CAP_SET_WORKING_DIR(bit 2, 0x04) lets clients detect support. (24bbc20, 25fdaa6 — @erichelgeson)
SCSI commands
- READ(12)/WRITE(12), READ(16)/WRITE(16), READ CAPACITY(16) — proper dispatch for the 12- and 16-byte disk commands. (c4f8a73 — @reinauer)
- VERIFY(10/12/16) — medium scan (BYTCHK=0) and byte-compare (BYTCHK=1) both implemented. (c4f8a73 — @reinauer)
- WRITE AND VERIFY(10/12/16) — data is written and re-read to confirm the sectors match. (c4f8a73 — @reinauer)
- MODE SENSE Verify Error Recovery page (07h) — optional SCSI-2 §9.3.3.8 page 07h (page length 0Ah, verify retry count 1, other fields zero), returned only in SCSI-2 mode. Some vintage OSes expect this page when requesting all pages (0x3F). (318a1c1 — @erichelgeson)
- MODE SENSE Notch and Partition page (0Ch) — optional SCSI-2 §9.3.3.5 page 0Ch with all fields zero, indicating a non-notched drive. Returned only for SCSI-2 direct-access devices (excluded from optical and sequential). (1e1a1a5 — @erichelgeson)
- Trace log coverage for new commands — SCSI trace output shows names for
Read16,Write16,Verify16,WriteVerify16,ServiceActionIn16,Write12,Verify12,WriteVerify12. (8bcc3c8 — @PetteriAimonen)
Initiator mode
- Fixed VHD image output — with
InitiatorVHD=1inbluescsi.ini, imaged drives are saved as Microsoft Fixed VHD files with a conforming 512-byte footer, directly mountable in Windows/QEMU/VirtualBox. (e7ebcab — @erichelgeson)
Diagnostics
- Hardware stack overflow protection (RP2350) —
MSPLIMis set on both cores with 32 bytes of exception-frame headroom; overflows now crash-dump instead of corrupting RAM. (20823c9 — @erichelgeson) - Enhanced hardfault logging — CFSR/HFSR/MMFAR/BFAR are decoded into human-readable fault conditions on RP2350. (20823c9 — @erichelgeson)
- SD card OID decoded in log — the card identification line now prints the 2-byte OID as ASCII alongside the resolved manufacturer name, making it easier to identify the exact card in a user's log. (ad1494a — @erichelgeson)
Bug Fixes
CD-ROM & CD audio
- SPDIF crash on multi-BIN CUE sheets (#353) —
selectImageFile()no longer allocates FastSeek for metadata-only opens, anddoReadTOC/doReadFullTOC/doReadTrackInformationstop audio before switching BIN files. (8b06063 — @erichelgeson) - SPDIF reported wrong LBA on READ SUB-CHANNEL / PLAY AUDIO (#353) — the audio position math now accounts for each track's
file_offsetanddata_start, so multi-BIN CUEs and tracks with unstored PREGAP report correct LBAs. (a2835e6 — @erichelgeson) - SPDIF PLAY AUDIO seek wrong for tracks with PREGAP —
doPlayAudionow usesdata_startinstead oftrack_start, fixing audio on discs like Tatsujin Ou (FM Towns) where Track 2 hasPREGAP 00:02:00. (b2f2fda — @erichelgeson) - Track boundary correctness — added
cdrom_track_end_lbaso READ CD splits transfers at track boundaries on multi-track discs instead of conflating BIN file size with track extent. (8f7e389 — @reinauer / @erichelgeson) - READ HEADER (0x44) — parses LBA from CDB bytes 2-5 instead of always returning data for LBA 0; audio-track mode is written to the correct variable. (8f7e389 — @reinauer / @erichelgeson)
- READ CD I/O errors —
seek()/read()failures now return CHECK CONDITION with MEDIUM ERROR / CIRC UNRECOVERED ERROR instead of silently returning corrupt data. (8f7e389 — @reinauer / @erichelgeson) - WRITE AND VERIFY (0x2E) — returns ILLEGAL REQUEST on CD-ROM instead of silently performing an unverified write. (8f7e389 — @reinauer / @erichelgeson)
getTrackFromLBA()without track_end_lba — corrected fallback for discs where the track end isn't known up-front. (389ce31 — @PetteriAimonen)- Stale
cdrom_track_end_lbaacross image changes — reset on CUE sheet reload and folder-based CD init. (b250f35 — @erichelgeson) - Audio playback after CD change — stale cached
trackinfofrom the previous disc no longer causes read errors on the next disc;doSeek's audio call is guarded bybin_container.isOpen(). (b2ea073 — @morio) - Audio with multiple CD-ROM drives — new play command stops all audio (
id=0xFF) and reloads the cue when the audio owner changes;audio_last_statusindexes by owner, not by passed id. Bus reset also stops audio. Applied to both I2S and SPDIF. (87cbe5b — @morio) - Audio array sizing for wide SCSI — 8-entry audio arrays now sized for 16-target wide boards; ID masks corrected. (5611fc4 — @morio)
- Eject wrapping on multi-BIN/CUE — eject button now compares the container directory name instead of the inner BIN filename, so multi-BIN discs wrap back to the first image. (30ed064 — @morio)
Tape drive
- SPACE now uses absolute position and signed 24-bit count — per SCSI-2 §10.2.11, SPACE is relative to the current position and the count is two's-complement (negative = reverse). Previous code used an unsigned count and set
tape_pos = count(absolute). (79432e3 — @erichelgeson) - Variable-block READ underlength/overlength conditions — conditions were swapped. Per SCSI-2 §10.2.4 overlength is not an error; only underlength errors, and only when SILI is clear. (e4d81d4 — @erichelgeson)
- READ BLOCK LIMITS bad LSB byte —
data[5]duplicateddata[4], reporting min=0x0202 for 512-byte blocks. (7bdd5a8 — @erichelgeson) - SPACE CDB byte extraction — was reading a 32-bit count across CDB[2-5] including the control byte. Now a proper 24-bit extract from CDB[2-4]. (7bdd5a8 — @erichelgeson)
- Variable-block READ/WRITE with transfer length 0 — per SCSI-2 §10.2.4 and §10.2.14, a zero transfer length is explicitly "not considered an error"; no data shall be transferred and the tape position is unchanged. (b6ed6b1 — @erichelgeson)
DaynaPORT / network
- AppleTalk slow under Virtual Memory on System 7 (#346) — multi-packet READ(6) is now gated on CDB byte 5 bit 6 (polled mode = 1 packet, blind mode = batched). Bus hold time stays short when the host's VM pager also needs bus access. Transfer size now respects the host's allocation length in CDB[3-4]. (7c20579 — @erichelgeson)
- Global INI strings no longer break DaynaPORT/AmigaWiFi — vendor/product/revision set under
[SCSI]inbluescsi.iniare skipped for network devices, which require specific IDs for their drivers. Per-device[SCSIn]overrides still apply. (9f795a7 — @morio) - WiFi (DaynaPORT) restored on CMake build — after the PlatformIO → CMake migration, CYW43 compiled from source needs
PICO_CYW43_SUPPORTED=1,CYW43_WARN=//,cyw43_arch_poll()inplatform_poll(), and our owncyw43_tcpip_link_status(). Tested on Pico 1W / Pico 2W with open and WPA2 networks. (4af22d7 — @erichelgeson) - Ultra / Ultra Wide WiFi with GCC 14 — custom board headers and
pico-sdk-internal v2.2.0-UltraSupport-rel2work around a pico-sdk write-buffer ordering bug on Cortex-M33 that broke CYW43 SPI on Ultra hardware. (b0e1a4e, 79df606 — @erichelgeson)
Initiator mode
- USB MSC initiator no longer overrides hardware switch — when the SD card is absent, the hardware initiator switch setting is respected instead of being forced by USB MSC. (290f513 — @erichelgeson)
- Ultra initiator mode on some drives — timing tweak so initiator mode works against drives that were previously flaky on Ultra hardware. (2007324 — @androda)
SCSI core
- WRITE to read-only media returns DATA_PROTECT — per SCSI-2 §9.1.12 and Table 69, WRITE PROTECTED (ASC 0x2700) pairs with sense key DATA_PROTECT (0x07), not ILLEGAL_REQUEST (0x05). Some hosts branch on the sense key to distinguish "bad CDB" from "media write-protected" and retried incorrectly. (b9bd4af — @erichelgeson)
- REQUEST SENSE Valid bit only when Information field is meaningful — Valid (0x80) was set unconditionally and the Information field was always populated with
transfer.lba, even for sense keys like ILLEGAL_REQUEST or UNIT_ATTENTION where no block address applies. Per SPC-2 §7.20, only MEDIUM_ERROR, HARDWARE_ERROR, and ABORTED_COMMAND now report Valid=1 with the LBA; other keys return error code 0x70 with a zeroed Information field. (f7feb1d — @erichelgeson) - MODE SENSE reserved CDB byte 3 — non-zero values in the reserved byte (SPC-3+ SUBPAGE CODE) are now rejected per SCSI-2 §8.2.10/8.2.11 and SPC-2 §7.8/7.9, returning CHECK CONDITION / ILLEGAL REQUEST / INVALID FIELD IN CDB. (f914e04 — @erichelgeson)
- Packed
scsiIdfield safety —S2S_TargetCfg::scsiIdpacks ID in bits 0-2 and theTARGET_ENABLEDflag in bit 7. Introduced typed accessors and fixed a prefetch cache comparison that was missing the mask, causing bogus invalidations when the enabled flag differed between operands. (826b981 — @erichelgeson) scsiLogDataOutNULL buffer crash — data-out trace logging no longer crashes when the buffer pointer is NULL. (beaada1 — @morio)- Stack overflow returning to IMG0 — refactor avoids the recursion that overflowed the stack when cycling back to the first image. (49b319f — @NT2MKU)
- Stack overflow during image init (RP2350) — stack sized and laid out to fit Audio SPDIF's peak usage. (887508b, 1851c05 — @erichelgeson)
- ROM drive flash-write crash on Ultra with WiFi — core1 mutex now protects flash writes during ROM drive loading so WiFi code on the other core can't be interrupted mid-flash. (15b7d10 — @PetteriAimonen)
delay_ns()sub-microsecond accuracy — was rounding up by a full microsecond, making RST glitch-filter timing up to ~2× too long. Now cycle-accurate. (b2a0584 — @erichelgeson)
Timing / sync negotiation
- Sync rate alignment with target timing — synthesize the sync offer from the actual PIO transfer period so we advertise rates we can sustain. (4df54b5 — @reinauer)
- Custom timing overrides hardened — INI timing overrides are bounds-checked and validated before applying, so partial bad configs no longer take effect. (830acb4 — @reinauer / @erichelgeson)
- Lowered DMA read-pacer floors — faster sync: RP2350 14→13 cycles (~19 MB/s at 252 MHz), RP2040 18→15 cycles (~16.7 MB/s at 252 MHz). RP2040 18 had caused a 16→10 MB/s regression. (18283f0 — @erichelgeson)
- Overclocking suggestion threshold — only logged when sync speed is 10 MB/s, not at lower speeds. (f534dbf — @erichelgeson)
- TurboMax clk_hz corrected — 252 MHz → 250 MHz (an accidental change in 75d0b6b0). (74c61a0 — @erichelgeson)
SD card & storage
- SD card hot-plug with multi-BIN/CUE —
scsiDiskCloseSDCardImages()now closesbin_containerand resetsimage_directory, so "Already found an image directory, skipping..." no longer prevents images from loading after re-insertion. (e44445d — @morio) - Geometry warning suppressed for >8 GB images — no more spurious C/H/S warnings on large disks. (f301988 — @erichelgeson)
BlueSCSI Toolbox
- Shared dir creation before file ops —
onSendFilePrep,doCountFiles, andonListFilesnow create the shared directory if missing and return CHECK CONDITION on failure, instead of silently writing to the SD root or continuing with no directory open. (581c6c7 — @erichelgeson)
Bootloader & boot
- RP2350 bootloader XIP cache guard — corrected a wrong
#definename that left the cache unguarded during bootloader flash operations. (455510a — @erichelgeson) - Bootloader log replay garbage —
log_raw(buffer, len)was resolving to a template that printed the buffer as a string plus the length as hex (e.g..0x000000A2) instead of a fixed-length copy. (ecb2ee5 — @erichelgeson) - USB serial log missing on RP2040 — the CMake migration dropped Arduino-Pico's background USB timer, starving CDC enumeration during setup. A 1 ms repeating timer alarm now pends a software IRQ that calls
tud_task()under__usb_mutex. Early-boot logs reach the serial console again. (7655af0 — @erichelgeson) - Build timestamp showed "Jan 1 1980" — Nix's
SOURCE_DATE_EPOCHwas feeding__DATE__/__TIME__the epoch. Now unset in the dev shell so firmware reports the real build time. (30ba8b1 — @erichelgeson)
Improvements
- Faster CD sector reads — when
skip_begin == 0(contiguous layout) we seek once before the transfer loop instead of per sector. (0d9ded1 — @reinauer / @erichelgeson) - Quieter Vdd warnings — voltage-drop warnings deferred by ~1 s, suppressing noise during power-off and brief dips. (1b9bcc4 — @erichelgeson)
- C++ exception bloat eliminated — 31.8 KB of unused C++ exception tables trimmed from the RP2040 image, plus improved flash/RAM symbol placement. (81738d2 — @erichelgeson)
- Static stack usage analysis in CI — build pipeline now flags functions with large stack frames before they reach hardware. (2aa6130 — @erichelgeson)
- Application code built at
-O2— switched from-Osfor better throughput on hot paths. (cb4da9e — @erichelgeson)
Build & infrastructure (user-visible)
- CMake + Nix flake build system — replaces PlatformIO.
./build.shin anix developshell builds any target. See BUILDING.md. (1c41f99 — @erichelgeson) - Release / pre-release tag handling — firmware build workflow now distinguishes release vs. pre-release tags for cleaner release management. (315b208 — @erichelgeson)
minGlue.hinclude guard — adds#ifndef MINGLUE_Hso test stubs can shadow the header; unblocks x86 unit testing for minIni glue. (4a3a15e — @erichelgeson)- macOS build support — flake and build scripts updated so macOS hosts can build the firmware. (8d1794b — @erichelgeson)
- Pico SDK pinned to
v2.2.0-UltraSupport-rel2— includes the upstream CYW43 SPI driver, PIO0 force for RP2040, and clock GPIO function fix. (79df606 — @erichelgeson) - PlatformIO/Arduino remnants removed — leftover board JSON files, build scripts, and library manifests cleaned up. (e291c2e — @erichelgeson)
- Handle new
bootloader_sizein linker scripts — needed for the reshaped bootloader with shared log region. (39aee65 — @erichelgeson) - PR memory-usage comment — CI posts a memory diff against the latest GitHub release on each PR. (db5dbe9 — @erichelgeson)
Contributors
@androda · @degrunert · @erichelgeson · @morio (J. Morio Sakaguchi) · @PetteriAimonen · @reinauer (Stefan Reinauer)
Commits
CD-ROM, CD audio, image handling
8b060639cdrom: fix SPDIF crash from heap exhaustion on multi-BIN CUE sheets (issue #353) — Eric Helgesona2835e6ecdrom: fix SPDIF READ SUB-CHANNEL / seek wrong LBA (issue #353) — Eric Helgesonb2f2fda6fix: SPDIF PLAY AUDIO uses wrong offset for tracks with PREGAP — Eric Helgeson8f7e389aFix CD-ROM and disk command correctness — Eric Helgeson (co-authored Stefan Reinauer)0d9ded17Reduce seek overhead in CD sector reads — Eric Helgeson (co-authored Stefan Reinauer)389ce314cdrom: Fix getTrackFromLBA() when track_end_lba is not given — Petteri Aimonenb250f357fix: add missing cdrom_track_end_lba resets in CUE sheet paths — Eric Helgesonb2ea0739Fix audio playback after CD change and stale trackinfo cache — John Morio Sakaguchi87cbe5b1Fix audio playback with multiple CD-ROM drives — J. Morio Sakaguchi5611fc4aFix audio array sizing and ID masks for wide SCSI support — J. Morio Sakaguchi30ed0641Fix eject wrapping back to the first image for multi-bin/cue — John Morio Sakaguchie44445d1Reset image_directory and bin_container on SD card close — John Morio Sakaguchif3019883Skip geometry warning for images larger than 8 GB — Eric Helgeson
Tape
79432e34fix: tape SPACE command uses absolute position and unsigned count — Eric Helgesone4d81d49fix: tape variable-block READ underlength/overlength conditions swapped — Eric Helgeson7bdd5a86fix: tape READ BLOCK LIMITS and SPACE CDB byte extraction bugs — Eric Helgesonb6ed6b14tape: accept transfer length 0 as no-op in variable-block READ/WRITE — Eric Helgeson
Disk / SCSI core commands
c4f8a730Add 12/16-byte disk commands and VERIFY/WRITE AND VERIFY support — Stefan Reinauer8bcc3c86logging: Add missing 12- and 16-byte command names — Petteri Aimonen826b981afix: add safe accessors for packed scsiId field, fix prefetch comparison bug — Eric Helgesonbeaada14Fix scsiLogDataOut logging with NULL buffer — J. Morio Sakaguchi49b319fcFix stack overflow during image selection back to IMG0 — Dennis Grunert1e1a1a51MODE SENSE: Add Notch and Partition page (0Ch) — Eric Helgeson318a1c14MODE SENSE: Add Verify Error Recovery page (07h) — Eric Helgesonf914e04cMODE SENSE: Reject non-zero reserved CDB byte 3 — Eric Helgesonf7feb1dbscsi: only set Valid bit in REQUEST SENSE when Information field is meaningful — Eric Helgesonb9bd4af5scsi: WRITE to read-only media returns DATA_PROTECT sense key — Eric Helgeson
Initiator mode
e7ebcab0Add Fixed VHD image output to initiator mode — Eric Helgeson20073247Ultra: Fix issue with initiator mode on some drives — androda290f513cfix: USB MSC initiator mode no longer overrides hardware switch when SD absent — Eric Helgeson
DaynaPORT / WiFi / network
7c205792fix: gate DaynaPORT multi-packet READ(6) on CDB byte 5 bit 6 — Eric Helgeson9f795a73Ignore global INI SCSI strings for network devices — John Morio Sakaguchi4af22d79fix: Restore WiFi (DaynaPORT) for CMake build on all Pico W variants — Eric Helgesonb0e1a4e5fix: Ultra/Ultra_Wide RM2 WiFi with custom board headers and GCC 14 — Eric Helgeson79df6065build: Update pico-sdk-internal to v2.2.0-UltraSupport-rel2 — Eric Helgeson
Toolbox
24bbc205toolbox: add SET_UPLOAD_DIR subcommand for firmware updates — Eric Helgeson25fdaa66toolbox: rename SET_UPLOAD_DIR to SET_WORKING_DIR, add GET_WORKING_DIR — Eric Helgeson581c6c7ffix: toolbox creates shared dir before file operations — Eric Helgeson
Timing / sync / performance
4df54b56Align RP2 sync negotiation with target timing — Stefan Reinauer830acb41Harden RP2 custom timing overrides — Eric Helgeson18283f09scsi: lower DMA read-pacer floors for faster sync negotiation — Eric Helgesonb2a0584cFix delay_ns() to be cycle-accurate for sub-microsecond values — Eric Helgeson74c61a04fix: correct TurboMax clk_hz from 252MHz to 250MHz — Eric Helgesonf534dbf1fix: only suggest overclocking when sync speed hits 10 — Eric Helgesoncb4da9e8build: switch application code from -Os to -O2 — Eric Helgeson1b9bcc4cDefer Vdd voltage drop warnings to reduce log noise — Eric Helgeson
Bootloader / boot / logging
cb61c370feat: universal zip firmware update, shared bootloader log, and lastlog.txt — Eric Helgeson455510afFix RP2350 bootloader XIP cache guard using wrong define name — Eric Helgesonecb2ee5afix: bootloader log replay printing garbage after content — Eric Helgeson7655af0dfix: add background USB timer for reliable CDC enumeration on RP2040 — Eric Helgeson30ba8b11fix: unset SOURCE_DATE_EPOCH so DATE/TIME show real build time — Eric Helgeson39aee652Handle new bootloader_size in ld scripts — Eric Helgesonad1494a0log: decode SD card OID as ASCII and add manufacturer name — Eric Helgeson
Safety / diagnostics
20823c98Add hardware stack overflow protection and enhanced crash diagnostics for RP2350 — Eric Helgeson887508b6fix: stack overflow crash on RP2350 during image init — Eric Helgeson1851c056fix: reduce RP2350 stack to 3KB for Audio SPDIF compatibility — Eric Helgeson15b7d107Add core1 mutex to protect flash writes during ROM drive loading — Petteri Aimonen81738d22fix: eliminate 31.8 KB C++ exception bloat and improve RP2040 symbol placement — Eric Helgeson2aa6130bbuild: add static stack usage analysis to build pipeline — Eric Helgeson
Build system / CI / docs
315b2080build: Allow for better release/pre-release management with tags — Eric Helgeson4a3a15e6build: add include guard to minGlue.h for testability — Eric Helgeson1c41f993build: migrate from PlatformIO to CMake with Nix flake — Eric Helgeson8d1794bbbuild: Add macOS support and fix build gotchas — Eric Helgesone291c2ebfix: Remove last of PlatformIO & Arduino — Eric Helgesonae0041d5build: Fix build after rebase on cmake — Eric Helgesondb5dbe93ci: add PR memory usage comment — Eric Helgesonf62c6946ci: enable cachix push with auth token — Eric Helgeson0aa11900ci: bump sticky-pull-request-comment to v3 — Eric Helgeson329e2334build: upgrade GitHub Actions to Node.js 24 compatible versions — Eric Helgeson69b61321build: prevent duplicate CI runs on PR branches — Eric Helgeson591224c2build: update analyze_crashlogs workflow to ubuntu-latest and checkout v4 — Eric Helgesonb69d1185build: add --clobber to tag release upload fallback — Eric Helgesonf4d3a728build: nix flake update — Eric Helgeson9e972ed7docs: add CMakePresets.json for IDE integration — Eric Helgeson9b508c0adocs: Update to reference Ultra/Ultra Wide — Eric Helgesonf71cd891docs: Add manual cmake setup in addition to nix — Eric Helgeson5017ee45docs: Add back missing images — Eric Helgeson3079692adev — Eric Helgeson