1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
//! Trait definitions for storage devices and storage controllers. 
//! 
//! All storage devices should implement the `StorageDevice` trait, 
//! such as hard disk drives, optical discs, SSDs, etc. 
//! All storage controllers should implement the `StorageController` trait,
//! such as AHCI controllers and IDE controllers.
//! 
//! Below is a quick example of how to iterate through available `StorageDevice`s on the system
//! and usage of the `StorageDevice` trait methods, as well as how to downcast it
//! into a specific concrete type, such as an `AtaDrive`.
//! ```rust
//! if let Some(controller) = storage_manager::storage_controllers().next() {
//!     if let Some(sd) = controller.lock().devices().next() {
//!         {
//!             // Call `StorageDevice` trait methods directly
//!             let mut locked_sd = sd.lock();
//!             debug!("Found drive with size {}, {} sectors", locked_sd.size_in_bytes(), locked_sd.size_in_blocks());
//! 
//!             // Here we downcast the `StorageDevice` into an `AtaDrive` so we can call `AtaDrive` methods.
//!             if let Some(ata_drive) = locked_sd.as_any_mut().downcast_mut() {
//!                 debug!("      drive was master? {}", ata_drive.is_master());
//! 
//!                 // Read 10 sectors from the beginning of the drive (at offset 0)
//!                 let mut initial_buf: [u8; 5120] = [0; 5120]; // 10 sectors of bytes
//!                 let sectors_read = ata_drive.read_pio(&mut initial_buf[..], 0).unwrap();
//!                 debug!("[SUCCESS] sectors_read: {:?}", sectors_read);
//!                 debug!("{:?}", core::str::from_utf8(&initial_buf));
//! 
//!                 // Write 3 sectors to the drive
//!                 let mut write_buf = [0u8; 512*3];
//!                 for b in write_buf.chunks_exact_mut(16) {
//!                     b.copy_from_slice(b"QWERTYUIOPASDFJK");
//!                 }
//!                 let bytes_written = ata_drive.write_pio(&write_buf[..], 2).unwrap();
//!                 debug!("WRITE_PIO {:?}", bytes_written);
//!             }
//!         }
//!         // Read 10 sectors from the drive using the `StorageDevice` trait methods.
//!         let mut after_buf: [u8; 5120] = [0; 5120];
//!         let sectors_read = sd.lock().read_blocks(&mut after_buf[..], 0).unwrap();
//!         debug!("{:X?}", &after_buf[..]);
//!         debug!("{:?}", core::str::from_utf8(&after_buf));
//!         trace!("POST-WRITE READ_BLOCKS {} sectors", sectors_read);
//!     }
//! }
//! ```
//! 
//! # Limitations
//! 
//! Note that if other crates are using a storage device through a block cache, 
//! the cache does not own the storage device and cache validity is questionable.
//! Be careful in that case. See the warning in the [block_cache](../block_cache/index.html) module.

#![no_std]

extern crate alloc;
extern crate spin;
#[macro_use] extern crate downcast_rs;
extern crate io;

use alloc::{
    boxed::Box,
    sync::Arc,
};
use spin::Mutex;
use downcast_rs::Downcast;
use io::{BlockIo, KnownLength, BlockReader, BlockWriter};


/// A trait that represents a storage controller,
/// such as an AHCI controller or IDE controller.
pub trait StorageController {
    /// Returns an iterator of references to all `StorageDevice`s attached to this controller.
    /// The lifetime of the iterator and the device references it returns are both bound
    /// by the lifetime of this `StorageController`.
    /// 
    /// # Note
    /// I would prefer to have this Iterator return a `&StorageDeviceRef`,
    /// but Rust does not permit casts from `&Arc<Mutex<Struct>>` to `&Arc<Mutex<Trait>>`,
    /// it only supports casts from `Arc<Mutex<Struct>>` to `Arc<Mutex<Trait>>`.
    fn devices<'c>(&'c self) -> Box<(dyn Iterator<Item = StorageDeviceRef> + 'c)>;
}

/// A trait object wrapped in an Arc and Mutex that allows 
/// arbitrary storage controllers to be shared in a thread-safe manner.
pub type StorageControllerRef = Arc<Mutex<dyn StorageController + Send>>;


/// A trait that represents a storage device,
/// such as hard disks, removable drives, SSDs, etc.
/// 
/// A `StorageDevice` must implement the following traits:
/// * `BlockIo`: to specify its block size.
/// * `BlockReader` and `BlockWriter`: to enable reading and writing data 
///   from/to the device at block granularity. 
/// * `KnownLength`: to specify the size in bytes (length) of the entire device. 
///
/// This trait includes additional functions to query device info, e.g.,
/// the device's total size in number of blocks.
pub trait StorageDevice: BlockIo + BlockReader + BlockWriter + KnownLength + Downcast {
	/// Returns the total size of this device, given in number of blocks (sectors).
    fn size_in_blocks(&self) -> usize;
}
impl_downcast!(StorageDevice);

/// A trait object wrapped in an Arc and Mutex that allows 
/// arbitrary storage devices to be shared in a thread-safe manner.
pub type StorageDeviceRef = Arc<Mutex<dyn StorageDevice + Send>>;