ipmi_rs/storage/sdr/
get_sdr.rs

1use std::num::NonZeroU16;
2
3use nonmax::NonMaxU8;
4
5use crate::connection::{IpmiCommand, Message, NetFn, ParseResponseError};
6
7use super::{Record, RecordId, RecordParseError};
8
9/// Get a device SDR.
10///
11/// This command must be used in accordance with the IPMI spec, i.e.
12/// all SDRs must be obtained sequentially. It is recommended that you use
13/// the [`Ipmi::sdrs`] function for this.
14///
15/// [`Ipmi::sdrs`]: crate::Ipmi::sdrs
16#[derive(Debug, Clone, Copy)]
17pub struct GetDeviceSdr {
18    reservation_id: Option<NonZeroU16>,
19    record_id: RecordId,
20    offset: u8,
21    bytes_to_read: Option<NonMaxU8>,
22}
23
24impl GetDeviceSdr {
25    pub fn new(reservation_id: Option<NonZeroU16>, record_id: RecordId) -> Self {
26        Self {
27            reservation_id,
28            record_id,
29            // Always read all bytes
30            offset: 0,
31            bytes_to_read: None,
32        }
33    }
34}
35
36impl From<GetDeviceSdr> for Message {
37    fn from(value: GetDeviceSdr) -> Self {
38        let mut data = vec![0u8; 6];
39
40        data[0..2].copy_from_slice(
41            &value
42                .reservation_id
43                .map(NonZeroU16::get)
44                .unwrap_or(0)
45                .to_le_bytes(),
46        );
47
48        data[2..4].copy_from_slice(&value.record_id.value().to_le_bytes());
49        data[4] = value.offset;
50        data[5] = value.bytes_to_read.map(|v| v.get()).unwrap_or(0xFF);
51
52        Message::new_request(NetFn::Storage, 0x23, data)
53    }
54}
55
56impl IpmiCommand for GetDeviceSdr {
57    type Output = RecordInfo;
58
59    type Error = (RecordParseError, RecordId);
60
61    fn parse_response(
62        completion_code: crate::connection::CompletionCode,
63        data: &[u8],
64    ) -> Result<Self::Output, ParseResponseError<Self::Error>> {
65        Self::check_cc_success(completion_code)?;
66
67        if data.len() < 9 {
68            return Err(ParseResponseError::NotEnoughData);
69        }
70
71        let next_id = RecordId::new_raw(u16::from_le_bytes([data[0], data[1]]));
72
73        let res = RecordInfo::parse(data).map_err(|e| (e, next_id))?;
74
75        Ok(res)
76    }
77}
78
79#[derive(Debug, Clone)]
80pub struct RecordInfo {
81    pub next_entry: RecordId,
82    pub record: Record,
83}
84
85impl RecordInfo {
86    pub fn parse(data: &[u8]) -> Result<Self, RecordParseError> {
87        let next_entry = RecordId::new_raw(u16::from_le_bytes([data[0], data[1]]));
88        let data = &data[2..];
89        Record::parse(data).map(|record| Self { next_entry, record })
90    }
91}