use anyhow::{Result, anyhow, bail};
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StatusClass {
Success = 0,
Redirection = 1,
InitiatorError = 2,
TargetError = 3,
Unknown(u8),
}
impl From<u8> for StatusClass {
fn from(b: u8) -> Self {
match b {
0 => StatusClass::Success,
1 => StatusClass::Redirection,
2 => StatusClass::InitiatorError,
3 => StatusClass::TargetError,
other => StatusClass::Unknown(other),
}
}
}
impl From<StatusClass> for u8 {
fn from(class: StatusClass) -> Self {
match class {
StatusClass::Success => 0x00,
StatusClass::Redirection => 0x01,
StatusClass::InitiatorError => 0x02,
StatusClass::TargetError => 0x03,
StatusClass::Unknown(v) => v,
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum StatusDetail {
Success(SuccessDetail),
Redirection(RedirectionDetail),
InitiatorErr(InitiatorErrorDetail),
TargetErr(TargetErrorDetail),
}
#[repr(u8)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum SuccessDetail {
CmdCompletedNormally = 0x00,
}
impl TryFrom<u8> for SuccessDetail {
type Error = anyhow::Error;
fn try_from(raw: u8) -> Result<Self> {
match raw {
0x00 => Ok(SuccessDetail::CmdCompletedNormally),
other => Err(anyhow!("unknown Success detail code: {:#02x}", other)),
}
}
}
#[repr(u8)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum RedirectionDetail {
TargetRedirected = 0x01,
}
impl TryFrom<u8> for RedirectionDetail {
type Error = anyhow::Error;
fn try_from(raw: u8) -> Result<Self> {
match raw {
0x01 => Ok(RedirectionDetail::TargetRedirected),
other => Err(anyhow!("unknown Redirection detail code: {:#02x}", other)),
}
}
}
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum InitiatorErrorDetail {
InitiatorError = 0x00,
AuthFailed = 0x01,
AuthzFailed = 0x02,
NotFound = 0x03,
TargetRemoved = 0x04,
UnsupportedVersion = 0x05,
TooManyConnections = 0x06,
MissingParameter = 0x07,
CantIncludeInSession = 0x08,
SessionTypeNotSupported = 0x09,
SessionDoesNotExist = 0x0a,
InvalidDuringLogin = 0x0b,
Reserved(u8),
}
impl TryFrom<u8> for InitiatorErrorDetail {
type Error = anyhow::Error;
fn try_from(byte: u8) -> Result<Self> {
match byte {
0x00 => Ok(InitiatorErrorDetail::InitiatorError),
0x01 => Ok(InitiatorErrorDetail::AuthFailed),
0x02 => Ok(InitiatorErrorDetail::AuthzFailed),
0x03 => Ok(InitiatorErrorDetail::NotFound),
0x04 => Ok(InitiatorErrorDetail::TargetRemoved),
0x05 => Ok(InitiatorErrorDetail::UnsupportedVersion),
0x06 => Ok(InitiatorErrorDetail::TooManyConnections),
0x07 => Ok(InitiatorErrorDetail::MissingParameter),
0x08 => Ok(InitiatorErrorDetail::CantIncludeInSession),
0x09 => Ok(InitiatorErrorDetail::SessionTypeNotSupported),
0x0a => Ok(InitiatorErrorDetail::SessionDoesNotExist),
0x0b => Ok(InitiatorErrorDetail::InvalidDuringLogin),
other => Err(anyhow!("unknown InitiatorErrorDetail: 0x{:02x}", other)),
}
}
}
#[repr(u8)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum TargetErrorDetail {
TargetBusy = 0x00,
TargetProtectedAreaBusy = 0x01,
TargetResourceUnavailable = 0x02,
TargetInternalError = 0x03,
VendorSpecific(u8),
Reserved(u8),
}
impl TryFrom<u8> for TargetErrorDetail {
type Error = anyhow::Error;
fn try_from(raw: u8) -> Result<Self, Self::Error> {
let detail = match raw {
0x00 => TargetErrorDetail::TargetBusy,
0x01 => TargetErrorDetail::TargetProtectedAreaBusy,
0x02 => TargetErrorDetail::TargetResourceUnavailable,
0x03 => TargetErrorDetail::TargetInternalError,
0x04..=0xFE => TargetErrorDetail::VendorSpecific(raw),
0xFF => TargetErrorDetail::Reserved(raw),
};
Ok(detail)
}
}
impl TryFrom<(StatusClass, u8)> for StatusDetail {
type Error = anyhow::Error;
fn try_from((class, raw): (StatusClass, u8)) -> Result<Self> {
Ok(match class {
StatusClass::Success => StatusDetail::Success(SuccessDetail::try_from(raw)?),
StatusClass::Redirection => {
StatusDetail::Redirection(RedirectionDetail::try_from(raw)?)
},
StatusClass::InitiatorError => {
StatusDetail::InitiatorErr(InitiatorErrorDetail::try_from(raw)?)
},
StatusClass::TargetError => {
StatusDetail::TargetErr(TargetErrorDetail::try_from(raw)?)
},
_ => bail!("invalid class"),
})
}
}
impl From<InitiatorErrorDetail> for u8 {
fn from(detail: InitiatorErrorDetail) -> Self {
match detail {
InitiatorErrorDetail::InitiatorError => 0x00,
InitiatorErrorDetail::AuthFailed => 0x01,
InitiatorErrorDetail::AuthzFailed => 0x02,
InitiatorErrorDetail::NotFound => 0x03,
InitiatorErrorDetail::TargetRemoved => 0x04,
InitiatorErrorDetail::UnsupportedVersion => 0x05,
InitiatorErrorDetail::TooManyConnections => 0x06,
InitiatorErrorDetail::MissingParameter => 0x07,
InitiatorErrorDetail::CantIncludeInSession => 0x08,
InitiatorErrorDetail::SessionTypeNotSupported => 0x09,
InitiatorErrorDetail::SessionDoesNotExist => 0x0A,
InitiatorErrorDetail::InvalidDuringLogin => 0x0B,
InitiatorErrorDetail::Reserved(v) => v,
}
}
}
impl From<TargetErrorDetail> for u8 {
fn from(detail: TargetErrorDetail) -> Self {
match detail {
TargetErrorDetail::TargetBusy => 0x00,
TargetErrorDetail::TargetProtectedAreaBusy => 0x01,
TargetErrorDetail::TargetResourceUnavailable => 0x02,
TargetErrorDetail::TargetInternalError => 0x03,
TargetErrorDetail::VendorSpecific(v) => v,
TargetErrorDetail::Reserved(v) => v,
}
}
}
impl From<StatusDetail> for u8 {
fn from(detail: StatusDetail) -> Self {
match detail {
StatusDetail::Success(inner) => inner as u8,
StatusDetail::Redirection(inner) => inner as u8,
StatusDetail::InitiatorErr(inner) => inner.into(),
StatusDetail::TargetErr(inner) => inner.into(),
}
}
}