103 lines
2.5 KiB
Rust
103 lines
2.5 KiB
Rust
use core::{mem::MaybeUninit, ops::Deref};
|
|
|
|
use alloc::boxed::Box;
|
|
use async_trait::async_trait;
|
|
use libk::{
|
|
dma::{DmaBuffer, DmaSliceMut},
|
|
error::Error,
|
|
};
|
|
|
|
use crate::command::ScsiCommand;
|
|
|
|
#[async_trait]
|
|
pub trait ScsiTransport: Send + Sync {
|
|
fn allocate_buffer(&self, size: usize) -> Result<DmaBuffer<[MaybeUninit<u8>]>, Error>;
|
|
|
|
/// Perform a no-data request
|
|
async fn perform_request_raw(
|
|
&mut self,
|
|
lun: u8,
|
|
request_data: &[u8],
|
|
response_buffer: DmaSliceMut<'_, MaybeUninit<u8>>,
|
|
) -> Result<usize, Error>;
|
|
|
|
fn max_bytes_per_request(&self) -> usize;
|
|
}
|
|
|
|
pub struct ScsiTransportWrapper {
|
|
inner: Box<dyn ScsiTransport>,
|
|
}
|
|
|
|
impl ScsiTransportWrapper {
|
|
pub fn new<T: ScsiTransport + 'static>(inner: T) -> Self {
|
|
Self {
|
|
inner: Box::new(inner),
|
|
}
|
|
}
|
|
|
|
pub async fn read(
|
|
&mut self,
|
|
lun: u8,
|
|
lba: u64,
|
|
lba_count: u16,
|
|
buffer: DmaSliceMut<'_, MaybeUninit<u8>>,
|
|
) -> Result<usize, Error> {
|
|
if lba >= u32::MAX as u64 {
|
|
return Err(Error::InvalidArgument);
|
|
}
|
|
let lba_bytes = (lba as u32).to_be_bytes();
|
|
let lba_count = (lba_count as u16).to_be_bytes();
|
|
// Issue a READ (10) command
|
|
let request_buffer = [
|
|
0x28,
|
|
0x00,
|
|
lba_bytes[0],
|
|
lba_bytes[1],
|
|
lba_bytes[2],
|
|
lba_bytes[3],
|
|
0x00,
|
|
lba_count[0],
|
|
lba_count[1],
|
|
0x00,
|
|
];
|
|
|
|
self.inner
|
|
.perform_request_raw(lun, &request_buffer, buffer)
|
|
.await
|
|
}
|
|
|
|
pub async fn perform_command<R: ScsiCommand>(
|
|
&mut self,
|
|
lun: u8,
|
|
request: R,
|
|
) -> Result<R::Response, Error>
|
|
where
|
|
[u8; R::RESPONSE_LEN]: Sized,
|
|
[u8; R::REQUEST_LEN]: Sized,
|
|
{
|
|
let mut response_buffer = self.allocate_buffer(R::RESPONSE_LEN)?;
|
|
let request_buffer = request.into_bytes();
|
|
|
|
let response_len = self
|
|
.inner
|
|
.perform_request_raw(
|
|
lun,
|
|
&request_buffer,
|
|
response_buffer.slice_mut(0..R::RESPONSE_LEN),
|
|
)
|
|
.await?;
|
|
let response_bytes =
|
|
unsafe { MaybeUninit::slice_assume_init_ref(&response_buffer[..response_len]) };
|
|
|
|
R::parse_response(response_bytes)
|
|
}
|
|
}
|
|
|
|
impl Deref for ScsiTransportWrapper {
|
|
type Target = dyn ScsiTransport;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
self.inner.as_ref()
|
|
}
|
|
}
|