ipmi_rs/storage/sdr/
get_dev_sdr_info.rs1use 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}