1use crate::AddNamespaceError;
7use crate::NvmeFaultController;
8use crate::NvmeFaultControllerCaps;
9use async_trait::async_trait;
10use disk_backend::resolve::ResolveDiskParameters;
11use nvme_resources::NamespaceDefinition;
12use nvme_resources::NvmeFaultControllerHandle;
13use pci_resources::ResolvePciDeviceHandleParams;
14use pci_resources::ResolvedPciDevice;
15use thiserror::Error;
16use vm_resource::AsyncResolveResource;
17use vm_resource::ResolveError;
18use vm_resource::ResourceResolver;
19use vm_resource::declare_static_async_resolver;
20use vm_resource::kind::PciDeviceHandleKind;
21
22pub struct NvmeFaultControllerResolver;
24
25declare_static_async_resolver! {
26 NvmeFaultControllerResolver,
27 (PciDeviceHandleKind, NvmeFaultControllerHandle),
28}
29
30#[derive(Debug, Error)]
32#[expect(missing_docs)]
33pub enum Error {
34 #[error("failed to resolve namespace {nsid}")]
35 NamespaceResolve {
36 nsid: u32,
37 #[source]
38 source: ResolveError,
39 },
40 #[error(transparent)]
41 AddNamespace(AddNamespaceError),
42}
43
44#[async_trait]
45impl AsyncResolveResource<PciDeviceHandleKind, NvmeFaultControllerHandle>
46 for NvmeFaultControllerResolver
47{
48 type Output = ResolvedPciDevice;
49 type Error = Error;
50
51 async fn resolve(
52 &self,
53 resolver: &ResourceResolver,
54 resource: NvmeFaultControllerHandle,
55 input: ResolvePciDeviceHandleParams<'_>,
56 ) -> Result<Self::Output, Self::Error> {
57 let controller = NvmeFaultController::new(
58 input.driver_source,
59 input.dma_target.guest_memory().clone(),
60 input.dma_target.msi_target(),
61 input.register_mmio,
62 NvmeFaultControllerCaps {
63 msix_count: resource.msix_count,
64 max_io_queues: resource.max_io_queues,
65 subsystem_id: resource.subsystem_id,
66 },
67 resource.fault_config,
68 resource.enable_tdisp_tests,
69 );
70 for NamespaceDefinition {
71 nsid,
72 read_only,
73 disk,
74 } in resource.namespaces
75 {
76 let disk = resolver
77 .resolve(
78 disk,
79 ResolveDiskParameters {
80 read_only,
81 driver_source: input.driver_source,
82 },
83 )
84 .await
85 .map_err(|source| Error::NamespaceResolve { nsid, source })?;
86 controller
87 .client()
88 .add_namespace(nsid, disk.0)
89 .await
90 .map_err(Error::AddNamespace)?;
91 }
92 Ok(controller.into())
93 }
94}