Skip to content

Commit

Permalink
Add command to read the VPD lock state
Browse files Browse the repository at this point in the history
The lock information is returned as an array of trailing data.
  • Loading branch information
labbott committed Feb 28, 2024
1 parent fe874ca commit ec9c966
Show file tree
Hide file tree
Showing 9 changed files with 176 additions and 1 deletion.
16 changes: 16 additions & 0 deletions faux-mgs/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,9 @@ enum Command {
#[clap(short, long, default_value_t = CfpaSlot::Active)]
slot: CfpaSlot,
},

/// Reads the lock status of any VPD in the system
VpdLockStatus,
}

#[derive(Subcommand, Debug, Clone)]
Expand Down Expand Up @@ -1284,6 +1287,19 @@ async fn run_command(
}?;
handle_cxpa("cfpa", data, out, json)
}
Command::VpdLockStatus => {
let data = sp.vpd_lock_status_all().await?;

if json {
Ok(Output::Json(json!({ "vpd_lock_status": data })))
} else {
let mut out = vec![];
for b in data {
out.push(format!("{b:x?}"));
}
Ok(Output::Lines(out))
}
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion gateway-messages/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ pub const ROT_PAGE_SIZE: usize = 512;
/// for more detail and discussion.
pub mod version {
pub const MIN: u32 = 2;
pub const CURRENT: u32 = 10;
pub const CURRENT: u32 = 11;
}

#[derive(
Expand Down
4 changes: 4 additions & 0 deletions gateway-messages/src/mgs_to_sp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,10 @@ pub enum MgsRequest {

/// Issues a sensor read request
ReadRot(RotRequest),

/// Dump information about the lock state of the VPD (Vital Product Data)
/// The values are serialized in the trailer of the packet
VpdLockState,
}

#[derive(
Expand Down
19 changes: 19 additions & 0 deletions gateway-messages/src/sp_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,9 @@ pub trait SpHandler {
request: RotRequest,
buf: &mut [u8],
) -> Result<RotResponse, SpError>;

fn vpd_lock_status_all(&mut self, buf: &mut [u8])
-> Result<usize, SpError>;
}

/// Handle a single incoming message.
Expand Down Expand Up @@ -949,6 +952,15 @@ fn handle_mgs_request<H: SpHandler>(
MgsRequest::CurrentTime => {
handler.current_time().map(SpResponse::CurrentTime)
}
MgsRequest::VpdLockState => {
let r = handler.vpd_lock_status_all(trailing_tx_buf);

if let Ok(n) = r {
outgoing_trailing_data =
Some(OutgoingTrailingData::ShiftFromTail(n));
}
r.map(|_| SpResponse::VpdLockState)
}
};

let response = match result {
Expand Down Expand Up @@ -1346,6 +1358,13 @@ mod tests {
fn current_time(&mut self) -> Result<u64, SpError> {
unimplemented!()
}

fn vpd_lock_status_all(
&mut self,
_buf: &mut [u8],
) -> Result<usize, SpError> {
unimplemented!()
}
}

#[cfg(feature = "std")]
Expand Down
56 changes: 56 additions & 0 deletions gateway-messages/src/sp_to_mgs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ pub enum SpResponse {
ReadSensor(SensorResponse),
CurrentTime(u64),
ReadRot(RotResponse),
/// The packet contains trailing lock information
VpdLockState,
}

/// Identifier for one of of an SP's KSZ8463 management-network-facing ports.
Expand Down Expand Up @@ -554,6 +556,7 @@ pub enum SpError {
Sprockets(SprocketsError),
Update(UpdateError),
Sensor(SensorError),
Vpd(VpdError),
}

impl fmt::Display for SpError {
Expand Down Expand Up @@ -664,6 +667,7 @@ impl fmt::Display for SpError {
Self::Sprockets(e) => write!(f, "sprockets: {}", e),
Self::Update(e) => write!(f, "update: {}", e),
Self::Sensor(e) => write!(f, "sensor: {}", e),
Self::Vpd(e) => write!(f, "vpd: {}", e),
}
}
}
Expand Down Expand Up @@ -964,3 +968,55 @@ impl fmt::Display for SensorError {

#[cfg(feature = "std")]
impl std::error::Error for SensorError {}

/// VPD errors encountered while reading
///
/// This value is wrapped by [`SpError`]
#[derive(
Debug, Clone, Copy, PartialEq, SerializedSize, Serialize, Deserialize,
)]
pub enum VpdError {
InvalidDevice,
NotPresent,
DeviceError,
Unavailable,
DeviceTimeout,
DeviceOff,
BadAddress,
BadBuffer,
BadRead,
BadWrite,
BadLock,
NotImplemented,
IsLocked,
PartiallyLocked,
AlreadyLocked,
TaskRestarted,
}

