Skip to content

spec sync v2.4 - #3888

Merged
igaw merged 42 commits into
linux-nvme:masterfrom
dwsuse:spec
Aug 24, 2026
Merged

spec sync v2.4#3888
igaw merged 42 commits into
linux-nvme:masterfrom
dwsuse:spec

Conversation

@dwsuse

@dwsuse dwsuse commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Bring the libnvme APIs in sync with the base spec version v2.4 (and associated sub specs). Obviously, this is done by AI.

I started to reviewed the commits and so far all looks very sane and consistent. It found real bugs in the spec and also in the implementation, e.g.

image

Given it almost doesn't change existing code, only adds the missing pieces the regression risk is low.

Fixes: #3774

dwsuse added 6 commits August 21, 2026 19:40
The Configurable Device Personality feature (Feature ID 22h, Log
Page 1Dh) had only bare enum stubs for its Feature and Log IDs, with
none of the underlying data structures. ECN139 finalizes the CDP
definitions in the NVMe Base Specification 2.4, and both TP4195
(Restore Manufacturing Default Settings) and TP4200 (Lockdown
Persistence Personality) build on this same infrastructure, so it
needs to land before either of those.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
Add Personality Identifier 02h (Lockdown Persistence Personality) on
top of the Configurable Device Personality scaffolding, plus its
Command Dword 11 (LDPE) and Get Features Completion Queue Entry
Dword 1 (LDPS) fields. This personality lets a host persist the
Lockdown command's prohibitions across power cycles.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
…s (TP4215)

Add the RUHS bit to the FID Supported and Effects Data Structure
scope field, indicating that modifying a feature's attributes may
impact Reclaim Unit Handles.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
Add the Purge Required (PREQ) bit to the Sanitize and Sanitize
Namespace commands, the Purged (PRGD) bit to the Sanitize Status log
page, and the Sanitize Purge Request and Reporting Supported (SPRRS)
bit to the Identify Controller Sanitize Capabilities field, letting a
host require that a sanitize operation purge user data (as defined by
IEEE Std 2883) or fail. Wire up the new nvme_init_sanitize_{nvm,ns}()
parameter, the --preq CLI flag on both sanitize commands, and print
support.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
Add the Minimum Idle I/O Exit Latency Limit (MIIELL) field to the
Power State Descriptor and the Idle I/O Exit Latency Limit (IIELL)
attribute to the Power Management feature, letting a host cap the
maximum additional command completion latency it will accept from
power optimizations while idle. CTRATT's IIELLSS support/scope bits
were already present; this adds the fields that actually carry the
limit. Wire up print support in id-ctrl and get/set-feature output.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
Add the Voltage Threshold (Feature ID 26h) and Voltage Measurement
(Feature ID 27h) features, letting a host monitor the NVM subsystem's
main voltage rail via up to 4 voltage sensors: programmable
overvoltage/undervoltage thresholds with an AER one-shot event, and
a Voltage Measurement log page (27h) tracking interval measurements
against a configurable log threshold. CTRATT's VMS bit and the
Feature/Log ID enum values were already present; this adds the
underlying structures: 4 Voltage Sensor descriptors and MSVMT in
Identify Controller, the Voltage Measurement log page, the Start
Voltage Measurements data structure, the SMART Informative Warning
byte (VLTHW), and the one-shot AER event.

Wire up id-ctrl and SMART print support, and generic get/set-feature
decode for both new features. The Voltage Measurement log page's
detailed pretty-printer is left for a follow-up (falls back to the
generic raw-log path for now).

Note: several Voltage Sensor and log-page fields sit at byte offsets
that aren't naturally 4-byte-aligned relative to their containing
struct (a real spec quirk, not a transcription error), so those
fields/structs use per-member or whole-struct __attribute__((packed))
to avoid the compiler silently inserting padding.

Signed-off-by: Daniel Wagner <dwagner@suse.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Synchronizes libnvme and nvme-cli with NVMe Base Specification 2.4 and related command-set specifications.

Changes:

  • Adds new protocol types, command initializers, feature fields, logs, and NVMe-MI PDA operations.
  • Exposes new lockdown, sanitize, live-migration, and reporting functionality through the CLI.
  • Updates tests, exported symbols, installation rules, and specification documentation.

Reviewed changes

