pbs tape: rust fmt

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
This commit is contained in:
Thomas Lamprecht
2022-04-06 17:00:29 +02:00
parent a527b54f84
commit b23adfd4ee
17 changed files with 863 additions and 811 deletions

View File

@ -1,20 +1,17 @@
use std::os::unix::prelude::AsRawFd;
use std::io::Write;
use std::os::unix::prelude::AsRawFd;
use anyhow::{bail, format_err, Error};
use endian_trait::Endian;
use proxmox_io::{ReadExt, WriteExt};
use crate::sgutils2::{SgRaw, alloc_page_aligned_buffer};
use crate::sgutils2::{alloc_page_aligned_buffer, SgRaw};
/// Test if drive supports hardware encryption
///
/// We search for AES_GCM algorithm with 256bits key.
pub fn has_encryption<F: AsRawFd>(
file: &mut F,
) -> bool {
pub fn has_encryption<F: AsRawFd>(file: &mut F) -> bool {
let data = match sg_spin_data_encryption_caps(file) {
Ok(data) => data,
Err(_) => return false,
@ -25,11 +22,7 @@ pub fn has_encryption<F: AsRawFd>(
/// Set or clear encryption key
///
/// We always use mixed mode,
pub fn set_encryption<F: AsRawFd>(
file: &mut F,
key: Option<[u8; 32]>,
) -> Result<(), Error> {
pub fn set_encryption<F: AsRawFd>(file: &mut F, key: Option<[u8; 32]>) -> Result<(), Error> {
let data = match sg_spin_data_encryption_caps(file) {
Ok(data) => data,
Err(_) if key.is_none() => {
@ -85,7 +78,6 @@ fn sg_spout_set_encryption<F: AsRawFd>(
algorythm_index: u8,
key: Option<[u8; 32]>,
) -> Result<(), Error> {
let mut sg_raw = SgRaw::new(file, 0)?;
let mut outbuf_len = std::mem::size_of::<SspSetDataEncryptionPage>();
@ -106,7 +98,11 @@ fn sg_spout_set_encryption<F: AsRawFd>(
algorythm_index,
key_format: 0,
reserved: [0u8; 8],
key_len: if let Some(ref key) = key { key.len() as u16 } else { 0 },
key_len: if let Some(ref key) = key {
key.len() as u16
} else {
0
},
};
let mut writer = &mut outbuf[..];
@ -119,58 +115,72 @@ fn sg_spout_set_encryption<F: AsRawFd>(
let mut cmd = Vec::new();
cmd.push(0xB5); // SECURITY PROTOCOL IN (SPOUT)
cmd.push(0x20); // Tape Data Encryption Page
cmd.push(0);cmd.push(0x10); // Set Data Encryption page
cmd.push(0);
cmd.push(0x10); // Set Data Encryption page
cmd.push(0);
cmd.push(0);
cmd.extend(&(outbuf_len as u32).to_be_bytes()); // data out len
cmd.push(0);
cmd.push(0);
sg_raw.do_out_command(&cmd, &outbuf)
sg_raw
.do_out_command(&cmd, &outbuf)
.map_err(|err| format_err!("set data encryption SPOUT(20h[0010h]) failed - {}", err))
}
// Warning: this blocks and fails if there is no media loaded
fn sg_spin_data_encryption_status<F: AsRawFd>(file: &mut F) -> Result<Vec<u8>, Error> {
let allocation_len: u32 = 8192+4;
let allocation_len: u32 = 8192 + 4;
let mut sg_raw = SgRaw::new(file, allocation_len as usize)?;
let mut cmd = Vec::new();
cmd.push(0xA2); // SECURITY PROTOCOL IN (SPIN)
cmd.push(0x20); // Tape Data Encryption Page
cmd.push(0);cmd.push(0x20); // Data Encryption Status page
cmd.push(0);
cmd.push(0x20); // Data Encryption Status page
cmd.push(0);
cmd.push(0);
cmd.extend(&allocation_len.to_be_bytes());
cmd.push(0);
cmd.push(0);
sg_raw.do_command(&cmd)
.map_err(|err| format_err!("read data encryption status SPIN(20h[0020h]) failed - {}", err))
sg_raw
.do_command(&cmd)
.map_err(|err| {
format_err!(
"read data encryption status SPIN(20h[0020h]) failed - {}",
err
)
})
.map(|v| v.to_vec())
}
// Warning: this blocks and fails if there is no media loaded
fn sg_spin_data_encryption_caps<F: AsRawFd>(file: &mut F) -> Result<Vec<u8>, Error> {
let allocation_len: u32 = 8192+4;
let allocation_len: u32 = 8192 + 4;
let mut sg_raw = SgRaw::new(file, allocation_len as usize)?;
let mut cmd = Vec::new();
cmd.push(0xA2); // SECURITY PROTOCOL IN (SPIN)
cmd.push(0x20); // Tape Data Encryption Page
cmd.push(0);cmd.push(0x10); // Data Encryption Capabilities page
cmd.push(0);
cmd.push(0x10); // Data Encryption Capabilities page
cmd.push(0);
cmd.push(0);
cmd.extend(&allocation_len.to_be_bytes());
cmd.push(0);
cmd.push(0);
sg_raw.do_command(&cmd)
.map_err(|err| format_err!("read data encryption caps SPIN(20h[0010h]) failed - {}", err))
sg_raw
.do_command(&cmd)
.map_err(|err| {
format_err!(
"read data encryption caps SPIN(20h[0010h]) failed - {}",
err
)
})
.map(|v| v.to_vec())
}
@ -215,7 +225,6 @@ struct SspDataEncryptionAlgorithmDescriptor {
// Returns the algorythm_index for AES-GCM
fn decode_spin_data_encryption_caps(data: &[u8]) -> Result<u8, Error> {
proxmox_lang::try_block!({
let mut reader = data;
let _page: SspDataEncryptionCapabilityPage = unsafe { reader.read_be_value()? };
@ -223,9 +232,10 @@ fn decode_spin_data_encryption_caps(data: &[u8]) -> Result<u8, Error> {
let mut aes_gcm_index = None;
loop {
if reader.is_empty() { break; };
let desc: SspDataEncryptionAlgorithmDescriptor =
unsafe { reader.read_be_value()? };
if reader.is_empty() {
break;
};
let desc: SspDataEncryptionAlgorithmDescriptor = unsafe { reader.read_be_value()? };
if desc.descriptor_len != 0x14 {
bail!("got wrong key descriptor len");
}
@ -245,8 +255,8 @@ fn decode_spin_data_encryption_caps(data: &[u8]) -> Result<u8, Error> {
Some(index) => Ok(index),
None => bail!("drive does not support AES-GCM encryption"),
}
}).map_err(|err: Error| format_err!("decode data encryption caps page failed - {}", err))
})
.map_err(|err: Error| format_err!("decode data encryption caps page failed - {}", err))
}
#[derive(Endian)]
@ -266,7 +276,6 @@ struct SspDataEncryptionStatusPage {
}
fn decode_spin_data_encryption_status(data: &[u8]) -> Result<DataEncryptionStatus, Error> {
proxmox_lang::try_block!({
let mut reader = data;
let page: SspDataEncryptionStatusPage = unsafe { reader.read_be_value()? };
@ -283,11 +292,9 @@ fn decode_spin_data_encryption_status(data: &[u8]) -> Result<DataEncryptionStatu
_ => bail!("unknown encryption mode"),
};
let status = DataEncryptionStatus {
mode,
};
let status = DataEncryptionStatus { mode };
Ok(status)
}).map_err(|err| format_err!("decode data encryption status page failed - {}", err))
})
.map_err(|err| format_err!("decode data encryption status page failed - {}", err))
}

View File

@ -17,7 +17,7 @@ use super::TapeAlertFlags;
// see IBM SCSI reference: https://www-01.ibm.com/support/docview.wss?uid=ssg1S7003556&aid=1
#[derive(Endian)]
#[repr(C,packed)]
#[repr(C, packed)]
struct MamAttributeHeader {
id: u16,
flags: u8,
@ -30,8 +30,13 @@ enum MamFormat {
DEC,
}
static MAM_ATTRIBUTES: &[ (u16, u16, MamFormat, &str) ] = &[
(0x00_00, 8, MamFormat::DEC, "Remaining Capacity In Partition"),
static MAM_ATTRIBUTES: &[(u16, u16, MamFormat, &str)] = &[
(
0x00_00,
8,
MamFormat::DEC,
"Remaining Capacity In Partition",
),
(0x00_01, 8, MamFormat::DEC, "Maximum Capacity In Partition"),
(0x00_02, 8, MamFormat::DEC, "Tapealert Flags"),
(0x00_03, 8, MamFormat::DEC, "Load Count"),
@ -40,19 +45,66 @@ static MAM_ATTRIBUTES: &[ (u16, u16, MamFormat, &str) ] = &[
(0x00_06, 1, MamFormat::BINARY, "Formatted Density Code"),
(0x00_07, 2, MamFormat::DEC, "Initialization Count"),
(0x00_09, 4, MamFormat::BINARY, "Volume Change Reference"),
(0x02_0A, 40, MamFormat::ASCII, "Device Vendor/Serial Number at Last Load"),
(0x02_0B, 40, MamFormat::ASCII, "Device Vendor/Serial Number at Load-1"),
(0x02_0C, 40, MamFormat::ASCII, "Device Vendor/Serial Number at Load-2"),
(0x02_0D, 40, MamFormat::ASCII, "Device Vendor/Serial Number at Load-3"),
(0x02_20, 8, MamFormat::DEC, "Total MBytes Written in Medium Life"),
(0x02_21, 8, MamFormat::DEC, "Total MBytes Read In Medium Life"),
(0x02_22, 8, MamFormat::DEC, "Total MBytes Written in Current Load"),
(0x02_23, 8, MamFormat::DEC, "Total MBytes Read in Current/Last Load"),
(0x02_24, 8, MamFormat::BINARY, "Logical Position of First Encrypted Block"),
(0x02_25, 8, MamFormat::BINARY, "Logical Position of First Unencrypted Block After the First Encrypted Block"),
(
0x02_0A,
40,
MamFormat::ASCII,
"Device Vendor/Serial Number at Last Load",
),
(
0x02_0B,
40,
MamFormat::ASCII,
"Device Vendor/Serial Number at Load-1",
),
(
0x02_0C,
40,
MamFormat::ASCII,
"Device Vendor/Serial Number at Load-2",
),
(
0x02_0D,
40,
MamFormat::ASCII,
"Device Vendor/Serial Number at Load-3",
),
(
0x02_20,
8,
MamFormat::DEC,
"Total MBytes Written in Medium Life",
),
(
0x02_21,
8,
MamFormat::DEC,
"Total MBytes Read In Medium Life",
),
(
0x02_22,
8,
MamFormat::DEC,
"Total MBytes Written in Current Load",
),
(
0x02_23,
8,
MamFormat::DEC,
"Total MBytes Read in Current/Last Load",
),
(
0x02_24,
8,
MamFormat::BINARY,
"Logical Position of First Encrypted Block",
),
(
0x02_25,
8,
MamFormat::BINARY,
"Logical Position of First Unencrypted Block After the First Encrypted Block",
),
(0x04_00, 8, MamFormat::ASCII, "Medium Manufacturer"),
(0x04_01, 32, MamFormat::ASCII, "Medium Serial Number"),
(0x04_02, 4, MamFormat::DEC, "Medium Length"),
@ -64,27 +116,54 @@ static MAM_ATTRIBUTES: &[ (u16, u16, MamFormat, &str) ] = &[
(0x04_08, 1, MamFormat::BINARY, "Medium Type"),
(0x04_09, 2, MamFormat::BINARY, "Medium Type Information"),
(0x04_0B, 10, MamFormat::BINARY, "Supported Density Codes"),
(0x08_00, 8, MamFormat::ASCII, "Application Vendor"),
(0x08_01, 32, MamFormat::ASCII, "Application Name"),
(0x08_02, 8, MamFormat::ASCII, "Application Version"),
(0x08_03, 160, MamFormat::ASCII, "User Medium Text Label"),
(0x08_04, 12, MamFormat::ASCII, "Date And Time Last Written"),
(0x08_05, 1, MamFormat::BINARY, "Text Localization Identifier"),
(
0x08_05,
1,
MamFormat::BINARY,
"Text Localization Identifier",
),
(0x08_06, 32, MamFormat::ASCII, "Barcode"),
(0x08_07, 80, MamFormat::ASCII, "Owning Host Textual Name"),
(0x08_08, 160, MamFormat::ASCII, "Media Pool"),
(0x08_0B, 16, MamFormat::ASCII, "Application Format Version"),
(0x08_0C, 50, MamFormat::ASCII, "Volume Coherency Information"),
(0x08_20, 36, MamFormat::ASCII, "Medium Globally Unique Identifier"),
(0x08_21, 36, MamFormat::ASCII, "Media Pool Globally Unique Identifier"),
(0x10_00, 28, MamFormat::BINARY, "Unique Cartridge Identify (UCI)"),
(0x10_01, 24, MamFormat::BINARY, "Alternate Unique Cartridge Identify (Alt-UCI)"),
(
0x08_0C,
50,
MamFormat::ASCII,
"Volume Coherency Information",
),
(
0x08_20,
36,
MamFormat::ASCII,
"Medium Globally Unique Identifier",
),
(
0x08_21,
36,
MamFormat::ASCII,
"Media Pool Globally Unique Identifier",
),
(
0x10_00,
28,
MamFormat::BINARY,
"Unique Cartridge Identify (UCI)",
),
(
0x10_01,
24,
MamFormat::BINARY,
"Alternate Unique Cartridge Identify (Alt-UCI)",
),
];
lazy_static::lazy_static!{
lazy_static::lazy_static! {
static ref MAM_ATTRIBUTE_NAMES: HashMap<u16, &'static (u16, u16, MamFormat, &'static str)> = {
let mut map = HashMap::new();
@ -98,8 +177,7 @@ lazy_static::lazy_static!{
}
fn read_tape_mam<F: AsRawFd>(file: &mut F) -> Result<Vec<u8>, Error> {
let alloc_len: u32 = 32*1024;
let alloc_len: u32 = 32 * 1024;
let mut sg_raw = SgRaw::new(file, alloc_len as usize)?;
let mut cmd = Vec::new();
@ -108,33 +186,35 @@ fn read_tape_mam<F: AsRawFd>(file: &mut F) -> Result<Vec<u8>, Error> {
cmd.extend(&alloc_len.to_be_bytes()); // alloc len
cmd.extend(&[0u8, 0u8]);
sg_raw.do_command(&cmd)
sg_raw
.do_command(&cmd)
.map_err(|err| format_err!("read cartidge memory failed - {}", err))
.map(|v| v.to_vec())
}
/// Read Medium auxiliary memory attributes (cartridge memory) using raw SCSI command.
pub fn read_mam_attributes<F: AsRawFd>(file: &mut F) -> Result<Vec<MamAttribute>, Error> {
let data = read_tape_mam(file)?;
decode_mam_attributes(&data)
}
fn decode_mam_attributes(data: &[u8]) -> Result<Vec<MamAttribute>, Error> {
let mut reader = data;
let data_len: u32 = unsafe { reader.read_be_value()? };
let expected_len = data_len as usize;
if reader.len() < expected_len {
bail!("read_mam_attributes: got unexpected data len ({} != {})", reader.len(), expected_len);
bail!(
"read_mam_attributes: got unexpected data len ({} != {})",
reader.len(),
expected_len
);
} else if reader.len() > expected_len {
// Note: Quantum hh7 returns the allocation_length instead of real data_len
reader = &data[4..expected_len+4];
reader = &data[4..expected_len + 4];
}
let mut list = Vec::new();
@ -143,7 +223,7 @@ fn decode_mam_attributes(data: &[u8]) -> Result<Vec<MamAttribute>, Error> {
if reader.is_empty() {
break;
}
let head: MamAttributeHeader = unsafe { reader.read_be_value()? };
let head: MamAttributeHeader = unsafe { reader.read_be_value()? };
//println!("GOT ID {:04X} {:08b} {}", head.id, head.flags, head.len);
let head_id = head.id;
@ -164,7 +244,8 @@ fn decode_mam_attributes(data: &[u8]) -> Result<Vec<MamAttribute>, Error> {
} else if info.1 == 4 {
format!("{}", u32::from_be_bytes(data[0..4].try_into()?))
} else if info.1 == 8 {
if head_id == 2 { // Tape Alert Flags
if head_id == 2 {
// Tape Alert Flags
let value = u64::from_be_bytes(data[0..8].try_into()?);
let flags = TapeAlertFlags::from_bits_truncate(value);
format!("{:?}", flags)
@ -174,7 +255,7 @@ fn decode_mam_attributes(data: &[u8]) -> Result<Vec<MamAttribute>, Error> {
} else {
unreachable!();
}
},
}
MamFormat::BINARY => hex::encode(&data),
};
list.push(MamAttribute {
@ -183,7 +264,10 @@ fn decode_mam_attributes(data: &[u8]) -> Result<Vec<MamAttribute>, Error> {
value,
});
} else {
eprintln!("read_mam_attributes: got starnge data len for id {:04X}", head_id);
eprintln!(
"read_mam_attributes: got starnge data len for id {:04X}",
head_id
);
}
} else {
// skip unknown IDs
@ -201,8 +285,11 @@ pub struct MediaUsageInfo {
/// Extract Media Usage Information from Cartridge Memory
pub fn mam_extract_media_usage(mam: &[MamAttribute]) -> Result<MediaUsageInfo, Error> {
let manufactured: i64 = match mam.iter().find(|v| v.id == 0x04_06).map(|v| v.value.clone()) {
let manufactured: i64 = match mam
.iter()
.find(|v| v.id == 0x04_06)
.map(|v| v.value.clone())
{
Some(date_str) => {
if date_str.len() != 8 {
bail!("unable to parse 'Medium Manufacture Date' - wrong length");
@ -222,15 +309,27 @@ pub fn mam_extract_media_usage(mam: &[MamAttribute]) -> Result<MediaUsageInfo, E
None => bail!("unable to read MAM 'Medium Manufacture Date'"),
};
let bytes_written: u64 = match mam.iter().find(|v| v.id == 0x02_20).map(|v| v.value.clone()) {
Some(read_str) => read_str.parse::<u64>()? * 1024*1024,
let bytes_written: u64 = match mam
.iter()
.find(|v| v.id == 0x02_20)
.map(|v| v.value.clone())
{
Some(read_str) => read_str.parse::<u64>()? * 1024 * 1024,
None => bail!("unable to read MAM 'Total MBytes Written In Medium Life'"),
};
let bytes_read: u64 = match mam.iter().find(|v| v.id == 0x02_21).map(|v| v.value.clone()) {
Some(read_str) => read_str.parse::<u64>()? * 1024*1024,
let bytes_read: u64 = match mam
.iter()
.find(|v| v.id == 0x02_21)
.map(|v| v.value.clone())
{
Some(read_str) => read_str.parse::<u64>()? * 1024 * 1024,
None => bail!("unable to read MAM 'Total MBytes Read In Medium Life'"),
};
Ok(MediaUsageInfo { manufactured, bytes_written, bytes_read })
Ok(MediaUsageInfo {
manufactured,
bytes_written,
bytes_read,
})
}

View File

@ -1,6 +1,6 @@
use anyhow::{bail, format_err, Error};
use std::io::Read;
use endian_trait::Endian;
use std::io::Read;
use std::os::unix::io::AsRawFd;
use proxmox_io::ReadExt;
@ -26,14 +26,15 @@ struct DesnityDescriptorBlock {
// Returns the maximum supported drive density code
pub fn report_density<F: AsRawFd>(file: &mut F) -> Result<u8, Error> {
let alloc_len: u16 = 8192;
let mut sg_raw = SgRaw::new(file, alloc_len as usize)?;
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)
let data = sg_raw
.do_command(&cmd)
.map_err(|err| format_err!("report density failed - {}", err))?;
let mut max_density = 0u8;
@ -48,13 +49,15 @@ pub fn report_density<F: AsRawFd>(file: &mut F) -> Result<u8, Error> {
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];
reader = &data[2..page_len + 2];
}
let mut reserved = [0u8; 2];
reader.read_exact(&mut reserved)?;
loop {
if reader.is_empty() { break; }
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;
@ -62,8 +65,8 @@ pub fn report_density<F: AsRawFd>(file: &mut F) -> Result<u8, Error> {
}
Ok(())
}).map_err(|err| format_err!("decode report density failed - {}", err))?;
})
.map_err(|err| format_err!("decode report density failed - {}", err))?;
Ok(max_density)
}

View File

@ -7,7 +7,7 @@ use proxmox_io::ReadExt;
use crate::sgutils2::SgRaw;
bitflags::bitflags!{
bitflags::bitflags! {
/// Tape Alert Flags
///
@ -73,16 +73,13 @@ bitflags::bitflags!{
}
/// Read Tape Alert Flags using raw SCSI command.
pub fn read_tape_alert_flags<F: AsRawFd>(file: &mut F) -> Result<TapeAlertFlags, Error> {
pub fn read_tape_alert_flags<F: AsRawFd>(file: &mut F) -> Result<TapeAlertFlags, Error> {
let data = sg_read_tape_alert_flags(file)?;
decode_tape_alert_flags(&data)
}
fn sg_read_tape_alert_flags<F: AsRawFd>(file: &mut F) -> Result<Vec<u8>, Error> {
let mut sg_raw = SgRaw::new(file, 512)?;
// Note: We cannjot use LP 2Eh TapeAlerts, because that clears flags on read.
@ -91,7 +88,7 @@ fn sg_read_tape_alert_flags<F: AsRawFd>(file: &mut F) -> Result<Vec<u8>, Error>
let mut cmd = Vec::new();
cmd.push(0x4D); // LOG SENSE
cmd.push(0);
cmd.push((1<<6) | 0x12); // Tape Alert Response log page
cmd.push((1 << 6) | 0x12); // Tape Alert Response log page
cmd.push(0);
cmd.push(0);
cmd.push(0);
@ -99,13 +96,13 @@ fn sg_read_tape_alert_flags<F: AsRawFd>(file: &mut F) -> Result<Vec<u8>, Error>
cmd.extend(&[2u8, 0u8]); // alloc len
cmd.push(0u8); // control byte
sg_raw.do_command(&cmd)
sg_raw
.do_command(&cmd)
.map_err(|err| format_err!("read tape alert flags failed - {}", err))
.map(|v| v.to_vec())
}
fn decode_tape_alert_flags(data: &[u8]) -> Result<TapeAlertFlags, Error> {
proxmox_lang::try_block!({
if !((data[0] & 0x7f) == 0x12 && data[1] == 0) {
bail!("invalid response");
@ -130,36 +127,36 @@ fn decode_tape_alert_flags(data: &[u8]) -> Result<TapeAlertFlags, Error> {
bail!("invalid parameter length");
}
let mut value: u64 = unsafe { reader.read_be_value()? };
let mut value: u64 = unsafe { reader.read_be_value()? };
// bits are in wrong order, reverse them
value = value.reverse_bits();
Ok(TapeAlertFlags::from_bits_truncate(value))
}).map_err(|err| format_err!("decode tape alert flags failed - {}", err))
})
.map_err(|err| format_err!("decode tape alert flags failed - {}", err))
}
const CRITICAL_FLAG_MASK: u64 =
TapeAlertFlags::MEDIA.bits() |
TapeAlertFlags::WRITE_FAILURE.bits() |
TapeAlertFlags::READ_FAILURE.bits() |
TapeAlertFlags::WRITE_PROTECT.bits() |
TapeAlertFlags::UNRECOVERABLE_SNAPPED_TAPE.bits() |
TapeAlertFlags::FORCED_EJECT.bits() |
TapeAlertFlags::EXPIRED_CLEANING_MEDIA.bits() |
TapeAlertFlags::INVALID_CLEANING_TAPE.bits() |
TapeAlertFlags::HARDWARE_A.bits() |
TapeAlertFlags::HARDWARE_B.bits() |
TapeAlertFlags::EJECT_MEDIA.bits() |
TapeAlertFlags::PREDICTIVE_FAILURE.bits() |
TapeAlertFlags::LOADER_STRAY_TAPE.bits() |
TapeAlertFlags::LOADER_MAGAZINE.bits() |
TapeAlertFlags::TAPE_SYSTEM_AREA_WRITE_FAILURE.bits() |
TapeAlertFlags::TAPE_SYSTEM_AREA_READ_FAILURE.bits() |
TapeAlertFlags::NO_START_OF_DATA.bits() |
TapeAlertFlags::LOADING_FAILURE.bits() |
TapeAlertFlags::UNRECOVERABLE_UNLOAD_FAILURE.bits() |
TapeAlertFlags::AUTOMATION_INTERFACE_FAILURE.bits();
const CRITICAL_FLAG_MASK: u64 = TapeAlertFlags::MEDIA.bits()
| TapeAlertFlags::WRITE_FAILURE.bits()
| TapeAlertFlags::READ_FAILURE.bits()
| TapeAlertFlags::WRITE_PROTECT.bits()
| TapeAlertFlags::UNRECOVERABLE_SNAPPED_TAPE.bits()
| TapeAlertFlags::FORCED_EJECT.bits()
| TapeAlertFlags::EXPIRED_CLEANING_MEDIA.bits()
| TapeAlertFlags::INVALID_CLEANING_TAPE.bits()
| TapeAlertFlags::HARDWARE_A.bits()
| TapeAlertFlags::HARDWARE_B.bits()
| TapeAlertFlags::EJECT_MEDIA.bits()
| TapeAlertFlags::PREDICTIVE_FAILURE.bits()
| TapeAlertFlags::LOADER_STRAY_TAPE.bits()
| TapeAlertFlags::LOADER_MAGAZINE.bits()
| TapeAlertFlags::TAPE_SYSTEM_AREA_WRITE_FAILURE.bits()
| TapeAlertFlags::TAPE_SYSTEM_AREA_READ_FAILURE.bits()
| TapeAlertFlags::NO_START_OF_DATA.bits()
| TapeAlertFlags::LOADING_FAILURE.bits()
| TapeAlertFlags::UNRECOVERABLE_UNLOAD_FAILURE.bits()
| TapeAlertFlags::AUTOMATION_INTERFACE_FAILURE.bits();
/// Check if tape-alert-flags contains critial errors.
pub fn tape_alert_flags_critical(flags: TapeAlertFlags) -> bool {
@ -167,8 +164,7 @@ pub fn tape_alert_flags_critical(flags: TapeAlertFlags) -> bool {
}
const MEDIA_LIFE_MASK: u64 =
TapeAlertFlags::MEDIA_LIFE.bits() |
TapeAlertFlags::NEARING_MEDIA_LIFE.bits();
TapeAlertFlags::MEDIA_LIFE.bits() | TapeAlertFlags::NEARING_MEDIA_LIFE.bits();
/// Check if tape-alert-flags indicates media-life end
pub fn tape_alert_flags_media_life(flags: TapeAlertFlags) -> bool {
@ -176,8 +172,7 @@ pub fn tape_alert_flags_media_life(flags: TapeAlertFlags) -> bool {
}
const MEDIA_CLEAN_MASK: u64 =
TapeAlertFlags::CLEAN_NOW.bits() |
TapeAlertFlags::CLEAN_PERIODIC.bits();
TapeAlertFlags::CLEAN_NOW.bits() | TapeAlertFlags::CLEAN_PERIODIC.bits();
/// Check if tape-alert-flags indicates media cleaning request
pub fn tape_alert_flags_cleaning_request(flags: TapeAlertFlags) -> bool {

View File

@ -16,22 +16,20 @@ use crate::sgutils2::SgRaw;
///
/// The Volume Statistics log page is included in Ultrium 5 and later
/// drives.
pub fn read_volume_statistics<F: AsRawFd>(file: &mut F) -> Result<Lp17VolumeStatistics, Error> {
pub fn read_volume_statistics<F: AsRawFd>(file: &mut F) -> Result<Lp17VolumeStatistics, Error> {
let data = sg_read_volume_statistics(file)?;
decode_volume_statistics(&data)
}
fn sg_read_volume_statistics<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) | 0x17); // Volume Statistics log page
cmd.push((1 << 6) | 0x17); // Volume Statistics log page
cmd.push(0); // Subpage 0
cmd.push(0);
cmd.push(0);
@ -39,7 +37,8 @@ fn sg_read_volume_statistics<F: AsRawFd>(file: &mut F) -> Result<Vec<u8>, Error>
cmd.extend(&alloc_len.to_be_bytes()); // alloc len
cmd.push(0u8); // control byte
sg_raw.do_command(&cmd)
sg_raw
.do_command(&cmd)
.map_err(|err| format_err!("read tape volume statistics failed - {}", err))
.map(|v| v.to_vec())
}
@ -53,8 +52,6 @@ struct LpParameterHeader {
}
fn decode_volume_statistics(data: &[u8]) -> Result<Lp17VolumeStatistics, Error> {
let read_be_counter = |reader: &mut &[u8], len: u8| {
let len = len as usize;
if len == 0 || len > 8 {
@ -86,7 +83,7 @@ fn decode_volume_statistics(data: &[u8]) -> Result<Lp17VolumeStatistics, Error>
bail!("invalid page length");
} else {
// Note: Quantum hh7 returns the allocation_length instead of real data_len
reader = &data[4..page_len+4];
reader = &data[4..page_len + 4];
}
let mut stat = Lp17VolumeStatistics::default();
@ -101,14 +98,13 @@ fn decode_volume_statistics(data: &[u8]) -> Result<Lp17VolumeStatistics, Error>
match head.parameter_code {
0x0000 => {
let value: u64 = read_be_counter(&mut reader, head.parameter_len)?;
if value == 0 {
bail!("page-valid flag not set");
if value == 0 {
bail!("page-valid flag not set");
}
page_valid = true;
}
0x0001 => {
stat.volume_mounts =
read_be_counter(&mut reader, head.parameter_len)?;
stat.volume_mounts = read_be_counter(&mut reader, head.parameter_len)?;
}
0x0002 => {
stat.volume_datasets_written =
@ -131,8 +127,7 @@ fn decode_volume_statistics(data: &[u8]) -> Result<Lp17VolumeStatistics, Error>
read_be_counter(&mut reader, head.parameter_len)?;
}
0x0007 => {
stat.volume_datasets_read =
read_be_counter(&mut reader, head.parameter_len)?;
stat.volume_datasets_read = read_be_counter(&mut reader, head.parameter_len)?;
}
0x0008 => {
stat.volume_recovered_read_errors =
@ -175,12 +170,10 @@ fn decode_volume_statistics(data: &[u8]) -> Result<Lp17VolumeStatistics, Error>
read_be_counter(&mut reader, head.parameter_len)?;
}
0x0014 => {
stat.medium_mount_time =
read_be_counter(&mut reader, head.parameter_len)?;
stat.medium_mount_time = read_be_counter(&mut reader, head.parameter_len)?;
}
0x0015 => {
stat.medium_ready_time =
read_be_counter(&mut reader, head.parameter_len)?;
stat.medium_ready_time = read_be_counter(&mut reader, head.parameter_len)?;
}
0x0016 => {
stat.total_native_capacity =
@ -207,12 +200,11 @@ fn decode_volume_statistics(data: &[u8]) -> Result<Lp17VolumeStatistics, Error>
}
}
0x0101 => {
stat.beginning_of_medium_passes =
stat.beginning_of_medium_passes =
read_be_counter(&mut reader, head.parameter_len)?;
}
0x0102 => {
stat.middle_of_tape_passes =
read_be_counter(&mut reader, head.parameter_len)?;
stat.middle_of_tape_passes = read_be_counter(&mut reader, head.parameter_len)?;
}
_ => {
reader.read_exact_allocated(head.parameter_len as usize)?;
@ -225,6 +217,6 @@ fn decode_volume_statistics(data: &[u8]) -> Result<Lp17VolumeStatistics, Error>
}
Ok(stat)
}).map_err(|err| format_err!("decode volume statistics failed - {}", err))
})
.map_err(|err| format_err!("decode volume statistics failed - {}", err))
}