nvme_spec/
lib.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! NVMe specification definitions (NVMe Base 2.0c and PCIe Transport 1.0c).
5//!
6//! Provides bitfield structs, command/completion queue entry formats, status
7//! codes, and register definitions. The [`nvm`] submodule defines the NVM
8//! command set (read, write, flush, DSM, reservations, namespace identification).
9//!
10//! Base 2.0c: <https://nvmexpress.org/wp-content/uploads/NVM-Express-Base-Specification-2.0c-2022.10.04-Ratified.pdf>
11//! PCIe transport 1.0c: <https://nvmexpress.org/wp-content/uploads/NVM-Express-PCIe-Transport-Specification-1.0c-2022.10.03-Ratified.pdf>
12
13#![expect(missing_docs)]
14#![forbid(unsafe_code)]
15#![no_std]
16
17pub mod nvm;
18
19use bitfield_struct::bitfield;
20use inspect::Inspect;
21use mesh::MeshPayload;
22use open_enum::open_enum;
23use storage_string::AsciiString;
24use zerocopy::FromBytes;
25use zerocopy::Immutable;
26use zerocopy::IntoBytes;
27use zerocopy::KnownLayout;
28
29type U128LE = zerocopy::U128<zerocopy::LE>;
30
31open_enum! {
32    pub enum Register: u64 {
33        CAP = 0x0,
34        VS = 0x8,
35        INTMS = 0xc,
36        INTMC = 0x10,
37        CC = 0x14,
38        RESERVED = 0x18,
39        CSTS = 0x1c,
40        NSSR = 0x20,
41        AQA = 0x24,
42        ASQ = 0x28,
43        ACQ = 0x30,
44        CMBLOC = 0x38,
45        CMBSZ = 0x3c,
46        BPINFO = 0x40,
47        BPRSEL = 0x44,
48        BPMBL = 0x48,
49    }
50}
51
52#[derive(Inspect)]
53#[bitfield(u64)]
54pub struct Cap {
55    pub mqes_z: u16,
56    pub cqr: bool,
57    pub ams_weighted_round_robin_with_urgent: bool,
58    pub ams_vendor_specific: bool,
59    #[bits(5)]
60    pub reserved: u8,
61    pub to: u8,
62    #[bits(4)]
63    pub dstrd: u8,
64    pub nssrs: bool,
65    pub css_nvm: bool,
66    #[bits(5)]
67    pub css_reserved: u8,
68    pub multiple_io: bool,
69    pub admin_only: bool,
70    pub bps: bool,
71    #[bits(2)]
72    pub cps: u8,
73    #[bits(4)]
74    pub mpsmin: u8,
75    #[bits(4)]
76    pub mpsmax: u8,
77    pub pmrs: bool,
78    pub cmbs: bool,
79    pub nsss: bool,
80    pub crwms: bool,
81    pub crims: bool,
82    #[bits(3)]
83    pub reserved2: u64,
84}
85
86#[derive(Inspect)]
87#[bitfield(u32)]
88pub struct Cc {
89    pub en: bool,
90    #[bits(3)]
91    pub reserved: u8,
92    #[bits(3)]
93    pub css: u8,
94    #[bits(4)]
95    pub mps: u8,
96    #[bits(3)]
97    pub ams: u8,
98    #[bits(2)]
99    pub shn: u8,
100    #[bits(4)]
101    pub iosqes: u8,
102    #[bits(4)]
103    pub iocqes: u8,
104    pub crime: bool,
105    #[bits(7)]
106    pub reserved2: u8,
107}
108
109#[derive(Inspect)]
110#[bitfield(u32)]
111pub struct Csts {
112    pub rdy: bool,
113    pub cfs: bool,
114    #[bits(2)]
115    pub shst: u8,
116    pub nssro: bool,
117    pub pp: bool,
118    pub st: bool,
119    #[bits(25)]
120    pub reserved: u32,
121}
122
123#[derive(Inspect)]
124#[bitfield(u32)]
125pub struct Aqa {
126    #[bits(12)]
127    pub asqs_z: u16,
128    #[bits(4)]
129    pub reserved: u8,
130    #[bits(12)]
131    pub acqs_z: u16,
132    #[bits(4)]
133    pub reserved2: u8,
134}
135
136#[repr(C)]
137#[derive(
138    Copy,
139    Clone,
140    Debug,
141    IntoBytes,
142    Immutable,
143    KnownLayout,
144    FromBytes,
145    Inspect,
146    MeshPayload,
147    PartialEq,
148)]
149pub struct Command {
150    pub cdw0: Cdw0,
151    pub nsid: u32,
152    pub cdw2: u32,
153    pub cdw3: u32,
154    pub mptr: u64,
155    #[inspect(iter_by_index)]
156    pub dptr: [u64; 2],
157    pub cdw10: u32,
158    pub cdw11: u32,
159    pub cdw12: u32,
160    pub cdw13: u32,
161    pub cdw14: u32,
162    pub cdw15: u32,
163}
164static_assertions::assert_eq_size!(Command, [u8; 64]);
165
166#[derive(Inspect)]
167#[bitfield(u32)]
168#[derive(PartialEq, IntoBytes, Immutable, KnownLayout, FromBytes, MeshPayload)]
169pub struct Cdw0 {
170    pub opcode: u8,
171    #[bits(2)]
172    pub fuse: u8,
173    #[bits(4)]
174    pub reserved: u8,
175    #[bits(2)]
176    pub psdt: u8,
177    pub cid: u16,
178}
179
180#[repr(C)]
181pub struct Opcode(pub u8);
182
183impl Opcode {
184    pub fn transfer_controller_to_host(&self) -> bool {
185        self.0 & 0b10 != 0
186    }
187
188    pub fn transfer_host_to_controller(&self) -> bool {
189        self.0 & 0b01 != 0
190    }
191}
192
193open_enum! {
194    pub enum AdminOpcode: u8 {
195        DELETE_IO_SUBMISSION_QUEUE = 0x00,
196        CREATE_IO_SUBMISSION_QUEUE = 0x01,
197        GET_LOG_PAGE = 0x02,
198        DELETE_IO_COMPLETION_QUEUE = 0x04,
199        CREATE_IO_COMPLETION_QUEUE = 0x05,
200        IDENTIFY = 0x06,
201        ABORT = 0x08,
202        SET_FEATURES = 0x09,
203        GET_FEATURES = 0x0a,
204        ASYNCHRONOUS_EVENT_REQUEST = 0x0c,
205        NAMESPACE_MANAGEMENT = 0x0d,
206        FIRMWARE_COMMIT = 0x10,
207        FIRMWARE_IMAGE_DOWNLOAD = 0x11,
208        DEVICE_SELF_TEST = 0x14,
209        NAMESPACE_ATTACHMENT = 0x15,
210        KEEP_ALIVE = 0x18,
211        DIRECTIVE_SEND = 0x19,
212        DIRECTIVE_RECEIVE = 0x1a,
213        VIRTUALIZATION_MANAGEMENT = 0x1c,
214        NV_ME_MI_SEND = 0x1d,
215        NV_ME_MI_RECEIVE = 0x1e,
216        CAPACITY_MANAGEMENT = 0x20,
217        LOCKDOWN = 0x24,
218        DOORBELL_BUFFER_CONFIG = 0x7c,
219        FABRICS_COMMANDS = 0x7f,
220        FORMAT_NVM = 0x80,
221        SECURITY_SEND = 0x81,
222        SECURITY_RECEIVE = 0x82,
223        SANITIZE = 0x84,
224        GET_LBA_STATUS = 0x86,
225    }
226}
227
228#[repr(C)]
229#[derive(Debug, Clone, IntoBytes, Immutable, KnownLayout, FromBytes, MeshPayload)]
230pub struct Completion {
231    pub dw0: u32,
232    pub dw1: u32,
233    pub sqhd: u16,
234    pub sqid: u16,
235    pub cid: u16,
236    pub status: CompletionStatus,
237}
238static_assertions::assert_eq_size!(Completion, [u8; 16]);
239
240#[bitfield(u16)]
241#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, MeshPayload)]
242pub struct CompletionStatus {
243    pub phase: bool,
244    /// 8 bits of status code followed by 3 bits of the status code type.
245    #[bits(11)]
246    pub status: u16,
247    #[bits(2)]
248    pub crd: u8,
249    pub more: bool,
250    pub dnr: bool,
251}
252
253open_enum! {
254    #[derive(Default)]
255    pub enum StatusCodeType: u8 {
256        GENERIC = 0,
257        COMMAND_SPECIFIC = 1,
258        MEDIA_ERROR = 2,
259        PATH_RELATED = 3,
260        VENDOR_SPECIFIC = 7,
261    }
262}
263
264open_enum! {
265    #[derive(Default)]
266    pub enum Status: u16 {
267        SUCCESS = 0x00,
268        INVALID_COMMAND_OPCODE = 0x01,
269        INVALID_FIELD_IN_COMMAND = 0x02,
270        COMMAND_ID_CONFLICT = 0x03,
271        DATA_TRANSFER_ERROR = 0x04,
272        COMMANDS_ABORTED_DUE_TO_POWER_LOSS_NOTIFICATION = 0x05,
273        INTERNAL_ERROR = 0x06,
274        COMMAND_ABORT_REQUESTED = 0x07,
275        COMMAND_ABORTED_DUE_TO_SQ_DELETION = 0x08,
276        COMMAND_ABORTED_DUE_TO_FAILED_FUSED_COMMAND = 0x09,
277        COMMAND_ABORTED_DUE_TO_MISSING_FUSED_COMMAND = 0x0a,
278        INVALID_NAMESPACE_OR_FORMAT = 0x0b,
279        COMMAND_SEQUENCE_ERROR = 0x0c,
280        INVALID_SGL_SEGMENT_DESCRIPTOR = 0x0d,
281        INVALID_NUMBER_OF_SGL_DESCRIPTORS = 0x0e,
282        DATA_SGL_LENGTH_INVALID = 0x0f,
283        METADATA_SGL_LENGTH_INVALID = 0x10,
284        SGL_DESCRIPTOR_TYPE_INVALID = 0x11,
285        INVALID_USE_OF_CONTROLLER_MEMORY_BUFFER = 0x12,
286        PRP_OFFSET_INVALID = 0x13,
287        ATOMIC_WRITE_UNIT_EXCEEDED = 0x14,
288        OPERATION_DENIED = 0x15,
289        SGL_OFFSET_INVALID = 0x16,
290        RESERVED = 0x17,
291        HOST_IDENTIFIER_INCONSISTENT_FORMAT = 0x18,
292        KEEP_ALIVE_TIMER_EXPIRED = 0x19,
293        KEEP_ALIVE_TIMEOUT_INVALID = 0x1a,
294        COMMAND_ABORTED_DUE_TO_PREEMPT_AND_ABORT = 0x1b,
295        SANITIZE_FAILED = 0x1c,
296        SANITIZE_IN_PROGRESS = 0x1d,
297        SGL_DATA_BLOCK_GRANULARITY_INVALID = 0x1e,
298        COMMAND_NOT_SUPPORTED_FOR_QUEUE_IN_CMB = 0x1f,
299        NAMESPACE_IS_WRITE_PROTECTED = 0x20,
300        COMMAND_INTERRUPTED = 0x21,
301        TRANSIENT_TRANSPORT_ERROR = 0x22,
302        COMMAND_PROHIBITED_BY_COMMAND_AND_FEATURE_LOCKDOWN = 0x23,
303        ADMIN_COMMAND_MEDIA_NOT_READY = 0x24,
304
305        LBA_OUT_OF_RANGE = 0x80,
306        CAPACITY_EXCEEDED = 0x81,
307        NAMESPACE_NOT_READY = 0x82,
308        RESERVATION_CONFLICT = 0x83,
309        FORMAT_IN_PROGRESS = 0x84,
310
311        COMPLETION_QUEUE_INVALID = 0x100,
312        INVALID_QUEUE_IDENTIFIER = 0x101,
313        INVALID_QUEUE_SIZE = 0x102,
314        ABORT_COMMAND_LIMIT_EXCEEDED = 0x103,
315        RESERVED2 = 0x104,
316        ASYNCHRONOUS_EVENT_REQUEST_LIMIT_EXCEEDED = 0x105,
317        INVALID_FIRMWARE_SLOT = 0x106,
318        INVALID_FIRMWARE_IMAGE = 0x107,
319        INVALID_INTERRUPT_VECTOR = 0x108,
320        INVALID_LOG_PAGE = 0x109,
321        INVALID_FORMAT = 0x10a,
322        FIRMWARE_ACTIVATION_REQUIRES_CONVENTIONAL_RESET = 0x10b,
323        INVALID_QUEUE_DELETION = 0x10c,
324        FEATURE_IDENTIFIER_NOT_SAVEABLE = 0x10d,
325        FEATURE_NOT_CHANGEABLE = 0x10e,
326        FEATURE_NOT_NAMESPACE_SPECIFIC = 0x10f,
327        FIRMWARE_ACTIVATION_REQUIRES_NVM_SUBSYSTEM_RESET = 0x110,
328        FIRMWARE_ACTIVATION_REQUIRES_CONTROLLER_LEVEL_RESET = 0x111,
329        FIRMWARE_ACTIVATION_REQUIRES_MAXIMUM_TIME_VIOLATION = 0x112,
330        FIRMWARE_ACTIVATION_PROHIBITED = 0x113,
331        OVERLAPPING_RANGE = 0x114,
332        NAMESPACE_INSUFFICIENT_CAPACITY = 0x115,
333        NAMESPACE_IDENTIFIER_UNAVAILABLE = 0x116,
334        RESERVED3 = 0x117,
335        NAMESPACE_ALREADY_ATTACHED = 0x118,
336        NAMESPACE_IS_PRIVATE = 0x119,
337        NAMESPACE_NOT_ATTACHED = 0x11a,
338        THIN_PROVISIONING_NOT_SUPPORTED = 0x11b,
339        CONTROLLER_LIST_INVALID = 0x11c,
340        DEVICE_SELF_TEST_IN_PROGRESS = 0x11d,
341        BOOT_PARTITION_WRITE_PROHIBITED = 0x11e,
342        INVALID_CONTROLLER_IDENTIFIER = 0x11f,
343        INVALID_SECONDARY_CONTROLLER_STATE = 0x120,
344        INVALID_NUMBER_OF_CONTROLLER_RESOURCES = 0x121,
345        INVALID_RESOURCE_IDENTIFIER = 0x122,
346        SANITIZE_PROHIBITED_WHILE_PERSISTENT_MEMORY_REGION_IS_ENABLED = 0x123,
347        ANA_GROUP_IDENTIFIER_INVALID = 0x124,
348        ANA_ATTACH_FAILED = 0x125,
349        INSUFFICIENT_CAPACITY = 0x126,
350        NAMESPACE_ATTACHMENT_LIMIT_EXCEEDED = 0x127,
351        PROHIBITION_OF_COMMAND_EXECUTION_NOT_SUPPORTED = 0x128,
352        IO_COMMAND_SET_NOT_SUPPORTED = 0x129,
353        IO_COMMAND_SET_NOT_ENABLED = 0x12a,
354        IO_COMMAND_SET_COMBINATION_REJECTED = 0x12b,
355        INVALID_IO_COMMAND_SET = 0x12c,
356        IDENTIFIER_UNAVAILABLE = 0x12d,
357
358        CONFLICTING_ATTRIBUTES = 0x180,         // Dataset Management, Read, Write
359        INVALID_PROTECTION_INFORMATION = 0x181,         // Compare, Read, Write, Write Zeroes
360        ATTEMPTED_WRITE_TO_READ_ONLY_RANGE = 0x182,         // Dataset Management, Write, Write Uncorrectable, Write Zeroes
361        COMMAND_SIZE_LIMIT_EXCEEDED = 0x183,         // Dataset Management
362
363        MEDIA_WRITE_FAULT                             = 0x280,
364        MEDIA_UNRECOVERED_READ_ERROR                  = 0x281,
365        MEDIA_END_TO_END_GUARD_CHECK_ERROR            = 0x282,
366        MEDIA_END_TO_END_APPLICATION_TAG_CHECK_ERROR  = 0x283,
367        MEDIA_END_TO_END_REFERENCE_TAG_CHECK_ERROR    = 0x284,
368        MEDIA_COMPARE_FAILURE                         = 0x285,
369        MEDIA_ACCESS_DENIED                           = 0x286,
370        MEDIA_DEALLOCATED_OR_UNWRITTEN_LOGICAL_BLOCK  = 0x287,
371    }
372}
373
374impl Status {
375    pub fn status_code(&self) -> u8 {
376        self.0 as u8
377    }
378
379    pub fn status_code_type(&self) -> StatusCodeType {
380        StatusCodeType((self.0 >> 8) as u8)
381    }
382}
383
384// Identify
385#[bitfield(u32)]
386pub struct Cdw10Identify {
387    pub cns: u8,
388    pub reserved: u8,
389    pub cntid: u16,
390}
391
392open_enum! {
393    pub enum Cns: u8 {
394        NAMESPACE = 0x0,
395        CONTROLLER = 0x1,
396        ACTIVE_NAMESPACES = 0x2,
397        DESCRIPTOR_NAMESPACE = 0x3,
398        NVM_SET = 0x4,
399        SPECIFIC_NAMESPACE_IO_COMMAND_SET = 0x5,
400        SPECIFIC_CONTROLLER_IO_COMMAND_SET = 0x6,
401        ACTIVE_NAMESPACE_LIST_IO_COMMAND_SET = 0x7,
402        ALLOCATED_NAMESPACE_LIST = 0x10,
403        ALLOCATED_NAMESPACE = 0x11,
404        CONTROLLER_LIST_OF_NSID = 0x12,
405        CONTROLLER_LIST_OF_NVM_SUBSYSTEM = 0x13,
406        PRIMARY_CONTROLLER_CAPABILITIES = 0x14,
407        SECONDARY_CONTROLLER_LIST = 0x15,
408        NAMESPACE_GRANULARITY_LIST = 0x16,
409        UUID_LIST = 0x17,
410        DOMAIN_LIST = 0x18,
411        ENDURANCE_GROUP_LIST = 0x19,
412        ALLOCATED_NAMESPACE_LIST_IO_COMMAND_SET = 0x1a,
413        ALLOCATED_NAMESPACE_IO_COMMAND_SET = 0x1b,
414        IO_COMMAND_SET = 0x1c,
415    }
416}
417
418#[derive(Inspect)]
419#[bitfield(u16)]
420#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
421pub struct OptionalAdminCommandSupport {
422    pub security_send_security_receive: bool,
423    pub format_nvm: bool,
424    pub firmware_activate_firmware_download: bool,
425    pub ns_management: bool,
426    pub self_test: bool,
427    pub directives: bool,
428    pub nvme_mi_send_nvme_mi_receive: bool,
429    pub virtualization_management: bool,
430    pub doorbell_buffer_config: bool,
431    pub get_lba_status: bool,
432    pub command_feature_lockdown: bool,
433    #[bits(5)]
434    pub rsvd: u16,
435}
436
437#[repr(C)]
438#[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes, Inspect, Clone)]
439pub struct IdentifyController {
440    pub vid: u16,
441    pub ssvid: u16,
442    pub sn: AsciiString<20>,
443    pub mn: AsciiString<40>,
444    pub fr: AsciiString<8>,
445    pub rab: u8,
446    pub ieee: [u8; 3],
447    pub cmic: u8,
448    /// Maximum data transfer size (in minimum page size units, as power of
449    /// two).
450    pub mdts: u8,
451    pub cntlid: u16,
452    pub ver: u32,
453    pub rtd3r: u32,
454    pub rtd3e: u32,
455    pub oaes: Oaes,
456    pub ctratt: u32,
457    pub rrls: u16,
458    #[inspect(skip)]
459    pub rsvd1: [u8; 9],
460    pub cntrltype: ControllerType,
461    pub fguid: [u8; 16],
462    pub crdt1: u16,
463    pub crdt2: u16,
464    pub crdt3: u16,
465    #[inspect(skip)]
466    pub rsvd2: [u8; 106],
467    #[inspect(skip)]
468    pub rsvd3: [u8; 13],
469    pub nvmsr: u8,
470    pub vwci: u8,
471    pub mec: u8,
472    pub oacs: OptionalAdminCommandSupport,
473    pub acl: u8,
474    pub aerl: u8,
475    pub frmw: FirmwareUpdates,
476    pub lpa: u8,
477    pub elpe: u8,
478    pub npss: u8,
479    pub avscc: u8,
480    pub apsta: u8,
481    pub wctemp: u16,
482    pub cctemp: u16,
483    pub mtfa: u16,
484    pub hmpre: u32,
485    pub hmmin: u32,
486    #[inspect(display)]
487    pub tnvmcap: U128LE,
488    #[inspect(display)]
489    pub unvmcap: U128LE,
490    pub rpmbs: u32,
491    pub edstt: u16,
492    pub dsto: u8,
493    pub fwug: u8,
494    pub kas: u16,
495    pub hctma: u16,
496    pub mntmt: u16,
497    pub mxtmt: u16,
498    pub sanicap: u32,
499    pub hmminds: u32,
500    pub hmmaxd: u16,
501    pub nsetidmax: u16,
502    pub endgidmax: u16,
503    pub anatt: u8,
504    pub anacap: u8,
505    pub anagrpmax: u32,
506    pub nanagrpid: u32,
507    pub pels: u32,
508    pub domain_id: u16,
509    #[inspect(skip)]
510    pub rsvd4: [u8; 10],
511    #[inspect(display)]
512    pub megcap: U128LE,
513    #[inspect(skip)]
514    pub rsvd5: [u8; 128],
515    pub sqes: QueueEntrySize,
516    pub cqes: QueueEntrySize,
517    pub maxcmd: u16,
518    pub nn: u32,
519    pub oncs: Oncs,
520    pub fuses: u16,
521    pub fna: u8,
522    pub vwc: VolatileWriteCache,
523    pub awun: u16,
524    pub awupf: u16,
525    pub icsvscc: u8,
526    pub nwpc: u8,
527    pub acwu: u16,
528    pub copy_descriptor_fmt: u16,
529    pub sgls: u32,
530    pub mnan: u32,
531    #[inspect(display)]
532    pub maxdna: U128LE,
533    pub maxcna: u32,
534    #[inspect(skip)]
535    pub rsvd6: [u8; 204],
536    #[inspect(with = "|x| core::str::from_utf8(x).map(|s| s.trim_end_matches('\0')).ok()")]
537    pub subnqn: [u8; 256],
538    #[inspect(skip)]
539    pub rsvd7: [u8; 768],
540    pub ioccsz: u32,
541    pub iorcsz: u32,
542    pub icdoff: u16,
543    pub fcatt: u8,
544    pub msdbd: u8,
545    pub ofcs: u16,
546    #[inspect(skip)]
547    pub rsvd8: [u8; 242],
548    #[inspect(skip)]
549    pub power: [u8; 1024],
550    #[inspect(skip)]
551    pub vendor: [u8; 1024],
552}
553
554const _: () = assert!(size_of::<IdentifyController>() == 4096);
555
556#[derive(Inspect)]
557#[bitfield(u8)]
558#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
559pub struct QueueEntrySize {
560    #[bits(4)]
561    pub min: u8,
562    #[bits(4)]
563    pub max: u8,
564}
565
566#[derive(Inspect)]
567#[bitfield(u8)]
568#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
569pub struct FirmwareUpdates {
570    pub ffsro: bool,
571    #[bits(3)]
572    pub nofs: u8,
573    pub fawr: bool,
574    pub smud: bool,
575    #[bits(2)]
576    pub rsvd: u8,
577}
578
579/// Optional asynchronous events supported
580#[derive(Inspect)]
581#[bitfield(u32)]
582#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
583pub struct Oaes {
584    _rsvd: u8,
585    pub namespace_attribute: bool,
586    pub firmware_activation: bool,
587    _rsvd2: bool,
588    pub asymmetric_namespace_access_change: bool,
589    pub predictable_latency_event_aggregate_log_change: bool,
590    pub lba_status_information: bool,
591    pub endurance_group_event_aggregate_log_page_change: bool,
592    pub normal_nvm_subsystem_shutdown: bool,
593    _rsvd3: u16,
594}
595
596/// Optional NVM command support
597#[derive(Inspect)]
598#[bitfield(u16)]
599#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
600pub struct Oncs {
601    pub compare: bool,
602    pub write_uncorrectable: bool,
603    pub dataset_management: bool,
604    pub write_zeroes: bool,
605    pub save: bool,
606    pub reservations: bool,
607    pub timestamp: bool,
608    pub verify: bool,
609    pub copy: bool,
610    #[bits(7)]
611    _rsvd: u16,
612}
613
614open_enum! {
615    #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
616    #[inspect(debug)]
617    pub enum ControllerType: u8 {
618        RESERVED = 0,
619        IO_CONTROLLER = 1,
620        DISCOVERY_CONTROLLER = 2,
621        ADMINISTRATIVE_CONTROLLER = 3,
622    }
623}
624
625#[derive(Inspect)]
626#[bitfield(u8)]
627#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
628pub struct VolatileWriteCache {
629    pub present: bool,
630    #[bits(2)]
631    pub broadcast_flush_behavior: u8,
632    #[bits(5)]
633    _rsvd: u8,
634}
635
636open_enum! {
637    pub enum BroadcastFlushBehavior: u8 {
638        NOT_INDICATED = 0,
639        NOT_SUPPORTED = 2,
640        SUPPORTED = 3,
641    }
642}
643
644#[bitfield(u32)]
645pub struct Cdw10SetFeatures {
646    pub fid: u8,
647    #[bits(23)]
648    _rsvd: u32,
649    pub save: bool,
650}
651
652#[bitfield(u32)]
653pub struct Cdw10GetFeatures {
654    pub fid: u8,
655    #[bits(3)]
656    pub sel: u8,
657    #[bits(21)]
658    _rsvd: u32,
659}
660
661open_enum! {
662    pub enum Feature: u8 {
663        ARBITRATION = 0x01,
664        POWER_MANAGEMENT = 0x02,
665        LBA_RANGE_TYPE = 0x03,
666        TEMPERATURE_THRESHOLD = 0x04,
667        ERROR_RECOVERY = 0x05,
668        VOLATILE_WRITE_CACHE = 0x06,
669        NUMBER_OF_QUEUES = 0x07,
670        INTERRUPT_COALESCING = 0x08,
671        INTERRUPT_VECTOR_CONFIG = 0x09,
672        WRITE_ATOMICITY = 0x0a,
673        ASYNC_EVENT_CONFIG = 0x0b,
674        AUTONOMOUS_POWER_STATE_TRANSITION = 0x0c,
675        HOST_MEMORY_BUFFER = 0x0d,
676        TIMESTAMP = 0x0e,
677        KEEP_ALIVE = 0x0f,
678        HOST_CONTROLLED_THERMAL_MANAGEMENT = 0x10,
679        NONOPERATIONAL_POWER_STATE = 0x11,
680        READ_RECOVERY_LEVEL_CONFIG = 0x12,
681        PREDICTABLE_LATENCY_MODE_CONFIG = 0x13,
682        PREDICTABLE_LATENCY_MODE_WINDOW = 0x14,
683        LBA_STATUS_INFORMATION_REPORT_INTERVAL = 0x15,
684        HOST_BEHAVIOR_SUPPORT = 0x16,
685        SANITIZE_CONFIG = 0x17,
686        ENDURANCE_GROUP_EVENT_CONFIG = 0x18,
687        IO_COMMAND_SET_PROFILE = 0x19,
688        ENHANCED_CONTROLLER_METADATA = 0x7d,
689        CONTROLLER_METADATA = 0x7e,
690        NAMESPACE_METADATA = 0x7f,
691        NVM_SOFTWARE_PROGRESS_MARKER = 0x80,
692        NVM_HOST_IDENTIFIER = 0x81,
693        NVM_RESERVATION_NOTIFICATION_MASK = 0x82,
694        NVM_RESERVATION_PERSISTENCE = 0x83,
695        NVM_NAMESPACE_WRITE_PROTECTION_CONFIG = 0x84,
696    }
697}
698
699#[bitfield(u32)]
700pub struct Cdw11FeatureNumberOfQueues {
701    pub nsq_z: u16,
702    pub ncq_z: u16,
703}
704
705#[bitfield(u32)]
706pub struct Cdw11FeatureVolatileWriteCache {
707    pub wce: bool,
708    #[bits(31)]
709    _rsvd: u32,
710}
711
712#[bitfield(u32)]
713pub struct Cdw11FeatureReservationPersistence {
714    /// Persist through power loss
715    pub ptpl: bool,
716    #[bits(31)]
717    _rsvd: u32,
718}
719
720#[bitfield(u32)]
721pub struct Cdw10CreateIoQueue {
722    pub qid: u16,
723    pub qsize_z: u16,
724}
725
726#[bitfield(u32)]
727pub struct Cdw11CreateIoCompletionQueue {
728    pub pc: bool,
729    pub ien: bool,
730    #[bits(14)]
731    pub rsvd: u16,
732    pub iv: u16,
733}
734
735#[bitfield(u32)]
736pub struct Cdw11CreateIoSubmissionQueue {
737    pub pc: bool,
738    #[bits(2)]
739    pub qprio: u8,
740    #[bits(13)]
741    pub rsvd: u16,
742    pub cqid: u16,
743}
744
745#[bitfield(u32)]
746pub struct Cdw10DeleteIoQueue {
747    pub qid: u16,
748    pub rsvd: u16,
749}
750
751#[bitfield(u32)]
752pub struct Cdw10GetLogPage {
753    /// Log page identifier
754    pub lid: u8,
755    #[bits(7)]
756    pub lsp: u8,
757    /// Retain asynchronous event
758    pub rae: bool,
759    pub numdl_z: u16,
760}
761
762#[bitfield(u32)]
763pub struct Cdw11GetLogPage {
764    pub numdu: u16,
765    pub lsi: u16,
766}
767
768open_enum! {
769    pub enum LogPageIdentifier: u8 {
770        SUPPORTED_LOG_PAGES = 0,
771        ERROR_INFORMATION = 1,
772        HEALTH_INFORMATION = 2,
773        FIRMWARE_SLOT_INFORMATION = 3,
774        CHANGED_NAMESPACE_LIST = 4,
775    }
776}
777
778#[bitfield(u32)]
779pub struct AsynchronousEventRequestDw0 {
780    #[bits(3)]
781    pub event_type: u8,
782    #[bits(5)]
783    _rsvd: u8,
784    pub information: u8,
785    pub log_page_identifier: u8,
786    _rsvd2: u8,
787}
788
789open_enum! {
790    pub enum AsynchronousEventType: u8 {
791        ERROR_STATUS = 0b000,
792        HEALTH_STATUS = 0b001,
793        NOTICE = 0b010,
794        IMMEDIATE = 0b011,
795        IO_COMMAND_SPECIFIC = 0b110,
796        VENDOR_SPECIFIC = 0b111,
797    }
798}
799
800open_enum! {
801    pub enum AsynchronousEventInformationNotice: u8 {
802        NAMESPACE_ATTRIBUTE_CHANGED = 0,
803        FIRMWARE_ACTIVATION_STARTING = 1,
804        TELEMETRY_LOG_CHANGED = 2,
805        ASYMMETRIC_NAMESPACE_ACCESS_CHANGE = 3,
806        PREDICTABLE_LATENCY_EVENT_AGGREGATE_LOG_CHANGE = 4,
807        LBA_STATUS_INFORMATION_ALERT = 5,
808        ENDURANCE_GROUP_EVENT_AGGREGATE_LOG_PAGE_CHANGE = 6,
809    }
810}