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}