Skip to main content

scsir/command/
write_and_verify.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 WriteAndVerifyCommand<'a> {
14    interface: &'a Scsi,
15    control: u8,
16    group_number: u8,
17    write_protect: u8,
18    disable_page_out: bool,
19    byte_check: u8,
20    logical_block_address: u64,
21    expected_initial_logical_block_reference_tag: u32,
22    expected_logical_block_application_tag: u16,
23    logical_block_application_tag_mask: u16,
24    logical_block_size: u32,
25    data_buffer: Vec<u8>,
26}
27
28impl<'a> WriteAndVerifyCommand<'a> {
29    fn new(interface: &'a Scsi) -> Self {
30        Self {
31            interface,
32            control: 0,
33            group_number: 0,
34            write_protect: 0,
35            disable_page_out: false,
36            byte_check: 0,
37            logical_block_address: 0,
38            expected_initial_logical_block_reference_tag: 0,
39            expected_logical_block_application_tag: 0,
40            logical_block_application_tag_mask: 0,
41            logical_block_size: 512,
42            data_buffer: vec![],
43        }
44    }
45
46    pub fn control(&mut self, value: u8) -> &mut Self {
47        self.control = value;
48        self
49    }
50
51    // group_number must be less than 0x20
52    pub fn group_number(&mut self, value: u8) -> &mut Self {
53        self.group_number = value;
54        self
55    }
56
57    // write_protect must be less than 0x08
58    pub fn write_protect(&mut self, value: u8) -> &mut Self {
59        self.write_protect = value;
60        self
61    }
62
63    pub fn disable_page_out(&mut self, value: bool) -> &mut Self {
64        self.disable_page_out = value;
65        self
66    }
67
68    // byte_check must be less than 0x04
69    pub fn byte_check(&mut self, value: u8) -> &mut Self {
70        self.byte_check = value;
71        self
72    }
73
74    pub fn logical_block_address(&mut self, value: u64) -> &mut Self {
75        self.logical_block_address = value;
76        self
77    }
78
79    pub fn expected_initial_logical_block_reference_tag(&mut self, value: u32) -> &mut Self {
80        self.expected_initial_logical_block_reference_tag = value;
81        self
82    }
83
84    pub fn expected_logical_block_application_tag(&mut self, value: u16) -> &mut Self {
85        self.expected_logical_block_application_tag = value;
86        self
87    }
88
89    pub fn logical_block_application_tag_mask(&mut self, value: u16) -> &mut Self {
90        self.logical_block_application_tag_mask = value;
91        self
92    }
93
94    pub fn logical_block_size(&mut self, value: u32) -> &mut Self {
95        self.logical_block_size = value;
96        self
97    }
98
99    pub fn parameter(&mut self, value: &[u8]) -> &mut Self {
100        self.data_buffer.clear();
101        self.data_buffer.extend_from_slice(value);
102        self
103    }
104
105    fn error_check(
106        &self,
107        logical_block_address_bits: u32,
108        transfer_length_bits: u32,
109        expect_tag: bool,
110    ) -> crate::Result<()> {
111        bitfield_bound_check!(self.group_number, 5, "group number")?;
112        bitfield_bound_check!(self.write_protect, 3, "verify protect")?;
113        bitfield_bound_check!(self.byte_check, 2, "byte check")?;
114        bitfield_bound_check!(
115            self.logical_block_address,
116            logical_block_address_bits,
117            "logical block address"
118        )?;
119
120        if self.data_buffer.len() % self.logical_block_size as usize != 0 {
121            return Err(crate::Error::BadArgument(format!(
122                "parameter length should be a multiple of logical block size, which is {}.",
123                self.logical_block_size
124            )));
125        }
126
127        if (self.data_buffer.len() / self.logical_block_size as usize)
128            .wrapping_shr(transfer_length_bits)
129            != 0
130        {
131            return Err(crate::Error::ArgumentOutOfBounds(format!(
132                "parameter length is out of bounds. The maximum possible value is {}, but {} was provided.",
133                1u128.wrapping_shl(transfer_length_bits) * self.logical_block_size as u128,
134                self.data_buffer.len()
135            )));
136        }
137
138        if !expect_tag
139            && (self.expected_initial_logical_block_reference_tag != 0
140                || self.expected_logical_block_application_tag != 0
141                || self.logical_block_application_tag_mask != 0)
142        {
143            return Err(crate::Error::BadArgument(
144                "expected tags and mask are not allowed here".to_owned(),
145            ));
146        }
147
148        Ok(())
149    }
150
151    pub fn issue_10(&mut self) -> crate::Result<()> {
152        self.error_check(32, 16, false)?;
153
154        let command_buffer = CommandBuffer10::new()
155            .with_operation_code(OPERATION_CODE_10)
156            .with_write_protect(self.write_protect)
157            .with_disable_page_out(self.disable_page_out.into())
158            .with_byte_check(self.byte_check)
159            .with_logical_block_address(self.logical_block_address as u32)
160            .with_group_number(self.group_number)
161            .with_transfer_length(
162                (self.data_buffer.len() / self.logical_block_size as usize) as u16,
163            )
164            .with_control(self.control);
165
166        self.interface.issue(&ThisCommand {
167            command_buffer,
168            data_buffer: self.data_buffer.clone().into(),
169        })
170    }
171
172    pub fn issue_12(&mut self) -> crate::Result<()> {
173        self.error_check(32, 32, false)?;
174
175        let command_buffer = CommandBuffer12::new()
176            .with_operation_code(OPERATION_CODE_12)
177            .with_write_protect(self.write_protect)
178            .with_disable_page_out(self.disable_page_out.into())
179            .with_byte_check(self.byte_check)
180            .with_logical_block_address(self.logical_block_address as u32)
181            .with_transfer_length(
182                (self.data_buffer.len() / self.logical_block_size as usize) as u32,
183            )
184            .with_group_number(self.group_number)
185            .with_control(self.control);
186
187        self.interface.issue(&ThisCommand {
188            command_buffer,
189            data_buffer: self.data_buffer.clone().into(),
190        })
191    }
192
193    pub fn issue_16(&mut self) -> crate::Result<()> {
194        self.error_check(64, 32, false)?;
195
196        let command_buffer = CommandBuffer16::new()
197            .with_operation_code(OPERATION_CODE_16)
198            .with_write_protect(self.write_protect)
199            .with_disable_page_out(self.disable_page_out.into())
200            .with_byte_check(self.byte_check)
201            .with_logical_block_address(self.logical_block_address)
202            .with_transfer_length(
203                (self.data_buffer.len() / self.logical_block_size as usize) as u32,
204            )
205            .with_group_number(self.group_number)
206            .with_control(self.control);
207
208        self.interface.issue(&ThisCommand {
209            command_buffer,
210            data_buffer: self.data_buffer.clone().into(),
211        })
212    }
213
214    pub fn issue_32(&mut self) -> crate::Result<()> {
215        self.error_check(64, 32, true)?;
216
217        let command_buffer = CommandBuffer32::new()
218            .with_operation_code(OPERATION_CODE_32)
219            .with_control(self.control)
220            .with_group_number(self.group_number)
221            .with_additional_cdb_length(0x18)
222            .with_service_action(SERVICE_ACTION_32)
223            .with_write_protect(self.write_protect)
224            .with_disable_page_out(self.disable_page_out.into())
225            .with_byte_check(self.byte_check)
226            .with_logical_block_address(self.logical_block_address)
227            .with_expected_initial_logical_block_reference_tag(
228                self.expected_initial_logical_block_reference_tag,
229            )
230            .with_expected_logical_block_application_tag(
231                self.expected_logical_block_application_tag,
232            )
233            .with_logical_block_application_tag_mask(self.logical_block_application_tag_mask)
234            .with_transfer_length(
235                (self.data_buffer.len() / self.logical_block_size as usize) as u32,
236            );
237
238        self.interface.issue(&ThisCommand {
239            command_buffer,
240            data_buffer: self.data_buffer.clone().into(),
241        })
242    }
243}
244
245impl Scsi {
246    pub fn write_and_verify(&self) -> WriteAndVerifyCommand<'_> {
247        WriteAndVerifyCommand::new(self)
248    }
249}
250
251const OPERATION_CODE_10: u8 = 0x2E;
252const OPERATION_CODE_12: u8 = 0xAE;
253const OPERATION_CODE_16: u8 = 0x8E;
254const OPERATION_CODE_32: u8 = 0x7F;
255const SERVICE_ACTION_32: u16 = 0x000C;
256
257#[bitfield]
258#[derive(Clone, Copy)]
259struct CommandBuffer10 {
260    operation_code: B8,
261    write_protect: B3,
262    disable_page_out: B1,
263    reserved_0: B1,
264    byte_check: B2,
265    obsolete: B1,
266    logical_block_address: B32,
267    reserved_1: B3,
268    group_number: B5,
269    transfer_length: B16,
270    control: B8,
271}
272
273#[bitfield]
274#[derive(Clone, Copy)]
275struct CommandBuffer12 {
276    operation_code: B8,
277    write_protect: B3,
278    disable_page_out: B1,
279    reserved_0: B1,
280    byte_check: B2,
281    obsolete: B1,
282    logical_block_address: B32,
283    transfer_length: B32,
284    reserved_1: B3,
285    group_number: B5,
286    control: B8,
287}
288
289#[bitfield]
290#[derive(Clone, Copy)]
291struct CommandBuffer16 {
292    operation_code: B8,
293    write_protect: B3,
294    disable_page_out: B1,
295    reserved_0: B1,
296    byte_check: B2,
297    reserved_1: B1,
298    logical_block_address: B64,
299    transfer_length: B32,
300    reserved_2: B3,
301    group_number: B5,
302    control: B8,
303}
304
305#[bitfield]
306#[derive(Clone, Copy)]
307struct CommandBuffer32 {
308    operation_code: B8,
309    control: B8,
310    reserved_0: B32,
311    reserved_1: B3,
312    group_number: B5,
313    additional_cdb_length: B8,
314    service_action: B16,
315    write_protect: B3,
316    disable_page_out: B1,
317    reserved_2: B1,
318    byte_check: B2,
319    reserved_3: B1,
320    reserved_4: B8,
321    logical_block_address: B64,
322    expected_initial_logical_block_reference_tag: B32,
323    expected_logical_block_application_tag: B16,
324    logical_block_application_tag_mask: B16,
325    transfer_length: B32,
326}
327
328struct ThisCommand<C> {
329    command_buffer: C,
330    data_buffer: VecBufferWrapper,
331}
332
333impl<C: Copy> Command for ThisCommand<C> {
334    type CommandBuffer = C;
335
336    type DataBuffer = AnyType;
337
338    type DataBufferWrapper = VecBufferWrapper;
339
340    type ReturnType = crate::Result<()>;
341
342    fn direction(&self) -> DataDirection {
343        DataDirection::ToDevice
344    }
345
346    fn command(&self) -> Self::CommandBuffer {
347        self.command_buffer
348    }
349
350    fn data(&self) -> Self::DataBufferWrapper {
351        self.data_buffer.clone()
352    }
353
354    fn data_size(&self) -> u32 {
355        self.data_buffer.len() as u32
356    }
357
358    fn process_result(&self, result: ResultData<Self::DataBufferWrapper>) -> Self::ReturnType {
359        result.check_ioctl_error()?;
360        result.check_common_error()?;
361
362        Ok(())
363    }
364}
365
366#[cfg(test)]
367mod tests {
368    use super::*;
369    use std::mem::size_of;
370
371    const COMMAND_LENGTH_10: usize = 10;
372    const COMMAND_LENGTH_12: usize = 12;
373    const COMMAND_LENGTH_16: usize = 16;
374    const COMMAND_LENGTH_32: usize = 32;
375
376    #[test]
377    fn layout_test() {
378        assert_eq!(
379            size_of::<CommandBuffer10>(),
380            COMMAND_LENGTH_10,
381            concat!("Size of: ", stringify!(CommandBuffer10))
382        );
383
384        assert_eq!(
385            size_of::<CommandBuffer12>(),
386            COMMAND_LENGTH_12,
387            concat!("Size of: ", stringify!(CommandBuffer12))
388        );
389
390        assert_eq!(
391            size_of::<CommandBuffer16>(),
392            COMMAND_LENGTH_16,
393            concat!("Size of: ", stringify!(CommandBuffer16))
394        );
395
396        assert_eq!(
397            size_of::<CommandBuffer32>(),
398            COMMAND_LENGTH_32,
399            concat!("Size of: ", stringify!(CommandBuffer32))
400        );
401    }
402}