ipmi_rs_core/storage/sel/
mod.rs1use core::fmt;
2
3use crate::connection::{Channel, LogicalUnit};
4
5use super::Timestamp;
6use crate::storage::sdr::{decode_event, EventData, SensorType};
7
8mod clear;
9pub use clear::{ClearSel, ClearSelAction, ErasureProgress};
10
11mod get_alloc_info;
12pub use get_alloc_info::{AllocInfo as SelAllocInfo, GetAllocInfo as SelGetAllocInfo};
13
14mod get_entry;
15pub use get_entry::{EntryInfo as SelEntryInfo, GetEntry as GetSelEntry};
16
17mod get_info;
18pub use get_info::{Command as SelCommand, GetInfo as GetSelInfo, Info as SelInfo};
19
20mod reserve;
21pub use reserve::ReserveSel;
22
23#[derive(Debug, Clone, Copy, PartialEq)]
24pub struct RecordId(u16);
25
26impl RecordId {
27 pub const FIRST: Self = Self(0x0000);
28 pub const LAST: Self = Self(0xFFFF);
29
30 pub fn new(id: u16) -> Option<Self> {
31 if RecordId(id) == Self::FIRST || RecordId(id) == Self::LAST {
32 None
33 } else {
34 Some(Self(id))
35 }
36 }
37
38 pub(crate) fn new_raw(id: u16) -> Self {
39 RecordId(id)
40 }
41
42 pub fn value(&self) -> u16 {
43 self.0
44 }
45
46 pub fn is_first(&self) -> bool {
47 self == &Self::FIRST
48 }
49
50 pub fn is_last(&self) -> bool {
51 self == &Self::LAST
52 }
53}
54
55#[derive(Debug, Clone, Copy, PartialEq)]
56enum SelRecordType {
57 System,
58 TimestampedOem(u8),
59 NonTimestampedOem(u8),
60 Unknown(u8),
61}
62
63impl From<u8> for SelRecordType {
64 fn from(value: u8) -> Self {
65 match value {
66 0x02 => Self::System,
67 0xC0..=0xDF => Self::TimestampedOem(value),
68 0xE0..=0xFF => Self::NonTimestampedOem(value),
69 v => Self::Unknown(v),
70 }
71 }
72}
73
74#[derive(Debug, Clone, Copy, PartialEq)]
75pub enum EventGenerator {
76 RqSAAndLun {
77 i2c_addr: u8,
78 channel_number: Channel,
79 lun: LogicalUnit,
80 },
81 SoftwareId {
82 software_id: u8,
83 channel_number: Channel,
84 },
85}
86
87impl TryFrom<(u8, u8)> for EventGenerator {
88 type Error = ParseEntryError;
89
90 fn try_from(value: (u8, u8)) -> Result<Self, Self::Error> {
91 let is_software_id = (value.0 & 0x1) == 0x1;
92 let i2c_or_sid = (value.0 >> 1) & 0x7F;
93 let channel_value = (value.1 >> 4) & 0xF;
94
95 let channel_number =
96 Channel::new(channel_value).ok_or(ParseEntryError::InvalidChannel(channel_value))?;
97
98 if is_software_id {
99 Ok(Self::SoftwareId {
100 software_id: i2c_or_sid,
101 channel_number,
102 })
103 } else {
104 let lun = LogicalUnit::from_low_bits(value.1);
105
106 Ok(Self::RqSAAndLun {
107 i2c_addr: i2c_or_sid,
108 channel_number,
109 lun,
110 })
111 }
112 }
113}
114
115#[derive(Debug, Clone, Copy, PartialEq)]
116pub enum EventMessageRevision {
117 V2_0,
118 V1_0,
119 Unknown(u8),
120}
121
122impl From<u8> for EventMessageRevision {
123 fn from(value: u8) -> Self {
124 match value {
125 0x04 => Self::V2_0,
126 0x03 => Self::V1_0,
127 v => Self::Unknown(v),
128 }
129 }
130}
131
132#[derive(Debug, Clone, Copy, PartialEq)]
133pub enum EventDirection {
134 Assert,
135 Deassert,
136}
137
138#[derive(Debug, Clone, PartialEq)]
139pub enum Entry {
140 System {
141 record_id: RecordId,
142 timestamp: Timestamp,
143 generator_id: EventGenerator,
144 event_message_format: EventMessageRevision,
145 sensor_type: u8,
146 sensor_number: u8,
147 event_direction: EventDirection,
148 event_type: u8,
149 event_data: EventData,
150 },
151 OemTimestamped {
152 record_id: RecordId,
153 ty: u8,
154 timestamp: Timestamp,
155 manufacturer_id: u32,
156 data: [u8; 6],
157 },
158 OemNotTimestamped {
159 record_id: RecordId,
160 ty: u8,
161 data: [u8; 13],
162 },
163}
164
165#[derive(Debug, Clone, Copy, PartialEq)]
166pub enum ParseEntryError {
167 NotEnoughData,
168 UnknownRecordType(u8),
169 InvalidChannel(u8),
170}
171
172impl Entry {
173 pub fn event_description(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
174 match self {
175 Entry::System {
176 event_type,
177 sensor_type,
178 event_data,
179 ..
180 } => decode_event(
181 f,
182 *event_type,
183 SensorType::from(*sensor_type),
184 event_data.offset,
185 ),
186 _ => Ok(()),
187 }
188 }
189
190 pub fn parse(data: &[u8]) -> Result<Self, ParseEntryError> {
191 if data.len() < 16 {
192 return Err(ParseEntryError::NotEnoughData);
193 }
194
195 let record_id = RecordId(u16::from_le_bytes([data[0], data[1]]));
196 let record_type = SelRecordType::from(data[2]);
197 let timestamp = u32::from_le_bytes([data[3], data[4], data[5], data[6]]);
198
199 match record_type {
200 SelRecordType::System => {
201 let generator_id = EventGenerator::try_from((data[7], data[8]))?;
202 let event_message_format = EventMessageRevision::from(data[9]);
203 let sensor_type = data[10];
204 let sensor_number = data[11];
205 let event_direction = if (data[12] & 0x80) == 0x80 {
206 EventDirection::Deassert
207 } else {
208 EventDirection::Assert
209 };
210 let event_type = data[12] & 0x7F;
211 let event_data = EventData::parse(&[data[13], data[14], data[15]]);
212 Ok(Self::System {
213 record_id,
214 timestamp: Timestamp::from(timestamp),
215 generator_id,
216 event_message_format,
217 sensor_type,
218 sensor_number,
219 event_direction,
220 event_type,
221 event_data,
222 })
223 }
224 SelRecordType::TimestampedOem(v) => Ok(Self::OemTimestamped {
225 record_id,
226 ty: v,
227 timestamp: Timestamp::from(timestamp),
228 manufacturer_id: u32::from_le_bytes([data[7], data[8], data[9], 0]),
229 data: [data[10], data[11], data[12], data[13], data[14], data[15]],
230 }),
231 SelRecordType::NonTimestampedOem(v) => Ok(Self::OemNotTimestamped {
232 record_id,
233 ty: v,
234 data: [
235 data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10],
236 data[11], data[12], data[13], data[14], data[15],
237 ],
238 }),
239 SelRecordType::Unknown(v) => Err(ParseEntryError::UnknownRecordType(v)),
240 }
241 }
242}