1use alloc::{boxed::Box, vec::Vec};
2
3use crate::{
4 BlkError, DeviceInfo, DriverGeneric, IrqHandler, IrqSourceList, OwnedRequest, PollError,
5 QueueInfo, QueueLimits, Request, RequestId, RequestPoll, RequestStatus, SubmitError,
6};
7
8pub type BInterface = Box<dyn Interface>;
9pub type BQueue = Box<dyn IQueue>;
10pub type BOwnedQueue = Box<dyn IQueueOwned>;
11pub type BIrqHandler = Box<dyn IrqHandler>;
12
13pub trait Interface: DriverGeneric {
14 fn device_info(&self) -> DeviceInfo;
15
16 fn queue_limits(&self) -> QueueLimits;
17
18 fn create_queue(&mut self) -> Option<BQueue>;
19
20 fn create_owned_queue(&mut self) -> Option<QueueHandle> {
21 None
22 }
23
24 fn enable_irq(&self) {}
25
26 fn disable_irq(&self) {}
27
28 fn is_irq_enabled(&self) -> bool {
29 false
30 }
31
32 fn irq_sources(&self) -> IrqSourceList {
33 Vec::new()
34 }
35
36 fn take_irq_handler(&mut self, _source_id: usize) -> Option<BIrqHandler> {
37 None
38 }
39}
40
41pub trait CompletionSink {
42 fn complete(&mut self, request: RequestId, result: Result<(), BlkError>);
43}
44
45pub trait IQueueOwned: Send + 'static {
47 fn id(&self) -> usize;
48
49 fn info(&self) -> QueueInfo;
50
51 fn submit_request(&mut self, request: OwnedRequest) -> Result<RequestId, SubmitError>;
52
53 fn poll_request(&mut self, request: RequestId) -> Result<RequestPoll, PollError>;
54
55 fn cancel_request(&mut self, request: RequestId) -> Result<RequestPoll, PollError>;
56
57 fn shutdown(&mut self) {}
58}
59
60pub struct QueueHandle {
61 queue: Option<BOwnedQueue>,
62}
63
64impl QueueHandle {
65 pub fn new(queue: BOwnedQueue) -> Self {
66 Self { queue: Some(queue) }
67 }
68
69 pub fn id(&self) -> usize {
70 self.queue
71 .as_ref()
72 .expect("owned queue handle must contain queue")
73 .id()
74 }
75
76 pub fn info(&self) -> QueueInfo {
77 self.queue
78 .as_ref()
79 .expect("owned queue handle must contain queue")
80 .info()
81 }
82
83 pub fn submit_request(&mut self, request: OwnedRequest) -> Result<RequestId, SubmitError> {
84 self.queue
85 .as_mut()
86 .expect("owned queue handle must contain queue")
87 .submit_request(request)
88 }
89
90 pub fn poll_request(&mut self, request: RequestId) -> Result<RequestPoll, PollError> {
91 self.queue
92 .as_mut()
93 .expect("owned queue handle must contain queue")
94 .poll_request(request)
95 }
96
97 pub fn cancel_request(&mut self, request: RequestId) -> Result<RequestPoll, PollError> {
98 self.queue
99 .as_mut()
100 .expect("owned queue handle must contain queue")
101 .cancel_request(request)
102 }
103
104 pub fn shutdown(&mut self) {
105 if let Some(queue) = self.queue.as_mut() {
106 queue.shutdown();
107 }
108 }
109}
110
111impl Drop for QueueHandle {
112 fn drop(&mut self) {
113 self.shutdown();
114 }
115}
116
117pub unsafe trait IQueue: Send + 'static {
127 fn id(&self) -> usize;
128
129 fn info(&self) -> QueueInfo;
130
131 fn submit_request(&mut self, request: Request<'_>) -> Result<RequestId, BlkError>;
132
133 fn poll_request(&mut self, request: RequestId) -> Result<RequestStatus, BlkError>;
134
135 fn poll_completions(
147 &mut self,
148 requests: &[RequestId],
149 sink: &mut dyn CompletionSink,
150 ) -> Result<(), BlkError> {
151 for &request in requests {
152 match self.poll_request(request) {
153 Ok(RequestStatus::Pending) => {}
154 Ok(RequestStatus::Complete) => sink.complete(request, Ok(())),
155 Err(err) => sink.complete(request, Err(err)),
156 }
157 }
158 Ok(())
159 }
160}
161
162#[cfg(test)]
163mod tests {
164 use alloc::vec::Vec;
165
166 use super::*;
167 use crate::{DeviceInfo, Event, QueueLimits, RequestOp};
168
169 struct NoopIrq {
170 calls: usize,
171 }
172
173 impl IrqHandler for NoopIrq {
174 fn handle_irq(&mut self) -> Event {
175 self.calls += 1;
176 let mut event = Event::none();
177 event.queues.insert(1);
178 event
179 }
180 }
181
182 struct Queue;
183
184 unsafe impl IQueue for Queue {
187 fn id(&self) -> usize {
188 1
189 }
190
191 fn info(&self) -> QueueInfo {
192 QueueInfo {
193 id: 1,
194 device: DeviceInfo::new(8, 512),
195 limits: QueueLimits::simple(512, u64::MAX),
196 }
197 }
198
199 fn submit_request(&mut self, request: Request<'_>) -> Result<RequestId, BlkError> {
200 assert!(matches!(request.op, RequestOp::Read | RequestOp::Write));
201 Ok(RequestId::new(1))
202 }
203
204 fn poll_request(&mut self, _request: RequestId) -> Result<RequestStatus, BlkError> {
205 Ok(RequestStatus::Complete)
206 }
207 }
208
209 #[test]
210 fn block_api_uses_unified_queue_and_irq_events() {
211 fn assert_queue<T: IQueue>() {}
212 fn assert_irq_handler<T: IrqHandler>() {}
213
214 assert_queue::<Queue>();
215 assert_irq_handler::<NoopIrq>();
216
217 let mut irq = NoopIrq { calls: 0 };
218 let event = irq.handle_irq();
219 assert!(event.queues.contains(1));
220 assert_eq!(irq.calls, 1);
221 }
222
223 #[derive(Default)]
224 struct RecordingSink {
225 completions: Vec<(RequestId, Result<(), BlkError>)>,
226 }
227
228 impl CompletionSink for RecordingSink {
229 fn complete(&mut self, request_id: RequestId, result: Result<(), BlkError>) {
230 self.completions.push((request_id, result));
231 }
232 }
233
234 struct BatchQueue;
235
236 unsafe impl IQueue for BatchQueue {
239 fn id(&self) -> usize {
240 0
241 }
242
243 fn info(&self) -> QueueInfo {
244 QueueInfo {
245 id: 0,
246 device: DeviceInfo::new(8, 512),
247 limits: QueueLimits::simple(512, u64::MAX),
248 }
249 }
250
251 fn submit_request(&mut self, _request: Request<'_>) -> Result<RequestId, BlkError> {
252 Ok(RequestId::new(0))
253 }
254
255 fn poll_request(&mut self, request: RequestId) -> Result<RequestStatus, BlkError> {
256 match usize::from(request) {
257 1 => Ok(RequestStatus::Complete),
258 2 => Ok(RequestStatus::Pending),
259 3 => Err(BlkError::Io),
260 _ => Err(BlkError::InvalidRequest),
261 }
262 }
263 }
264
265 #[test]
266 fn default_batch_completion_polls_pending_ids_and_reports_terminal_results() {
267 let mut queue = BatchQueue;
268 let mut sink = RecordingSink::default();
269 let ids = [RequestId::new(1), RequestId::new(2), RequestId::new(3)];
270
271 queue.poll_completions(&ids, &mut sink).unwrap();
272
273 assert_eq!(
274 sink.completions,
275 [
276 (RequestId::new(1), Ok(())),
277 (RequestId::new(3), Err(BlkError::Io)),
278 ]
279 );
280 }
281
282 #[test]
283 fn simple_queue_limits_are_single_inflight() {
284 let limits = QueueLimits::simple(512, u64::MAX);
285
286 assert_eq!(limits.max_inflight, 1);
287 }
288
289 struct CountingIrq {
290 count: usize,
291 }
292
293 impl IrqHandler for CountingIrq {
294 fn handle_irq(&mut self) -> Event {
295 self.count += 1;
296 Event::from_queue_bits(self.count as u64)
297 }
298 }
299
300 #[test]
301 fn boxed_irq_handler_is_move_only_and_mutable() {
302 let mut handler: BIrqHandler = Box::new(CountingIrq { count: 0 });
303
304 assert_eq!(handler.handle_irq().queues.bits(), 1);
305 assert_eq!(handler.handle_irq().queues.bits(), 2);
306 }
307
308 struct OwnedQueue;
309
310 impl IQueueOwned for OwnedQueue {
311 fn id(&self) -> usize {
312 2
313 }
314
315 fn info(&self) -> QueueInfo {
316 QueueInfo {
317 id: 2,
318 device: DeviceInfo::new(8, 512),
319 limits: QueueLimits::simple(512, u64::MAX),
320 }
321 }
322
323 fn submit_request(&mut self, request: OwnedRequest) -> Result<RequestId, SubmitError> {
324 Err(SubmitError::new(BlkError::Retry, request))
325 }
326
327 fn poll_request(&mut self, _request: RequestId) -> Result<RequestPoll, PollError> {
328 Ok(RequestPoll::Pending)
329 }
330
331 fn cancel_request(&mut self, _request: RequestId) -> Result<RequestPoll, PollError> {
332 Err(PollError::UnknownRequest)
333 }
334 }
335
336 #[test]
337 fn owned_queue_submit_error_returns_request_ownership() {
338 let mut handle = QueueHandle::new(Box::new(OwnedQueue));
339 let request = OwnedRequest {
340 op: RequestOp::Flush,
341 lba: 0,
342 block_count: 0,
343 data: None,
344 flags: Default::default(),
345 };
346
347 let err = handle.submit_request(request).unwrap_err();
348
349 assert_eq!(err.error, BlkError::Retry);
350 assert!(matches!(err.request().op, RequestOp::Flush));
351 }
352}