ipmi_rs/storage/sdr/
get_dev_sdr_info.rs

1use std::marker::PhantomData;
2
3use crate::{
4    connection::{CompletionCode, IpmiCommand, LogicalUnit, Message, NetFn, ParseResponseError},
5    log_vec, Loggable,
6};
7
8#[derive(Debug, Clone, Copy, PartialEq)]
9pub struct SdrCount;
10
11#[derive(Debug, Clone, Copy, PartialEq)]
12pub struct SensorCount;
13
14trait FromOpValue {
15    fn from(value: u8) -> Self;
16}
17
18#[derive(Debug, Clone, Copy, PartialEq)]
19pub struct NumberOfSensors(pub u8);
20
21impl FromOpValue for NumberOfSensors {
22    fn from(value: u8) -> Self {
23        Self(value)
24    }
25}
26
27#[derive(Debug, Clone, Copy, PartialEq)]
28pub struct NumberOfSdrs(pub u8);
29
30impl FromOpValue for NumberOfSdrs {
31    fn from(value: u8) -> Self {
32        Self(value)
33    }
34}
35
36#[derive(Debug, Clone)]
37pub struct DeviceSdrInfo<T> {
38    pub operation_value: T,
39    pub dynamic_population: bool,
40    pub lun_0_has_sensors: bool,
41    pub lun_1_has_sensors: bool,
42    pub lun_2_has_sensors: bool,
43    pub lun_3_has_sensors: bool,
44    pub sensor_population_epoch: Option<u32>,
45}
46
47impl<T> DeviceSdrInfo<T> {
48    pub fn lun_has_sensors(&self, lun: LogicalUnit) -> bool {
49        match lun {
50            LogicalUnit::Zero => self.lun_0_has_sensors,
51            LogicalUnit::One => self.lun_1_has_sensors,
52            LogicalUnit::Two => self.lun_2_has_sensors,
53            LogicalUnit::Three => self.lun_3_has_sensors,
54        }
55    }
56
57    fn partial_log(&self, mut log: Vec<crate::fmt::LogItem>) -> Vec<crate::fmt::LogItem> {
58        let mut luns_with_sensors = Vec::new();
59        if self.lun_0_has_sensors {
60            luns_with_sensors.push(0);
61        }
62        if self.lun_1_has_sensors {
63            luns_with_sensors.push(1);
64        }
65        if self.lun_2_has_sensors {
66            luns_with_sensors.push(2);
67        }
68        if self.lun_3_has_sensors {
69            luns_with_sensors.push(3);
70        }
71
72        log.push((1, "LUNs with sensors", format!("{:?}", luns_with_sensors)).into());
73
74        if let Some(epoch) = self.sensor_population_epoch {
75            log.push((1, "Sensor pop. epoch", format!("0x{epoch:04X}")).into());
76        }
77
78        log
79    }
80
81    fn parse(data: &[u8]) -> Option<Self>
82    where
83        T: FromOpValue,
84    {
85        if data.len() < 2 {
86            return None;
87        }
88
89        let op_value = data[0];
90        let dynamic_population = (data[1] & 0x80) == 0x80;
91
92        let lun_3_has_sensors = (data[1] & 0x08) == 0x08;
93        let lun_2_has_sensors = (data[1] & 0x04) == 0x04;
94        let lun_1_has_sensors = (data[1] & 0x02) == 0x02;
95        let lun_0_has_sensors = (data[1] & 0x01) == 0x01;
96
97        let sensor_population_epoch = if dynamic_population && data.len() < 6 {
98            return None;
99        } else if dynamic_population {
100            Some(u32::from_le_bytes([data[2], data[3], data[4], data[5]]))
101        } else {
102            None
103        };
104
105        Some(Self {
106            operation_value: T::from(op_value),
107            dynamic_population,
108            lun_0_has_sensors,
109            lun_1_has_sensors,
110            lun_2_has_sensors,
111            lun_3_has_sensors,
112            sensor_population_epoch,
113        })
114    }
115}
116
117impl Loggable for DeviceSdrInfo<NumberOfSdrs> {
118    fn as_log(&self) -> Vec<crate::fmt::LogItem> {
119        let log = log_vec![
120            (0, "Device SDR information"),
121            (1, "Number of SDRs", self.operation_value.0)
122        ];
123        self.partial_log(log)
124    }
125}
126
127impl Loggable for DeviceSdrInfo<NumberOfSensors> {
128    fn as_log(&self) -> Vec<crate::fmt::LogItem> {
129        let log = log_vec![
130            (0, "Device SDR information"),
131            (1, "Number of sensors", self.operation_value.0)
132        ];
133        self.partial_log(log)
134    }
135}
136
137#[derive(Debug, Clone, Copy, PartialEq)]
138pub struct GetDeviceSdrInfo<T> {
139    _phantom: PhantomData<T>,
140}
141
142impl<T> GetDeviceSdrInfo<T> {
143    pub fn new(_: T) -> Self {
144        Self {
145            _phantom: PhantomData,
146        }
147    }
148}
149
150impl From<GetDeviceSdrInfo<SdrCount>> for Message {
151    fn from(_: GetDeviceSdrInfo<SdrCount>) -> Self {
152        Message::new_request(NetFn::SensorEvent, 0x20, vec![0x01])
153    }
154}
155
156impl From<GetDeviceSdrInfo<SensorCount>> for Message {
157    fn from(_: GetDeviceSdrInfo<SensorCount>) -> Self {
158        Message::new_request(NetFn::SensorEvent, 0x20, vec![0x01])
159    }
160}
161
162impl IpmiCommand for GetDeviceSdrInfo<SdrCount> {
163    type Output = DeviceSdrInfo<NumberOfSdrs>;
164
165    type Error = ();
166
167    fn parse_response(
168        completion_code: CompletionCode,
169        data: &[u8],
170    ) -> Result<Self::Output, ParseResponseError<Self::Error>> {
171        Self::check_cc_success(completion_code)?;
172
173        DeviceSdrInfo::parse(data).ok_or(ParseResponseError::NotEnoughData)
174    }
175}
176
177impl IpmiCommand for GetDeviceSdrInfo<SensorCount> {
178    type Output = DeviceSdrInfo<NumberOfSensors>;
179
180    type Error = ();
181
182    fn parse_response(
183        completion_code: CompletionCode,
184        data: &[u8],
185    ) -> Result<Self::Output, ParseResponseError<Self::Error>> {
186        Self::check_cc_success(completion_code)?;
187
188        DeviceSdrInfo::parse(data).ok_or(ParseResponseError::NotEnoughData)
189    }
190}