Skip to main content

strat9_kernel/hardware/storage/
nvme.rs

1// NVMe block device driver
2// Reference: NVM Express Base Specification 2.0
3//
4// Features:
5// - Controller initialization and admin queue
6// - I/O queue pair with IRQ-driven completion
7// - NVMe read (opcode 0x02) and write (opcode 0x01) commands
8// - WaitQueue-based synchronous I/O
9// - Namespace identification
10
11#![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; // 512 entries per PRP list page
29
30const ADMIN_CQE_ERROR: u16 = (0x1 << 14) | (0x1 << 10);
31
32// =========================================================================
33// TSC-based timeout helpers
34// =========================================================================
35
36/// Read the TSC (Time Stamp Counter).
37#[inline]
38fn rdtsc() -> u64 {
39    unsafe { core::arch::x86_64::_rdtsc() }
40}
41
42/// Convert TSC ticks to approximate milliseconds (assumes ~3GHz TSC).
43/// For exact calibration, use the kernel's TSC frequency if available.
44fn tsc_to_ms(ticks: u64) -> u64 {
45    // Rough: 3GHz TSC → 3_000_000 ticks per ms
46    ticks / 3_000_000
47}
48
49/// Get a TSC deadline for `ms` milliseconds from now.
50fn tsc_deadline_ms(ms: u32) -> u64 {
51    rdtsc().wrapping_add((ms as u64) * 3_000_000)
52}
53
54/// Check if a TSC deadline has expired.
55fn tsc_expired(deadline: u64) -> bool {
56    rdtsc() >= deadline
57}
58
59/// Read a 64-bit register from the NVMe controller.
60unsafe 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
66/// Build PRP (Physical Region Page) list for a physically contiguous buffer.
67///
68/// Returns (prp1, prp2):
69/// - If the buffer fits in a single page: prp1 = buf_phys, prp2 = 0
70/// - If the buffer spans multiple pages: prp1 = buf_phys, prp2 = PRP list phys addr
71///
72/// The caller must ensure `buf_phys` is page-aligned and the buffer is physically
73/// contiguous for multi-page transfers.
74unsafe 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    // Allocate a PRP list page
81    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    // First page covers buf_phys..end_of_first_page
87    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/// LBA Format descriptor (4 bytes each, starting at byte 128 of Identify Namespace).
227#[repr(C)]
228#[derive(Copy, Clone)]
229struct LbaFormat {
230    _metadata_size: u16,
231    lbads: u8,
232    _relative_perf: u8,
233}
234
235/// Identify Namespace data (first 384 bytes needed).
236/// Layout per NVMe spec: bytes 0-73 are explicit fields, 74-127 reserved, 128-383 LBAF[0..64].
237#[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], // bytes 74-127
267    /// LBA Format Support : 64 entries × 4 bytes at offset 128
268    lbaf: [LbaFormat; 64],
269}
270
271/// Identify Controller data (partial : fields we need).
272#[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        // Step 1: Disable controller if it's already enabled
459        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            // Some AMD NVMe controllers (e.g. on Lenovo X13) hang if we send
467            // SHN (shutdown notification) before clearing CC.EN.  The safe
468            // approach for re-initialisation is to skip SHN and just write
469            // CC.EN=0 directly.  This matches Linux's nvme_disable_ctrl().
470            regs.cc.set_enable(false);
471            log::info!("NVMe init: wrote CC.EN=0 (no SHN), waiting for CSTS.RDY...");
472
473            // Wait for CSTS.RDY (bit 0) to clear : up to 5.5 s per NVMe spec.
474            // Use a generous timeout; some AMD controllers are slow to respond.
475            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                    // Last resort: write CC=0x00000000
487                    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        // Small delay after disable ; some AMD controllers need this before
514        // admin queue registers become writable.
515        let settle = tsc_deadline_ms(2);
516        while !tsc_expired(settle) {
517            core::hint::spin_loop();
518        }
519
520        // Step 2: Verify CSTS
521        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        // Step 3: Write admin queue registers (32-bit writes, like Redox/MaestroOS)
529        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        // Step 4: Configure CC
539        log::info!("NVMe init: configuring CC...");
540        regs.cc.clear_io_fields();
541        regs.cc.set_css(0); // NVM Command Set
542        regs.cc.set_iosqes(6); // 2^6 = 64 byte submission queue entries
543        regs.cc.set_iocqes(6); // 2^6 = 64 byte completion queue entries
544        log::info!("NVMe init: CC={:#010x} (configured)", regs.cc.value.read());
545
546        // Step 5: Enable controller
547        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        // Step 6: Wait for CSTS.RDY (up to 5.5s per NVMe spec)
552        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        // NVMe spec CDW10: bits 15:0=QID, bits 31:16=QSIZE(0-based)
615        // NVMe spec CDW11: bit 0=PCIE, bit 1=IEN, bits 31:16=IV
616        let cq_cmd = Command {
617            opcode: 0x05,
618            cdw10: qsz << 16,   // QID=0 in bits 15:0, QSIZE in bits 31:16
619            cdw11: 0x0000_0003, // PCIE=1, IEN=1
620            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        // NVMe spec CDW10: bits 15:0=QID, bits 31:16=QSIZE(0-based)
639        // NVMe spec CDW11: bit 0=PCIE, bits 31:16=CQID
640        let sq_cmd = Command {
641            opcode: 0x01,
642            cdw10: (qsz << 16) | 1, // QID=1 in bits 15:0, QSIZE in bits 31:16
643            cdw11: (1 << 16) | 0x0000_0001, // CQID=1 in bits 31:16, PCIE=1
644            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        // Copy data to owned Vec before the DMA frame is freed.
688        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        // frame dropped here → physical memory freed
695        Ok(data)
696    }
697
698    fn identify_namespaces(&mut self) -> Result<(), NvmeError> {
699        // Step 1: Identify Controller : get NN, MDTS, SQES, CQES, and info
700        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        // Validate SQES/CQES (like MaestroOS)
706        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; // 2^6 = 64 bytes
711        let our_cqes = 4u8; // 2^4 = 16 bytes
712
713        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        // Validate page size against CAP (like MaestroOS)
731        let cap = unsafe { regs_read64(self.registers, 0x00) };
732        let mpsmin = ((cap >> 48) & 0xF) as u32 + 12; // log2 of min page size
733        let mpsmax = ((cap >> 52) & 0xF) as u32 + 12; // log2 of max page size
734        let our_mps = 12u32; // 4096 bytes
735        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        // Step 2: Identify Active Namespace ID List (CNS=2)
759        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        // Step 3: Identify each active namespace
773        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); // NVMe spec: up to 5.5s for admin commands
1109        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}