nvme/lib.rs
1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! NVMe controller emulator (NVMe 2.0, NVM command set).
5//!
6//! This crate emulates an NVMe controller as a PCI device with MMIO BAR0,
7//! MSI-X, and admin + I/O queue pairs. It targets the
8//! [NVMe Base 2.0](https://nvmexpress.org/specifications/) specification
9//! (version register reports 0x00020000) with vendor ID 0x1414 (Microsoft).
10//!
11//! # Architecture
12//!
13//! - **PCI layer** ([`NvmeController`]) — MMIO BAR0 register handling, PCI
14//! config space, MSI-X interrupt routing, doorbell writes.
15//! - **Coordinator** — manages enable/reset sequencing, namespace add/remove.
16//! - **Admin worker** — processes admin commands: Identify Controller/Namespace,
17//! Create/Delete I/O Queue, Get/Set Features, Async Event Request.
18//! - **I/O workers** — pool of tasks (one per completion queue) processing NVM
19//! commands: READ, WRITE, FLUSH, Dataset Management (TRIM), and persistent
20//! reservation commands.
21//!
22//! # What it doesn't implement
23//!
24//! Firmware update, admin-level namespace management (create/delete), multi-path
25//! I/O, end-to-end data protection (PI), and save/restore (`SaveRestore`
26//! returns not-supported).
27//!
28//! # Namespace management
29//!
30//! Namespaces can be added and removed at runtime via [`NvmeControllerClient`].
31//! Each namespace wraps a [`Disk`](disk_backend::Disk) and a background task
32//! monitors capacity changes via `wait_resize`, completing Async Event Requests
33//! with `CHANGED_NAMESPACE_LIST` when the disk size changes.
34//!
35//! # Key constants
36//!
37//! - `MAX_DATA_TRANSFER_SIZE`: 256 KB
38//! - `MAX_QES`: 256 queue entries
39//! - `BAR0_LEN`: 64 KB
40
41#![forbid(unsafe_code)]
42
43mod error;
44mod namespace;
45mod pci;
46mod prp;
47mod queue;
48pub mod resolver;
49mod workers;
50
51#[cfg(test)]
52mod tests;
53
54pub use pci::NvmeController;
55pub use pci::NvmeControllerCaps;
56pub use workers::NsidConflict;
57pub use workers::NvmeControllerClient;
58
59use guestmem::ranges::PagedRange;
60use nvme_spec as spec;
61
62// Device configuration shared by PCI and NVMe.
63const DOORBELL_STRIDE_BITS: u8 = 2;
64const VENDOR_ID: u16 = 0x1414;
65const NVME_VERSION: u32 = 0x00020000;
66const MAX_QES: u16 = 256;
67const BAR0_LEN: u64 = 0x10000;
68const IOSQES: u8 = 6;
69const IOCQES: u8 = 4;
70
71// NVMe page sizes. This must match the `PagedRange` page size.
72const PAGE_SIZE: usize = 4096;
73const PAGE_SIZE64: u64 = 4096;
74const PAGE_MASK: u64 = !(PAGE_SIZE64 - 1);
75const PAGE_SHIFT: u32 = PAGE_SIZE.trailing_zeros();
76const _: () = assert!(PAGE_SIZE == PagedRange::PAGE_SIZE);