ipmi_rs/app/
get_device_id.rs

1use crate::{
2    connection::{IpmiCommand, Message, NetFn, ParseResponseError},
3    log_vec, Loggable,
4};
5
6pub struct GetDeviceId;
7
8impl From<GetDeviceId> for Message {
9    fn from(_: GetDeviceId) -> Self {
10        Message::new_request(NetFn::App, 0x01, Vec::new())
11    }
12}
13
14impl IpmiCommand for GetDeviceId {
15    type Output = DeviceId;
16
17    type Error = ();
18
19    fn parse_response(
20        completion_code: crate::connection::CompletionCode,
21        data: &[u8],
22    ) -> Result<Self::Output, ParseResponseError<Self::Error>> {
23        Self::check_cc_success(completion_code)?;
24        DeviceId::from_data(data).ok_or(ParseResponseError::NotEnoughData)
25    }
26}
27
28#[derive(Clone, Debug, PartialEq)]
29pub struct DeviceId {
30    pub device_id: u8,
31    pub device_revision: u8,
32    pub provides_device_sdrs: bool,
33    pub device_available: bool,
34    pub major_fw_revision: u8,
35    pub minor_fw_revision: u8,
36    pub major_version: u8,
37    pub minor_version: u8,
38    pub chassis_support: bool,
39    pub bridge_support: bool,
40    pub ipmb_event_generator_support: bool,
41    pub ipmb_event_receiver_support: bool,
42    pub fru_inventory_support: bool,
43    pub sel_device_support: bool,
44    pub sdr_repository_support: bool,
45    pub sensor_device_support: bool,
46    pub manufacturer_id: u32,
47    pub product_id: u16,
48    pub aux_revision: Option<[u8; 4]>,
49}
50
51impl DeviceId {
52    pub fn from_data(data: &[u8]) -> Option<Self> {
53        if data.len() < 11 {
54            return None;
55        }
56
57        let aux_revision = if data.len() < 15 {
58            None
59        } else {
60            Some([data[11], data[12], data[13], data[14]])
61        };
62
63        let fw_min = {
64            let min_nib_low = data[3] & 0xF;
65            let min_nib_high = (data[3] >> 4) & 0xF;
66
67            min_nib_low + min_nib_high * 10
68        };
69
70        let me = Self {
71            device_id: data[0],
72            device_revision: data[1] & 0xF,
73            provides_device_sdrs: (data[1] & 0x80) == 0x80,
74            device_available: (data[2] & 0x80) != 0x80,
75            major_fw_revision: (data[2] & 0x7F),
76            minor_fw_revision: fw_min,
77            major_version: data[4] & 0xF,
78            minor_version: (data[4] >> 4) & 0xF,
79            chassis_support: (data[5] & 0x80) == 0x80,
80            bridge_support: (data[5] & 0x40) == 0x40,
81            ipmb_event_generator_support: (data[5] & 0x20) == 0x20,
82            ipmb_event_receiver_support: (data[5] & 0x10) == 0x10,
83            fru_inventory_support: (data[5] & 0x08) == 0x08,
84            sel_device_support: (data[5] & 0x04) == 0x04,
85            sdr_repository_support: (data[5] & 0x02) == 0x02,
86            sensor_device_support: (data[5] & 0x01) == 0x01,
87            manufacturer_id: u32::from_le_bytes([data[6], data[7], data[8], 0]),
88            product_id: u16::from_le_bytes([data[9], data[10]]),
89            aux_revision,
90        };
91
92        Some(me)
93    }
94}
95
96impl Loggable for DeviceId {
97    fn as_log(&self) -> Vec<crate::fmt::LogItem> {
98        let (dev_id, dev_rev) = (self.device_id, self.device_revision);
99        let (fw_maj, fw_min) = (self.major_fw_revision, self.minor_fw_revision);
100        let (v_maj, v_min) = (self.major_version, self.minor_version);
101        let manf_id = self.manufacturer_id;
102
103        let (ipmb_event_gen, ipmb_event_recv) = (
104            self.ipmb_event_generator_support,
105            self.ipmb_event_receiver_support,
106        );
107
108        let fru_inv = self.fru_inventory_support;
109        let sdr_rep = self.sdr_repository_support;
110        let sensor_dev = self.sensor_device_support;
111        let sdrs = self.provides_device_sdrs;
112
113        let mut log = log_vec![
114            (0, "Device ID information"),
115            (1, "Device ID", format!("0x{dev_id:02X}")),
116            (1, "Device revision", format!("0x{dev_rev:02X}")),
117            (1, "Manufacturer ID", format!("0x{manf_id:02X}")),
118            (1, "Product ID", format!("0x{:02X}", self.product_id)),
119            (1, "IPMI Version", format!("{v_maj}.{v_min}")),
120            (1, "FW revision", format!("{fw_maj}.{fw_min}")),
121            // Aux revision
122            (1, "Device available", self.device_available),
123            (1, "Provides device SDRs", sdrs),
124            (1, "Chassis support", self.chassis_support),
125            (1, "Bridge support", self.bridge_support),
126            (1, "IPMB Event gen sup", ipmb_event_gen),
127            (1, "IPMB Event recv sup", ipmb_event_recv),
128            (1, "FRU Inventory sup", fru_inv),
129            (1, "SEL Device support", self.sel_device_support),
130            (1, "SDR Repository sup", sdr_rep),
131            (1, "Sensor Device sup", sensor_dev)
132        ];
133
134        if let Some(aux_rev) = &self.aux_revision {
135            let element = (1, "Auxiliary revision", format!("{aux_rev:02X?}")).into();
136            log.insert(7, element);
137        }
138
139        log
140    }
141}