1use guid::Guid;
8
9#[expect(missing_docs)]
12#[derive(Debug, PartialEq, Eq)]
13pub enum ControllerType {
14 Scsi,
15 Ide,
16 Nvme,
17}
18
19#[derive(Debug, PartialEq, Eq)]
24pub struct Vtl2StorageBackingDeviceBuilder {
25 device_type: ControllerType,
26 device_path: Guid,
27 sub_device_path: u32,
28}
29
30impl Vtl2StorageBackingDeviceBuilder {
31 pub fn new(device_type: ControllerType, device_path: Guid, sub_device_path: u32) -> Self {
41 assert_ne!(device_type, ControllerType::Ide); Self {
43 device_type,
44 device_path,
45 sub_device_path,
46 }
47 }
48
49 pub fn build(self) -> vtl2_settings_proto::PhysicalDevice {
51 let device_type = match self.device_type {
52 ControllerType::Scsi => vtl2_settings_proto::physical_device::DeviceType::Vscsi,
53 ControllerType::Nvme => vtl2_settings_proto::physical_device::DeviceType::Nvme,
54 ControllerType::Ide => unreachable!(),
55 };
56 vtl2_settings_proto::PhysicalDevice {
57 device_type: device_type.into(),
58 device_path: self.device_path.to_string(),
59 sub_device_path: self.sub_device_path,
60 }
61 }
62}
63
64pub fn build_vtl2_storage_backing_physical_devices(
69 mut devices: Vec<Vtl2StorageBackingDeviceBuilder>,
70) -> Option<vtl2_settings_proto::PhysicalDevices> {
71 match devices.len() {
72 0 => None,
73 1 => Some(vtl2_settings_proto::PhysicalDevices {
74 r#type: vtl2_settings_proto::physical_devices::BackingType::Single.into(),
75 device: Some(devices.pop().unwrap().build()),
76 devices: Vec::new(),
77 }),
78 _ => Some(vtl2_settings_proto::PhysicalDevices {
79 r#type: vtl2_settings_proto::physical_devices::BackingType::Striped.into(),
80 device: None,
81 devices: devices.drain(..).map(|d| d.build()).collect(),
82 }),
83 }
84}
85
86#[derive(Debug, PartialEq, Eq)]
96pub struct Vtl2LunBuilder {
97 channel: Option<u32>,
98 location: u32,
99 device_id: Guid,
100 vendor_id: String,
101 product_id: String,
102 product_revision_level: String,
103 serial_number: String,
104 model_number: String,
105 physical_devices: Vec<Vtl2StorageBackingDeviceBuilder>,
106 is_dvd: bool,
107 chunk_size_in_kb: u32,
108}
109
110impl Vtl2LunBuilder {
111 pub fn disk() -> Self {
114 Self {
115 channel: None,
116 location: 0,
117 device_id: Guid::new_random(),
118 vendor_id: "OpenVMM".to_string(),
119 product_id: "Disk".to_string(),
120 product_revision_level: "1.0".to_string(),
121 serial_number: "0".to_string(),
122 model_number: "1".to_string(),
123 physical_devices: Vec::new(),
124 is_dvd: false,
125 chunk_size_in_kb: 0,
126 }
127 }
128
129 pub fn dvd() -> Self {
132 let mut s = Self::disk();
133 s.is_dvd = true;
134 s.product_id = "DVD".to_string();
135 s
136 }
137
138 pub fn with_channel(mut self, channel: u32) -> Self {
140 self.channel = Some(channel);
141 self
142 }
143
144 pub fn with_location(mut self, location: u32) -> Self {
146 self.location = location;
147 self
148 }
149
150 pub fn with_physical_devices(
154 mut self,
155 physical_devices: Vec<Vtl2StorageBackingDeviceBuilder>,
156 ) -> Self {
157 self.physical_devices = physical_devices;
158 self
159 }
160
161 pub fn with_physical_device(self, physical_device: Vtl2StorageBackingDeviceBuilder) -> Self {
165 self.with_physical_devices(vec![physical_device])
166 }
167
168 pub fn with_chunk_size_in_kb(mut self, chunk_size_in_kb: u32) -> Self {
170 self.chunk_size_in_kb = chunk_size_in_kb;
171 self
172 }
173
174 pub fn build(self) -> vtl2_settings_proto::Lun {
176 vtl2_settings_proto::Lun {
177 channel: self.channel,
178 location: self.location,
179 device_id: self.device_id.to_string(),
180 vendor_id: self.vendor_id,
181 product_id: self.product_id,
182 product_revision_level: self.product_revision_level,
183 serial_number: self.serial_number,
184 model_number: self.model_number,
185 physical_devices: build_vtl2_storage_backing_physical_devices(self.physical_devices),
186 is_dvd: self.is_dvd,
187 chunk_size_in_kb: self.chunk_size_in_kb,
188 ..Default::default()
189 }
190 }
191}
192
193#[derive(Debug, PartialEq, Eq)]
200pub struct Vtl2StorageControllerBuilder {
201 instance_id: Guid,
202 protocol: ControllerType,
203 luns: Vec<Vtl2LunBuilder>,
204 io_queue_depth: Option<u32>,
205}
206
207impl Vtl2StorageControllerBuilder {
208 pub fn new(protocol: ControllerType) -> Self {
212 Self {
213 instance_id: Guid::new_random(),
214 protocol,
215 luns: Vec::new(),
216 io_queue_depth: None,
217 }
218 }
219
220 pub fn with_instance_id(mut self, instance_id: Guid) -> Self {
222 self.instance_id = instance_id;
223 self
224 }
225
226 pub fn add_lun(mut self, lun: Vtl2LunBuilder) -> Self {
228 self.luns.push(lun);
229 self
230 }
231
232 pub fn add_luns(mut self, luns: Vec<Vtl2LunBuilder>) -> Self {
234 self.luns.extend(luns);
235 self
236 }
237
238 pub fn build(mut self) -> vtl2_settings_proto::StorageController {
240 let protocol = match self.protocol {
241 ControllerType::Scsi => vtl2_settings_proto::storage_controller::StorageProtocol::Scsi,
242 ControllerType::Nvme => vtl2_settings_proto::storage_controller::StorageProtocol::Nvme,
243 ControllerType::Ide => vtl2_settings_proto::storage_controller::StorageProtocol::Ide,
244 };
245
246 vtl2_settings_proto::StorageController {
247 instance_id: self.instance_id.to_string(),
248 protocol: protocol.into(),
249 luns: self.luns.drain(..).map(|l| l.build()).collect(),
250 io_queue_depth: self.io_queue_depth,
251 }
252 }
253}