scsir 0.3.0

A simple library for issuing SCSI commands
Documentation
#![allow(dead_code)]

use std::mem::size_of;

use modular_bitfield_msb::prelude::*;

use crate::{command::inquiry::InquiryCommand, data_wrapper::FlexibleStruct};

#[derive(Debug)]
pub struct ModePagePolicy {
    pub descriptors: Vec<ModePagePolicyDescriptor>,
}

#[derive(Debug)]
pub struct ModePagePolicyDescriptor {
    pub policy_page_code: u8,
    pub policy_subpage_code: u8,
    pub multiple_logical_units_share: bool,
    pub mode_page_policy: u8,
}

pub fn mode_page_policy(this: &mut InquiryCommand) -> crate::Result<ModePagePolicy> {
    this.page_code(Some(PAGE_CODE));

    let result: FlexibleStruct<PageHeader, Descriptor> = this.issue_flex(0)?;
    let remaining = result.get_body().page_length() as usize / size_of::<Descriptor>();
    let result = if remaining == 0 {
        result
    } else {
        this.issue_flex(remaining)?
    };

    unsafe {
        Ok(ModePagePolicy {
            descriptors: result
                .elements_as_slice()
                .iter()
                .map(|e| ModePagePolicyDescriptor {
                    policy_page_code: e.policy_page_code(),
                    policy_subpage_code: e.policy_subpage_code(),
                    multiple_logical_units_share: e.multiple_logical_units_share() != 0,
                    mode_page_policy: e.mode_page_policy(),
                })
                .collect(),
        })
    }
}

const PAGE_CODE: u8 = 0x87;

#[bitfield]
#[derive(Clone, Copy, Debug)]
struct PageHeader {
    peripheral_qualifier: B3,
    peripheral_device_type: B5,
    page_code: B8,
    page_length: B16,
}

#[bitfield]
#[derive(Clone, Copy, Debug)]
struct Descriptor {
    reserved_0: B2,
    policy_page_code: B6,
    policy_subpage_code: B8,
    multiple_logical_units_share: B1,
    reserved_1: B5,
    mode_page_policy: B2,
    reserved_2: B8,
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::mem::size_of;

    const PAGE_HEADER_LENGTH: usize = 4;
    const DESCRIPTOR_HEADER_LENGTH: usize = 4;

    #[test]
    fn layout_test() {
        assert_eq!(
            size_of::<PageHeader>(),
            PAGE_HEADER_LENGTH,
            concat!("Size of: ", stringify!(PageHeader))
        );

        assert_eq!(
            size_of::<Descriptor>(),
            DESCRIPTOR_HEADER_LENGTH,
            concat!("Size of: ", stringify!(DescriptorHeader))
        );
    }
}