Copilot reviewed 28 out of 30 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
src/nvme-print-stdout.c Prints new controller, SMART, sanitize, voltage, and rate-limiting fields.
src/nvme-print-json.c Adds JSON output for new controller, SMART, sanitize, and voltage fields.
src/nvme-cmds-security.c Adds controller selection to Lockdown commands.
src/nvme-cmds-sanitize.c Adds Purge Required support.
README.md Links the specification coverage document.
plugins/lm/lm-nvme.c Updates live-migration command construction.
libnvme/tests/mi.c Updates MI command tests for new encodings.
libnvme/tests/meson.build Registers new type tests.
libnvme/tests/ioctl/misc.c Updates command-construction tests.
libnvme/tests/ioctl/logs.c Updates log command tests.
libnvme/src/nvme/util.c Adds string conversions for new values.
libnvme/src/nvme/nvme-types.h Exposes the new command-set types.
libnvme/src/nvme/nvme-types-zns.h Extends Zoned Namespace definitions.
libnvme/src/nvme/nvme-types-slm.h Introduces Subsystem Local Memory types.
libnvme/src/nvme/nvme-types-nvm.h Adds NVM 2.4-related structures and fields.
libnvme/src/nvme/nvme-types-mi.h Adds NVMe-MI protocol definitions.
libnvme/src/nvme/nvme-types-base.h Expands base-spec structures, enums, and bitfields.
libnvme/src/nvme/nvme-cmds-nvm.h Adds NVM command initializers.
libnvme/src/nvme/nvme-cmds-fabrics.h Adds Fabrics command helpers.
libnvme/src/nvme/nvme-cmds-base.h Adds and extends base command initializers.
libnvme/src/nvme/mi.h Declares new MI PDA APIs.
libnvme/src/nvme/mi.c Implements MI PDA operations.
libnvme/src/nvme/mi-types.h Extends internal MI message definitions.
libnvme/src/meson.build Installs the new public header.
libnvme/src/libnvme-mi.ld Exports new MI symbols.
libnvme/examples/mi-mctp.c Displays additional MI port information.
Documentation/SPEC-COVERAGE.md Adds chapter-level specification tracking.
Documentation/nvme-sanitize.txt Documents Purge Required.
Documentation/nvme-log-sanitize.txt Documents the Purged status bit.
Documentation/nvme-lockdown.txt Documents controller selection options.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/nvme-cmds-security.c Outdated
Comment thread libnvme/src/nvme/nvme-cmds-base.h
Comment thread src/nvme-print-stdout.c Outdated
Comment thread Documentation/SPEC-COVERAGE.md
Comment thread Documentation/SPEC-COVERAGE.md
Comment thread src/nvme-print-json.c
Comment thread libnvme/src/nvme/mi.c
dwsuse added 20 commits August 24, 2026 11:25
…4222)

Add the Controller-scoped Command and Feature Lockdown capability
(CCFLS bit in Identify Controller OACS), letting a host target a
Lockdown command's prohibitions at a specific controller or the
secondary controllers of a specific primary controller, instead of
only the whole NVM subsystem. Adds the Controller Select (CSEL) field
to the Lockdown command's Command Dword 10 and the corresponding
Controller Select Specific (CSS) field to Command Dword 14, plus the
Controller-scoped Enhanced Command and Feature Lockdown log page
format (requested via the existing Log Specific Parameter/Identifier
mechanism already used by other logs).

Wire up the new --csel/--css flags on `nvme lockdown` and OACS print
support. The Enhanced log page's pretty-printer is left for a
follow-up, same as the Voltage Measurement log from TP4210.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
Add the Port Capabilities (PRTCAP) field to the Port Information Data
Structure returned by the Read MI Data Structure command, exposing
the CIAPS and AEMS bits that were previously part of an undecoded
reserved byte. Wire up an AEMS print line in the mi-mctp example.

Two other pieces of TP6042 are deliberately left out of scope:
- The behavioral requirements for how a Management Endpoint responder
  handles malformed ROR/NMIMT/CIAP field values are responder-side
  protocol compliance rules; libnvme only implements the host
  (requester) side.
- The new BPOPL bit lives in the Management Endpoint State data
  structure for the Get State command, which libnvme doesn't
  implement at all yet (a separate, larger, pre-existing gap
  predating this TP) — adding one bit to a structure/command that
  doesn't exist isn't actionable on its own.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
