From 258ea4e6a58a6137d19869d432c428d5a8d1bd79 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 9 Mar 2025 17:02:25 +0100 Subject: [PATCH] storage/usbscsid: Use the unified disk scheme implementation --- Cargo.lock | 3 +- storage/usbscsid/Cargo.toml | 3 +- storage/usbscsid/src/main.rs | 103 +++++++++++++++------- storage/usbscsid/src/scheme.rs | 146 ------------------------------- storage/usbscsid/src/scsi/mod.rs | 2 +- 5 files changed, 78 insertions(+), 179 deletions(-) delete mode 100644 storage/usbscsid/src/scheme.rs diff --git a/Cargo.lock b/Cargo.lock index d024866c9b..f9dd06081e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1594,10 +1594,11 @@ name = "usbscsid" version = "0.1.0" dependencies = [ "base64 0.11.0", + "driver-block", "libredox", "plain", "redox-daemon", - "redox-scheme 0.3.0", + "redox_event", "redox_syscall", "thiserror", "xhcid", diff --git a/storage/usbscsid/Cargo.toml b/storage/usbscsid/Cargo.toml index 7a7f1e3752..5e862aa06c 100644 --- a/storage/usbscsid/Cargo.toml +++ b/storage/usbscsid/Cargo.toml @@ -11,8 +11,9 @@ license = "MIT" base64 = "0.11" # Only for debugging libredox = "0.1.3" plain = "0.2" +driver-block = { path = "../driver-block" } redox-daemon = "0.1" +redox_event = "0.4" redox_syscall = { version = "0.5", features = ["std"] } -redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } thiserror = "1" xhcid = { path = "../../xhcid" } diff --git a/storage/usbscsid/src/main.rs b/storage/usbscsid/src/main.rs index a4cb53992a..9950814e7c 100644 --- a/storage/usbscsid/src/main.rs +++ b/storage/usbscsid/src/main.rs @@ -1,15 +1,15 @@ +use std::collections::BTreeMap; use std::env; -use redox_scheme::{RequestKind, SignalBehavior, Socket}; +use driver_block::{Disk, DiskScheme}; +use syscall::{Error, EIO}; use xhcid_interface::{ConfigureEndpointsReq, XhciClientHandle}; pub mod protocol; pub mod scsi; -mod scheme; - -use scheme::ScsiScheme; -use scsi::Scsi; +use crate::protocol::Protocol; +use crate::scsi::Scsi; fn main() { let mut args = env::args().skip(1); @@ -37,7 +37,7 @@ fn main() { .expect("usbscsid: failed to daemonize"); } fn daemon(daemon: redox_daemon::Daemon, scheme: String, port: usize, protocol: u8) -> ! { - let disk_scheme_name = format!(":disk.usb-{scheme}+{port}-scsi"); + let disk_scheme_name = format!("disk.usb-{scheme}+{port}-scsi"); // TODO: Use eventfds. let handle = XhciClientHandle::new(scheme.to_owned(), port); @@ -82,38 +82,81 @@ fn daemon(daemon: redox_daemon::Daemon, scheme: String, port: usize, protocol: u // TODO: Let all of the USB drivers fork or be managed externally, and xhcid won't have to keep // track of all the drivers. - let socket_fd = - Socket::create(&disk_scheme_name).expect("usbscsid: failed to create disk scheme"); - - //libredox::call::setrens(0, 0).expect("scsid: failed to enter null namespace"); let mut scsi = Scsi::new(&mut *protocol).expect("usbscsid: failed to setup SCSI"); println!("SCSI initialized"); 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); + let event_queue = event::EventQueue::new().unwrap(); - // TODO: Use nonblocking and put all pending calls in a todo VecDeque. Use an eventfd as well. - loop { - let req = match socket_fd - .next_request(SignalBehavior::Restart) - .expect("scsid: failed to read disk scheme") - { - Some(r) => { - if let RequestKind::Call(c) = r.kind() { - c - } else { - continue; - } - } - None => break, - }; - let resp = req.handle_scheme(&mut scsi_scheme); - socket_fd - .write_response(resp, SignalBehavior::Restart) - .expect("scsid: failed to write cqe"); + event::user_data! { + enum Event { + Scheme, + } + }; + + let mut scheme = DiskScheme::new( + disk_scheme_name, + BTreeMap::from([( + 0, + UsbDisk { + scsi: &mut scsi, + protocol: &mut *protocol, + }, + )]), + ); + + //libredox::call::setrens(0, 0).expect("nvmed: failed to enter null namespace"); + + event_queue + .subscribe( + scheme.event_handle().raw(), + Event::Scheme, + event::EventFlags::READ, + ) + .unwrap(); + + for event in event_queue { + match event.unwrap().user_data { + Event::Scheme => scheme.tick().unwrap(), + } } std::process::exit(0); } + +struct UsbDisk<'a> { + scsi: &'a mut Scsi, + protocol: &'a mut dyn Protocol, +} + +impl Disk for UsbDisk<'_> { + fn block_size(&self) -> u32 { + self.scsi.block_size + } + + fn size(&self) -> u64 { + self.scsi.get_disk_size() + } + + fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result> { + match self.scsi.read(self.protocol, block, buffer) { + Ok(bytes_read) => Ok(Some(bytes_read as usize)), + Err(err) => { + eprintln!("usbscsid: READ IO ERROR: {err}"); + Err(Error::new(EIO)) + } + } + } + + fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result> { + match self.scsi.write(self.protocol, block, buffer) { + Ok(bytes_written) => Ok(Some(bytes_written as usize)), + Err(err) => { + eprintln!("usbscsid: WRITE IO ERROR: {err}"); + Err(Error::new(EIO)) + } + } + } +} diff --git a/storage/usbscsid/src/scheme.rs b/storage/usbscsid/src/scheme.rs deleted file mode 100644 index 4680fb937e..0000000000 --- a/storage/usbscsid/src/scheme.rs +++ /dev/null @@ -1,146 +0,0 @@ -use std::collections::BTreeMap; -use std::str; - -use crate::protocol::Protocol; -use crate::scsi::Scsi; - -use redox_scheme::{CallerCtx, OpenResult, Scheme}; -use syscall::error::{Error, Result}; -use syscall::error::{EACCES, EBADF, EINVAL, EIO, ENOSYS}; -use syscall::flag::{MODE_CHR, MODE_DIR}; -use syscall::flag::{O_DIRECTORY, O_STAT}; -use syscall::schemev2::NewFdFlags; - -// TODO: Only one disk, right? -const LIST_CONTENTS: &'static [u8] = b"0\n"; - -enum Handle { - List, - Disk, - //Partition(usize, u32), -} - -pub struct ScsiScheme<'a> { - scsi: &'a mut Scsi, - protocol: &'a mut dyn Protocol, - handles: BTreeMap, - next_fd: usize, -} - -impl<'a> ScsiScheme<'a> { - pub fn new(scsi: &'a mut Scsi, protocol: &'a mut dyn Protocol) -> Self { - Self { - scsi, - protocol, - handles: BTreeMap::new(), - next_fd: 0, - } - } -} - -impl Scheme for ScsiScheme<'_> { - fn xopen(&mut self, path_str: &str, flags: usize, ctx: &CallerCtx) -> Result { - if ctx.uid != 0 { - return Err(Error::new(EACCES)); - } - if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { - return Err(Error::new(EACCES)); - } - let path_str = path_str.trim_start_matches('/'); - let handle = if path_str.is_empty() { - // List - Handle::List - } else if let Some(_p_pos) = path_str.chars().position(|c| c == 'p') { - // TODO: Partitions. - return Err(Error::new(ENOSYS)); - } else { - Handle::Disk - }; - self.next_fd += 1; - self.handles.insert(self.next_fd, handle); - Ok(OpenResult::ThisScheme { - number: self.next_fd, - flags: NewFdFlags::POSITIONED, - }) - } - fn fstat(&mut self, fd: usize, stat: &mut syscall::Stat) -> Result { - match self.handles.get(&fd).ok_or(Error::new(EBADF))? { - Handle::Disk => { - stat.st_mode = MODE_CHR; - stat.st_size = self.scsi.get_disk_size(); - 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; - } - } - Ok(0) - } - fn fpath(&mut self, fd: usize, buf: &mut [u8]) -> Result { - let path = match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { - Handle::Disk => "0", - Handle::List => "", - } - .as_bytes(); - let min = std::cmp::min(path.len(), buf.len()); - buf[..min].copy_from_slice(&path[..min]); - Ok(min) - } - fn fsize(&mut self, fd: usize) -> Result { - Ok(match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { - Handle::Disk => self.scsi.get_disk_size(), - Handle::List => LIST_CONTENTS.len() as u64, - }) - } - fn read(&mut self, fd: usize, buf: &mut [u8], offset: u64, _fcntl_flags: u32) -> Result { - match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { - Handle::Disk => { - if offset % 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 / u64::from(self.scsi.block_size); - match self.scsi.read(self.protocol, lba, buf) { - Ok(bytes_read) => Ok(bytes_read as usize), - Err(err) => { - eprintln!("usbscsid: READ IO ERROR: {err}"); - Err(Error::new(EIO)) - } - } - } - Handle::List => { - let src = usize::try_from(offset) - .ok() - .and_then(|o| LIST_CONTENTS.get(o..)) - .unwrap_or(&[]); - let min = core::cmp::min(src.len(), buf.len()); - buf[..min].copy_from_slice(&src[..min]); - - Ok(min) - } - } - } - fn write(&mut self, fd: usize, buf: &[u8], offset: u64, _fcntl_flags: u32) -> Result { - match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { - Handle::Disk => { - if offset % 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 / u64::from(self.scsi.block_size); - match self.scsi.write(self.protocol, lba, buf) { - Ok(bytes_written) => Ok(bytes_written as usize), - Err(err) => { - eprintln!("usbscsid: WRITE IO ERROR: {err}"); - Err(Error::new(EIO)) - } - } - } - Handle::List => Err(Error::new(EBADF)), - } - } -} diff --git a/storage/usbscsid/src/scsi/mod.rs b/storage/usbscsid/src/scsi/mod.rs index e6364e9c2f..a5350ea67f 100644 --- a/storage/usbscsid/src/scsi/mod.rs +++ b/storage/usbscsid/src/scsi/mod.rs @@ -249,7 +249,7 @@ impl Scsi { pub fn res_read_capacity10(&self) -> &cmds::ReadCapacity10ParamData { plain::from_bytes(&self.data_buffer).unwrap() } - pub fn get_disk_size(&mut self) -> u64 { + pub fn get_disk_size(&self) -> u64 { self.block_count * u64::from(self.block_size) } pub fn read(