scsir/command/
write_buffer.rs

1#![allow(dead_code)]
2
3use modular_bitfield_msb::prelude::*;
4
5use crate::{
6    command::bitfield_bound_check,
7    data_wrapper::{AnyType, VecBufferWrapper},
8    result_data::ResultData,
9    Command, DataDirection, Scsi,
10};
11
12#[derive(Clone, Debug)]
13pub struct ReadBufferCommand<'a> {
14    interface: &'a Scsi,
15    mode_specific: u8,
16    mode: u8,
17    buffer_offset: u32,
18    command_buffer: CommandBuffer,
19    data_buffer: Vec<u8>,
20}
21
22impl<'a> ReadBufferCommand<'a> {
23    fn new(interface: &'a Scsi) -> Self {
24        Self {
25            interface,
26            mode_specific: 0,
27            mode: 0,
28            buffer_offset: 0,
29            command_buffer: CommandBuffer::new().with_operation_code(OPERATION_CODE),
30            data_buffer: vec![],
31        }
32    }
33
34    // mode_specific must be less than 0x08
35    pub fn mode_specific(&mut self, value: u8) -> &mut Self {
36        self.mode_specific = value;
37        self
38    }
39
40    // mode must be less than 0x20
41    pub fn mode(&mut self, value: u8) -> &mut Self {
42        self.mode = value;
43        self
44    }
45
46    pub fn buffer_id(&mut self, value: u8) -> &mut Self {
47        self.command_buffer.set_buffer_id(value);
48        self
49    }
50
51    // buffer_offset must be less than 0x100_0000
52    pub fn buffer_offset(&mut self, value: u32) -> &mut Self {
53        self.buffer_offset = value;
54        self
55    }
56
57    pub fn control(&mut self, value: u8) -> &mut Self {
58        self.command_buffer.set_control(value);
59        self
60    }
61
62    pub fn parameter(&mut self, value: &[u8]) -> &mut Self {
63        self.data_buffer.clear();
64        self.data_buffer.extend_from_slice(value);
65        self
66    }
67
68    pub fn issue(&mut self) -> crate::Result<()> {
69        bitfield_bound_check!(self.mode_specific, 3, "mode specific")?;
70        bitfield_bound_check!(self.mode, 5, "mode")?;
71        bitfield_bound_check!(self.buffer_offset, 24, "buffer offset")?;
72        bitfield_bound_check!(self.data_buffer.len(), 24, "parameter length")?;
73
74        let command_buffer = self
75            .command_buffer
76            .with_mode_specific(self.mode_specific)
77            .with_mode(self.mode)
78            .with_buffer_offset(self.buffer_offset)
79            .with_parameter_list_length(self.data_buffer.len() as u32);
80
81        self.interface.issue(&ThisCommand {
82            command_buffer,
83            data_buffer: self.data_buffer.clone().into(),
84        })
85    }
86}
87
88impl Scsi {
89    pub fn write_buffer(&self) -> ReadBufferCommand {
90        ReadBufferCommand::new(self)
91    }
92}
93
94const OPERATION_CODE: u8 = 0x3B;
95
96#[bitfield]
97#[derive(Clone, Copy, Debug)]
98struct CommandBuffer {
99    operation_code: B8,
100    mode_specific: B3,
101    mode: B5,
102    buffer_id: B8,
103    buffer_offset: B24,
104    parameter_list_length: B24,
105    control: B8,
106}
107
108struct ThisCommand {
109    command_buffer: CommandBuffer,
110    data_buffer: VecBufferWrapper,
111}
112
113impl Command for ThisCommand {
114    type CommandBuffer = CommandBuffer;
115
116    type DataBuffer = AnyType;
117
118    type DataBufferWrapper = VecBufferWrapper;
119
120    type ReturnType = crate::Result<()>;
121
122    fn direction(&self) -> DataDirection {
123        DataDirection::ToDevice
124    }
125
126    fn command(&self) -> Self::CommandBuffer {
127        self.command_buffer
128    }
129
130    fn data(&self) -> Self::DataBufferWrapper {
131        self.data_buffer.clone()
132    }
133
134    fn data_size(&self) -> u32 {
135        self.data_buffer.len() as u32
136    }
137
138    fn process_result(&self, result: ResultData<Self::DataBufferWrapper>) -> Self::ReturnType {
139        result.check_ioctl_error()?;
140        result.check_common_error()?;
141
142        Ok(())
143    }
144}
145
146#[cfg(test)]
147mod tests {
148    use super::*;
149    use std::mem::size_of;
150
151    const COMMAND_LENGTH: usize = 10;
152
153    #[test]
154    fn layout_test() {
155        assert_eq!(
156            size_of::<CommandBuffer>(),
157            COMMAND_LENGTH,
158            concat!("Size of: ", stringify!(CommandBuffer))
159        );
160    }
161}