Fallback in ahci driver when disk: not available, ability to list disk devices
This commit is contained in:
parent
feee00039f
commit
4b780927d2
|
@ -11,7 +11,7 @@ pub struct Disk {
|
||||||
size: u64,
|
size: u64,
|
||||||
clb: Dma<[HbaCmdHeader; 32]>,
|
clb: Dma<[HbaCmdHeader; 32]>,
|
||||||
ctbas: [Dma<HbaCmdTable>; 32],
|
ctbas: [Dma<HbaCmdTable>; 32],
|
||||||
fb: Dma<[u8; 256]>,
|
_fb: Dma<[u8; 256]>,
|
||||||
buf: Dma<[u8; 256 * 512]>
|
buf: Dma<[u8; 256 * 512]>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ impl Disk {
|
||||||
size: size,
|
size: size,
|
||||||
clb: clb,
|
clb: clb,
|
||||||
ctbas: ctbas,
|
ctbas: ctbas,
|
||||||
fb: fb,
|
_fb: fb,
|
||||||
buf: buf
|
buf: buf
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -389,7 +389,7 @@ pub struct HbaCmdTable {
|
||||||
cfis: [Mmio<u8>; 64], // Command FIS
|
cfis: [Mmio<u8>; 64], // Command FIS
|
||||||
|
|
||||||
// 0x40
|
// 0x40
|
||||||
acmd: [Mmio<u8>; 16], // ATAPI command, 12 or 16 bytes
|
_acmd: [Mmio<u8>; 16], // ATAPI command, 12 or 16 bytes
|
||||||
|
|
||||||
// 0x50
|
// 0x50
|
||||||
_rsv: [Mmio<u8>; 48], // Reserved
|
_rsv: [Mmio<u8>; 48], // Reserved
|
||||||
|
@ -402,12 +402,12 @@ pub struct HbaCmdTable {
|
||||||
pub struct HbaCmdHeader {
|
pub struct HbaCmdHeader {
|
||||||
// DW0
|
// DW0
|
||||||
cfl: Mmio<u8>, /* Command FIS length in DWORDS, 2 ~ 16, atapi: 4, write - host to device: 2, prefetchable: 1 */
|
cfl: Mmio<u8>, /* Command FIS length in DWORDS, 2 ~ 16, atapi: 4, write - host to device: 2, prefetchable: 1 */
|
||||||
pm: Mmio<u8>, // Reset - 0x80, bist: 0x40, clear busy on ok: 0x20, port multiplier
|
_pm: Mmio<u8>, // Reset - 0x80, bist: 0x40, clear busy on ok: 0x20, port multiplier
|
||||||
|
|
||||||
prdtl: Mmio<u16>, // Physical region descriptor table length in entries
|
prdtl: Mmio<u16>, // Physical region descriptor table length in entries
|
||||||
|
|
||||||
// DW1
|
// DW1
|
||||||
prdbc: Mmio<u32>, // Physical region descriptor byte count transferred
|
_prdbc: Mmio<u32>, // Physical region descriptor byte count transferred
|
||||||
|
|
||||||
// DW2, 3
|
// DW2, 3
|
||||||
ctba: Mmio<u64>, // Command table descriptor base address
|
ctba: Mmio<u64>, // Command table descriptor base address
|
||||||
|
|
|
@ -10,14 +10,23 @@ extern crate syscall;
|
||||||
use std::{env, usize};
|
use std::{env, usize};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::os::unix::io::{AsRawFd, FromRawFd};
|
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
||||||
use syscall::{EVENT_READ, MAP_WRITE, Event, Packet, Scheme};
|
use syscall::{EVENT_READ, MAP_WRITE, Event, Packet, Result, Scheme};
|
||||||
|
|
||||||
use scheme::DiskScheme;
|
use scheme::DiskScheme;
|
||||||
|
|
||||||
pub mod ahci;
|
pub mod ahci;
|
||||||
pub mod scheme;
|
pub mod scheme;
|
||||||
|
|
||||||
|
fn create_scheme_fallback<'a>(name: &'a str, fallback: &'a str) -> Result<(&'a str, RawFd)> {
|
||||||
|
if let Ok(fd) = syscall::open(&format!(":{}", name), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK) {
|
||||||
|
Ok((name, fd))
|
||||||
|
} else {
|
||||||
|
syscall::open(&format!(":{}", fallback), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK)
|
||||||
|
.map(|fd| (fallback, fd))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut args = env::args().skip(1);
|
let mut args = env::args().skip(1);
|
||||||
|
|
||||||
|
@ -36,7 +45,7 @@ fn main() {
|
||||||
if unsafe { syscall::clone(0).unwrap() } == 0 {
|
if unsafe { syscall::clone(0).unwrap() } == 0 {
|
||||||
let address = unsafe { syscall::physmap(bar, 4096, MAP_WRITE).expect("ahcid: failed to map address") };
|
let address = unsafe { syscall::physmap(bar, 4096, MAP_WRITE).expect("ahcid: failed to map address") };
|
||||||
{
|
{
|
||||||
let socket_fd = syscall::open(":disk", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("ahcid: failed to create disk scheme");
|
let (_scheme_name, socket_fd) = create_scheme_fallback("disk", &name).expect("ahcid: failed to create disk scheme");
|
||||||
let mut socket = unsafe { File::from_raw_fd(socket_fd) };
|
let mut socket = unsafe { File::from_raw_fd(socket_fd) };
|
||||||
syscall::fevent(socket_fd, EVENT_READ).expect("ahcid: failed to fevent disk scheme");
|
syscall::fevent(socket_fd, EVENT_READ).expect("ahcid: failed to fevent disk scheme");
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,24 @@
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::{cmp, str};
|
use std::{cmp, str};
|
||||||
|
use std::fmt::Write;
|
||||||
|
use std::io::Read;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
use spin::Mutex;
|
use spin::Mutex;
|
||||||
use syscall::{Error, EACCES, EBADF, EINVAL, ENOENT, Result, Scheme, Stat, MODE_FILE, SEEK_CUR, SEEK_END, SEEK_SET};
|
use syscall::{Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, Result, Scheme, Stat, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, SEEK_CUR, SEEK_END, SEEK_SET};
|
||||||
|
|
||||||
use ahci::disk::Disk;
|
use ahci::disk::Disk;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
enum Handle {
|
||||||
|
//TODO: Make these enum variants normal tuples (), not nested tuples (())
|
||||||
|
List((Vec<u8>, usize)),
|
||||||
|
Disk((Arc<Mutex<Disk>>, usize))
|
||||||
|
}
|
||||||
|
|
||||||
pub struct DiskScheme {
|
pub struct DiskScheme {
|
||||||
disks: Box<[Arc<Mutex<Disk>>]>,
|
disks: Box<[Arc<Mutex<Disk>>]>,
|
||||||
handles: Mutex<BTreeMap<usize, (Arc<Mutex<Disk>>, usize)>>,
|
handles: Mutex<BTreeMap<usize, Handle>>,
|
||||||
next_id: AtomicUsize
|
next_id: AtomicUsize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,18 +38,33 @@ impl DiskScheme {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scheme for DiskScheme {
|
impl Scheme for DiskScheme {
|
||||||
fn open(&self, path: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result<usize> {
|
fn open(&self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result<usize> {
|
||||||
if uid == 0 {
|
if uid == 0 {
|
||||||
let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?;
|
let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?.trim_matches('/');
|
||||||
|
if path_str.is_empty() {
|
||||||
|
if flags & O_DIRECTORY == O_DIRECTORY || flags & O_STAT == O_STAT {
|
||||||
|
let mut list = String::new();
|
||||||
|
|
||||||
let i = path_str.parse::<usize>().or(Err(Error::new(ENOENT)))?;
|
for i in 0..self.disks.len() {
|
||||||
|
write!(list, "{}\n", i).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(disk) = self.disks.get(i) {
|
let id = self.next_id.fetch_add(1, Ordering::SeqCst);
|
||||||
let id = self.next_id.fetch_add(1, Ordering::SeqCst);
|
self.handles.lock().insert(id, Handle::List((list.into_bytes(), 0)));
|
||||||
self.handles.lock().insert(id, (disk.clone(), 0));
|
Ok(id)
|
||||||
Ok(id)
|
} else {
|
||||||
|
Err(Error::new(EISDIR))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(Error::new(ENOENT))
|
let i = path_str.parse::<usize>().or(Err(Error::new(ENOENT)))?;
|
||||||
|
|
||||||
|
if let Some(disk) = self.disks.get(i) {
|
||||||
|
let id = self.next_id.fetch_add(1, Ordering::SeqCst);
|
||||||
|
self.handles.lock().insert(id, Handle::Disk((disk.clone(), 0)));
|
||||||
|
Ok(id)
|
||||||
|
} else {
|
||||||
|
Err(Error::new(ENOENT))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(Error::new(EACCES))
|
Err(Error::new(EACCES))
|
||||||
|
@ -61,46 +85,78 @@ impl Scheme for DiskScheme {
|
||||||
|
|
||||||
fn fstat(&self, id: usize, stat: &mut Stat) -> Result<usize> {
|
fn fstat(&self, id: usize, stat: &mut Stat) -> Result<usize> {
|
||||||
let handles = self.handles.lock();
|
let handles = self.handles.lock();
|
||||||
let handle = handles.get(&id).ok_or(Error::new(EBADF))?;
|
match *handles.get(&id).ok_or(Error::new(EBADF))? {
|
||||||
|
Handle::List(ref handle) => {
|
||||||
stat.st_mode = MODE_FILE;
|
stat.st_mode = MODE_DIR;
|
||||||
stat.st_size = handle.0.lock().size();
|
stat.st_size = handle.0.len() as u64;
|
||||||
Ok(0)
|
Ok(0)
|
||||||
|
},
|
||||||
|
Handle::Disk(ref handle) => {
|
||||||
|
stat.st_mode = MODE_FILE;
|
||||||
|
stat.st_size = handle.0.lock().size();
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
|
fn read(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
|
||||||
let mut handles = self.handles.lock();
|
let mut handles = self.handles.lock();
|
||||||
let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
|
match *handles.get_mut(&id).ok_or(Error::new(EBADF))? {
|
||||||
|
Handle::List(ref mut handle) => {
|
||||||
let mut disk = handle.0.lock();
|
let count = (&handle.0[handle.1..]).read(buf).unwrap();
|
||||||
let count = disk.read((handle.1 as u64)/512, buf)?;
|
handle.1 += count;
|
||||||
handle.1 += count;
|
Ok(count)
|
||||||
Ok(count)
|
},
|
||||||
|
Handle::Disk(ref mut handle) => {
|
||||||
|
let mut disk = handle.0.lock();
|
||||||
|
let count = disk.read((handle.1 as u64)/512, buf)?;
|
||||||
|
handle.1 += count;
|
||||||
|
Ok(count)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write(&self, id: usize, buf: &[u8]) -> Result<usize> {
|
fn write(&self, id: usize, buf: &[u8]) -> Result<usize> {
|
||||||
let mut handles = self.handles.lock();
|
let mut handles = self.handles.lock();
|
||||||
let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
|
match *handles.get_mut(&id).ok_or(Error::new(EBADF))? {
|
||||||
|
Handle::List(_) => {
|
||||||
let mut disk = handle.0.lock();
|
Err(Error::new(EBADF))
|
||||||
let count = disk.write((handle.1 as u64)/512, buf)?;
|
},
|
||||||
handle.1 += count;
|
Handle::Disk(ref mut handle) => {
|
||||||
Ok(count)
|
let mut disk = handle.0.lock();
|
||||||
|
let count = disk.write((handle.1 as u64)/512, buf)?;
|
||||||
|
handle.1 += count;
|
||||||
|
Ok(count)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn seek(&self, id: usize, pos: usize, whence: usize) -> Result<usize> {
|
fn seek(&self, id: usize, pos: usize, whence: usize) -> Result<usize> {
|
||||||
let mut handles = self.handles.lock();
|
let mut handles = self.handles.lock();
|
||||||
let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
|
match *handles.get_mut(&id).ok_or(Error::new(EBADF))? {
|
||||||
|
Handle::List(ref mut handle) => {
|
||||||
|
let len = handle.0.len() as usize;
|
||||||
|
handle.1 = match whence {
|
||||||
|
SEEK_SET => cmp::min(len, pos),
|
||||||
|
SEEK_CUR => cmp::max(0, cmp::min(len as isize, handle.1 as isize + pos as isize)) as usize,
|
||||||
|
SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize,
|
||||||
|
_ => return Err(Error::new(EINVAL))
|
||||||
|
};
|
||||||
|
|
||||||
let len = handle.0.lock().size() as usize;
|
Ok(handle.1)
|
||||||
handle.1 = match whence {
|
},
|
||||||
SEEK_SET => cmp::min(len, pos),
|
Handle::Disk(ref mut handle) => {
|
||||||
SEEK_CUR => cmp::max(0, cmp::min(len as isize, handle.1 as isize + pos as isize)) as usize,
|
let len = handle.0.lock().size() as usize;
|
||||||
SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize,
|
handle.1 = match whence {
|
||||||
_ => return Err(Error::new(EINVAL))
|
SEEK_SET => cmp::min(len, pos),
|
||||||
};
|
SEEK_CUR => cmp::max(0, cmp::min(len as isize, handle.1 as isize + pos as isize)) as usize,
|
||||||
|
SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize,
|
||||||
|
_ => return Err(Error::new(EINVAL))
|
||||||
|
};
|
||||||
|
|
||||||
Ok(handle.1)
|
Ok(handle.1)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn close(&self, id: usize) -> Result<usize> {
|
fn close(&self, id: usize) -> Result<usize> {
|
||||||
|
|
Loading…
Reference in a new issue