Skip to main content

rdif_block/
interface.rs

1use alloc::{boxed::Box, sync::Arc, vec::Vec};
2
3use ax_kspin::SpinRaw as Mutex;
4
5use crate::{
6    BlkError, DeviceInfo, DriverGeneric, IrqHandler, IrqSourceList, OwnedRequest, PollError,
7    QueueInfo, QueueLimits, Request, RequestId, RequestPoll, RequestStatus, SubmitError,
8};
9
10pub type BInterface = Box<dyn Interface>;
11pub type BQueue = Box<dyn IQueue>;
12pub type BOwnedQueue = Box<dyn IQueueOwned>;
13pub type BIrqHandler = Box<dyn IrqHandler>;
14
15pub trait Interface: DriverGeneric {
16    fn device_info(&self) -> DeviceInfo;
17
18    fn queue_limits(&self) -> QueueLimits;
19
20    fn create_queue(&mut self) -> Option<BQueue>;
21
22    fn create_owned_queue(&mut self) -> Option<QueueHandle> {
23        None
24    }
25
26    fn enable_irq(&self) {}
27
28    fn disable_irq(&self) {}
29
30    fn is_irq_enabled(&self) -> bool {
31        false
32    }
33
34    fn irq_sources(&self) -> IrqSourceList {
35        Vec::new()
36    }
37
38    fn take_irq_handler(&mut self, _source_id: usize) -> Option<BIrqHandler> {
39        None
40    }
41}
42
43pub trait CompletionSink {
44    fn complete(&mut self, request: RequestId, result: Result<(), BlkError>);
45}
46
47/// A request queue that owns DMA backing for every in-flight request.
48pub trait IQueueOwned: Send + 'static {
49    fn id(&self) -> usize;
50
51    fn info(&self) -> QueueInfo;
52
53    fn submit_request(&mut self, request: OwnedRequest) -> Result<RequestId, SubmitError>;
54
55    fn poll_request(&mut self, request: RequestId) -> Result<RequestPoll, PollError>;
56
57    fn cancel_request(&mut self, request: RequestId) -> Result<RequestPoll, PollError>;
58
59    fn shutdown(&mut self) {}
60}
61
62pub struct QueueHandle {
63    queue: Option<BOwnedQueue>,
64}
65
66impl QueueHandle {
67    pub fn new(queue: BOwnedQueue) -> Self {
68        Self { queue: Some(queue) }
69    }
70
71    pub fn id(&self) -> usize {
72        self.queue
73            .as_ref()
74            .expect("owned queue handle must contain queue")
75            .id()
76    }
77
78    pub fn info(&self) -> QueueInfo {
79        self.queue
80            .as_ref()
81            .expect("owned queue handle must contain queue")
82            .info()
83    }
84
85    pub fn submit_request(&mut self, request: OwnedRequest) -> Result<RequestId, SubmitError> {
86        self.queue
87            .as_mut()
88            .expect("owned queue handle must contain queue")
89            .submit_request(request)
90    }
91
92    pub fn poll_request(&mut self, request: RequestId) -> Result<RequestPoll, PollError> {
93        self.queue
94            .as_mut()
95            .expect("owned queue handle must contain queue")
96            .poll_request(request)
97    }
98
99    pub fn cancel_request(&mut self, request: RequestId) -> Result<RequestPoll, PollError> {
100        self.queue
101            .as_mut()
102            .expect("owned queue handle must contain queue")
103            .cancel_request(request)
104    }
105
106    pub fn shutdown(&mut self) {
107        if let Some(queue) = self.queue.as_mut() {
108            queue.shutdown();
109        }
110    }
111}
112
113impl Drop for QueueHandle {
114    fn drop(&mut self) {
115        self.shutdown();
116    }
117}
118
119#[derive(Clone)]
120pub struct IrqHandlerSlot {
121    inner: Arc<Mutex<Option<BIrqHandler>>>,
122}
123
124impl IrqHandlerSlot {
125    pub fn new(handler: BIrqHandler) -> Self {
126        Self {
127            inner: Arc::new(Mutex::new(Some(handler))),
128        }
129    }
130
131    pub fn take(&self) -> Option<IrqHandlerHandle> {
132        let handler = self.inner.lock().take()?;
133        Some(IrqHandlerHandle {
134            slot: Self {
135                inner: Arc::clone(&self.inner),
136            },
137            handler: Some(handler),
138        })
139    }
140}
141
142pub struct IrqHandlerHandle {
143    slot: IrqHandlerSlot,
144    handler: Option<BIrqHandler>,
145}
146
147impl IrqHandler for IrqHandlerHandle {
148    fn handle_irq(&self) -> crate::Event {
149        self.handler
150            .as_ref()
151            .expect("IRQ handler handle must contain handler")
152            .handle_irq()
153    }
154}
155
156impl Drop for IrqHandlerHandle {
157    fn drop(&mut self) {
158        if let Some(handler) = self.handler.take() {
159            let mut slot = self.slot.inner.lock();
160            debug_assert!(slot.is_none());
161            *slot = Some(handler);
162        }
163    }
164}
165
166/// A request queue for one block device hardware/software queue.
167///
168/// # Safety
169///
170/// Implementers may access `Request` segments after `submit_request` returns
171/// and until the matching `poll_request` returns `RequestStatus::Complete` or
172/// an error. They must not access any segment before `submit_request` is called
173/// or after completion/error has been reported, and request IDs must not alias
174/// two concurrently pending requests in a way that extends this lifetime.
175pub unsafe trait IQueue: Send + 'static {
176    fn id(&self) -> usize;
177
178    fn info(&self) -> QueueInfo;
179
180    fn submit_request(&mut self, request: Request<'_>) -> Result<RequestId, BlkError>;
181
182    fn poll_request(&mut self, request: RequestId) -> Result<RequestStatus, BlkError>;
183
184    /// Poll a set of in-flight requests and report observed terminal results.
185    ///
186    /// Implementers must report per-request completion or failure through
187    /// `sink.complete`. The return value describes the batch query itself:
188    /// `Err` means this poll attempt did not reliably observe request states
189    /// and must not be interpreted as terminal status for any request that was
190    /// not reported to the sink.
191    ///
192    /// `BlkError::Retry` is submit-side backpressure only. `poll_request` and
193    /// `poll_completions` must not return `Retry`; pending requests are
194    /// represented by omitting them from the sink in this method.
195    fn poll_completions(
196        &mut self,
197        requests: &[RequestId],
198        sink: &mut dyn CompletionSink,
199    ) -> Result<(), BlkError> {
200        for &request in requests {
201            match self.poll_request(request) {
202                Ok(RequestStatus::Pending) => {}
203                Ok(RequestStatus::Complete) => sink.complete(request, Ok(())),
204                Err(err) => sink.complete(request, Err(err)),
205            }
206        }
207        Ok(())
208    }
209}
210
211#[cfg(test)]
212mod tests {
213    use alloc::vec::Vec;
214
215    use super::*;
216    use crate::{DeviceInfo, Event, QueueLimits, RequestOp};
217
218    struct NoopIrq;
219
220    impl IrqHandler for NoopIrq {
221        fn handle_irq(&self) -> Event {
222            let mut event = Event::none();
223            event.queues.insert(1);
224            event
225        }
226    }
227
228    struct Queue;
229
230    // SAFETY: This test queue never stores request segments beyond
231    // `submit_request` and reports completion immediately.
232    unsafe impl IQueue for Queue {
233        fn id(&self) -> usize {
234            1
235        }
236
237        fn info(&self) -> QueueInfo {
238            QueueInfo {
239                id: 1,
240                device: DeviceInfo::new(8, 512),
241                limits: QueueLimits::simple(512, u64::MAX),
242            }
243        }
244
245        fn submit_request(&mut self, request: Request<'_>) -> Result<RequestId, BlkError> {
246            assert!(matches!(request.op, RequestOp::Read | RequestOp::Write));
247            Ok(RequestId::new(1))
248        }
249
250        fn poll_request(&mut self, _request: RequestId) -> Result<RequestStatus, BlkError> {
251            Ok(RequestStatus::Complete)
252        }
253    }
254
255    #[test]
256    fn block_api_uses_unified_queue_and_irq_events() {
257        fn assert_queue<T: IQueue>() {}
258        fn assert_irq_handler<T: IrqHandler>() {}
259
260        assert_queue::<Queue>();
261        assert_irq_handler::<NoopIrq>();
262
263        let event = NoopIrq.handle_irq();
264        assert!(event.queues.contains(1));
265    }
266
267    #[derive(Default)]
268    struct RecordingSink {
269        completions: Vec<(RequestId, Result<(), BlkError>)>,
270    }
271
272    impl CompletionSink for RecordingSink {
273        fn complete(&mut self, request_id: RequestId, result: Result<(), BlkError>) {
274            self.completions.push((request_id, result));
275        }
276    }
277
278    struct BatchQueue;
279
280    // SAFETY: This test queue never stores request segments and reports
281    // synthetic completion status from the requested ID only.
282    unsafe impl IQueue for BatchQueue {
283        fn id(&self) -> usize {
284            0
285        }
286
287        fn info(&self) -> QueueInfo {
288            QueueInfo {
289                id: 0,
290                device: DeviceInfo::new(8, 512),
291                limits: QueueLimits::simple(512, u64::MAX),
292            }
293        }
294
295        fn submit_request(&mut self, _request: Request<'_>) -> Result<RequestId, BlkError> {
296            Ok(RequestId::new(0))
297        }
298
299        fn poll_request(&mut self, request: RequestId) -> Result<RequestStatus, BlkError> {
300            match usize::from(request) {
301                1 => Ok(RequestStatus::Complete),
302                2 => Ok(RequestStatus::Pending),
303                3 => Err(BlkError::Io),
304                _ => Err(BlkError::InvalidRequest),
305            }
306        }
307    }
308
309    #[test]
310    fn default_batch_completion_polls_pending_ids_and_reports_terminal_results() {
311        let mut queue = BatchQueue;
312        let mut sink = RecordingSink::default();
313        let ids = [RequestId::new(1), RequestId::new(2), RequestId::new(3)];
314
315        queue.poll_completions(&ids, &mut sink).unwrap();
316
317        assert_eq!(
318            sink.completions,
319            [
320                (RequestId::new(1), Ok(())),
321                (RequestId::new(3), Err(BlkError::Io)),
322            ]
323        );
324    }
325
326    #[test]
327    fn simple_queue_limits_are_single_inflight() {
328        let limits = QueueLimits::simple(512, u64::MAX);
329
330        assert_eq!(limits.max_inflight, 1);
331    }
332
333    #[test]
334    fn irq_handler_slot_returns_handler_on_drop() {
335        let slot = IrqHandlerSlot::new(Box::new(NoopIrq));
336        let handler = slot.take().unwrap();
337
338        assert!(slot.take().is_none());
339        assert!(handler.handle_irq().queues.contains(1));
340
341        drop(handler);
342        assert!(slot.take().is_some());
343    }
344
345    struct OwnedQueue;
346
347    impl IQueueOwned for OwnedQueue {
348        fn id(&self) -> usize {
349            2
350        }
351
352        fn info(&self) -> QueueInfo {
353            QueueInfo {
354                id: 2,
355                device: DeviceInfo::new(8, 512),
356                limits: QueueLimits::simple(512, u64::MAX),
357            }
358        }
359
360        fn submit_request(&mut self, request: OwnedRequest) -> Result<RequestId, SubmitError> {
361            Err(SubmitError::new(BlkError::Retry, request))
362        }
363
364        fn poll_request(&mut self, _request: RequestId) -> Result<RequestPoll, PollError> {
365            Ok(RequestPoll::Pending)
366        }
367
368        fn cancel_request(&mut self, _request: RequestId) -> Result<RequestPoll, PollError> {
369            Err(PollError::UnknownRequest)
370        }
371    }
372
373    #[test]
374    fn owned_queue_submit_error_returns_request_ownership() {
375        let mut handle = QueueHandle::new(Box::new(OwnedQueue));
376        let request = OwnedRequest {
377            op: RequestOp::Flush,
378            lba: 0,
379            block_count: 0,
380            data: None,
381            flags: Default::default(),
382        };
383
384        let err = handle.submit_request(request).unwrap_err();
385
386        assert_eq!(err.error, BlkError::Retry);
387        assert!(matches!(err.request().op, RequestOp::Flush));
388    }
389}