Add enum nvme_mi_form_factor covering the full Form Factor value
table (PCIe, Ethernet, and vendor-specific variants) used by the
Upstream Connector Element Descriptor in the VPD Topology MultiRecord
Area, including the new SFF-TA-1042 E2 9.5mm value this TP adds. The
underlying Upstream Connector Element Descriptor structure didn't
exist in libnvme at all — only the element-type tag did — so this
also adds struct nvme_mi_vpd_usce for its fixed header fields; the
trailing Upstream Port Descriptor list is implementation-specific
sized per spec, so it's left as an opaque trailing array.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
Adds the Rate Limiting Feature (28h) and log page (28h) that let a
host limit the bandwidth and IOPS of a target (e.g. controller) in
the NVM subsystem, along with the supporting OAES/AEC notification
bit, async event notice value, and NVM command set specific Identify
Controller Rate Limiting Attributes/Soft Limit Max Controllers
fields.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
Adds the CXL HDM Support Information (CHSI) field to the Identify
Controller data structure and the new Host Addressable Namespaces
log page (85h), which reports which SLM memory namespaces are
accessible via PCIe BAR or CXL HDM host memory addressing.

This seeds nvme-types-slm.h for the Subsystem Local Memory (SLM)
Command Set (CSI 03h). The SLM command set itself (memory namespace
Identify data structures, SLM Read/Write/Copy/Fill commands) remains
unimplemented in libnvme; only the log page and Identify field this
TP defines are added here.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
Adds the NVMe-MI PDA Read (0Dh), PDA Write (0Eh), and PDA Write
Zeroes (0Fh) commands for out-of-band access to the new optional
Persistent Data Area, along with the Data Format (DFORMAT) enum and
the PDA Size (PDAS) / Supported Data Format (SDFORMAT) fields on the
2-Wire Port Specific Data structure that advertise support and size.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
Adds struct nvme_tdisp_device_interface_report and the TDISP
Information (TI) bitfield enum describing the NVMe class-specific
DEVICE_SPECIFIC_INFO payload returned by a PCIe TDISP
GET_DEVICE_INTERFACE_REPORT request.

Unlike other command-set gaps, no NVMe Admin, I/O, or MI command
transfers this structure: it is produced by the device's Device
Security Module and consumed by a platform TEE Security Module
entirely through the PCIe TDISP protocol, outside any NVMe
command/response path libnvme implements. This is added as a pure
type definition for decoding a report obtained via some other
TDISP/SPDM stack, with no corresponding libnvme command wrapper.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
…lity (TP4195)

Add Personality Identifier 03h on top of the Configurable Device
Personality scaffolding, along with the rest of the Restore
Manufacturing Default Settings capability it belongs to:

- Personality Identifier 03h (Revert to Subsystem Manufacturing
  Settings), which uses no data buffer and no personality-specific
  command fields.
- New Generic Command Status value 0x2D, Failed to Restore
  Configuration, returned when a restore operation cannot complete.
- Identify Controller Restore Manufacturing Configuration Attributes
  (RMDCA, byte 362) with RDCCS/RDNCS/RDSCS support bits.
- The new Manufacturer Default Configuration Status log page (Log
  Page Identifier 24h), reporting DCCS/DNCS/DSCS status bits.
- Namespace Management gains a Restore Default Namespace
  Configuration operation (SEL 2h).
- Capacity Management gains a Restore Default Capacity Management
  Configuration operation (OPER 5h); added enum
  nvme_capacity_mgmt_oper since no OPER values were previously named.

Added command helpers for all three restore operations and CLI print
support for RMDCA. Verified struct/field offsets with a standalone
test program against the integrated Base Specification 2.4.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
…ec 2.4)

Figure 103 (Generic Command Status Values) defines 0x2B "Sanitize
Namespace Failed" and 0x2C "Sanitize Namespace In Progress", referenced
by the Namespace Sanitize Operation admin command restriction tables
(Figure 145/146), but neither had a named constant in
enum nvme_status_field.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
… Track Receive

Gap analysis of Base Spec 2.4 chapter 5.2 found four Admin commands with
opcodes defined but no nvme_init_* constructor, unlike every other
command in this file:

- Abort (5.2.1): adds nvme_init_abort() with CDW10 CID/SQID fields.
- Asynchronous Event Request (5.2.2) and Keep Alive (5.2.15): trivial
  constructors, all command specific fields are reserved.
- Track Receive (5.2.31): was asymmetric with Track Send, which already
  had a constructor. Adds nvme_init_lm_track_receive() plus the Tracked
  Memory Change Data Structure and descriptor types it returns
  (Figures 556-559), offsets verified against the spec with offsetof.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
