1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#[derive(Debug)]
#[cfg_attr(feature = "serializable", derive(Serialize))]
pub struct Inquiry {
pub connected: Option<bool>,
pub device_type: String, // TODO enum?
pub removable: bool,
pub naca_bit: bool, /// Normal ACA bit support, see SAM-3
pub hier_addressing: bool,
pub scc: bool,
pub acc: bool,
pub tpc: bool,
pub protection: bool,
pub enclosure_services: bool,
pub multiport: bool,
pub media_changer: bool,
pub linked_cmds: bool,
pub vendor_id: String,
pub product_id: String,
pub product_rev: String,
pub drive_serial: String,
}
fn is_set(x: u8, bit: usize) -> bool {
x & (1<<bit) != 0
}
pub fn parse_inquiry(data: &Vec<u8>) -> Inquiry {
Inquiry {
connected: match (data[0] & 0b1110_0000) >> 5 { // Peripheral Qualifier
0b000 => Some(true),
0b001 => Some(false),
// 010 is reserved
// 011 for server not capable of supporting a peripheral device
// 100..111 is vendor specific
_ => None,
},
device_type: match data[0] & 0b0001_1111 {
0x00 => "SBC-2", // Direct access block device (e.g., magnetic disk)
0x01 => "SSC-2", // Sequential-access device (e.g., magnetic tape)
0x02 => "SSC", // Printer device
0x03 => "SPC-2", // Processor device
0x04 => "SBC", // Write-once device (e.g., some optical disks)
0x05 => "MMC-4", // CD/DVD device
0x06 => "Scanner device", // (obsolete)
0x07 => "SBC", // Optical memory device (e.g., some optical disks)
0x08 => "SMC-2", // Medium changer device (e.g., jukeboxes)
0x09 => "Communications device", // (obsolete)
0x0A | 0x0B => "?", // Obsolete
0x0C => "SCC-2", // Storage array controller device (e.g., RAID)
0x0D => "SES", // Enclosure services device
0x0E => "RBC", // Simplified direct-access device (e.g., magnetic disk)
0x0F => "OCRW", // Optical card reader/writer device
0x10 => "BCC", // Bridge Controller Commands
0x11 => "OSD", // Object-based Storage Device
0x12 => "ADC", // Automation/Drive Interface
0x13 | 0x1D => "Reserved",
0x1E => "Well known logical unit",
0x1F => "Unknown or no device type",
_ => unreachable!(),
}.to_string(),
removable: is_set(data[1], 7),
/* TODO data[2] → Version:
0x03 SPC
0x04 SPC-2
the rest is ???
*/
naca_bit: is_set(data[3], 5),
hier_addressing: is_set(data[3], 4),
// ResponseFormat: data[3] & 0b1111, // TODO
// data[4]: additional length
scc: is_set(data[5], 7), // storage array controller component support
acc: is_set(data[5], 6), // device contains an access controls coordinator
// TODO? (data[5] & 0b0011_0000) Target Port Group Support
tpc: is_set(data[5], 3), // support for 3rd-party copy commands
protection: is_set(data[5], 0),
enclosure_services: is_set(data[6], 6),
multiport: is_set(data[6], 4),
media_changer: is_set(data[6], 3),
linked_cmds: is_set(data[7], 3),
/* TODO? match (bque: is_set(data[6], 7), cmdque: is_set(data[7], 1)):
00 obsolete
01 full task mgmt model
01 basic task mgmt model
11 invalid
*/
// XXX? > ASCII data fields … may be terminated with one or more ASCII null (00h) characters.
vendor_id: String::from_utf8(data[8..16].to_vec()).unwrap().trim().to_string(),
product_id: String::from_utf8(data[16..32].to_vec()).unwrap().trim().to_string(),
product_rev: String::from_utf8(data[32..36].to_vec()).unwrap().trim().to_string(),
drive_serial: String::from_utf8(data[36..44].to_vec()).unwrap().trim().to_string(),
// TODO TODO TODO TODO TODO
}
}