1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
use modular_bitfield::prelude::*;

use crate::ds::{
    cmd::{admin::AdminCommand, PrpListOrBuffer},
    namespace::NamespaceId,
    queue::{
        subentry::{CommandDword0, CommonCommand, Dptr, FuseSpec, Psdt},
        CommandId, QueueId, QueueSize,
    },
    Address, InterruptVector,
};

use super::{
    dataset::{AccessFrequency, AccessLatency},
    NvmCommand,
};

#[bitfield(bits = 32)]
#[repr(u32)]
struct ReadDword10 {
    start_lba_lo: u32,
}

#[bitfield(bits = 32)]
#[repr(u32)]
struct ReadDword11 {
    start_lba_hi: u32,
}

#[bitfield(bits = 32)]
#[repr(u32)]
struct ReadDword12 {
    pub nr_blocks: u16,
    #[skip]
    resv: B14,
    pub force_unit_access: B1,
    pub limited_retry: B1,
}

#[bitfield(bits = 32)]
#[derive(Debug, Clone, Copy, Default)]
#[repr(u32)]
pub struct ReadDword13 {
    pub access_frequency: AccessFrequency,
    pub access_latency: AccessLatency,
    pub sequenial: bool,
    pub incompressable: bool,
    #[skip]
    resv: B24,
}

pub struct ReadCommand {
    dw10: ReadDword10,
    dw11: ReadDword11,
    dw12: ReadDword12,
    dw13: ReadDword13,
    dptr: Dptr,
    cdw0: CommandDword0,
    nsid: NamespaceId,
}

impl ReadCommand {
    /// Construct a Create IO Completion Queue request. See base spec section 5.4 for more details.
    pub fn new(
        cid: CommandId,
        nsid: NamespaceId,
        dptr: Dptr,
        start_lba: u64,
        nr_blocks: u16,
        access_info: ReadDword13,
    ) -> Self {
        Self {
            dw10: ReadDword10::new().with_start_lba_lo(start_lba as u32),
            dw11: ReadDword11::new().with_start_lba_hi((start_lba >> 32) as u32),
            dw12: ReadDword12::new().with_nr_blocks(nr_blocks - 1),
            dw13: access_info,
            dptr,
            cdw0: CommandDword0::build(NvmCommand::Read.into(), cid, FuseSpec::Normal, Psdt::Prp),
            nsid,
        }
    }
}

impl From<ReadCommand> for CommonCommand {
    fn from(c: ReadCommand) -> Self {
        Self::new()
            .with_cdw0(c.cdw0)
            .with_cdw10(c.dw10.into())
            .with_cdw11(c.dw11.into())
            .with_cdw12(c.dw12.into())
            .with_cdw13(c.dw13.into())
            .with_nsid(c.nsid)
            .with_dptr(c.dptr)
    }
}