Deep gap analysis of Base Spec 2.4 section 5.2.12 (Get Features) found:

- Abort (5.2.1) Figure 148 CQE Dword0 IANP bit had no representation:
  adds enum nvme_abort_cqe_dw0.
- 17 of the 44 Feature Identifiers had no nvme_init_get_features_*/
  nvme_init_set_features_* constructor, unlike every other feature in
  this file: Spinup Control, Power Loss Signaling Config, Flexible
  Data Placement, FDP Events, Namespace Admin Label, Configurable
  Device Personality, Power Limit, Power Threshold, Power Measurement,
  Voltage Threshold, Voltage Measurement, Embedded Management
  Controller Address, Host Management Agent Address, the three Host
  Metadata features, and Boot Partition Write Protection Config.

These were reachable through the generic nvme_get_features()/
nvme_set_features() API and already wired into the CLI, so this closes
an API-completeness gap in the typed constructor layer rather than a
functional one. All of the per-feature CDW/CQE bitfield macros and
data structures these constructors use already existed from earlier
TP work; only the constructors themselves were missing. Added one new
type, enum nvme_host_metadata_cdw11/_ea, for the Host Metadata
GDHM/EA fields which had no representation at all.

Verified struct sizes (nvme_mgmt_addr_desc, nvme_host_metadata,
nvme_voltage_measurement_start_data) and the Voltage Threshold bit
packing against the spec with a standalone test program.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
Gap analysis of section 5.2.13 found the Log Page Identifier enum
complete, but 4 of the log pages it defines had no
nvme_init_get_log_* constructor:

- Device Personalities (0x1D) and Voltage Measurement (0x27): the
  backing structs already existed from earlier TP work, only the
  constructors were missing.
- Cross-Controller Reset (0x1E) and Lost Host Communication (0x1F):
  neither had any struct at all. Added struct nvme_cross_ctrl_reset_log/
  _entry (with the Remove Completed log-specific-parameter bit and
  CCRS/CCRF status enums) and struct nvme_lost_host_comm_log/_entry,
  plus their constructors in nvme-cmds-fabrics.h alongside the other
  message-based-transport log pages (Discovery/Host Discovery/AVE
  Discovery) that already have working infrastructure there.

Verified all new struct offsets against the spec's byte tables with a
standalone test program before committing.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
Gap analysis of section 5.2.14 (Identify command) found:

- enum nvme_identify_cns missing 2 values new in Base Spec 2.4:
  NVME_IDENTIFY_CNS_UNDERLYING_CTRL_LIST (0x21) and
  NVME_IDENTIFY_CNS_EXPORTED_NVM_SUBSYS_TEMPLATE_UUID_LIST (0x22).
- 6 CNS values had no nvme_init_identify_* constructor:
  - 0x1D (Get Underlying Namespace List), 0x1E (Get Ports List), and
    0x20 (Supported Controller State Formats) had no backing struct at
    all despite predating 2.4. Added struct nvme_underlying_ns_list/
    _entry, struct nvme_ports_list/nvme_fabrics_transport_entry, and
    struct nvme_supported_ctrl_state_formats.
  - 0x1F and 0x21 reuse existing structs (nvme_id_independent_id_ns,
    nvme_ctrl_list respectively), only the constructor was missing.
  - 0x22 gets a new, minimal UUID-list-only struct, consistent with
    the "thinnest possible addition" used elsewhere for
    Exported-NVM-Subsystem-adjacent decode-only types, without taking
    on the larger deferred Exported NVM Subsystem feature itself.

Verified all new struct sizes and offsets against the spec's byte
tables with a standalone test program before committing.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
Field-level audit of the Lockdown command found NVME_LOCKDOWN_CDW14_UIDX_MASK
set to 0x3f (6 bits) instead of 0x7f (7 bits), the only outlier among every
other UUID Index field in the codebase (Get Log Page, Identify, Set/Get
Features all correctly use 0x7f per Figure 782). Truncated bit 6 of any
UUID index >= 64 passed to nvme_init_lockdown().

Signed-off-by: Daniel Wagner <dwagner@suse.com>
Gap analysis of Base Spec 2.4 chapter 5.4 (Message-Based Transport Admin
Commands) found:

