all lists on lists.proxmox.com
 help / color / mirror / Atom feed
From: Dietmar Maurer <dietmar@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [PATCH 09/11] tape: correctly set/display drive option
Date: Wed,  7 Apr 2021 12:23:06 +0200	[thread overview]
Message-ID: <20210407102308.9750-10-dietmar@proxmox.com> (raw)
In-Reply-To: <20210407102308.9750-1-dietmar@proxmox.com>

---
 src/api2/types/tape/drive.rs  |  12 +--
 src/bin/proxmox-tape.rs       |   5 +-
 src/tape/drive/lto/mod.rs     |  48 ++++++-----
 src/tape/drive/lto/sg_tape.rs | 153 ++++++++++++++++++++++++++++++++--
 4 files changed, 182 insertions(+), 36 deletions(-)

diff --git a/src/api2/types/tape/drive.rs b/src/api2/types/tape/drive.rs
index 058e544f..2a0857fd 100644
--- a/src/api2/types/tape/drive.rs
+++ b/src/api2/types/tape/drive.rs
@@ -176,13 +176,15 @@ impl TryFrom<u8> for TapeDensity {
 pub struct LtoDriveAndMediaStatus {
     /// Block size (0 is variable size)
     pub blocksize: u32,
+    /// Compression enabled
+    pub compression: bool,
+    /// Drive buffer mode
+    pub buffer_mode: u8,
     /// Tape density
+    pub density: TapeDensity,
+    /// Media is write protected
     #[serde(skip_serializing_if="Option::is_none")]
-    pub density: Option<TapeDensity>,
-    /// Status flags
-    pub status: String,
-    /// Lto Driver Options
-    pub options: String,
+    pub write_protect: Option<bool>,
     /// Tape Alert Flags
     #[serde(skip_serializing_if="Option::is_none")]
     pub alert_flags: Option<String>,
diff --git a/src/bin/proxmox-tape.rs b/src/bin/proxmox-tape.rs
index f1de6236..1d23b71c 100644
--- a/src/bin/proxmox-tape.rs
+++ b/src/bin/proxmox-tape.rs
@@ -741,8 +741,9 @@ async fn status(mut param: Value) -> Result<(), Error> {
     let options = default_table_format_options()
         .column(ColumnConfig::new("blocksize"))
         .column(ColumnConfig::new("density"))
-        .column(ColumnConfig::new("status"))
-        .column(ColumnConfig::new("options"))
+        .column(ColumnConfig::new("compression"))
+        .column(ColumnConfig::new("buffer-mode"))
+        .column(ColumnConfig::new("write-protect"))
         .column(ColumnConfig::new("alert-flags"))
         .column(ColumnConfig::new("file-number"))
         .column(ColumnConfig::new("block-number"))
diff --git a/src/tape/drive/lto/mod.rs b/src/tape/drive/lto/mod.rs
index 7fcef8a0..c9f3bf93 100644
--- a/src/tape/drive/lto/mod.rs
+++ b/src/tape/drive/lto/mod.rs
@@ -38,6 +38,7 @@ use crate::{
         MamAttribute,
         LtoDriveAndMediaStatus,
         LtoTapeDrive,
+        TapeDensity,
     },
     tape::{
         TapeRead,
@@ -82,8 +83,7 @@ impl LtoTapeDrive {
 
             handle.sg_tape.wait_until_ready()?;
 
-            // Only root can set driver options, so we cannot
-            // handle.set_default_options()?;
+            handle.set_default_options()?;
 
             Ok(handle)
         }).map_err(|err: Error| format_err!("open drive '{}' ({}) failed - {}", self.name, self.path, err))
@@ -104,8 +104,14 @@ impl LtoTapeHandle {
     }
 
     /// Set all options we need/want
-    pub fn set_default_options(&self) -> Result<(), Error> {
-        // fixme
+    pub fn set_default_options(&mut self) -> Result<(), Error> {
+
+        let compression = Some(true);
+        let block_length = Some(0); // variable length mode
+        let buffer_mode = Some(true); // Always use drive buffer
+
+        self.sg_tape.set_drive_options(compression, block_length, buffer_mode)?;
+
         Ok(())
     }
 
@@ -117,28 +123,21 @@ impl LtoTapeHandle {
     /// Get Tape and Media status
     pub fn get_drive_and_media_status(&mut self) -> Result<LtoDriveAndMediaStatus, Error>  {
 
-        let (file_number, block_number) = match self.sg_tape.position() {
-            Ok(position) => (
-                Some(position.logical_file_id),
-                Some(position.logical_object_number),
-            ),
-            Err(_) => (None, None),
-        };
-
-        let options = String::from("FIXME");
+        let drive_status = self.sg_tape.read_drive_status()?;
 
         let alert_flags = self.tape_alert_flags()
             .map(|flags| format!("{:?}", flags))
             .ok();
 
         let mut status = LtoDriveAndMediaStatus {
-            blocksize: 0, // fixme: remove
-            density: None, // fixme
-            status: String::from("FIXME"),
-            options,
+            blocksize: drive_status.block_length,
+            compression: drive_status.compression,
+            buffer_mode: drive_status.buffer_mode,
+            density: TapeDensity::try_from(drive_status.density_code)?,
             alert_flags,
-            file_number,
-            block_number,
+            write_protect: None,
+            file_number: None,
+            block_number: None,
             manufactured: None,
             bytes_read: None,
             bytes_written: None,
@@ -147,7 +146,16 @@ impl LtoTapeHandle {
             volume_mounts: None,
         };
 
-        if self.sg_tape.test_unit_ready()? {
+        if self.sg_tape.test_unit_ready().is_ok() {
+
+            if drive_status.write_protect {
+                status.write_protect = Some(drive_status.write_protect);
+            }
+
+            let position = self.sg_tape.position()?;
+
+            status.file_number = Some(position.logical_file_id);
+            status.block_number = Some(position.logical_object_number);
 
             if let Ok(mam) = self.cartridge_memory() {
 
diff --git a/src/tape/drive/lto/sg_tape.rs b/src/tape/drive/lto/sg_tape.rs
index 9af0eae3..f3d71edd 100644
--- a/src/tape/drive/lto/sg_tape.rs
+++ b/src/tape/drive/lto/sg_tape.rs
@@ -10,7 +10,7 @@ use nix::fcntl::{fcntl, FcntlArg, OFlag};
 
 use proxmox::{
     sys::error::SysResult,
-    tools::io::ReadExt,
+    tools::io::{ReadExt, WriteExt},
 };
 
 use crate::{
@@ -39,7 +39,11 @@ use crate::{
         SenseInfo,
         ScsiError,
         InquiryInfo,
+        ModeParameterHeader,
+        ModeBlockDescriptor,
+        alloc_page_aligned_buffer,
         scsi_inquiry,
+        scsi_mode_sense,
     },
 };
 
@@ -54,6 +58,42 @@ pub struct ReadPositionLongPage {
     obsolete: [u8;8],
 }
 
+#[repr(C, packed)]
+#[derive(Endian, Debug, Copy, Clone)]
+struct DataCompressionModePage {
+    page_code: u8,   // 0x0f
+    page_length: u8,  // 0x0e
+    flags2: u8,
+    flags3: u8,
+    compression_algorithm: u32,
+    decompression_algorithm: u32,
+    reserved: [u8;4],
+}
+
+impl DataCompressionModePage {
+
+    pub fn set_compression(&mut self, enable: bool) {
+        if enable {
+            self.flags2 |= 128;
+        } else {
+            self.flags2 = self.flags2 & 127;
+        }
+    }
+
+    pub fn compression_enabled(&self) -> bool {
+        (self.flags2 & 0b1000_0000) != 0
+    }
+}
+
+#[derive(Debug)]
+pub struct LtoTapeStatus {
+    pub block_length: u32,
+    pub density_code: u8,
+    pub buffer_mode: u8,
+    pub write_protect: bool,
+    pub compression: bool,
+}
+
 pub struct SgTape {
     file: File,
 }
@@ -378,19 +418,19 @@ impl SgTape {
         Ok(())
     }
 
-    pub fn test_unit_ready(&mut self) -> Result<bool, Error> {
+    pub fn test_unit_ready(&mut self) -> Result<(), Error> {
 
         let mut sg_raw = SgRaw::new(&mut self.file, 16)?;
         sg_raw.set_timeout(30); // use short timeout
         let mut cmd = Vec::new();
         cmd.extend(&[0x00, 0, 0, 0, 0, 0]); // TEST UNIT READY
 
-        // fixme: check sense
-        sg_raw.do_command(&cmd)
-            .map_err(|err| format_err!("unit not ready - {}", err))?;
-
-        Ok(true)
-
+        match sg_raw.do_command(&cmd) {
+            Ok(_) => Ok(()),
+            Err(err) => {
+                bail!("test_unit_ready failed - {}", err);
+            }
+        }
     }
 
     pub fn wait_until_ready(&mut self) -> Result<(), Error> {
@@ -400,7 +440,7 @@ impl SgTape {
 
         loop {
             match self.test_unit_ready() {
-                Ok(true) => return Ok(()),
+                Ok(()) => return Ok(()),
                 _ => {
                     std::thread::sleep(std::time::Duration::new(1, 0));
                     if start.elapsed()? > max_wait {
@@ -522,6 +562,101 @@ impl SgTape {
             None => Ok(None),
         }
     }
+
+    /// Set important drive options
+    pub fn set_drive_options(
+        &mut self,
+        compression: Option<bool>,
+        block_length: Option<u32>,
+        buffer_mode: Option<bool>,
+    ) -> Result<(), Error> {
+
+        // Note: Read/Modify/Write
+
+        let (mut head, mut block_descriptor, mut page) = self.read_compression_page()?;
+
+        let mut sg_raw = SgRaw::new(&mut self.file, 0)?;
+        sg_raw.set_timeout(Self::SCSI_TAPE_DEFAULT_TIMEOUT);
+
+        head.mode_data_len = 0; // need to b e zero
+
+        if let Some(compression) = compression {
+            page.set_compression(compression);
+        }
+
+        if let Some(block_length) = block_length {
+            block_descriptor.set_block_length(block_length)?;
+        }
+
+        if let Some(buffer_mode) = buffer_mode {
+            let mut mode = head.flags3 & 0b1_000_1111;
+            if buffer_mode {
+                mode |= 0b0_001_0000;
+            }
+            head.flags3 = mode;
+        }
+
+        let mut data = Vec::new();
+        unsafe {
+            data.write_be_value(head)?;
+            data.write_be_value(block_descriptor)?;
+            data.write_be_value(page)?;
+        }
+
+        let mut cmd = Vec::new();
+        cmd.push(0x55); // MODE SELECT(10)
+        cmd.push(0b0001_0000); // PF=1
+        cmd.extend(&[0,0,0,0,0]); //reserved
+
+        let param_list_len: u16 = data.len() as u16;
+        cmd.extend(&param_list_len.to_be_bytes());
+        cmd.push(0); // control
+
+        let mut buffer = alloc_page_aligned_buffer(4096)?;
+
+        buffer[..data.len()].copy_from_slice(&data[..]);
+
+        sg_raw.do_out_command(&cmd, &buffer[..data.len()])
+            .map_err(|err| format_err!("set drive options failed - {}", err))?;
+
+        Ok(())
+    }
+
+    fn read_compression_page(
+        &mut self,
+    ) -> Result<(ModeParameterHeader, ModeBlockDescriptor, DataCompressionModePage), Error> {
+
+        let (head, block_descriptor, page): (_,_, DataCompressionModePage)
+            = scsi_mode_sense(&mut self.file, false, 0x0f, 0)?;
+
+        if !(page.page_code == 0x0f && page.page_length == 0x0e) {
+            bail!("read_compression_page: got strange page code/length");
+        }
+
+        let block_descriptor = match block_descriptor {
+            Some(block_descriptor) => block_descriptor,
+            None => bail!("read_compression_page failed: missing block descriptor"),
+        };
+
+        Ok((head, block_descriptor, page))
+    }
+
+    /// Read drive options/status
+    ///
+    /// We read the drive compression page, including the
+    /// block_descriptor. This is all information we need for now.
+    pub fn read_drive_status(&mut self) -> Result<LtoTapeStatus, Error> {
+
+        let (head, block_descriptor, page) = self.read_compression_page()?;
+
+        Ok(LtoTapeStatus {
+            block_length: block_descriptor.block_length(),
+            write_protect: (head.flags3 & 0b1000_0000) != 0,
+            buffer_mode: (head.flags3 & 0b0111_0000) >> 4,
+            compression: page.compression_enabled(),
+            density_code: block_descriptor.density_code,
+        })
+    }
 }
 
 pub struct SgTapeReader<'a> {
-- 
2.20.1




  parent reply	other threads:[~2021-04-07 10:24 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-04-07 10:22 [pbs-devel] [PATCH 00/11] Userspace tape driver Dietmar Maurer
2021-04-07 10:22 ` [pbs-devel] [PATCH 01/11] tape: introduce trait BlockRead Dietmar Maurer
2021-04-07 10:22 ` [pbs-devel] [PATCH 02/11] tape: introduce trait BlockWrite Dietmar Maurer
2021-04-07 10:23 ` [pbs-devel] [PATCH 03/11] tape: implement LTO userspace driver Dietmar Maurer
2021-04-07 10:23 ` [pbs-devel] [PATCH 04/11] tape: implement format/erase Dietmar Maurer
2021-04-07 10:23 ` [pbs-devel] [PATCH 05/11] tape: fix LEOM handling Dietmar Maurer
2021-04-07 10:23 ` [pbs-devel] [PATCH 06/11] tape: make fsf/bsf driver specific Dietmar Maurer
2021-04-07 10:23 ` [pbs-devel] [PATCH 07/11] tape: make sure there is a filemark at the end of the tape Dietmar Maurer
2021-04-07 10:23 ` [pbs-devel] [PATCH 08/11] sgutils2: add scsi_mode_sense helper Dietmar Maurer
2021-04-07 10:23 ` Dietmar Maurer [this message]
2021-04-07 10:23 ` [pbs-devel] [PATCH 10/11] tape: pmt - re-implement fsr/bsr Dietmar Maurer
2021-04-07 10:23 ` [pbs-devel] [PATCH 11/11] tape: pmt - re-implement lock/unlock command 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=20210407102308.9750-10-dietmar@proxmox.com \
    --to=dietmar@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal