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 location: u32,
98 device_id: Guid,
99 vendor_id: String,
100 product_id: String,
101 product_revision_level: String,
102 serial_number: String,
103 model_number: String,
104 physical_devices: Vec<Vtl2StorageBackingDeviceBuilder>,
105 is_dvd: bool,
106 chunk_size_in_kb: u32,
107}
108
109impl Vtl2LunBuilder {
110 pub fn disk() -> Self {
113 Self {
114 location: 0,
115 device_id: Guid::new_random(),
116 vendor_id: "OpenVMM".to_string(),
117 product_id: "Disk".to_string(),
118 product_revision_level: "1.0".to_string(),
119 serial_number: "0".to_string(),
120 model_number: "1".to_string(),
121 physical_devices: Vec::new(),
122 is_dvd: false,
123 chunk_size_in_kb: 0,
124 }
125 }
126
127 pub fn dvd() -> Self {
130 let mut s = Self::disk();
131 s.is_dvd = true;
132 s.product_id = "DVD".to_string();
133 s
134 }
135
136 pub fn with_location(mut self, location: u32) -> Self {
138 self.location = location;
139 self
140 }
141
142 pub fn with_physical_devices(
146 mut self,
147 physical_devices: Vec<Vtl2StorageBackingDeviceBuilder>,
148 ) -> Self {
149 self.physical_devices = physical_devices;
150 self
151 }
152
153 pub fn with_physical_device(self, physical_device: Vtl2StorageBackingDeviceBuilder) -> Self {
157 self.with_physical_devices(vec![physical_device])
158 }
159
160 pub fn with_chunk_size_in_kb(mut self, chunk_size_in_kb: u32) -> Self {
162 self.chunk_size_in_kb = chunk_size_in_kb;
163 self
164 }
165
166 pub fn build(self) -> vtl2_settings_proto::Lun {
168 vtl2_settings_proto::Lun {
169 location: self.location,
170 device_id: self.device_id.to_string(),
171 vendor_id: self.vendor_id,
172 product_id: self.product_id,
173 product_revision_level: self.product_revision_level,
174 serial_number: self.serial_number,
175 model_number: self.model_number,
176 physical_devices: build_vtl2_storage_backing_physical_devices(self.physical_devices),
177 is_dvd: self.is_dvd,
178 chunk_size_in_kb: self.chunk_size_in_kb,
179 ..Default::default()
180 }
181 }
182}
183
184#[derive(Debug, PartialEq, Eq)]
191pub struct Vtl2StorageControllerBuilder {
192 instance_id: Guid,
193 protocol: ControllerType,
194 luns: Vec<Vtl2LunBuilder>,
195 io_queue_depth: Option<u32>,
196}
197
198impl Vtl2StorageControllerBuilder {
199 pub fn scsi() -> Self {
202 Self {
203 instance_id: Guid::new_random(),
204 protocol: ControllerType::Scsi,
205 luns: Vec::new(),
206 io_queue_depth: None,
207 }
208 }
209
210 pub fn with_instance_id(mut self, instance_id: Guid) -> Self {
212 self.instance_id = instance_id;
213 self
214 }
215
216 pub fn with_protocol(mut self, protocol: ControllerType) -> Self {
218 self.protocol = protocol;
219 self
220 }
221
222 pub fn add_lun(mut self, lun: Vtl2LunBuilder) -> Self {
224 self.luns.push(lun);
225 self
226 }
227
228 pub fn add_luns(mut self, luns: Vec<Vtl2LunBuilder>) -> Self {
230 self.luns.extend(luns);
231 self
232 }
233
234 pub fn build(mut self) -> vtl2_settings_proto::StorageController {
236 let protocol = match self.protocol {
237 ControllerType::Scsi => vtl2_settings_proto::storage_controller::StorageProtocol::Scsi,
238 ControllerType::Nvme => vtl2_settings_proto::storage_controller::StorageProtocol::Nvme,
239 ControllerType::Ide => vtl2_settings_proto::storage_controller::StorageProtocol::Ide,
240 };
241
242 vtl2_settings_proto::StorageController {
243 instance_id: self.instance_id.to_string(),
244 protocol: protocol.into(),
245 luns: self.luns.drain(..).map(|l| l.build()).collect(),
246 io_queue_depth: self.io_queue_depth,
247 }
248 }
249}