rdif_block/
lib.rs

1#![no_std]
2
3extern crate alloc;
4
5use core::ops::{Deref, DerefMut};
6
7use alloc::boxed::Box;
8pub use rdif_base::{DriverGeneric, KError, io};
9
10mod blk;
11
12pub use blk::*;
13
14pub use dma_api;
15
16/// Configuration for DMA buffer allocation.
17///
18/// This structure specifies the requirements for DMA buffers used in
19/// block device operations. The configuration ensures that buffers
20/// meet the hardware's alignment and addressing constraints.
21pub struct BuffConfig {
22    /// DMA addressing mask for the device.
23    ///
24    /// This mask defines the addressable memory range for DMA operations.
25    /// For example, a 32-bit device would use `0xFFFFFFFF`.
26    pub dma_mask: u64,
27
28    /// Required alignment for buffer addresses.
29    ///
30    /// Buffers must be aligned to this boundary (in bytes) for optimal
31    /// performance and hardware compatibility. Common values are 512 or 4096.
32    pub align: usize,
33
34    /// Size of each buffer in bytes.
35    ///
36    /// This typically matches the device's block size to ensure efficient
37    /// data transfer and avoid partial block operations.
38    pub size: usize,
39}
40
41/// Errors that can occur during block device operations.
42///
43/// These errors provide detailed information about what went wrong during
44/// block device operations and how the caller should respond.
45#[derive(thiserror::Error, Debug)]
46pub enum BlkError {
47    /// The requested operation is not supported by the device.
48    ///
49    /// This error occurs when attempting to perform an operation that the
50    /// hardware or driver does not support. For example, trying to write
51    /// to a read-only device.
52    ///
53    /// **Recovery**: Check device capabilities and use only supported operations.
54    #[error("Operation not supported")]
55    NotSupported,
56
57    /// The operation should be retried later.
58    ///
59    /// This error indicates that the operation failed due to temporary conditions
60    /// and should be retried. This commonly occurs when:
61    /// - The device queue is full
62    /// - The device is temporarily busy
63    /// - Resource contention prevents immediate completion
64    ///
65    /// **Recovery**: Wait a short time and retry the operation. Consider implementing
66    /// exponential backoff for repeated retries.
67    #[error("Operation should be retried")]
68    Retry,
69
70    /// Insufficient memory to complete the operation.
71    ///
72    /// This error occurs when there is not enough memory available to:
73    /// - Allocate DMA buffers
74    /// - Create internal data structures
75    /// - Complete the requested operation
76    ///
77    /// **Recovery**: Free unused resources or wait for memory to become available.
78    /// Consider reducing the number of concurrent operations.
79    #[error("Insufficient memory")]
80    NoMemory,
81
82    /// The specified block index is invalid or out of range.
83    ///
84    /// This error occurs when:
85    /// - The block index exceeds the device's capacity
86    /// - The block index is negative (in languages that allow it)
87    /// - The block has been marked as bad or unusable
88    ///
89    /// **Recovery**: Verify that the block index is within the valid range
90    /// (0 to `num_blocks() - 1`) and that the block is accessible.
91    #[error("Invalid block index: {0} (check device capacity and block accessibility)")]
92    InvalidBlockIndex(usize),
93
94    /// An unspecified error occurred.
95    ///
96    /// This error wraps other error types that don't fit into the specific
97    /// categories above. The wrapped error provides additional context about
98    /// what went wrong.
99    ///
100    /// **Recovery**: Examine the wrapped error for specific recovery instructions.
101    /// This often indicates a lower-level hardware or system error.
102    #[error("Other error: {0}")]
103    Other(Box<dyn core::error::Error>),
104}
105
106impl From<BlkError> for io::ErrorKind {
107    fn from(value: BlkError) -> Self {
108        match value {
109            BlkError::NotSupported => io::ErrorKind::Unsupported,
110            BlkError::Retry => io::ErrorKind::Interrupted,
111            BlkError::NoMemory => io::ErrorKind::OutOfMemory,
112            BlkError::InvalidBlockIndex(_) => io::ErrorKind::NotAvailable,
113            BlkError::Other(e) => io::ErrorKind::Other(e),
114        }
115    }
116}
117
118impl From<dma_api::DError> for BlkError {
119    fn from(value: dma_api::DError) -> Self {
120        match value {
121            dma_api::DError::NoMemory => BlkError::NoMemory,
122            e => BlkError::Other(Box::new(e)),
123        }
124    }
125}
126
127/// Operations that require a block storage device driver to implement.
128///
129/// This trait defines the core interface that all block device drivers
130/// must implement to work with the rdrive framework. It provides methods
131/// for queue management, interrupt handling, and device lifecycle operations.
132pub trait Interface: DriverGeneric {
133    fn create_queue(&mut self) -> Option<Box<dyn IQueue>>;
134
135    /// Enable interrupts for the device.
136    ///
137    /// After calling this method, the device will generate interrupts
138    /// for completed operations and other events.
139    fn enable_irq(&mut self);
140
141    /// Disable interrupts for the device.
142    ///
143    /// After calling this method, the device will not generate interrupts.
144    /// This is useful during critical sections or device shutdown.
145    fn disable_irq(&mut self);
146
147    /// Check if interrupts are currently enabled.
148    ///
149    /// Returns `true` if interrupts are enabled, `false` otherwise.
150    fn is_irq_enabled(&self) -> bool;
151
152    /// Handles an IRQ from the device, returning an event if applicable.
153    ///
154    /// This method should be called from the device's interrupt handler.
155    /// It processes the interrupt and returns information about which
156    /// queues have completed operations.
157    fn handle_irq(&mut self) -> Event;
158}
159
160#[repr(transparent)]
161#[derive(Debug, Clone, Copy)]
162pub struct IdList(u64);
163
164impl IdList {
165    pub const fn none() -> Self {
166        Self(0)
167    }
168
169    pub fn contains(&self, id: usize) -> bool {
170        (self.0 & (1 << id)) != 0
171    }
172
173    pub fn insert(&mut self, id: usize) {
174        self.0 |= 1 << id;
175    }
176
177    pub fn remove(&mut self, id: usize) {
178        self.0 &= !(1 << id);
179    }
180
181    pub fn iter(&self) -> impl Iterator<Item = usize> {
182        (0..64).filter(move |i| self.contains(*i))
183    }
184}
185
186#[derive(Debug, Clone, Copy)]
187pub struct Event {
188    /// Bitmask of queue IDs that have events.
189    pub queue: IdList,
190}
191
192impl Event {
193    pub const fn none() -> Self {
194        Self {
195            queue: IdList::none(),
196        }
197    }
198}
199
200#[repr(transparent)]
201#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
202pub struct RequestId(usize);
203
204impl RequestId {
205    pub fn new(id: usize) -> Self {
206        Self(id)
207    }
208}
209
210impl From<RequestId> for usize {
211    fn from(value: RequestId) -> Self {
212        value.0
213    }
214}
215
216#[derive(Clone, Copy)]
217pub struct Buffer {
218    pub virt: *mut u8,
219    pub bus: u64,
220    pub size: usize,
221}
222
223impl Deref for Buffer {
224    type Target = [u8];
225
226    fn deref(&self) -> &Self::Target {
227        unsafe { core::slice::from_raw_parts(self.virt, self.size) }
228    }
229}
230
231impl DerefMut for Buffer {
232    fn deref_mut(&mut self) -> &mut Self::Target {
233        unsafe { core::slice::from_raw_parts_mut(self.virt, self.size) }
234    }
235}
236
237/// Read queue trait for block devices.
238pub trait IQueue: Send + 'static {
239    /// Get the queue identifier.
240    fn id(&self) -> usize;
241
242    /// Get the total number of blocks available.
243    fn num_blocks(&self) -> usize;
244
245    /// Get the size of each block in bytes.
246    fn block_size(&self) -> usize;
247
248    /// Get the buffer configuration for this queue.
249    fn buff_config(&self) -> BuffConfig;
250
251    fn submit_request(&mut self, request: Request<'_>) -> Result<RequestId, BlkError>;
252
253    /// Poll the status of a previously submitted request.
254    fn poll_request(&mut self, request: RequestId) -> Result<(), BlkError>;
255}
256
257#[derive(Clone)]
258pub struct Request<'a> {
259    pub block_id: usize,
260    pub kind: RequestKind<'a>,
261}
262
263#[derive(Clone)]
264pub enum RequestKind<'a> {
265    Read(Buffer),
266    Write(&'a [u8]),
267}