storage/usbscsid: Use the unified disk scheme implementation
This commit is contained in:
Generated
+2
-1
@@ -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",
|
||||
|
||||
@@ -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" }
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user