Almost successfully read blocks using SCSI.

This commit is contained in:
4lDO2
2020-02-14 18:38:24 +01:00
parent 034e6bce70
commit d44296dec9
9 changed files with 585 additions and 596 deletions
+4 -1
View File
@@ -64,7 +64,10 @@ fn main() {
//syscall::setrens(0, 0).expect("scsid: failed to enter null namespace");
let mut scsi = Scsi::new(&mut *protocol);
let mut scsi_scheme = ScsiScheme::new(&mut scsi);
let mut buffer = [0u8; 512];
scsi.read(&mut *protocol, 0, &mut buffer).unwrap();
println!("DISK CONTENT: {}", base64::encode(&buffer[..]));
let mut scsi_scheme = ScsiScheme::new(&mut scsi, &mut *protocol);
// TODO: Use nonblocking and put all pending calls in a todo VecDeque. Use an eventfd as well.
'scheme_loop: loop {
+10 -7
View File
@@ -3,7 +3,7 @@ use std::slice;
use xhcid_interface::{ConfDesc, DeviceReqData, EndpBinaryDirection, EndpDirection, EndpointStatus, IfDesc, Invalid, PortReqTy, PortReqRecipient, PortTransferStatus, XhciClientHandle, XhciClientHandleError, XhciEndpHandle};
use super::{Protocol, ProtocolError, SendCommandStatus};
use super::{Protocol, ProtocolError, SendCommandStatus, SendCommandStatusKind};
pub const CBW_SIGNATURE: u32 = 0x43425355;
@@ -206,12 +206,15 @@ impl<'a> Protocol for BulkOnlyTransport<'a> {
dbg!(self.bulk_in.status()?, self.bulk_out.status()?);
}
Ok(if csw.status == CswStatus::Passed as u8 {
SendCommandStatus::Success
} else if csw.status == CswStatus::Failed as u8 {
SendCommandStatus::Failed { residue: NonZeroU32::new(csw.data_residue) }
} else {
return Err(ProtocolError::ProtocolError("bulk-only transport phase error, or other"));
Ok(SendCommandStatus {
kind: if csw.status == CswStatus::Passed as u8 {
SendCommandStatusKind::Success
} else if csw.status == CswStatus::Failed as u8 {
SendCommandStatusKind::Failed
} else {
return Err(ProtocolError::ProtocolError("bulk-only transport phase error, or other"));
},
residue: NonZeroU32::new(csw.data_residue),
})
}
}
+19 -5
View File
@@ -22,12 +22,26 @@ pub enum ProtocolError {
ProtocolError(&'static str),
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum SendCommandStatus {
Success,
Failed { residue: Option<NonZeroU32> },
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
pub struct SendCommandStatus {
pub residue: Option<NonZeroU32>,
pub kind: SendCommandStatusKind,
}
impl Default for SendCommandStatus {
impl SendCommandStatus {
pub fn bytes_transferred(&self, transfer_len: u32) -> u32 {
transfer_len - self.residue.map(u32::from).unwrap_or(0)
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum SendCommandStatusKind {
Success,
Failed,
}
impl Default for SendCommandStatusKind {
fn default() -> Self {
Self::Success
}
+51 -8
View File
@@ -1,16 +1,18 @@
use std::collections::BTreeMap;
use std::str;
use std::{cmp, str};
use crate::protocol::Protocol;
use crate::scsi::Scsi;
use syscall::SchemeMut;
use syscall::error::{Error, Result};
use syscall::error::{EACCES, EBADF, ENOENT, ENOSYS};
use syscall::error::{EACCES, EBADF, EINVAL, EIO, ENOENT, ENOSYS};
use syscall::flag::{O_DIRECTORY, O_STAT};
use syscall::flag::{MODE_CHR, MODE_DIR};
use syscall::flag::{SEEK_CUR, SEEK_END, SEEK_SET};
// TODO: Only one disk, right?
const LIST_CONTENTS: &'static [u8] = b"disk\n";
const LIST_CONTENTS: &'static [u8] = b"0\n";
enum Handle {
List(usize),
@@ -20,14 +22,16 @@ enum Handle {
pub struct ScsiScheme<'a> {
scsi: &'a mut Scsi,
protocol: &'a mut Protocol,
handles: BTreeMap<usize, Handle>,
next_fd: usize,
}
impl<'a> ScsiScheme<'a> {
pub fn new(scsi: &'a mut Scsi) -> Self {
pub fn new(scsi: &'a mut Scsi, protocol: &'a mut dyn Protocol) -> Self {
Self {
scsi,
protocol,
handles: BTreeMap::new(),
next_fd: 0,
}
@@ -58,12 +62,12 @@ impl<'a> SchemeMut for ScsiScheme<'a> {
Handle::Disk(_) => {
stat.st_mode = MODE_CHR;
stat.st_size = self.scsi.get_disk_size();
// TODO: stat.st_blocks
stat.st_blksize = self.scsi.block_size;
stat.st_blocks = self.scsi.block_count;
}
Handle::List(_) => {
stat.st_mode = MODE_DIR;
stat.st_size = LIST_CONTENTS.len() as u64;
// TODO: stat.st_blocks
}
}
Err(Error::new(ENOSYS))
@@ -72,10 +76,49 @@ impl<'a> SchemeMut for ScsiScheme<'a> {
Err(Error::new(ENOSYS))
}
fn seek(&mut self, fd: usize, pos: usize, whence: usize) -> Result<usize> {
Err(Error::new(ENOSYS))
match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? {
Handle::Disk(ref mut offset) => {
let len = self.scsi.get_disk_size() as usize;
*offset = match whence {
SEEK_SET => cmp::max(0, cmp::min(pos, len)),
SEEK_CUR => cmp::max(0, cmp::min(*offset + pos, len)),
SEEK_END => cmp::max(0, cmp::min(len + pos, len)),
_ => return Err(Error::new(EINVAL)),
};
Ok(*offset)
}
Handle::List(ref mut offset) => {
let len = LIST_CONTENTS.len();
*offset = match whence {
SEEK_SET => cmp::max(0, cmp::min(pos, len)),
SEEK_CUR => cmp::max(0, cmp::min(*offset + pos, len)),
SEEK_END => cmp::max(0, cmp::min(len + pos, len)),
_ => return Err(Error::new(EINVAL)),
};
Ok(*offset)
}
}
}
fn read(&mut self, fd: usize, buf: &mut [u8]) -> Result<usize> {
Err(Error::new(ENOSYS))
match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? {
Handle::Disk(ref mut offset) => {
if *offset as u64 % u64::from(self.scsi.block_size) != 0 || buf.len() as u64 % u64::from(self.scsi.block_size) != 0 {
return Err(Error::new(EINVAL));
}
let lba = *offset as u64 / u64::from(self.scsi.block_size);
let bytes_read = self.scsi.read(self.protocol, lba, buf).map_err(|err| dbg!(err)).or(Err(Error::new(EIO)))?;
Ok(bytes_read as usize)
}
Handle::List(ref mut offset) => {
let max_bytes_to_read = cmp::min(LIST_CONTENTS.len(), buf.len());
let bytes_to_read = cmp::max(max_bytes_to_read, *offset) - *offset;
buf[..bytes_to_read].copy_from_slice(&LIST_CONTENTS[..bytes_to_read]);
*offset += bytes_to_read;
Ok(bytes_to_read)
}
}
}
fn write(&mut self, fd: usize, buf: &[u8]) -> Result<usize> {
Err(Error::new(ENOSYS))
+148 -201
View File
@@ -1,187 +1,5 @@
use std::{fmt, mem, slice};
use super::opcodes::{Opcode, ServiceActionA3};
#[repr(packed)]
pub struct ReportIdentInfo {
pub opcode: u8,
/// bits 7:5 reserved
pub serviceaction: u8,
pub _rsvd: u16,
pub restricted: u16,
/// little endian
pub alloc_len: u32,
/// bit 0 reserved
pub info_ty: u8,
pub control: u8,
}
unsafe impl plain::Plain for ReportIdentInfo {}
impl ReportIdentInfo {
pub const fn new(alloc_len: u32, info_ty: ReportIdInfoInfoTy, control: u8) -> Self {
Self {
opcode: Opcode::ServiceActionA3 as u8,
serviceaction: ServiceActionA3::ReportIdentInfo as u8,
_rsvd: 0,
restricted: 0,
alloc_len: u32::to_le(alloc_len),
info_ty: (info_ty as u8) << REP_ID_INFO_INFO_TY_SHIFT,
control,
}
}
}
#[repr(u8)]
pub enum ReportIdInfoInfoTy {
PeripheralDevIdInfo = 0b000_0000,
PeripheralDevTextIdInfo = 0b000_0010,
IdentInfoSupp = 0b111_1111,
// every other number ending with a 1 is restricted
}
pub const REP_ID_INFO_INFO_TY_MASK: u8 = 0xFE;
pub const REP_ID_INFO_INFO_TY_SHIFT: u8 = 1;
#[repr(packed)]
pub struct ReportSuppOpcodes {
pub opcode: u8,
/// bits 7:5 reserved
pub serviceaction: u8,
/// bits 2:0 represent "REPORTING OPTIONS", bits 6:3 are reserved, and bit 7 is RCTD
pub rep_opts: u8,
pub req_opcode: u8,
/// little endian
pub req_serviceaction: u16,
/// little endian
pub alloc_len: u32,
pub _rsvd: u8,
pub control: u8,
}
unsafe impl plain::Plain for ReportSuppOpcodes {}
impl ReportSuppOpcodes {
pub const fn new(rep_opts: ReportSuppOpcodesOptions, rctd: bool, req_opcode: u8, req_serviceaction: u16, alloc_len: u32, control: u8) -> Self {
Self {
opcode: Opcode::ServiceActionA3 as u8,
serviceaction: ServiceActionA3::ReportSuppOpcodes as u8,
rep_opts: ((rctd as u8) << REP_OPTS_RCTD_SHIFT) | rep_opts as u8,
req_opcode,
req_serviceaction: u16::to_le(req_serviceaction),
alloc_len: u32::to_le(alloc_len),
_rsvd: 0,
control,
}
}
pub const fn get_all(rctd: bool, alloc_len: u32, control: u8) -> Self {
Self::new(ReportSuppOpcodesOptions::ListAll, rctd, 0, 0, alloc_len, control)
}
pub const fn get_supp_no_sa(rctd: bool, opcode: Opcode, alloc_len: u32, control: u8) -> Self {
Self::new(ReportSuppOpcodesOptions::NoServicaction, rctd, opcode as u8, 0, alloc_len, control)
}
pub const fn get_supp(rctd: bool, opcode: Opcode, serviceaction: u16, alloc_len: u32, control: u8) -> Self {
Self::new(ReportSuppOpcodesOptions::ExplicitBoth, rctd, opcode as u8, serviceaction, alloc_len, control)
}
}
pub const REP_OPTS_MAIN_MASK: u8 = 0b0000_0111;
pub const REP_OPTS_MAIN_SHIFT: u8 = 0;
pub const REP_OPTS_RCTD_BIT: u8 = 1 << REP_OPTS_RCTD_SHIFT;
pub const REP_OPTS_RCTD_SHIFT: u8 = 7;
/// Valid values of the `req_opts` field of `ReportSuppOpcodes`.
#[repr(u8)]
pub enum ReportSuppOpcodesOptions {
/// Returns all commands, no matter what parameters are set.
ListAll,
/// Returns one command with the requested opcode. If the command has service actions, this
/// command fails.
NoServicaction,
/// Returns one command with the requested opcode and service action. If the command doesn't
/// support service actions, this command fails.
ExplicitBoth,
/// Returns one command with the requested opcode and service action. The command may or may
/// not implement service actions, but if it does, it has to be correct for the return value to
/// indicate SUPPORTED.
///
/// This option seems to be reserved for SPC-3 (inquiry version value of 5).
IndicateSupport,
}
#[repr(packed)]
pub struct AllCommandsParam {
/// Little endian
pub data_len: u32,
pub descs: [CommandDescriptor; 0],
}
impl AllCommandsParam {
pub const fn alloc_len(&self) -> u32 {
3 + u32::from_le(self.data_len)
}
pub unsafe fn descs(&self) -> &[CommandDescriptor] {
assert_eq!(mem::size_of::<CommandDescriptor>(), 20);
slice::from_raw_parts(&self.descs as *const CommandDescriptor, (self.alloc_len() as usize - 4) / mem::size_of::<CommandDescriptor>())
}
}
unsafe impl plain::Plain for AllCommandsParam {}
#[repr(packed)]
#[derive(Clone, Copy, Debug)]
pub struct CommandDescriptor {
pub opcode: u8,
pub _rsvd1: u8,
/// little endian
pub serviceaction: u16,
pub _rsvd2: u8,
/// bit 0 is SERVACTV, bit 1 is CTDP, and bits 7:2 reserved
pub a: u8,
/// little endian
pub cdb_len: u16,
pub cmd_timeouts_desc: [u8; 12],
}
#[repr(packed)]
pub struct OneCommandParam {
pub _rsvd: u8,
pub a: u8,
pub cdb_size: u16,
pub usage_data: [u8; 0],
}
unsafe impl plain::Plain for OneCommandParam {}
impl OneCommandParam {
pub const fn ctdp(&self) -> bool {
self.a & (1 << 7) != 0
}
pub fn support(&self) -> OneCommandParamSupport {
let raw = self.a & 0b111;
// Safe because all possible values are covered by the enum.
unsafe { mem::transmute(raw) }
}
pub const fn total_len(&self) -> u16 {
self.cdb_size as u16 + 3
}
/// Unsafe because the reference to self has to be valid for an additional (self.cdb_size - 1) bytes.
pub unsafe fn cdb_usage_data(&self) -> &[u8] {
slice::from_raw_parts(&self.usage_data as *const u8, self.total_len() as usize - 4)
}
}
#[repr(u8)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum OneCommandParamSupport {
NoDataAvail = 0b000,
NotSupported = 0b001,
Rsvd2 = 0b010,
Supported = 0b011,
Rsvd4 = 0b100,
SupportedVendor = 0b101,
Rsvd6 = 0b110,
Rsvd7 = 0b111,
}
use super::opcodes::Opcode;
#[repr(packed)]
pub struct Inquiry {
@@ -189,7 +7,7 @@ pub struct Inquiry {
/// bits 7:2 are reserved, bit 1 (CMDDT) is obsolete, bit 0 is EVPD
pub evpd: u8,
pub page_code: u8,
/// little endian
/// big endian
pub alloc_len: u16,
pub control: u8,
}
@@ -201,7 +19,7 @@ impl Inquiry {
opcode: Opcode::Inquiry as u8,
evpd: evpd as u8,
page_code,
alloc_len: u16::to_le(alloc_len),
alloc_len: u16::to_be(alloc_len),
control,
}
}
@@ -231,6 +49,33 @@ pub struct StandardInquiryData {
_rsvd2: [u8; 22],
}
unsafe impl plain::Plain for StandardInquiryData {}
impl StandardInquiryData {
pub const fn periph_dev_ty(&self) -> u8 {
self.a & 0x1F
}
pub const fn periph_dev_qual(&self) -> u8 {
(self.a & 0xE0) >> 5
}
pub const fn version(&self) -> u8 {
self.version
}
}
#[repr(u8)]
pub enum PeriphDeviceType {
DirectAccess,
SeqAccess,
// there are more
}
#[repr(u8)]
pub enum InquiryVersion {
NoConformance,
Spc,
Spc2,
Spc3,
Spc4,
Spc5,
}
#[repr(packed)]
#[derive(Clone, Copy, Debug)]
@@ -269,7 +114,7 @@ pub struct FixedFormatSenseData {
pub add_sense_code: u8,
pub add_sense_code_qual: u8,
pub field_replacable_unit_code: u8,
pub sense_key_specific: [u8; 3], // little endian
pub sense_key_specific: [u8; 3], // big endian
pub add_sense_bytes: [u8; 0],
}
unsafe impl plain::Plain for FixedFormatSenseData {}
@@ -326,6 +171,7 @@ pub struct Read16 {
pub b: u8,
pub control: u8,
}
unsafe impl plain::Plain for Read16 {}
impl Read16 {
pub const fn new(lba: u64, transfer_len: u32, control: u8) -> Self {
@@ -335,8 +181,8 @@ impl Read16 {
Self {
opcode: Opcode::Read16 as u8,
a: 0,
lba: u64::to_le(lba),
transfer_len: u32::to_le(transfer_len),
lba: u64::to_be(lba),
transfer_len: u32::to_be(transfer_len),
b: 0,
control,
}
@@ -389,7 +235,7 @@ impl ModeSense10 {
b: page_code | ((pc as u8) << 6),
subpage_code,
_rsvd: [0u8; 3],
alloc_len: u16::from_le(alloc_len),
alloc_len: u16::from_be(alloc_len),
control,
}
}
@@ -407,7 +253,7 @@ pub enum ModePageControl {
}
#[repr(packed)]
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy)]
pub struct ShortLbaModeParamBlkDesc {
pub block_count: u32,
_rsvd: u8,
@@ -417,21 +263,28 @@ unsafe impl plain::Plain for ShortLbaModeParamBlkDesc {}
impl ShortLbaModeParamBlkDesc {
pub const fn block_count(&self) -> u32 {
u32::from_le(self.block_count)
u32::from_be(self.block_count)
}
pub const fn logical_block_len(&self) -> u32 {
u24_le_to_u32(self.logical_block_len)
u24_be_to_u32(self.logical_block_len)
}
}
impl fmt::Debug for ShortLbaModeParamBlkDesc {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("ShortLbaModeParamBlkDesc")
.field("block_count", &self.block_count())
.field("logical_block_len", &self.logical_block_len())
.finish()
}
}
const fn u24_le_to_u32(u24: [u8; 3]) -> u32 {
const fn u24_be_to_u32(u24: [u8; 3]) -> u32 {
((u24[0] as u32) << 16)
| ((u24[1] as u32) << 8)
| (u24[2] as u32)
}
/// From SPC-3, when LONGLBA is set. For newer devices, `ShortLbaModeParamBlkDesc` is used instead (I
/// think).
/// From SPC-3, when LONGLBA is not set, and the peripheral device type of the INQUIRY data indicates that the device is not a direct access device. Otherwise, `ShortLbaModeParamBlkDesc` is used instead.
#[repr(packed)]
#[derive(Clone, Copy)]
pub struct GeneralModeParamBlkDesc {
@@ -442,12 +295,21 @@ pub struct GeneralModeParamBlkDesc {
}
unsafe impl plain::Plain for GeneralModeParamBlkDesc {}
impl GeneralModeParamBlkDesc {
pub fn block_count(&self) -> u32 {
u24_be_to_u32(self.block_count)
}
pub fn logical_block_len(&self) -> u32 {
u24_be_to_u32(self.block_length)
}
}
impl fmt::Debug for GeneralModeParamBlkDesc {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("GeneralModeParamBlkDesc")
.field("density_code", &self.density_code)
.field("block_count", &u24_le_to_u32(self.block_count))
.field("block_length", &u24_le_to_u32(self.block_length))
.field("block_count", &u24_be_to_u32(self.block_count))
.field("block_length", &u24_be_to_u32(self.block_length))
.finish()
}
}
@@ -463,10 +325,10 @@ unsafe impl plain::Plain for LongLbaModeParamBlkDesc {}
impl LongLbaModeParamBlkDesc {
pub const fn block_count(&self) -> u64 {
u64::from_le(self.block_count)
u64::from_be(self.block_count)
}
pub const fn logical_block_len(&self) -> u32 {
u32::from_le(self.logical_block_len)
u32::from_be(self.logical_block_len)
}
}
@@ -493,12 +355,97 @@ pub struct ModeParamHeader10 {
unsafe impl plain::Plain for ModeParamHeader10 {}
impl ModeParamHeader10 {
pub const fn mode_data_len(&self) -> u16 {
u16::from_le(self.mode_data_len)
u16::from_be(self.mode_data_len)
}
pub const fn block_desc_len(&self) -> u16 {
u16::from_le(self.block_desc_len)
u16::from_be(self.block_desc_len)
}
pub const fn longlba(&self) -> bool {
(self.b & 0x01) != 0
}
}
#[repr(packed)]
#[derive(Clone, Copy, Debug)]
pub struct RwErrorRecoveryPage {
pub a: u8,
pub page_length: u8,
pub b: u8,
pub read_retry_count: u8,
_obsolete: [u8; 3],
_rsvd: u8,
pub recovery_time_limit: u16,
}
unsafe impl plain::Plain for RwErrorRecoveryPage {}
pub(crate) struct ModePageIterRaw<'a> {
buffer: &'a [u8],
}
impl<'a> Iterator for ModePageIterRaw<'a> {
type Item = &'a [u8];
fn next(&mut self) -> Option<Self::Item> {
if self.buffer.len() < 2 {
return None;
}
let a = self.buffer[0];
let page_len = if a & (1 << 6) == 0 {
// item is page_0 mode
self.buffer[1] as usize + 1
} else {
// item is sub_page mode
self.buffer[2] as usize + 3
};
if self.buffer.len() < page_len {
return None;
}
let buffer = &self.buffer[..page_len];
self.buffer = if page_len == self.buffer.len() {
&[]
} else {
&self.buffer[page_len..]
};
Some(buffer)
}
}
#[derive(Clone, Copy, Debug)]
pub enum AnyModePage<'a> {
RwErrorRecovery(&'a RwErrorRecoveryPage),
}
struct ModePageIter<'a> {
raw: ModePageIterRaw<'a>,
}
impl<'a> Iterator for ModePageIter<'a> {
type Item = AnyModePage<'a>;
fn next(&mut self) -> Option<Self::Item> {
let next_buf = self.raw.next()?;
let a = next_buf[0];
let page_code = a & 0x1F;
let spf = a & (1 << 6) != 0;
if !spf {
if page_code == 0x01 {
Some(AnyModePage::RwErrorRecovery(plain::from_bytes(next_buf).ok()?))
} else {
println!("Unimplemented sub_page {}", base64::encode(next_buf));
None
}
} else {
println!("Unimplemented page_0 {}", base64::encode(next_buf));
None
}
}
}
pub fn mode_page_iter(buffer: &[u8]) -> impl Iterator<Item = AnyModePage> {
ModePageIter { raw: ModePageIterRaw { buffer } }
}
+79 -55
View File
@@ -1,4 +1,5 @@
use std::mem;
use std::{mem, ops};
use std::convert::TryFrom;
pub mod cmds;
pub mod opcodes;
@@ -6,7 +7,7 @@ pub mod opcodes;
use thiserror::Error;
use xhcid_interface::DeviceReqData;
use crate::protocol::{Protocol, ProtocolError, SendCommandStatus};
use crate::protocol::{Protocol, ProtocolError, SendCommandStatus, SendCommandStatusKind};
use cmds::{SenseKey, StandardInquiryData};
use opcodes::Opcode;
@@ -14,6 +15,8 @@ pub struct Scsi {
command_buffer: [u8; 16],
inquiry_buffer: [u8; 259],
data_buffer: Vec<u8>,
pub block_size: u32,
pub block_count: u64,
}
const INQUIRY_CMD_LEN: u8 = 6;
@@ -35,6 +38,8 @@ impl Scsi {
command_buffer: [0u8; 16],
inquiry_buffer: [0u8; 259], // additional_len = 255 max
data_buffer: Vec::new(),
block_size: 0,
block_count: 0,
};
// Get the max length that the device supports, of the Standard Inquiry Data.
@@ -43,7 +48,16 @@ impl Scsi {
this.get_standard_inquiry_data(protocol, max_inquiry_len);
this.res_standard_inquiry_data();
dbg!(this.get_mode_sense10(protocol).unwrap());
let (block_size, block_count) = {
let (_, blkdescs, mode_page_iter) = this.get_mode_sense10(protocol).unwrap();
// TODO: Can there be multiple disks at all?
let only_blkdesc = blkdescs.get(0).unwrap();
(only_blkdesc.block_size(), only_blkdesc.block_count())
};
this.block_size = block_size;
this.block_count = block_count;
this
}
@@ -58,51 +72,18 @@ impl Scsi {
protocol.send_command(&self.command_buffer[..INQUIRY_CMD_LEN as usize], DeviceReqData::In(&mut self.inquiry_buffer[..max_inquiry_len as usize])).expect("Failed to send INQUIRY command");
}
/*/// Similar to `check_supp_opcode_sized`, but simply checks whether the opcode is supported,
/// without fetching any actual data.
pub fn check_supp_opcode(&mut self, protocol: &mut dyn Protocol, opcode: Opcode, sa: Option<u16>) -> Result<bool, ScsiError> {
self.check_supp_opcode_sized(protocol, opcode, sa, 2)
}
pub fn check_supp_opcode_sized(&mut self, protocol: &mut dyn Protocol, opcode: Opcode, sa: Option<u16>, alloc_len: u32) -> Result<bool, ScsiError> {
let report_supp_opcodes = self.cmd_report_supp_opcodes();
*report_supp_opcodes = if let Some(serviceaction) = sa {
cmds::ReportSuppOpcodes::get_supp(false, opcode, serviceaction, alloc_len, 0)
} else {
cmds::ReportSuppOpcodes::get_supp_no_sa(false, opcode, alloc_len, 0)
};
self.data_buffer.resize(std::mem::size_of::<cmds::OneCommandParam>(), 0);
protocol.send_command(&self.command_buffer[..REPORT_SUPP_OPCODES_CMD_LEN as usize], DeviceReqData::In(&mut self.data_buffer[..alloc_len as usize]))?;
Ok(self.res_one_command().support() == cmds::OneCommandParamSupport::Supported)
}*/
/*pub fn get_supp_opcodes_alloc_len(&mut self, protocol: &mut dyn Protocol) -> u32 {
self.get_supp_opcodes(protocol, MIN_REPORT_SUPP_OPCODES_ALLOC_LEN);
self.res_all_commands().alloc_len()
}*/
/*pub fn get_supp_opcodes(&mut self, protocol: &mut dyn Protocol, alloc_len: u32) {
let report_supp_opcodes = self.cmd_report_supp_opcodes();
*report_supp_opcodes = cmds::ReportSuppOpcodes::get_all(false, alloc_len, 0);
self.data_buffer.resize(alloc_len as usize, 0);
let status = protocol.send_command(&self.command_buffer[..REPORT_SUPP_OPCODES_CMD_LEN as usize], DeviceReqData::In(&mut self.data_buffer[..alloc_len as usize])).expect("Failed to send REPORT_SUPP_OPCODES command");
if status != SendCommandStatus::Success {
self.get_ff_sense(protocol, cmds::RequestSense::MINIMAL_ALLOC_LEN);
let data = self.res_ff_sense_data();
if data.sense_key() == SenseKey::IllegalRequest && data.add_sense_code == cmds::ADD_SENSE_CODE05_INVAL_CDB_FIELD {
}
}
}*/
pub fn get_ff_sense(&mut self, protocol: &mut dyn Protocol, alloc_len: u8) {
let request_sense = self.cmd_request_sense();
*request_sense = cmds::RequestSense::new(false, alloc_len, 0);
self.data_buffer.resize(alloc_len.into(), 0);
protocol.send_command(&self.command_buffer[..REQUEST_SENSE_CMD_LEN as usize], DeviceReqData::In(&mut self.data_buffer[..alloc_len as usize])).expect("Failed to send REQUEST_SENSE command");
}
pub fn get_mode_sense10(&mut self, protocol: &mut dyn Protocol) -> Result<(&cmds::ModeParamHeader10, BlkDescSlice), ScsiError> {
pub fn get_mode_sense10(&mut self, protocol: &mut dyn Protocol) -> Result<(&cmds::ModeParamHeader10, BlkDescSlice, impl Iterator<Item = cmds::AnyModePage>), ScsiError> {
let initial_alloc_len = 4; // covers both mode_data_len and blk_desc_len.
let mode_sense10 = self.cmd_mode_sense10();
*mode_sense10 = cmds::ModeSense10::get_block_desc(initial_alloc_len, 0);
self.data_buffer.resize(mem::size_of::<cmds::ModeParamHeader10>(), 0);
if let SendCommandStatus::Failed { .. } = protocol.send_command(&self.command_buffer[..10], DeviceReqData::In(&mut self.data_buffer[..initial_alloc_len as usize]))? {
if let SendCommandStatus { kind: SendCommandStatusKind::Failed, .. } = protocol.send_command(&self.command_buffer[..10], DeviceReqData::In(&mut self.data_buffer[..initial_alloc_len as usize]))? {
self.get_ff_sense(protocol, 252);
panic!("{:?}", self.res_ff_sense_data());
}
@@ -113,7 +94,7 @@ impl Scsi {
*mode_sense10 = cmds::ModeSense10::get_block_desc(optimal_alloc_len, 0);
self.data_buffer.resize(optimal_alloc_len as usize, 0);
protocol.send_command(&self.command_buffer[..10], DeviceReqData::In(&mut self.data_buffer[..optimal_alloc_len as usize]))?;
Ok((self.res_mode_param_header10(), self.res_blkdesc_mode10()))
Ok((self.res_mode_param_header10(), self.res_blkdesc_mode10(), self.res_mode_pages10()))
}
pub fn cmd_inquiry(&mut self) -> &mut cmds::Inquiry {
@@ -125,22 +106,15 @@ impl Scsi {
pub fn cmd_mode_sense10(&mut self) -> &mut cmds::ModeSense10 {
plain::from_mut_bytes(&mut self.command_buffer).unwrap()
}
/*pub fn cmd_report_supp_opcodes(&mut self) -> &mut cmds::ReportSuppOpcodes {
plain::from_mut_bytes(&mut self.command_buffer).unwrap()
}*/
pub fn cmd_request_sense(&mut self) -> &mut cmds::RequestSense {
plain::from_mut_bytes(&mut self.command_buffer).unwrap()
}
pub fn cmd_read16(&mut self) -> &mut cmds::Read16 {
plain::from_mut_bytes(&mut self.command_buffer).unwrap()
}
pub fn res_standard_inquiry_data(&self) -> &StandardInquiryData {
plain::from_bytes(&self.inquiry_buffer).unwrap()
}
/*
pub fn res_all_commands(&self) -> &cmds::AllCommandsParam {
plain::from_bytes(&self.data_buffer).unwrap()
}
pub fn res_one_command(&self) -> &cmds::OneCommandParam {
plain::from_bytes(&self.data_buffer).unwrap()
}*/
pub fn res_ff_sense_data(&self) -> &cmds::FixedFormatSenseData {
plain::from_bytes(&self.data_buffer).unwrap()
}
@@ -158,21 +132,71 @@ impl Scsi {
pub fn res_blkdesc_mode10(&self) -> BlkDescSlice {
let header = self.res_mode_param_header10();
let descs_start = mem::size_of::<cmds::ModeParamHeader10>();
println!("MODE_SENSE PAGES: {}", base64::encode(&self.data_buffer[descs_start + header.block_desc_len() as usize..]));
if header.longlba() {
BlkDescSlice::Long(plain::slice_from_bytes(&self.data_buffer[descs_start..descs_start + usize::from(header.block_desc_len)]).unwrap())
BlkDescSlice::Long(plain::slice_from_bytes(&self.data_buffer[descs_start..descs_start + usize::from(header.block_desc_len())]).unwrap())
} else if self.res_standard_inquiry_data().periph_dev_ty() != cmds::PeriphDeviceType::DirectAccess as u8 && self.res_standard_inquiry_data().version() == cmds::InquiryVersion::Spc3 as u8 {
BlkDescSlice::General(plain::slice_from_bytes(&self.data_buffer[descs_start..descs_start + usize::from(header.block_desc_len())]).unwrap())
} else {
//BlkDescSlice::Short(plain::slice_from_bytes(&self.data_buffer[descs_start..descs_start + usize::from(header.block_desc_len)]).unwrap())
BlkDescSlice::General(plain::slice_from_bytes(&self.data_buffer[descs_start..descs_start + usize::from(header.block_desc_len)]).unwrap())
BlkDescSlice::Short(plain::slice_from_bytes(&self.data_buffer[descs_start..descs_start + usize::from(header.block_desc_len())]).unwrap())
}
}
pub fn res_mode_pages10(&self) -> impl Iterator<Item = cmds::AnyModePage> {
let header = self.res_mode_param_header10();
let descs_start = mem::size_of::<cmds::ModeParamHeader10>();
let buffer = &self.data_buffer[descs_start + header.block_desc_len() as usize..];
cmds::mode_page_iter(buffer)
}
pub fn get_disk_size(&mut self) -> u64 {
todo!()
self.block_count * u64::from(self.block_size)
}
pub fn read(&mut self, protocol: &mut dyn Protocol, lba: u64, buffer: &mut [u8]) -> Result<u32, ScsiError> {
let blocks_to_read = buffer.len() as u64 / u64::from(self.block_size);
let transfer_len = u32::try_from(blocks_to_read * u64::from(self.block_size)).ok().unwrap_or(std::u32::MAX);
{
let read = self.cmd_read16();
*read = cmds::Read16::new(lba, transfer_len, 0);
}
let status = protocol.send_command(&self.command_buffer[..16], DeviceReqData::In(&mut buffer[..transfer_len as usize]))?;
Ok(status.bytes_transferred(transfer_len))
}
}
#[derive(Debug)]
pub enum BlkDescSlice<'a> {
//Short(&'a [cmds::ShortLbaModeParamBlkDesc]),
Short(&'a [cmds::ShortLbaModeParamBlkDesc]),
General(&'a [cmds::GeneralModeParamBlkDesc]),
Long(&'a [cmds::LongLbaModeParamBlkDesc]),
}
#[derive(Debug)]
pub enum BlkDesc<'a> {
Short(&'a cmds::ShortLbaModeParamBlkDesc),
General(&'a cmds::GeneralModeParamBlkDesc),
Long(&'a cmds::LongLbaModeParamBlkDesc),
}
impl<'a> BlkDesc<'a> {
fn block_size(&self) -> u32 {
match self {
Self::Short(s) => s.logical_block_len(),
Self::General(g) => g.logical_block_len(),
Self::Long(l) => l.logical_block_len(),
}
}
fn block_count(&self) -> u64 {
match self {
Self::Short(s) => s.block_count().into(),
Self::General(g) => g.block_count().into(),
Self::Long(l) => l.block_count(),
}
}
}
impl<'a> BlkDescSlice<'a> {
fn get(&self, idx: usize) -> Option<BlkDesc<'a>> {
match self {
Self::Short(s) => s.get(idx).map(BlkDesc::Short),
Self::Long(l) => l.get(idx).map(BlkDesc::Long),
Self::General(g) => g.get(idx).map(BlkDesc::General),
}
}
}
+28 -64
View File
@@ -298,22 +298,15 @@ impl Xhci {
println!(" - XHCI initialized");
}
pub fn enable_port_slot(cmd: &mut CommandRing, dbs: &mut [Doorbell]) -> u8 {
let (cmd, cycle, event) = cmd.next();
pub fn enable_port_slot(&mut self, slot_ty: u8) -> Result<u8> {
assert_eq!(slot_ty & 0x1F, slot_ty);
cmd.enable_slot(0, cycle);
dbs[0].write(0);
while event.data.read() == 0 {
println!(" - Waiting for event");
}
let slot = (event.control.read() >> 24) as u8;
cmd.reserved(false);
event.reserved(false);
slot
let cloned_event_trb = self.execute_command("ENABLE_SLOT", |cmd, cycle| cmd.enable_slot(0, cycle))?;
Ok(cloned_event_trb.event_slot())
}
pub fn disable_port_slot(&mut self, slot: u8) -> Result<()> {
self.execute_command("DISABLE_SLOT", |cmd, cycle| cmd.enable_slot(0, cycle))?;
Ok(())
}
pub fn slot_state(&self, slot: usize) -> u8 {
@@ -336,14 +329,13 @@ impl Xhci {
println!(" - Enable slot");
self.run.ints[0].erdp.write(self.cmd.erdp());
let slot = Self::enable_port_slot(&mut self.cmd, &mut self.dbs);
let slot_ty = self.supported_protocol(i as u8).expect("Failed to find supported protocol information for port").proto_slot_ty();
let slot = self.enable_port_slot(slot_ty)?;
println!(" - Slot {}", slot);
let mut input = Dma::<InputContext>::zeroed()?;
let mut ring = self.address_device(&mut input, i, slot, speed)?;
let mut ring = self.address_device(&mut input, i, slot_ty, slot, speed)?;
let dev_desc = Self::get_dev_desc_raw(
&mut self.ports,
@@ -401,31 +393,14 @@ impl Xhci {
b &= 0x0000_FFFF;
b |= (new_max_packet_size) << 16;
endp_ctx.b.write(b);
{
let (cmd, cycle, event) = self.cmd.next();
cmd.evaluate_context(slot_id, input_context.physical(), false, cycle);
self.dbs[0].write(0);
while event.data.read() == 0 {
println!(" - Waiting for event");
}
if event.completion_code() != TrbCompletionCode::Success as u8
|| event.trb_type() != TrbType::CommandCompletion as u8
{
panic!("EVALUATE_CONTEXT failed with {:#0x} {:#0x} {:#0x}", event.data.read(), event.status.read(), event.control.read());
}
cmd.reserved(false);
event.reserved(false);
}
self.execute_command("EVALUATE_CONTEXT", |trb, cycle| {
trb.evaluate_context(slot_id, input_context.physical(), false, cycle)
})?;
Ok(())
}
pub fn address_device(&mut self, input_context: &mut Dma<InputContext>, i: usize, slot: u8, speed: u8) -> Result<Ring> {
pub fn address_device(&mut self, input_context: &mut Dma<InputContext>, i: usize, slot_ty: u8, slot: u8, speed: u8) -> Result<Ring> {
let mut ring = Ring::new(true)?;
{
@@ -502,27 +477,12 @@ impl Xhci {
endp_ctx.trh.write((tr >> 32) as u32);
endp_ctx.trl.write(tr as u32);
}
let input_context_physical = input_context.physical();
{
let (cmd, cycle, event) = self.cmd.next();
cmd.address_device(slot, input_context.physical(), false, cycle);
self.dbs[0].write(0);
while event.data.read() == 0 {
println!(" - Waiting for event");
}
if event.completion_code() != TrbCompletionCode::Success as u8
|| event.trb_type() != TrbType::CommandCompletion as u8
{
panic!("ADDRESS DEVICE FAILED");
}
cmd.reserved(false);
event.reserved(false);
}
self.execute_command("ADDRESS_DEVICE", |trb, cycle| {
trb.address_device(slot, input_context_physical, false, cycle)
}).expect("ADDRESS_DEVICE failed");
Ok(ring)
}
@@ -623,6 +583,11 @@ impl Xhci {
}
})
}
pub fn supported_protocol(&self, port: u8) -> Option<&'static SupportedProtoCap> {
self
.supported_protocols_iter()
.find(|supp_proto| supp_proto.compat_port_range().contains(&port))
}
pub fn supported_protocol_speeds(
&self,
port: u8,
@@ -690,9 +655,8 @@ impl Xhci {
| 7 << PROTO_SPEED_PSIV_SHIFT,
),
];
let supp_proto = self
.supported_protocols_iter()
.find(|supp_proto| supp_proto.compat_port_range().contains(&port))?;
let supp_proto = self.supported_protocol(port)?;
Some(if supp_proto.psic() != 0 {
unsafe { supp_proto.protocol_speeds().iter() }
+234 -255
View File
@@ -25,11 +25,16 @@ use super::extended::ProtocolSpeed;
use super::operational::OperationalRegs;
use super::ring::Ring;
use super::runtime::RuntimeRegs;
use super::trb::{TransferKind, TrbCompletionCode, TrbType};
use super::trb::{TransferKind, Trb, TrbCompletionCode, TrbType};
use super::usb::endpoint::{EndpointTy, ENDP_ATTR_TY_MASK};
use crate::driver_interface::*;
pub enum ControlFlow {
Continue,
Break,
}
#[derive(Clone, Copy, Debug)]
pub enum EndpIfState {
Init,
@@ -200,47 +205,149 @@ impl AnyDescriptor {
}
impl Xhci {
fn device_req_no_data(&mut self, port: usize, req: usb::Setup) -> Result<()> {
let ps = self.port_states.get_mut(&port).ok_or(Error::new(EIO))?;
let ring = ps
.endpoint_states
.get_mut(&0)
.ok_or(Error::new(EIO))?
.ring()
.ok_or(Error::new(EIO))?;
pub fn execute_command<F: FnOnce(&mut Trb, bool)>(&mut self, cmd_name: &str, f: F) -> Result<Trb> {
self.run.ints[0].erdp.write(self.cmd.erdp());
let (cmd, cycle, event) = self.cmd.next();
f(cmd, cycle);
self.dbs[0].write(0);
while event.data.read() == 0 {
println!(" - {} Waiting for event", cmd_name);
}
if event.completion_code() != TrbCompletionCode::Success as u8
|| event.trb_type() != TrbType::CommandCompletion as u8
{
println!("{} failed with event TRB ({:#0x} {:#0x} {:#0x}) and command TRB ({:#0x} {:#0x} {:#0x})", cmd_name, event.data.read(), event.status.read(), event.control.read(), cmd.data.read(), cmd.status.read(), cmd.control.read());
return Err(Error::new(EIO));
}
let ret = event.clone();
cmd.reserved(false);
event.reserved(false);
self.run.ints[0].erdp.write(self.cmd.erdp());
Ok(ret)
}
pub fn execute_control_transfer<D>(&mut self, port_num: usize, setup: usb::Setup, tk: TransferKind, name: &str, mut d: D) -> Result<Trb>
where
D: FnMut(&mut Trb, bool) -> ControlFlow,
{
let slot = self.port_state(port_num)?.slot;
let ring = self.endpoint_state_mut(port_num, 0)?.ring().ok_or(Error::new(EIO))?;
{
let (cmd, cycle) = ring.next();
cmd.setup(req, TransferKind::NoData, cycle);
cmd.setup(setup, tk, cycle);
}
if tk != TransferKind::NoData {
loop {
let (trb, cycle) = ring.next();
match d(trb, cycle) {
ControlFlow::Break => break,
ControlFlow::Continue => continue,
}
}
}
{
let (cmd, cycle) = ring.next();
cmd.status(false, cycle);
cmd.status(tk == TransferKind::In, cycle);
}
self.dbs[ps.slot as usize].write(Self::def_control_endp_doorbell());
self.dbs[usize::from(slot)].write(Self::def_control_endp_doorbell());
{
let cloned_trb = {
let event = self.cmd.next_event();
while event.data.read() == 0 {
println!(" - Waiting for event");
}
let status = event.status.read();
let control = event.control.read();
if (status >> 24) != TrbCompletionCode::Success as u32 {
println!("DEVICE_REQ ERROR, COMPLETION CODE {:#0x}", (status >> 24));
println!(" - {} Waiting for event", name);
}
println!(
"DEVICE_REQ EVENT {:#0x} {:#0x} {:#0x}",
event.data.read(),
status,
control
);
}
if event.completion_code() != TrbCompletionCode::Success as u8 || event.trb_type() != TrbType::Transfer as u8 {
println!("{} CONTROL TRANSFER ERROR, EVENT TRB {:#0x} {:#0x} {:#0}»", name, event.data.read(), event.status.read(), event.control.read());
}
event.clone()
};
self.run.ints[0].erdp.write(self.cmd.erdp());
Ok(cloned_trb)
}
/// NOTE: There has to be AT LEAST one successful invocation of `d`, that actually updates the
/// TRB (it could be a NO-OP in the worst case).
pub fn execute_transfer<D>(&mut self, port_num: usize, endp_num: u8, stream_id: u16, name: &str, mut d: D) -> Result<Trb>
where
D: FnMut(&mut Trb, bool) -> ControlFlow,
{
let port_state = self.port_state_mut(port_num)?;
let slot = port_state.slot;
let endp_state = port_state
.endpoint_states
.get_mut(&endp_num)
.ok_or(Error::new(EBADF))?;
let ring: &mut Ring = match endp_state {
EndpointState { transfer: super::RingOrStreams::Ring(ref mut ring), .. } => ring,
EndpointState { transfer: super::RingOrStreams::Streams(stream_ctx_array), .. } => {
stream_ctx_array
.rings
.get_mut(&1)
.ok_or(Error::new(EBADF))?
}
};
loop {
let (trb, cycle) = ring.next();
match d(trb, cycle) {
ControlFlow::Break => break,
ControlFlow::Continue => continue,
}
}
self.dbs[usize::from(slot)].write(Self::endp_doorbell(endp_num, self.endp_desc(port_num, endp_num)?, stream_id));
let cloned_trb = {
let event = self.cmd.next_event();
while event.data.read() == 0 {
println!(" - {} Waiting for event", name);
}
// FIXME: EDTLA if event data was set
if event.completion_code() != TrbCompletionCode::ShortPacket as u8
&& event.transfer_length() != 0
{
println!(
"Event trb didn't yield a short packet, but some bytes were not transferred"
);
}
if event.completion_code() != TrbCompletionCode::Success as u8
|| event.trb_type() != TrbType::Transfer as u8
{
println!(
"Custom transfer event failed with {:#0x} {:#0x} {:#0x}",
event.data.read(),
event.status.read(),
event.control.read()
);
}
// TODO: Handle event data
println!("EVENT DATA: {:?}", event.event_data());
let cloned_trb = event.clone();
event.reserved(false);
cloned_trb
};
self.run.ints[0].erdp.write(self.cmd.erdp());
Ok(cloned_trb)
}
fn device_req_no_data(&mut self, port: usize, req: usb::Setup) -> Result<()> {
self.execute_control_transfer(port, req, TransferKind::NoData, "DEVICE_REQ_NO_DATA", |_, _| ControlFlow::Break)?;
Ok(())
}
fn set_configuration(&mut self, port: usize, config: u8) -> Result<()> {
@@ -267,26 +374,7 @@ impl Xhci {
.ok_or(Error::new(EBADF))?
.slot;
let (cmd, cycle, event) = self.cmd.next();
cmd.reset_endpoint(slot, endp_num_xhc, tsp, cycle);
self.dbs[0].write(0);
while event.data.read() == 0 {
println!(" - Waiting for event");
}
if event.completion_code() != TrbCompletionCode::Success as u8
|| event.trb_type() != TrbType::CommandCompletion as u8
{
println!("RESET_ENDPOINT failed with event TRB ({:#0x} {:#0x} {:#0x}) and command TRB ({:#0x} {:#0x} {:#0x})", event.data.read(), event.status.read(), event.control.read(), cmd.data.read(), cmd.status.read(), cmd.control.read());
return Err(Error::new(EIO));
}
cmd.reserved(false);
event.reserved(false);
self.run.ints[0].erdp.write(self.cmd.erdp());
self.execute_command("RESET_ENDPOINT", |trb, cycle| trb.reset_endpoint(slot, endp_num_xhc, tsp, cycle))?;
Ok(())
}
@@ -349,6 +437,37 @@ impl Xhci {
}
}
fn port_state(&self, port: usize) -> Result<&super::PortState> {
self.port_states.get(&port).ok_or(Error::new(EBADF))
}
fn port_state_mut(&mut self, port: usize) -> Result<&mut super::PortState> {
self.port_states.get_mut(&port).ok_or(Error::new(EBADF))
}
fn endpoint_state_mut(&mut self, port: usize, endp_num: u8) -> Result<&mut EndpointState> {
self.port_state_mut(port)?.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADF))
}
fn input_context(&mut self, port: usize) -> Result<&mut Dma<InputContext>> {
Ok(&mut self.port_state_mut(port)?.input_context)
}
fn endp_ctx(&mut self, port: usize, endp_num_xhc: u8) -> Result<&mut super::context::EndpointContext> {
Ok(self.input_context(port)?
.device
.endpoints
.get_mut(endp_num_xhc as usize - 1)
.ok_or(Error::new(EIO))?)
}
fn dev_desc(&self, port: usize) -> Result<&DevDesc> {
Ok(&self.port_state(port)?.dev_desc)
}
fn config_descs(&self, port: usize) -> Result<&[ConfDesc]> {
Ok(&self.dev_desc(port)?.config_descs)
}
fn config_desc(&self, port: usize, desc: u8) -> Result<&ConfDesc> {
Ok(self.config_descs(port)?.get(usize::from(desc)).ok_or(Error::new(EBADF))?)
}
fn endp_descs(&self, port: usize, config_desc: u8, if_desc: u8) -> Result<&[EndpDesc]> {
Ok(&self.port_state(port)?.dev_desc.config_descs.get(usize::from(config_desc)).ok_or(Error::new(EIO))?.interface_descs.get(usize::from(if_desc)).ok_or(Error::new(EIO))?.endpoints)
}
fn configure_endpoints(&mut self, port: usize, json_buf: &[u8]) -> Result<()> {
let mut req: ConfigureEndpointsReq =
serde_json::from_slice(json_buf).or(Err(Error::new(EBADMSG)))?;
@@ -365,67 +484,59 @@ impl Xhci {
return Err(Error::new(EBADMSG));
}
let (endp_desc_count, new_context_entries) = {
let endpoints = self.endp_descs(port, req.config_desc, req.interface_desc.unwrap_or(0))?;
if endpoints.len() >= 31 {
return Err(Error::new(EIO));
}
(endpoints.len(), (match endpoints.last() {
Some(l) => Self::endp_num_to_dci(endpoints.len() as u8, l),
None => 1,
}) + 1)
};
let lec = self.cap.lec();
let max_psa_size = self.cap.max_psa_size();
let port_speed_id = self.ports[port].speed();
let speed_id: &ProtocolSpeed = self.lookup_psiv(port as u8, port_speed_id).ok_or(Error::new(EIO))?;
let port_state = self.port_states.get_mut(&port).ok_or(Error::new(ENOENT))?;
let input_context: &mut Dma<InputContext> = &mut port_state.input_context;
{
let input_context = self.input_context(port)?;
// Configure the slot context as well, which holds the last index of the endp descs.
input_context.add_context.write(1);
input_context.drop_context.write(0);
// Configure the slot context as well, which holds the last index of the endp descs.
input_context.add_context.write(1);
input_context.drop_context.write(0);
const CONTEXT_ENTRIES_MASK: u32 = 0xF800_0000;
const CONTEXT_ENTRIES_SHIFT: u8 = 27;
const CONTEXT_ENTRIES_MASK: u32 = 0xF800_0000;
const CONTEXT_ENTRIES_SHIFT: u8 = 27;
let current_slot_a = input_context.device.slot.a.read();
let current_slot_a = input_context.device.slot.a.read();
let dev_desc = &port_state.dev_desc;
let endpoints = &dev_desc
.config_descs
.get(req.config_desc as usize)
.ok_or(Error::new(EBADMSG))?
.interface_descs.get(req.interface_desc.unwrap_or(0) as usize).ok_or(Error::new(EBADMSG))?
.endpoints;
if endpoints.len() >= 31 {
return Err(Error::new(EIO));
input_context.device.slot.a.write(
(current_slot_a & !CONTEXT_ENTRIES_MASK)
| ((u32::from(new_context_entries) << CONTEXT_ENTRIES_SHIFT)
& CONTEXT_ENTRIES_MASK),
);
input_context.control.write(
(u32::from(req.alternate_setting.unwrap_or(0)) << 16)
| (u32::from(req.interface_desc.unwrap_or(0)) << 8)
| u32::from(req.config_desc),
);
}
let new_context_entries = match endpoints.last() {
Some(l) => Self::endp_num_to_dci(endpoints.len() as u8, l),
None => 1,
} + 1;
input_context.device.slot.a.write(
(current_slot_a & !CONTEXT_ENTRIES_MASK)
| ((u32::from(new_context_entries) << CONTEXT_ENTRIES_SHIFT)
& CONTEXT_ENTRIES_MASK),
);
input_context.control.write(
(u32::from(req.alternate_setting.unwrap_or(0)) << 16)
| (u32::from(req.interface_desc.unwrap_or(0)) << 8)
| u32::from(req.config_desc),
);
let lec = self.cap.lec();
for endp_idx in 0..endpoints.len() as u8 {
for endp_idx in 0..endp_desc_count as u8 {
let endp_num = endp_idx + 1;
let endpoints = self.endp_descs(port, req.config_desc, req.interface_desc.unwrap_or(0))?;
let dev_desc = self.dev_desc(port)?;
let endp_desc = endpoints.get(endp_idx as usize).ok_or(Error::new(EIO))?;
let endp_num_xhc = Self::endp_num_to_dci(endp_num, endp_desc);
input_context.add_context.writef(1 << endp_num_xhc, true);
let endp_ctx = input_context
.device
.endpoints
.get_mut(endp_num_xhc as usize - 1)
.ok_or(Error::new(EIO))?;
let max_streams = endp_desc.max_streams();
let max_psa_size = self.cap.max_psa_size();
// TODO: Secondary streams.
let primary_streams = if max_streams != 0 {
@@ -467,6 +578,8 @@ impl Xhci {
assert_eq!(max_error_count & 0x3, max_error_count);
assert_ne!(ep_ty, 0); // 0 means invalid.
let port_state = self.port_state_mut(port)?;
let ring_ptr = if max_streams != 0 {
let mut array = StreamContextArray::new(1 << (max_streams + 1))?;
@@ -502,6 +615,11 @@ impl Xhci {
};
assert_eq!(primary_streams & 0x1F, primary_streams);
let input_context = self.input_context(port)?;
input_context.add_context.writef(1 << endp_num_xhc, true);
let endp_ctx = self.endp_ctx(port, endp_num_xhc)?;
endp_ctx.a.write(
u32::from(mult) << 8
| u32::from(primary_streams) << 10
@@ -526,37 +644,12 @@ impl Xhci {
);
}
self.run.ints[0].erdp.write(self.cmd.erdp());
{
let (cmd, cycle, event) = self.cmd.next();
cmd.configure_endpoint(port_state.slot, input_context.physical(), cycle);
self.dbs[0].write(0);
while event.data.read() == 0 {
println!(" - Waiting for event");
}
if event.completion_code() != TrbCompletionCode::Success as u8
|| event.trb_type() != TrbType::CommandCompletion as u8
{
println!("CONFIGURE_ENDPOINT failed with event TRB ({:#0x} {:#0x} {:#0x}) and command TRB ({:#0x} {:#0x} {:#0x})", event.data.read(), event.status.read(), event.control.read(), cmd.data.read(), cmd.status.read(), cmd.control.read());
return Err(Error::new(EIO));
}
cmd.reserved(false);
event.reserved(false);
}
let slot = self.port_state(port)?.slot;
let input_context_physical = self.input_context(port)?.physical();
self.execute_command("CONFIGURE_ENDPOINT", |trb, cycle| trb.configure_endpoint(slot, input_context_physical, cycle));
// Tell the device about this configuration.
let configuration_value = port_state
.dev_desc
.config_descs
.get(req.config_desc as usize)
.ok_or(Error::new(EIO))?
.configuration_value;
let configuration_value = self.config_desc(port, req.config_desc)?.configuration_value;
self.set_configuration(port, configuration_value)?;
if let (Some(interface_num), Some(alternate_setting)) =
@@ -609,7 +702,7 @@ impl Xhci {
} else { unreachable!() }
}
fn endp_desc(&self, port_num: usize, endp_num: u8) -> Result<&EndpDesc> {
self.port_states.get(&port_num).ok_or(Error::new(EIO))?.dev_desc.config_descs.first().ok_or(Error::new(EIO))?.interface_descs.first().ok_or(Error::new(EIO))?.endpoints.get(endp_num as usize - 1).ok_or(Error::new(EIO))
Ok(self.endp_descs(port_num, 0, 0)?.get(usize::from(endp_num) - 1).ok_or(Error::new(EBADF))?)
}
fn endp_doorbell(endp_num: u8, desc: &EndpDesc, stream_id: u16) -> u32 {
let db_target = Self::endp_num_to_dci(endp_num, desc);
@@ -667,25 +760,11 @@ impl Xhci {
return Err(Error::new(EBADF));
}
let endp_state = port_state
.endpoint_states
.get_mut(&endp_num)
.ok_or(Error::new(EBADF))?;
let ring: &mut Ring = match endp_state {
EndpointState { transfer: super::RingOrStreams::Ring(ref mut ring), .. } => ring,
EndpointState { transfer: super::RingOrStreams::Streams(stream_ctx_array), .. } => {
stream_ctx_array
.rings
.get_mut(&1)
.ok_or(Error::new(EBADF))?
}
};
// TODO: Scatter-gather transfers, possibly allowing >64KiB sizes.
let len = u16::try_from(buf.len()).or(Err(Error::new(ENOSYS)))?;
let max_packet_size = endp_desc.max_packet_size;
{
let (trb, cycle) = ring.next();
let (buffer, idt, estimated_td_size) = {
let (buffer, idt) = if len <= 8 && max_packet_size >= 8 && direction != EndpDirection::In {
buf.map_buf(|sbuf| {
let mut bytes = [0u8; 8];
@@ -700,7 +779,12 @@ impl Xhci {
false,
)
};
let estimated_td_size = mem::size_of_val(&trb) as u8; // one trb per td
let estimated_td_size = mem::size_of::<Trb>() as u8; // one trb per td
(buffer, idt, estimated_td_size)
};
let stream_id = 1u16;
let event = self.execute_transfer(port_num, endp_num, stream_id, "CUSTOM_TRANSFER", |trb, cycle| {
trb.normal(
buffer,
len,
@@ -714,50 +798,16 @@ impl Xhci {
idt,
false,
);
}
ControlFlow::Break
})?;
let stream_id = 1u16;
self.dbs[port_state.slot as usize].write(Self::endp_doorbell(endp_num, self.endp_desc(port_num, endp_num)?, stream_id));
let (completion_code, bytes_transferred) = {
let event = self.cmd.next_event();
while event.data.read() == 0 {
println!(" - Waiting for event");
}
// FIXME: EDTLA if event data was set
if event.completion_code() != TrbCompletionCode::ShortPacket as u8
&& event.transfer_length() != 0
{
println!(
"Event trb didn't yield a short packet, but some bytes were not transferred"
);
}
if event.completion_code() != TrbCompletionCode::Success as u8
|| event.trb_type() != TrbType::Transfer as u8
{
println!(
"Custom transfer event failed with {:#0x} {:#0x} {:#0x}",
event.data.read(),
event.status.read(),
event.control.read()
);
}
// TODO: Handle event data
println!("EVENT DATA: {:?}", event.event_data());
(
event.completion_code(),
u32::from(len) - event.transfer_length(),
)
};
let bytes_transferred = u32::from(len) - event.transfer_length();
if let DeviceReqData::In(dbuf) = &mut buf {
dbuf.copy_from_slice(&*dma_buffer.as_ref().unwrap());
}
Ok((completion_code, bytes_transferred as u32))
Ok((event.completion_code(), bytes_transferred))
}
pub(crate) fn get_dev_desc(&mut self, port_id: usize) -> Result<DevDesc> {
let st = self
@@ -947,58 +997,10 @@ impl Xhci {
// be better. Maybe something simple like bincode could be used, if a custom binary struct
// is too much overkill.
let port_state = self
.port_states
.get_mut(&port_num)
.ok_or(Error::new(EBADF))?;
let ring = match port_state
.endpoint_states
.get_mut(&0)
.ok_or(Error::new(EIO))?
{
EndpointState { transfer: super::RingOrStreams::Ring(ref mut ring), .. } => ring,
// Control endpoints never use streams
_ => return Err(Error::new(EIO)),
};
{
let (cmd, cycle) = ring.next();
cmd.setup(setup, TransferKind::In, cycle);
}
if transfer_kind != TransferKind::NoData {
let (cmd, cycle) = ring.next();
cmd.data(
data_buffer.as_ref().map(|dma| dma.physical()).unwrap_or(0),
setup.length,
transfer_kind == TransferKind::In,
cycle,
);
}
{
let (cmd, cycle) = ring.next();
cmd.status(transfer_kind == TransferKind::In, cycle);
}
self.dbs[port_state.slot as usize].write(Self::def_control_endp_doorbell());
{
let event = self.cmd.next_event();
while event.data.read() == 0 {
println!(" - Waiting for event");
}
if event.completion_code() != TrbCompletionCode::Success as u8
|| event.trb_type() != TrbType::Transfer as u8
{
println!(
"Custom device request failed with EVENT {:#0x} {:#0x} {:#0x}",
event.data.read(),
event.status.read(),
event.control.read()
);
}
}
self.execute_control_transfer(port_num, setup, transfer_kind, "CUSTOM_DEVICE_REQ", |trb, cycle| {
trb.data(data_buffer.as_ref().map(|dma| dma.physical()).unwrap_or(0), setup.length, transfer_kind == TransferKind::In, cycle);
ControlFlow::Break
})?;
Ok(())
}
fn port_req_init_st(&mut self, port_num: usize, req: &PortReq) -> Result<PortReqState> {
@@ -1517,8 +1519,10 @@ impl Xhci {
&mut super::RingOrStreams::Ring(ref mut ring) => ring,
&mut super::RingOrStreams::Streams(ref mut arr) => arr.rings.get_mut(&1).ok_or(Error::new(EBADFD))?,
};
let (cmd, cycle) = ring.next();
cmd.transfer_no_op(0, false, false, false, cycle);
let deque_ptr_and_cycle = ring.register();
let slot = port_state.slot;
@@ -1538,33 +1542,8 @@ impl Xhci {
let slot = self.slot(port_num)?;
let endp_num_xhc = Self::endp_num_to_dci(endp_num, self.endp_desc(port_num, endp_num)?);
// TODO: Merge these command boilerplates into a single function.
self.run.ints[0].erdp.write(self.cmd.erdp());
self.execute_command("SET_TR_DEQUEUE_POINTER", |trb, cycle| trb.set_tr_deque_ptr(deque_ptr_and_cycle, cycle, StreamContextType::PrimaryRing, 1, endp_num_xhc, slot))?;
{
let (cmd, cycle, event) = self.cmd.next();
// TODO: I guess this very command is the one used to actually multiplex between
// streams.
cmd.set_tr_deque_ptr(deque_ptr_and_cycle, cycle, StreamContextType::PrimaryRing, 1, endp_num_xhc, slot);
self.dbs[0].write(0);
while event.data.read() == 0 {
println!(" - Waiting for event");
}
if event.completion_code() != TrbCompletionCode::Success as u8
|| event.trb_type() != TrbType::CommandCompletion as u8
{
println!("SET_TR_DEQUEUE_POINTER failed with event TRB ({:#0x} {:#0x} {:#0x}) and command TRB ({:#0x} {:#0x} {:#0x})", event.data.read(), event.status.read(), event.control.read(), cmd.data.read(), cmd.status.read(), cmd.control.read());
return Err(Error::new(EIO));
}
cmd.reserved(false);
event.reserved(false);
}
Ok(())
}
pub fn on_write_endp_ctl(&mut self, port_num: usize, endp_num: u8, buf: &[u8]) -> Result<usize> {
+12
View File
@@ -112,6 +112,15 @@ pub struct Trb {
pub status: Mmio<u32>,
pub control: Mmio<u32>,
}
impl Clone for Trb {
fn clone(&self) -> Self {
Self {
data: Mmio::from(self.data.read()),
status: Mmio::from(self.status.read()),
control: Mmio::from(self.control.read()),
}
}
}
pub const TRB_STATUS_COMPLETION_CODE_SHIFT: u8 = 24;
pub const TRB_STATUS_COMPLETION_CODE_MASK: u32 = 0xFF00_0000;
@@ -148,6 +157,9 @@ impl Trb {
pub fn completion_param(&self) -> u32 {
self.status.read() & TRB_STATUS_COMPLETION_PARAM_MASK
}
pub fn event_slot(&self) -> u8 {
(self.control.read() >> 24) as u8
}
/// Returns the number of bytes that should have been transmitten, but weren't.
pub fn transfer_length(&self) -> u32 {
self.status.read() & TRB_STATUS_TRANSFER_LENGTH_MASK