storage/usbscsid: Use the unified disk scheme implementation

This commit is contained in:
bjorn3
2025-03-09 17:02:25 +01:00
parent 9800c57133
commit 258ea4e6a5
5 changed files with 78 additions and 179 deletions
Generated
+2 -1
View File
@@ -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",
+2 -1
View File
@@ -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" }
+73 -30
View File
@@ -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<Option<usize>> {
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<Option<usize>> {
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))
}
}
}
}
-146
View File
@@ -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<usize, Handle>,
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<OpenResult> {
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<usize> {
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<usize> {
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<u64> {
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<usize> {
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<usize> {
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)),
}
}
}
+1 -1
View File
@@ -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(