ipmi_rs/storage/sdr/
get_info.rs

1use crate::{
2    connection::{IpmiCommand, Message, NetFn, ParseResponseError},
3    fmt::LogItem,
4    log_vec,
5    storage::Timestamp,
6    Loggable,
7};
8
9pub struct GetRepositoryInfo;
10
11impl From<GetRepositoryInfo> for Message {
12    fn from(_: GetRepositoryInfo) -> Self {
13        Message::new_request(NetFn::Storage, 0x20, Vec::new())
14    }
15}
16
17impl IpmiCommand for GetRepositoryInfo {
18    type Output = RepositoryInfo;
19
20    type Error = ();
21
22    fn parse_response(
23        completion_code: crate::connection::CompletionCode,
24        data: &[u8],
25    ) -> Result<Self::Output, ParseResponseError<Self::Error>> {
26        Self::check_cc_success(completion_code)?;
27
28        RepositoryInfo::parse(data).ok_or(ParseResponseError::NotEnoughData)
29    }
30}
31
32#[derive(Clone, Copy, Debug, PartialEq)]
33pub enum FreeSpace {
34    Full,
35    AtLeast { bytes: u16 },
36    Unspecified,
37}
38
39impl From<u16> for FreeSpace {
40    fn from(value: u16) -> Self {
41        match value {
42            0x0000 => Self::Full,
43            0xFFFF => Self::Unspecified,
44            v => Self::AtLeast { bytes: v },
45        }
46    }
47}
48
49impl core::fmt::Display for FreeSpace {
50    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51        match self {
52            FreeSpace::Full => write!(f, "Full"),
53            FreeSpace::AtLeast { bytes } => write!(f, "At least {} bytes", bytes),
54            FreeSpace::Unspecified => write!(f, "Unspecified"),
55        }
56    }
57}
58
59#[derive(Clone, Copy, Debug, PartialEq)]
60pub enum Operation {
61    ModalityUnspecified,
62    NonModalUpdate,
63    ModalUpdate,
64    NonModalAndModalUpdate,
65    Delete,
66    PartialAdd,
67    Reserve,
68    GetAllocInfo,
69}
70
71#[derive(Clone, Debug)]
72pub struct RepositoryInfo {
73    pub version_major: u8,
74    pub version_minor: u8,
75    pub record_count: u16,
76    pub free_space: FreeSpace,
77    pub most_recent_addition: Timestamp,
78    pub most_recent_erase: Timestamp,
79    pub overflow: bool,
80    pub supported_ops: Vec<Operation>,
81}
82
83impl RepositoryInfo {
84    pub fn parse(v: &[u8]) -> Option<Self> {
85        let version_minor = (v[0] & 0xF0) >> 4;
86        let version_major = v[0] & 0x0F;
87        let record_count = u16::from_le_bytes([v[1], v[2]]);
88        let free_space = FreeSpace::from(u16::from_le_bytes([v[3], v[4]]));
89        let most_recent_addition = Timestamp::from(u32::from_le_bytes([v[5], v[6], v[7], v[8]]));
90        let most_recent_erase = Timestamp::from(u32::from_le_bytes([v[9], v[10], v[11], v[12]]));
91        let overflow = (v[13] & 0x80) == 0x80;
92
93        let modality = v[13] & 0x60 >> 5;
94        let modality = match modality {
95            0b00 => Operation::ModalityUnspecified,
96            0b01 => Operation::NonModalUpdate,
97            0b10 => Operation::ModalUpdate,
98            0b11 => Operation::NonModalAndModalUpdate,
99            _ => unreachable!(),
100        };
101
102        let mut ops = Vec::with_capacity(5);
103        ops.push(modality);
104
105        for (offset, command) in [
106            Operation::GetAllocInfo,
107            Operation::Reserve,
108            Operation::PartialAdd,
109            Operation::Delete,
110        ]
111        .into_iter()
112        .enumerate()
113        {
114            if v[13] & (1 << offset) == (1 << offset) {
115                ops.push(command);
116            }
117        }
118
119        Some(Self {
120            version_major,
121            version_minor,
122            record_count,
123            free_space,
124            most_recent_addition,
125            most_recent_erase,
126            overflow,
127            supported_ops: ops,
128        })
129    }
130}
131
132impl Loggable for RepositoryInfo {
133    fn as_log(&self) -> Vec<LogItem> {
134        let Self {
135            version_major,
136            version_minor,
137            record_count,
138            free_space,
139            most_recent_addition,
140            most_recent_erase,
141            overflow,
142            supported_ops,
143        } = self;
144
145        let (v_maj, v_min) = (version_major, version_minor);
146
147        log_vec![
148            (0, "SDR Repository Information"),
149            (1, "Version", format!("{v_maj}.{v_min}")),
150            (1, "Record count", record_count),
151            (1, "Free space", free_space),
152            (1, "Most recent add", most_recent_addition),
153            (1, "Most recent erase", most_recent_erase),
154            (1, "SDR Overflow", overflow),
155            (1, "Supported ops", format!("{supported_ops:?}"))
156        ]
157    }
158}