- Cross-Controller Reset (5.4.1, opcode 0x38): the admin command itself had
  no constructor (only its log page was added previously). Adds
  nvme_init_cross_ctrl_reset(), enum nvme_cross_ctrl_reset_cdw10, enum
  nvme_cross_ctrl_reset_cqe_dw0 (IRS/V/CLRI), and the 3 missing
  command-specific status codes 0x3F/0x40/0x41.
- Discovery Information Management (5.4.2): already fully correct
  (nvme_init_dim_send's TAS field matches the spec exactly). No gap; its
  Extended Discovery Information Entry payload is deliberately left as a
  raw buffer, consistent with how other deeply-nested variable formats are
  handled elsewhere in this codebase.
- Fabric Zoning Lookup/Receive/Send (5.4.3-5.4.5): none had a constructor.
  Adds all three, plus enum nvme_fabric_zoning_recv_cdw12/_cqe_dw0 and
  _send_cdw12. Status codes 0x30/0x31/0x33/0x34 already existed and are
  shared correctly across all three.
- Manage Exported Port (5.4.6): deferred, part of the larger Exported NVM
  Subsystem family.
- Send Discovery Log Page (5.4.7): no constructor. Adds
  nvme_init_send_discovery_log_page() plus enum
  nvme_send_discovery_log_page_rlps/_cdw10/_cqe_dw0.

Verified all new bit-packed CDW10 fields against the spec's bit ranges
before committing.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
Field-level dive into the remaining 5.2 commands that had only had a
constructor-existence check so far (Capacity Management, Controller Data
Queue, Device Self-test, Directive Send/Receive, Firmware Commit, Firmware
Image Download, Format NVM, Namespace Attachment, Namespace Management,
Security Send/Receive, Migration Send/Receive) found all of them correct
except two real bugs:

- NVME_SC_EXCEEDS_MAX_NS_SANITIZE was 0x3C instead of 0x12 (Figure 455).
  The dedicated libnvme_sanitize_ns_status_to_string() decoder could never
  match the real status a controller returns for this command. 0x12 is
  already used by NVME_SC_FW_NEEDS_MAX_TIME for Firmware Commit, but
  command specific status is scoped per opcode, so the numeric collision
  is expected and harmless - the two names are used in separate,
  command-specific decode paths, never the same switch statement.

- nvme_init_lm_track_send() had no way to supply the data buffer required
  by the Track Memory Changes management operation when starting tracking
  (TACT set), making that operation uncallable. Added
  struct nvme_lm_track_memory_changes_data and
  struct nvme_lm_memory_range_tracking_descriptor (Figures 566/567), the
  TACT enum, and a data/len parameter pair on the constructor, updating
  its two existing call sites. The descriptor struct needs
  __attribute__((packed)): its natural 16-byte alignment would otherwise
  silently break the spec's tight 12-byte array stride, caught by
  offsetof()/sizeof() verification before committing.

Migration Receive/Send's "Exported NVM Subsystem State" operations
(SEL 1h/3h) remain deliberately unwired, consistent with the rest of the
Exported NVM Subsystem family being out of scope for this pass.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
….2.4)

First piece of the deferred Exported NVM Subsystem command family (see
plan_exported_nvm_subsystem_family in project memory). This command has
no command specific fields at all, so it's just an opcode with no data
buffer - the smallest gap in that family.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
Second piece of the deferred Exported NVM Subsystem command family (see
plan_exported_nvm_subsystem_family in project memory). Implements the
Create Exported NVM Subsystem management operation (SEL 00h), the first
of the family's operations that needs to exist before any of the others
(List/Get/Associate all operate on an already-created subsystem):

- nvme_init_manage_export_nvms_receive(): generic constructor for the
  command, taking the SEL/MOS/MOSE/MOSI/offset/NUMDL fields shared across
  all 6 management operations this opcode supports.
- nvme_init_manage_export_nvms_receive_create(): Create-specific wrapper
  (TR/ENSTI in Command Dword 11, RA in the message-based-only MOS field),
  plus struct nvme_exported_nvm_subsys_create_data for the 256-byte
  SUBNQN data buffer and the CQE Dword0 ESUBID decode.

Verified the new struct's size against the spec with a standalone test
program before committing.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
Third piece of the deferred Exported NVM Subsystem command family (see
plan_exported_nvm_subsystem_family in project memory). Implements the
Delete management operation (SEL 01h):

- nvme_init_manage_export_nvms_send(): generic constructor for the
  command, taking the SEL/MOS/MOSE (Command Dword 10) and
  ESUBIDV/ESUBID (Command Dword 14) fields shared across all 6
  management operations this opcode supports.
