ipmi_rs_core/storage/sel/clear.rs
1//! Clear SEL Command
2//!
3//! Reference: IPMI 2.0 Specification, Section 31.9 "Clear SEL Command"
4
5use std::num::NonZeroU16;
6
7use crate::connection::{IpmiCommand, Message, NetFn, NotEnoughData};
8
9/// Action to perform when clearing the SEL.
10#[derive(Debug, Clone, Copy, PartialEq)]
11pub enum ClearSelAction {
12 /// Initiate erase (0xAA)
13 InitiateErase,
14 /// Get erasure status (0x00)
15 GetStatus,
16}
17
18/// Erasure progress status.
19#[derive(Debug, Clone, Copy, PartialEq)]
20pub enum ErasureProgress {
21 /// Erasure in progress
22 InProgress,
23 /// Erase completed
24 Completed,
25}
26
27/// Clear SEL command.
28///
29/// This command is used to erase all records in the SEL. The command requires
30/// a valid Reservation ID obtained from the Reserve SEL command unless the
31/// implementation does not support SEL reservation. In that case, the
32/// Reservation ID should be set to 0x0000.
33///
34/// The clearing operation is a two-step process:
35/// 1. Send ClearSel with `InitiateErase` action to start the erase
36/// 2. Optionally poll with `GetStatus` action to check completion
37///
38/// Reference: IPMI 2.0 Specification, Section 31.9, Table 31-9
39pub struct ClearSel {
40 reservation_id: Option<NonZeroU16>,
41 action: ClearSelAction,
42}
43
44impl ClearSel {
45 /// Create a new ClearSel command to initiate erasure.
46 pub fn initiate(reservation_id: Option<NonZeroU16>) -> Self {
47 Self {
48 reservation_id,
49 action: ClearSelAction::InitiateErase,
50 }
51 }
52
53 /// Create a new ClearSel command to get erasure status.
54 pub fn get_status(reservation_id: Option<NonZeroU16>) -> Self {
55 Self {
56 reservation_id,
57 action: ClearSelAction::GetStatus,
58 }
59 }
60}
61
62impl IpmiCommand for ClearSel {
63 type Output = ErasureProgress;
64 type Error = NotEnoughData;
65
66 /// Parse the response which contains the erasure progress.
67 ///
68 /// Response data format (IPMI 2.0 Spec, Table 31-9):
69 /// - Byte 0: Erasure progress
70 /// - \[3:0\]: 0h = erasure in progress, 1h = erase completed
71 fn parse_success_response(data: &[u8]) -> Result<Self::Output, Self::Error> {
72 if data.is_empty() {
73 return Err(NotEnoughData);
74 }
75
76 let progress = data[0] & 0x0F;
77 Ok(if progress == 0x01 {
78 ErasureProgress::Completed
79 } else {
80 ErasureProgress::InProgress
81 })
82 }
83}
84
85impl From<ClearSel> for Message {
86 /// Build the request message.
87 ///
88 /// Request format (IPMI 2.0 Spec, Table 31-9):
89 /// - Byte 0-1: Reservation ID, LS byte first
90 /// - Byte 2: 'C' (0x43)
91 /// - Byte 3: 'L' (0x4C)
92 /// - Byte 4: 'R' (0x52)
93 /// - Byte 5: Action
94 /// - 0xAA = initiate erase
95 /// - 0x00 = get erasure status
96 fn from(value: ClearSel) -> Self {
97 let action_byte = match value.action {
98 ClearSelAction::InitiateErase => 0xAA,
99 ClearSelAction::GetStatus => 0x00,
100 };
101
102 let mut data = vec![0u8; 6];
103 data[0..2].copy_from_slice(&value.reservation_id.map_or(0, |id| id.get()).to_le_bytes());
104 data[2] = 0x43; // 'C'
105 data[3] = 0x4C; // 'L'
106 data[4] = 0x52; // 'R'
107 data[5] = action_byte;
108
109 // NetFn: Storage (0x0A), Cmd: 0x47
110 Message::new_request(NetFn::Storage, 0x47, data)
111 }
112}