rdif_block/
lib.rs

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