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 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 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}