troubleshooting scsi block errors
This commit is contained in:
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user