← All posts
RSS
Systems & Storage / Field Notes Rev. 07.2026

Before It Becomes RTL: Inside OpenFlash Controller Lab

An open-source lab that treats an SSD controller the way it deserves to be treated — as a system to be simulated, measured, and argued with in software long before a single gate gets synthesized.

NAND flash controllers FTL & scheduling Linux blk-mq QEMU

Most storage hardware projects start with a datasheet and end, months later, with a driver that either works or doesn't. OpenFlash Controller Lab — an open-source repository from developer manishklach — takes a different route. It builds the entire controller stack as an executable architecture first: a discrete-event NAND and flash-translation-layer simulator, a behavioral reference controller, a versioned host/controller ABI, a QEMU PCI device model, and a Linux blk-mq driver scaffold — all wired together so that scheduling and placement ideas can be measured before anyone commits to RTL.

The premise is simple but easy to skip in practice: NAND media is slow relative to PCIe and the CPU, and the only way a controller hides that latency is by keeping many independent channels and dies busy at once. That single fact cascades into requirements for every layer of the stack — the FTL has to place data without triggering pathological garbage collection, the scheduler has to exploit parallelism without starving reads or writes, the queue transport has to avoid stale completion races, and the Linux driver has to submit asynchronously and recover cleanly from timeouts. OpenFlash's whole design is an attempt to turn that chain of requirements into code you can actually run.

01 What's already running

The project is unusually candid about where it stands, and that candor is worth taking seriously — the README states outright that it is not yet suitable for storing valuable data or loading against unverified hardware. Here's the shape of what does work today:

Component Status
NAND Simulator
Channels, dies, timing distributions, ECC retry, wear, and garbage collection, all seeded for reproducibility.
Runnable
FTL
Full page mapping, striping across channels/dies, invalidation, live-page relocation.
Runnable
Scheduler
FIFO baseline plus a starvation-bounded read-priority policy.
Runnable
Host/Controller ABI
64-byte command/completion layout, versioned v0.1, enforced across Python, C, and QEMU in CI.
v0.1
QEMU PCI Device
BAR0, guest DMA, one MSI-X vector, RAM-backed I/O — built against a pinned QEMU 11.0.2 in CI.
Build pinned
Linux Driver
PCI bind, admin rings, MSI-X, identify — does not yet register a block device.
Module builds
Firmware / RTL
Requirements derived from the validated software model; channel engines not yet started.
Planned

02 How the pieces fit together

The whole point of the project is that these components aren't isolated demos — they're a single pipeline running from an application request down to a simulated die. Traffic flows through the same stages a shipped SSD would use:

Request path, application to media
App / fio Linux block layer PCI / blk-mq driver DMA queues Command processor Scheduler FTL Channel / die engines

This is deliberately a managed block device architecture: FTL, ECC, wear-leveling, and bad-block policy stay behind the controller ABI, and Linux talks to it through blk-mq like any other NVMe-class device. A raw-NAND MTD/UBI/UBIFS design is acknowledged as possible but treated as an explicitly separate product boundary, rather than something bolted onto the same ABI.

03 Numbers you can actually reproduce

Because the simulator is seeded, the same command produces the same result on any machine — which is what makes it useful for comparing scheduling policies rather than just admiring them. Running the built-in comparison between FIFO and read-priority scheduling looks like this:

openflash-sim compare --seed 7
# 10,000 requests, 8 channels, 4 dies/channel, 70% reads
python -m openflash.cli compare \
  --requests 10000 --read-ratio 0.70 \
  --channels 8 --dies-per-channel 4 --seed 7

fifo               644.5 MiB/s   41249 IOPS   p99=211871.6 us
read-priority      817.6 MiB/s   52328 IOPS   p99=167508.5 us

Read-priority scheduling wins here on every axis in this particular configuration — more throughput, more IOPS, and a much tighter p99 read tail. The project is careful to flag that these are model results, not hardware benchmarks, which is exactly the right instinct: a simulator can tell you which scheduling idea is directionally promising, but it can't tell you what silicon will actually do until it's calibrated against a real NAND part.

Why this restraint matters It's common in hobby hardware projects to quietly let simulator output drift into marketing copy. OpenFlash's README explicitly instructs contributors not to present simulator output as hardware performance — a small governance detail that says a lot about how the project intends to grow.

04 Four things worth knowing before you clone it

The ABI is the contract

A 64-byte little-endian command/completion layout, BAR0 lifecycle, and durability rules are defined once in a normative C header, then checked for consistency against the Python and QEMU implementations in CI.

The driver is intentionally incomplete

It binds to PCI, sets up admin rings, and completes identify — but does not register a disk yet. Timeout/reset semantics and data verification have to land first.

Licensing is split correctly

The simulator, docs, and QEMU model are Apache-2.0. The Linux kernel driver subtree is GPL-2.0-only, isolated because it depends on GPL-only kernel interfaces.

fio profiles exist, but are future gates

The bench/fio profiles describe the acceptance workloads the project wants to pass once a real block device is registered — they aren't runnable results yet.

05 What's next on the roadmap

The project lays out its own path in stages, and stage two — turning the emulated controller into a working Linux data path — is where the near-term work concentrates:

Beyond that sits the more ambitious stage three: moving the validated scheduler and FTL behavior into firmware, building ONFI channel engines, persistent metadata recovery, FPGA tests, and eventually power-cut qualification. It's a long runway, but it's the right order — validate the policy in software, then let the hardware inherit behavior that's already been tested, rather than the other way around.


What makes OpenFlash worth a look isn't that it's a finished SSD controller — it explicitly isn't one yet. It's that the project treats "is this architecture idea any good" as a question you should be able to answer with a seeded simulation and a test suite, months before you'd ever tape out silicon. That's a discipline a lot of storage hardware projects skip, and it's the kind of foundation that makes the eventual firmware and RTL work far less risky.

The full source, docs, and roadmap gates live on GitHub.

View openflash-controller-lab →