public inbox for pbs-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Dominik Csapak <d.csapak@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [PATCH proxmox-backup 1/4] tape: add functions to parse drive device activity
Date: Mon, 13 May 2024 12:49:23 +0200	[thread overview]
Message-ID: <20240513104926.3113394-2-d.csapak@proxmox.com> (raw)
In-Reply-To: <20240513104926.3113394-1-d.csapak@proxmox.com>

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>
---
 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<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),
+        })
+    }
+}
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<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)
+}
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<F: AsRawFd>(file: &mut F) -> Result<Vec<u8>, 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<Lp17VolumeStatistics, Error> {
-- 
2.39.2



_______________________________________________
pbs-devel mailing list
pbs-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel


  reply	other threads:[~2024-05-13 10:49 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-05-13 10:49 [pbs-devel] [PATCH proxmox-backup 0/4] tape: improve UX by showing " Dominik Csapak
2024-05-13 10:49 ` Dominik Csapak [this message]
2024-05-13 10:49 ` [pbs-devel] [PATCH proxmox-backup 2/4] tape: add drive activity to drive status api Dominik Csapak
2024-05-13 10:49 ` [pbs-devel] [PATCH proxmox-backup 3/4] tape: drive status: make some depend on the activity Dominik Csapak
2024-05-13 10:49 ` [pbs-devel] [PATCH proxmox-backup 4/4] tape: include drive activity in status Dominik Csapak
2024-05-14  8:32 ` [pbs-devel] applied: [PATCH proxmox-backup 0/4] tape: improve UX by showing device activity Dietmar Maurer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240513104926.3113394-2-d.csapak@proxmox.com \
    --to=d.csapak@proxmox.com \
    --cc=pbs-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal