Bringing an Endangered Drobo 5D Back to Life via Custom DriverKit and Rust
The Drobo 5D’s hardware remains intact—five Thunderbolt 2 bays paired with hardware RAID—even after Apple’s macOS 12.3 changes killed kernel extensions. Without Data Robotics’ proprietary driver transitioning to DriverKit, the device’s legacy kext vanished, leaving only a broken connection. Instead of shelling out $800 for Synology, I spent three weekends collaborating with Claude Code to reverse-engineer the hardware and craft a new IOKit bridge.
To diagnose the disconnect, I examined Thunderbolt’s SCSI-over-Thunderbolt protocol, which the kext once exposed via /dev/drobo* character devices. The Thunderbolt controller still enumerates, but diskutil list reveals nothing. A simple check in IORegistry confirms the device exists—only its block storage node remains missing:
$ ioreg -l -p IOService | grep -i drobo
| | | +-o IOThunderboltDevice <class IOThunderboltDevice, id 0x1000003b5, registered, matched, active, busy 0 (0 ms), retain 7>
| | | | +-o DROBO 5D <class IOThunderboltDevice, id 0x1000003b6, registered, matched, active, busy 0 (0 ms), retain 6>
The first step was extracting the command set from the old kext’s strings. Claude parsed the output, revealing critical codes like 0xC1 (get array status), 0xC2 (read capacity), and 0xC3 (read blocks). Each command follows a 16-byte header with little-endian LBA and block counts. [Full command table linked here.]
To bypass Swift’s kernel boundary limitations, I built a DriverKit skeleton with Claude’s help. The IOUserClient subclass now handles vendor-specific CDB conversions, though scatter-gather I/O required manual fixes in memory descriptor mapping. The generated IOExternalMethodDispatch table hit 90% accuracy on the first try, leaving only minor tweaks for byte-swapping discrepancies between Drobo’s big-endian firmware and SCSI’s little-endian standard.
For userspace logic, Rust provided zero-cost abstractions. The daemon leverages io_connect_method_structureI_structureO to bridge the client and kernel, processing commands like 0xC3 (read) and 0xC4 (write) in a structured manner:
fn submit_cdb(conn: io_connect_t, cdb: &[u8; 16], data: &mut [u8]) -> kern_return_t {
let mut input = DroboCommandInput { cdb: *cdb, data_len: data.len() as u32 };
// ... rest of the submission logic
}
The daemon exposes an NBD socket, enabling nbdkit to present /dev/nbd0 to macOS. After compiling and loading the driver, diskutil list finally shows the array. A filesystem repair (fsck_apfs -y /dev/disk4) and mount (mount_apfs /dev/disk4s1 /Volumes/Drobo) restored the full 16 TB of data.
Key pitfalls included Thunderbolt’s 30-second idle power drop, which the daemon now mitigates with a 0xC1 heartbeat every 15 seconds. Byte-swap mismatches between Drobo’s big-endian CDBs and macOS’s little-endian SCSI layer also required careful handling in the user client. Finally, DriverKit entitlements—com.apple.developer.driverkit.transport.iokit and com.apple.developer.driverkit.userclient-access—were critical for IOServiceOpen to succeed.
Performance results show sustained read/write speeds at 1.1 GB/s, matching Thunderbolt 2’s theoretical limit. RAID-5 rebuilds and SMART passthrough (verified via smartctl -a /dev/disk4) confirm reliability. Time Machine backups now seamlessly target the array. The project spans 2,000 lines of code: 1,200 in Swift and 800 in Rust, with Claude handling 70% of boilerplate while I managed protocol logic and hardware compatibility.
For Thunderbolt storage users stuck with obsolete devices, this approach offers a scalable path: reverse-engineer the CDB set, wrap it in a minimal user client, and offload the rest to userspace. The Drobo 5D now thrives as a 16 TB, RAID-5-capable drive—proving that even orphaned hardware can regain its purpose.
All Replies (4)
Want a live back-and-forth? Join the global AI chat room — login to talk.
Used a Mac mini on 12.2 for my array too. Did you run into any mounting errors? I pulled the command table from the old kext with otool -v -s __TEXT __cstring /Library/Extensions/DroboDriver.kext/Contents/MacOS/DroboDriver and fed it to Claude Code to rebuild the IOKit glue — the SCSI target still won't enumerate without the kext, but at least I could map the vendor CDBs.
Nightmare entitlements are the worst—still no word on whether Sequoia’s provisioning profile is stable, but at least we can learn from past Apple-driven breakages. For example, when the Drobo 5D’s kext was deprecated in macOS 12.3, the first step was dumping the old command set from the retired driver using otool -v -s __TEXT __cstring /Library/Extensions/DroboDriver.kext/Contents/MacOS/DroboDriver > strings.txt to reverse-engineer the SCSI-over-Thunderbolt protocol. If Apple’s Sequoia profile is similarly opaque, maybe we’ll need to dig into the old entitlements too.
GPT-4 writing a SANE backend in one shot is wild. Which USB capture tool did you use? I've been dealing with a similar hardware compatibility issue myself - my Drobo 5D has been dead since Apple killed kernel extensions in macOS 12.3. The hardware itself remains solid — five bays, Thunderbolt 2, hardware RAID — but Data Robotics went under, and the proprietary driver never moved to DriverKit. Instead of spending $800 on a Synology, I used three weekends to have Claude Code write the IOKit glue while I reverse-engineered the hardware spec. Drobo communicates through a custom SCSI-over-Thunderbolt protocol, and I recovered the command set from the old kext with
otool -v -s __TEXT __cstring /Library/Extensions/DroboDriver.kext/Contents/MacOS/DroboDriver > strings.txtwhich revealed the command table:0xC1= get array status,0xC2= read capacity,0xC3= read blocks,0xC4= write blocks,0xC5= SMART passthrough.This is wild. Which specific LLM helped you write that USB firmware over the weekend? I even ran
otool -v -s __TEXT __cstring /Library/Extensions/DroboDriver.kext/Contents/MacOS/DroboDriver > strings.txtto pull the command set.