scsir/command/
read_defect_data.rs

1#![allow(dead_code)]
2
3use std::{marker::PhantomData, mem::size_of};
4
5use modular_bitfield_msb::prelude::*;
6
7use crate::{
8    command::{bitfield_bound_check, get_array},
9    data_wrapper::{AnyType, FlexibleStruct},
10    result_data::ResultData,
11    Command, DataDirection, Scsi,
12};
13
14#[derive(Clone, Debug)]
15pub struct ReadDefectDataCommand<'a> {
16    interface: &'a Scsi,
17    request_primary_defect_list: bool,
18    request_grown_defect_list: bool,
19    defect_list_format: u8,
20    address_descriptor_index: u32,
21    descriptor_length: u32,
22    control: u8,
23}
24
25#[derive(Clone, Debug)]
26pub struct CommandResult {
27    pub primary_defect_list_valid: bool,
28    pub grown_defect_list_valid: bool,
29    pub total_descriptor_length: u32,
30    pub descriptors: DefectList,
31}
32
33#[derive(Clone, Debug)]
34pub enum DefectList {
35    ShortBlockFormat(Vec<ShortBlockFormatAddressDescriptor>),
36    ExtendedBytesFromIndex(Vec<ExtendedBytesFromIndexAddressDescriptor>),
37    ExtendedPhysicalSector(Vec<ExtendedPhysicalSectorAddressDescriptor>),
38    LongBlockFormat(Vec<LongBlockFormatAddressDescriptor>),
39    BytesFromIndexFormat(Vec<BytesFromIndexFormatAddressDescriptor>),
40    PhysicalSectorFormat(Vec<PhysicalSectorFormatAddressDescriptor>),
41    Custom(Vec<u8>),
42}
43
44#[derive(Clone, Copy, Debug)]
45pub struct ShortBlockFormatAddressDescriptor {
46    pub short_block_address: u32,
47}
48
49#[derive(Clone, Copy, Debug)]
50pub struct ExtendedBytesFromIndexAddressDescriptor {
51    pub cylinder_number: u32,
52    pub head_number: u8,
53    pub multi_address_descriptor_start: bool,
54    pub bytes_from_index: u32,
55}
56
57#[derive(Clone, Copy, Debug)]
58pub struct ExtendedPhysicalSectorAddressDescriptor {
59    pub cylinder_number: u32,
60    pub head_number: u8,
61    pub multi_address_descriptor_start: bool,
62    pub sector_number: u32,
63}
64
65#[derive(Clone, Copy, Debug)]
66pub struct LongBlockFormatAddressDescriptor {
67    pub long_block_address: u64,
68}
69
70#[derive(Clone, Copy, Debug)]
71pub struct BytesFromIndexFormatAddressDescriptor {
72    pub cylinder_number: u32,
73    pub head_number: u8,
74    pub bytes_from_index: u32,
75}
76
77#[derive(Clone, Copy, Debug)]
78pub struct PhysicalSectorFormatAddressDescriptor {
79    pub cylinder_number: u32,
80    pub head_number: u8,
81    pub sector_number: u32,
82}
83
84impl<'a> ReadDefectDataCommand<'a> {
85    fn new(interface: &'a Scsi) -> Self {
86        Self {
87            interface,
88            request_primary_defect_list: false,
89            request_grown_defect_list: false,
90            defect_list_format: 0,
91            address_descriptor_index: 0,
92            descriptor_length: 0,
93            control: 0,
94        }
95    }
96
97    pub fn request_primary_defect_list(&mut self, value: bool) -> &mut Self {
98        self.request_primary_defect_list = value;
99        self
100    }
101
102    pub fn request_grown_defect_list(&mut self, value: bool) -> &mut Self {
103        self.request_grown_defect_list = value;
104        self
105    }
106
107    // defect_list_format must be less than 0x08
108    pub fn defect_list_format(&mut self, value: u8) -> &mut Self {
109        self.defect_list_format = value;
110        self
111    }
112
113    pub fn address_descriptor_index(&mut self, value: u32) -> &mut Self {
114        self.address_descriptor_index = value;
115        self
116    }
117
118    pub fn control(&mut self, value: u8) -> &mut Self {
119        self.control = value;
120        self
121    }
122
123    pub fn descriptor_length(&mut self, value: u32) -> &mut Self {
124        self.descriptor_length = value;
125        self
126    }
127
128    fn error_check(
129        &self,
130        header_size: usize,
131        max_allocation_length: usize,
132        allow_address_descriptor_index: bool,
133    ) -> crate::Result<()> {
134        bitfield_bound_check!(self.defect_list_format, 3, "defect list format")?;
135
136        let max_descriptor_length =
137            (max_allocation_length - header_size) / self.get_defect_list_item_size();
138        if self.descriptor_length > max_descriptor_length as u32 {
139            return Err(
140                crate::Error::ArgumentOutOfBounds(
141                    format!(
142                        "Expected descriptor length is out of bounds. The maximum possible value is {}, but {} was provided.",
143                        max_descriptor_length,
144                        self.descriptor_length)));
145        }
146
147        if !allow_address_descriptor_index && self.address_descriptor_index > 0 {
148            return Err(crate::Error::BadArgument(
149                "address descriptor index is not allowed here".to_owned(),
150            ));
151        }
152
153        Ok(())
154    }
155
156    fn get_defect_list_item_size(&self) -> usize {
157        match self.defect_list_format {
158            0b0000 => size_of::<super::format_unit::ShortBlockFormatAddressDescriptor>(),
159            0b0001 => size_of::<super::format_unit::ExtendedBytesFromIndexAddressDescriptor>(),
160            0b0010 => size_of::<super::format_unit::ExtendedPhysicalSectorAddressDescriptor>(),
161            0b0011 => size_of::<super::format_unit::LongBlockFormatAddressDescriptor>(),
162            0b0100 => size_of::<super::format_unit::BytesFromIndexFormatAddressDescriptor>(),
163            0b0101 => size_of::<super::format_unit::PhysicalSectorFormatAddressDescriptor>(),
164            _ => size_of::<u8>(),
165        }
166    }
167
168    pub fn issue_10(&mut self) -> crate::Result<CommandResult> {
169        let extra_allocation_length =
170            self.descriptor_length as usize * self.get_defect_list_item_size();
171        let allocation_length = size_of::<DataBufferHeader10>() + extra_allocation_length;
172
173        self.error_check(size_of::<DataBufferHeader10>(), u16::MAX.into(), false)?;
174
175        let command_buffer = CommandBuffer10::new()
176            .with_operation_code(OPERATION_CODE_10)
177            .with_request_primary_defect_list(self.request_primary_defect_list.into())
178            .with_request_grown_defect_list(self.request_grown_defect_list.into())
179            .with_defect_list_format(self.defect_list_format)
180            .with_allocation_length(allocation_length as u16)
181            .with_control(self.control);
182
183        let (body, defect_list) = self.interface.issue(&ThisCommand {
184            command_buffer,
185            extra_allocation_length,
186            defect_list_format: self.defect_list_format,
187            marker: PhantomData::<DataBufferHeader10>,
188        })?;
189
190        Ok(CommandResult {
191            primary_defect_list_valid: body.primary_defect_list_valid() != 0,
192            grown_defect_list_valid: body.grown_defect_list_valid() != 0,
193            total_descriptor_length: (body.defect_list_length() as usize
194                / self.get_defect_list_item_size()) as u32,
195            descriptors: defect_list,
196        })
197    }
198
199    pub fn issue_12(&mut self) -> crate::Result<CommandResult> {
200        let extra_allocation_length =
201            self.descriptor_length as usize * self.get_defect_list_item_size();
202        let allocation_length = size_of::<DataBufferHeader12>() + extra_allocation_length;
203
204        self.error_check(size_of::<DataBufferHeader12>(), u32::MAX as usize, true)?;
205
206        let command_buffer = CommandBuffer12::new()
207            .with_operation_code(OPERATION_CODE_12)
208            .with_request_primary_defect_list(self.request_primary_defect_list.into())
209            .with_request_grown_defect_list(self.request_grown_defect_list.into())
210            .with_defect_list_format(self.defect_list_format)
211            .with_address_descriptor_index(self.address_descriptor_index)
212            .with_allocation_length(allocation_length as u32)
213            .with_control(self.control);
214
215        let (body, defect_list) = self.interface.issue(&ThisCommand {
216            command_buffer,
217            extra_allocation_length,
218            defect_list_format: self.defect_list_format,
219            marker: PhantomData::<DataBufferHeader12>,
220        })?;
221
222        Ok(CommandResult {
223            primary_defect_list_valid: body.primary_defect_list_valid() != 0,
224            grown_defect_list_valid: body.grown_defect_list_valid() != 0,
225            total_descriptor_length: (body.defect_list_length() as usize
226                / self.get_defect_list_item_size()) as u32,
227            descriptors: defect_list,
228        })
229    }
230}
231
232impl Scsi {
233    pub fn read_defect_data(&self) -> ReadDefectDataCommand {
234        ReadDefectDataCommand::new(self)
235    }
236}
237
238const OPERATION_CODE_10: u8 = 0x37;
239const OPERATION_CODE_12: u8 = 0xB7;
240
241#[bitfield]
242#[derive(Clone, Copy)]
243struct CommandBuffer10 {
244    operation_code: B8,
245    reserved_0: B8,
246    reserved_1: B3,
247    request_primary_defect_list: B1,
248    request_grown_defect_list: B1,
249    defect_list_format: B3,
250    reserved_2: B32,
251    allocation_length: B16,
252    control: B8,
253}
254
255#[bitfield]
256#[derive(Clone, Copy)]
257struct CommandBuffer12 {
258    operation_code: B8,
259    reserved_0: B3,
260    request_primary_defect_list: B1,
261    request_grown_defect_list: B1,
262    defect_list_format: B3,
263    address_descriptor_index: B32,
264    allocation_length: B32,
265    reserved_1: B8,
266    control: B8,
267}
268
269#[bitfield]
270#[derive(Clone, Copy, Default)]
271struct DataBufferHeader10 {
272    reserved_0: B8,
273    reserved_1: B3,
274    primary_defect_list_valid: B1,
275    grown_defect_list_valid: B1,
276    defect_list_format: B3,
277    defect_list_length: B16,
278}
279
280#[bitfield]
281#[derive(Clone, Copy, Default)]
282struct DataBufferHeader12 {
283    reserved_0: B8,
284    reserved_1: B3,
285    primary_defect_list_valid: B1,
286    grown_defect_list_valid: B1,
287    defect_list_format: B3,
288    reserved_2: B16,
289    defect_list_length: B32,
290}
291
292struct ThisCommand<C, Body> {
293    command_buffer: C,
294    extra_allocation_length: usize,
295    defect_list_format: u8,
296
297    marker: PhantomData<Body>,
298}
299
300impl<C: Copy, Body: Copy> Command for ThisCommand<C, Body> {
301    type CommandBuffer = C;
302
303    type DataBuffer = AnyType;
304
305    type DataBufferWrapper = FlexibleStruct<Body, u8>;
306
307    type ReturnType = crate::Result<(Body, DefectList)>;
308
309    fn direction(&self) -> DataDirection {
310        DataDirection::FromDevice
311    }
312
313    fn command(&self) -> Self::CommandBuffer {
314        self.command_buffer
315    }
316
317    fn data(&self) -> Self::DataBufferWrapper {
318        unsafe { FlexibleStruct::with_length(self.extra_allocation_length) }
319    }
320
321    fn data_size(&self) -> u32 {
322        (self.extra_allocation_length + size_of::<Body>()) as u32
323    }
324
325    fn process_result(&self, result: ResultData<Self::DataBufferWrapper>) -> Self::ReturnType {
326        result.check_ioctl_error()?;
327        result.check_common_error()?;
328
329        let mut defect_list = match self.defect_list_format {
330            0b0000 => DefectList::ShortBlockFormat(vec![]),
331            0b0001 => DefectList::ExtendedBytesFromIndex(vec![]),
332            0b0010 => DefectList::ExtendedPhysicalSector(vec![]),
333            0b0011 => DefectList::LongBlockFormat(vec![]),
334            0b0100 => DefectList::BytesFromIndexFormat(vec![]),
335            0b0101 => DefectList::PhysicalSectorFormat(vec![]),
336            _ => DefectList::Custom(vec![]),
337        };
338
339        match &mut defect_list {
340            DefectList::ShortBlockFormat(v) => {
341                for chunk in unsafe { result.data.elements_as_slice() }.chunks(size_of::<
342                    super::format_unit::ShortBlockFormatAddressDescriptor,
343                >()) {
344                    let (bytes, _) = get_array(chunk);
345                    let raw =
346                        super::format_unit::ShortBlockFormatAddressDescriptor::from_bytes(bytes);
347                    v.push(ShortBlockFormatAddressDescriptor {
348                        short_block_address: raw.short_block_address(),
349                    });
350                }
351            }
352            DefectList::ExtendedBytesFromIndex(v) => {
353                for chunk in unsafe { result.data.elements_as_slice() }.chunks(size_of::<
354                    super::format_unit::ExtendedBytesFromIndexAddressDescriptor,
355                >()) {
356                    let (bytes, _) = get_array(chunk);
357                    let raw =
358                        super::format_unit::ExtendedBytesFromIndexAddressDescriptor::from_bytes(
359                            bytes,
360                        );
361                    v.push(ExtendedBytesFromIndexAddressDescriptor {
362                        cylinder_number: raw.cylinder_number(),
363                        head_number: raw.head_number(),
364                        multi_address_descriptor_start: raw.multi_address_descriptor_start() != 0,
365                        bytes_from_index: raw.bytes_from_index(),
366                    });
367                }
368            }
369            DefectList::ExtendedPhysicalSector(v) => {
370                for chunk in unsafe { result.data.elements_as_slice() }.chunks(size_of::<
371                    super::format_unit::ExtendedPhysicalSectorAddressDescriptor,
372                >()) {
373                    let (bytes, _) = get_array(chunk);
374                    let raw =
375                        super::format_unit::ExtendedPhysicalSectorAddressDescriptor::from_bytes(
376                            bytes,
377                        );
378                    v.push(ExtendedPhysicalSectorAddressDescriptor {
379                        cylinder_number: raw.cylinder_number(),
380                        head_number: raw.head_number(),
381                        multi_address_descriptor_start: raw.multi_address_descriptor_start() != 0,
382                        sector_number: raw.sector_number(),
383                    });
384                }
385            }
386            DefectList::LongBlockFormat(v) => {
387                for chunk in unsafe { result.data.elements_as_slice() }.chunks(size_of::<
388                    super::format_unit::LongBlockFormatAddressDescriptor,
389                >()) {
390                    let (bytes, _) = get_array(chunk);
391                    let raw =
392                        super::format_unit::LongBlockFormatAddressDescriptor::from_bytes(bytes);
393                    v.push(LongBlockFormatAddressDescriptor {
394                        long_block_address: raw.long_block_address(),
395                    });
396                }
397            }
398            DefectList::BytesFromIndexFormat(v) => {
399                for chunk in unsafe { result.data.elements_as_slice() }.chunks(size_of::<
400                    super::format_unit::BytesFromIndexFormatAddressDescriptor,
401                >()) {
402                    let (bytes, _) = get_array(chunk);
403                    let raw = super::format_unit::BytesFromIndexFormatAddressDescriptor::from_bytes(
404                        bytes,
405                    );
406                    v.push(BytesFromIndexFormatAddressDescriptor {
407                        cylinder_number: raw.cylinder_number(),
408                        head_number: raw.head_number(),
409                        bytes_from_index: raw.bytes_from_index(),
410                    });
411                }
412            }
413            DefectList::PhysicalSectorFormat(v) => {
414                for chunk in unsafe { result.data.elements_as_slice() }.chunks(size_of::<
415                    super::format_unit::PhysicalSectorFormatAddressDescriptor,
416                >()) {
417                    let (bytes, _) = get_array(chunk);
418                    let raw = super::format_unit::PhysicalSectorFormatAddressDescriptor::from_bytes(
419                        bytes,
420                    );
421                    v.push(PhysicalSectorFormatAddressDescriptor {
422                        cylinder_number: raw.cylinder_number(),
423                        head_number: raw.head_number(),
424                        sector_number: raw.sector_number(),
425                    });
426                }
427            }
428            DefectList::Custom(v) => {
429                v.extend_from_slice(unsafe { result.data.elements_as_slice() });
430            }
431        }
432
433        Ok((
434            unsafe { result.data.get_body_maybe_uninit().assume_init() },
435            defect_list,
436        ))
437    }
438}
439
440#[cfg(test)]
441mod tests {
442    use super::*;
443    use std::mem::size_of;
444
445    const COMMAND_LENGTH_10: usize = 10;
446    const COMMAND_LENGTH_12: usize = 12;
447    const DATA_HEADER_LENGTH_10: usize = 4;
448    const DATA_HEADER_LENGTH_12: usize = 8;
449
450    #[test]
451    fn layout_test() {
452        assert_eq!(
453            size_of::<CommandBuffer10>(),
454            COMMAND_LENGTH_10,
455            concat!("Size of: ", stringify!(CommandBuffer10))
456        );
457
458        assert_eq!(
459            size_of::<CommandBuffer12>(),
460            COMMAND_LENGTH_12,
461            concat!("Size of: ", stringify!(CommandBuffer12))
462        );
463
464        assert_eq!(
465            size_of::<DataBufferHeader10>(),
466            DATA_HEADER_LENGTH_10,
467            concat!("Size of: ", stringify!(DataBufferHeader10))
468        );
469
470        assert_eq!(
471            size_of::<DataBufferHeader12>(),
472            DATA_HEADER_LENGTH_12,
473            concat!("Size of: ", stringify!(DataBufferHeader12))
474        );
475    }
476}