- nvme_init_manage_export_nvms_send_delete(): Delete-specific wrapper.
  The target Exported NVM Subsystem is identified either by ESUBID
  (Command Dword 14, no data buffer needed) or by SUBNQN in the data
  buffer, per the ESUBIDV bit - added struct
  nvme_exported_nvm_subsys_nqn_data for the latter case.
- NVME_SC_CONTROLLER_ACTIVE (0x42): new command specific status code,
  shared between Delete and the not-yet-implemented Associate
  Controllers operation.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
…(5.2.18)

Fourth piece of the deferred Exported NVM Subsystem command family (see
plan_exported_nvm_subsystem_family in project memory). Implements the
4 remaining SEL 01h-04h List operations, each reusing the
nvme_init_manage_export_nvms_receive() base constructor added for
Create:

- List Exported NVM Subsystems (01h): struct nvme_exported_nvm_subsys_list/
  _descriptor, starting point is the Exported NVM Subsystem Identifier in
  the MOSI field.
- List Exported Namespaces (02h): struct nvme_exported_ns_list/_descriptor,
  starting point is the command's own NSID field (exclusive, unlike the
  other three which are inclusive).
- List Exported Controllers (03h, message-based transports only): struct
  nvme_exported_ctrl_list/_descriptor, starting point is the Exported
  Controller Identifier in the MOSE field.
- List Exported Ports (04h, memory-based transports only): struct
  nvme_exported_port_list/_descriptor, starting point is the Exported
  Port Identifier in the MOSE field.

The Exported NVM Subsystem List Data Structure's byte-range table in the
spec PDF is garbled by an extraction artifact (inconsistent stride
between listed descriptor offsets); resolved by deriving the layout from
the unambiguous single-descriptor figure instead (260 bytes: 256-byte
NQN + 2 reserved + 2-byte identifier). Verified all 4 new descriptor and
list-header struct sizes/offsets against the spec with a standalone test
program before committing.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
dwsuse added 16 commits August 24, 2026 09:56
Fifth piece of the deferred Exported NVM Subsystem command family (see
plan_exported_nvm_subsystem_family in project memory). Implements both
management operations of this command (opcode 0x31):

- nvme_init_manage_export_ns(): generic constructor, taking the
  SEL/MOS (Command Dword 10) and ESUBIDV/ESUBID (Command Dword 14)
  fields shared by both operations.
- nvme_init_manage_export_ns_associate() / _disassociate(): operation
  specific wrappers, with struct nvme_associate_ns_data (576 bytes) and
  struct nvme_disassociate_ns_data (320 bytes) for their data buffers.

The Associate/Disassociate Namespace Data Structure figures in the spec
PDF label their offset column "Bits" but the numbers are actually byte
offsets - confirmed by cross-checking the two 256-byte NQN fields
(ENSNQN, UNSNQN), which only make sense as byte counts. Verified both
struct layouts against the spec with a standalone test program before
committing.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
…(5.2.19)

Sixth piece of the deferred Exported NVM Subsystem command family (see
plan_exported_nvm_subsystem_family in project memory). Implements the 5
remaining SEL operations, completing this command:

- Change Access Mode (02h, message-based only): RA bit in the MOS field,
  reuses struct nvme_exported_nvm_subsys_nqn_data from Delete for the
  identify-by-NQN case.
- Grant Host Access (03h) / Revoke Host Access (04h, message-based only):
  share struct nvme_exported_subsys_mgmt_data, a 256-byte header
  (NUMHENT/NUMENSE counts) followed by two back-to-back variable-length
  lists (struct nvme_exported_subsys_mgmt_host_entry, struct
  nvme_exported_subsys_mgmt_subsys_entry, 320 bytes each) - left as a raw
  trailing byte buffer since C can't express two differently-sized
  variable-length lists as fixed struct members. New status codes
  NVME_SC_INVALID_HOST (0x35) and NVME_SC_INVALID_NVM_SUBSYSTEM (0x36).
- Associate Controllers (05h, memory-based only): struct
  nvme_exported_ctrl_assoc_data/_descriptor. New status code
  NVME_SC_INVALID_EXPORTED_ASSOCIATION (0x43).
- Set Exported Configuration State (06h): data buffer format is Exported
  NVM Subsystem Template specific, left as an opaque buffer matching the
  established pattern for other template-defined payloads. New status
  code NVME_SC_INVALID_EXPORTED_CONFIG_STATE (0x44) and its CQE Dword0
  BITLOC/DWLOC decode.

