#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Direction {
In,
Out,
None,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ScsiStatus {
Good,
CheckCondition,
ConditionMet,
Busy,
ReservationConflict,
TaskSetFull,
AcaActive,
TaskAborted,
Unknown(u8),
}
impl From<u8> for ScsiStatus {
fn from(v: u8) -> Self {
match v {
0x00 => ScsiStatus::Good,
0x02 => ScsiStatus::CheckCondition,
0x04 => ScsiStatus::ConditionMet,
0x08 => ScsiStatus::Busy,
0x18 => ScsiStatus::ReservationConflict,
0x28 => ScsiStatus::TaskSetFull,
0x30 => ScsiStatus::AcaActive,
0x40 => ScsiStatus::TaskAborted,
v => ScsiStatus::Unknown(v),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ScsiDeviceType {
Disk,
Tape,
Printer,
Processor,
CdDvd,
Scanner,
OpticalMemory,
MediumChanger,
Communications,
Unknown(u8),
}
impl From<u8> for ScsiDeviceType {
fn from(v: u8) -> Self {
match v {
0x00 => ScsiDeviceType::Disk,
0x01 => ScsiDeviceType::Tape,
0x02 => ScsiDeviceType::Printer,
0x03 => ScsiDeviceType::Processor,
0x05 => ScsiDeviceType::CdDvd,
0x06 => ScsiDeviceType::Scanner,
0x07 => ScsiDeviceType::OpticalMemory,
0x08 => ScsiDeviceType::MediumChanger,
0x09 => ScsiDeviceType::Communications,
v => ScsiDeviceType::Unknown(v),
}
}
}
#[derive(Debug, Clone)]
pub struct OpenOpts {
pub exclusive: bool,
}
impl Default for OpenOpts {
fn default() -> Self {
OpenOpts { exclusive: false }
}
}
pub const MAX_CDB_LEN: usize = 16;
pub const MAX_SENSE_LEN: usize = 32;
#[derive(Debug, Clone)]
pub struct ScsiCommand {
pub cdb: [u8; MAX_CDB_LEN],
pub cdb_len: u8,
pub direction: Direction,
pub data: Vec<u8>,
pub timeout_secs: Option<u32>,
}
#[derive(Debug, Clone)]
pub struct ScsiResult {
pub status: ScsiStatus,
pub sense: [u8; MAX_SENSE_LEN],
pub sense_len: u8,
pub data: Vec<u8>,
pub transferred: u32,
}
#[derive(Debug, Clone)]
pub struct ScsiDeviceInfo {
pub path: String,
pub device_type: ScsiDeviceType,
pub vendor: String,
pub product: String,
pub revision: String,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn scsi_status_known_values() {
let cases: &[(u8, ScsiStatus)] = &[
(0x00, ScsiStatus::Good),
(0x02, ScsiStatus::CheckCondition),
(0x04, ScsiStatus::ConditionMet),
(0x08, ScsiStatus::Busy),
(0x18, ScsiStatus::ReservationConflict),
(0x28, ScsiStatus::TaskSetFull),
(0x30, ScsiStatus::AcaActive),
(0x40, ScsiStatus::TaskAborted),
];
for &(byte, ref expected) in cases {
assert_eq!(ScsiStatus::from(byte), *expected, "byte {byte:#04x}");
}
}
#[test]
fn scsi_status_unknown_falls_through() {
assert_eq!(ScsiStatus::from(0xFF), ScsiStatus::Unknown(0xFF));
assert_eq!(ScsiStatus::from(0x01), ScsiStatus::Unknown(0x01));
}
}