From b9e0fcbdcd2d92e1995025b8180d0a45aee7b9fa Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Thu, 22 Apr 2021 13:53:26 +0200 Subject: [PATCH] tape: implement report_desnity --- src/tape/drive/lto/sg_tape.rs | 24 ++++--- src/tape/drive/lto/sg_tape/report_density.rs | 69 ++++++++++++++++++++ 2 files changed, 84 insertions(+), 9 deletions(-) create mode 100644 src/tape/drive/lto/sg_tape/report_density.rs diff --git a/src/tape/drive/lto/sg_tape.rs b/src/tape/drive/lto/sg_tape.rs index 4e9265fb..003834db 100644 --- a/src/tape/drive/lto/sg_tape.rs +++ b/src/tape/drive/lto/sg_tape.rs @@ -20,6 +20,9 @@ pub use tape_alert_flags::*; mod mam; pub use mam::*; +mod report_density; +pub use report_density::*; + use proxmox::{ sys::error::SysResult, tools::io::{ReadExt, WriteExt}, @@ -103,6 +106,7 @@ pub struct LtoTapeStatus { pub struct SgTape { file: File, info: InquiryInfo, + density_code: u8, // drive type encryption_key_loaded: bool, } @@ -120,9 +124,13 @@ impl SgTape { if info.peripheral_type != 1 { bail!("not a tape device (peripheral_type = {})", info.peripheral_type); } + + let density_code = report_density(&mut file)?; + Ok(Self { file, info, + density_code, encryption_key_loaded: false, }) } @@ -194,18 +202,16 @@ impl SgTape { sg_raw.set_timeout(Self::SCSI_TAPE_DEFAULT_TIMEOUT); let mut cmd = Vec::new(); - // Try FORMAT first (requires LTO5 or newer) - cmd.extend(&[0x04, 0, 0, 0, 0, 0]); - - if let Err(err) = sg_raw.do_command(&cmd) { - eprintln!("format failed - using erase insead: {}", err); - // try rewind/erase instead - self.rewind()?; - self.erase_media(fast)? - } else { + if self.density_code >= 0x58 { // FORMAT requires LTO5 or newer) + cmd.extend(&[0x04, 0, 0, 0, 0, 0]); + sg_raw.do_command(&cmd)?; if !fast { self.erase_media(false)?; // overwrite everything } + } else { + // try rewind/erase instead + self.rewind()?; + self.erase_media(fast)? } Ok(()) diff --git a/src/tape/drive/lto/sg_tape/report_density.rs b/src/tape/drive/lto/sg_tape/report_density.rs new file mode 100644 index 00000000..9b0a233f --- /dev/null +++ b/src/tape/drive/lto/sg_tape/report_density.rs @@ -0,0 +1,69 @@ +use anyhow::{bail, format_err, Error}; +use std::io::Read; +use endian_trait::Endian; +use std::os::unix::io::AsRawFd; + +use proxmox::tools::io::ReadExt; + +use crate::tools::sgutils2::SgRaw; + +#[repr(C, packed)] +#[derive(Endian)] +struct DesnityDescriptorBlock { + primary_density_code: u8, + secondary_density_code: u8, + flags2: u8, + reserved: [u8; 2], + bits_per_mm: [u8; 3], + media_width: u16, + tracks: u16, + capacity: u32, + organizazion: [u8; 8], + density_name: [u8; 8], + description: [u8; 20], +} + +// Returns the maximum supported drive density code +pub fn report_density(file: &mut F) -> Result { + let alloc_len: u16 = 8192; + let mut sg_raw = SgRaw::new(file, alloc_len as usize)?; + + let mut cmd = Vec::new(); + cmd.extend(&[0x44, 0, 0, 0, 0, 0, 0]); // REPORT DENSITY SUPPORT (MEDIA=0) + cmd.extend(&alloc_len.to_be_bytes()); // alloc len + cmd.push(0u8); // control byte + + let data = sg_raw.do_command(&cmd) + .map_err(|err| format_err!("report density failed - {}", err))?; + + let mut max_density = 0u8; + + proxmox::try_block!({ + let mut reader = &data[..]; + + let page_len: u16 = unsafe { reader.read_be_value()? }; + let page_len = page_len as usize; + + if (page_len + 2) > data.len() { + bail!("invalid page length {} {}", page_len + 2, data.len()); + } else { + // Note: Quantum hh7 returns the allocation_length instead of real data_len + reader = &data[2..page_len+2]; + } + let mut reserved = [0u8; 2]; + reader.read_exact(&mut reserved)?; + + loop { + if reader.is_empty() { break; } + let block: DesnityDescriptorBlock = unsafe { reader.read_be_value()? }; + if block.primary_density_code > max_density { + max_density = block.primary_density_code; + } + } + + Ok(()) + + }).map_err(|err| format_err!("decode report density failed - {}", err))?; + + Ok(max_density) +}