Verified all new struct sizes/offsets against the spec with a standalone
test program before committing.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
Final piece of the deferred Exported NVM Subsystem command family (see
plan_exported_nvm_subsystem_family in project memory) - this completes
the whole family and, with it, the entire Base Spec 2.4 chapter 5
(Admin Command Set) gap analysis.

Implements both management operations of this message-based-transport-
only command (opcode 0x35):

- nvme_init_manage_export_port(): generic constructor for the SEL/MOS
  fields shared by both operations.
- nvme_init_manage_export_port_create(): GEPID bit in the MOS field,
  struct nvme_exported_port_create_data (320 bytes: SUBNQN, EPID, PIDUD,
  TRSVCID) and the CQE Dword0 EPID decode for controller-assigned IDs.
- nvme_init_manage_export_port_delete(): struct
  nvme_exported_port_delete_data (320 bytes: SUBNQN, EPID).

Placed in nvme-cmds-fabrics.h alongside the other message-based-
transport-only commands added earlier in this audit (Cross-Controller
Reset, Fabric Zoning, Send Discovery Log Page). Verified both struct
sizes/offsets against the spec with a standalone test program before
committing.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
Gap analysis of Base Spec 2.4 chapters 6 (Fabrics Command Set) and 7
(I/O Commands) found both largely complete already:

- Chapter 6: all 6 Fabrics Command Types present and correct. Property
  Get/Set and Authentication Send/Receive verified field-correct.
  Connect/Disconnect are implemented as full connection-management
  functions in fabrics.c rather than simple passthru constructors,
  appropriate given they manage queue/connection lifecycle.
- Chapter 7: opcode table complete (8/8). Flush, I/O Management
  Receive/Send, and all 4 Reservation commands were already fully
  correct, including the newer Dispersed Namespace Reservation Support
  (DISNSRS) bit.

One real gap: the Cancel command (opcode 0x18) had no constructor at
all. Adds nvme_init_cancel(), enum nvme_cancel_acode (Command Dword 11
Action Code), the Command Dword 10 CID/SQID fields, the CQE Dword0
CEDA/CMDA decode, and NVME_SC_INVALID_CMD_ID (0x84) - a command
specific status code that was entirely unnamed despite the same
numeric value already being used, correctly, by three other
command-scoped status constants (command specific status is scoped
per opcode, so the reuse is expected).

Signed-off-by: Daniel Wagner <dwagner@suse.com>
…stics

NVM Command Set Spec 1.3 section 4.1.3.8 (Feature Identifier 1Ch) had no
nvme_init_get_features_perf_characteristics()/nvme_init_set_features_perf_characteristics()
wrappers, even though the CDW11 bitfield macros, decode helper, and data
structures (struct nvme_perf_characteristics and friends) already existed.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
NVM Command Set Spec 1.3 Figure 116 (Media Reallocated Event Type
Specific Data Structure) packs the 8-byte LBA field at byte offset 4,
right after the 2-byte NLBAM field, for a total structure size of 16
bytes matching the FDP Event's type_specific[16] field.

Without __attribute__((packed)), natural alignment pads __le64 lba to
offset 8, growing the struct to 24 bytes and misplacing every field
after NLBAM relative to the real on-the-wire layout.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
…S decode

NVM Command Set Spec 1.3 Figure 123 (Identify Namespace Data Structure)
defines NSFEAT bit 6 (Multiple Atomicity Mode, MAM) and bit 7 (Optional
Read Performance, OPTRPERF) which were entirely missing from
enum nvme_id_nsfeat.

enum nvme_id_ns_mc's two doc comments were swapped relative to their
bit values: NVME_NS_MC_EXTENDED (bit 0) was documented as the separate
buffer bit and NVME_NS_MC_SEPARATE (bit 1) as the extended LBA bit,
backwards from Figure 123's MTELBAS/MTSBS definitions.

The struct nvme_id_ns.kpios field (Key Per I/O Status) had no
shift/mask decode enum at all, unlike every other bitfield byte in the
struct and unlike the analogous controller-level KPIOC field which
already has one.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
NVM Command Set Spec 1.3 Figure 129 (I/O Command Set Specific Identify
Controller Data Structure) defines bitfields for the Key Per I/O
Capabilities (KPIOCAP: KPIOS bit0, KPIOSC bit1) and Admin Optional
Command Support (AOCS: RALBAS bit0) fields, but struct nvme_id_ctrl_nvm
had no shift/mask decode enums for either, unlike every other
multi-bit field in the struct (e.g. RLA already has one).

