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}