scsir 0.3.0

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

use modular_bitfield_msb::prelude::*;

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

#[derive(Debug)]
pub struct BlockLimits {
    pub write_same_non_zero: bool,
    pub maximum_compare_and_write_length: u8,
    pub optimal_transfer_length_granularity: u16,
    pub maximum_transfer_length: u32,
    pub optimal_transfer_length: u32,
    pub maximum_prefetch_length: u32,
    pub maximum_unmap_lba_count: u32,
    pub maximum_unmap_block_descriptor_count: u32,
    pub optimal_unmap_granularity: u32,
    pub unmap_granularity_alignment: Option<u32>,
    pub maximum_write_same_length: u64,
    pub maximum_atomic_transfer_length: u32,
    pub atomic_alignment: u32,
    pub atomic_transfer_length_granularity: u32,
    pub maximum_atomic_transfer_length_with_atomic_boundary: u32,
    pub maximum_atomic_boundary_size: u32,
}

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

    let result: FlexibleStruct<Page, ()> = this.issue_flex(0)?;

    let body = result.get_body();

    let unmap_granularity_alignment = match body.unmap_granularity_alignment_valid() != 0 {
        true => Some(body.unmap_granularity_alignment()),
        false => None,
    };

    Ok(BlockLimits {
        write_same_non_zero: body.write_same_non_zero() != 0,
        maximum_compare_and_write_length: body.maximum_compare_and_write_length(),
        optimal_transfer_length_granularity: body.optimal_transfer_length_granularity(),
        maximum_transfer_length: body.maximum_transfer_length(),
        optimal_transfer_length: body.optimal_transfer_length(),
        maximum_prefetch_length: body.maximum_prefetch_length(),
        maximum_unmap_lba_count: body.maximum_unmap_lba_count(),
        maximum_unmap_block_descriptor_count: body.maximum_unmap_block_descriptor_count(),
        optimal_unmap_granularity: body.optimal_unmap_granularity(),
        unmap_granularity_alignment,
        maximum_write_same_length: body.maximum_write_same_length(),
        maximum_atomic_transfer_length: body.maximum_atomic_transfer_length(),
        atomic_alignment: body.atomic_alignment(),
        atomic_transfer_length_granularity: body.atomic_transfer_length_granularity(),
        maximum_atomic_transfer_length_with_atomic_boundary: body
            .maximum_atomic_transfer_length_with_atomic_boundary(),
        maximum_atomic_boundary_size: body.maximum_atomic_boundary_size(),
    })
}

const PAGE_CODE: u8 = 0xB0;

#[bitfield]
#[derive(Clone, Copy, Debug)]
struct Page {
    peripheral_qualifier: B3,
    peripheral_device_type: B5,
    page_code: B8,
    page_length: B16,
    reserved: B7,
    write_same_non_zero: B1,
    maximum_compare_and_write_length: B8,
    optimal_transfer_length_granularity: B16,
    maximum_transfer_length: B32,
    optimal_transfer_length: B32,
    maximum_prefetch_length: B32,
    maximum_unmap_lba_count: B32,
    maximum_unmap_block_descriptor_count: B32,
    optimal_unmap_granularity: B32,
    unmap_granularity_alignment_valid: B1,
    unmap_granularity_alignment: B31,
    maximum_write_same_length: B64,
    maximum_atomic_transfer_length: B32,
    atomic_alignment: B32,
    atomic_transfer_length_granularity: B32,
    maximum_atomic_transfer_length_with_atomic_boundary: B32,
    maximum_atomic_boundary_size: B32,
}

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

    const PAGE_LENGTH: usize = 64;

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