1use 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; const 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 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#[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 #[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
162fn 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 #[expect(clippy::disallowed_methods)] 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 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 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 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 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 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 self.add_changed_namespace(nsid);
318 }
319
320 async fn remove_namespace(&mut self, nsid: u32) {
321 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 self.poll_namespace_change
334 .remove(&nsid)
335 .unwrap()
336 .cancel()
337 .await;
338
339 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#[derive(Debug, Error)]
394pub enum AddNamespaceError {
395 #[error("namespace id conflict for {0}")]
397 Conflict(u32),
398 #[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 poll_fn(|cx| state.admin_cq.poll_ready(cx)).await?;
455
456 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 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; *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 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 tracing::debug!(nsid = command.nsid, "inactive namespace id");
670 }
671 }
672 spec::Cns::SPECIFIC_CONTROLLER_IO_COMMAND_SET => {
673 let csi = (command.cdw11 >> 24) as u8;
679 if csi != 0 {
680 return Err(spec::Status::INVALID_FIELD_IN_COMMAND.into());
681 }
682 }
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], 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 .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 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 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 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 if cdw11.thsel() > 1 {
800 return Err(spec::Status::INVALID_FIELD_IN_COMMAND.into());
801 }
802 }
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 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 dw[0] = spec::Cdw11FeatureVolatileWriteCache::new()
853 .with_wce(true)
854 .into();
855 }
856 spec::Feature::ASYNC_EVENT_CONFIG => {
857 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 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 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 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 prp.zero(&self.config.mem, len.min(512))?;
1173 }
1174 spec::LogPageIdentifier::FIRMWARE_SLOT_INFORMATION => {
1175 prp.zero(&self.config.mem, len.min(512))?;
1177 }
1178 spec::LogPageIdentifier::CHANGED_NAMESPACE_LIST => {
1179 prp.zero(&self.config.mem, len.min(4096))?;
1181 if state.changed_namespaces.len() > 1024 {
1183 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 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 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}