impl fmt::Display for VpdError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidDevice => write!(f, "device index is invalid"),
Self::NotPresent => write!(f, "device is not present"),
Self::DeviceError => write!(f, "error with VPD device"),
Self::Unavailable => write!(f, "vpd device is unavailable"),
Self::DeviceTimeout => write!(f, "vpd device timed out"),
Self::DeviceOff => write!(f, "vpd device is off"),
Self::BadAddress => write!(f, "bad address"),
Self::BadBuffer => write!(f, "bad buffer"),
Self::BadRead => write!(f, "bad read"),
Self::BadWrite => write!(f, "bad write"),
Self::BadLock => write!(f, "lock failed"),
Self::NotImplemented => {
write!(f, "Feature is not implemented/compiled out")
}
Self::IsLocked => write!(f, "VPD is locked, cannot write"),
Self::PartiallyLocked => write!(f, "VPD is partially locked"),
Self::AlreadyLocked => {
write!(f, "VPD is already locked, cannot lock again")
}
Self::TaskRestarted => write!(f, "task restarted"),
}
}
}
1 change: 1 addition & 0 deletions gateway-messages/tests/versioning/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ mod v07;
mod v08;
mod v09;
mod v10;
mod v11;

pub fn assert_serialized(
out: &mut [u8],
Expand Down
65 changes: 65 additions & 0 deletions gateway-messages/tests/versioning/v11.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

//! The tests in this module check that the serialized form of messages from MGS
//! protocol version 11 have not changed.
//!
//! If a test in this module fails, _do not change the test_! This means you
//! have changed, deleted, or reordered an existing message type or enum
//! variant, and you should revert that change. This will remain true until we
//! bump the `version::MIN` to a value higher than 11, at which point these
//! tests can be removed as we will stop supporting v11.

use super::assert_serialized;
use gateway_messages::MgsRequest;
use gateway_messages::SerializedSize;
use gateway_messages::SpError;
use gateway_messages::SpResponse;
use gateway_messages::VpdError;

#[test]
fn sp_response() {
let mut out = [0; SpResponse::MAX_SIZE];
let response = SpResponse::VpdLockState;
let expected = [41];
assert_serialized(&mut out, &expected, &response);
}

#[test]
fn host_request() {
let mut out = [0; MgsRequest::MAX_SIZE];
let request = MgsRequest::VpdLockState;
let expected = [41];
assert_serialized(&mut out, &expected, &request);
}

#[test]
fn vpd_protocol_errors() {
let mut out = [0; MgsRequest::MAX_SIZE];

for (error, serialized) in [
(VpdError::InvalidDevice, &[0]),
(VpdError::NotPresent, &[1]),
(VpdError::DeviceError, &[2]),
(VpdError::Unavailable, &[3]),
(VpdError::DeviceTimeout, &[4]),
(VpdError::DeviceOff, &[5]),
(VpdError::BadAddress, &[6]),
(VpdError::BadBuffer, &[7]),
(VpdError::BadRead, &[8]),
(VpdError::BadWrite, &[9]),
(VpdError::BadLock, &[10]),
(VpdError::NotImplemented, &[11]),
(VpdError::IsLocked, &[12]),
(VpdError::PartiallyLocked, &[13]),
(VpdError::AlreadyLocked, &[14]),
(VpdError::TaskRestarted, &[15]),
] {
// Test VpdError variants encoded in an SpResponse
let response = SpResponse::Error(SpError::Vpd(error));
let mut expected = vec![17, 34];
expected.extend_from_slice(serialized);
assert_serialized(&mut out, &expected, &response);
}
}
6 changes: 6 additions & 0 deletions gateway-sp-comms/src/single_sp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -841,6 +841,12 @@ impl SingleSp {
.await
.and_then(expect_read_rot)
}

pub async fn vpd_lock_status_all(&self) -> Result<Vec<u8>> {
let result = rpc(&self.cmds_tx, MgsRequest::VpdLockState, None).await;

result.result.and_then(expect_vpd_lock_state)
}
}

// Helper trait to call a "paginated" (i.e., split across multiple UDP packets)
Expand Down
8 changes: 8 additions & 0 deletions gateway-sp-comms/src/sp_response_expect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,14 @@ pub(crate) fn expect_caboose_value(
expect_caboose_value(r).map(|((), data)| data)
}

pub(crate) fn expect_vpd_lock_state(
r: (SocketAddrV6, SpResponse, Vec<u8>),
) -> Result<Vec<u8>> {
// Wrapper around the autogenerated function for a nicer return type
expect_data_fn!(VpdLockState);
expect_vpd_lock_state(r).map(|((), data)| data)
}

/// Expects a `RotResponse::Ok` followed by 512 bytes of trailing data
///
/// Returns just the trailing data on success, and an error in other cases
Expand Down

0 comments on commit ec9c966

Please sign in to comment.