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 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}