[pbs-devel] [PATCH 08/11] sgutils2: add scsi_mode_sense helper

Dietmar Maurer dietmar at proxmox.com
Wed Apr 7 12:23:05 CEST 2021


---
 src/tools/sgutils2.rs | 99 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 99 insertions(+)

diff --git a/src/tools/sgutils2.rs b/src/tools/sgutils2.rs
index 4edfd9d9..af6ab6de 100644
--- a/src/tools/sgutils2.rs
+++ b/src/tools/sgutils2.rs
@@ -242,6 +242,46 @@ pub struct InquiryInfo {
     pub revision: String,
 }
 
+#[repr(C, packed)]
+#[derive(Endian, Debug, Copy, Clone)]
+pub struct ModeParameterHeader {
+    pub mode_data_len: u16,
+    pub medium_type: u8,
+    pub flags3: u8,
+    reserved4: [u8;2],
+    pub block_descriptior_len: u16,
+}
+
+#[repr(C, packed)]
+#[derive(Endian, Debug, Copy, Clone)]
+/// SCSI ModeBlockDescriptor for Tape devices
+pub struct ModeBlockDescriptor {
+    pub density_code: u8,
+    pub number_of_blocks: [u8;3],
+    reserverd: u8,
+    pub block_length: [u8; 3],
+}
+
+impl ModeBlockDescriptor {
+
+    pub fn block_length(&self) -> u32 {
+        ((self.block_length[0] as u32) << 16) +
+            ((self.block_length[1] as u32) << 8) +
+            (self.block_length[2] as u32)
+
+    }
+
+    pub fn set_block_length(&mut self, length: u32) -> Result<(), Error> {
+        if length > 0x80_00_00 {
+            bail!("block length '{}' is too large", length);
+        }
+        self.block_length[0] = ((length & 0x00ff0000) >> 16) as u8;
+        self.block_length[1] = ((length & 0x0000ff00) >> 8) as u8;
+        self.block_length[2] = (length & 0x000000ff) as u8;
+        Ok(())
+    }
+}
+
 pub const SCSI_PT_DO_START_OK:c_int = 0;
 pub const SCSI_PT_DO_BAD_PARAMS:c_int = 1;
 pub const SCSI_PT_DO_TIMEOUT:c_int = 2;
@@ -654,3 +694,62 @@ pub fn scsi_inquiry<F: AsRawFd>(
         Ok(info)
     }).map_err(|err: Error| format_err!("decode inquiry page failed - {}", err))
 }
+
+/// Run SCSI Mode Sense
+///
+/// Warning: P needs to be repr(C, packed)]
+pub fn scsi_mode_sense<F: AsRawFd, P: Endian>(
+    file: &mut F,
+    disable_block_descriptor: bool,
+    page_code: u8,
+    sub_page_code: u8,
+) -> Result<(ModeParameterHeader, Option<ModeBlockDescriptor>, P), Error> {
+
+    let allocation_len: u16 = 4096;
+    let mut sg_raw = SgRaw::new(file, allocation_len as usize)?;
+
+    let mut cmd = Vec::new();
+    cmd.push(0x5A); // MODE SENSE(10)
+    if disable_block_descriptor {
+        cmd.push(8); // DBD=1 (Disable Block Descriptors)
+    } else {
+        cmd.push(0); // DBD=0 (Include Block Descriptors)
+    }
+    cmd.push(page_code & 63); // report current values for page_code
+    cmd.push(sub_page_code);
+
+    cmd.extend(&[0, 0, 0]); // reserved
+    cmd.extend(&allocation_len.to_be_bytes()); // allocation len
+    cmd.push(0); //control
+
+    let data = sg_raw.do_command(&cmd)
+        .map_err(|err| format_err!("mode sense failed - {}", err))?;
+
+    proxmox::try_block!({
+        let mut reader = &data[..];
+
+        let head: ModeParameterHeader = unsafe { reader.read_be_value()? };
+
+        if (head.mode_data_len as usize + 2) != data.len() {
+            bail!("wrong mode_data_len");
+        }
+
+        if disable_block_descriptor && head.block_descriptior_len != 0 {
+            bail!("wrong block_descriptior_len");
+        }
+
+        let mut block_descriptor: Option<ModeBlockDescriptor> = None;
+
+        if !disable_block_descriptor {
+            if head.block_descriptior_len != 8 {
+                bail!("wrong block_descriptior_len");
+            }
+
+            block_descriptor = Some(unsafe { reader.read_be_value()? });
+        }
+
+        let page: P = unsafe { reader.read_be_value()? };
+
+        Ok((head, block_descriptor, page))
+    }).map_err(|err: Error| format_err!("decode mode sense failed - {}", err))
+}
-- 
2.20.1





More information about the pbs-devel mailing list