Signed-off-by: Daniel Wagner <dwagner@suse.com>
NVM Command Set Spec 1.3 section 4.1.5.8 / Figure 132 allows up to 64
Namespace Granularity descriptors when the LBA Format Extension Enable
(LBAFEE) field is set in the Host Behavior Support feature, but
NVME_ID_ND_DESCRIPTOR_MAX was hardcoded to 16 (the pre-LBAFEE limit).

Consumers (nvme-print-stdout.c, nvme-print-json.c) iterate up to
glist->num_descriptors, a device-reported 0's based value with no
bound to the old 16-entry array, so a device reporting more than 16
descriptors caused an out-of-bounds read of struct nvme_id_ns_granularity_list.entry[].

Bumped the array to 64 entries and shrank the trailing reserved region
accordingly to keep the struct at the required 4096 bytes.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
NVM Command Set Spec 1.3 Figure 140 (LBA Status Descriptor Entry)
defines the LBA Range Status (LBARS) field as bits 2:0 of the Status
byte, with four defined values (000b-011b), but there was no
shift/mask/value enum for it, unlike the sibling completion-condition
field which already has enum nvme_lba_status_cmpc.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
ZNS Command Set Spec Figure 38 (Zone Descriptor Data Structure) packs
Zone Type (ZT) into bits 3:0 of the zt byte, Zone State (ZS) into bits
7:4 of the zs byte, and Reset/Finish Zone Recommended Time Limit
(RZRTL/FZRTL) into bits 3:2/1:0 of the zai byte, but none of these had
shift/mask decode enums or macros.

Callers were expected to know the magic ">> 4" shift for ZS themselves
(nvme-cli's print code does this correctly, but nothing in libnvme
documented or provided it), and the ZT/RZRTL/FZRTL bitfields had no
decode support at all despite being read directly as raw bytes
elsewhere.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
ZNS Command Set Spec Figure 42 defines the Zone Capacity Changed (ZCC)
bit in Completion Queue Entry Dword 0 for the Zone Management Send
command, but there was no decode enum/macro for it at all.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
ZNS Command Set Spec Figure 43 (Asynchronous Event Information -
Notice, Zoned Namespace Command Set) defines value EFh for the Zone
Descriptor Changed event, but enum nvme_ae_info_notice had no entry
for it despite already having NVME_FEAT_AE_ZDCN (the corresponding
Set Features enable bit) and NVME_LOG_LID_ZNS_CHANGED_ZONES (the log
page it's paired with).

Signed-off-by: Daniel Wagner <dwagner@suse.com>
ZNS Command Set Spec Rev 1.5 Figure 51 (I/O Command Set Specific
Identify Controller Data Structure for the Zoned Namespace Command
Set) defines Zoned Controller Attributes (ZCTRATT), Total/Unallocated
Active/Open/ZRWA Resources (TAR/UAR/TOR/UOR/TZRWAR/UZRWAR), and a
Version (VER) field at bytes 4-35, none of which existed in
struct nvme_zns_id_ctrl -- it only had zasl followed by 4095 bytes of
reserved. This header's DOC comment still claimed to target Revision
1.4; these fields were added by an ECN folded into 1.5.

Also added decode enums for the ZOC (VZC/ZAE), OZCS (RAZB/ZRWASUP),
and ZRWACAP (EXPFLUSHSUP) bitfields in nvme_zns_id_ns -- nvme-cli's
print code already hand-decoded these bits correctly
(show_nvme_id_ns_zoned_zoc/ozcs, stdout_zns_id_ns_zrwacap) but libnvme
itself provided no shift/mask macros for them.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
ZNS Command Set Spec Figure 54 (I/O Namespace Management - Host
Specific Fields) defines the Allocate ZRWA Resources (AZR) bit in the
znsco byte, but there was no enum for it despite the field already
being documented in the struct's doc comment.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
Track which chapters of each NVMe specification have been verified
field-by-field against libnvme, and when, so future audits know what
is already covered.

Signed-off-by: Daniel Wagner <dwagner@suse.com>
@igaw
igaw merged commit 2552e27 into linux-nvme:master Aug 24, 2026
30 of 31 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Update libnvme APIs to spec v2.4

3 participants