Implement READ CAPACITY 10.
This allows the block count and block size to be determined when no block descriptors in the mode sense data are returned.
This commit is contained in:
@@ -91,9 +91,11 @@ fn main() {
|
||||
|
||||
//syscall::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);
|
||||
|
||||
// TODO: Use nonblocking and put all pending calls in a todo VecDeque. Use an eventfd as well.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use super::opcodes::Opcode;
|
||||
use std::{fmt, mem, slice};
|
||||
use std::convert::TryInto;
|
||||
|
||||
#[repr(packed)]
|
||||
pub struct Inquiry {
|
||||
@@ -415,6 +416,47 @@ impl ModeParamHeader10 {
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct ReadCapacity10 {
|
||||
pub opcode: u8,
|
||||
_rsvd1: u8,
|
||||
obsolete_lba: u32,
|
||||
_rsvd2: [u8; 3],
|
||||
pub control: u8,
|
||||
}
|
||||
unsafe impl plain::Plain for ReadCapacity10 {}
|
||||
|
||||
impl ReadCapacity10 {
|
||||
pub const fn new(control: u8) -> Self {
|
||||
Self {
|
||||
opcode: Opcode::ReadCapacity10 as u8,
|
||||
_rsvd1: 0,
|
||||
obsolete_lba: 0,
|
||||
_rsvd2: [0; 3],
|
||||
control,
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: ReadCapacity16
|
||||
|
||||
#[repr(packed)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct ReadCapacity10ParamData {
|
||||
pub max_lba: u32,
|
||||
pub block_len: u32,
|
||||
}
|
||||
unsafe impl plain::Plain for ReadCapacity10ParamData {}
|
||||
|
||||
impl ReadCapacity10ParamData {
|
||||
pub const fn block_count(&self) -> u32 {
|
||||
u32::from_be(self.max_lba)
|
||||
}
|
||||
pub const fn logical_block_len(&self) -> u32 {
|
||||
u32::from_be(self.block_len)
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct RwErrorRecoveryPage {
|
||||
@@ -428,6 +470,15 @@ pub struct RwErrorRecoveryPage {
|
||||
}
|
||||
unsafe impl plain::Plain for RwErrorRecoveryPage {}
|
||||
|
||||
#[repr(packed)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct CachingModePage {
|
||||
pub a: u8,
|
||||
pub page_length: u8,
|
||||
// TODO: more
|
||||
}
|
||||
unsafe impl plain::Plain for CachingModePage {}
|
||||
|
||||
pub(crate) struct ModePageIterRaw<'a> {
|
||||
buffer: &'a [u8],
|
||||
}
|
||||
@@ -446,7 +497,7 @@ impl<'a> Iterator for ModePageIterRaw<'a> {
|
||||
self.buffer[1] as usize + 1
|
||||
} else {
|
||||
// item is sub_page mode
|
||||
self.buffer[2] as usize + 3
|
||||
u16::from_be_bytes((&self.buffer[2..3]).try_into().ok()?) as usize + 3
|
||||
};
|
||||
if self.buffer.len() < page_len {
|
||||
return None;
|
||||
@@ -466,6 +517,7 @@ impl<'a> Iterator for ModePageIterRaw<'a> {
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum AnyModePage<'a> {
|
||||
RwErrorRecovery(&'a RwErrorRecoveryPage),
|
||||
Caching(&'a CachingModePage)
|
||||
}
|
||||
|
||||
struct ModePageIter<'a> {
|
||||
@@ -487,6 +539,10 @@ impl<'a> Iterator for ModePageIter<'a> {
|
||||
Some(AnyModePage::RwErrorRecovery(
|
||||
plain::from_bytes(next_buf).ok()?,
|
||||
))
|
||||
} else if page_code == 0x08 {
|
||||
Some(AnyModePage::Caching(
|
||||
plain::from_bytes(next_buf).ok()?,
|
||||
))
|
||||
} else {
|
||||
println!("Unimplemented sub_page {}", base64::encode(next_buf));
|
||||
None
|
||||
|
||||
@@ -63,9 +63,20 @@ impl Scsi {
|
||||
let (block_size, block_count) = {
|
||||
let (_, blkdescs, mode_page_iter) = this.get_mode_sense10(protocol)?;
|
||||
|
||||
for page in mode_page_iter {
|
||||
println!("PAGE: {:?}", page);
|
||||
}
|
||||
|
||||
// TODO: Can there be multiple disks at all?
|
||||
let only_blkdesc = blkdescs.get(0).unwrap();
|
||||
(only_blkdesc.block_size(), only_blkdesc.block_count())
|
||||
if let Some(only_blkdesc) = blkdescs.get(0) {
|
||||
println!("Found block desc: {:?}", only_blkdesc);
|
||||
(only_blkdesc.block_size(), only_blkdesc.block_count())
|
||||
} else {
|
||||
println!("read_capacity10");
|
||||
let r = this.read_capacity(protocol)?;
|
||||
println!("read_capacity10 result: {:?}", r);
|
||||
(r.logical_block_len(), r.block_count().into())
|
||||
}
|
||||
};
|
||||
|
||||
this.block_size = block_size;
|
||||
@@ -100,6 +111,18 @@ impl Scsi {
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
pub fn read_capacity(&mut self, protocol: &mut dyn Protocol) -> Result<&cmds::ReadCapacity10ParamData> {
|
||||
// The spec explicitly states that the allocation length is 8 bytes.
|
||||
let read_capacity10 = self.cmd_read_capacity10();
|
||||
*read_capacity10 = cmds::ReadCapacity10::new(0);
|
||||
self.data_buffer.resize(10usize, 0u8);
|
||||
protocol
|
||||
.send_command(
|
||||
&self.command_buffer[..10],
|
||||
DeviceReqData::In(&mut self.data_buffer[..8]),
|
||||
)?;
|
||||
Ok(self.res_read_capacity10())
|
||||
}
|
||||
pub fn get_mode_sense10(
|
||||
&mut self,
|
||||
protocol: &mut dyn Protocol,
|
||||
@@ -156,6 +179,9 @@ impl Scsi {
|
||||
pub fn cmd_request_sense(&mut self) -> &mut cmds::RequestSense {
|
||||
plain::from_mut_bytes(&mut self.command_buffer).unwrap()
|
||||
}
|
||||
pub fn cmd_read_capacity10(&mut self) -> &mut cmds::ReadCapacity10 {
|
||||
plain::from_mut_bytes(&mut self.command_buffer).unwrap()
|
||||
}
|
||||
pub fn cmd_read16(&mut self) -> &mut cmds::Read16 {
|
||||
plain::from_mut_bytes(&mut self.command_buffer).unwrap()
|
||||
}
|
||||
@@ -221,6 +247,9 @@ impl Scsi {
|
||||
let buffer = &self.data_buffer[descs_start + header.block_desc_len() as usize..];
|
||||
cmds::mode_page_iter(buffer)
|
||||
}
|
||||
pub fn res_read_capacity10(&self) -> &cmds::ReadCapacity10ParamData {
|
||||
plain::from_bytes(&self.data_buffer).unwrap()
|
||||
}
|
||||
pub fn get_disk_size(&mut self) -> u64 {
|
||||
self.block_count * u64::from(self.block_size)
|
||||
}
|
||||
@@ -230,21 +259,23 @@ impl Scsi {
|
||||
lba: u64,
|
||||
buffer: &mut [u8],
|
||||
) -> Result<u32> {
|
||||
let blocks_to_read = buffer.len() as u64 / u64::from(self.block_size);
|
||||
let bytes_to_read = blocks_to_read as usize * self.block_size as usize;
|
||||
let transfer_len = u32::try_from(blocks_to_read).or(Err(ScsiError::Overflow(
|
||||
let blocks_to_read = dbg!(buffer.len() as u64 / u64::from(dbg!(self.block_size)));
|
||||
let bytes_to_read = dbg!(blocks_to_read as usize * self.block_size as usize);
|
||||
let transfer_len = dbg!(u32::try_from(blocks_to_read).or(Err(ScsiError::Overflow(
|
||||
"number of blocks to read couldn't fit inside a u32",
|
||||
)))?;
|
||||
)))?);
|
||||
{
|
||||
let read = self.cmd_read16();
|
||||
*read = cmds::Read16::new(lba, transfer_len, 0);
|
||||
}
|
||||
// TODO: Use the to-be-written TransferReadStream instead of relying on everything being
|
||||
// able to fit within a single buffer.
|
||||
self.data_buffer.resize(bytes_to_read, 0u8);
|
||||
let status = protocol.send_command(
|
||||
&self.command_buffer[..16],
|
||||
DeviceReqData::In(&mut buffer[..bytes_to_read]),
|
||||
DeviceReqData::In(&mut self.data_buffer[..bytes_to_read]),
|
||||
)?;
|
||||
buffer[..bytes_to_read].copy_from_slice(&self.data_buffer[..bytes_to_read]);
|
||||
Ok(status.bytes_transferred(bytes_to_read as u32))
|
||||
}
|
||||
pub fn write(
|
||||
|
||||
Reference in New Issue
Block a user