Skip to main content

nvme/workers/
admin.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Admin queue handler.
5
6use super::IoQueueEntrySizes;
7use super::MAX_DATA_TRANSFER_SIZE;
8use super::io::IoHandler;
9use super::io::IoState;
10use crate::DOORBELL_STRIDE_BITS;
11use crate::MAX_NSID;
12use crate::MAX_QES;
13use crate::NVME_VERSION;
14use crate::PAGE_MASK;
15use crate::PAGE_SIZE;
16use crate::VENDOR_ID;
17use crate::error::CommandResult;
18use crate::error::NvmeError;
19use crate::namespace::Namespace;
20use crate::prp::PrpRange;
21use crate::queue::CompletionQueue;
22use crate::queue::DoorbellMemory;
23use crate::queue::QueueError;
24use crate::queue::SubmissionQueue;
25use crate::spec;
26use disk_backend::Disk;
27use futures::FutureExt;
28use futures::SinkExt;
29use futures::StreamExt;
30use futures_concurrency::future::Race;
31use guestmem::GuestMemory;
32use guid::Guid;
33use inspect::Inspect;
34use pal_async::task::Spawn;
35use pal_async::task::Task;
36use parking_lot::Mutex;
37use parking_lot::RwLock;
38use std::collections::BTreeMap;
39use std::collections::btree_map;
40use std::future::pending;
41use std::future::poll_fn;
42use std::io::Cursor;
43use std::io::Write;
44use std::sync::Arc;
45use task_control::AsyncRun;
46use task_control::Cancelled;
47use task_control::InspectTask;
48use task_control::StopTask;
49use task_control::TaskControl;
50use thiserror::Error;
51use vmcore::interrupt::Interrupt;
52use vmcore::vm_task::VmTaskDriver;
53use vmcore::vm_task::VmTaskDriverSource;
54use zerocopy::FromBytes;
55use zerocopy::FromZeros;
56use zerocopy::IntoBytes;
57
58const IOSQES: u8 = 6;
59const IOCQES: u8 = 4;
60const MAX_ASYNC_EVENT_REQUESTS: u8 = 4; // minimum recommended by spec
61const ERROR_LOG_PAGE_ENTRIES: u8 = 1;
62
63#[derive(Inspect)]
64pub struct AdminConfig {
65    #[inspect(skip)]
66    pub driver_source: VmTaskDriverSource,
67    #[inspect(skip)]
68    pub mem: GuestMemory,
69    #[inspect(skip)]
70    pub interrupts: Vec<Interrupt>,
71    #[inspect(skip)]
72    pub doorbells: Arc<RwLock<DoorbellMemory>>,
73    #[inspect(display)]
74    pub subsystem_id: Guid,
75    pub max_sqs: u16,
76    pub max_cqs: u16,
77    pub qe_sizes: Arc<Mutex<IoQueueEntrySizes>>,
78}
79
80#[derive(Inspect)]
81pub struct AdminHandler {
82    driver: VmTaskDriver,
83    config: AdminConfig,
84    #[inspect(iter_by_key)]
85    namespaces: BTreeMap<u32, Arc<Namespace>>,
86}
87
88#[derive(Inspect)]
89pub struct AdminState {
90    admin_sq: SubmissionQueue,
91    admin_cq: CompletionQueue,
92    #[inspect(with = "|x| inspect::iter_by_index(x).map_key(|x| x + 1)")]
93    io_sqs: Vec<Option<IoSq>>,
94    #[inspect(with = "|x| inspect::iter_by_index(x).map_key(|x| x + 1)")]
95    io_cqs: Vec<IoCq>,
96    #[inspect(skip)]
97    sq_delete_response: mesh::Receiver<u16>,
98    #[inspect(iter_by_index)]
99    asynchronous_event_requests: Vec<u16>,
100    #[inspect(
101        rename = "namespaces",
102        with = "|x| inspect::iter_by_key(x.iter().map(|v| (v, ChangedNamespace { changed: true })))"
103    )]
104    changed_namespaces: Vec<u32>,
105    notified_changed_namespaces: bool,
106    /// Asynchronous Event Configuration (Set Features FID 0x0B / CDW11),
107    /// stored verbatim and echoed back via Get Features. The NVMe Base
108    /// specification lists this Feature as mandatory for I/O controllers
109    /// (Base 2.0c section 3.1.2.1.1 / Base 2.3 section 3.1.3.6, "Feature
110    /// Support Requirements"). Each bit in CDW11 enables a class of
111    /// asynchronous event notification (refer to
112    /// [`spec::Cdw11FeatureAsyncEventConfig`]). Initiators that strictly
113    /// follow the spec may refuse to allocate any Asynchronous Event
114    /// Request resources when the Set Features command for this Feature
115    /// is rejected, which breaks AEN delivery (including the
116    /// changed-namespace AEN that drives namespace hot-add notification).
117    ///
118    /// Defaults to all bits set so that any AEN class the controller
119    /// chooses to fire is enabled until the host explicitly narrows the
120    /// mask via Set Features.
121    async_event_config: u32,
122    #[inspect(skip)]
123    recv_changed_namespace: futures::channel::mpsc::Receiver<u32>,
124    #[inspect(skip)]
125    send_changed_namespace: futures::channel::mpsc::Sender<u32>,
126    #[inspect(skip)]
127    poll_namespace_change: BTreeMap<u32, Task<()>>,
128    features: FeatureState,
129}
130
131/// Stored configuration for the mandatory Set/Get Features that the controller
132/// accepts and echoes back but does not otherwise act upon. Storing and echoing
133/// these values satisfies the NVMe Base 2.3 §3.1.3.6 (Figure 32) requirement
134/// that an I/O controller accept every mandatory feature.
135#[derive(Inspect)]
136struct FeatureState {
137    #[inspect(hex)]
138    arbitration: u32,
139    #[inspect(hex)]
140    power_management: u32,
141    #[inspect(hex)]
142    error_recovery: u32,
143    #[inspect(hex)]
144    interrupt_coalescing: u32,
145    /// Coalescing Disable bit per interrupt vector, indexed by interrupt vector.
146    #[inspect(iter_by_index)]
147    interrupt_vector_coalescing_disable: Vec<bool>,
148}
149
150impl FeatureState {
151    fn new(num_interrupt_vectors: usize) -> Self {
152        Self {
153            arbitration: 0,
154            power_management: 0,
155            error_recovery: 0,
156            interrupt_coalescing: 0,
157            interrupt_vector_coalescing_disable: vec![false; num_interrupt_vectors],
158        }
159    }
160}
161
162/// The Temperature Threshold value reported for the requested threshold type.
163///
164/// The emulator models no temperature sensors, so thresholds never trip and no
165/// state needs to be stored: Set Features is accepted and ignored, and Get
166/// Features always reports the reset defaults — an over-temperature threshold
167/// of the maximum (effectively disabled) and an under-temperature threshold of
168/// zero.
169fn default_temperature_threshold(thsel: u8) -> u16 {
170    if thsel == 0 { 0xffff } else { 0x0000 }
171}
172
173#[derive(Inspect)]
174struct ChangedNamespace {
175    changed: bool,
176}
177
178#[derive(Inspect)]
179struct IoSq {
180    pending_delete_cid: Option<u16>,
181    sq_idx: usize,
182    cqid: u16,
183}
184
185#[derive(Inspect)]
186struct IoCq {
187    driver: VmTaskDriver,
188    #[inspect(flatten)]
189    task: TaskControl<IoHandler, IoState>,
190}
191
192impl AdminState {
193    pub fn new(handler: &AdminHandler, asq: u64, asqs: u16, acq: u64, acqs: u16) -> Self {
194        // Start polling for namespace changes. Use a bounded channel to avoid
195        // unbounded memory allocation when the queue is stuck.
196        #[expect(clippy::disallowed_methods)] // TODO
197        let (send_changed_namespace, recv_changed_namespace) = futures::channel::mpsc::channel(256);
198        let poll_namespace_change = handler
199            .namespaces
200            .iter()
201            .map(|(&nsid, namespace)| {
202                (
203                    nsid,
204                    spawn_namespace_notifier(
205                        &handler.driver,
206                        nsid,
207                        namespace.clone(),
208                        send_changed_namespace.clone(),
209                    ),
210                )
211            })
212            .collect();
213
214        let admin_cq = CompletionQueue::new(
215            handler.config.doorbells.clone(),
216            1,
217            handler.config.mem.clone(),
218            Some(handler.config.interrupts[0].clone()),
219            acq,
220            acqs,
221        );
222        let mut state = Self {
223            admin_sq: SubmissionQueue::new(&admin_cq, 0, asq, asqs),
224            admin_cq,
225            io_sqs: Vec::new(),
226            io_cqs: Vec::new(),
227            sq_delete_response: Default::default(),
228            asynchronous_event_requests: Vec::new(),
229            changed_namespaces: Vec::new(),
230            notified_changed_namespaces: false,
231            async_event_config: u32::MAX,
232            recv_changed_namespace,
233            send_changed_namespace,
234            poll_namespace_change,
235            features: FeatureState::new(handler.config.interrupts.len()),
236        };
237        state.set_max_queues(handler, handler.config.max_sqs, handler.config.max_cqs);
238        state
239    }
240
241    /// Stops all submission queues and drains them of any pending IO.
242    ///
243    /// This future may be dropped and reissued.
244    pub async fn drain(&mut self) {
245        for cq in &mut self.io_cqs {
246            cq.task.stop().await;
247            if let Some(state) = cq.task.state_mut() {
248                state.drain().await;
249                cq.task.remove();
250            }
251        }
252    }
253
254    /// Caller must ensure that no queues are active.
255    fn set_max_queues(&mut self, handler: &AdminHandler, num_sqs: u16, num_cqs: u16) {
256        self.io_sqs.truncate(num_sqs.into());
257        self.io_sqs.resize_with(num_sqs.into(), || None);
258        self.io_cqs.resize_with(num_cqs.into(), || {
259            // This driver doesn't explicitly do any IO (that's handled by
260            // the storage backends), so the target VP doesn't matter. But
261            // set it anyway as a hint to the backend that this queue needs
262            // its own thread.
263            let driver = handler
264                .config
265                .driver_source
266                .builder()
267                .run_on_target(false)
268                .target_vp(0)
269                .build("nvme");
270
271            IoCq {
272                driver,
273                task: TaskControl::new(IoHandler::new(
274                    handler.config.mem.clone(),
275                    self.sq_delete_response.sender(),
276                )),
277            }
278        });
279    }
280
281    fn add_changed_namespace(&mut self, nsid: u32) {
282        if let Err(i) = self.changed_namespaces.binary_search(&nsid) {
283            self.changed_namespaces.insert(i, nsid);
284        }
285    }
286
287    async fn add_namespace(
288        &mut self,
289        driver: &VmTaskDriver,
290        nsid: u32,
291        namespace: &Arc<Namespace>,
292    ) {
293        // Update the IO queues.
294        for cq in &mut self.io_cqs {
295            let io_running = cq.task.stop().await;
296            if let Some(io_state) = cq.task.state_mut() {
297                io_state.add_namespace(nsid, namespace.clone());
298            }
299            if io_running {
300                cq.task.start();
301            }
302        }
303
304        // Start polling.
305        let old = self.poll_namespace_change.insert(
306            nsid,
307            spawn_namespace_notifier(
308                driver,
309                nsid,
310                namespace.clone(),
311                self.send_changed_namespace.clone(),
312            ),
313        );
314        assert!(old.is_none());
315
316        // Notify the guest driver of the change.
317        self.add_changed_namespace(nsid);
318    }
319
320    async fn remove_namespace(&mut self, nsid: u32) {
321        // Update the IO queues.
322        for cq in &mut self.io_cqs {
323            let io_running = cq.task.stop().await;
324            if let Some(io_state) = cq.task.state_mut() {
325                io_state.remove_namespace(nsid);
326            }
327            if io_running {
328                cq.task.start();
329            }
330        }
331
332        // Stop polling.
333        self.poll_namespace_change
334            .remove(&nsid)
335            .unwrap()
336            .cancel()
337            .await;
338
339        // Notify the guest driver of the change.
340        self.add_changed_namespace(nsid);
341    }
342}
343
344fn spawn_namespace_notifier(
345    driver: &VmTaskDriver,
346    nsid: u32,
347    namespace: Arc<Namespace>,
348    mut send_changed_namespace: futures::channel::mpsc::Sender<u32>,
349) -> Task<()> {
350    driver.spawn("wait_resize", async move {
351        let mut counter = None;
352        loop {
353            counter = Some(namespace.wait_change(counter).await);
354            tracing::info!(nsid, "namespace changed");
355            if send_changed_namespace.send(nsid).await.is_err() {
356                break;
357            }
358        }
359    })
360}
361
362#[derive(Debug, Error)]
363#[error("invalid queue identifier {qid}")]
364struct InvalidQueueIdentifier {
365    qid: u16,
366    #[source]
367    reason: InvalidQueueIdentifierReason,
368}
369
370#[derive(Debug, Error)]
371enum InvalidQueueIdentifierReason {
372    #[error("queue id is out of bounds")]
373    Oob,
374    #[error("queue id is in use")]
375    InUse,
376    #[error("queue id is not in use")]
377    NotInUse,
378}
379
380impl From<InvalidQueueIdentifier> for NvmeError {
381    fn from(err: InvalidQueueIdentifier) -> Self {
382        Self::new(spec::Status::INVALID_QUEUE_IDENTIFIER, err)
383    }
384}
385
386enum Event {
387    Command(Result<spec::Command, QueueError>),
388    SqDeleteComplete(u16),
389    NamespaceChange(u32),
390}
391
392/// Error returned when a namespace cannot be added.
393#[derive(Debug, Error)]
394pub enum AddNamespaceError {
395    /// A namespace with this ID already exists.
396    #[error("namespace id conflict for {0}")]
397    Conflict(u32),
398    /// The namespace ID is outside the valid range supported by the
399    /// subsystem (see the `NN` field of Identify Controller).
400    #[error("namespace id {0} is out of range (must be 1..={MAX_NSID})")]
401    OutOfRange(u32),
402}
403
404impl AdminHandler {
405    pub fn new(driver: VmTaskDriver, config: AdminConfig) -> Self {
406        Self {
407            driver,
408            config,
409            namespaces: Default::default(),
410        }
411    }
412
413    pub async fn add_namespace(
414        &mut self,
415        state: Option<&mut AdminState>,
416        nsid: u32,
417        disk: Disk,
418    ) -> Result<(), AddNamespaceError> {
419        if nsid == 0 || nsid > MAX_NSID {
420            return Err(AddNamespaceError::OutOfRange(nsid));
421        }
422        let namespace = &*match self.namespaces.entry(nsid) {
423            btree_map::Entry::Vacant(entry) => entry.insert(Arc::new(Namespace::new(
424                self.config.mem.clone(),
425                nsid,
426                disk,
427            ))),
428            btree_map::Entry::Occupied(_) => return Err(AddNamespaceError::Conflict(nsid)),
429        };
430
431        if let Some(state) = state {
432            state.add_namespace(&self.driver, nsid, namespace).await;
433        }
434
435        Ok(())
436    }
437
438    pub async fn remove_namespace(&mut self, state: Option<&mut AdminState>, nsid: u32) -> bool {
439        if self.namespaces.remove(&nsid).is_none() {
440            return false;
441        }
442
443        if let Some(state) = state {
444            state.remove_namespace(nsid).await;
445        }
446
447        true
448    }
449
450    async fn next_event(&mut self, state: &mut AdminState) -> Result<Event, QueueError> {
451        let event = loop {
452            // Wait for there to be room for a completion for the next
453            // command or the completed sq deletion.
454            poll_fn(|cx| state.admin_cq.poll_ready(cx)).await?;
455
456            // Fire the changed-namespace AEN only when the host has
457            // enabled the Attached Namespace Attribute Notices class via
458            // Set Features 0Bh (NVMe Base 2.0c section 5.21.1.11 /
459            // Base 2.3 section 5.2.26.1.5, CDW11 bit 8). Per spec,
460            // "If this bit is cleared to '0', then the controller shall
461            // not send the Attached Namespace Attribute Changed
462            // asynchronous event to the host." The mask defaults to all
463            // bits set, so this only suppresses delivery when the host
464            // has explicitly opted out via Set Features.
465            let ns_aen_enabled = spec::Cdw11FeatureAsyncEventConfig::from(state.async_event_config)
466                .namespace_attribute_notices();
467
468            if !state.changed_namespaces.is_empty()
469                && !state.notified_changed_namespaces
470                && ns_aen_enabled
471            {
472                if let Some(cid) = state.asynchronous_event_requests.pop() {
473                    state.admin_cq.write(
474                        spec::Completion {
475                            dw0: spec::AsynchronousEventRequestDw0::new()
476                                .with_event_type(spec::AsynchronousEventType::NOTICE.0)
477                                .with_log_page_identifier(spec::LogPageIdentifier::CHANGED_NAMESPACE_LIST.0)
478                                .with_information(spec::AsynchronousEventInformationNotice::NAMESPACE_ATTRIBUTE_CHANGED.0)
479                                .into(),
480                            dw1: 0,
481                            sqhd: state.admin_sq.sqhd(),
482                            sqid: 0,
483                            cid,
484                            status: spec::CompletionStatus::new(),
485                        },
486                    )?;
487
488                    state.notified_changed_namespaces = true;
489                    continue;
490                }
491            }
492
493            let next_command = poll_fn(|cx| state.admin_sq.poll_next(cx)).map(Event::Command);
494            let sq_delete_complete = async {
495                let Some(sqid) = state.sq_delete_response.next().await else {
496                    pending().await
497                };
498                Event::SqDeleteComplete(sqid)
499            };
500            let changed_namespace = async {
501                let Some(nsid) = state.recv_changed_namespace.next().await else {
502                    pending().await
503                };
504                Event::NamespaceChange(nsid)
505            };
506
507            break (next_command, sq_delete_complete, changed_namespace)
508                .race()
509                .await;
510        };
511        Ok(event)
512    }
513
514    async fn process_event(
515        &mut self,
516        state: &mut AdminState,
517        event: Result<Event, QueueError>,
518    ) -> Result<(), QueueError> {
519        let (cid, result) = match event? {
520            Event::Command(command) => {
521                let command = command?;
522                let opcode = spec::AdminOpcode(command.cdw0.opcode());
523
524                tracing::debug!(?opcode, ?command, "command");
525
526                let result = match opcode {
527                    spec::AdminOpcode::IDENTIFY => self
528                        .handle_identify(state, &command)
529                        .map(|()| Some(Default::default())),
530                    spec::AdminOpcode::GET_FEATURES => {
531                        self.handle_get_features(state, &command).await.map(Some)
532                    }
533                    spec::AdminOpcode::SET_FEATURES => {
534                        self.handle_set_features(state, &command).map(Some)
535                    }
536                    spec::AdminOpcode::CREATE_IO_COMPLETION_QUEUE => self
537                        .handle_create_io_completion_queue(state, &command)
538                        .map(|()| Some(Default::default())),
539                    spec::AdminOpcode::CREATE_IO_SUBMISSION_QUEUE => self
540                        .handle_create_io_submission_queue(state, &command)
541                        .await
542                        .map(|()| Some(Default::default())),
543                    spec::AdminOpcode::DELETE_IO_COMPLETION_QUEUE => self
544                        .handle_delete_io_completion_queue(state, &command)
545                        .await
546                        .map(|()| Some(Default::default())),
547                    spec::AdminOpcode::DELETE_IO_SUBMISSION_QUEUE => {
548                        self.handle_delete_io_submission_queue(state, &command)
549                            .await
550                    }
551                    spec::AdminOpcode::ASYNCHRONOUS_EVENT_REQUEST => {
552                        self.handle_asynchronous_event_request(state, &command)
553                    }
554                    spec::AdminOpcode::ABORT => self.handle_abort(),
555                    spec::AdminOpcode::GET_LOG_PAGE => self
556                        .handle_get_log_page(state, &command)
557                        .map(|()| Some(Default::default())),
558                    spec::AdminOpcode::DOORBELL_BUFFER_CONFIG
559                        if self.supports_shadow_doorbells(state) =>
560                    {
561                        self.handle_doorbell_buffer_config(state, &command)
562                            .await
563                            .map(|()| Some(Default::default()))
564                    }
565                    opcode => {
566                        tracelimit::warn_ratelimited!(?opcode, "unsupported opcode");
567                        Err(spec::Status::INVALID_COMMAND_OPCODE.into())
568                    }
569                };
570
571                let result = match result {
572                    Ok(Some(cr)) => cr,
573                    Ok(None) => return Ok(()),
574                    Err(err) => {
575                        tracelimit::warn_ratelimited!(
576                            error = &err as &dyn std::error::Error,
577                            cid = command.cdw0.cid(),
578                            ?opcode,
579                            "command error"
580                        );
581                        err.into()
582                    }
583                };
584
585                (command.cdw0.cid(), result)
586            }
587            Event::SqDeleteComplete(sqid) => {
588                let sq = state.io_sqs[sqid as usize - 1].take().unwrap();
589                let cid = sq.pending_delete_cid.unwrap();
590                (cid, Default::default())
591            }
592            Event::NamespaceChange(nsid) => {
593                state.add_changed_namespace(nsid);
594                return Ok(());
595            }
596        };
597
598        let status = spec::CompletionStatus::new().with_status(result.status.0);
599
600        let completion = spec::Completion {
601            dw0: result.dw[0],
602            dw1: result.dw[1],
603            sqid: 0,
604            sqhd: state.admin_sq.sqhd(),
605            status,
606            cid,
607        };
608
609        state.admin_cq.write(completion)?;
610        Ok(())
611    }
612
613    fn handle_identify(
614        &mut self,
615        state: &AdminState,
616        command: &spec::Command,
617    ) -> Result<(), NvmeError> {
618        let cdw10: spec::Cdw10Identify = command.cdw10.into();
619        // All identify results are 4096 bytes.
620        let mut buf = [0u64; 512];
621        let buf = buf.as_mut_bytes();
622        match spec::Cns(cdw10.cns()) {
623            spec::Cns::CONTROLLER => {
624                let id = spec::IdentifyController::mut_from_prefix(buf).unwrap().0; // TODO: zerocopy: from-prefix (mut_from_prefix): use-rest-of-range (https://github.com/microsoft/openvmm/issues/759)
625                *id = self.identify_controller(state);
626
627                write!(
628                    Cursor::new(&mut id.subnqn[..]),
629                    "nqn.2014-08.org.nvmexpress:uuid:{}",
630                    self.config.subsystem_id
631                )
632                .unwrap();
633            }
634            spec::Cns::ACTIVE_NAMESPACES => {
635                if command.nsid >= 0xfffffffe {
636                    return Err(spec::Status::INVALID_NAMESPACE_OR_FORMAT.into());
637                }
638                let nsids = <[u32]>::mut_from_bytes(buf).unwrap();
639                for (ns, nsid) in self
640                    .namespaces
641                    .keys()
642                    .filter(|&ns| *ns > command.nsid)
643                    .zip(nsids)
644                {
645                    *nsid = *ns;
646                }
647            }
648            spec::Cns::NAMESPACE => {
649                if command.nsid == 0 || command.nsid > MAX_NSID {
650                    return Err(spec::Status::INVALID_NAMESPACE_OR_FORMAT.into());
651                }
652                if let Some(ns) = self.namespaces.get(&command.nsid) {
653                    ns.identify(buf);
654                } else {
655                    // Valid but inactive namespace: return a zero-filled
656                    // structure (the buffer is already zeroed).
657                    tracing::debug!(nsid = command.nsid, "inactive namespace id");
658                }
659            }
660            spec::Cns::DESCRIPTOR_NAMESPACE => {
661                if command.nsid == 0 || command.nsid > MAX_NSID {
662                    return Err(spec::Status::INVALID_NAMESPACE_OR_FORMAT.into());
663                }
664                if let Some(ns) = self.namespaces.get(&command.nsid) {
665                    ns.namespace_id_descriptor(buf);
666                } else {
667                    // Valid but inactive namespace: return a zero-filled
668                    // structure (the buffer is already zeroed).
669                    tracing::debug!(nsid = command.nsid, "inactive namespace id");
670                }
671            }
672            spec::Cns::SPECIFIC_CONTROLLER_IO_COMMAND_SET => {
673                // CSI is in Command Dword 11, bits 31:24. Only the NVM command
674                // set (CSI 0h) is supported, and it defines no I/O Command Set
675                // specific Identify Controller data structure, so return a
676                // zero-filled structure per NVMe Base 2.3 section 5.2.13.2.6.
677                // Any other command set is unsupported.
678                let csi = (command.cdw11 >> 24) as u8;
679                if csi != 0 {
680                    return Err(spec::Status::INVALID_FIELD_IN_COMMAND.into());
681                }
682                // The buffer is already zero-filled; fall through to write it
683                // back to the host.
684            }
685            cns => {
686                tracelimit::warn_ratelimited!(?cns, "unsupported cns");
687                return Err(spec::Status::INVALID_FIELD_IN_COMMAND.into());
688            }
689        };
690        PrpRange::parse(&self.config.mem, buf.len(), command.dptr)?.write(&self.config.mem, buf)?;
691        Ok(())
692    }
693
694    fn identify_controller(&self, state: &AdminState) -> spec::IdentifyController {
695        spec::IdentifyController {
696            vid: VENDOR_ID,
697            ssvid: VENDOR_ID,
698            mdts: (MAX_DATA_TRANSFER_SIZE / PAGE_SIZE).trailing_zeros() as u8,
699            ver: NVME_VERSION,
700            rtd3r: 400000,
701            rtd3e: 400000,
702            sqes: spec::QueueEntrySize::new()
703                .with_min(IOSQES)
704                .with_max(IOSQES),
705            cqes: spec::QueueEntrySize::new()
706                .with_min(IOCQES)
707                .with_max(IOCQES),
708            frmw: spec::FirmwareUpdates::new().with_ffsro(true).with_nofs(1),
709            nn: MAX_NSID,
710            ieee: [0x74, 0xe2, 0x8c], // Microsoft
711            fr: (*b"v1.00000").into(),
712            mn: (*b"MSFT NVMe Accelerator v1.0              ").into(),
713            sn: (*b"SN: 000001          ").into(),
714            aerl: MAX_ASYNC_EVENT_REQUESTS - 1,
715            elpe: ERROR_LOG_PAGE_ENTRIES - 1,
716            oaes: spec::Oaes::new().with_namespace_attribute(true),
717            oncs: spec::Oncs::new()
718                .with_dataset_management(true)
719                // Namespaces still have to opt in individually via `rescap`.
720                .with_reservations(true),
721            vwc: spec::VolatileWriteCache::new()
722                .with_present(true)
723                .with_broadcast_flush_behavior(spec::BroadcastFlushBehavior::NOT_SUPPORTED.0),
724            cntrltype: spec::ControllerType::IO_CONTROLLER,
725            oacs: spec::OptionalAdminCommandSupport::new()
726                .with_doorbell_buffer_config(self.supports_shadow_doorbells(state)),
727            ..FromZeros::new_zeroed()
728        }
729    }
730
731    fn handle_set_features(
732        &mut self,
733        state: &mut AdminState,
734        command: &spec::Command,
735    ) -> Result<CommandResult, NvmeError> {
736        let cdw10: spec::Cdw10SetFeatures = command.cdw10.into();
737        let mut dw = [0; 2];
738        // This controller does not support saving feature values across power
739        // cycles or resets (Identify Controller ONCS.SSFS is 0), so a request
740        // to save a feature value must be rejected rather than silently applied
741        // for the current power cycle only.
742        if cdw10.save() {
743            return Err(spec::Status::FEATURE_IDENTIFIER_NOT_SAVEABLE.into());
744        }
745        match spec::Feature(cdw10.fid()) {
746            spec::Feature::NUMBER_OF_QUEUES => {
747                if state.io_sqs.iter().any(|sq| sq.is_some())
748                    || state.io_cqs.iter().any(|cq| cq.task.has_state())
749                {
750                    return Err(spec::Status::COMMAND_SEQUENCE_ERROR.into());
751                }
752                let cdw11: spec::Cdw11FeatureNumberOfQueues = command.cdw11.into();
753                if cdw11.ncq_z() == u16::MAX || cdw11.nsq_z() == u16::MAX {
754                    return Err(spec::Status::INVALID_FIELD_IN_COMMAND.into());
755                }
756                let num_sqs = (cdw11.nsq_z() + 1).min(self.config.max_sqs);
757                let num_cqs = (cdw11.ncq_z() + 1).min(self.config.max_cqs);
758                state.set_max_queues(self, num_sqs, num_cqs);
759
760                dw[0] = spec::Cdw11FeatureNumberOfQueues::new()
761                    .with_ncq_z(num_cqs - 1)
762                    .with_nsq_z(num_sqs - 1)
763                    .into();
764            }
765            spec::Feature::VOLATILE_WRITE_CACHE => {
766                let cdw11 = spec::Cdw11FeatureVolatileWriteCache::from(command.cdw11);
767                if !cdw11.wce() {
768                    tracelimit::warn_ratelimited!(
769                        "ignoring unsupported attempt to disable write cache"
770                    );
771                }
772            }
773            spec::Feature::ASYNC_EVENT_CONFIG => {
774                // The Asynchronous Event Configuration feature is mandatory
775                // for I/O controllers per the NVMe Base specification's
776                // Feature Support Requirements table (Base 2.0c section
777                // 3.1.2.1.1 / Base 2.3 section 3.1.3.6). The host sets bits
778                // in CDW11 to enable each class of asynchronous event
779                // notification. We store the value verbatim; Get Features
780                // echoes it back, and the AEN dispatch loop consults the
781                // relevant bits before firing each notification class.
782                state.async_event_config = command.cdw11;
783            }
784            spec::Feature::ARBITRATION => {
785                state.features.arbitration = command.cdw11;
786            }
787            spec::Feature::POWER_MANAGEMENT => {
788                let cdw11 = spec::Cdw11FeaturePowerManagement::from(command.cdw11);
789                // Only power state 0 is supported (NPSS is 0 in the Identify
790                // Controller data structure, i.e. one power state).
791                if cdw11.ps() != 0 {
792                    return Err(spec::Status::INVALID_FIELD_IN_COMMAND.into());
793                }
794                state.features.power_management = command.cdw11;
795            }
796            spec::Feature::TEMPERATURE_THRESHOLD => {
797                let cdw11 = spec::Cdw11FeatureTemperatureThreshold::from(command.cdw11);
798                // Only over- and under-temperature thresholds are defined.
799                if cdw11.thsel() > 1 {
800                    return Err(spec::Status::INVALID_FIELD_IN_COMMAND.into());
801                }
802                // Accepted and ignored: the emulator models no temperature.
803            }
804            spec::Feature::ERROR_RECOVERY => {
805                state.features.error_recovery = command.cdw11;
806            }
807            spec::Feature::INTERRUPT_COALESCING => {
808                state.features.interrupt_coalescing = command.cdw11;
809            }
810            spec::Feature::INTERRUPT_VECTOR_CONFIG => {
811                let cdw11 = spec::Cdw11FeatureInterruptVectorConfig::from(command.cdw11);
812                let cd = state
813                    .features
814                    .interrupt_vector_coalescing_disable
815                    .get_mut(cdw11.iv() as usize)
816                    .ok_or(spec::Status::INVALID_FIELD_IN_COMMAND)?;
817                *cd = cdw11.cd();
818            }
819            feature => {
820                tracelimit::warn_ratelimited!(?feature, "unsupported feature");
821                return Err(spec::Status::INVALID_FIELD_IN_COMMAND.into());
822            }
823        }
824        Ok(CommandResult::new(spec::Status::SUCCESS, dw))
825    }
826
827    async fn handle_get_features(
828        &mut self,
829        state: &mut AdminState,
830        command: &spec::Command,
831    ) -> Result<CommandResult, NvmeError> {
832        let cdw10: spec::Cdw10GetFeatures = command.cdw10.into();
833        let mut dw = [0; 2];
834
835        // Only the current value (Select 000b) is supported; the controller
836        // does not support default/saved/supported-capabilities selects
837        // (Identify Controller ONCS.SSFS is 0).
838        if cdw10.sel() != 0 {
839            return Err(spec::Status::INVALID_FIELD_IN_COMMAND.into());
840        }
841        match spec::Feature(cdw10.fid()) {
842            spec::Feature::NUMBER_OF_QUEUES => {
843                let num_cqs = state.io_cqs.len();
844                let num_sqs = state.io_sqs.len();
845                dw[0] = spec::Cdw11FeatureNumberOfQueues::new()
846                    .with_ncq_z((num_cqs - 1) as u16)
847                    .with_nsq_z((num_sqs - 1) as u16)
848                    .into();
849            }
850            spec::Feature::VOLATILE_WRITE_CACHE => {
851                // Write cache is always enabled.
852                dw[0] = spec::Cdw11FeatureVolatileWriteCache::new()
853                    .with_wce(true)
854                    .into();
855            }
856            spec::Feature::ASYNC_EVENT_CONFIG => {
857                // Echo back the most recently configured mask. The cache
858                // is initialized to all bits set (refer to
859                // [`AdminState::new`]) so that a host which never issues
860                // Set Features 0Bh still sees every notification class
861                // reported as enabled, preserving the pre-existing
862                // behavior of unconditional AEN delivery.
863                dw[0] = state.async_event_config;
864            }
865            spec::Feature::NVM_RESERVATION_PERSISTENCE => {
866                let namespace = self
867                    .namespaces
868                    .get(&command.nsid)
869                    .ok_or(spec::Status::INVALID_NAMESPACE_OR_FORMAT)?;
870
871                return namespace.get_feature(command).await;
872            }
873            spec::Feature::ARBITRATION => {
874                dw[0] = state.features.arbitration;
875            }
876            spec::Feature::POWER_MANAGEMENT => {
877                dw[0] = state.features.power_management;
878            }
879            spec::Feature::TEMPERATURE_THRESHOLD => {
880                let cdw11 = spec::Cdw11FeatureTemperatureThreshold::from(command.cdw11);
881                if cdw11.thsel() > 1 {
882                    return Err(spec::Status::INVALID_FIELD_IN_COMMAND.into());
883                }
884                dw[0] = spec::Cdw11FeatureTemperatureThreshold::new()
885                    .with_tmpth(default_temperature_threshold(cdw11.thsel()))
886                    .with_tmpsel(cdw11.tmpsel())
887                    .with_thsel(cdw11.thsel())
888                    .into();
889            }
890            spec::Feature::ERROR_RECOVERY => {
891                dw[0] = state.features.error_recovery;
892            }
893            spec::Feature::INTERRUPT_COALESCING => {
894                dw[0] = state.features.interrupt_coalescing;
895            }
896            spec::Feature::INTERRUPT_VECTOR_CONFIG => {
897                let cdw11 = spec::Cdw11FeatureInterruptVectorConfig::from(command.cdw11);
898                let cd = *state
899                    .features
900                    .interrupt_vector_coalescing_disable
901                    .get(cdw11.iv() as usize)
902                    .ok_or(spec::Status::INVALID_FIELD_IN_COMMAND)?;
903                dw[0] = spec::Cdw11FeatureInterruptVectorConfig::new()
904                    .with_iv(cdw11.iv())
905                    .with_cd(cd)
906                    .into();
907            }
908            feature => {
909                tracelimit::warn_ratelimited!(?feature, "unsupported feature");
910                return Err(spec::Status::INVALID_FIELD_IN_COMMAND.into());
911            }
912        }
913        Ok(CommandResult::new(spec::Status::SUCCESS, dw))
914    }
915
916    fn handle_create_io_completion_queue(
917        &mut self,
918        state: &mut AdminState,
919        command: &spec::Command,
920    ) -> Result<(), NvmeError> {
921        let cdw10: spec::Cdw10CreateIoQueue = command.cdw10.into();
922        let cdw11: spec::Cdw11CreateIoCompletionQueue = command.cdw11.into();
923        if !cdw11.pc() {
924            return Err(spec::Status::INVALID_FIELD_IN_COMMAND.into());
925        }
926        let cqid = cdw10.qid();
927        let cq = state
928            .io_cqs
929            .get_mut((cqid as usize).wrapping_sub(1))
930            .ok_or(InvalidQueueIdentifier {
931                qid: cqid,
932                reason: InvalidQueueIdentifierReason::Oob,
933            })?;
934
935        if cq.task.has_state() {
936            return Err(InvalidQueueIdentifier {
937                qid: cqid,
938                reason: InvalidQueueIdentifierReason::InUse,
939            }
940            .into());
941        }
942
943        let interrupt = if cdw11.ien() {
944            let iv = cdw11.iv();
945            if iv as usize >= self.config.interrupts.len() {
946                return Err(spec::Status::INVALID_INTERRUPT_VECTOR.into());
947            };
948            Some(iv)
949        } else {
950            None
951        };
952        let gpa = command.dptr[0] & PAGE_MASK;
953        let len0 = cdw10.qsize_z();
954        if len0 == 0 || len0 >= MAX_QES || self.config.qe_sizes.lock().cqe_bits != IOCQES {
955            return Err(spec::Status::INVALID_QUEUE_SIZE.into());
956        }
957
958        let interrupt = interrupt.map(|iv| self.config.interrupts[iv as usize].clone());
959        let namespaces = self.namespaces.clone();
960
961        let state = IoState::new(
962            &self.config.mem,
963            self.config.doorbells.clone(),
964            gpa,
965            len0 + 1,
966            cqid,
967            interrupt,
968            namespaces,
969        );
970
971        cq.task.insert(&cq.driver, "nvme-io", state);
972        cq.task.start();
973        Ok(())
974    }
975
976    async fn handle_create_io_submission_queue(
977        &mut self,
978        state: &mut AdminState,
979        command: &spec::Command,
980    ) -> Result<(), NvmeError> {
981        let cdw10: spec::Cdw10CreateIoQueue = command.cdw10.into();
982        let cdw11: spec::Cdw11CreateIoSubmissionQueue = command.cdw11.into();
983        if !cdw11.pc() {
984            return Err(spec::Status::INVALID_FIELD_IN_COMMAND.into());
985        }
986        let sqid = cdw10.qid();
987        let sq = state
988            .io_sqs
989            .get_mut((sqid as usize).wrapping_sub(1))
990            .ok_or(InvalidQueueIdentifier {
991                qid: sqid,
992                reason: InvalidQueueIdentifierReason::Oob,
993            })?;
994
995        if sq.is_some() {
996            return Err(InvalidQueueIdentifier {
997                qid: sqid,
998                reason: InvalidQueueIdentifierReason::InUse,
999            }
1000            .into());
1001        }
1002
1003        let cqid = cdw11.cqid();
1004        let cq = state
1005            .io_cqs
1006            .get_mut((cqid as usize).wrapping_sub(1))
1007            .ok_or(spec::Status::COMPLETION_QUEUE_INVALID)?;
1008
1009        if !cq.task.has_state() {
1010            return Err(spec::Status::COMPLETION_QUEUE_INVALID.into());
1011        }
1012
1013        let sq_gpa = command.dptr[0] & PAGE_MASK;
1014        let len0 = cdw10.qsize_z();
1015        if len0 == 0 || len0 >= MAX_QES || self.config.qe_sizes.lock().sqe_bits != IOSQES {
1016            return Err(spec::Status::INVALID_QUEUE_SIZE.into());
1017        }
1018
1019        let running = cq.task.stop().await;
1020        let sq_idx = cq
1021            .task
1022            .state_mut()
1023            .unwrap()
1024            .create_sq(sqid, sq_gpa, len0 + 1);
1025        if running {
1026            cq.task.start();
1027        }
1028        *sq = Some(IoSq {
1029            sq_idx,
1030            pending_delete_cid: None,
1031            cqid,
1032        });
1033        Ok(())
1034    }
1035
1036    async fn handle_delete_io_submission_queue(
1037        &self,
1038        state: &mut AdminState,
1039        command: &spec::Command,
1040    ) -> Result<Option<CommandResult>, NvmeError> {
1041        let cdw10: spec::Cdw10DeleteIoQueue = command.cdw10.into();
1042        let sqid = cdw10.qid();
1043        let sq = state
1044            .io_sqs
1045            .get_mut((sqid as usize).wrapping_sub(1))
1046            .ok_or(InvalidQueueIdentifier {
1047                qid: sqid,
1048                reason: InvalidQueueIdentifierReason::Oob,
1049            })?
1050            .as_mut()
1051            .ok_or(InvalidQueueIdentifier {
1052                qid: sqid,
1053                reason: InvalidQueueIdentifierReason::NotInUse,
1054            })?;
1055
1056        if sq.pending_delete_cid.is_some() {
1057            return Err(InvalidQueueIdentifier {
1058                qid: sqid,
1059                reason: InvalidQueueIdentifierReason::NotInUse,
1060            }
1061            .into());
1062        }
1063
1064        let cq = &mut state.io_cqs[(sq.cqid as usize).wrapping_sub(1)];
1065        let running = cq.task.stop().await;
1066        cq.task.state_mut().unwrap().delete_sq(sq.sq_idx);
1067        if running {
1068            cq.task.start();
1069        }
1070        sq.pending_delete_cid = Some(command.cdw0.cid());
1071        Ok(None)
1072    }
1073
1074    async fn handle_delete_io_completion_queue(
1075        &self,
1076        state: &mut AdminState,
1077        command: &spec::Command,
1078    ) -> Result<(), NvmeError> {
1079        let cdw10: spec::Cdw10DeleteIoQueue = command.cdw10.into();
1080        let cqid = cdw10.qid();
1081        let cq = state
1082            .io_cqs
1083            .get_mut((cqid as usize).wrapping_sub(1))
1084            .ok_or(InvalidQueueIdentifier {
1085                qid: cqid,
1086                reason: InvalidQueueIdentifierReason::Oob,
1087            })?;
1088
1089        if !cq.task.has_state() {
1090            return Err(InvalidQueueIdentifier {
1091                qid: cqid,
1092                reason: InvalidQueueIdentifierReason::NotInUse,
1093            }
1094            .into());
1095        }
1096        let running = cq.task.stop().await;
1097        if cq.task.state().unwrap().has_sqs() {
1098            if running {
1099                cq.task.start();
1100            }
1101            return Err(spec::Status::INVALID_QUEUE_DELETION.into());
1102        }
1103        cq.task.remove();
1104        Ok(())
1105    }
1106
1107    fn handle_asynchronous_event_request(
1108        &self,
1109        state: &mut AdminState,
1110        command: &spec::Command,
1111    ) -> Result<Option<CommandResult>, NvmeError> {
1112        if state.asynchronous_event_requests.len() >= MAX_ASYNC_EVENT_REQUESTS as usize {
1113            return Err(spec::Status::ASYNCHRONOUS_EVENT_REQUEST_LIMIT_EXCEEDED.into());
1114        }
1115        state.asynchronous_event_requests.push(command.cdw0.cid());
1116        Ok(None)
1117    }
1118
1119    /// Abort is a required command, but a legal implementation is to just
1120    /// complete it with a status that means "I'm sorry, that command couldn't
1121    /// be aborted."
1122    fn handle_abort(&self) -> Result<Option<CommandResult>, NvmeError> {
1123        Ok(Some(CommandResult {
1124            status: spec::Status::SUCCESS,
1125            dw: [1, 0],
1126        }))
1127    }
1128
1129    fn handle_get_log_page(
1130        &self,
1131        state: &mut AdminState,
1132        command: &spec::Command,
1133    ) -> Result<(), NvmeError> {
1134        let cdw10 = spec::Cdw10GetLogPage::from(command.cdw10);
1135        let cdw11 = spec::Cdw11GetLogPage::from(command.cdw11);
1136        let numd =
1137            ((cdw10.numdl_z() as u32) | ((cdw11.numdu() as u32) << 16)).saturating_add(1) as usize;
1138        let len = numd * 4;
1139        let prp = PrpRange::parse(&self.config.mem, len, command.dptr)?;
1140
1141        match spec::LogPageIdentifier(cdw10.lid()) {
1142            spec::LogPageIdentifier::SUPPORTED_LOG_PAGES => {
1143                // Figure 207: one 4-byte LID Supported and Effects entry per
1144                // LID (0h..=FFh), 1024 bytes total. Mark each log page this
1145                // controller supports with LSUPP set.
1146                let mut page = [0u32; 256];
1147                let supported = spec::LidSupportedAndEffects::new().with_lsupp(true);
1148                for lid in [
1149                    spec::LogPageIdentifier::SUPPORTED_LOG_PAGES,
1150                    spec::LogPageIdentifier::ERROR_INFORMATION,
1151                    spec::LogPageIdentifier::HEALTH_INFORMATION,
1152                    spec::LogPageIdentifier::FIRMWARE_SLOT_INFORMATION,
1153                    spec::LogPageIdentifier::CHANGED_NAMESPACE_LIST,
1154                ] {
1155                    page[lid.0 as usize] = supported.into();
1156                }
1157                let bytes = page.as_bytes();
1158                prp.write(&self.config.mem, &bytes[..len.min(bytes.len())])?;
1159            }
1160            spec::LogPageIdentifier::ERROR_INFORMATION => {
1161                // Write empty log entries.
1162                prp.zero(
1163                    &self.config.mem,
1164                    len.min(ERROR_LOG_PAGE_ENTRIES as usize * 64),
1165                )?;
1166            }
1167            spec::LogPageIdentifier::HEALTH_INFORMATION => {
1168                if command.nsid != !0 {
1169                    return Err(spec::Status::INVALID_FIELD_IN_COMMAND.into());
1170                }
1171                // Write an empty page.
1172                prp.zero(&self.config.mem, len.min(512))?;
1173            }
1174            spec::LogPageIdentifier::FIRMWARE_SLOT_INFORMATION => {
1175                // Write an empty page.
1176                prp.zero(&self.config.mem, len.min(512))?;
1177            }
1178            spec::LogPageIdentifier::CHANGED_NAMESPACE_LIST => {
1179                // Zero the whole list.
1180                prp.zero(&self.config.mem, len.min(4096))?;
1181                // Now write in the changed namespaces.
1182                if state.changed_namespaces.len() > 1024 {
1183                    // Too many to fit, write !0 so the driver scans everything.
1184                    prp.write(&self.config.mem, (!0u32).as_bytes())?;
1185                } else {
1186                    let count = state.changed_namespaces.len().min(numd);
1187                    prp.write(
1188                        &self.config.mem,
1189                        state.changed_namespaces[..count].as_bytes(),
1190                    )?;
1191                }
1192                state.changed_namespaces.clear();
1193                if !cdw10.rae() {
1194                    state.notified_changed_namespaces = false;
1195                }
1196            }
1197            lid => {
1198                tracelimit::warn_ratelimited!(?lid, "unsupported log page");
1199                return Err(spec::Status::INVALID_LOG_PAGE.into());
1200            }
1201        }
1202
1203        Ok(())
1204    }
1205
1206    fn supports_shadow_doorbells(&self, state: &AdminState) -> bool {
1207        let num_queues = state.io_sqs.len().max(state.io_cqs.len()) + 1;
1208        let len = num_queues * (2 << DOORBELL_STRIDE_BITS);
1209        // The spec only allows a single shadow doorbell page.
1210        len <= PAGE_SIZE
1211    }
1212
1213    async fn handle_doorbell_buffer_config(
1214        &self,
1215        state: &mut AdminState,
1216        command: &spec::Command,
1217    ) -> Result<(), NvmeError> {
1218        // Validated by caller.
1219        assert!(self.supports_shadow_doorbells(state));
1220
1221        let shadow_db_gpa = command.dptr[0];
1222        let event_idx_gpa = command.dptr[1];
1223        if (shadow_db_gpa | event_idx_gpa) & !PAGE_MASK != 0 {
1224            return Err(NvmeError::from(spec::Status::INVALID_FIELD_IN_COMMAND));
1225        }
1226
1227        self.config
1228            .doorbells
1229            .write()
1230            .replace_mem(self.config.mem.clone(), shadow_db_gpa, Some(event_idx_gpa))
1231            .map_err(|err| NvmeError::new(spec::Status::DATA_TRANSFER_ERROR, err))?;
1232
1233        Ok(())
1234    }
1235}
1236
1237impl AsyncRun<AdminState> for AdminHandler {
1238    async fn run(
1239        &mut self,
1240        stop: &mut StopTask<'_>,
1241        state: &mut AdminState,
1242    ) -> Result<(), Cancelled> {
1243        loop {
1244            let event = stop.until_stopped(self.next_event(state)).await?;
1245            if let Err(err) = self.process_event(state, event).await {
1246                tracing::error!(
1247                    error = &err as &dyn std::error::Error,
1248                    "admin queue failure"
1249                );
1250                break;
1251            }
1252        }
1253        Ok(())
1254    }
1255}
1256
1257impl InspectTask<AdminState> for AdminHandler {
1258    fn inspect(&self, req: inspect::Request<'_>, state: Option<&AdminState>) {
1259        req.respond().merge(self).merge(state);
1260    }
1261}