1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use core::cmp::min;
use core::fmt::Debug;

use modular_bitfield::prelude::*;

#[derive(Clone)]
#[repr(C)]
pub struct IdentifyNamespaceDataStructure {
    pub size: u64,
    pub capacity: u64,
    pub utilization: u64,
    pub features: NamespaceFeatures,
    num_lba_formats: u8,
    pub formatted_lba_size: FormattedLbaSize,
    _resv: [u8; 101],
    lba_format_support: [LbaFormat; 64],
    _resv2: [u8; 4096 - 384],
}

impl Default for IdentifyNamespaceDataStructure {
    fn default() -> Self {
        Self {
            size: Default::default(),
            capacity: Default::default(),
            utilization: Default::default(),
            features: Default::default(),
            num_lba_formats: Default::default(),
            formatted_lba_size: Default::default(),
            _resv: [0; 101],
            lba_format_support: [Default::default(); 64],
            _resv2: [0; 4096 - 384],
        }
    }
}

impl Debug for IdentifyNamespaceDataStructure {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("IdentifyNamespaceDataStructure")
            .field("size", &self.size)
            .field("capacity", &self.capacity)
            .field("utilization", &self.utilization)
            .field("features", &self.features)
            .field("num_lba_formats", &self.num_lba_formats)
            .field("formatted_lba_size", &self.formatted_lba_size)
            .field("lba_format_support", &self.lba_formats())
            .finish()
    }
}

impl IdentifyNamespaceDataStructure {
    pub fn lba_formats(&self) -> &[LbaFormat] {
        &self.lba_format_support[0..=min(self.num_lba_formats.into(), 63)]
    }
}

const _SIZE_CHECKER: [u8; 0x1000] = [0; std::mem::size_of::<IdentifyNamespaceDataStructure>()];

#[bitfield(bits = 32)]
#[derive(Default, Clone, Debug, Copy)]
pub struct LbaFormat {
    #[skip(setters)]
    pub metadata_size: u16,
    #[skip(setters)]
    pub data_size_log2: u8,
    #[skip(setters)]
    pub relative_performance: RelativePerformance,
    #[skip]
    res: B6,
}

impl LbaFormat {
    pub fn data_size(&self) -> usize {
        1 << self.data_size_log2()
    }
}

#[derive(BitfieldSpecifier, Clone, Debug)]
#[bits = 2]
pub enum RelativePerformance {
    Best = 0,
    Better = 1,
    Good = 2,
    Degraded = 3,
}

#[bitfield(bits = 8)]
#[derive(Debug, Default, Clone)]
pub struct FormattedLbaSize {
    #[skip(setters)]
    idx_lo: B4,
    #[skip(setters)]
    pub extended_block: B1,
    #[skip(setters)]
    idx_hi: B2,
    #[skip]
    resv: B1,
}

impl FormattedLbaSize {
    pub fn index(&self) -> usize {
        usize::from(self.idx_lo()) | usize::from(self.idx_hi()) << 4
    }
}

#[bitfield(bits = 8)]
#[derive(Debug, Default, Clone)]
pub struct NamespaceFeatures {
    #[skip(setters)]
    pub supports_thin_provisioning: B1,
    #[skip(setters)]
    pub supports_atomic_fields: B1,
    #[skip(setters)]
    pub supports_dealloc_lb_err: B1,
    #[skip(setters)]
    pub uid_reuse: B1,
    #[skip(setters)]
    pub opt_perf: B1,
    #[skip]
    resv: B3,
}