tape: add functions to parse drive device activity
we use the VHF part from the DT Device Activity page for that. This is intended to query the drive for it's current state and activity. Currently only the activity is parsed and used. Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
This commit is contained in:
parent
4b21a00744
commit
3f1a084b90
@ -276,3 +276,68 @@ pub struct Lp17VolumeStatistics {
|
|||||||
/// Volume serial number
|
/// Volume serial number
|
||||||
pub serial: String,
|
pub serial: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The DT Device Activity from DT Device Status LP page
|
||||||
|
#[api]
|
||||||
|
#[derive(Copy, Clone, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "kebab-case")]
|
||||||
|
pub enum DeviceActivity {
|
||||||
|
/// No activity
|
||||||
|
NoActivity,
|
||||||
|
/// Cleaning
|
||||||
|
Cleaning,
|
||||||
|
/// Loading
|
||||||
|
Loading,
|
||||||
|
/// Unloading
|
||||||
|
Unloading,
|
||||||
|
/// Other unspecified activity
|
||||||
|
Other,
|
||||||
|
/// Reading
|
||||||
|
Reading,
|
||||||
|
/// Writing
|
||||||
|
Writing,
|
||||||
|
/// Locating
|
||||||
|
Locating,
|
||||||
|
/// Rewinding
|
||||||
|
Rewinding,
|
||||||
|
/// Erasing
|
||||||
|
Erasing,
|
||||||
|
/// Formatting
|
||||||
|
Formatting,
|
||||||
|
/// Calibrating
|
||||||
|
Calibrating,
|
||||||
|
/// Other (DT)
|
||||||
|
OtherDT,
|
||||||
|
/// Updating microcode
|
||||||
|
MicrocodeUpdate,
|
||||||
|
/// Reading encrypted data
|
||||||
|
ReadingEncrypted,
|
||||||
|
/// Writing encrypted data
|
||||||
|
WritingEncrypted,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u8> for DeviceActivity {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||||
|
Ok(match value {
|
||||||
|
0x00 => DeviceActivity::NoActivity,
|
||||||
|
0x01 => DeviceActivity::Cleaning,
|
||||||
|
0x02 => DeviceActivity::Loading,
|
||||||
|
0x03 => DeviceActivity::Unloading,
|
||||||
|
0x04 => DeviceActivity::Other,
|
||||||
|
0x05 => DeviceActivity::Reading,
|
||||||
|
0x06 => DeviceActivity::Writing,
|
||||||
|
0x07 => DeviceActivity::Locating,
|
||||||
|
0x08 => DeviceActivity::Rewinding,
|
||||||
|
0x09 => DeviceActivity::Erasing,
|
||||||
|
0x0A => DeviceActivity::Formatting,
|
||||||
|
0x0B => DeviceActivity::Calibrating,
|
||||||
|
0x0C => DeviceActivity::OtherDT,
|
||||||
|
0x0D => DeviceActivity::MicrocodeUpdate,
|
||||||
|
0x0E => DeviceActivity::ReadingEncrypted,
|
||||||
|
0x0F => DeviceActivity::WritingEncrypted,
|
||||||
|
other => bail!("invalid DT device activity value: {:x}", other),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -15,6 +15,9 @@ mod volume_statistics;
|
|||||||
use proxmox_uuid::Uuid;
|
use proxmox_uuid::Uuid;
|
||||||
pub use volume_statistics::*;
|
pub use volume_statistics::*;
|
||||||
|
|
||||||
|
mod device_status;
|
||||||
|
pub use device_status::*;
|
||||||
|
|
||||||
mod tape_alert_flags;
|
mod tape_alert_flags;
|
||||||
pub use tape_alert_flags::*;
|
pub use tape_alert_flags::*;
|
||||||
|
|
||||||
|
99
pbs-tape/src/sg_tape/device_status.rs
Normal file
99
pbs-tape/src/sg_tape/device_status.rs
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
use std::os::fd::AsRawFd;
|
||||||
|
|
||||||
|
use anyhow::{bail, format_err, Error};
|
||||||
|
|
||||||
|
use pbs_api_types::DeviceActivity;
|
||||||
|
use proxmox_io::ReadExt;
|
||||||
|
|
||||||
|
use super::LpParameterHeader;
|
||||||
|
use crate::sgutils2::SgRaw;
|
||||||
|
|
||||||
|
/// SCSI command to query volume statistics
|
||||||
|
///
|
||||||
|
/// CDB: LOG SENSE / LP11h DT Device Activity
|
||||||
|
///
|
||||||
|
/// Only returns the Device Activity result from the VHF data
|
||||||
|
pub fn read_device_activity<F: AsRawFd>(file: &mut F) -> Result<DeviceActivity, Error> {
|
||||||
|
let data = sg_read_dt_device_status(file)?;
|
||||||
|
|
||||||
|
decode_dt_device_status(&data)
|
||||||
|
.map_err(|err| format_err!("decode dt device status failed - {}", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::vec_init_then_push)]
|
||||||
|
fn sg_read_dt_device_status<F: AsRawFd>(file: &mut F) -> Result<Vec<u8>, Error> {
|
||||||
|
let alloc_len: u16 = 8192;
|
||||||
|
let mut sg_raw = SgRaw::new(file, alloc_len as usize)?;
|
||||||
|
|
||||||
|
let mut cmd = Vec::new();
|
||||||
|
cmd.push(0x4D); // LOG SENSE
|
||||||
|
cmd.push(0);
|
||||||
|
cmd.push((1 << 6) | 0x11); // DT Device Status log page
|
||||||
|
cmd.push(0); // Subpage 0
|
||||||
|
cmd.push(0);
|
||||||
|
cmd.push(0);
|
||||||
|
cmd.push(0);
|
||||||
|
cmd.extend(alloc_len.to_be_bytes()); // alloc len
|
||||||
|
cmd.push(0u8); // control byte
|
||||||
|
|
||||||
|
sg_raw.set_timeout(1); // use short timeout
|
||||||
|
sg_raw
|
||||||
|
.do_command(&cmd)
|
||||||
|
.map_err(|err| format_err!("read tape dt device status failed - {}", err))
|
||||||
|
.map(|v| v.to_vec())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode_dt_device_status(data: &[u8]) -> Result<DeviceActivity, Error> {
|
||||||
|
if !((data[0] & 0x7f) == 0x11 && data[1] == 0) {
|
||||||
|
bail!("invalid response");
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut reader = &data[2..];
|
||||||
|
|
||||||
|
let page_len: u16 = unsafe { reader.read_be_value()? };
|
||||||
|
|
||||||
|
let page_len = page_len as usize;
|
||||||
|
|
||||||
|
if (page_len + 4) > data.len() {
|
||||||
|
bail!("invalid page length");
|
||||||
|
} else {
|
||||||
|
// Note: Quantum hh7 returns the allocation_length instead of real data_len
|
||||||
|
reader = &data[4..page_len + 4];
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut page_valid = false;
|
||||||
|
|
||||||
|
let mut activity = DeviceActivity::Other;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if reader.is_empty() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let head: LpParameterHeader = unsafe { reader.read_be_value()? };
|
||||||
|
|
||||||
|
match head.parameter_code {
|
||||||
|
0x0000 => {
|
||||||
|
let vhf_descriptor = reader.read_exact_allocated(head.parameter_len as usize)?;
|
||||||
|
|
||||||
|
if vhf_descriptor.len() != 4 {
|
||||||
|
bail!("invalid VHF data descriptor");
|
||||||
|
}
|
||||||
|
|
||||||
|
activity = vhf_descriptor[2].try_into()?;
|
||||||
|
|
||||||
|
if vhf_descriptor[0] & 0x01 == 1 {
|
||||||
|
page_valid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
reader.read_exact_allocated(head.parameter_len as usize)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !page_valid {
|
||||||
|
bail!("missing page-valid parameter");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(activity)
|
||||||
|
}
|
@ -46,10 +46,10 @@ fn sg_read_volume_statistics<F: AsRawFd>(file: &mut F) -> Result<Vec<u8>, Error>
|
|||||||
|
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
#[derive(Endian)]
|
#[derive(Endian)]
|
||||||
struct LpParameterHeader {
|
pub(crate) struct LpParameterHeader {
|
||||||
parameter_code: u16,
|
pub parameter_code: u16,
|
||||||
control: u8,
|
pub control: u8,
|
||||||
parameter_len: u8,
|
pub parameter_len: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode_volume_statistics(data: &[u8]) -> Result<Lp17VolumeStatistics, Error> {
|
fn decode_volume_statistics(data: &[u8]) -> Result<Lp17VolumeStatistics, Error> {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user