tape: correctly set/display drive option
This commit is contained in:
parent
b717871d2a
commit
0892a512bc
@ -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>,
|
||||
|
@ -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"))
|
||||
|
@ -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() {
|
||||
|
||||
|
@ -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(¶m_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> {
|
||||
|
Loading…
Reference in New Issue
Block a user