1#![allow(dead_code)]
12
13use crate::{
14 hardware::pci_client::{self as pci, Bar, ProbeCriteria},
15 memory::{allocate_zeroed_frame, paging, phys_to_virt},
16 sync::waitqueue::WaitQueue,
17};
18use alloc::{boxed::Box, format, string::String, sync::Arc, vec::Vec};
19use core::{
20 ptr,
21 sync::atomic::{AtomicBool, AtomicU8, Ordering},
22};
23use spin::Mutex;
24
25const NVME_PAGE_SIZE: usize = 4096;
26const IO_QUEUE_SIZE: usize = 64;
27const MAX_IO_COMMANDS: usize = IO_QUEUE_SIZE;
28const MAX_PRP_ENTRIES: usize = NVME_PAGE_SIZE / 8; const ADMIN_CQE_ERROR: u16 = (0x1 << 14) | (0x1 << 10);
31
32#[inline]
38fn rdtsc() -> u64 {
39 unsafe { core::arch::x86_64::_rdtsc() }
40}
41
42fn tsc_to_ms(ticks: u64) -> u64 {
45 ticks / 3_000_000
47}
48
49fn tsc_deadline_ms(ms: u32) -> u64 {
51 rdtsc().wrapping_add((ms as u64) * 3_000_000)
52}
53
54fn tsc_expired(deadline: u64) -> bool {
56 rdtsc() >= deadline
57}
58
59unsafe fn regs_read64(base: usize, offset: u64) -> u64 {
61 let low = core::ptr::read_volatile((base + offset as usize) as *const u32) as u64;
62 let high = core::ptr::read_volatile((base + offset as usize + 4) as *const u32) as u64;
63 low | (high << 32)
64}
65
66unsafe fn build_prp_list(buf_phys: u64, byte_count: usize) -> (u64, u64) {
75 let first_page_remaining = NVME_PAGE_SIZE - (buf_phys as usize % NVME_PAGE_SIZE);
76 if byte_count <= first_page_remaining {
77 return (buf_phys, 0);
78 }
79
80 let prp_frame = allocate_zeroed_frame().expect("NVMe: failed to allocate PRP list");
82 let prp_phys = prp_frame.start_address.as_u64();
83 paging::ensure_identity_map_range(prp_phys, NVME_PAGE_SIZE as u64);
84 let prp_virt = phys_to_virt(prp_phys) as *mut u64;
85
86 let mut remaining = byte_count - first_page_remaining;
88 let mut next_phys = (buf_phys & !0xFFF) + NVME_PAGE_SIZE as u64;
89 let mut idx = 0;
90
91 while remaining > 0 && idx < MAX_PRP_ENTRIES {
92 core::ptr::write_volatile(prp_virt.add(idx), next_phys);
93 idx += 1;
94 next_phys += NVME_PAGE_SIZE as u64;
95 remaining = remaining.saturating_sub(NVME_PAGE_SIZE);
96 }
97
98 (buf_phys, prp_phys)
99}
100
101#[repr(transparent)]
102struct VolatileCell<T> {
103 value: T,
104}
105
106impl<T> VolatileCell<T> {
107 fn read(&self) -> T
108 where
109 T: Copy,
110 {
111 unsafe { ptr::read_volatile(&self.value) }
112 }
113 fn write(&self, val: T) {
114 unsafe { ptr::write_volatile(core::ptr::addr_of!(self.value) as *mut T, val) }
115 }
116}
117
118unsafe impl<T: Send> Send for VolatileCell<T> {}
119unsafe impl<T: Sync> Sync for VolatileCell<T> {}
120
121#[repr(C)]
122struct Capability {
123 value: VolatileCell<u64>,
124}
125
126impl Capability {
127 fn max_queue_entries(&self) -> u16 {
128 (self.value.read() & 0xFFFF) as u16
129 }
130 fn doorbell_stride(&self) -> u64 {
131 (self.value.read() >> 32) & 0xF
132 }
133}
134
135#[repr(transparent)]
136struct Version {
137 value: VolatileCell<u32>,
138}
139
140#[repr(C)]
141struct ControllerConfig {
142 value: VolatileCell<u32>,
143}
144
145impl ControllerConfig {
146 fn clear_io_fields(&self) {
147 let mut val = self.value.read();
148 val &= !(((0xF) << 16) | ((0xF) << 20) | ((0x7) << 4));
149 self.value.write(val);
150 }
151 fn set_iosqes(&self, size: u32) {
152 let mut val = self.value.read();
153 val |= (size & 0xF) << 16;
154 self.value.write(val);
155 }
156 fn set_iocqes(&self, size: u32) {
157 let mut val = self.value.read();
158 val |= (size & 0xF) << 20;
159 self.value.write(val);
160 }
161 fn set_css(&self, css: u32) {
162 let mut val = self.value.read();
163 val |= (css & 0x7) << 4;
164 self.value.write(val);
165 }
166 fn set_enable(&self, enable: bool) {
167 let mut val = self.value.read();
168 if enable {
169 val |= 1;
170 } else {
171 val &= !1;
172 }
173 self.value.write(val);
174 }
175 fn is_enabled(&self) -> bool {
176 (self.value.read() & 1) != 0
177 }
178}
179
180#[repr(transparent)]
181struct ControllerStatus {
182 value: VolatileCell<u32>,
183}
184
185impl ControllerStatus {
186 fn is_ready(&self) -> bool {
187 (self.value.read() & 1) != 0
188 }
189 fn is_fatal(&self) -> bool {
190 (self.value.read() >> 1) & 1 != 0
191 }
192}
193
194#[repr(C)]
195struct Registers {
196 capability: Capability,
197 version: Version,
198 _intms: VolatileCell<u32>,
199 _intmc: VolatileCell<u32>,
200 cc: ControllerConfig,
201 _reserved1: VolatileCell<u32>,
202 csts: ControllerStatus,
203 _reserved2: VolatileCell<u32>,
204 aqa: VolatileCell<u32>,
205 asq_low: VolatileCell<u32>,
206 asq_high: VolatileCell<u32>,
207 acq_low: VolatileCell<u32>,
208 acq_high: VolatileCell<u32>,
209}
210
211#[derive(Debug, Clone, Copy)]
212enum NvmeError {
213 ControllerFatal,
214 Timeout,
215 InvalidNamespace,
216 IoError,
217}
218
219#[derive(Debug, Clone)]
220pub struct NvmeNamespace {
221 pub nsid: u32,
222 pub size: u64,
223 pub block_size: u32,
224}
225
226#[repr(C)]
228#[derive(Copy, Clone)]
229struct LbaFormat {
230 _metadata_size: u16,
231 lbads: u8,
232 _relative_perf: u8,
233}
234
235#[repr(C)]
238#[derive(Copy, Clone)]
239struct IdentifyNamespaceData {
240 nsze: u64,
241 _ncap: u64,
242 _nuse: u64,
243 _nsfeat: u8,
244 _nlbaf: u8,
245 flbas: u8,
246 _mc: u8,
247 _dpc: u8,
248 _dps: u8,
249 _nmic: u8,
250 _rescap: u8,
251 _fpi: u8,
252 _dlfeat: u8,
253 _nawun: u16,
254 _nawupf: u16,
255 _nacwu: u16,
256 _nabsn: u16,
257 _nabo: u16,
258 _nabspf: u16,
259 _noiob: u16,
260 _nvmcap: [u64; 2],
261 _npwg: u16,
262 _npwa: u16,
263 _npdg: u16,
264 _npda: u16,
265 _nows: u16,
266 _reserved: [u8; 54], lbaf: [LbaFormat; 64],
269}
270
271#[repr(C)]
273#[derive(Copy, Clone)]
274struct IdentifyControllerData {
275 _vid: u16,
276 _ssvid: u16,
277 _sn: [u8; 20],
278 _mn: [u8; 40],
279 _fr: [u8; 8],
280 _rab: u8,
281 _ieee: [u8; 3],
282 _cmic: u8,
283 mdts: u8,
284 _cntlid: u16,
285 _ver: u32,
286 _rtd3r: u32,
287 _rtd3e: u32,
288 _oaes: u32,
289 _ctratt: u32,
290 _reserved0: [u8; 100],
291 _oacs: u16,
292 _acl: u8,
293 _aerl: u8,
294 _frmw: u8,
295 _lpa: u8,
296 _elpe: u8,
297 _npss: u8,
298 _avscc: u8,
299 _apsta: u8,
300 _wctemp: u16,
301 _cctemp: u16,
302 _reserved1: [u8; 242],
303 sqes: u8,
304 cqes: u8,
305 _maxcmd: u16,
306 nn: u32,
307 _oncs: u16,
308 _fuses: u16,
309 _fna: u8,
310 _vwc: u8,
311 _awun: u16,
312 _awupf: u16,
313 _icsvscc: u8,
314 _nwpc: u8,
315 _acwu: u16,
316 _cdfs: u16,
317 _sgls: u32,
318 _reserved2: [u8; 228],
319 _subnqn: [u8; 256],
320 _reserved3: [u8; 1024],
321 _psd: [[u8; 32]; 32],
322 _vs: [u8; 1024],
323}
324
325struct IoQueuePair {
326 submission: IoQueue<Submission>,
327 completion: IoQueue<Completion>,
328 command_id: u16,
329 size: usize,
330}
331
332struct IoQueue<T: QueueType> {
333 doorbell: *const VolatileCell<u32>,
334 entries: *mut T::EntryType,
335 size: usize,
336 index: usize,
337 phase: bool,
338 phys_addr: u64,
339}
340
341unsafe impl<T: QueueType> Send for IoQueue<T> {}
342unsafe impl<T: QueueType> Sync for IoQueue<T> {}
343
344impl<T: QueueType> IoQueue<T> {
345 fn new(registers_base: usize, size: usize, queue_id: u16, dstrd: usize) -> Self {
346 let doorbell_offset =
347 0x1000 + ((((queue_id as usize) * 2) + T::DOORBELL_OFFSET) * (4 << dstrd));
348 let doorbell =
349 unsafe { &*((registers_base + doorbell_offset) as *const VolatileCell<u32>) };
350
351 let frame = allocate_zeroed_frame().expect("NVMe: failed to allocate I/O queue frame");
352 let phys_addr = frame.start_address.as_u64();
353 paging::ensure_identity_map_range(phys_addr, NVME_PAGE_SIZE as u64);
354 let virt_addr = phys_to_virt(phys_addr);
355
356 unsafe {
357 ptr::write_bytes(
358 virt_addr as *mut u8,
359 0,
360 size * core::mem::size_of::<T::EntryType>(),
361 );
362 }
363
364 Self {
365 doorbell,
366 entries: virt_addr as *mut T::EntryType,
367 size,
368 index: 0,
369 phase: true,
370 phys_addr,
371 }
372 }
373}
374
375#[derive(Debug, Clone, Copy)]
376pub struct NvmeCompletionResult {
377 pub command_id: u16,
378 pub status: u16,
379}
380
381pub struct NvmeController {
382 registers: usize,
383 admin_queue: Mutex<QueuePair>,
384 io_queue: Mutex<IoQueuePair>,
385 namespaces: Vec<NvmeNamespace>,
386 pub name: String,
387 irq_line: u8,
388 io_done: Box<[AtomicBool]>,
389 io_wq: WaitQueue,
390}
391
392unsafe impl Send for NvmeController {}
393unsafe impl Sync for NvmeController {}
394
395impl NvmeController {
396 unsafe fn new(registers: usize, name: String) -> Result<Self, NvmeError> {
397 let regs = &*(registers as *const Registers);
398 let dstrd = regs.capability.doorbell_stride() as usize;
399 let max_entries = regs.capability.max_queue_entries();
400 let queue_size = core::cmp::min(max_entries as usize, 1024);
401
402 let admin_queue = QueuePair::new(registers, queue_size, dstrd);
403
404 let io_sub = IoQueue::new(registers, IO_QUEUE_SIZE, 1, dstrd);
405 let io_comp = IoQueue::new(registers, IO_QUEUE_SIZE, 1, dstrd);
406 let io_queue = IoQueuePair {
407 submission: io_sub,
408 completion: io_comp,
409 command_id: 0,
410 size: IO_QUEUE_SIZE,
411 };
412
413 let io_done: Box<[AtomicBool]> = (0..MAX_IO_COMMANDS)
414 .map(|_| AtomicBool::new(false))
415 .collect();
416
417 let mut controller = Self {
418 registers,
419 admin_queue: Mutex::new(admin_queue),
420 io_queue: Mutex::new(io_queue),
421 namespaces: Vec::new(),
422 name,
423 irq_line: 0,
424 io_done,
425 io_wq: WaitQueue::new(),
426 };
427
428 controller.init_admin_queue()?;
429 controller.create_io_queues()?;
430 controller.identify_namespaces()?;
431 Ok(controller)
432 }
433
434 fn submit_admin_command(&self, command: Command) -> Result<CompletionEntry, NvmeError> {
435 let mut admin = self.admin_queue.lock();
436 admin.submit_command(command).ok_or(NvmeError::IoError)
437 }
438
439 fn init_admin_queue(&mut self) -> Result<(), NvmeError> {
440 let regs = unsafe { &*(self.registers as *const Registers) };
441 let (admin_sq_phys, admin_cq_phys, queue_size) = {
442 let q = self.admin_queue.lock();
443 (q.submission_phys(), q.completion_phys(), q.size)
444 };
445
446 if queue_size == 0 {
447 return Err(NvmeError::IoError);
448 }
449 let qsz = ((queue_size as u32).saturating_sub(1)) & 0x0FFF;
450
451 log::info!("NVMe init: queue_size={} qsz={}", queue_size, qsz);
452 log::info!(
453 "NVMe init: ASQ phys={:#x} ACQ phys={:#x}",
454 admin_sq_phys,
455 admin_cq_phys
456 );
457
458 let cc_val = regs.cc.value.read();
460 let csts_val = regs.csts.value.read();
461 log::info!("NVMe init: CC={:#010x} CSTS={:#010x}", cc_val, csts_val);
462
463 if cc_val & 1 != 0 {
464 log::info!("NVMe init: controller enabled, disabling...");
465
466 regs.cc.set_enable(false);
471 log::info!("NVMe init: wrote CC.EN=0 (no SHN), waiting for CSTS.RDY...");
472
473 let deadline = tsc_deadline_ms(5500);
476 let mut log_count = 0u32;
477 loop {
478 let csts = regs.csts.value.read();
479 if csts & 1 == 0 {
480 log::info!("NVMe init: controller disabled, CSTS={:#x}", csts);
481 break;
482 }
483 if tsc_expired(deadline) {
484 log::warn!("NVMe init: RDY timeout, CSTS={:#x} : forcing CC=0", csts);
485
486 regs.cc.value.write(0x0000_0000);
488 log::info!("NVMe init: wrote CC=0x00000000 (full reset)");
489 let force_deadline = tsc_deadline_ms(3000);
490 while !tsc_expired(force_deadline) {
491 let c = regs.csts.value.read();
492 if c & 1 == 0 {
493 log::info!("NVMe init: forced disable OK, CSTS={:#x}", c);
494 break;
495 }
496 core::hint::spin_loop();
497 }
498 break;
499 }
500 core::hint::spin_loop();
501 log_count += 1;
502 if log_count % 2_000_000 == 0 {
503 log::info!(
504 "NVMe init: still waiting... CSTS={:#x}",
505 regs.csts.value.read()
506 );
507 }
508 }
509 } else {
510 log::info!("NVMe init: controller already disabled");
511 }
512
513 let settle = tsc_deadline_ms(2);
516 while !tsc_expired(settle) {
517 core::hint::spin_loop();
518 }
519
520 let csts = regs.csts.value.read();
522 log::info!("NVMe init: CSTS={:#x}", csts);
523 if csts & 2 != 0 {
524 log::error!("NVMe init: CSTS.CFS (fatal) set!");
525 return Err(NvmeError::ControllerFatal);
526 }
527
528 log::info!("NVMe init: writing AQA={:#x}...", qsz | (qsz << 16));
530 regs.aqa.write(qsz | (qsz << 16));
531 log::info!("NVMe init: writing ASQ={:#x}...", admin_sq_phys);
532 regs.asq_low.write(admin_sq_phys as u32);
533 regs.asq_high.write((admin_sq_phys >> 32) as u32);
534 log::info!("NVMe init: writing ACQ={:#x}...", admin_cq_phys);
535 regs.acq_low.write(admin_cq_phys as u32);
536 regs.acq_high.write((admin_cq_phys >> 32) as u32);
537
538 log::info!("NVMe init: configuring CC...");
540 regs.cc.clear_io_fields();
541 regs.cc.set_css(0); regs.cc.set_iosqes(6); regs.cc.set_iocqes(6); log::info!("NVMe init: CC={:#010x} (configured)", regs.cc.value.read());
545
546 log::info!("NVMe init: enabling controller...");
548 regs.cc.set_enable(true);
549 log::info!("NVMe init: CC={:#010x} (EN=1)", regs.cc.value.read());
550
551 let deadline = tsc_deadline_ms(5500);
553 let mut log_interval = 0u32;
554 loop {
555 let csts = regs.csts.value.read();
556 if csts & 1 != 0 {
557 log::info!("NVMe init: controller ready, CSTS={:#x}", csts);
558 break;
559 }
560 if tsc_expired(deadline) {
561 log::error!("NVMe init: enable timeout! CSTS={:#x}", csts);
562 return Err(NvmeError::Timeout);
563 }
564 core::hint::spin_loop();
565 log_interval += 1;
566 if log_interval % 500_000 == 0 {
567 log::info!("NVMe init: waiting for ready... CSTS={:#x}", csts);
568 }
569 }
570
571 let csts = regs.csts.value.read();
572 log::info!("NVMe init: final CSTS={:#x}", csts);
573
574 if csts & 2 != 0 {
575 log::error!("NVMe init: controller fatal error!");
576 return Err(NvmeError::ControllerFatal);
577 }
578
579 log::info!(
580 "NVMe: Controller v{}.{}.{} ready",
581 regs.version.value.read() >> 16,
582 (regs.version.value.read() >> 8) & 0xFF,
583 regs.version.value.read() & 0xFF
584 );
585 Ok(())
586 }
587
588 fn create_io_queues(&mut self) -> Result<(), NvmeError> {
589 let (io_sq_phys, io_cq_phys, queue_size) = {
590 let q = self.io_queue.lock();
591 (q.submission.phys_addr, q.completion.phys_addr, q.size)
592 };
593
594 let qsz = ((queue_size as u32).saturating_sub(1)) & 0xFFF;
595
596 log::info!(
597 "NVMe I/O queues: size={} qsz={} SQ={:#x} CQ={:#x}",
598 queue_size,
599 qsz,
600 io_sq_phys,
601 io_cq_phys
602 );
603
604 log::info!("NVMe I/O: sending Set Features (IRQ coalescing)...");
605 let set_feature_cmd = Command {
606 opcode: 0x09,
607 cdw10: 0x07,
608 cdw11: 0x0100_0000,
609 ..Default::default()
610 };
611 self.submit_admin_command(set_feature_cmd).ok();
612
613 log::info!("NVMe I/O: creating I/O CQ...");
614 let cq_cmd = Command {
617 opcode: 0x05,
618 cdw10: qsz << 16, cdw11: 0x0000_0003, prp1: io_cq_phys,
621 ..Default::default()
622 };
623 match self.submit_admin_command(cq_cmd) {
624 Ok(c) => {
625 if c.status_code() != 0 {
626 log::warn!("NVMe: Create I/O CQ failed: status={}", c.status_code());
627 } else {
628 log::info!("NVMe I/O: CQ created OK");
629 }
630 }
631 Err(e) => {
632 log::warn!("NVMe: Create I/O CQ error: {:?}", e);
633 return Err(e);
634 }
635 }
636
637 log::info!("NVMe I/O: creating I/O SQ...");
638 let sq_cmd = Command {
641 opcode: 0x01,
642 cdw10: (qsz << 16) | 1, cdw11: (1 << 16) | 0x0000_0001, prp1: io_sq_phys,
645 ..Default::default()
646 };
647 match self.submit_admin_command(sq_cmd) {
648 Ok(c) => {
649 if c.status_code() != 0 {
650 log::warn!("NVMe: Create I/O SQ failed: status={}", c.status_code());
651 } else {
652 log::info!("NVMe I/O: SQ created OK");
653 }
654 }
655 Err(e) => {
656 log::warn!("NVMe: Create I/O SQ error: {:?}", e);
657 return Err(e);
658 }
659 }
660
661 log::info!("NVMe: I/O queues created (size={})", queue_size);
662 Ok(())
663 }
664
665 fn identify(&self, cns: u8, nsid: u32) -> Result<Vec<u8>, NvmeError> {
666 let frame = allocate_zeroed_frame().ok_or(NvmeError::IoError)?;
667 let phys = frame.start_address.as_u64();
668 paging::ensure_identity_map_range(phys, NVME_PAGE_SIZE as u64);
669 let virt = phys_to_virt(phys) as *mut u8;
670 unsafe {
671 ptr::write_bytes(virt, 0, NVME_PAGE_SIZE);
672 }
673
674 let cmd = Command {
675 opcode: 0x06,
676 nsid,
677 prp1: phys,
678 cdw10: cns as u32,
679 ..Default::default()
680 };
681
682 let completion = self.submit_admin_command(cmd)?;
683 if completion.status_code() != 0 {
684 return Err(NvmeError::IoError);
685 }
686
687 let mut data = Vec::with_capacity(NVME_PAGE_SIZE);
689 unsafe {
690 for i in 0..NVME_PAGE_SIZE {
691 data.push(ptr::read_volatile(virt.add(i)));
692 }
693 }
694 Ok(data)
696 }
697
698 fn identify_namespaces(&mut self) -> Result<(), NvmeError> {
699 let ctrl_data = self.identify(0x01, 0)?;
701 let ctrl = unsafe { core::ptr::read(ctrl_data.as_ptr() as *const IdentifyControllerData) };
702 let nn = ctrl.nn;
703 let mdts = ctrl.mdts;
704
705 let min_sqes = ctrl.sqes & 0xF;
707 let max_sqes = (ctrl.sqes >> 4) & 0xF;
708 let min_cqes = ctrl.cqes & 0xF;
709 let max_cqes = (ctrl.cqes >> 4) & 0xF;
710 let our_sqes = 6u8; let our_cqes = 4u8; if our_sqes < min_sqes || our_sqes > max_sqes {
714 log::warn!(
715 "NVMe: SQES {} not in range [{}..{}] : controller may reject commands",
716 our_sqes,
717 min_sqes,
718 max_sqes
719 );
720 }
721 if our_cqes < min_cqes || our_cqes > max_cqes {
722 log::warn!(
723 "NVMe: CQES {} not in range [{}..{}] : controller may reject completions",
724 our_cqes,
725 min_cqes,
726 max_cqes
727 );
728 }
729
730 let cap = unsafe { regs_read64(self.registers, 0x00) };
732 let mpsmin = ((cap >> 48) & 0xF) as u32 + 12; let mpsmax = ((cap >> 52) & 0xF) as u32 + 12; let our_mps = 12u32; if our_mps < mpsmin || our_mps > mpsmax {
736 log::warn!(
737 "NVMe: Page size {} not in range [{}..{}] bytes",
738 1 << our_mps,
739 1 << mpsmin,
740 1 << mpsmax
741 );
742 }
743
744 log::info!(
745 "NVMe: Controller NN={} MDTS={} SQES={:#x} CQES={:#x} MPS=[{}..{}]",
746 nn,
747 mdts,
748 ctrl.sqes,
749 ctrl.cqes,
750 1 << mpsmin,
751 1 << mpsmax
752 );
753
754 if nn == 0 {
755 return Err(NvmeError::InvalidNamespace);
756 }
757
758 let ns_list = self.identify(0x02, 0)?;
760 let ns_list_words = unsafe {
761 core::slice::from_raw_parts(ns_list.as_ptr() as *const u32, ns_list.len() / 4)
762 };
763 let mut active_nsids: Vec<u32> = Vec::new();
764 for &word in ns_list_words.iter() {
765 if word == 0 {
766 break;
767 }
768 active_nsids.push(word);
769 }
770 log::info!("NVMe: {} active namespace(s)", active_nsids.len());
771
772 for nsid in &active_nsids {
774 if let Ok(ns_data) = self.identify(0x00, *nsid) {
775 let ns =
776 unsafe { core::ptr::read(ns_data.as_ptr() as *const IdentifyNamespaceData) };
777
778 let flbas = ns.flbas as usize;
779 let lbaf_idx = flbas & 0xF;
780 let lbads = ns.lbaf[lbaf_idx].lbads;
781 let block_size = 1u32 << lbads;
782
783 self.namespaces.push(NvmeNamespace {
784 nsid: *nsid,
785 size: ns.nsze,
786 block_size,
787 });
788 log::info!(
789 "NVMe: NSID {} - {} blocks @ {} bytes (LBADS={}, FLBAS={:#x})",
790 nsid,
791 ns.nsze,
792 block_size,
793 lbads,
794 flbas
795 );
796 }
797 }
798 Ok(())
799 }
800
801 fn submit_io_command(&self, command: &mut Command) -> Result<u16, NvmeError> {
802 let mut io = self.io_queue.lock();
803 let cmd_id = io.command_id;
804 command.command_id = cmd_id;
805 io.command_id = io.command_id.wrapping_add(1);
806
807 let slot = cmd_id as usize % io.size;
808
809 let idx = cmd_id as usize % MAX_IO_COMMANDS;
810 self.io_done[idx].store(false, Ordering::SeqCst);
811
812 unsafe {
813 ptr::write(io.submission.entries.add(slot), *command);
814 core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
815 (*io.submission.doorbell).write(((slot + 1) % io.size) as u32);
816 }
817
818 Ok(cmd_id)
819 }
820
821 pub fn read_blocks(
822 &self,
823 nsid: u32,
824 lba: u64,
825 block_count: u32,
826 buf_phys: u64,
827 ) -> Result<(), NvmeError> {
828 let byte_count = block_count as usize * 512;
829 let (prp1, prp2) = unsafe { build_prp_list(buf_phys, byte_count) };
830
831 let cmd_id = {
832 let mut cmd = Command {
833 opcode: 0x02,
834 nsid,
835 prp1,
836 prp2,
837 cdw10: (lba & 0xFFFF_FFFF) as u32,
838 cdw11: ((lba >> 32) & 0xFFFF_FFFF) as u32,
839 cdw12: (block_count - 1),
840 ..Default::default()
841 };
842 self.submit_io_command(&mut cmd)?
843 };
844
845 let idx = cmd_id as usize % MAX_IO_COMMANDS;
846
847 self.io_wq.wait_until(|| {
848 if self.io_done[idx].load(Ordering::Acquire) {
849 Some(())
850 } else {
851 None
852 }
853 });
854
855 Ok(())
856 }
857
858 pub fn write_blocks(
859 &self,
860 nsid: u32,
861 lba: u64,
862 block_count: u32,
863 buf_phys: u64,
864 ) -> Result<(), NvmeError> {
865 let byte_count = block_count as usize * 512;
866 let (prp1, prp2) = unsafe { build_prp_list(buf_phys, byte_count) };
867
868 let cmd_id = {
869 let mut cmd = Command {
870 opcode: 0x01,
871 nsid,
872 prp1,
873 prp2,
874 cdw10: (lba & 0xFFFF_FFFF) as u32,
875 cdw11: ((lba >> 32) & 0xFFFF_FFFF) as u32,
876 cdw12: (block_count - 1),
877 ..Default::default()
878 };
879 self.submit_io_command(&mut cmd)?
880 };
881
882 let idx = cmd_id as usize % MAX_IO_COMMANDS;
883
884 self.io_wq.wait_until(|| {
885 if self.io_done[idx].load(Ordering::Acquire) {
886 Some(())
887 } else {
888 None
889 }
890 });
891
892 Ok(())
893 }
894
895 pub fn handle_interrupt(&self) {
896 let mut io = self.io_queue.lock();
897
898 loop {
899 let entry = unsafe { &*io.completion.entries.add(io.completion.index) };
900 let status = entry.status;
901 if ((status & 0x1) != 0) == io.completion.phase {
902 let cmd_id = entry.command_id;
903 let sc = (entry.status >> 1) & 0xFF;
904 let dnr = (entry.status >> 14) & 1;
905
906 io.completion.index = (io.completion.index + 1) % io.completion.size;
907 if io.completion.index == 0 {
908 io.completion.phase = !io.completion.phase;
909 }
910 unsafe {
911 (*io.completion.doorbell).write(io.completion.index as u32);
912 }
913
914 let idx = cmd_id as usize % MAX_IO_COMMANDS;
915 if sc != 0 && dnr == 0 {
916 log::warn!("NVMe: I/O error cmd_id={} sc={}", cmd_id, sc);
917 }
918 self.io_done[idx].store(true, Ordering::Release);
919 self.io_wq.wake_all();
920 } else {
921 break;
922 }
923 }
924 }
925
926 pub fn namespace_count(&self) -> usize {
927 self.namespaces.len()
928 }
929
930 pub fn get_namespace(&self, index: usize) -> Option<&NvmeNamespace> {
931 self.namespaces.get(index)
932 }
933
934 pub fn set_irq_line(&mut self, irq: u8) {
935 self.irq_line = irq;
936 }
937
938 pub fn irq_line(&self) -> u8 {
939 self.irq_line
940 }
941}
942
943#[repr(C)]
944#[derive(Default, Copy, Clone)]
945struct Command {
946 opcode: u8,
947 flags: u8,
948 command_id: u16,
949 nsid: u32,
950 cdw2: u32,
951 cdw3: u32,
952 prp1: u64,
953 prp2: u64,
954 cdw10: u32,
955 cdw11: u32,
956 cdw12: u32,
957 cdw13: u32,
958 cdw14: u32,
959 cdw15: u32,
960}
961
962#[repr(C)]
963#[derive(Copy, Clone)]
964struct CompletionEntry {
965 dw0: u32,
966 dw1: u32,
967 sq_head: u16,
968 sq_id: u16,
969 command_id: u16,
970 status: u16,
971}
972
973impl CompletionEntry {
974 fn status_code(&self) -> u8 {
975 ((self.status >> 1) & 0xFF) as u8
976 }
977}
978
979struct QueuePair {
980 #[allow(dead_code)]
981 id: u16,
982 size: usize,
983 command_id: u16,
984 submission: Queue<Submission>,
985 completion: Queue<Completion>,
986}
987
988struct Submission;
989struct Completion;
990
991trait QueueType {
992 type EntryType;
993 const DOORBELL_OFFSET: usize;
994}
995
996impl QueueType for Submission {
997 type EntryType = Command;
998 const DOORBELL_OFFSET: usize = 0;
999}
1000
1001impl QueueType for Completion {
1002 type EntryType = CompletionEntry;
1003 const DOORBELL_OFFSET: usize = 1;
1004}
1005
1006struct Queue<T: QueueType> {
1007 doorbell: *const VolatileCell<u32>,
1008 entries: *mut T::EntryType,
1009 size: usize,
1010 index: usize,
1011 phase: bool,
1012 phys_addr: u64,
1013}
1014
1015impl<T: QueueType> Queue<T> {
1016 fn new(registers_base: usize, size: usize, queue_id: u16, dstrd: usize) -> Self {
1017 let doorbell_offset =
1018 0x1000 + ((((queue_id as usize) * 2) + T::DOORBELL_OFFSET) * (4 << dstrd));
1019 let doorbell =
1020 unsafe { &*((registers_base + doorbell_offset) as *const VolatileCell<u32>) };
1021
1022 let frame = allocate_zeroed_frame().expect("NVMe: failed to allocate queue frame");
1023 let phys_addr = frame.start_address.as_u64();
1024 paging::ensure_identity_map_range(phys_addr, NVME_PAGE_SIZE as u64);
1025 let virt_addr = phys_to_virt(phys_addr);
1026
1027 unsafe {
1028 ptr::write_bytes(
1029 virt_addr as *mut u8,
1030 0,
1031 size * core::mem::size_of::<T::EntryType>(),
1032 );
1033 }
1034
1035 Self {
1036 doorbell,
1037 entries: virt_addr as *mut T::EntryType,
1038 size,
1039 index: 0,
1040 phase: true,
1041 phys_addr,
1042 }
1043 }
1044
1045 fn phys_addr(&self) -> u64 {
1046 self.phys_addr
1047 }
1048}
1049
1050impl Queue<Completion> {
1051 fn poll_completion(&mut self) -> Option<CompletionEntry> {
1052 unsafe {
1053 let entry = &*self.entries.add(self.index);
1054 let status = entry.status;
1055 if ((status & 0x1) != 0) == self.phase {
1056 let completion = ptr::read(entry);
1057 self.index = (self.index + 1) % self.size;
1058 if self.index == 0 {
1059 self.phase = !self.phase;
1060 }
1061 (*self.doorbell).write(self.index as u32);
1062 Some(completion)
1063 } else {
1064 None
1065 }
1066 }
1067 }
1068}
1069
1070impl Queue<Submission> {
1071 fn submit_command(&mut self, command: Command, idx: usize) {
1072 unsafe {
1073 ptr::write(self.entries.add(idx), command);
1074 (*self.doorbell).write(((idx + 1) % self.size) as u32);
1075 }
1076 core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
1077 }
1078}
1079
1080impl QueuePair {
1081 fn new(registers_base: usize, size: usize, dstrd: usize) -> Self {
1082 static NEXT_ID: AtomicU8 = AtomicU8::new(0);
1083 let id = NEXT_ID.fetch_add(1, Ordering::SeqCst) as u16;
1084 Self {
1085 id,
1086 size,
1087 command_id: 0,
1088 submission: Queue::new(registers_base, size, id, dstrd),
1089 completion: Queue::new(registers_base, size, id, dstrd),
1090 }
1091 }
1092
1093 fn submission_phys(&self) -> u64 {
1094 self.submission.phys_addr()
1095 }
1096 fn completion_phys(&self) -> u64 {
1097 self.completion.phys_addr()
1098 }
1099
1100 fn submit_command(&mut self, command: Command) -> Option<CompletionEntry> {
1101 let slot = self.command_id as usize % self.size;
1102 let mut cmd = command;
1103 unsafe {
1104 ptr::write(&mut cmd.command_id as *mut u16, self.command_id);
1105 }
1106 self.command_id = self.command_id.wrapping_add(1);
1107 self.submission.submit_command(cmd, slot);
1108 let deadline = tsc_deadline_ms(5500); loop {
1110 if let Some(c) = self.completion.poll_completion() {
1111 return Some(c);
1112 }
1113 if tsc_expired(deadline) {
1114 log::error!("NVMe: admin command timeout");
1115 return None;
1116 }
1117 core::hint::spin_loop();
1118 }
1119 }
1120}
1121
1122static NVME_CONTROLLERS: Mutex<Vec<Arc<Mutex<NvmeController>>>> = Mutex::new(Vec::new());
1123static NVME_INITIALIZED: AtomicBool = AtomicBool::new(false);
1124
1125pub static NVME_IRQ_LINE: AtomicU8 = AtomicU8::new(0);
1126
1127pub fn init() {
1128 log::info!("[NVMe] Scanning for NVMe controllers...");
1129
1130 let candidates = pci::probe_all(ProbeCriteria {
1131 vendor_id: None,
1132 device_id: None,
1133 class_code: Some(pci::class::MASS_STORAGE),
1134 subclass: Some(pci::storage_subclass::NVM),
1135 prog_if: None,
1136 });
1137
1138 for (i, pci_dev) in candidates.into_iter().enumerate() {
1139 log::info!(
1140 "NVMe: Found controller at {:?} (VEN:{:04x} DEV:{:04x})",
1141 pci_dev.address,
1142 pci_dev.vendor_id,
1143 pci_dev.device_id
1144 );
1145
1146 let irq = pci_dev.interrupt_line;
1147 pci_dev.enable_bus_master();
1148 pci_dev.enable_memory_space();
1149
1150 let bar = match pci_dev.read_bar(0) {
1151 Some(Bar::Memory64 { addr, .. }) => addr,
1152 _ => {
1153 log::warn!("NVMe: Invalid BAR0");
1154 continue;
1155 }
1156 };
1157
1158 paging::ensure_identity_map_range(bar, 0x10000);
1159 let registers = phys_to_virt(bar) as usize;
1160 let name = format!("nvme{}", i);
1161
1162 match unsafe { NvmeController::new(registers, name.clone()) } {
1163 Ok(mut controller) => {
1164 controller.set_irq_line(irq);
1165 NVME_IRQ_LINE.store(irq, Ordering::Relaxed);
1166 log::info!("NVMe: {} initialized, IRQ={}", name, irq);
1167 NVME_CONTROLLERS
1168 .lock()
1169 .push(Arc::new(Mutex::new(controller)));
1170 crate::arch::x86_64::idt::register_nvme_irq(irq);
1171 }
1172 Err(e) => {
1173 log::warn!("NVMe: Failed to initialize controller: {:?}", e);
1174 }
1175 }
1176 }
1177
1178 NVME_INITIALIZED.store(true, Ordering::SeqCst);
1179 log::info!(
1180 "[NVMe] Found {} controller(s)",
1181 NVME_CONTROLLERS.lock().len()
1182 );
1183}
1184
1185pub fn get_first_controller() -> Option<Arc<Mutex<NvmeController>>> {
1186 NVME_CONTROLLERS.lock().first().cloned()
1187}
1188
1189pub fn is_available() -> bool {
1190 NVME_INITIALIZED.load(Ordering::Relaxed) && !NVME_CONTROLLERS.lock().is_empty()
1191}
1192
1193pub fn handle_interrupt() {
1194 if let Some(ctrl) = get_first_controller() {
1195 let controller = ctrl.lock();
1196 controller.handle_interrupt();
1197 }
1198}
1199
1200pub fn list_controllers() -> Vec<String> {
1201 NVME_CONTROLLERS
1202 .lock()
1203 .iter()
1204 .map(|c| c.lock().name.clone())
1205 .collect()
1206}