⚠️ VeridianOS Kernel Documentation - This is low-level kernel code. All functions are unsafe unless explicitly marked otherwise. no_std

veridian_kernel/drivers/usb/
mass_storage.rs

1//! USB Mass Storage Class Driver
2//!
3//! Implements the USB Mass Storage Bulk-Only Transport (BOT) protocol with
4//! SCSI Transparent Command Set for block device access. Supports standard
5//! SCSI commands: INQUIRY, TEST UNIT READY, READ CAPACITY(10), READ(10),
6//! WRITE(10), and REQUEST SENSE.
7//!
8//! Reference: USB Mass Storage Class Bulk-Only Transport Specification Rev 1.0
9
10#![allow(dead_code)]
11
12#[cfg(feature = "alloc")]
13extern crate alloc;
14
15#[cfg(feature = "alloc")]
16use alloc::vec::Vec;
17use core::sync::atomic::{AtomicU32, Ordering};
18
19use crate::error::KernelError;
20
21// ---------------------------------------------------------------------------
22// SCSI Command Opcodes
23// ---------------------------------------------------------------------------
24
25/// SCSI command opcodes used with USB Mass Storage BOT
26mod scsi_opcodes {
27    pub const TEST_UNIT_READY: u8 = 0x00;
28    pub const REQUEST_SENSE: u8 = 0x03;
29    pub const INQUIRY: u8 = 0x12;
30    pub const READ_CAPACITY_10: u8 = 0x25;
31    pub const READ_10: u8 = 0x28;
32    pub const WRITE_10: u8 = 0x2A;
33}
34
35// ---------------------------------------------------------------------------
36// SCSI Sense Key Definitions
37// ---------------------------------------------------------------------------
38
39/// SCSI sense keys for error reporting
40#[derive(Debug, Clone, Copy, PartialEq, Eq)]
41#[repr(u8)]
42pub enum SenseKey {
43    NoSense = 0x00,
44    RecoveredError = 0x01,
45    NotReady = 0x02,
46    MediumError = 0x03,
47    HardwareError = 0x04,
48    IllegalRequest = 0x05,
49    UnitAttention = 0x06,
50    DataProtect = 0x07,
51    BlankCheck = 0x08,
52    AbortedCommand = 0x0B,
53    VolumeOverflow = 0x0D,
54    Miscompare = 0x0E,
55}
56
57impl SenseKey {
58    /// Parse a sense key from a raw byte value
59    pub fn from_byte(byte: u8) -> Self {
60        match byte & 0x0F {
61            0x00 => Self::NoSense,
62            0x01 => Self::RecoveredError,
63            0x02 => Self::NotReady,
64            0x03 => Self::MediumError,
65            0x04 => Self::HardwareError,
66            0x05 => Self::IllegalRequest,
67            0x06 => Self::UnitAttention,
68            0x07 => Self::DataProtect,
69            0x08 => Self::BlankCheck,
70            0x0B => Self::AbortedCommand,
71            0x0D => Self::VolumeOverflow,
72            0x0E => Self::Miscompare,
73            _ => Self::HardwareError,
74        }
75    }
76}
77
78// ---------------------------------------------------------------------------
79// Command Block Wrapper (CBW)
80// ---------------------------------------------------------------------------
81
82/// CBW signature: "USBC" in little-endian
83pub const CBW_SIGNATURE: u32 = 0x43425355;
84
85/// CBW direction flags
86pub const CBW_DIRECTION_OUT: u8 = 0x00;
87pub const CBW_DIRECTION_IN: u8 = 0x80;
88
89/// Command Block Wrapper (31 bytes)
90///
91/// Sent from host to device on the Bulk-Out endpoint to initiate a command.
92#[repr(C, packed)]
93#[derive(Debug, Clone, Copy)]
94pub struct CommandBlockWrapper {
95    /// Signature: must be CBW_SIGNATURE (0x43425355)
96    pub signature: u32,
97    /// Tag: unique per-command identifier, echoed in CSW
98    pub tag: u32,
99    /// Data transfer length in bytes
100    pub data_transfer_length: u32,
101    /// Flags: bit 7 = direction (0 = OUT, 1 = IN)
102    pub flags: u8,
103    /// Logical Unit Number (bits 3:0)
104    pub lun: u8,
105    /// Length of the command block (1-16)
106    pub cb_length: u8,
107    /// SCSI Command Descriptor Block (16 bytes, zero-padded)
108    pub cb: [u8; 16],
109}
110
111impl CommandBlockWrapper {
112    /// Size of a CBW in bytes
113    pub const SIZE: usize = 31;
114
115    /// Create a new CBW with default values
116    pub fn new(tag: u32, data_length: u32, direction: u8, lun: u8, command: &[u8]) -> Self {
117        let cb_len = command.len().min(16) as u8;
118        let mut cb = [0u8; 16];
119        let copy_len = command.len().min(16);
120        cb[..copy_len].copy_from_slice(&command[..copy_len]);
121
122        Self {
123            signature: CBW_SIGNATURE,
124            tag,
125            data_transfer_length: data_length,
126            flags: direction,
127            lun: lun & 0x0F,
128            cb_length: cb_len,
129            cb,
130        }
131    }
132
133    /// Serialize the CBW to a 31-byte array (little-endian)
134    pub fn to_bytes(&self) -> [u8; Self::SIZE] {
135        let mut buf = [0u8; Self::SIZE];
136        let sig = self.signature.to_le_bytes();
137        buf[0..4].copy_from_slice(&sig);
138        let tag = self.tag.to_le_bytes();
139        buf[4..8].copy_from_slice(&tag);
140        let dtl = self.data_transfer_length.to_le_bytes();
141        buf[8..12].copy_from_slice(&dtl);
142        buf[12] = self.flags;
143        buf[13] = self.lun;
144        buf[14] = self.cb_length;
145        buf[15..31].copy_from_slice(&self.cb);
146        buf
147    }
148
149    /// Deserialize a CBW from a 31-byte slice
150    pub fn from_bytes(data: &[u8]) -> Result<Self, KernelError> {
151        if data.len() < Self::SIZE {
152            return Err(KernelError::InvalidArgument {
153                name: "cbw_data",
154                value: "buffer too small for CBW",
155            });
156        }
157        let signature = u32::from_le_bytes([data[0], data[1], data[2], data[3]]);
158        if signature != CBW_SIGNATURE {
159            return Err(KernelError::InvalidArgument {
160                name: "cbw_signature",
161                value: "invalid CBW signature",
162            });
163        }
164        let tag = u32::from_le_bytes([data[4], data[5], data[6], data[7]]);
165        let data_transfer_length = u32::from_le_bytes([data[8], data[9], data[10], data[11]]);
166        let flags = data[12];
167        let lun = data[13];
168        let cb_length = data[14];
169        let mut cb = [0u8; 16];
170        cb.copy_from_slice(&data[15..31]);
171
172        Ok(Self {
173            signature,
174            tag,
175            data_transfer_length,
176            flags,
177            lun,
178            cb_length,
179            cb,
180        })
181    }
182}
183
184// ---------------------------------------------------------------------------
185// Command Status Wrapper (CSW)
186// ---------------------------------------------------------------------------
187
188/// CSW signature: "USBS" in little-endian
189pub const CSW_SIGNATURE: u32 = 0x53425355;
190
191/// CSW status values
192#[derive(Debug, Clone, Copy, PartialEq, Eq)]
193#[repr(u8)]
194pub enum CswStatus {
195    /// Command passed (good status)
196    Passed = 0x00,
197    /// Command failed
198    Failed = 0x01,
199    /// Phase error (requires reset recovery)
200    PhaseError = 0x02,
201}
202
203impl CswStatus {
204    /// Parse status from raw byte
205    pub fn from_byte(byte: u8) -> Self {
206        match byte {
207            0x00 => Self::Passed,
208            0x01 => Self::Failed,
209            _ => Self::PhaseError,
210        }
211    }
212}
213
214/// Command Status Wrapper (13 bytes)
215///
216/// Sent from device to host on the Bulk-In endpoint after command completion.
217#[repr(C, packed)]
218#[derive(Debug, Clone, Copy)]
219pub struct CommandStatusWrapper {
220    /// Signature: must be CSW_SIGNATURE (0x53425355)
221    pub signature: u32,
222    /// Tag: must match the tag from the corresponding CBW
223    pub tag: u32,
224    /// Data residue: difference between expected and actual data transferred
225    pub data_residue: u32,
226    /// Status byte
227    pub status: u8,
228}
229
230impl CommandStatusWrapper {
231    /// Size of a CSW in bytes
232    pub const SIZE: usize = 13;
233
234    /// Deserialize a CSW from a 13-byte slice
235    pub fn from_bytes(data: &[u8]) -> Result<Self, KernelError> {
236        if data.len() < Self::SIZE {
237            return Err(KernelError::InvalidArgument {
238                name: "csw_data",
239                value: "buffer too small for CSW",
240            });
241        }
242        let signature = u32::from_le_bytes([data[0], data[1], data[2], data[3]]);
243        if signature != CSW_SIGNATURE {
244            return Err(KernelError::InvalidArgument {
245                name: "csw_signature",
246                value: "invalid CSW signature",
247            });
248        }
249        let tag = u32::from_le_bytes([data[4], data[5], data[6], data[7]]);
250        let data_residue = u32::from_le_bytes([data[8], data[9], data[10], data[11]]);
251        let status = data[12];
252
253        Ok(Self {
254            signature,
255            tag,
256            data_residue,
257            status,
258        })
259    }
260
261    /// Serialize the CSW to a 13-byte array
262    pub fn to_bytes(&self) -> [u8; Self::SIZE] {
263        let mut buf = [0u8; Self::SIZE];
264        buf[0..4].copy_from_slice(&self.signature.to_le_bytes());
265        buf[4..8].copy_from_slice(&self.tag.to_le_bytes());
266        buf[8..12].copy_from_slice(&self.data_residue.to_le_bytes());
267        buf[12] = self.status;
268        buf
269    }
270
271    /// Get the status as a typed enum
272    pub fn get_status(&self) -> CswStatus {
273        CswStatus::from_byte(self.status)
274    }
275}
276
277// ---------------------------------------------------------------------------
278// SCSI Sense Data
279// ---------------------------------------------------------------------------
280
281/// Parsed SCSI sense data from REQUEST SENSE response
282#[derive(Debug, Clone, Copy)]
283pub struct SenseData {
284    /// Response code (0x70 = current, 0x71 = deferred)
285    pub response_code: u8,
286    /// Sense key
287    pub sense_key: SenseKey,
288    /// Additional Sense Code (ASC)
289    pub asc: u8,
290    /// Additional Sense Code Qualifier (ASCQ)
291    pub ascq: u8,
292}
293
294impl SenseData {
295    /// Parse sense data from a REQUEST SENSE response buffer
296    pub fn from_bytes(data: &[u8]) -> Result<Self, KernelError> {
297        if data.len() < 14 {
298            return Err(KernelError::InvalidArgument {
299                name: "sense_data",
300                value: "buffer too small for sense data",
301            });
302        }
303        Ok(Self {
304            response_code: data[0] & 0x7F,
305            sense_key: SenseKey::from_byte(data[2]),
306            asc: data[12],
307            ascq: data[13],
308        })
309    }
310
311    /// Returns true if no error condition is present
312    pub fn is_ok(&self) -> bool {
313        self.sense_key == SenseKey::NoSense
314    }
315}
316
317// ---------------------------------------------------------------------------
318// SCSI Inquiry Data
319// ---------------------------------------------------------------------------
320
321/// Parsed SCSI INQUIRY response
322#[derive(Debug, Clone, Copy)]
323pub struct InquiryData {
324    /// Peripheral device type (e.g., 0x00 = direct access block device)
325    pub device_type: u8,
326    /// Removable media indicator
327    pub removable: bool,
328    /// SCSI version supported
329    pub version: u8,
330    /// Vendor identification (8 bytes, space-padded ASCII)
331    pub vendor: [u8; 8],
332    /// Product identification (16 bytes, space-padded ASCII)
333    pub product: [u8; 16],
334    /// Product revision level (4 bytes)
335    pub revision: [u8; 4],
336}
337
338impl InquiryData {
339    /// Parse INQUIRY response data (minimum 36 bytes standard response)
340    pub fn from_bytes(data: &[u8]) -> Result<Self, KernelError> {
341        if data.len() < 36 {
342            return Err(KernelError::InvalidArgument {
343                name: "inquiry_data",
344                value: "buffer too small for inquiry response",
345            });
346        }
347        let mut vendor = [0u8; 8];
348        vendor.copy_from_slice(&data[8..16]);
349        let mut product = [0u8; 16];
350        product.copy_from_slice(&data[16..32]);
351        let mut revision = [0u8; 4];
352        revision.copy_from_slice(&data[32..36]);
353
354        Ok(Self {
355            device_type: data[0] & 0x1F,
356            removable: (data[1] & 0x80) != 0,
357            version: data[2],
358            vendor,
359            product,
360            revision,
361        })
362    }
363}
364
365// ---------------------------------------------------------------------------
366// Device State
367// ---------------------------------------------------------------------------
368
369/// Mass storage device states
370#[derive(Debug, Clone, Copy, PartialEq, Eq)]
371pub enum MassStorageState {
372    /// Device has not been initialized
373    Uninitialized,
374    /// Device is ready for I/O
375    Ready,
376    /// Device encountered an error
377    Error,
378}
379
380// ---------------------------------------------------------------------------
381// Block Device Trait
382// ---------------------------------------------------------------------------
383
384/// Trait for block-level I/O on a storage device
385pub trait BlockDevice {
386    /// Read `count` blocks starting at logical block address `lba` into `buf`.
387    /// Returns the number of bytes actually read.
388    fn read_blocks(&self, lba: u64, count: u32, buf: &mut [u8]) -> Result<usize, KernelError>;
389
390    /// Write `count` blocks starting at logical block address `lba` from `buf`.
391    /// Returns the number of bytes actually written.
392    fn write_blocks(&self, lba: u64, count: u32, buf: &[u8]) -> Result<usize, KernelError>;
393
394    /// Get the block (sector) size in bytes
395    fn block_size(&self) -> u32;
396
397    /// Get the total number of blocks on the device
398    fn total_blocks(&self) -> u64;
399}
400
401// ---------------------------------------------------------------------------
402// Mass Storage Device
403// ---------------------------------------------------------------------------
404
405/// Global tag counter for CBW/CSW matching
406static NEXT_TAG: AtomicU32 = AtomicU32::new(1);
407
408/// Generate a unique tag for CBW/CSW pairs
409fn next_tag() -> u32 {
410    NEXT_TAG.fetch_add(1, Ordering::Relaxed)
411}
412
413/// USB Mass Storage device using Bulk-Only Transport (BOT)
414#[derive(Debug)]
415pub struct MassStorageDevice {
416    /// USB device address on the bus
417    pub device_address: u8,
418    /// Bulk-In endpoint address
419    pub bulk_in_ep: u8,
420    /// Bulk-Out endpoint address
421    pub bulk_out_ep: u8,
422    /// Active Logical Unit Number
423    pub lun: u8,
424    /// Maximum number of LUNs supported by the device
425    pub max_lun: u8,
426    /// Cached block (sector) size in bytes
427    pub cached_block_size: u32,
428    /// Cached total block count
429    pub cached_total_blocks: u64,
430    /// Current device state
431    pub state: MassStorageState,
432    /// Last sense data from REQUEST SENSE
433    pub last_sense: Option<SenseData>,
434}
435
436impl MassStorageDevice {
437    /// Create a new mass storage device handle.
438    ///
439    /// `device_address`: USB device address on the bus
440    /// `bulk_in_ep`: endpoint address for Bulk-In transfers
441    /// `bulk_out_ep`: endpoint address for Bulk-Out transfers
442    pub fn new(device_address: u8, bulk_in_ep: u8, bulk_out_ep: u8) -> Self {
443        Self {
444            device_address,
445            bulk_in_ep,
446            bulk_out_ep,
447            lun: 0,
448            max_lun: 0,
449            cached_block_size: 0,
450            cached_total_blocks: 0,
451            state: MassStorageState::Uninitialized,
452            last_sense: None,
453        }
454    }
455
456    /// Set the active Logical Unit Number
457    pub fn set_lun(&mut self, lun: u8) {
458        self.lun = lun;
459    }
460
461    /// Build a SCSI INQUIRY command (6-byte CDB)
462    pub fn build_inquiry_cdb(allocation_length: u8) -> [u8; 6] {
463        [
464            scsi_opcodes::INQUIRY,
465            0, // reserved
466            0, // reserved
467            0, // reserved
468            allocation_length,
469            0, // control
470        ]
471    }
472
473    /// Build a SCSI TEST UNIT READY command (6-byte CDB)
474    pub fn build_test_unit_ready_cdb() -> [u8; 6] {
475        [
476            scsi_opcodes::TEST_UNIT_READY,
477            0,
478            0,
479            0,
480            0,
481            0, // control
482        ]
483    }
484
485    /// Build a SCSI REQUEST SENSE command (6-byte CDB)
486    pub fn build_request_sense_cdb(allocation_length: u8) -> [u8; 6] {
487        [
488            scsi_opcodes::REQUEST_SENSE,
489            0,
490            0,
491            0,
492            allocation_length,
493            0, // control
494        ]
495    }
496
497    /// Build a SCSI READ CAPACITY(10) command (10-byte CDB)
498    pub fn build_read_capacity_10_cdb() -> [u8; 10] {
499        [
500            scsi_opcodes::READ_CAPACITY_10,
501            0,
502            0,
503            0,
504            0,
505            0,
506            0,
507            0,
508            0,
509            0, // control
510        ]
511    }
512
513    /// Build a SCSI READ(10) command (10-byte CDB)
514    pub fn build_read_10_cdb(lba: u32, transfer_length: u16) -> [u8; 10] {
515        let lba_bytes = lba.to_be_bytes();
516        let len_bytes = transfer_length.to_be_bytes();
517        [
518            scsi_opcodes::READ_10,
519            0, // flags
520            lba_bytes[0],
521            lba_bytes[1],
522            lba_bytes[2],
523            lba_bytes[3],
524            0, // group number
525            len_bytes[0],
526            len_bytes[1],
527            0, // control
528        ]
529    }
530
531    /// Build a SCSI WRITE(10) command (10-byte CDB)
532    pub fn build_write_10_cdb(lba: u32, transfer_length: u16) -> [u8; 10] {
533        let lba_bytes = lba.to_be_bytes();
534        let len_bytes = transfer_length.to_be_bytes();
535        [
536            scsi_opcodes::WRITE_10,
537            0, // flags
538            lba_bytes[0],
539            lba_bytes[1],
540            lba_bytes[2],
541            lba_bytes[3],
542            0, // group number
543            len_bytes[0],
544            len_bytes[1],
545            0, // control
546        ]
547    }
548
549    /// Build a CBW for the given SCSI command
550    fn build_cbw(&self, command: &[u8], data_length: u32, direction: u8) -> CommandBlockWrapper {
551        CommandBlockWrapper::new(next_tag(), data_length, direction, self.lun, command)
552    }
553
554    /// Validate a CSW against the expected tag and check status.
555    fn validate_csw(
556        &mut self,
557        csw_bytes: &[u8],
558        expected_tag: u32,
559    ) -> Result<CommandStatusWrapper, KernelError> {
560        let csw = CommandStatusWrapper::from_bytes(csw_bytes)?;
561        if csw.tag != expected_tag {
562            self.state = MassStorageState::Error;
563            return Err(KernelError::HardwareError {
564                device: "usb-mass-storage",
565                code: 0x10, // tag mismatch
566            });
567        }
568        match csw.get_status() {
569            CswStatus::Passed => Ok(csw),
570            CswStatus::Failed => {
571                // Command failed -- caller should issue REQUEST SENSE
572                Err(KernelError::HardwareError {
573                    device: "usb-mass-storage",
574                    code: 0x11, // command failed
575                })
576            }
577            CswStatus::PhaseError => {
578                self.state = MassStorageState::Error;
579                Err(KernelError::HardwareError {
580                    device: "usb-mass-storage",
581                    code: 0x12, // phase error, needs reset recovery
582                })
583            }
584        }
585    }
586
587    /// Initialize the device: INQUIRY, TEST UNIT READY, READ CAPACITY.
588    ///
589    /// On success, `cached_block_size` and `cached_total_blocks` are populated
590    /// and the device transitions to the `Ready` state.
591    pub fn initialize(&mut self) -> Result<InquiryData, KernelError> {
592        // Step 1: INQUIRY
593        let inquiry_cdb = Self::build_inquiry_cdb(36);
594        let cbw = self.build_cbw(&inquiry_cdb, 36, CBW_DIRECTION_IN);
595        let inquiry_data = self.execute_command_in(&cbw, 36)?;
596        let inquiry = InquiryData::from_bytes(&inquiry_data)?;
597
598        // Verify this is a direct-access block device (type 0x00)
599        if inquiry.device_type != 0x00 {
600            self.state = MassStorageState::Error;
601            return Err(KernelError::HardwareError {
602                device: "usb-mass-storage",
603                code: 0x20, // unsupported device type
604            });
605        }
606
607        // Step 2: TEST UNIT READY
608        let tur_cdb = Self::build_test_unit_ready_cdb();
609        let cbw = self.build_cbw(&tur_cdb, 0, CBW_DIRECTION_OUT);
610        if let Err(_e) = self.execute_command_none(&cbw) {
611            // Device may need time -- try REQUEST SENSE and retry
612            let _sense = self.request_sense();
613            // Retry TEST UNIT READY once
614            let cbw = self.build_cbw(&tur_cdb, 0, CBW_DIRECTION_OUT);
615            self.execute_command_none(&cbw)?;
616        }
617
618        // Step 3: READ CAPACITY(10)
619        let rc_cdb = Self::build_read_capacity_10_cdb();
620        let cbw = self.build_cbw(&rc_cdb, 8, CBW_DIRECTION_IN);
621        let cap_data = self.execute_command_in(&cbw, 8)?;
622
623        if cap_data.len() >= 8 {
624            let last_lba = u32::from_be_bytes([cap_data[0], cap_data[1], cap_data[2], cap_data[3]]);
625            let block_size =
626                u32::from_be_bytes([cap_data[4], cap_data[5], cap_data[6], cap_data[7]]);
627
628            self.cached_total_blocks = (last_lba as u64) + 1;
629            self.cached_block_size = block_size;
630        }
631
632        self.state = MassStorageState::Ready;
633        Ok(inquiry)
634    }
635
636    /// Issue a SCSI REQUEST SENSE command and cache the result
637    pub fn request_sense(&mut self) -> Result<SenseData, KernelError> {
638        let cdb = Self::build_request_sense_cdb(18);
639        let cbw = self.build_cbw(&cdb, 18, CBW_DIRECTION_IN);
640        let sense_bytes = self.execute_command_in(&cbw, 18)?;
641        let sense = SenseData::from_bytes(&sense_bytes)?;
642        self.last_sense = Some(sense);
643        Ok(sense)
644    }
645
646    /// Execute a BOT command with a data-in phase (device-to-host).
647    ///
648    /// This is a placeholder transport layer that builds the CBW bytes and
649    /// simulates the three BOT phases (CBW out, data in, CSW in). In a real
650    /// driver, each phase would use bulk endpoint transfers via the USB host
651    /// controller.
652    fn execute_command_in(
653        &mut self,
654        cbw: &CommandBlockWrapper,
655        expected_len: u32,
656    ) -> Result<Vec<u8>, KernelError> {
657        // Phase 1: Send CBW on Bulk-Out
658        let _cbw_bytes = cbw.to_bytes();
659
660        // In a real implementation:
661        //   usb_bulk_out(self.bulk_out_ep, &cbw_bytes)?;
662        //   let data = usb_bulk_in(self.bulk_in_ep, expected_len)?;
663        //   let csw_bytes = usb_bulk_in(self.bulk_in_ep, 13)?;
664        //   self.validate_csw(&csw_bytes, cbw.tag)?;
665
666        // Stub: return zeroed data of the requested length
667        let data = alloc::vec![0u8; expected_len as usize];
668        Ok(data)
669    }
670
671    /// Execute a BOT command with no data phase
672    fn execute_command_none(&mut self, cbw: &CommandBlockWrapper) -> Result<(), KernelError> {
673        let _cbw_bytes = cbw.to_bytes();
674
675        // In a real implementation:
676        //   usb_bulk_out(self.bulk_out_ep, &cbw_bytes)?;
677        //   let csw_bytes = usb_bulk_in(self.bulk_in_ep, 13)?;
678        //   self.validate_csw(&csw_bytes, cbw.tag)?;
679
680        Ok(())
681    }
682
683    /// Execute a BOT command with a data-out phase (host-to-device)
684    fn execute_command_out(
685        &mut self,
686        cbw: &CommandBlockWrapper,
687        data: &[u8],
688    ) -> Result<(), KernelError> {
689        let _cbw_bytes = cbw.to_bytes();
690        let _data_out = data;
691
692        // In a real implementation:
693        //   usb_bulk_out(self.bulk_out_ep, &cbw_bytes)?;
694        //   usb_bulk_out(self.bulk_out_ep, data)?;
695        //   let csw_bytes = usb_bulk_in(self.bulk_in_ep, 13)?;
696        //   self.validate_csw(&csw_bytes, cbw.tag)?;
697
698        Ok(())
699    }
700}
701
702impl BlockDevice for MassStorageDevice {
703    fn read_blocks(&self, lba: u64, count: u32, buf: &mut [u8]) -> Result<usize, KernelError> {
704        if self.state != MassStorageState::Ready {
705            return Err(KernelError::InvalidState {
706                expected: "Ready",
707                actual: "not Ready",
708            });
709        }
710
711        if self.cached_block_size == 0 {
712            return Err(KernelError::InvalidState {
713                expected: "initialized (block_size > 0)",
714                actual: "block_size is 0",
715            });
716        }
717
718        let total_bytes = (count as usize) * (self.cached_block_size as usize);
719        if buf.len() < total_bytes {
720            return Err(KernelError::InvalidArgument {
721                name: "buf",
722                value: "buffer too small for requested blocks",
723            });
724        }
725
726        // Validate LBA range
727        if lba.saturating_add(count as u64) > self.cached_total_blocks {
728            return Err(KernelError::InvalidArgument {
729                name: "lba+count",
730                value: "exceeds device capacity",
731            });
732        }
733
734        // READ(10) uses 32-bit LBA and 16-bit transfer count
735        let lba32 = lba as u32;
736        let cdb = Self::build_read_10_cdb(lba32, count as u16);
737        let cbw = CommandBlockWrapper::new(
738            next_tag(),
739            total_bytes as u32,
740            CBW_DIRECTION_IN,
741            self.lun,
742            &cdb,
743        );
744        let _cbw_bytes = cbw.to_bytes();
745
746        // Stub: in a real driver, data would be read via bulk-in
747        // For now, zero-fill the buffer to indicate successful stub execution
748        for byte in buf[..total_bytes].iter_mut() {
749            *byte = 0;
750        }
751
752        Ok(total_bytes)
753    }
754
755    fn write_blocks(&self, lba: u64, count: u32, buf: &[u8]) -> Result<usize, KernelError> {
756        if self.state != MassStorageState::Ready {
757            return Err(KernelError::InvalidState {
758                expected: "Ready",
759                actual: "not Ready",
760            });
761        }
762
763        if self.cached_block_size == 0 {
764            return Err(KernelError::InvalidState {
765                expected: "initialized (block_size > 0)",
766                actual: "block_size is 0",
767            });
768        }
769
770        let total_bytes = (count as usize) * (self.cached_block_size as usize);
771        if buf.len() < total_bytes {
772            return Err(KernelError::InvalidArgument {
773                name: "buf",
774                value: "buffer too small for requested blocks",
775            });
776        }
777
778        // Validate LBA range
779        if lba.saturating_add(count as u64) > self.cached_total_blocks {
780            return Err(KernelError::InvalidArgument {
781                name: "lba+count",
782                value: "exceeds device capacity",
783            });
784        }
785
786        let lba32 = lba as u32;
787        let cdb = Self::build_write_10_cdb(lba32, count as u16);
788        let cbw = CommandBlockWrapper::new(
789            next_tag(),
790            total_bytes as u32,
791            CBW_DIRECTION_OUT,
792            self.lun,
793            &cdb,
794        );
795        let _cbw_bytes = cbw.to_bytes();
796
797        // Stub: in a real driver, data would be sent via bulk-out
798        Ok(total_bytes)
799    }
800
801    fn block_size(&self) -> u32 {
802        self.cached_block_size
803    }
804
805    fn total_blocks(&self) -> u64 {
806        self.cached_total_blocks
807    }
808}
809
810// ---------------------------------------------------------------------------
811// Tests
812// ---------------------------------------------------------------------------
813
814#[cfg(test)]
815mod tests {
816    use super::*;
817
818    #[test]
819    fn test_cbw_signature() {
820        assert_eq!(CBW_SIGNATURE, 0x43425355);
821    }
822
823    #[test]
824    fn test_csw_signature() {
825        assert_eq!(CSW_SIGNATURE, 0x53425355);
826    }
827
828    #[test]
829    fn test_cbw_serialization_roundtrip() {
830        let command = [0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00];
831        let cbw = CommandBlockWrapper::new(42, 4096, CBW_DIRECTION_IN, 0, &command);
832        let bytes = cbw.to_bytes();
833
834        assert_eq!(bytes.len(), CommandBlockWrapper::SIZE);
835        assert_eq!(bytes[0], 0x55); // 'U' (LE byte 0 of 0x43425355)
836        assert_eq!(bytes[1], 0x53); // 'S'
837        assert_eq!(bytes[2], 0x42); // 'B'
838        assert_eq!(bytes[3], 0x43); // 'C'
839
840        let parsed = CommandBlockWrapper::from_bytes(&bytes).unwrap();
841        // Copy fields out of packed struct before asserting (E0793)
842        let tag = parsed.tag;
843        let dtl = parsed.data_transfer_length;
844        let flags = parsed.flags;
845        let lun = parsed.lun;
846        let cb0 = parsed.cb[0];
847        assert_eq!(tag, 42);
848        assert_eq!(dtl, 4096);
849        assert_eq!(flags, CBW_DIRECTION_IN);
850        assert_eq!(lun, 0);
851        assert_eq!(cb0, 0x28); // READ(10) opcode
852    }
853
854    #[test]
855    fn test_cbw_from_bytes_invalid_signature() {
856        let mut bytes = [0u8; 31];
857        bytes[0] = 0xFF; // wrong signature
858        let result = CommandBlockWrapper::from_bytes(&bytes);
859        assert!(result.is_err());
860    }
861
862    #[test]
863    fn test_cbw_from_bytes_too_short() {
864        let bytes = [0u8; 10];
865        let result = CommandBlockWrapper::from_bytes(&bytes);
866        assert!(result.is_err());
867    }
868
869    #[test]
870    fn test_csw_serialization_roundtrip() {
871        let csw = CommandStatusWrapper {
872            signature: CSW_SIGNATURE,
873            tag: 42,
874            data_residue: 0,
875            status: CswStatus::Passed as u8,
876        };
877        let bytes = csw.to_bytes();
878        assert_eq!(bytes.len(), CommandStatusWrapper::SIZE);
879
880        let parsed = CommandStatusWrapper::from_bytes(&bytes).unwrap();
881        // Copy fields out of packed struct before asserting (E0793)
882        let tag = parsed.tag;
883        let residue = parsed.data_residue;
884        assert_eq!(tag, 42);
885        assert_eq!(residue, 0);
886        assert_eq!(parsed.get_status(), CswStatus::Passed);
887    }
888
889    #[test]
890    fn test_csw_failed_status() {
891        let csw = CommandStatusWrapper {
892            signature: CSW_SIGNATURE,
893            tag: 1,
894            data_residue: 512,
895            status: CswStatus::Failed as u8,
896        };
897        let bytes = csw.to_bytes();
898        let parsed = CommandStatusWrapper::from_bytes(&bytes).unwrap();
899        assert_eq!(parsed.get_status(), CswStatus::Failed);
900        let residue = parsed.data_residue;
901        assert_eq!(residue, 512);
902    }
903
904    #[test]
905    fn test_csw_phase_error() {
906        let status = CswStatus::from_byte(0x02);
907        assert_eq!(status, CswStatus::PhaseError);
908        // Unknown values also map to PhaseError
909        let unknown = CswStatus::from_byte(0xFF);
910        assert_eq!(unknown, CswStatus::PhaseError);
911    }
912
913    #[test]
914    fn test_sense_key_parsing() {
915        assert_eq!(SenseKey::from_byte(0x00), SenseKey::NoSense);
916        assert_eq!(SenseKey::from_byte(0x02), SenseKey::NotReady);
917        assert_eq!(SenseKey::from_byte(0x05), SenseKey::IllegalRequest);
918        assert_eq!(SenseKey::from_byte(0x03), SenseKey::MediumError);
919        // Upper nibble should be masked
920        assert_eq!(SenseKey::from_byte(0xF5), SenseKey::IllegalRequest);
921    }
922
923    #[test]
924    fn test_sense_data_parsing() {
925        let mut raw = [0u8; 18];
926        raw[0] = 0x70; // current errors, fixed format
927        raw[2] = 0x05; // ILLEGAL REQUEST
928        raw[12] = 0x24; // ASC: invalid field in CDB
929        raw[13] = 0x00; // ASCQ
930        let sense = SenseData::from_bytes(&raw).unwrap();
931        assert_eq!(sense.response_code, 0x70);
932        assert_eq!(sense.sense_key, SenseKey::IllegalRequest);
933        assert_eq!(sense.asc, 0x24);
934        assert_eq!(sense.ascq, 0x00);
935        assert!(!sense.is_ok());
936    }
937
938    #[test]
939    fn test_sense_data_no_sense() {
940        let mut raw = [0u8; 18];
941        raw[0] = 0x70;
942        raw[2] = 0x00; // NO SENSE
943        let sense = SenseData::from_bytes(&raw).unwrap();
944        assert!(sense.is_ok());
945    }
946
947    #[test]
948    fn test_inquiry_data_parsing() {
949        let mut raw = [0u8; 36];
950        raw[0] = 0x00; // direct access block device
951        raw[1] = 0x80; // removable
952        raw[2] = 0x05; // SPC-3
953                       // Vendor: "VERIDIAN"
954        raw[8..16].copy_from_slice(b"VERIDIAN");
955        // Product: "USB DISK        "
956        raw[16..32].copy_from_slice(b"USB DISK        ");
957        // Revision: "1.00"
958        raw[32..36].copy_from_slice(b"1.00");
959
960        let inquiry = InquiryData::from_bytes(&raw).unwrap();
961        assert_eq!(inquiry.device_type, 0x00);
962        assert!(inquiry.removable);
963        assert_eq!(inquiry.version, 0x05);
964        assert_eq!(&inquiry.vendor, b"VERIDIAN");
965        assert_eq!(&inquiry.product, b"USB DISK        ");
966        assert_eq!(&inquiry.revision, b"1.00");
967    }
968
969    #[test]
970    fn test_mass_storage_device_creation() {
971        let dev = MassStorageDevice::new(1, 0x81, 0x02);
972        assert_eq!(dev.device_address, 1);
973        assert_eq!(dev.bulk_in_ep, 0x81);
974        assert_eq!(dev.bulk_out_ep, 0x02);
975        assert_eq!(dev.lun, 0);
976        assert_eq!(dev.state, MassStorageState::Uninitialized);
977        assert_eq!(dev.cached_block_size, 0);
978        assert_eq!(dev.cached_total_blocks, 0);
979    }
980
981    #[test]
982    fn test_block_device_read_not_ready() {
983        let dev = MassStorageDevice::new(1, 0x81, 0x02);
984        let mut buf = [0u8; 512];
985        let result = dev.read_blocks(0, 1, &mut buf);
986        assert!(result.is_err()); // device is Uninitialized
987    }
988
989    #[test]
990    fn test_block_device_write_not_ready() {
991        let dev = MassStorageDevice::new(1, 0x81, 0x02);
992        let buf = [0u8; 512];
993        let result = dev.write_blocks(0, 1, &buf);
994        assert!(result.is_err()); // device is Uninitialized
995    }
996
997    #[test]
998    fn test_block_device_read_ready() {
999        let mut dev = MassStorageDevice::new(1, 0x81, 0x02);
1000        dev.state = MassStorageState::Ready;
1001        dev.cached_block_size = 512;
1002        dev.cached_total_blocks = 1024;
1003
1004        let mut buf = [0xFFu8; 512];
1005        let result = dev.read_blocks(0, 1, &mut buf);
1006        assert!(result.is_ok());
1007        assert_eq!(result.unwrap(), 512);
1008    }
1009
1010    #[test]
1011    fn test_block_device_write_ready() {
1012        let mut dev = MassStorageDevice::new(1, 0x81, 0x02);
1013        dev.state = MassStorageState::Ready;
1014        dev.cached_block_size = 512;
1015        dev.cached_total_blocks = 1024;
1016
1017        let buf = [0xAAu8; 512];
1018        let result = dev.write_blocks(0, 1, &buf);
1019        assert!(result.is_ok());
1020        assert_eq!(result.unwrap(), 512);
1021    }
1022
1023    #[test]
1024    fn test_block_device_buffer_too_small() {
1025        let mut dev = MassStorageDevice::new(1, 0x81, 0x02);
1026        dev.state = MassStorageState::Ready;
1027        dev.cached_block_size = 512;
1028        dev.cached_total_blocks = 1024;
1029
1030        let mut buf = [0u8; 256]; // too small for 1 block of 512
1031        let result = dev.read_blocks(0, 1, &mut buf);
1032        assert!(result.is_err());
1033    }
1034
1035    #[test]
1036    fn test_block_device_lba_out_of_range() {
1037        let mut dev = MassStorageDevice::new(1, 0x81, 0x02);
1038        dev.state = MassStorageState::Ready;
1039        dev.cached_block_size = 512;
1040        dev.cached_total_blocks = 100;
1041
1042        let mut buf = [0u8; 512];
1043        // LBA 100 is past the end (0-99 valid)
1044        let result = dev.read_blocks(100, 1, &mut buf);
1045        assert!(result.is_err());
1046    }
1047
1048    #[test]
1049    fn test_scsi_read_10_cdb() {
1050        let cdb = MassStorageDevice::build_read_10_cdb(0x00000100, 8);
1051        assert_eq!(cdb[0], 0x28); // READ(10) opcode
1052                                  // LBA = 0x00000100, big-endian
1053        assert_eq!(cdb[2], 0x00);
1054        assert_eq!(cdb[3], 0x00);
1055        assert_eq!(cdb[4], 0x01);
1056        assert_eq!(cdb[5], 0x00);
1057        // Transfer length = 8 blocks, big-endian
1058        assert_eq!(cdb[7], 0x00);
1059        assert_eq!(cdb[8], 0x08);
1060    }
1061
1062    #[test]
1063    fn test_scsi_write_10_cdb() {
1064        let cdb = MassStorageDevice::build_write_10_cdb(0x00001000, 1);
1065        assert_eq!(cdb[0], 0x2A); // WRITE(10) opcode
1066                                  // LBA big-endian
1067        assert_eq!(cdb[2], 0x00);
1068        assert_eq!(cdb[3], 0x00);
1069        assert_eq!(cdb[4], 0x10);
1070        assert_eq!(cdb[5], 0x00);
1071        // Transfer length = 1
1072        assert_eq!(cdb[7], 0x00);
1073        assert_eq!(cdb[8], 0x01);
1074    }
1075
1076    #[test]
1077    fn test_lun_setting() {
1078        let mut dev = MassStorageDevice::new(1, 0x81, 0x02);
1079        assert_eq!(dev.lun, 0);
1080        dev.set_lun(3);
1081        assert_eq!(dev.lun, 3);
1082    }
1083
1084    #[test]
1085    fn test_cbw_lun_masking() {
1086        let command = [0x00; 6]; // TEST UNIT READY
1087        let cbw = CommandBlockWrapper::new(1, 0, CBW_DIRECTION_OUT, 0xFF, &command);
1088        assert_eq!(cbw.lun, 0x0F); // only lower 4 bits
1089    }
1090
1091    #[test]
1092    fn test_csw_from_bytes_invalid_signature() {
1093        let mut bytes = [0u8; 13];
1094        bytes[0] = 0x00; // wrong signature
1095        let result = CommandStatusWrapper::from_bytes(&bytes);
1096        assert!(result.is_err());
1097    }
1098
1099    #[test]
1100    fn test_multi_block_read() {
1101        let mut dev = MassStorageDevice::new(1, 0x81, 0x02);
1102        dev.state = MassStorageState::Ready;
1103        dev.cached_block_size = 512;
1104        dev.cached_total_blocks = 2048;
1105
1106        let mut buf = [0u8; 4096]; // 8 blocks
1107        let result = dev.read_blocks(0, 8, &mut buf);
1108        assert!(result.is_ok());
1109        assert_eq!(result.unwrap(), 4096);
1110    }
1111}