nvme_mi_dev/
nvme.rs

1// SPDX-License-Identifier: GPL-3.0-only
2/*
3 * Copyright (c) 2025 Code Construct
4 */
5pub mod mi;
6
7use deku::ctx::{BitSize, Endian, Order};
8use deku::{DekuError, DekuRead, DekuWrite, deku_derive};
9use flagset::flags;
10use log::debug;
11
12use crate::wire::WireFlagSet;
13use crate::wire::WireString;
14use crate::wire::WireUuid;
15use crate::wire::WireVec;
16use crate::{Discriminant, Encode};
17
18// Base v2.1, 3.1.4, Figure 33
19#[repr(usize)]
20pub enum ControllerProperties {
21    Cc(ControllerConfiguration) = 0x14,
22}
23
24// Base v2.1, 3.1.4.5, Figure 41
25#[derive(Clone, Copy, Debug, Default)]
26pub struct ControllerConfiguration {
27    pub en: bool,
28}
29
30// Base v2.1, 3.1.4.6, Figure 42
31flags! {
32    #[repr(u32)]
33    pub enum ControllerStatusFlags: u32 {
34        Rdy = 1 << 0,
35        Cfs = 1 << 1,
36        ShstInProgress = 1 << 2,
37        ShstComplete = 1 << 3,
38        ShstReserved = (ControllerStatusFlags::ShstInProgress | ControllerStatusFlags::ShstComplete).bits(),
39        Nssro = 1 << 4,
40        Pp = 1 << 5,
41        St = 1 << 6,
42    }
43}
44
45// Base v2.1, 4.2.1, Figure 98
46//
47// Switch to LSB order because the packing of these fields is just messy,
48// largely thanks to the position of P. However, the SC / SCT ordering also
49// throws ergonomic deku representations straight out the window.
50#[derive(Debug, DekuRead, DekuWrite)]
51#[deku(bit_order = "lsb", ctx = "endian: Endian", endian = "endian")]
52struct AdminIoCqeStatus {
53    cid: u16,
54    #[deku(bits = 1)]
55    p: bool,
56    #[deku(bits = 8)]
57    sc: u8,
58    #[deku(bits = 3)]
59    sct: u8,
60    #[deku(bits = 2)]
61    crd: CommandRetryDelay,
62    #[deku(bits = 1)]
63    m: bool,
64    #[deku(bits = 1)]
65    dnr: bool,
66}
67
68impl From<AdminIoCqeStatusType> for AdminIoCqeStatus {
69    fn from(value: AdminIoCqeStatusType) -> Self {
70        match value {
71            AdminIoCqeStatusType::GenericCommandStatus(sts) => AdminIoCqeStatus {
72                cid: 0,
73                sc: sts as u8,
74                p: true,
75                dnr: sts != AdminIoCqeGenericCommandStatus::SuccessfulCompletion,
76                m: false,
77                crd: CommandRetryDelay::None,
78                sct: value.id(),
79            },
80            AdminIoCqeStatusType::CommandSpecificStatus(sts) => AdminIoCqeStatus {
81                cid: 0,
82                sc: sts,
83                p: true,
84                dnr: true,
85                m: false,
86                crd: CommandRetryDelay::None,
87                sct: value.id(),
88            },
89            AdminIoCqeStatusType::MediaAndDataIntegrityErrors => todo!(),
90            AdminIoCqeStatusType::PathRelatedStatus => todo!(),
91            AdminIoCqeStatusType::VendorSpecific => todo!(),
92        }
93    }
94}
95
96// Base v2.1, 4.2.3, Figure 100, CRD
97#[derive(Debug, DekuRead, DekuWrite)]
98#[deku(
99    bits = "bits.0",
100    bit_order = "order",
101    ctx = "endian: Endian, bits: BitSize, order: Order",
102    endian = "endian",
103    id_type = "u8"
104)]
105#[repr(u8)]
106enum CommandRetryDelay {
107    None = 0x00,
108    Time1 = 0x01,
109    Time2 = 0x02,
110    Time3 = 0x03,
111}
112
113// Base v2.1, 4.2.3, Figure 101
114#[derive(Clone, Copy, Debug, Eq, PartialEq)]
115#[repr(u8)]
116enum AdminIoCqeStatusType {
117    GenericCommandStatus(AdminIoCqeGenericCommandStatus) = 0x00,
118    CommandSpecificStatus(u8) = 0x01,
119    #[expect(dead_code)]
120    MediaAndDataIntegrityErrors = 0x02,
121    #[expect(dead_code)]
122    PathRelatedStatus = 0x03,
123    #[expect(dead_code)]
124    VendorSpecific = 0x07,
125}
126unsafe impl Discriminant<u8> for AdminIoCqeStatusType {}
127
128// Base v2.1, 4.2.3.1, Figure 102
129#[derive(Clone, Copy, Debug, Eq, PartialEq)]
130#[repr(u8)]
131enum AdminIoCqeGenericCommandStatus {
132    SuccessfulCompletion = 0x00,
133    InvalidFieldInCommand = 0x02,
134    InternalError = 0x06,
135    InvalidNamespaceOrFormat = 0x0b,
136}
137
138impl From<DekuError> for AdminIoCqeGenericCommandStatus {
139    fn from(err: DekuError) -> Self {
140        debug!("Codec operation failed: {err}");
141        Self::InternalError
142    }
143}
144
145// Base v2.1, 4.6.1, Figure 137
146// TODO: Unify with ControllerListResponse
147#[derive(Debug, DekuRead, Eq, PartialEq)]
148#[deku(ctx = "endian: Endian", endian = "little")]
149struct ControllerListRequest {
150    numids: u16,
151    #[deku(count = "*numids")]
152    ids: WireVec<u16, 2047>,
153}
154
155// Base v2.1, 5.1.10, Figure 189, SES
156#[derive(Debug, DekuRead, DekuWrite, Eq, PartialEq)]
157#[deku(
158    bits = "bits.0",
159    ctx = "endian: Endian, bits: BitSize",
160    endian = "endian",
161    id_type = "u8"
162)]
163#[repr(u8)]
164enum SecureEraseSettings {
165    NoOperation = 0b000,
166    UserDataErase = 0b001,
167    CryptographicErase = 0b010,
168}
169
170// Base v2.1, 5.1.10, Figure 189
171#[derive(Debug, DekuRead, DekuWrite, Eq, PartialEq)]
172#[deku(ctx = "endian: Endian", endian = "endian")]
173struct AdminFormatNvmConfiguration {
174    #[deku(bits = "3")]
175    pi: u8,
176    #[deku(bits = "1")]
177    mset: bool,
178    #[deku(bits = "4")]
179    lbafl: u8,
180    #[deku(bits = "2", pad_bits_before = "2")]
181    lbafu: u8,
182    #[deku(bits = "3")]
183    ses: SecureEraseSettings,
184    #[deku(bits = "1", pad_bytes_after = "2")]
185    pil: bool,
186}
187
188impl AdminFormatNvmConfiguration {
189    fn lbafi(&self) -> u8 {
190        self.lbafu << 4 | self.lbafl
191    }
192}
193
194// Base v2.1, 5.1.12, Figure 202
195// MI v2.0, 6.3, Figure 141
196#[derive(Debug, DekuRead, DekuWrite, Eq, PartialEq)]
197#[deku(ctx = "endian: Endian, lid: u8", id = "lid", endian = "endian")]
198#[repr(u8)]
199pub enum AdminGetLogPageLidRequestType {
200    SupportedLogPages = 0x00,
201    ErrorInformation = 0x01,
202    SmartHealthInformation = 0x02,
203    FeatureIdentifiersSupportedAndEffects = 0x12,
204    SanitizeStatus = 0x81,
205}
206unsafe impl crate::Discriminant<u8> for AdminGetLogPageLidRequestType {}
207
208// Base v2.1, 5.1.12.1.1, Figure 203
209#[derive(Debug, DekuRead, DekuWrite)]
210#[deku(endian = "little")]
211pub struct AdminGetLogPageSupportedLogPagesResponse {
212    lsids: WireVec<LidSupportedAndEffectsDataStructure, 256>,
213}
214impl Encode<1024> for AdminGetLogPageSupportedLogPagesResponse {}
215
216// Base v2.1, 5.1.12.1.1, Figure 204
217flags! {
218    pub enum LidSupportedAndEffectsFlags: u8 {
219        Lsupp,
220        Ios,
221    }
222}
223
224// Base v2.1, 5.1.12.1.1, Figure 204
225#[derive(Clone, Copy, Debug, DekuRead, DekuWrite)]
226#[deku(ctx = "endian: Endian", endian = "endian")]
227pub struct LidSupportedAndEffectsDataStructure {
228    flags: WireFlagSet<LidSupportedAndEffectsFlags>,
229    #[deku(seek_from_current = "1")]
230    lidsp: u16,
231}
232
233// Base v2.1, 5.1.12.1.3, Figure 206, CW
234flags! {
235    pub enum CriticalWarningFlags: u8 {
236        Ascbt,
237        Ttc,
238        Ndr,
239        Amro,
240        Vmbf,
241        Pmrro,
242    }
243}
244
245// Base v2.1, 5.1.12.1.3, Figure 206, EGCWS
246flags! {
247    pub enum EnduranceGroupCriticalWarningSummaryFlags: u8 {
248        Egascbt = 1 << 0,
249        Egdr = 1 << 2,
250        Egro = 1 << 3,
251    }
252}
253
254// Base v2.1, 5.1.12.1.3, Figure 206
255#[derive(Debug, Default, DekuRead, DekuWrite)]
256#[deku(endian = "little")]
257pub struct SmartHealthInformationLogPageResponse {
258    cw: WireFlagSet<CriticalWarningFlags>,
259    ctemp: u16,
260    avsp: u8,
261    avspt: u8,
262    pused: u8,
263    egcws: WireFlagSet<EnduranceGroupCriticalWarningSummaryFlags>,
264    #[deku(seek_from_current = "25")]
265    dur: u128,
266    duw: u128,
267    hrc: u128,
268    hwc: u128,
269    cbt: u128,
270    pwrc: u128,
271    poh: u128,
272    upl: u128,
273    mdie: u128,
274    neile: u128,
275    wctt: u32,
276    cctt: u32,
277    tsen: [u16; 8],
278    tmttc: [u32; 2],
279    #[deku(pad_bytes_after = "280")]
280    tttmt: [u32; 2],
281}
282impl Encode<512> for SmartHealthInformationLogPageResponse {}
283
284// Base v2.1, 5.1.12.1.18, Figure 262
285flags! {
286    pub enum FidSupportedAndEffectsFlags: u32 {
287        Fsupp = 1 << 0,
288        Udcc = 1 << 1,
289        Ncc = 1 << 2,
290        Nic = 1 << 3,
291        Ccc = 1 << 4,
292        Uss = 1 << 19,
293        FspNscpe = 1 << 20,
294        FspCscpe = 1 << 21,
295        FspNsetscpe = 1 << 22,
296        FspEgscpe = 1 << 23,
297        FspDscpe = 1 << 24,
298        FspNsubscpe = 1 << 25,
299        FspCdqscp = 1 << 26,
300        FspMask = (
301            FidSupportedAndEffectsFlags::FspNscpe
302            | FidSupportedAndEffectsFlags::FspNsetscpe
303            | FidSupportedAndEffectsFlags::FspEgscpe
304            | FidSupportedAndEffectsFlags::FspNsubscpe
305            | FidSupportedAndEffectsFlags::FspCdqscp
306        ).bits()
307    }
308}
309
310// Base v2.1, 5.1.12.1.33, Figure 291, SSTAT, SOS
311#[derive(Clone, Copy, Debug, Default, DekuRead, DekuWrite, Eq, PartialEq)]
312#[deku(
313    bits = "bits.0",
314    ctx = "endian: Endian, bits: BitSize",
315    endian = "endian",
316    id_type = "u8"
317)]
318#[repr(u8)]
319pub enum SanitizeOperationStatus {
320    #[default]
321    SanitizeNeverStarted = 0b000,
322    Sanitized = 0b001,
323    Sanitizing = 0b010,
324    SanitizeFailed = 0b011,
325    SanitizedUnexpectedDeallocate = 0b100,
326}
327unsafe impl crate::Discriminant<u8> for SanitizeOperationStatus {}
328
329// Base v2.1, 5.1.12.1.33, Figure 291, SSTAT
330#[derive(Clone, Copy, Debug, Default, DekuRead, DekuWrite)]
331#[deku(ctx = "endian: Endian", endian = "endian")]
332pub struct SanitizeStatus {
333    #[deku(bits = "5")]
334    opc: u8,
335    #[deku(bits = "3")]
336    sos: SanitizeOperationStatus,
337    #[deku(bits = "1", pad_bits_before = "6")]
338    mvcncled: bool,
339    #[deku(bits = "1")]
340    gde: bool,
341}
342
343// Base v2.1, 5.12.1.33, Fgure 291, SSI, SANS
344#[derive(Clone, Copy, Debug, Default, DekuRead, DekuWrite, Eq, PartialEq)]
345#[deku(
346    bits = "bits.0",
347    ctx = "endian: Endian, bits: BitSize",
348    endian = "endian",
349    id_type = "u8"
350)]
351#[repr(u8)]
352enum SanitizeState {
353    #[default]
354    Idle = 0x00,
355    RestrictedProcessing = 0x01,
356    RestrictedFailure = 0x02,
357    UnrestrictedProcessing = 0x03,
358    UnrestrictedFailure = 0x04,
359    MediaVerification = 0x05,
360    PostVerificationDeallocation = 0x06,
361}
362unsafe impl crate::Discriminant<u8> for SanitizeState {}
363
364// Base v2.1, 5.1.12.1.33, Figure 291, SSI
365#[derive(Clone, Copy, Debug, Default, DekuRead, DekuWrite)]
366#[deku(ctx = "endian: Endian", endian = "endian")]
367pub struct SanitizeStateInformation {
368    #[deku(bits = "4")]
369    fails: u8,
370    #[deku(bits = "4")]
371    sans: SanitizeState,
372}
373
374// Base v2.1, 5.1.12.1.33, Figure 291
375#[derive(Debug, DekuRead, DekuWrite)]
376#[deku(endian = "little")]
377struct SanitizeStatusLogPageResponse {
378    sprog: u16,
379    sstat: SanitizeStatus,
380    scdw10: AdminSanitizeConfiguration,
381    eto: u32,
382    etbe: u32,
383    etce: u32,
384    etodmm: u32,
385    etbenmm: u32,
386    etcenmm: u32,
387    etpvds: u32,
388    ssi: SanitizeStateInformation,
389}
390impl Encode<512> for SanitizeStatusLogPageResponse {}
391
392// Base v2.1, 5.1.13.1, Figure 310
393#[derive(Clone, Copy, Debug, DekuRead, DekuWrite, Eq, PartialEq)]
394#[deku(ctx = "endian: Endian, cns: u8", id = "cns", endian = "endian")]
395#[repr(u8)]
396enum AdminIdentifyCnsRequestType {
397    NvmIdentifyNamespace = 0x00,
398    IdentifyController = 0x01,
399    ActiveNamespaceIDList = 0x02,
400    NamespaceIdentificationDescriptorList = 0x03,
401    IoIdentifyNamespace = 0x05,
402    IoIdentifyController = 0x06,
403    IoActiveNamespaceIdList = 0x07,
404    IdentifyNamespace = 0x08,
405    AllocatedNamespaceIdList = 0x10,
406    IdentifyNamespaceForAllocatedNamespaceId = 0x11,
407    NamespaceAttachedControllerList = 0x12,
408    NvmSubsystemControllerList = 0x13,
409    SecondaryControllerList = 0x15,
410}
411unsafe impl Discriminant<u8> for AdminIdentifyCnsRequestType {}
412
413// Base v2.1, 5.1.13.1, Figure 310
414// NVM Command Set v1.0c, 4.1.5.1, Figure 97
415#[derive(Debug, Default, DekuRead, DekuWrite)]
416#[deku(endian = "little")]
417pub struct AdminIdentifyNvmIdentifyNamespaceResponse {
418    nsze: u64,
419    ncap: u64,
420    nuse: u64,
421    nsfeat: u8,
422    nlbaf: u8,
423    flbas: u8,
424    mc: u8,
425    dpc: u8,
426    dps: u8,
427    #[deku(seek_from_current = "18")]
428    nvmcap: u128,
429    #[deku(seek_from_current = "64")]
430    // FIXME: use another struct
431    lbaf0: u16,
432    lbaf0_lbads: u8,
433    lbaf0_rp: u8,
434}
435impl Encode<4096> for AdminIdentifyNvmIdentifyNamespaceResponse {}
436
437impl From<&crate::Namespace> for AdminIdentifyNvmIdentifyNamespaceResponse {
438    fn from(value: &crate::Namespace) -> Self {
439        Self {
440            nsze: value.size,
441            ncap: value.capacity,
442            nuse: value.used,
443            nsfeat: ((value.size == value.capacity) as u8),
444            nlbaf: 0,
445            flbas: 0,
446            mc: 0,
447            dpc: 0,
448            dps: 0,
449            nvmcap: 2_u128.pow(value.block_order as u32) * value.size as u128,
450            lbaf0: 0,
451            lbaf0_lbads: value.block_order,
452            lbaf0_rp: 0,
453        }
454    }
455}
456
457// Base v2.1, 5.1.13.1, Figure 311
458#[derive(Clone, Copy, Debug, DekuRead, DekuWrite)]
459#[deku(id_type = "u8", endian = "endian", ctx = "endian: Endian")]
460#[repr(u8)]
461pub enum CommandSetIdentifier {
462    Nvm = 0x00,
463    KeyValue = 0x01,
464    ZonedNamespace = 0x02,
465    SubsystemLocalMemory = 0x03,
466    ComputationalPrograms = 0x04,
467}
468
469// Base v2.1, 5.1.13.2.1, Figure 312, CMIC
470flags! {
471    enum ControllerMultipathIoNamespaceSharingCapabilityFlags: u8 {
472        Mports,
473        Mctrs,
474        Ft,
475        Anars,
476    }
477}
478
479// Base v2.1, 5.1.13.2.1, Figure 312, CTRATT
480flags! {
481    enum ControllerAttributeFlags: u32 {
482        Hids,
483        Nopspm,
484        Nsets,
485        Rrlvls,
486        Egs,
487        Plm,
488        Tbkas,
489        Ng,
490        Sqa,
491        Ulist,
492        Mds,
493        Fcm,
494        Vcm,
495        Deg,
496        Dnvms,
497        Elbas,
498        Mem,
499        Hmbr,
500        Rhii,
501        Fdps,
502    }
503}
504
505// Base v2.1, 5.1.13.2.1, Figure 312, CNTRLTYPE
506#[derive(Clone, Copy, Debug, DekuRead, DekuWrite, PartialEq)]
507#[deku(id_type = "u8", endian = "endian", ctx = "endian: Endian")]
508#[repr(u8)]
509enum ControllerType {
510    Reserved = 0x00,
511    IoController = 0x01,
512    DiscoveryController = 0x02,
513    AdministrativeController = 0x03,
514}
515
516impl From<crate::ControllerType> for ControllerType {
517    fn from(value: crate::ControllerType) -> Self {
518        match value {
519            crate::ControllerType::Io => Self::IoController,
520            crate::ControllerType::Discovery => Self::DiscoveryController,
521            crate::ControllerType::Administrative => Self::AdministrativeController,
522        }
523    }
524}
525
526// Base v2.1, 5.1.13.2.1, Figure 312, NVMSR
527flags! {
528    enum NvmSubsystemReportFlags: u8 {
529        Nvmesd,
530        Nvmee,
531    }
532}
533
534// Base v2.1, 5.1.13.2.1, Figure 312, MEC
535flags! {
536    enum ManagementEndpointCapabilityFlags: u8 {
537        Twpme,
538        Pcieme,
539    }
540}
541
542// Base v2.1, 5.1.13.2.1, Figure 312, LPA
543flags! {
544    #[repr(u8)]
545    pub enum LogPageAttributes: u8 {
546        Smarts,
547        Cses,
548        Lpeds,
549        Ts,
550        Pes,
551        Mlps,
552        Da4s,
553    }
554}
555
556// Base v2.1, 5.1.13.2.1, Figure 312, SANICAP, NODMMAS
557#[derive(Clone, Copy, Debug, Default, DekuRead, DekuWrite)]
558#[deku(
559    bits = "bits.0",
560    bit_order = "order",
561    ctx = "endian: Endian, bits: BitSize, order: Order",
562    endian = "endian",
563    id_type = "u8"
564)]
565#[repr(u8)]
566pub enum NoDeallocateModifiesMediaAfterSanitize {
567    Undefined = 0b00,
568    #[default]
569    Unmodified = 0b01,
570    Modified = 0b10,
571    Reserved = 0b11,
572}
573
574// Base v2.1, 5.1.13.2.1, Figure 312, SANICAP
575flags! {
576    pub enum SanitizeCapabilityFlags: u32 {
577        Ces = 1 << 0,
578        Bes = 1 << 1,
579        Ows = 1 << 2,
580        Vers = 1 << 3,
581        Ndi = 1 << 29,
582    }
583}
584
585// Base v2.1, 5.1.13.2.1, Figure 312, SANICAP
586#[derive(Clone, Copy, Debug, DekuRead, DekuWrite)]
587#[deku(bit_order = "lsb", ctx = "endian: Endian", endian = "endian")]
588pub struct SanitizeCapabilities {
589    #[deku(bits = 30)]
590    caps: WireFlagSet<SanitizeCapabilityFlags>,
591    #[deku(bits = 2)]
592    nodmmas: NoDeallocateModifiesMediaAfterSanitize,
593}
594
595// Base v2.1, 5.1.13.2.1, Figure 312, FNA
596flags! {
597    pub enum FormatNvmAttributes: u8 {
598        Fns,
599        Sens,
600        Cryes,
601        Fnvmbs,
602    }
603}
604
605// Base v2.1, 5.1.13.2.1, Figure 312
606#[derive(Debug, DekuRead, DekuWrite)]
607#[deku(endian = "little")]
608struct AdminIdentifyControllerResponse {
609    vid: u16,
610    ssvid: u16,
611    sn: WireString<20>,
612    mn: WireString<40>,
613    fr: WireString<8>,
614    rab: u8,
615    ieee: [u8; 3],
616    cmic: WireFlagSet<ControllerMultipathIoNamespaceSharingCapabilityFlags>,
617    mdts: u8,
618    cntlid: u16,
619    ver: u32,
620    rtd3r: u32,
621    rtd3e: u32,
622    oaes: u32,
623    ctratt: WireFlagSet<ControllerAttributeFlags>,
624    #[deku(seek_from_current = "11")]
625    cntrltype: crate::nvme::ControllerType,
626    #[deku(seek_from_current = "141")]
627    nvmsr: WireFlagSet<NvmSubsystemReportFlags>,
628    vwci: u8,
629    mec: WireFlagSet<ManagementEndpointCapabilityFlags>,
630    ocas: u16,
631    acl: u8,
632    aerl: u8,
633    frmw: u8,
634    lpa: WireFlagSet<LogPageAttributes>,
635    elpe: u8,
636    npss: u8,
637    avscc: u8,
638    apsta: u8,
639    wctemp: u16,
640    cctemp: u16,
641    #[deku(seek_from_current = "49")]
642    fwug: u8,
643    kas: u16,
644    #[deku(seek_from_current = "6")]
645    sanicap: SanitizeCapabilities,
646    #[deku(seek_from_current = "54")]
647    cqt: u16,
648    #[deku(seek_from_current = "124")]
649    sqes: u8,
650    cqes: u8,
651    maxcmd: u16,
652    nn: u32,
653    oncs: u16,
654    fuses: u16,
655    fna: WireFlagSet<FormatNvmAttributes>,
656    vwc: u8,
657    awun: u16,
658    awupf: u16,
659    icsvscc: u8,
660    nwpc: u8,
661    #[deku(seek_from_current = "8")]
662    mnan: u32,
663    #[deku(seek_from_current = "224")]
664    subnqn: WireString<256>,
665    #[deku(seek_from_current = "778")]
666    fcatt: u8,
667    msdbd: u8,
668    ofcs: u16,
669}
670impl Encode<4096> for AdminIdentifyControllerResponse {}
671
672// Base v2.1, 5.1.13.2.2
673#[derive(Debug, DekuRead, DekuWrite)]
674#[deku(endian = "little")]
675struct AdminIdentifyActiveNamespaceIdListResponse {
676    nsid: WireVec<u32, 1024>,
677}
678impl Encode<4096> for AdminIdentifyActiveNamespaceIdListResponse {}
679
680impl AdminIdentifyActiveNamespaceIdListResponse {
681    fn new() -> Self {
682        Self {
683            nsid: WireVec::new(),
684        }
685    }
686}
687
688// Base v2.1, 5.1.13.2.3, Figure 315
689#[derive(Clone, Copy, Debug, DekuRead, DekuWrite)]
690#[deku(id_type = "u8", endian = "endian", ctx = "endian: Endian")]
691#[repr(u8)]
692enum NamespaceIdentifierType {
693    Reserved = 0,
694    #[deku(id = 1)]
695    Ieuid(u8, u16, [u8; 8]),
696    #[deku(id = 2)]
697    Nguid(u8, u16, [u8; 16]),
698    #[deku(id = 3)]
699    Nuuid(u8, u16, WireUuid),
700    #[deku(id = 4)]
701    Csi(u8, u16, crate::nvme::CommandSetIdentifier),
702}
703
704impl From<crate::NamespaceIdentifierType> for NamespaceIdentifierType {
705    fn from(value: crate::NamespaceIdentifierType) -> Self {
706        match value {
707            crate::NamespaceIdentifierType::Ieuid(v) => Self::Ieuid(v.len() as u8, 0, v),
708            crate::NamespaceIdentifierType::Nguid(v) => Self::Nguid(v.len() as u8, 0, v),
709            crate::NamespaceIdentifierType::Nuuid(uuid) => Self::Nuuid(16, 0, WireUuid::new(uuid)),
710            crate::NamespaceIdentifierType::Csi(v) => Self::Csi(1, 0, v),
711        }
712    }
713}
714
715// Base v2.1, 5.1.13.2.3, Figure 315
716#[derive(Debug)]
717#[deku_derive(DekuRead, DekuWrite)]
718#[deku(endian = "little")]
719struct AdminIdentifyNamespaceIdentificationDescriptorListResponse {
720    nids: WireVec<NamespaceIdentifierType, { crate::MAX_NIDTS }>,
721}
722impl Encode<4096> for AdminIdentifyNamespaceIdentificationDescriptorListResponse {}
723
724// Base v2.1, 5.1.13.2.9
725#[derive(Debug, DekuRead, DekuWrite)]
726#[deku(endian = "little")]
727struct AdminIdentifyAllocatedNamespaceIdListResponse {
728    nsid: WireVec<u32, 1024>,
729}
730impl Encode<4096> for AdminIdentifyAllocatedNamespaceIdListResponse {}
731
732// Base v2.1, Section 5.1.13.2.12
733#[derive(Debug, DekuWrite)]
734#[deku(endian = "little")]
735struct ControllerListResponse {
736    #[deku(update = "self.ids.len()")]
737    numids: u16,
738    #[deku(count = "numids")]
739    ids: WireVec<u16, 2047>,
740}
741impl Encode<4096> for ControllerListResponse {}
742
743impl ControllerListResponse {
744    fn new() -> Self {
745        Self {
746            numids: 0,
747            ids: WireVec::new(),
748        }
749    }
750}
751
752// Base v2.1, 5.1.20.1, Figure 364, SEL
753#[derive(Debug, DekuRead, Eq, PartialEq)]
754#[deku(ctx = "endian: Endian", endian = "endian", id_type = "u8")]
755#[repr(u8)]
756enum AdminNamespaceAttachmentSelect {
757    ControllerAttach = 0x00,
758    ControllerDetach = 0x01,
759}
760
761// Base v2.1, 5.1.21, Figure 376, SEL
762#[derive(Debug, DekuRead, DekuWrite, Eq, PartialEq)]
763#[deku(ctx = "endian: Endian, sel: u8", endian = "endian", id = "sel")]
764#[repr(u8)]
765enum AdminNamespaceManagementSelect {
766    #[deku(id = 0x00)]
767    Create(NvmNamespaceManagementCreate),
768    Delete = 0x01,
769}
770
771// Base v2.1, 5.1.21
772// NVM Command Set v1.0c, 4.1.6, Figure 105
773#[derive(Debug, DekuRead, DekuWrite, Eq, PartialEq)]
774#[deku(ctx = "endian: Endian", endian = "endian")]
775struct NvmNamespaceManagementCreate {
776    nsze: u64,
777    ncap: u64,
778    #[deku(seek_from_current = "10")]
779    flbas: u8,
780    #[deku(seek_from_current = "2")]
781    dps: u8,
782    nmic: u8,
783    #[deku(seek_from_current = "61")]
784    anagrpid: u32,
785    #[deku(seek_from_current = "4")]
786    nvmsetid: u16,
787    endgid: u16,
788    #[deku(seek_from_current = "280")]
789    #[deku(pad_bytes_after = "3704")]
790    lbstm: u64,
791}
792
793// Base v2.1, 5.1.22, Figure 372, SANACT
794#[derive(Clone, Copy, Debug, Default, DekuRead, DekuWrite, Eq, PartialEq)]
795#[deku(
796    bits = "bits.0",
797    ctx = "endian: Endian, bits: BitSize",
798    endian = "endian",
799    id_type = "u8"
800)]
801#[repr(u8)]
802enum SanitizeAction {
803    #[default]
804    Reserved = 0x00,
805    ExitFailureMode = 0x01,
806    StartBlockErase = 0x02,
807    StartOverwrite = 0x03,
808    StartCryptoErase = 0x04,
809    ExitMediaVerificationState = 0x05,
810}
811
812impl TryFrom<u32> for SanitizeAction {
813    type Error = ();
814
815    fn try_from(value: u32) -> Result<Self, Self::Error> {
816        match value {
817            0x00 => Ok(Self::Reserved),
818            0x01 => Ok(Self::ExitFailureMode),
819            0x02 => Ok(Self::StartBlockErase),
820            0x03 => Ok(Self::StartOverwrite),
821            0x04 => Ok(Self::StartCryptoErase),
822            0x05 => Ok(Self::ExitMediaVerificationState),
823            _ => Err(()),
824        }
825    }
826}
827
828// Base v2.1, 5.1.22, Figure 372
829#[derive(Clone, Copy, Debug, Default, DekuRead, DekuWrite, Eq, PartialEq)]
830#[deku(ctx = "endian: Endian", endian = "endian")]
831pub struct AdminSanitizeConfiguration {
832    #[deku(bits = "4")]
833    owpass: u8,
834    #[deku(bits = "1")]
835    ause: bool,
836    #[deku(bits = "3")]
837    sanact: SanitizeAction,
838    #[deku(bits = "1", pad_bits_before = "5")]
839    emvs: bool,
840    #[deku(bits = "1")]
841    ndas: bool,
842    #[deku(bits = "1", pad_bytes_after = "2")]
843    oipbp: bool,
844}
845
846// Base v2.1, 5.1.25, Figure 385
847// Base v2.1, 3.1.3.6, Figure 32
848#[derive(Debug, DekuRead, DekuWrite)]
849#[deku(ctx = "endian: Endian", endian = "endian", id_type = "u8")]
850#[repr(u8)]
851pub enum FeatureIdentifiers {
852    KeepAliveTimer = 0x0f,
853}