tape: add read_medium_configuration_page() to detect WORM media

And use it inside format_media().
This commit is contained in:
Dietmar Maurer 2021-04-27 11:00:59 +02:00
parent 8369ade880
commit 5e169f387c

View File

@ -94,6 +94,23 @@ impl DataCompressionModePage {
}
}
#[repr(C, packed)]
#[derive(Endian)]
struct MediumConfigurationModePage {
page_code: u8, // 0x1d
page_length: u8, // 0x1e
flags2: u8,
reserved: [u8;29],
}
impl MediumConfigurationModePage {
pub fn is_worm(&self) -> bool {
(self.flags2 & 1) == 1
}
}
#[derive(Debug)]
pub struct LtoTapeStatus {
pub block_length: u32,
@ -199,11 +216,21 @@ impl SgTape {
/// Format media, single partition
pub fn format_media(&mut self, fast: bool) -> Result<(), Error> {
// get info about loaded media first
let (_head, block_descriptor, _) = self.read_compression_page()?;
// try to get info about loaded media first
let (has_format, is_worm) = match self.read_medium_configuration_page() {
Ok((_head, block_descriptor, page)) => {
// FORMAT requires LTO5 or newer
let has_format = block_descriptor.density_code >= 0x58;
let is_worm = page.is_worm();
(has_format, is_worm)
}
Err(_) => {
// LTO3 and older do not supprt medium configuration mode page
(false, false)
}
};
/* todo: howto detect WORM media?
if MediumType::is_worm(xx) {
if is_worm {
// We cannot FORMAT WORM media! Instead we check if its empty.
self.move_to_eom(false)?;
@ -212,17 +239,16 @@ impl SgTape {
bail!("format failed - detected WORM media with data.");
}
return Ok(());
}
*/
Ok(())
} else {
self.rewind()?;
let mut sg_raw = SgRaw::new(&mut self.file, 16)?;
sg_raw.set_timeout(Self::SCSI_TAPE_DEFAULT_TIMEOUT);
let mut cmd = Vec::new();
if block_descriptor.density_code >= 0x58 { // FORMAT requires LTO5 or newer
if has_format {
cmd.extend(&[0x04, 0, 0, 0, 0, 0]); // FORMAT
sg_raw.do_command(&cmd)?;
if !fast {
@ -235,6 +261,7 @@ impl SgTape {
Ok(())
}
}
/// Lock/Unlock drive door
pub fn set_medium_removal(&mut self, allow: bool) -> Result<(), ScsiError> {
@ -668,6 +695,30 @@ impl SgTape {
Ok(())
}
fn read_medium_configuration_page(
&mut self,
) -> Result<(ModeParameterHeader, ModeBlockDescriptor, MediumConfigurationModePage), Error> {
let (head, block_descriptor, page): (_,_, MediumConfigurationModePage)
= scsi_mode_sense(&mut self.file, false, 0x1d, 0)?;
proxmox::try_block!({
if (page.page_code & 0b0011_1111) != 0x1d {
bail!("wrong page code {}", page.page_code);
}
if page.page_length != 0x1e {
bail!("wrong page length {}", page.page_length);
}
let block_descriptor = match block_descriptor {
Some(block_descriptor) => block_descriptor,
None => bail!("missing block descriptor"),
};
Ok((head, block_descriptor, page))
}).map_err(|err| format_err!("read_medium_configuration failed - {}", err))
}
fn read_compression_page(
&mut self,
) -> Result<(ModeParameterHeader, ModeBlockDescriptor, DataCompressionModePage), Error> {
@ -675,16 +726,21 @@ impl SgTape {
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");
proxmox::try_block!({
if (page.page_code & 0b0011_1111) != 0x0f {
bail!("wrong page code {}", page.page_code);
}
if page.page_length != 0x0e {
bail!("wrong page length {}", page.page_length);
}
let block_descriptor = match block_descriptor {
Some(block_descriptor) => block_descriptor,
None => bail!("read_compression_page failed: missing block descriptor"),
None => bail!("missing block descriptor"),
};
Ok((head, block_descriptor, page))
}).map_err(|err| format_err!("read_compression_page failed: {}", err))
}
/// Read drive options/status