Basic MSC disk working!
This commit is contained in:
@ -3,14 +3,31 @@ pub mod block_device;
|
||||
pub mod commands;
|
||||
pub mod enums;
|
||||
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use self::block_device::BlockDevice;
|
||||
use crate::class::msc::subclass::scsi::commands::inquiry::InquiryCommand;
|
||||
use crate::class::msc::subclass::scsi::commands::{
|
||||
CachingModePage, InquiryCommand, InquiryResponse, ModeParameterHeader6, ModeSense6Command, PageCode,
|
||||
PreventAllowMediumRemoval, Read10Command, ReadCapacity10Command, ReadCapacity10Response,
|
||||
ReadFormatCapacitiesCommand, ReadFormatCapacitiesResponse, RequestSenseCommand, RequestSenseResponse,
|
||||
TestUnitReadyCommand, Write10Command,
|
||||
};
|
||||
use crate::class::msc::subclass::scsi::enums::{
|
||||
PeripheralDeviceType, PeripheralQualifier, ResponseCode, ResponseDataFormat, SenseKey, SpcVersion,
|
||||
TargetPortGroupSupport,
|
||||
};
|
||||
use crate::class::msc::transport::{self, CommandSetHandler};
|
||||
|
||||
pub struct Scsi<B: BlockDevice> {
|
||||
device: B,
|
||||
}
|
||||
|
||||
impl<B: BlockDevice> Scsi<B> {
|
||||
pub fn new(device: B) -> Self {
|
||||
Self { device }
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: BlockDevice> CommandSetHandler for Scsi<B> {
|
||||
async fn command_out(
|
||||
&mut self,
|
||||
@ -22,14 +39,43 @@ impl<B: BlockDevice> CommandSetHandler for Scsi<B> {
|
||||
|
||||
let op_code = cmd[0];
|
||||
match op_code {
|
||||
InquiryCommand::OPCODE => {
|
||||
let cmd = InquiryCommand::from_bytes(cmd);
|
||||
// info!("inquiry: {:#?}", cmd);
|
||||
TestUnitReadyCommand::OPCODE => {
|
||||
info!("TestUnitReadyCommand: {:#?}", TestUnitReadyCommand::from_bytes(cmd));
|
||||
return Ok(());
|
||||
}
|
||||
_ => warn!("Unknown opcode: {}", op_code),
|
||||
PreventAllowMediumRemoval::OPCODE => match PreventAllowMediumRemoval::from_bytes(cmd) {
|
||||
Some(req) => {
|
||||
info!("PreventAllowMediumRemoval: {:?}", req);
|
||||
return Ok(());
|
||||
}
|
||||
None => error!("Error parsing PreventAllowMediumRemoval"),
|
||||
},
|
||||
Write10Command::OPCODE => match Write10Command::from_bytes(cmd) {
|
||||
Some(req) => {
|
||||
info!("Write10Command: {:?}", req);
|
||||
|
||||
let mut data = MaybeUninit::<[u8; 512]>::uninit();
|
||||
|
||||
let start_lba = req.lba();
|
||||
let transfer_length = req.transfer_length() as u32;
|
||||
|
||||
if start_lba + transfer_length - 1 > self.device.num_blocks() {
|
||||
return Err(transport::CommandError::CommandError);
|
||||
}
|
||||
|
||||
for lba in start_lba..start_lba + transfer_length {
|
||||
pipe.read(unsafe { data.assume_init_mut() }).await?;
|
||||
self.device.write_block(lba, unsafe { data.assume_init_ref() }).unwrap();
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
None => error!("Error parsing Write10Command"),
|
||||
},
|
||||
_ => warn!("Unknown OUT opcode: {}", op_code),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Err(transport::CommandError::CommandError)
|
||||
}
|
||||
|
||||
async fn command_in(
|
||||
@ -40,6 +86,133 @@ impl<B: BlockDevice> CommandSetHandler for Scsi<B> {
|
||||
) -> Result<(), transport::CommandError> {
|
||||
assert!(lun == 0, "LUNs are not supported");
|
||||
|
||||
Ok(())
|
||||
let op_code = cmd[0];
|
||||
info!("op_code: {}", op_code);
|
||||
match op_code {
|
||||
InquiryCommand::OPCODE => match InquiryCommand::from_bytes(cmd) {
|
||||
Some(req) => {
|
||||
info!("inquiry: {:#?}", req);
|
||||
|
||||
let vendor_ident = b"FAKE ";
|
||||
let product_ident = b"PRODUCT ";
|
||||
|
||||
let mut resp = InquiryResponse::new();
|
||||
resp.set_peripheral_device_type(PeripheralDeviceType::DirectAccessBlock);
|
||||
resp.set_peripheral_qualifier(PeripheralQualifier::Connected);
|
||||
resp.set_removable_medium(true);
|
||||
resp.set_version(SpcVersion::Spc3);
|
||||
resp.set_response_data_format(ResponseDataFormat::Standard);
|
||||
resp.set_hierarchical_support(false);
|
||||
resp.set_normal_aca(false);
|
||||
resp.set_additional_length((InquiryResponse::SIZE - 4) as u8);
|
||||
resp.set_protect(false);
|
||||
resp.set_third_party_copy(false);
|
||||
resp.set_target_port_group_support(TargetPortGroupSupport::Unsupported);
|
||||
resp.set_access_controls_coordinator(false);
|
||||
resp.set_scc_supported(false);
|
||||
resp.set_multi_port(false);
|
||||
resp.set_enclosure_services(false);
|
||||
resp.set_vendor_identification(vendor_ident);
|
||||
resp.set_product_identification(product_ident);
|
||||
resp.set_product_revision_level(&[b' '; 4]);
|
||||
|
||||
pipe.write(&resp.data).await?;
|
||||
return Ok(());
|
||||
}
|
||||
None => error!("Error parsing InquiryCommand"),
|
||||
},
|
||||
ModeSense6Command::OPCODE => match ModeSense6Command::from_bytes(cmd) {
|
||||
Some(req) => {
|
||||
info!("ModeSense6Command: {:?}", req);
|
||||
|
||||
// let mut buf = [0u8; ModeParameterHeader6::SIZE + CachingModePage::SIZE];
|
||||
|
||||
// let mut header = ModeParameterHeader6::from_bytes(&mut buf[0..ModeSense6Command::SIZE]).unwrap();
|
||||
// header.set_mode_data_length((ModeParameterHeader6::SIZE + CachingModePage::SIZE - 1) as u8);
|
||||
|
||||
// let mut caching_mode_page =
|
||||
// CachingModePage::from_bytes(&mut buf[ModeParameterHeader6::SIZE..]).unwrap();
|
||||
// caching_mode_page.set_page_code(PageCode::CachingModePage);
|
||||
// caching_mode_page.set_page_length(CachingModePage::SIZE as u8);
|
||||
// caching_mode_page.set_read_cache_disable(true);
|
||||
// caching_mode_page.set_write_cache_enable(false);
|
||||
|
||||
// pipe.write(&buf).await?;
|
||||
|
||||
let mut header = ModeParameterHeader6::new();
|
||||
header.set_mode_data_length(ModeParameterHeader6::SIZE as u8 - 1);
|
||||
pipe.write(&header.data).await?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
None => error!("Error parsing ModeSense6Command"),
|
||||
},
|
||||
RequestSenseCommand::OPCODE => match RequestSenseCommand::from_bytes(cmd) {
|
||||
Some(req) => {
|
||||
info!("RequestSenseCommand: {:?}", req);
|
||||
|
||||
let mut resp = RequestSenseResponse::new();
|
||||
resp.set_response_code(ResponseCode::CurrentFixedSenseData);
|
||||
resp.set_sense_key(SenseKey::NoSense);
|
||||
|
||||
pipe.write(&resp.data).await?;
|
||||
return Ok(());
|
||||
}
|
||||
None => error!("Error parsing RequestSenseCommand"),
|
||||
},
|
||||
ReadCapacity10Command::OPCODE => match ReadCapacity10Command::from_bytes(cmd) {
|
||||
Some(req) => {
|
||||
info!("ReadCapacity10Command: {:?}", req);
|
||||
|
||||
let mut resp = ReadCapacity10Response::new();
|
||||
resp.set_max_lba(self.device.num_blocks());
|
||||
resp.set_block_size(self.device.block_size() as u32);
|
||||
|
||||
pipe.write(&resp.data).await?;
|
||||
return Ok(());
|
||||
}
|
||||
None => error!("Error parsing ReadCapacity10Command"),
|
||||
},
|
||||
ReadFormatCapacitiesCommand::OPCODE => match ReadFormatCapacitiesCommand::from_bytes(cmd) {
|
||||
Some(req) => {
|
||||
info!("ReadFormatCapacitiesCommand: {:?}", req);
|
||||
|
||||
let mut resp = ReadFormatCapacitiesResponse::new();
|
||||
resp.set_capacity_list_length(8);
|
||||
resp.set_max_lba(self.device.num_blocks());
|
||||
resp.set_block_size(self.device.block_size() as u32);
|
||||
|
||||
pipe.write(&resp.data).await?;
|
||||
return Ok(());
|
||||
}
|
||||
None => error!("Error parsing ReadFormatCapacitiesCommand"),
|
||||
},
|
||||
Read10Command::OPCODE => match Read10Command::from_bytes(cmd) {
|
||||
Some(req) => {
|
||||
info!("Read10: {:?} {:?}", req, cmd);
|
||||
|
||||
let mut data = MaybeUninit::<[u8; 512]>::uninit();
|
||||
|
||||
let start_lba = req.lba();
|
||||
let transfer_length = req.transfer_length() as u32;
|
||||
|
||||
if start_lba + transfer_length - 1 > self.device.num_blocks() {
|
||||
return Err(transport::CommandError::CommandError);
|
||||
}
|
||||
|
||||
for lba in start_lba..start_lba + transfer_length {
|
||||
self.device.read_block(lba, unsafe { data.assume_init_mut() }).unwrap();
|
||||
|
||||
pipe.write(unsafe { data.assume_init_ref() }).await?;
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
None => error!("Error parsing Read10Command"),
|
||||
},
|
||||
_ => warn!("Unknown IN opcode: {}", op_code),
|
||||
}
|
||||
|
||||
Err(transport::CommandError::CommandError)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user