1pub mod data;
11pub mod pages;
12
13#[cfg(target_os = "linux")]
14mod linux;
15
16#[cfg(target_os = "freebsd")]
17mod freebsd;
18
19use std::io;
20use ata;
21use byteorder::{ReadBytesExt, BigEndian};
22use self::data::sense;
23
24use Direction;
25use Device;
26
27use utils::hexdump_8;
28
29quick_error! {
30 #[derive(Debug)]
31 pub enum Error {
32 IO(err: io::Error) {
33 from()
34 display("IO error: {}", err)
35 description(err.description())
36 cause(err)
37 }
38 Sense(key: sense::key::SenseKey, asc: u8, ascq: u8) { description("SCSI error")
43 display("SCSI error: {:?} ({})",
44 key,
45 sense::key::decode_asc(*asc, *ascq)
46 .map(|x| x.to_string())
47 .unwrap_or_else(|| format!("unknown additional sense code: {:02x} {:02x}", asc, ascq)))
48 }
49 Nonsense {}
52 }
53}
54
55quick_error! {
57 #[derive(Debug)]
58 pub enum ATAError {
59 SCSI(err: Error) {
60 from()
61 from(err: io::Error) -> (Error::IO(err))
62 display("{}", err)
63 }
64 NotSupported {}
66 NoRegisters {}
68 }
69}
70
71#[derive(Debug)]
72pub struct SCSIDevice {
73 device: Device,
74}
75
76impl SCSIDevice {
77 pub fn new(device: Device) -> Self {
78 Self { device }
79 }
80
81 pub fn do_cmd(&self, cmd: &[u8], dir: Direction, sense_len: usize, data_len: usize) -> Result<(Vec<u8>, Vec<u8>), io::Error> {
84 info!("SCSI cmd: dir={:?} cmd={:?}", dir, cmd);
85
86 let ret = Self::do_platform_cmd(self, cmd, dir, sense_len, data_len);
88 match ret {
89 Ok((ref sense, ref data)) => {
90 debug!("SCSI autosense: {}", hexdump_8(sense));
91 debug!("SCSI data: {}", hexdump_8(data));
92 },
93 ref err => {
94 debug!("SCSI err: {:?}", err);
95 }
96 }
97 ret
98 }
99}
100
101pub trait SCSICommon {
103 fn do_cmd(&self, cmd: &[u8], dir: Direction, sense_len: usize, data_len: usize) -> Result<(Vec<u8>, Vec<u8>), io::Error>;
105
106 fn scsi_inquiry(&self, vital: bool, code: u8) -> Result<(Vec<u8>, Vec<u8>), Error> {
107 info!("issuing INQUIRY: code={:?} vital={:?}", code, vital);
108
109 const alloc: usize = 4096;
111
112 let cmd: [u8; 6] = [
113 0x12, if vital {1} else {0}, code,
116 (alloc >> 8) as u8,
117 (alloc & 0xff) as u8,
118 0, ];
120
121 Ok(self.do_cmd(&cmd, Direction::From, 32, alloc)?)
122 }
123
124 fn read_capacity_10(&self, lba: Option<u32>) -> Result<(Vec<u8>, u32, u32), Error> {
126 info!("issuing READ CAPACITY(10): lba={:?}", lba);
127
128 let (pmi, lba) = match lba {
130 Some(lba) => (true, lba),
131 None => (false, 0),
132 };
133
134 let cmd: [u8; 10] = [
135 0x25, 0, ((lba >> 24) & 0xff) as u8,
138 ((lba >> 16) & 0xff) as u8,
139 ((lba >> 8) & 0xff) as u8,
140 ((lba) & 0xff) as u8,
141 0, 0, if pmi { 1 } else { 0 }, 0, ];
146
147 let (sense, data) = self.do_cmd(&cmd, Direction::From, 32, 8)?;
148
149 Ok((
150 sense,
151 (&data[0..4]).read_u32::<BigEndian>().unwrap(),
152 (&data[4..8]).read_u32::<BigEndian>().unwrap(),
153 ))
154 }
155
156 fn log_sense(&self, changed: bool, save_params: bool, default: bool, threshold: bool, page: u8, subpage: u8, param_ptr: u16) -> Result<(Vec<u8>, Vec<u8>), Error> {
170 info!("issuing LOG SENSE: page={page:?} subpage={subpage:?} param_ptr={param_ptr:?} changed={changed:?} save_params={save_params:?} default={default:?} threshold={threshold:?}",
171 changed = changed,
172 save_params = save_params,
173 default = default,
174 threshold = threshold,
175 page = page,
176 subpage = subpage,
177 param_ptr = param_ptr,
178 );
179
180 const alloc: usize = 4096;
182
183 let pc = match (default, threshold) {
185 (false, true) => 0b00, (false, false) => 0b01, (true, true) => 0b10, (true, false) => 0b11, };
190
191 let cmd: [u8; 10] = [
192 0x4d, if changed {0b10} else {0} + if save_params {0b1} else {0}, (pc << 6) + page,
196 subpage,
197 0, (param_ptr >> 8) as u8,
199 (param_ptr & 0xff) as u8,
200 (alloc >> 8) as u8,
201 (alloc & 0xff) as u8,
202 0, ];
204
205 Ok(self.do_cmd(&cmd, Direction::From, 32, alloc)?)
206 }
207
208 fn ata_pass_through_16(&self, dir: Direction, regs: &ata::RegistersWrite) -> Result<(ata::RegistersRead, Vec<u8>), ATAError> {
209 info!("issuing ATA PASS-THROUGH (16): dir={:?} regs={:?}", dir, regs);
210
211 let extend = 0; let protocol = match dir {
214 Direction::None => 3, Direction::From => 4, Direction::To => unimplemented!(), _ => unimplemented!(),
218 };
219 let multiple_count = 0; let ata_cmd: [u8; 16] = [
221 0x85, (multiple_count << 5) + (protocol << 1) + extend,
223 0b0010_1101,
230 0, regs.features,
231 0, regs.sector_count,
232 0, regs.sector,
233 0, regs.cyl_low,
234 0, regs.cyl_high,
235 regs.device,
236 regs.command,
237 0, ];
239
240 let (sense, data) = self.do_cmd(&ata_cmd, Direction::From, 32, 512)?;
241
242 let descriptors = match sense::parse(&sense) {
244 Some((true, sense::Sense::Descriptor(sense::DescriptorData {
246 descriptors,
247 key: 0x01, asc: 0x00, ascq: 0x1D,
249 ..
250 }))) => {
251 descriptors
252 },
253
254 Some((true, sense::Sense::Descriptor(sense::DescriptorData {
255 descriptors,
256 key: 0x00, asc: 0x00, ascq: 0x00,
259 ..
260 }))) => {
261 descriptors
262 },
263
264 Some((true, sense::Sense::Fixed(sense::FixedData::Valid {
265 key: 0x05, asc: 0x20, ascq: 0x00, ..
267 }))) => {
268 return Err(ATAError::NotSupported);
269 },
270
271 Some((true, sense::Sense::Fixed(sense::FixedData::Valid {
272 key, asc, ascq, ..
273 })))
274 | Some((true, sense::Sense::Descriptor(sense::DescriptorData {
275 key, asc, ascq, ..
276 })))
277 => {
278 return Err(Error::Sense(sense::key::SenseKey::from(key), asc, ascq))?;
280 },
281
282 Some((true, sense::Sense::Fixed(sense::FixedData::Invalid(_)))) => {
283 return Err(Error::Nonsense)?;
285 },
286
287 Some((false, _)) | None => {
288 return Err(ATAError::NoRegisters);
290 },
291 };
292
293 for desc in descriptors {
294 if desc.code != 0x09 { continue; }
295 if desc.data.len() != 12 { continue; }
296
297 let d = desc.data;
298
299 return Ok((ata::RegistersRead {
301 error: d[1],
302
303 sector_count: d[3],
304
305 sector: d[5],
306 cyl_low: d[7],
307 cyl_high: d[9],
308 device: d[10],
309
310 status: d[11],
311 }, data))
312 }
313
314 return Err(ATAError::NoRegisters);
315 }
316}
317
318impl SCSICommon for SCSIDevice {
319 fn do_cmd(&self, cmd: &[u8], dir: Direction, sense_len: usize, data_len: usize) -> Result<(Vec<u8>, Vec<u8>), io::Error> {
321 Self::do_cmd(self, cmd, dir, sense_len, data_len)
322 }
323}