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 (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}