troubleshooting scsi block errors

This commit is contained in:
2025-07-29 01:02:54 -06:00
parent 60ed910a88
commit 7ed35fb771
2 changed files with 60 additions and 25 deletions

View File

@@ -44,7 +44,7 @@ impl<'d, D: Driver<'d>> MassStorageClass<'d, D> {
if self.handle_command(&cbw.CBWCB).await.is_ok() { if self.handle_command(&cbw.CBWCB).await.is_ok() {
self.send_csw_success(cbw.dCBWTag).await self.send_csw_success(cbw.dCBWTag).await
} else { } else {
self.send_csw_success(cbw.dCBWTag).await self.send_csw_fail(cbw.dCBWTag).await
} }
} }
} }
@@ -59,7 +59,7 @@ impl<'d, D: Driver<'d>> MassStorageClass<'d, D> {
match parse_cb(cbw) { match parse_cb(cbw) {
ScsiCommand::Unknown => { ScsiCommand::Unknown => {
#[cfg(feature = "defmt")] #[cfg(feature = "defmt")]
defmt::info!("Got unexpected scsi command: {}", cbw); defmt::warn!("Got unexpected scsi command: {}", cbw);
Err(()) Err(())
} }
ScsiCommand::Inquiry { ScsiCommand::Inquiry {
@@ -72,28 +72,27 @@ impl<'d, D: Driver<'d>> MassStorageClass<'d, D> {
response.push(0x80).map_err(|_| ())?; // Removable response.push(0x80).map_err(|_| ())?; // Removable
response.push(0x05).map_err(|_| ())?; // SPC-3 compliance response.push(0x05).map_err(|_| ())?; // SPC-3 compliance
response.push(0x02).map_err(|_| ())?; // Response data format response.push(0x02).map_err(|_| ())?; // Response data format
response.push(0).map_err(|_| ())?; // Additional length response.push(0x00).map_err(|_| ())?; // Additional length - edited later
response.push(0x00).map_err(|_| ())?; // FLAGS
response.push(0x00).map_err(|_| ())?; // FLAGS
response.push(0).map_err(|_| ())?; // FLAGS
assert!(response.len() == 8);
// Vendor ID (8 bytes) let vendor = b"LEGTCMPR";
response.extend_from_slice(b"LEGTCMPR")?; assert!(vendor.len() == 8);
// Product ID (16 bytes) response.extend_from_slice(vendor)?;
response.extend_from_slice(b"Pico Calc Sdcard")?;
// Product Revision (4 bytes): encode volume size in GB let product = b"Pico Calc Sdcard";
let size_bytes = self.sdcard.size(); assert!(product.len() == 16);
let size_gb = ((size_bytes + 500_000_000) / 1_000_000_000) as u32; response.extend_from_slice(product)?;
let rev_str = format!(4, "{}", size_gb);
let rev_bytes = rev_str.as_bytes(); let version = b"1.00";
response.extend_from_slice(&[ assert!(version.len() == 4);
*rev_bytes.get(0).unwrap_or(&b'0'), response.extend_from_slice(version)?; // 4-byte firmware version
*rev_bytes.get(1).unwrap_or(&b'0'),
*rev_bytes.get(2).unwrap_or(&b'0'),
*rev_bytes.get(3).unwrap_or(&b'0'),
])?;
let addl_len = response.len() - 5; let addl_len = response.len() - 5;
response[4] = addl_len as u8; response[4] = addl_len as u8;
assert!(response.len() == 36);
} else { } else {
match page_code { match page_code {
0x00 => { 0x00 => {
@@ -153,19 +152,43 @@ impl<'d, D: Driver<'d>> MassStorageClass<'d, D> {
page_code, page_code,
subpage_code, subpage_code,
alloc_len, alloc_len,
} => Ok(()), } => {
// DBD=0, no block descriptors; total length = 4
let response = [
0x03, // Mode data length (excluding this byte): 3
0x00, // Medium type
0x00, // Device-specific parameter
0x00, // Block descriptor length = 0 (DBD = 1)
];
let len = alloc_len.min(response.len() as u8) as usize;
self.bulk_in.write(&response[..len]).await.map_err(|_| ())
}
ScsiCommand::ModeSense10 { ScsiCommand::ModeSense10 {
dbd, dbd,
page_control, page_control,
page_code, page_code,
subpage_code, subpage_code,
alloc_len, alloc_len,
} => Ok(()), } => {
let response = [
0x00, 0x06, // Mode data length = 6
0x00, // Medium type
0x00, // Device-specific parameter
0x00, 0x00, // Reserved
0x00, 0x00, // Block descriptor length = 0
];
let len = alloc_len.min(response.len() as u16) as usize;
self.bulk_in.write(&response[..len]).await.map_err(|_| ())
}
ScsiCommand::ReadCapacity10 => { ScsiCommand::ReadCapacity10 => {
let block_size = SdCard::BLOCK_SIZE as u64; let block_size = SdCard::BLOCK_SIZE as u64;
let total_blocks = self.sdcard.size() / block_size; let total_blocks = self.sdcard.size() / block_size;
let last_lba = total_blocks - 1; let last_lba = total_blocks.checked_sub(1).unwrap_or(0);
response.extend_from_slice(&(last_lba as u32).to_be_bytes())?; response.extend_from_slice(&(last_lba as u32).to_be_bytes())?;
response.extend_from_slice(&(block_size as u32).to_be_bytes())?; response.extend_from_slice(&(block_size as u32).to_be_bytes())?;
@@ -178,9 +201,9 @@ impl<'d, D: Driver<'d>> MassStorageClass<'d, D> {
let last_lba = total_blocks.checked_sub(1).unwrap_or(0); let last_lba = total_blocks.checked_sub(1).unwrap_or(0);
response.extend_from_slice(&last_lba.to_be_bytes()); // 8 bytes last LBA response.extend_from_slice(&last_lba.to_be_bytes())?; // 8 bytes last LBA
response.extend_from_slice(&(block_size as u32).to_be_bytes()); // 4 bytes block length response.extend_from_slice(&(block_size as u32).to_be_bytes())?; // 4 bytes block length
response.extend_from_slice(&[0u8; 20]); // 20 reserved bytes zeroed response.extend_from_slice(&[0u8; 20])?; // 20 reserved bytes zeroed
let len = alloc_len.min(response.len() as u32) as usize; let len = alloc_len.min(response.len() as u32) as usize;
self.bulk_in.write(&response[..len]).await.map_err(|_| ()) self.bulk_in.write(&response[..len]).await.map_err(|_| ())
@@ -188,6 +211,7 @@ impl<'d, D: Driver<'d>> MassStorageClass<'d, D> {
ScsiCommand::Read { lba, len } => { ScsiCommand::Read { lba, len } => {
for i in 0..len { for i in 0..len {
let block_idx = BlockIdx(lba as u32 + i as u32); let block_idx = BlockIdx(lba as u32 + i as u32);
defmt::info!("Reading LBA {} (block idx: {:?})", lba, block_idx);
self.sdcard.read_blocks(&mut block, block_idx); self.sdcard.read_blocks(&mut block, block_idx);
self.bulk_in self.bulk_in
.write(&block[0].contents) .write(&block[0].contents)
@@ -218,7 +242,7 @@ impl<'d, D: Driver<'d>> MassStorageClass<'d, D> {
// Descriptor // Descriptor
response[4..8].copy_from_slice(&num_blocks.to_be_bytes()); response[4..8].copy_from_slice(&num_blocks.to_be_bytes());
response[8] = 0x02; // formatted media response[8] = 0x03; // formatted media
response[9..12].copy_from_slice(&block_size.to_be_bytes()[1..4]); // only 3 bytes response[9..12].copy_from_slice(&block_size.to_be_bytes()[1..4]); // only 3 bytes
let response_len = alloc_len.min(response.len() as u16) as usize; let response_len = alloc_len.min(response.len() as u16) as usize;
@@ -227,6 +251,7 @@ impl<'d, D: Driver<'d>> MassStorageClass<'d, D> {
.await .await
.map_err(|_| ()) .map_err(|_| ())
} }
ScsiCommand::PreventAllowMediumRemoval { prevent: _prevent } => Ok(()),
} }
} }
@@ -235,6 +260,7 @@ impl<'d, D: Driver<'d>> MassStorageClass<'d, D> {
} }
pub async fn send_csw_fail(&mut self, tag: u32) { pub async fn send_csw_fail(&mut self, tag: u32) {
defmt::error!("Command Failed");
self.send_csw(tag, 0x01, 0).await; // 0x01 = Command Failed self.send_csw(tag, 0x01, 0).await; // 0x01 = Command Failed
} }

View File

@@ -32,6 +32,8 @@ const WRITE_10: u8 = 0x2A;
/* MMC */ /* MMC */
const READ_FORMAT_CAPACITIES: u8 = 0x23; const READ_FORMAT_CAPACITIES: u8 = 0x23;
const PREVENT_ALLOW_MEDIUM_REMOVAL: u8 = 0x1E;
/// SCSI command /// SCSI command
/// ///
/// Refer to specifications (SPC,SAM,SBC,MMC,etc.) /// Refer to specifications (SPC,SAM,SBC,MMC,etc.)
@@ -85,6 +87,10 @@ pub enum ScsiCommand {
ReadFormatCapacities { ReadFormatCapacities {
alloc_len: u16, alloc_len: u16,
}, },
PreventAllowMediumRemoval {
prevent: bool,
},
} }
#[repr(u8)] #[repr(u8)]
@@ -143,6 +149,9 @@ pub fn parse_cb(cb: &[u8]) -> ScsiCommand {
READ_FORMAT_CAPACITIES => ScsiCommand::ReadFormatCapacities { READ_FORMAT_CAPACITIES => ScsiCommand::ReadFormatCapacities {
alloc_len: u16::from_be_bytes([cb[7], cb[8]]), alloc_len: u16::from_be_bytes([cb[7], cb[8]]),
}, },
PREVENT_ALLOW_MEDIUM_REMOVAL => ScsiCommand::PreventAllowMediumRemoval {
prevent: (cb[1] & 0b00000001) != 0,
},
_ => ScsiCommand::Unknown, _ => ScsiCommand::Unknown,
} }
} }