1use super::StorageDevice;
7use crate::ScsiController;
8use crate::ScsiControllerDisk;
9use crate::ScsiControllerState;
10use crate::ScsiPathInUse;
11use anyhow::Context;
12use async_trait::async_trait;
13use futures::StreamExt;
14use pal_async::task::Spawn;
15use scsi_core::ResolveScsiDeviceHandleParams;
16use std::sync::Arc;
17use std::sync::Weak;
18use storvsp_resources::ScsiControllerHandle;
19use storvsp_resources::ScsiControllerRequest;
20use storvsp_resources::ScsiDeviceAndPath;
21use storvsp_resources::ScsiPath;
22use thiserror::Error;
23use vm_resource::AsyncResolveResource;
24use vm_resource::ResolveError;
25use vm_resource::ResourceResolver;
26use vm_resource::declare_static_async_resolver;
27use vm_resource::kind::VmbusDeviceHandleKind;
28use vmbus_channel::resources::ResolveVmbusDeviceHandleParams;
29use vmbus_channel::resources::ResolvedVmbusDevice;
30use vmcore::vm_task::VmTaskDriverSource;
31
32pub struct StorvspResolver;
34
35declare_static_async_resolver! {
36 StorvspResolver,
37 (VmbusDeviceHandleKind, ScsiControllerHandle),
38}
39
40#[derive(Debug, Error)]
42pub enum Error {
43 #[error(transparent)]
44 ScsiPathInUse(ScsiPathInUse),
45 #[error("failed to resolve scsi device at {path}")]
46 Device {
47 path: ScsiPath,
48 #[source]
49 source: ResolveError,
50 },
51}
52
53#[async_trait]
54impl AsyncResolveResource<VmbusDeviceHandleKind, ScsiControllerHandle> for StorvspResolver {
55 type Output = ResolvedVmbusDevice;
56 type Error = Error;
57
58 async fn resolve(
59 &self,
60 resolver: &ResourceResolver,
61 resource: ScsiControllerHandle,
62 input: ResolveVmbusDeviceHandleParams<'_>,
63 ) -> Result<Self::Output, Self::Error> {
64 let controller = ScsiController::new();
65 let device = StorageDevice::build_scsi(
66 input.driver_source,
67 &controller,
68 resource.instance_id,
69 resource.max_sub_channel_count,
70 resource.io_queue_depth.unwrap_or(256),
71 );
72
73 for ScsiDeviceAndPath { path, device } in resource.devices {
74 let device = resolver
75 .resolve(
76 device,
77 ResolveScsiDeviceHandleParams {
78 driver_source: input.driver_source,
79 },
80 )
81 .await
82 .map_err(|err| Error::Device { path, source: err })?;
83
84 controller
85 .attach(path, ScsiControllerDisk { disk: device.0 })
86 .map_err(Error::ScsiPathInUse)?;
87 }
88
89 let driver = input.driver_source.simple();
90 if let Some(requests) = resource.requests {
91 driver
92 .spawn(
93 "storvsp-requests",
94 handle_requests(
95 input.driver_source.clone(),
96 Arc::downgrade(&controller.state),
97 resolver.clone(),
98 requests,
99 ),
100 )
101 .detach();
102 }
103
104 Ok(device.into())
105 }
106}
107
108async fn handle_requests(
109 driver_source: VmTaskDriverSource,
110 state: Weak<ScsiControllerState>,
111 resolver: ResourceResolver,
112 mut requests: mesh::Receiver<ScsiControllerRequest>,
113) {
114 while let Some(req) = requests.next().await {
115 match req {
116 ScsiControllerRequest::AddDevice(rpc) => {
117 rpc.handle_failable(async |ScsiDeviceAndPath { path, device }| {
118 let device = resolver
119 .resolve(
120 device,
121 ResolveScsiDeviceHandleParams {
122 driver_source: &driver_source,
123 },
124 )
125 .await
126 .context("failed to resolve media")?;
127
128 if let Some(state) = state.upgrade() {
129 ScsiController { state }
130 .attach(path, ScsiControllerDisk::new(device.0))
131 .context("failed to attach device")?;
132 }
133 anyhow::Ok(())
134 })
135 .await
136 }
137 ScsiControllerRequest::RemoveDevice(rpc) => rpc.handle_failable_sync(|path| {
138 if let Some(state) = state.upgrade() {
139 ScsiController { state }
140 .remove(path)
141 .context("failed to remove device")?;
142 }
143 anyhow::Ok(())
144 }),
145 }
146 }
147}