From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id 3C5811FF3A6 for ; Mon, 13 May 2024 12:49:24 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 3F38213A0D; Mon, 13 May 2024 12:49:32 +0200 (CEST) From: Dominik Csapak To: pbs-devel@lists.proxmox.com Date: Mon, 13 May 2024 12:49:23 +0200 Message-Id: <20240513104926.3113394-2-d.csapak@proxmox.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240513104926.3113394-1-d.csapak@proxmox.com> References: <20240513104926.3113394-1-d.csapak@proxmox.com> MIME-Version: 1.0 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.016 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: [pbs-devel] [PATCH proxmox-backup 1/4] tape: add functions to parse drive device activity X-BeenThere: pbs-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Backup Server development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Proxmox Backup Server development discussion Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pbs-devel-bounces@lists.proxmox.com Sender: "pbs-devel" 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 --- pbs-api-types/src/tape/drive.rs | 65 +++++++++++++++ pbs-tape/src/sg_tape.rs | 3 + pbs-tape/src/sg_tape/device_status.rs | 99 +++++++++++++++++++++++ pbs-tape/src/sg_tape/volume_statistics.rs | 8 +- 4 files changed, 171 insertions(+), 4 deletions(-) create mode 100644 pbs-tape/src/sg_tape/device_status.rs diff --git a/pbs-api-types/src/tape/drive.rs b/pbs-api-types/src/tape/drive.rs index 626c5d9c3..de569980a 100644 --- a/pbs-api-types/src/tape/drive.rs +++ b/pbs-api-types/src/tape/drive.rs @@ -276,3 +276,68 @@ pub struct Lp17VolumeStatistics { /// Volume serial number 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 for DeviceActivity { + type Error = Error; + + fn try_from(value: u8) -> Result { + 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), + }) + } +} diff --git a/pbs-tape/src/sg_tape.rs b/pbs-tape/src/sg_tape.rs index 146d05507..85be6b071 100644 --- a/pbs-tape/src/sg_tape.rs +++ b/pbs-tape/src/sg_tape.rs @@ -15,6 +15,9 @@ mod volume_statistics; use proxmox_uuid::Uuid; pub use volume_statistics::*; +mod device_status; +pub use device_status::*; + mod tape_alert_flags; pub use tape_alert_flags::*; diff --git a/pbs-tape/src/sg_tape/device_status.rs b/pbs-tape/src/sg_tape/device_status.rs new file mode 100644 index 000000000..353ba0a7b --- /dev/null +++ b/pbs-tape/src/sg_tape/device_status.rs @@ -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(file: &mut F) -> Result { + 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(file: &mut F) -> Result, 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 { + 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) +} diff --git a/pbs-tape/src/sg_tape/volume_statistics.rs b/pbs-tape/src/sg_tape/volume_statistics.rs index f27a682c1..d3815db09 100644 --- a/pbs-tape/src/sg_tape/volume_statistics.rs +++ b/pbs-tape/src/sg_tape/volume_statistics.rs @@ -46,10 +46,10 @@ fn sg_read_volume_statistics(file: &mut F) -> Result, Error> #[repr(C, packed)] #[derive(Endian)] -struct LpParameterHeader { - parameter_code: u16, - control: u8, - parameter_len: u8, +pub(crate) struct LpParameterHeader { + pub parameter_code: u16, + pub control: u8, + pub parameter_len: u8, } fn decode_volume_statistics(data: &[u8]) -> Result { -- 2.39.2 _______________________________________________ pbs-devel mailing list pbs-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel