diff --git a/src/scsi/mod.rs b/src/scsi/mod.rs index 605bcfb..56c8c1a 100644 --- a/src/scsi/mod.rs +++ b/src/scsi/mod.rs @@ -12,8 +12,15 @@ use crate::storage::SdCard; const BULK_ENDPOINT_PACKET_SIZE: usize = 64; +#[derive(PartialEq, Eq)] +enum State { + Ready, + Ejected, +} + pub struct MassStorageClass<'d, D: Driver<'d>> { sdcard: SdCard, + state: State, bulk_out: D::EndpointOut, bulk_in: D::EndpointIn, last_sense: Option, @@ -32,6 +39,7 @@ impl<'d, D: Driver<'d>> MassStorageClass<'d, D> { bulk_out, bulk_in, sdcard, + state: State::Ready, last_sense: None, } } @@ -42,6 +50,12 @@ impl<'d, D: Driver<'d>> MassStorageClass<'d, D> { if let Ok(n) = self.bulk_out.read(&mut cbw_buf).await { if n == 31 { if let Some(cbw) = CommandBlockWrapper::parse(&cbw_buf[..n]) { + if self.state == State::Ejected { + self.last_sense = Some(ScsiError::NotReady); + self.send_csw_fail(cbw.dCBWTag).await; + continue; + } + // TODO: validate cbw if self.handle_command(&cbw.CBWCB).await.is_ok() { self.send_csw_success(cbw.dCBWTag).await @@ -213,7 +227,7 @@ impl<'d, D: Driver<'d>> MassStorageClass<'d, D> { ScsiCommand::Read { lba, len } => { for i in 0..len { let block_idx = BlockIdx(lba as u32 + i as u32); - self.sdcard.read_blocks(&mut block, block_idx); + self.sdcard.read_blocks(&mut block, block_idx)?; for chunk in block[0].contents.chunks(BULK_ENDPOINT_PACKET_SIZE.into()) { self.bulk_in.write(chunk).await.map_err(|_| ())?; } @@ -227,9 +241,9 @@ impl<'d, D: Driver<'d>> MassStorageClass<'d, D> { .contents .chunks_mut(BULK_ENDPOINT_PACKET_SIZE.into()) { - slf.bulk_out.read(chunk).await.map_err(|_| ())?; + self.bulk_out.read(chunk).await.map_err(|_| ())?; } - self.sdcard.write_blocks(&mut block, block_idx); + self.sdcard.write_blocks(&mut block, block_idx)?; } Ok(()) } @@ -254,6 +268,13 @@ impl<'d, D: Driver<'d>> MassStorageClass<'d, D> { .map_err(|_| ()) } ScsiCommand::PreventAllowMediumRemoval { prevent: _prevent } => Ok(()), + ScsiCommand::StartStopUnit { stop, load_eject } => { + if stop && load_eject { + self.state = State::Ejected; + self.last_sense = Some(ScsiError::NotReady); + } + Ok(()) + } } } diff --git a/src/scsi/scsi_types.rs b/src/scsi/scsi_types.rs index be0bb81..a9fcfc3 100644 --- a/src/scsi/scsi_types.rs +++ b/src/scsi/scsi_types.rs @@ -2,10 +2,7 @@ use num_enum::TryFromPrimitive; #[derive(Debug, Clone, Copy)] pub enum ScsiError { - IllegalRequest { asc: u8, ascq: u8 }, - NotReady { asc: u8, ascq: u8 }, - MediumError { asc: u8, ascq: u8 }, - // Add others as needed + NotReady, } /// THE CODE BELOW ORIGINATES FROM: https://github.com/apohrebniak/usbd-storage/blob/master/usbd-storage/src/subclass/scsi.rs @@ -33,6 +30,7 @@ const WRITE_10: u8 = 0x2A; const READ_FORMAT_CAPACITIES: u8 = 0x23; const PREVENT_ALLOW_MEDIUM_REMOVAL: u8 = 0x1E; +const START_STOP_UNIT: u8 = 0x1B; /// SCSI command /// @@ -91,6 +89,11 @@ pub enum ScsiCommand { PreventAllowMediumRemoval { prevent: bool, }, + + StartStopUnit { + stop: bool, + load_eject: bool, + }, } #[repr(u8)] @@ -152,6 +155,10 @@ pub fn parse_cb(cb: &[u8]) -> ScsiCommand { PREVENT_ALLOW_MEDIUM_REMOVAL => ScsiCommand::PreventAllowMediumRemoval { prevent: (cb[1] & 0b00000001) != 0, }, + START_STOP_UNIT => ScsiCommand::StartStopUnit { + stop: (cb[1] & 0b00000001) != 0, + load_eject: (cb[1] & 0b00000010) == 0, + }, _ => ScsiCommand::Unknown, } } diff --git a/src/storage.rs b/src/storage.rs index f41a56b..ad1a8fa 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -1,12 +1,11 @@ -use embassy_futures::block_on; use embassy_rp::gpio::{Input, Output}; use embassy_rp::peripherals::SPI0; use embassy_rp::spi::{Blocking, Spi}; +use embassy_time::Delay; use embedded_hal_bus::spi::ExclusiveDevice; -use embedded_sdmmc::{self, Block, BlockIdx}; use embedded_sdmmc::{ - BlockCount, BlockDevice, Directory, SdCard as SdmmcSdCard, TimeSource, Timestamp, Volume, - VolumeIdx, VolumeManager, + Block, BlockCount, BlockDevice, BlockIdx, Directory, SdCard as SdmmcSdCard, TimeSource, + Timestamp, Volume, VolumeIdx, VolumeManager, sdcard::Error, }; pub const MAX_DIRS: usize = 4; @@ -14,7 +13,7 @@ pub const MAX_FILES: usize = 5; pub const MAX_VOLUMES: usize = 1; type Device = ExclusiveDevice, Output<'static>, embassy_time::Delay>; -type SD = SdmmcSdCard; +type SD = SdmmcSdCard; type VolMgr = VolumeManager; type Vol<'a> = Volume<'a, SD, DummyTimeSource, MAX_DIRS, MAX_FILES, MAX_VOLUMES>; type Dir<'a> = Directory<'a, SD, DummyTimeSource, MAX_DIRS, MAX_FILES, MAX_VOLUMES>; @@ -83,17 +82,21 @@ impl SdCard { result } - pub fn read_blocks(&self, blocks: &mut [Block], start_block_idx: BlockIdx) { + pub fn read_blocks(&self, blocks: &mut [Block], start_block_idx: BlockIdx) -> Result<(), ()> { + let mut res: Result<(), Error> = Ok(()); self.volume_mgr.device(|sd| { - sd.read(blocks, start_block_idx); + res = sd.read(blocks, start_block_idx); DummyTimeSource {} }); + res.map_err(|_| ()) } - pub fn write_blocks(&self, blocks: &mut [Block], start_block_idx: BlockIdx) { + pub fn write_blocks(&self, blocks: &mut [Block], start_block_idx: BlockIdx) -> Result<(), ()> { + let mut res: Result<(), Error> = Ok(()); self.volume_mgr.device(|sd| { - sd.write(blocks, start_block_idx); + let res = sd.write(blocks, start_block_idx); DummyTimeSource {} }); + res.map_err(|_| ()) } }