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 =
65 ScsiController::new_with_poll_mode_queue_depth(resource.poll_mode_queue_depth);
66 let device = StorageDevice::build_scsi(
67 input.driver_source,
68 &controller,
69 resource.instance_id,
70 resource.max_sub_channel_count,
71 resource.io_queue_depth.unwrap_or(256),
72 );
73
74 for ScsiDeviceAndPath { path, device } in resource.devices {
75 let device = resolver
76 .resolve(
77 device,
78 ResolveScsiDeviceHandleParams {
79 driver_source: input.driver_source,
80 },
81 )
82 .await
83 .map_err(|err| Error::Device { path, source: err })?;
84
85 controller
86 .attach(path, ScsiControllerDisk { disk: device.0 })
87 .map_err(Error::ScsiPathInUse)?;
88 }
89
90 let driver = input.driver_source.simple();
91 if let Some(requests) = resource.requests {
92 driver
93 .spawn(
94 "storvsp-requests",
95 handle_requests(
96 input.driver_source.clone(),
97 Arc::downgrade(&controller.state),
98 resolver.clone(),
99 requests,
100 ),
101 )
102 .detach();
103 }
104
105 Ok(device.into())
106 }
107}
108
109async fn handle_requests(
110 driver_source: VmTaskDriverSource,
111 state: Weak<ScsiControllerState>,
112 resolver: ResourceResolver,
113 mut requests: mesh::Receiver<ScsiControllerRequest>,
114) {
115 while let Some(req) = requests.next().await {
116 match req {
117 ScsiControllerRequest::AddDevice(rpc) => {
118 rpc.handle_failable(async |ScsiDeviceAndPath { path, device }| {
119 let device = resolver
120 .resolve(
121 device,
122 ResolveScsiDeviceHandleParams {
123 driver_source: &driver_source,
124 },
125 )
126 .await
127 .context("failed to resolve media")?;
128
129 if let Some(state) = state.upgrade() {
130 ScsiController { state }
131 .attach(path, ScsiControllerDisk::new(device.0))
132 .context("failed to attach device")?;
133 }
134 anyhow::Ok(())
135 })
136 .await
137 }
138 ScsiControllerRequest::RemoveDevice(rpc) => rpc.handle_failable_sync(|path| {
139 if let Some(state) = state.upgrade() {
140 ScsiController { state }
141 .remove(path)
142 .context("failed to remove device")?;
143 }
144 anyhow::Ok(())
145 }),
146 }
147 }
148}