// pub mod bitfield; 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::{ 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 { device: B, } impl Scsi { pub fn new(device: B) -> Self { Self { device } } } impl CommandSetHandler for Scsi { async fn command_out( &mut self, lun: u8, cmd: &[u8], pipe: &mut impl transport::DataPipeOut, ) -> Result<(), transport::CommandError> { assert!(lun == 0, "LUNs are not supported"); let op_code = cmd[0]; match op_code { TestUnitReadyCommand::OPCODE => { info!("TestUnitReadyCommand: {:#?}", TestUnitReadyCommand::from_bytes(cmd)); return Ok(()); } 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), } Err(transport::CommandError::CommandError) } async fn command_in( &mut self, lun: u8, cmd: &[u8], pipe: &mut impl transport::DataPipeIn, ) -> Result<(), transport::CommandError> { assert!(lun == 0, "LUNs are not supported"); 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) } }