1use alloc::boxed::Box;
2use core::{
3 marker::PhantomData,
4 ops::{Deref, DerefMut},
5};
6
7use dma_api::{CompletedDma, PreparedDma};
8
9use crate::{BlkError, DeviceInfo, QueueInfo, QueueLimits};
10
11#[repr(transparent)]
12#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
13pub struct RequestId(usize);
14
15impl RequestId {
16 pub const fn new(id: usize) -> Self {
17 Self(id)
18 }
19}
20
21impl From<RequestId> for usize {
22 fn from(value: RequestId) -> Self {
23 value.0
24 }
25}
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28pub enum RequestStatus {
29 Pending,
30 Complete,
31}
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34pub enum RequestOp {
35 Read,
36 Write,
37 Flush,
38 Discard,
39 WriteZeroes,
40}
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq)]
43pub struct RequestFlags(u32);
44
45impl RequestFlags {
46 pub const NONE: Self = Self(0);
47 pub const FUA: Self = Self(1 << 0);
48 pub const PREFLUSH: Self = Self(1 << 1);
49 pub const SYNC: Self = Self(1 << 2);
50 pub const META: Self = Self(1 << 3);
51 pub const POLLED: Self = Self(1 << 4);
52 pub const NOWAIT: Self = Self(1 << 5);
53 pub const ALL_KNOWN: Self = Self(
54 Self::FUA.bits()
55 | Self::PREFLUSH.bits()
56 | Self::SYNC.bits()
57 | Self::META.bits()
58 | Self::POLLED.bits()
59 | Self::NOWAIT.bits(),
60 );
61
62 pub const fn bits(self) -> u32 {
63 self.0
64 }
65
66 pub const fn is_empty(self) -> bool {
67 self.0 == 0
68 }
69
70 pub const fn contains(self, other: Self) -> bool {
71 (self.0 & other.0) == other.0
72 }
73
74 pub const fn intersects(self, other: Self) -> bool {
75 (self.0 & other.0) != 0
76 }
77
78 pub const fn unsupported_by(self, supported: Self) -> Self {
79 Self(self.0 & !supported.0)
80 }
81}
82
83impl core::ops::BitOr for RequestFlags {
84 type Output = Self;
85
86 fn bitor(self, rhs: Self) -> Self::Output {
87 Self(self.0 | rhs.0)
88 }
89}
90
91impl core::ops::BitOrAssign for RequestFlags {
92 fn bitor_assign(&mut self, rhs: Self) {
93 self.0 |= rhs.0;
94 }
95}
96
97impl Default for RequestFlags {
98 fn default() -> Self {
99 Self::NONE
100 }
101}
102
103#[derive(Clone, Copy)]
104pub struct Segment<'a> {
105 pub virt: *mut u8,
106 pub bus: u64,
107 pub len: usize,
108 _marker: PhantomData<&'a mut [u8]>,
109}
110
111impl<'a> Segment<'a> {
112 pub unsafe fn from_raw_parts(virt: *mut u8, bus: u64, len: usize) -> Self {
121 Self {
122 virt,
123 bus,
124 len,
125 _marker: PhantomData,
126 }
127 }
128}
129
130impl Deref for Segment<'_> {
131 type Target = [u8];
132
133 fn deref(&self) -> &Self::Target {
134 unsafe { core::slice::from_raw_parts(self.virt, self.len) }
135 }
136}
137
138impl DerefMut for Segment<'_> {
139 fn deref_mut(&mut self) -> &mut Self::Target {
140 unsafe { core::slice::from_raw_parts_mut(self.virt, self.len) }
141 }
142}
143
144pub type Buffer<'a> = Segment<'a>;
145
146pub struct Request<'a> {
147 pub op: RequestOp,
148 pub lba: u64,
149 pub block_count: u32,
150 pub segments: &'a mut [Segment<'a>],
151 pub flags: RequestFlags,
152}
153
154impl Request<'_> {
155 pub fn data_len(&self) -> usize {
156 self.segments.iter().map(|segment| segment.len).sum()
157 }
158
159 pub fn is_data_op(&self) -> bool {
160 matches!(self.op, RequestOp::Read | RequestOp::Write)
161 }
162}
163
164pub struct OwnedRequest {
166 pub op: RequestOp,
167 pub lba: u64,
168 pub block_count: u32,
169 pub data: Option<PreparedDma>,
170 pub flags: RequestFlags,
171}
172
173impl OwnedRequest {
174 pub fn data_len(&self) -> usize {
175 self.data.as_ref().map_or(0, |data| data.len().get())
176 }
177
178 pub fn is_data_op(&self) -> bool {
179 matches!(self.op, RequestOp::Read | RequestOp::Write)
180 }
181}
182
183pub struct SubmitError {
185 pub error: BlkError,
186 request: Box<OwnedRequest>,
187}
188
189impl SubmitError {
190 pub fn new(error: BlkError, request: OwnedRequest) -> Self {
191 Self {
192 error,
193 request: Box::new(request),
194 }
195 }
196
197 pub fn into_request(self) -> OwnedRequest {
198 *self.request
199 }
200
201 pub fn request(&self) -> &OwnedRequest {
202 &self.request
203 }
204}
205
206pub struct CompletedRequest {
208 pub id: RequestId,
209 pub result: Result<(), BlkError>,
210 pub data: Option<CompletedDma>,
211}
212
213impl CompletedRequest {
214 pub const fn new(
215 id: RequestId,
216 result: Result<(), BlkError>,
217 data: Option<CompletedDma>,
218 ) -> Self {
219 Self { id, result, data }
220 }
221}
222
223pub enum RequestPoll {
225 Pending,
226 Ready(CompletedRequest),
227}
228
229#[derive(Debug, Clone, Copy, PartialEq, Eq)]
234pub enum PollError {
235 UnknownRequest,
236 WrongQueue,
237 DriverPoisoned,
238}
239
240impl From<PollError> for BlkError {
241 fn from(value: PollError) -> Self {
242 match value {
243 PollError::UnknownRequest | PollError::WrongQueue => BlkError::InvalidRequest,
244 PollError::DriverPoisoned => BlkError::Io,
245 }
246 }
247}
248
249pub fn validate_request(info: QueueInfo, request: &Request<'_>) -> Result<(), BlkError> {
250 validate_request_flags(info, request.flags)?;
251 validate_request_shape(info.device, info.limits, request)
252}
253
254pub fn validate_request_shape(
255 info: DeviceInfo,
256 limits: QueueLimits,
257 request: &Request<'_>,
258) -> Result<(), BlkError> {
259 if request.block_count == 0 && !matches!(request.op, RequestOp::Flush) {
260 return Err(BlkError::InvalidRequest);
261 }
262
263 if request.lba >= info.num_blocks
264 || request
265 .lba
266 .checked_add(request.block_count as u64)
267 .is_none_or(|end| end > info.num_blocks)
268 {
269 return Err(BlkError::InvalidBlockIndex(request.lba));
270 }
271
272 match request.op {
273 RequestOp::Read | RequestOp::Write => {
274 let expected = request
275 .block_count
276 .checked_mul(info.logical_block_size as u32)
277 .map(|len| len as usize)
278 .ok_or(BlkError::InvalidRequest)?;
279 if request.segments.is_empty()
280 || request.segments.len() > limits.max_segments
281 || request.data_len() != expected
282 {
283 return Err(BlkError::InvalidRequest);
284 }
285 if request
286 .segments
287 .iter()
288 .any(|segment| segment.len > limits.max_segment_size)
289 {
290 return Err(BlkError::InvalidRequest);
291 }
292 }
293 RequestOp::Flush => {
294 if !request.segments.is_empty() || request.block_count != 0 {
295 return Err(BlkError::InvalidRequest);
296 }
297 if !limits.supports_flush {
298 return Err(BlkError::NotSupported);
299 }
300 }
301 RequestOp::Discard => {
302 if !request.segments.is_empty() {
303 return Err(BlkError::InvalidRequest);
304 }
305 if !limits.supports_discard {
306 return Err(BlkError::NotSupported);
307 }
308 }
309 RequestOp::WriteZeroes => {
310 if !request.segments.is_empty() {
311 return Err(BlkError::InvalidRequest);
312 }
313 if !limits.supports_write_zeroes {
314 return Err(BlkError::NotSupported);
315 }
316 }
317 }
318
319 if request.block_count > limits.max_blocks_per_request {
320 return Err(BlkError::InvalidRequest);
321 }
322
323 Ok(())
324}
325
326pub fn validate_owned_request(info: QueueInfo, request: &OwnedRequest) -> Result<(), BlkError> {
327 validate_request_flags(info, request.flags)?;
328 validate_owned_request_shape(info.device, info.limits, request)
329}
330
331pub fn validate_owned_request_shape(
332 info: DeviceInfo,
333 limits: QueueLimits,
334 request: &OwnedRequest,
335) -> Result<(), BlkError> {
336 if request.block_count == 0 && !matches!(request.op, RequestOp::Flush) {
337 return Err(BlkError::InvalidRequest);
338 }
339
340 if request.lba >= info.num_blocks
341 || request
342 .lba
343 .checked_add(request.block_count as u64)
344 .is_none_or(|end| end > info.num_blocks)
345 {
346 return Err(BlkError::InvalidBlockIndex(request.lba));
347 }
348
349 match request.op {
350 RequestOp::Read | RequestOp::Write => {
351 let expected = request
352 .block_count
353 .checked_mul(info.logical_block_size as u32)
354 .map(|len| len as usize)
355 .ok_or(BlkError::InvalidRequest)?;
356 if request.data_len() != expected {
357 return Err(BlkError::InvalidRequest);
358 }
359 let Some(data) = &request.data else {
360 return Err(BlkError::InvalidRequest);
361 };
362 let segments = data.segments();
363 if segments.is_empty()
364 || segments.len() > limits.max_segments
365 || segments
366 .iter()
367 .any(|segment| segment.len.get() > limits.max_segment_size)
368 {
369 return Err(BlkError::InvalidRequest);
370 }
371 }
372 RequestOp::Flush => {
373 if request.data.is_some() || request.block_count != 0 {
374 return Err(BlkError::InvalidRequest);
375 }
376 if !limits.supports_flush {
377 return Err(BlkError::NotSupported);
378 }
379 }
380 RequestOp::Discard => {
381 if request.data.is_some() {
382 return Err(BlkError::InvalidRequest);
383 }
384 if !limits.supports_discard {
385 return Err(BlkError::NotSupported);
386 }
387 }
388 RequestOp::WriteZeroes => {
389 if request.data.is_some() {
390 return Err(BlkError::InvalidRequest);
391 }
392 if !limits.supports_write_zeroes {
393 return Err(BlkError::NotSupported);
394 }
395 }
396 }
397
398 if request.block_count > limits.max_blocks_per_request {
399 return Err(BlkError::InvalidRequest);
400 }
401
402 Ok(())
403}
404
405fn validate_request_flags(info: QueueInfo, flags: RequestFlags) -> Result<(), BlkError> {
406 let unknown = flags.unsupported_by(RequestFlags::ALL_KNOWN);
407 if !unknown.is_empty() {
408 return Err(BlkError::InvalidRequest);
409 }
410
411 let unsupported = flags.unsupported_by(info.limits.supported_flags);
412 if !unsupported.is_empty() {
413 return Err(BlkError::NotSupported);
414 }
415
416 if flags.intersects(RequestFlags::PREFLUSH) && !info.limits.supports_flush {
417 return Err(BlkError::NotSupported);
418 }
419
420 Ok(())
421}
422
423#[cfg(test)]
424mod tests {
425 use super::*;
426
427 #[test]
428 fn request_status_distinguishes_pending_from_errors() {
429 assert_eq!(RequestStatus::Pending, RequestStatus::Pending);
430 assert_ne!(RequestStatus::Pending, RequestStatus::Complete);
431 }
432
433 #[test]
434 fn segment_carries_cpu_and_dma_addresses() {
435 let mut bytes = [0x5a_u8; 4];
436 let segment = unsafe { Segment::from_raw_parts(bytes.as_mut_ptr(), 0x1000, bytes.len()) };
437
438 assert_eq!(segment.bus, 0x1000);
439 assert_eq!(&*segment, &[0x5a; 4]);
440 }
441
442 #[test]
443 fn request_shape_checks_lba_and_segments() {
444 let info = DeviceInfo::new(8, 512);
445 let limits = QueueLimits {
446 max_blocks_per_request: 8,
447 max_segment_size: 1024,
448 ..QueueLimits::simple(512, u64::MAX)
449 };
450 let mut bytes = [0_u8; 1024];
451 let segment = unsafe { Segment::from_raw_parts(bytes.as_mut_ptr(), 0x1000, bytes.len()) };
452 let mut segments = [segment];
453 let request = Request {
454 op: RequestOp::Read,
455 lba: 1,
456 block_count: 2,
457 segments: &mut segments,
458 flags: RequestFlags::NONE,
459 };
460
461 assert_eq!(validate_request_shape(info, limits, &request), Ok(()));
462 }
463
464 #[test]
465 fn request_shape_rejects_wrong_segment_size() {
466 let info = DeviceInfo::new(8, 512);
467 let limits = QueueLimits::simple(512, u64::MAX);
468 let mut bytes = [0_u8; 512];
469 let segment = unsafe { Segment::from_raw_parts(bytes.as_mut_ptr(), 0x1000, bytes.len()) };
470 let mut segments = [segment];
471 let request = Request {
472 op: RequestOp::Write,
473 lba: 1,
474 block_count: 2,
475 segments: &mut segments,
476 flags: RequestFlags::NONE,
477 };
478
479 assert_eq!(
480 validate_request_shape(info, limits, &request),
481 Err(BlkError::InvalidRequest)
482 );
483 }
484
485 fn queue_info_with(limits: QueueLimits) -> QueueInfo {
486 QueueInfo {
487 id: 0,
488 device: DeviceInfo::new(64, 512),
489 limits,
490 }
491 }
492
493 #[test]
494 fn request_validation_rejects_unsupported_flags() {
495 let info = queue_info_with(QueueLimits::simple(512, u64::MAX));
496 let mut bytes = [0_u8; 512];
497 let segment = unsafe { Segment::from_raw_parts(bytes.as_mut_ptr(), 0x1000, bytes.len()) };
498 let mut segments = [segment];
499 let request = Request {
500 op: RequestOp::Write,
501 lba: 0,
502 block_count: 1,
503 segments: &mut segments,
504 flags: RequestFlags::FUA,
505 };
506
507 assert_eq!(
508 validate_request(info, &request),
509 Err(BlkError::NotSupported)
510 );
511 }
512
513 #[test]
514 fn request_validation_rejects_unknown_flags() {
515 let info = queue_info_with(QueueLimits::simple(512, u64::MAX));
516 let mut bytes = [0_u8; 512];
517 let segment = unsafe { Segment::from_raw_parts(bytes.as_mut_ptr(), 0x1000, bytes.len()) };
518 let mut segments = [segment];
519 let request = Request {
520 op: RequestOp::Read,
521 lba: 0,
522 block_count: 1,
523 segments: &mut segments,
524 flags: RequestFlags(1 << 24),
525 };
526
527 assert_eq!(
528 validate_request(info, &request),
529 Err(BlkError::InvalidRequest)
530 );
531 }
532
533 #[test]
534 fn request_validation_accepts_supported_flags() {
535 let mut limits = QueueLimits::simple(512, u64::MAX);
536 limits.supported_flags = RequestFlags::FUA;
537 let info = queue_info_with(limits);
538 let mut bytes = [0_u8; 512];
539 let segment = unsafe { Segment::from_raw_parts(bytes.as_mut_ptr(), 0x1000, bytes.len()) };
540 let mut segments = [segment];
541 let request = Request {
542 op: RequestOp::Write,
543 lba: 0,
544 block_count: 1,
545 segments: &mut segments,
546 flags: RequestFlags::FUA,
547 };
548
549 assert_eq!(validate_request(info, &request), Ok(()));
550 }
551
552 #[test]
553 fn preflush_flag_requires_flush_support() {
554 let mut limits = QueueLimits::simple(512, u64::MAX);
555 limits.supported_flags = RequestFlags::PREFLUSH;
556 let info = queue_info_with(limits);
557 let mut bytes = [0_u8; 512];
558 let segment = unsafe { Segment::from_raw_parts(bytes.as_mut_ptr(), 0x1000, bytes.len()) };
559 let mut segments = [segment];
560 let request = Request {
561 op: RequestOp::Write,
562 lba: 0,
563 block_count: 1,
564 segments: &mut segments,
565 flags: RequestFlags::PREFLUSH,
566 };
567
568 assert_eq!(
569 validate_request(info, &request),
570 Err(BlkError::NotSupported)
571 );
572 }
573
574 #[test]
575 fn request_validation_rejects_transfer_larger_than_hard_block_limit() {
576 let info = queue_info_with(QueueLimits {
577 dma_mask: u64::MAX,
578 dma_domain: dma_api::DmaDomainId::legacy_global(),
579 dma_alignment: 512,
580 max_inflight: 1,
581 max_blocks_per_request: 2,
582 max_segments: 1,
583 max_segment_size: 4096,
584 supported_flags: RequestFlags::NONE,
585 supports_flush: false,
586 supports_discard: false,
587 supports_write_zeroes: false,
588 });
589 let mut bytes = [0_u8; 1536];
590 let segment = unsafe { Segment::from_raw_parts(bytes.as_mut_ptr(), 0x1000, bytes.len()) };
591 let mut segments = [segment];
592 let request = Request {
593 op: RequestOp::Write,
594 lba: 0,
595 block_count: 3,
596 segments: &mut segments,
597 flags: RequestFlags::NONE,
598 };
599
600 assert_eq!(
601 validate_request(info, &request),
602 Err(BlkError::InvalidRequest)
603 );
604 }
605}