Skip to main content

rdif_block/
lib.rs

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