#![forbid(unsafe_code)]
use inspect::Inspect;
use scsi_buffers::RequestBuffers;
use scsi_defs::ScsiOp;
use scsi_defs::ScsiStatus;
use scsi_defs::srb::SrbStatus;
use stackfuture::StackFuture;
use std::sync::Arc;
use vm_resource::CanResolveTo;
use vm_resource::kind::ScsiDeviceHandleKind;
use vmcore::save_restore::RestoreError;
use vmcore::save_restore::SaveError;
use vmcore::vm_task::VmTaskDriverSource;
impl CanResolveTo<ResolvedScsiDevice> for ScsiDeviceHandleKind {
type Input<'a> = ResolveScsiDeviceHandleParams<'a>;
}
pub struct ResolvedScsiDevice(pub Arc<dyn AsyncScsiDisk>);
impl<T: 'static + AsyncScsiDisk> From<T> for ResolvedScsiDevice {
fn from(value: T) -> Self {
Self(Arc::new(value))
}
}
pub struct ResolveScsiDeviceHandleParams<'a> {
pub driver_source: &'a VmTaskDriverSource,
}
pub const ASYNC_SCSI_DISK_STACK_SIZE: usize = 1256 + 336;
pub trait AsyncScsiDisk: Send + Sync + Inspect + ScsiSaveRestore {
fn execute_scsi<'a>(
&'a self,
external_data: &'a RequestBuffers<'a>,
request: &'a Request,
) -> StackFuture<'a, ScsiResult, { ASYNC_SCSI_DISK_STACK_SIZE }>;
}
#[derive(Debug)]
pub struct Request {
pub cdb: [u8; 0x10],
pub srb_flags: u32,
}
impl Request {
pub fn scsiop(&self) -> ScsiOp {
ScsiOp(self.cdb[0])
}
}
#[derive(Debug)]
pub struct ScsiResult {
pub scsi_status: ScsiStatus,
pub srb_status: SrbStatus,
pub tx: usize,
pub sense_data: Option<scsi_defs::SenseData>,
}
pub trait ScsiSaveRestore {
fn save(&self) -> Result<Option<save_restore::ScsiSavedState>, SaveError>;
fn restore(&self, state: &save_restore::ScsiSavedState) -> Result<(), RestoreError>;
}
pub mod save_restore {
#![expect(missing_docs)]
use mesh::payload::Protobuf;
#[derive(Debug, Copy, Clone, Eq, PartialEq, Protobuf)]
#[mesh(package = "storage.scsi.common")]
pub struct SavedSenseData {
#[mesh(1)]
pub sense_key: u8,
#[mesh(2)]
pub additional_sense_code: u8,
#[mesh(3)]
pub additional_sense_code_qualifier: u8,
}
#[derive(Debug, Copy, Clone, Protobuf)]
#[mesh(package = "storage.scsi.disk")]
pub struct ScsiDiskSavedState {
#[mesh(1)]
pub sector_count: u64,
#[mesh(2)]
pub sense_data: Option<SavedSenseData>,
}
#[derive(Debug, Protobuf, Copy, Clone)]
#[mesh(package = "storage.scsi")]
pub enum ScsiSavedState {
#[mesh(1)]
ScsiDvd(ScsiDvdSavedState),
#[mesh(2)]
ScsiDisk(ScsiDiskSavedState),
}
#[derive(Debug, Protobuf, Copy, Clone)]
#[mesh(package = "storage.scsi.dvd")]
pub struct ScsiDvdSavedState {
#[mesh(1)]
pub sense_data: Option<SavedSenseData>,
#[mesh(2)]
pub persistent: bool,
#[mesh(3)]
pub prevent: bool,
#[mesh(4)]
pub drive_state: DriveState,
#[mesh(5)]
pub pending_medium_event: IsoMediumEvent,
}
#[derive(Debug, Default, PartialEq, Eq, Copy, Clone, inspect::Inspect, Protobuf)]
#[expect(clippy::enum_variant_names)]
#[mesh(package = "storage.scsi.dvd")]
pub enum DriveState {
#[mesh(1)]
MediumPresentTrayOpen,
#[mesh(2)]
MediumPresentTrayClosed,
#[mesh(3)]
MediumNotPresentTrayOpen,
#[default]
#[mesh(4)]
MediumNotPresentTrayClosed,
}
impl DriveState {
pub fn tray_open(&self) -> bool {
*self == DriveState::MediumPresentTrayOpen
|| *self == DriveState::MediumNotPresentTrayOpen
}
pub fn medium_present(&self) -> bool {
*self == DriveState::MediumPresentTrayOpen
|| *self == DriveState::MediumPresentTrayClosed
}
}
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Protobuf)]
#[mesh(package = "storage.scsi.dvd")]
pub enum IsoMediumEvent {
#[default]
#[mesh(1)]
None = 0x00,
#[mesh(2)]
NoMediaToMedia = 0x01,
#[mesh(3)]
MediaToNoMedia = 0x02,
#[mesh(4)]
MediaToMedia = 0x03,
}
}