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}