use libnvme_sys::{nvme_error_log_page, nvme_firmware_slot, nvme_smart_log};
use crate::util::fixed_ascii_to_str;
use crate::{Error, Result};
pub struct SmartLog {
pub(crate) inner: Box<nvme_smart_log>,
}
impl SmartLog {
pub fn critical_warning(&self) -> u8 {
self.inner.critical_warning
}
pub fn temperature_kelvin(&self) -> u16 {
u16::from_le_bytes(self.inner.temperature)
}
pub fn temperature_celsius(&self) -> i16 {
(self.temperature_kelvin() as i32 - 273) as i16
}
pub fn available_spare(&self) -> u8 {
self.inner.avail_spare
}
pub fn available_spare_threshold(&self) -> u8 {
self.inner.spare_thresh
}
pub fn percentage_used(&self) -> u8 {
self.inner.percent_used
}
pub fn endurance_group_critical_warning(&self) -> u8 {
self.inner.endu_grp_crit_warn_sumry
}
pub fn data_units_read(&self) -> u128 {
u128::from_le_bytes(self.inner.data_units_read)
}
pub fn data_units_written(&self) -> u128 {
u128::from_le_bytes(self.inner.data_units_written)
}
pub fn host_read_commands(&self) -> u128 {
u128::from_le_bytes(self.inner.host_reads)
}
pub fn host_write_commands(&self) -> u128 {
u128::from_le_bytes(self.inner.host_writes)
}
pub fn controller_busy_time_minutes(&self) -> u128 {
u128::from_le_bytes(self.inner.ctrl_busy_time)
}
pub fn power_cycles(&self) -> u128 {
u128::from_le_bytes(self.inner.power_cycles)
}
pub fn power_on_hours(&self) -> u128 {
u128::from_le_bytes(self.inner.power_on_hours)
}
pub fn unsafe_shutdowns(&self) -> u128 {
u128::from_le_bytes(self.inner.unsafe_shutdowns)
}
pub fn media_errors(&self) -> u128 {
u128::from_le_bytes(self.inner.media_errors)
}
pub fn num_error_log_entries(&self) -> u128 {
u128::from_le_bytes(self.inner.num_err_log_entries)
}
pub fn warning_temp_time_minutes(&self) -> u32 {
self.inner.warning_temp_time
}
pub fn critical_temp_time_minutes(&self) -> u32 {
self.inner.critical_comp_time
}
pub fn temperature_sensor_kelvin(&self, index: u8) -> Option<u16> {
if !(1..=8).contains(&index) {
return None;
}
let value = self.inner.temp_sensor[usize::from(index - 1)];
if value == 0 {
None
} else {
Some(value)
}
}
}
impl std::fmt::Debug for SmartLog {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("SmartLog")
.field("critical_warning", &self.critical_warning())
.field("temperature_celsius", &self.temperature_celsius())
.field("percentage_used", &self.percentage_used())
.field("power_cycles", &self.power_cycles())
.field("power_on_hours", &self.power_on_hours())
.field("unsafe_shutdowns", &self.unsafe_shutdowns())
.finish()
}
}
pub struct FirmwareSlotLog {
pub(crate) inner: Box<nvme_firmware_slot>,
}
impl FirmwareSlotLog {
pub fn afi(&self) -> u8 {
self.inner.afi
}
pub fn active_slot(&self) -> u8 {
self.inner.afi & 0x07
}
pub fn next_slot_to_activate(&self) -> Option<u8> {
let next = (self.inner.afi >> 4) & 0x07;
if next == 0 {
None
} else {
Some(next)
}
}
pub fn slot_firmware(&self, slot: u8) -> Result<&str> {
if !(1..=7).contains(&slot) {
return Err(Error::NotAvailable);
}
fixed_ascii_to_str(&self.inner.frs[usize::from(slot - 1)])
}
}
impl std::fmt::Debug for FirmwareSlotLog {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("FirmwareSlotLog")
.field("active_slot", &self.active_slot())
.field("next_slot_to_activate", &self.next_slot_to_activate())
.field("slot_1", &self.slot_firmware(1).ok())
.field("slot_2", &self.slot_firmware(2).ok())
.field("slot_3", &self.slot_firmware(3).ok())
.finish()
}
}
#[derive(Clone, Copy)]
pub struct ErrorLogEntry {
pub(crate) inner: nvme_error_log_page,
}
impl ErrorLogEntry {
pub fn error_count(&self) -> u64 {
self.inner.error_count
}
pub fn submission_queue_id(&self) -> u16 {
self.inner.sqid
}
pub fn command_id(&self) -> u16 {
self.inner.cmdid
}
pub fn status_field(&self) -> u16 {
self.inner.status_field
}
pub fn parameter_error_location(&self) -> u16 {
self.inner.parm_error_location
}
pub fn lba(&self) -> u64 {
self.inner.lba
}
pub fn nsid(&self) -> u32 {
self.inner.nsid
}
pub fn vendor_specific(&self) -> u8 {
self.inner.vs
}
pub fn transport_type(&self) -> u8 {
self.inner.trtype
}
pub fn csi(&self) -> u8 {
self.inner.csi
}
pub fn opcode(&self) -> u8 {
self.inner.opcode
}
}
impl std::fmt::Debug for ErrorLogEntry {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ErrorLogEntry")
.field("error_count", &self.error_count())
.field(
"status_field",
&format_args!("0x{:04x}", self.status_field()),
)
.field("opcode", &format_args!("0x{:02x}", self.opcode()))
.field("nsid", &self.nsid())
.field("lba", &self.lba())
.finish()
}
}