Skip to main content

nvme_driver/
nvme.rs

1use alloc::vec::Vec;
2use core::ptr::NonNull;
3
4use dma_api::{DeviceDma, DmaDirection, DmaOp};
5use log::{debug, info};
6use mmio_api::{Mmio, MmioAddr, MmioOp};
7
8use crate::{
9    command::{
10        self, ControllerInfo, Feature, Identify, IdentifyActiveNamespaceList, IdentifyController,
11        IdentifyNamespaceDataStructure,
12    },
13    err::*,
14    queue::{CommandSet, NvmeQueue},
15    registers::NvmeReg,
16};
17
18pub struct Nvme {
19    bar: NonNull<NvmeReg>,
20    _mmio: Option<Mmio>,
21    dma: DeviceDma,
22    admin_queue: NvmeQueue,
23    io_queues: Vec<NvmeQueue>,
24    num_ns: usize,
25    sqes: u32,
26    cqes: u32,
27}
28
29#[derive(Debug, Clone, Copy)]
30pub struct Config {
31    pub page_size: usize,
32    pub io_queue_pair_count: usize,
33}
34
35impl Nvme {
36    pub fn new(
37        bar_addr: impl Into<MmioAddr>,
38        bar_size: usize,
39        dma_mask: u64,
40        dma_op: &'static dyn DmaOp,
41        mmio_op: &'static dyn MmioOp,
42        config: Config,
43    ) -> Result<Self> {
44        mmio_api::init(mmio_op);
45        let mmio = mmio_api::ioremap(bar_addr.into(), bar_size)?;
46        let dma = DeviceDma::new(dma_mask, dma_op);
47        Self::new_mmio(mmio, dma, config)
48    }
49
50    fn new_mmio(mmio: Mmio, dma: DeviceDma, config: Config) -> Result<Self> {
51        let bar = NonNull::new(mmio.as_ptr()).expect("mmio mapping must not be null");
52        Self::new_with_bar(bar.cast(), Some(mmio), dma, config)
53    }
54
55    fn new_with_bar(
56        bar: NonNull<NvmeReg>,
57        mmio: Option<Mmio>,
58        dma: DeviceDma,
59        config: Config,
60    ) -> Result<Self> {
61        let admin_queue = NvmeQueue::new(0, bar, &dma, config.page_size, 64, 64)?;
62
63        assert!(config.io_queue_pair_count > 0);
64
65        let mut s = Self {
66            bar,
67            _mmio: mmio,
68            dma,
69            admin_queue,
70            io_queues: Vec::new(),
71            num_ns: 0,
72            sqes: 6,
73            cqes: 4,
74        };
75
76        let version = s.version();
77
78        info!(
79            "NVME @{bar:?} init begin, version: {}.{}.{} ",
80            version.0, version.1, version.2
81        );
82
83        s.init(config)?;
84
85        Ok(s)
86    }
87
88    pub fn dma_mask(&self) -> u64 {
89        self.dma.dma_mask()
90    }
91
92    fn reset(&mut self) {
93        self.reg().reset();
94    }
95
96    fn reset_and_setup_controller_info(&mut self) -> Result<ControllerInfo> {
97        self.reset();
98
99        self.nvme_configure_admin_queue();
100
101        self.reg().ready_for_read_controller_info();
102
103        self.get_identfy(IdentifyController::new())
104    }
105
106    fn init(&mut self, config: Config) -> Result {
107        let controller = self.reset_and_setup_controller_info()?;
108
109        debug!("Controller: {:?}", controller);
110
111        self.sqes = controller.sqes_min as _;
112        self.cqes = controller.cqes_min as _;
113
114        self.reset();
115
116        self.nvme_configure_admin_queue();
117
118        self.reg().setup_cc(self.sqes, self.cqes);
119
120        let controller = self.get_identfy(IdentifyController::new())?;
121
122        debug!("Controller: {:?}", controller);
123
124        self.num_ns = controller.number_of_namespaces as _;
125
126        self.config_io_queue(config)?;
127
128        debug!("IO queue ok.");
129        loop {
130            let ns = self.get_identfy(IdentifyNamespaceDataStructure::new(1))?;
131            if let Some(ns) = ns {
132                debug!("Namespace: {:?}", ns);
133                break;
134            }
135        }
136        debug!("Namespace ok.");
137        Ok(())
138    }
139
140    pub fn namespace_list(&mut self) -> Result<Vec<Namespace>> {
141        let id_list = self.get_identfy(IdentifyActiveNamespaceList::new())?;
142        let mut out = Vec::new();
143
144        for id in id_list {
145            let ns = self
146                .get_identfy(IdentifyNamespaceDataStructure::new(id))?
147                .unwrap();
148
149            out.push(Namespace {
150                id,
151                lba_size: ns.lba_size as _,
152                lba_count: ns.namespace_size as _,
153                metadata_size: ns.metadata_size as _,
154            });
155        }
156
157        Ok(out)
158    }
159
160    // config admin queue
161    // 1. set admin queue(cq && sq) size
162    // 2. set admin queue(cq && sq) dma address
163    // 3. enable ctrl
164    fn nvme_configure_admin_queue(&mut self) {
165        self.reg().set_admin_submission_and_completion_queue_size(
166            self.admin_queue.sq.len(),
167            self.admin_queue.cq.len(),
168        );
169
170        self.reg()
171            .set_admin_submission_queue_base_address(self.admin_queue.sq.bus_addr());
172
173        self.reg()
174            .set_admin_completion_queue_base_address(self.admin_queue.cq.bus_addr());
175    }
176
177    fn config_io_queue(&mut self, config: Config) -> Result {
178        let num = config.io_queue_pair_count;
179        // 设置 io queue 数量
180        let cmd = CommandSet::set_features(Feature::NumberOfQueues {
181            nsq: num as u32 - 1,
182            ncq: num as u32 - 1,
183        });
184        self.admin_queue.command_sync(cmd)?;
185
186        for i in 0..num {
187            let id = (i + 1) as u32;
188            let io_queue = NvmeQueue::new(
189                id,
190                self.bar,
191                &self.dma,
192                config.page_size,
193                2usize.pow(self.sqes as _),
194                2usize.pow(self.cqes as _),
195            )?;
196
197            let data = CommandSet::create_io_completion_queue(
198                io_queue.qid,
199                io_queue.cq.len() as _,
200                io_queue.cq.bus_addr(),
201                true,
202                false,
203                0,
204            );
205            self.admin_queue.command_sync(data)?;
206
207            let data = CommandSet::create_io_submission_queue(
208                io_queue.qid,
209                io_queue.sq.len() as _,
210                io_queue.sq.bus_addr(),
211                true,
212                0,
213                io_queue.qid,
214                0,
215            );
216
217            self.admin_queue.command_sync(data)?;
218
219            self.io_queues.push(io_queue);
220        }
221
222        Ok(())
223    }
224
225    pub fn get_identfy<T: Identify>(&mut self, mut want: T) -> Result<T::Output> {
226        let cmd = want.command_set_mut();
227
228        cmd.cdw0 = CommandSet::cdw0_from_opcode(command::Opcode::IDENTIFY);
229        cmd.cdw10 = T::CNS;
230
231        let buff =
232            self.dma
233                .array_zero_with_align::<u8>(0x1000, 0x1000, DmaDirection::FromDevice)?;
234        cmd.prp1 = buff.dma_addr().as_u64();
235
236        self.admin_queue.command_sync(*cmd)?;
237
238        let data: Vec<u8> = buff.iter().collect();
239        let res = want.parse(&data);
240        Ok(res)
241    }
242
243    pub fn block_write_sync(
244        &mut self,
245        ns: &Namespace,
246        block_start: u64,
247        buff: &[u8],
248    ) -> Result<()> {
249        assert!(
250            buff.len().is_multiple_of(ns.lba_size),
251            "buffer size must be multiple of lba size"
252        );
253
254        let mut dma_buff = self.dma.array_zero_with_align::<u8>(
255            buff.len(),
256            ns.lba_size,
257            DmaDirection::ToDevice,
258        )?;
259        dma_buff.copy_from_slice(buff);
260
261        let blk_num = dma_buff.len() / ns.lba_size;
262
263        let cmd = CommandSet::nvm_cmd_write(
264            ns.id,
265            dma_buff.dma_addr().as_u64(),
266            block_start,
267            blk_num as _,
268        );
269
270        self.io_queues[0].command_sync(cmd)?;
271
272        Ok(())
273    }
274
275    pub fn block_read_sync(
276        &mut self,
277        ns: &Namespace,
278        block_start: u64,
279        buff: &mut [u8],
280    ) -> Result<()> {
281        assert!(
282            buff.len().is_multiple_of(ns.lba_size),
283            "buffer size must be multiple of lba size"
284        );
285
286        let dma_buff = self.dma.array_zero_with_align::<u8>(
287            buff.len(),
288            ns.lba_size,
289            DmaDirection::FromDevice,
290        )?;
291
292        let blk_num = dma_buff.len() / ns.lba_size;
293
294        let cmd = CommandSet::nvm_cmd_read(
295            ns.id,
296            dma_buff.dma_addr().as_u64(),
297            block_start,
298            blk_num as _,
299        );
300
301        self.io_queues[0].command_sync(cmd)?;
302
303        for (index, value) in dma_buff.iter().enumerate() {
304            buff[index] = value;
305        }
306        Ok(())
307    }
308
309    pub fn version(&self) -> (usize, usize, usize) {
310        self.reg().version()
311    }
312
313    fn reg(&self) -> &NvmeReg {
314        unsafe { self.bar.as_ref() }
315    }
316}
317
318unsafe impl Send for Nvme {}
319
320#[derive(Debug, Clone, Copy)]
321pub struct Namespace {
322    pub id: u32,
323    pub lba_size: usize,
324    pub lba_count: usize,
325    pub metadata_size: usize,
326}