Make the usb scsi scheme able to do block I/O.

This commit is contained in:
4lDO2
2020-02-15 00:26:19 +01:00
parent d44296dec9
commit bd0892e45d
13 changed files with 1104 additions and 323 deletions
+101 -30
View File
@@ -1,7 +1,11 @@
use std::num::NonZeroU32;
use std::slice;
use xhcid_interface::{ConfDesc, DeviceReqData, EndpBinaryDirection, EndpDirection, EndpointStatus, IfDesc, Invalid, PortReqTy, PortReqRecipient, PortTransferStatus, XhciClientHandle, XhciClientHandleError, XhciEndpHandle};
use xhcid_interface::{
ConfDesc, DeviceReqData, EndpBinaryDirection, EndpDirection, EndpointStatus, IfDesc, Invalid,
PortReqRecipient, PortReqTy, PortTransferStatus, XhciClientHandle, XhciClientHandleError,
XhciEndpHandle,
};
use super::{Protocol, ProtocolError, SendCommandStatus, SendCommandStatusKind};
@@ -18,12 +22,18 @@ pub struct CommandBlockWrapper {
pub tag: u32,
pub data_transfer_len: u32,
pub flags: u8, // upper nibble reserved
pub lun: u8, // bits 7:5 reserved
pub lun: u8, // bits 7:5 reserved
pub cb_len: u8,
pub command_block: [u8; 16],
}
impl CommandBlockWrapper {
pub fn new(tag: u32, data_transfer_len: u32, direction: EndpBinaryDirection, lun: u8, cb: &[u8]) -> Result<Self, ProtocolError> {
pub fn new(
tag: u32,
data_transfer_len: u32,
direction: EndpBinaryDirection,
lun: u8,
cb: &[u8],
) -> Result<Self, ProtocolError> {
let mut command_block = [0u8; 16];
if cb.len() > 16 {
return Err(ProtocolError::TooLargeCommandBlock(cb.len()));
@@ -86,11 +96,23 @@ pub struct BulkOnlyTransport<'a> {
pub const FEATURE_ENDPOINT_HALT: u16 = 0;
impl<'a> BulkOnlyTransport<'a> {
pub fn init(handle: &'a XhciClientHandle, config_desc: &ConfDesc, if_desc: &IfDesc) -> Result<Self, ProtocolError> {
pub fn init(
handle: &'a XhciClientHandle,
config_desc: &ConfDesc,
if_desc: &IfDesc,
) -> Result<Self, ProtocolError> {
let endpoints = &if_desc.endpoints;
let bulk_in_num = (endpoints.iter().position(|endpoint| endpoint.direction() == EndpDirection::In).unwrap() + 1) as u8;
let bulk_out_num = (endpoints.iter().position(|endpoint| endpoint.direction() == EndpDirection::Out).unwrap() + 1) as u8;
let bulk_in_num = (endpoints
.iter()
.position(|endpoint| endpoint.direction() == EndpDirection::In)
.unwrap()
+ 1) as u8;
let bulk_out_num = (endpoints
.iter()
.position(|endpoint| endpoint.direction() == EndpDirection::Out)
.unwrap()
+ 1) as u8;
let max_lun = get_max_lun(handle, 0)?;
println!("BOT_MAX_LUN {}", max_lun);
@@ -108,26 +130,40 @@ impl<'a> BulkOnlyTransport<'a> {
}
fn clear_stall_in(&mut self) -> Result<(), XhciClientHandleError> {
self.bulk_in.reset(false)?;
self.handle.clear_feature(PortReqRecipient::Endpoint, u16::from(self.bulk_in_num), FEATURE_ENDPOINT_HALT)
self.handle.clear_feature(
PortReqRecipient::Endpoint,
u16::from(self.bulk_in_num),
FEATURE_ENDPOINT_HALT,
)
}
fn clear_stall_out(&mut self) -> Result<(), XhciClientHandleError> {
self.bulk_out.reset(false)?;
self.handle.clear_feature(PortReqRecipient::Endpoint, u16::from(self.bulk_out_num), FEATURE_ENDPOINT_HALT)
self.handle.clear_feature(
PortReqRecipient::Endpoint,
u16::from(self.bulk_out_num),
FEATURE_ENDPOINT_HALT,
)
}
fn reset_recovery(&mut self) -> Result<(), ProtocolError> {
bulk_only_mass_storage_reset(self.handle, self.interface_num.into())?;
self.clear_stall_in()?;
self.clear_stall_out()?;
if self.bulk_in.status()? == EndpointStatus::Halted || self.bulk_out.status()? == EndpointStatus::Halted {
return Err(ProtocolError::RecoveryFailed)
if self.bulk_in.status()? == EndpointStatus::Halted
|| self.bulk_out.status()? == EndpointStatus::Halted
{
return Err(ProtocolError::RecoveryFailed);
}
Ok(())
}
}
impl<'a> Protocol for BulkOnlyTransport<'a> {
fn send_command(&mut self, cb: &[u8], data: DeviceReqData) -> Result<SendCommandStatus, ProtocolError> {
fn send_command(
&mut self,
cb: &[u8],
data: DeviceReqData,
) -> Result<SendCommandStatus, ProtocolError> {
self.current_tag += 1;
let tag = self.current_tag;
@@ -160,26 +196,38 @@ impl<'a> Protocol for BulkOnlyTransport<'a> {
DeviceReqData::In(buffer) => {
match self.bulk_in.transfer_read(buffer)? {
PortTransferStatus::Success => (),
PortTransferStatus::ShortPacket(len) => panic!("received short packed (len {}) when transferring data", len),
PortTransferStatus::ShortPacket(len) => {
panic!("received short packed (len {}) when transferring data", len)
}
PortTransferStatus::Stalled => {
println!("bulk in endpoint stalled when reading data");
self.clear_stall_in()?;
}
PortTransferStatus::Unknown => return Err(ProtocolError::XhciError(XhciClientHandleError::InvalidResponse(Invalid("unknown transfer status")))),
PortTransferStatus::Unknown => {
return Err(ProtocolError::XhciError(
XhciClientHandleError::InvalidResponse(Invalid(
"unknown transfer status",
)),
))
}
};
println!("{}", base64::encode(&buffer[..]));
}
DeviceReqData::Out(buffer) => {
match self.bulk_out.transfer_write(buffer)? {
PortTransferStatus::Success => (),
PortTransferStatus::ShortPacket(len) => panic!("received short packed (len {}) when transferring data", len),
PortTransferStatus::Stalled => {
println!("bulk out endpoint stalled when reading data");
self.clear_stall_out()?;
}
PortTransferStatus::Unknown => return Err(ProtocolError::XhciError(XhciClientHandleError::InvalidResponse(Invalid("unknown transfer status")))),
DeviceReqData::Out(buffer) => match self.bulk_out.transfer_write(buffer)? {
PortTransferStatus::Success => (),
PortTransferStatus::ShortPacket(len) => {
panic!("received short packed (len {}) when transferring data", len)
}
}
PortTransferStatus::Stalled => {
println!("bulk out endpoint stalled when reading data");
self.clear_stall_out()?;
}
PortTransferStatus::Unknown => {
return Err(ProtocolError::XhciError(
XhciClientHandleError::InvalidResponse(Invalid("unknown transfer status")),
))
}
},
DeviceReqData::NoData => (),
}
@@ -190,18 +238,22 @@ impl<'a> Protocol for BulkOnlyTransport<'a> {
println!("bulk in endpoint stalled when reading CSW");
self.clear_stall_in()?;
}
PortTransferStatus::ShortPacket(n) if n != 13 => panic!("received a short packet when reading CSW ({} != 13)", n),
PortTransferStatus::ShortPacket(n) if n != 13 => {
panic!("received a short packet when reading CSW ({} != 13)", n)
}
_ => (),
};
println!("{}", base64::encode(&csw_buffer));
let csw = plain::from_bytes::<CommandStatusWrapper>(&csw_buffer).unwrap();
dbg!(csw);
if !csw.is_valid() || csw.tag != cbw.tag {
self.reset_recovery()?;
}
dbg!(csw);
if self.bulk_in.status()? == EndpointStatus::Halted || self.bulk_out.status()? == EndpointStatus::Halted {
if self.bulk_in.status()? == EndpointStatus::Halted
|| self.bulk_out.status()? == EndpointStatus::Halted
{
println!("Trying to recover from stall");
dbg!(self.bulk_in.status()?, self.bulk_out.status()?);
}
@@ -212,19 +264,38 @@ impl<'a> Protocol for BulkOnlyTransport<'a> {
} else if csw.status == CswStatus::Failed as u8 {
SendCommandStatusKind::Failed
} else {
return Err(ProtocolError::ProtocolError("bulk-only transport phase error, or other"));
return Err(ProtocolError::ProtocolError(
"bulk-only transport phase error, or other",
));
},
residue: NonZeroU32::new(csw.data_residue),
})
}
}
pub fn bulk_only_mass_storage_reset(handle: &XhciClientHandle, if_num: u16) -> Result<(), XhciClientHandleError> {
handle.device_request(PortReqTy::Class, PortReqRecipient::Interface, 0xFF, 0, if_num, DeviceReqData::NoData)
pub fn bulk_only_mass_storage_reset(
handle: &XhciClientHandle,
if_num: u16,
) -> Result<(), XhciClientHandleError> {
handle.device_request(
PortReqTy::Class,
PortReqRecipient::Interface,
0xFF,
0,
if_num,
DeviceReqData::NoData,
)
}
pub fn get_max_lun(handle: &XhciClientHandle, if_num: u16) -> Result<u8, XhciClientHandleError> {
let mut lun = 0u8;
let buffer = slice::from_mut(&mut lun);
handle.device_request(PortReqTy::Class, PortReqRecipient::Interface, 0xFE, 0, if_num, DeviceReqData::In(buffer))?;
handle.device_request(
PortReqTy::Class,
PortReqRecipient::Interface,
0xFE,
0,
if_num,
DeviceReqData::In(buffer),
)?;
Ok(lun)
}
+18 -5
View File
@@ -2,7 +2,9 @@ use std::io;
use std::num::NonZeroU32;
use thiserror::Error;
use xhcid_interface::{DeviceReqData, DevDesc, ConfDesc, IfDesc, XhciClientHandle, XhciClientHandleError};
use xhcid_interface::{
ConfDesc, DevDesc, DeviceReqData, IfDesc, XhciClientHandle, XhciClientHandleError,
};
#[derive(Debug, Error)]
pub enum ProtocolError {
@@ -40,7 +42,6 @@ pub enum SendCommandStatusKind {
Failed,
}
impl Default for SendCommandStatusKind {
fn default() -> Self {
Self::Success
@@ -48,7 +49,11 @@ impl Default for SendCommandStatusKind {
}
pub trait Protocol {
fn send_command(&mut self, command: &[u8], data: DeviceReqData) -> Result<SendCommandStatus, ProtocolError>;
fn send_command(
&mut self,
command: &[u8],
data: DeviceReqData,
) -> Result<SendCommandStatus, ProtocolError>;
}
/// Bulk-only transport
@@ -60,9 +65,17 @@ mod uas {
use bot::BulkOnlyTransport;
pub fn setup<'a>(handle: &'a XhciClientHandle, protocol: u8, dev_desc: &DevDesc, conf_desc: &ConfDesc, if_desc: &IfDesc) -> Option<Box<dyn Protocol + 'a>> {
pub fn setup<'a>(
handle: &'a XhciClientHandle,
protocol: u8,
dev_desc: &DevDesc,
conf_desc: &ConfDesc,
if_desc: &IfDesc,
) -> Option<Box<dyn Protocol + 'a>> {
match protocol {
0x50 => Some(Box::new(BulkOnlyTransport::init(handle, conf_desc, if_desc).unwrap())),
0x50 => Some(Box::new(
BulkOnlyTransport::init(handle, conf_desc, if_desc).unwrap(),
)),
_ => None,
}
}