diff --git a/usbscsid/src/main.rs b/usbscsid/src/main.rs index 82a5529ccd..932c57af8b 100644 --- a/usbscsid/src/main.rs +++ b/usbscsid/src/main.rs @@ -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 { diff --git a/usbscsid/src/protocol/bot.rs b/usbscsid/src/protocol/bot.rs index 0aafe80aeb..13ab6a784f 100644 --- a/usbscsid/src/protocol/bot.rs +++ b/usbscsid/src/protocol/bot.rs @@ -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), }) } } diff --git a/usbscsid/src/protocol/mod.rs b/usbscsid/src/protocol/mod.rs index 2ffe4e5d83..7315ab9805 100644 --- a/usbscsid/src/protocol/mod.rs +++ b/usbscsid/src/protocol/mod.rs @@ -22,12 +22,26 @@ pub enum ProtocolError { ProtocolError(&'static str), } -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum SendCommandStatus { - Success, - Failed { residue: Option }, +#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)] +pub struct SendCommandStatus { + pub residue: Option, + 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 } diff --git a/usbscsid/src/scheme.rs b/usbscsid/src/scheme.rs index 46d1a18393..0c88ba6177 100644 --- a/usbscsid/src/scheme.rs +++ b/usbscsid/src/scheme.rs @@ -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, 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 { - 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 { - 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 { Err(Error::new(ENOSYS)) diff --git a/usbscsid/src/scsi/cmds.rs b/usbscsid/src/scsi/cmds.rs index 98c6006a86..31949566bd 100644 --- a/usbscsid/src/scsi/cmds.rs +++ b/usbscsid/src/scsi/cmds.rs @@ -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::(), 20); - slice::from_raw_parts(&self.descs as *const CommandDescriptor, (self.alloc_len() as usize - 4) / mem::size_of::()) - } -} - -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 { + 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 { + 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 { + ModePageIter { raw: ModePageIterRaw { buffer } } +} diff --git a/usbscsid/src/scsi/mod.rs b/usbscsid/src/scsi/mod.rs index 7254dcb7a1..3368db7aac 100644 --- a/usbscsid/src/scsi/mod.rs +++ b/usbscsid/src/scsi/mod.rs @@ -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, + 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) -> Result { - 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, alloc_len: u32) -> Result { - 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::(), 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), 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::(), 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::(); - 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 { + let header = self.res_mode_param_header10(); + let descs_start = mem::size_of::(); + 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 { + 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> { + 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), + } + } +} diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index e49570a260..e71c9dc225 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -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 { + 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::::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, i: usize, slot: u8, speed: u8) -> Result { + pub fn address_device(&mut self, input_context: &mut Dma, i: usize, slot_ty: u8, slot: u8, speed: u8) -> Result { 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() } diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index acea2a2608..11465d64fb 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -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(&mut self, cmd_name: &str, f: F) -> Result { + 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(&mut self, port_num: usize, setup: usb::Setup, tk: TransferKind, name: &str, mut d: D) -> Result + 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(&mut self, port_num: usize, endp_num: u8, stream_id: u16, name: &str, mut d: D) -> Result + 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> { + 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 = &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::() 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 { 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 { @@ -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 { diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index 8e070d36e6..4dafc85860 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -112,6 +112,15 @@ pub struct Trb { pub status: Mmio, pub control: Mmio, } +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