task: better async error handling
This commit is contained in:
parent
2770281213
commit
f166968e57
15
src/device/nvme/error.rs
Normal file
15
src/device/nvme/error.rs
Normal file
@ -0,0 +1,15 @@
|
||||
use abi::error::Error;
|
||||
|
||||
use super::queue::CommandError;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum NvmeError {
|
||||
MemoryError(Error),
|
||||
CommandError(CommandError),
|
||||
}
|
||||
|
||||
impl From<CommandError> for NvmeError {
|
||||
fn from(value: CommandError) -> Self {
|
||||
Self::CommandError(value)
|
||||
}
|
||||
}
|
@ -29,12 +29,14 @@ use crate::{
|
||||
|
||||
use self::{
|
||||
command::{CreateIoCompletionQueue, CreateIoSubmissionQueue, SetFeatureRequest},
|
||||
error::NvmeError,
|
||||
queue::QueuePair,
|
||||
};
|
||||
|
||||
use super::bus::pci::{FromPciBus, PciDeviceInfo};
|
||||
|
||||
mod command;
|
||||
mod error;
|
||||
mod queue;
|
||||
|
||||
register_bitfields! {
|
||||
@ -120,29 +122,23 @@ impl Regs {
|
||||
}
|
||||
|
||||
impl NvmeController {
|
||||
async fn late_init(&'static self) {
|
||||
// let ioq = QueuePair::new(capacity, sq_doorbell, cq_doorbell).unwrap();
|
||||
|
||||
async fn late_init(&'static self) -> Result<(), NvmeError> {
|
||||
runtime::spawn(self.poll_task()).expect("Couldn't spawn NVMe poll task");
|
||||
let admin_q = self.admin_q.get();
|
||||
|
||||
// Request a CQ/SQ pair for I/O
|
||||
admin_q
|
||||
.request_no_data(SetFeatureRequest::NumberOfQueues(1, 1))
|
||||
.unwrap()
|
||||
.await
|
||||
.unwrap();
|
||||
.await?;
|
||||
|
||||
// Allocate the queue
|
||||
let (sq_doorbell, cq_doorbell) = unsafe { self.doorbell_pair(1) };
|
||||
let io_q = QueuePair::new(32, sq_doorbell, cq_doorbell).unwrap();
|
||||
let io_q = QueuePair::new(32, sq_doorbell, cq_doorbell).map_err(NvmeError::MemoryError)?;
|
||||
|
||||
// Identify the controller
|
||||
let identify = admin_q
|
||||
.request(IdentifyControllerRequest { nsid: 0 })
|
||||
.unwrap()
|
||||
.await
|
||||
.unwrap();
|
||||
.request(IdentifyControllerRequest { nsid: 0 })?
|
||||
.await?;
|
||||
|
||||
// Create the queue on the device side
|
||||
admin_q
|
||||
@ -151,9 +147,7 @@ impl NvmeController {
|
||||
size: 32,
|
||||
data: io_q.cq_physical_pointer(),
|
||||
})
|
||||
.unwrap()
|
||||
.await
|
||||
.unwrap();
|
||||
.await?;
|
||||
admin_q
|
||||
.request_no_data(CreateIoSubmissionQueue {
|
||||
id: 1,
|
||||
@ -161,9 +155,7 @@ impl NvmeController {
|
||||
size: 32,
|
||||
data: io_q.sq_physical_pointer(),
|
||||
})
|
||||
.unwrap()
|
||||
.await
|
||||
.unwrap();
|
||||
.await?;
|
||||
|
||||
loop {}
|
||||
}
|
||||
|
@ -22,7 +22,10 @@ use crate::{
|
||||
task::runtime::QueueWaker,
|
||||
};
|
||||
|
||||
use super::command::{Command, Request};
|
||||
use super::{
|
||||
command::{Command, Request},
|
||||
error::NvmeError,
|
||||
};
|
||||
|
||||
#[derive(Zeroable, Pod, Clone, Copy, Debug)]
|
||||
#[repr(C)]
|
||||
@ -338,12 +341,7 @@ impl<'a> QueuePair<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn submit<C: Command>(
|
||||
&self,
|
||||
cmd: C,
|
||||
ranges: &[PhysicalAddress],
|
||||
set_pending: bool,
|
||||
) -> Result<u32, Error> {
|
||||
pub fn submit<C: Command>(&self, cmd: C, ranges: &[PhysicalAddress], set_pending: bool) -> u32 {
|
||||
let mut inner = self.inner.lock();
|
||||
let mut sqe = SubmissionQueueEntry::zeroed();
|
||||
|
||||
@ -370,24 +368,27 @@ impl<'a> QueuePair<'a> {
|
||||
|
||||
inner.sq.enqueue(sqe);
|
||||
|
||||
Ok(command_id)
|
||||
command_id
|
||||
}
|
||||
|
||||
pub fn request_no_data<'r, C: Command>(
|
||||
&'r self,
|
||||
req: C,
|
||||
) -> Result<impl Future<Output = Result<(), CommandError>> + 'r, Error>
|
||||
) -> impl Future<Output = Result<(), CommandError>> + 'r
|
||||
where
|
||||
'r: 'a,
|
||||
{
|
||||
let command_id = self.submit(req, &[], true)?;
|
||||
Ok(self.wait_for_completion(command_id, ()))
|
||||
let command_id = self.submit(req, &[], true);
|
||||
self.wait_for_completion(command_id, ())
|
||||
}
|
||||
|
||||
pub fn request<'r, R: Request>(
|
||||
&'r self,
|
||||
req: R,
|
||||
) -> Result<impl Future<Output = Result<PhysicalRefMut<'r, R::Response>, CommandError>>, Error>
|
||||
) -> Result<
|
||||
impl Future<Output = Result<PhysicalRefMut<'r, R::Response>, CommandError>>,
|
||||
NvmeError,
|
||||
>
|
||||
where
|
||||
R::Response: 'r,
|
||||
'r: 'a,
|
||||
@ -395,11 +396,11 @@ impl<'a> QueuePair<'a> {
|
||||
assert_ne!(size_of::<R::Response>(), 0);
|
||||
assert!(size_of::<R::Response>() < 0x1000);
|
||||
|
||||
let page = phys::alloc_page()?;
|
||||
let page = phys::alloc_page().map_err(NvmeError::MemoryError)?;
|
||||
// TODO PageBox
|
||||
let response = unsafe { PhysicalRefMut::map(page) };
|
||||
|
||||
let command_id = self.submit(req, &[page], true)?;
|
||||
let command_id = self.submit(req, &[page], true);
|
||||
Ok(self.wait_for_completion(command_id, response))
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@ use futures_util::{task::waker_ref, Future};
|
||||
use crate::task::{spawn_kernel_closure, thread::Thread};
|
||||
|
||||
use super::{
|
||||
task::Task,
|
||||
task::{Task, Termination},
|
||||
task_queue::{self},
|
||||
};
|
||||
|
||||
@ -38,7 +38,9 @@ pub fn spawn_async_worker(index: usize) -> Result<(), Error> {
|
||||
}
|
||||
|
||||
/// Creates a new task for the [Future] and queues it for execution in background
|
||||
pub fn spawn<F: Future<Output = ()> + Send + 'static>(future: F) -> Result<(), Error> {
|
||||
pub fn spawn<T: Termination, F: Future<Output = T> + Send + 'static>(
|
||||
future: F,
|
||||
) -> Result<(), Error> {
|
||||
enqueue(Task::new(future))
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,15 @@
|
||||
use core::fmt;
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use futures_util::{future::BoxFuture, task::ArcWake, Future, FutureExt};
|
||||
use kernel_util::sync::IrqSafeSpinlock;
|
||||
|
||||
use super::executor;
|
||||
|
||||
pub trait Termination {
|
||||
fn print(&self);
|
||||
}
|
||||
|
||||
pub struct Task {
|
||||
pub(super) future: IrqSafeSpinlock<Option<BoxFuture<'static, ()>>>,
|
||||
}
|
||||
@ -15,8 +21,25 @@ impl ArcWake for Task {
|
||||
}
|
||||
|
||||
impl Task {
|
||||
pub fn new<F: Future<Output = ()> + Send + 'static>(future: F) -> Arc<Self> {
|
||||
let future = IrqSafeSpinlock::new(Some(future.boxed()));
|
||||
pub fn new<T: Termination, F: Future<Output = T> + Send + 'static>(future: F) -> Arc<Self> {
|
||||
let future = IrqSafeSpinlock::new(Some(
|
||||
async move {
|
||||
future.await.print();
|
||||
}
|
||||
.boxed(),
|
||||
));
|
||||
Arc::new(Self { future })
|
||||
}
|
||||
}
|
||||
|
||||
impl Termination for () {
|
||||
fn print(&self) {}
|
||||
}
|
||||
|
||||
impl<T, E: fmt::Debug> Termination for Result<T, E> {
|
||||
fn print(&self) {
|
||||
if let Err(error) = self {
|
||||
errorln!("A task finished with an error: {:?}", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user