From dcfb758362265d81cdd5815cda7352d1d6ac3f72 Mon Sep 17 00:00:00 2001 From: sky5454 Date: Wed, 1 May 2024 19:45:22 +0800 Subject: [PATCH 01/10] [SCSI] add SCSI Protocol as preliminary supported. --- uefi-raw/src/protocol/mod.rs | 1 + uefi-raw/src/protocol/scsi.rs | 265 ++++++++++++++++++++++++++++++++++ uefi/src/proto/mod.rs | 8 +- uefi/src/proto/scsi.rs | 159 ++++++++++++++++++++ 4 files changed, 430 insertions(+), 3 deletions(-) create mode 100644 uefi-raw/src/protocol/scsi.rs create mode 100644 uefi/src/proto/scsi.rs diff --git a/uefi-raw/src/protocol/mod.rs b/uefi-raw/src/protocol/mod.rs index 16616ca0a..d62300ed1 100644 --- a/uefi-raw/src/protocol/mod.rs +++ b/uefi-raw/src/protocol/mod.rs @@ -16,4 +16,5 @@ pub mod memory_protection; pub mod misc; pub mod network; pub mod rng; +pub mod scsi; pub mod shell_params; diff --git a/uefi-raw/src/protocol/scsi.rs b/uefi-raw/src/protocol/scsi.rs new file mode 100644 index 000000000..931a53ace --- /dev/null +++ b/uefi-raw/src/protocol/scsi.rs @@ -0,0 +1,265 @@ +use core::ffi::c_void; + +use bitflags::bitflags; + +use crate::protocol::device_path::DevicePathProtocol; +use crate::{guid, Event, Guid, Status}; + +bitflags! { + /// DataDirection + #[repr(transparent)] + #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] + pub struct DataDirection: u8 { + const EFI_SCSI_IO_DATA_DIRECTION_READ = 0; + const EFI_SCSI_IO_DATA_DIRECTION_WRITE = 1; + const EFI_SCSI_IO_DATA_DIRECTION_BIDIRECTIONAL = 2; + } +} + +bitflags! { + /// HostAdapterStatus + #[repr(transparent)] + #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] + pub struct HostAdapterStatus: u8 { + const EFI_SCSI_IO_STATUS_HOST_ADAPTER_OK = 0x00 ; + const EFI_SCSI_IO_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND =0x09 ; + const EFI_SCSI_IO_STATUS_HOST_ADAPTER_TIMEOUT =0x0b ; + const EFI_SCSI_IO_STATUS_HOST_ADAPTER_MESSAGE_REJECT =0x0d ; + const EFI_SCSI_IO_STATUS_HOST_ADAPTER_BUS_RESET =0x0e ; + const EFI_SCSI_IO_STATUS_HOST_ADAPTER_PARITY_ERROR =0x0f ; + const EFI_SCSI_IO_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED =0x10 ; + const EFI_SCSI_IO_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT =0x11 ; + const EFI_SCSI_IO_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN =0x12 ; + const EFI_SCSI_IO_STATUS_HOST_ADAPTER_BUS_FREE =0x13 ; + const EFI_SCSI_IO_STATUS_HOST_ADAPTER_PHASE_ERROR =0x14 ; + const EFI_SCSI_IO_STATUS_HOST_ADAPTER_OTHER =0x7f ; + + } +} + +bitflags! { + /// TargetStatus + #[repr(transparent)] + #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] + pub struct TargetStatus: u8 { + const EFI_SCSI_IO_STATUS_TARGET_GOOD =0x00; + const EFI_SCSI_IO_STATUS_TARGET_CHECK_CONDITION =0x02; + const EFI_SCSI_IO_STATUS_TARGET_CONDITION_MET =0x04; + const EFI_SCSI_IO_STATUS_TARGET_BUSY =0x08; + const EFI_SCSI_IO_STATUS_TARGET_INTERMEDIATE =0x10; + const EFI_SCSI_IO_STATUS_TARGET_INTERMEDIATE_CONDITION_METn =0x14; + const EFI_SCSI_IO_STATUS_TARGET_RESERVATION_CONFLICT =0x18; + const EFI_SCSI_IO_STATUS_TARGET_COMMAND_TERMINATED =0x22; + const EFI_SCSI_IO_STATUS_TARGET_QUEUE_FULL =0x28; + } +} + +#[derive(Debug)] +#[repr(C)] +pub struct ScsiIoScsiRequestPacket { + pub timeout: u64, + + pub in_data_buffer: *mut c_void, + pub out_data_buffer: *mut c_void, + pub sense_data: *mut c_void, + pub cdb: *mut c_void, + + pub in_transfer_length: u32, + pub out_transfer_length: u32, + + pub cdb_length: u8, + pub data_direction: DataDirection, + pub host_adapter_status: HostAdapterStatus, + pub target_status: TargetStatus, + pub sense_data_length: u8, +} + +bitflags! { + /// DeviceType + /// Defined in the SCSI Primary Commands standard (e.g., SPC-4) + #[repr(transparent)] + #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] + pub struct DeviceType: u8 { + const DISK = 0x00; // Disk device + const TAPE = 0x01; // Tape device + const PRINTER = 0x02;// Printer + const PROCESSOR = 0x03;// Processor + const WORM = 0x04;// Write-once read-multiple + const CDROM = 0x05;// CD or DVD device + const SCANNER = 0x06;// Scanner device + const OPTICAL = 0x07;// Optical memory device + const MEDIUMCHANGER = 0x08;// Medium Changer device + const COMMUNICATION = 0x09;// Communications device + + + const MFI_A = 0x0A; // Obsolete + const MFI_B = 0x0B; // Obsolete + const MFI_RAID = 0x0C; // Storage array controller + + const MFI_SES = 0x0D; // Enclosure services device + const MFI_RBC = 0x0E; // Simplified direct-access + + + const MFI_OCRW = 0x0F; // Optical card reader/ + + const MFI_BRIDGE = 0x10; // Bridge Controller + + const MFI_OSD = 0x11; // Object-based Storage + + const RESERVED_LOW = 0x12; // Reserved (low) + const RESERVED_HIGH = 0x1E; // Reserved (high) + const UNKNOWN = 0x1F; // Unknown no device type + } +} + +#[derive(Debug)] +#[repr(C)] +pub struct ScsiIoProtocol { + //TODO: return deviceType + pub get_device_type: + unsafe extern "efiapi" fn(this: *const Self, device_type: *mut DeviceType) -> Status, + //TODO: raw pointer need to fixed, see uefi-rs service code like pointer *u8 + pub get_device_location: + unsafe extern "efiapi" fn(this: *const Self, target: *mut *mut u8, lun: *mut u64) -> Status, + pub reset_bus: unsafe extern "efiapi" fn(this: *mut Self) -> Status, + pub reset_device: unsafe extern "efiapi" fn(this: *mut Self) -> Status, + pub execute_scsi_command: unsafe extern "efiapi" fn( + this: *const Self, + packet: *mut ScsiIoScsiRequestPacket, + event: Event, + ) -> Status, + pub io_align: u32, +} + +/// 15.4. EFI SCSI I/O Protocol +impl ScsiIoProtocol { + pub const GUID: Guid = guid!("932f47e6-2362-4002-803e-3cd54b138f85"); +} + +// TODO: see device_path.rs, then see 15.5. SCSI Device Paths and 15.6. SCSI Pass Thru Device Paths + +#[derive(Debug)] +#[repr(C)] +pub struct ExtScsiPassThruProtocol { + pub mode: ExtScsiPassThruMode, + pub pass_thru: unsafe extern "efiapi" fn( + this: *const Self, + target: *mut u8, + lun: u64, + packet: *mut ExtScsiIoScsiRequestPacket, + event: Event, + ) -> Status, + pub get_next_target_lun: + unsafe extern "efiapi" fn(this: *const Self, target: *mut *mut u8, lun: *mut u64) -> Status, + pub build_device_path: unsafe extern "efiapi" fn( + this: *mut Self, + target: *mut u8, + lun: u64, + device_path: *mut *mut DevicePathProtocol, + ) -> Status, + pub get_target_lun: unsafe extern "efiapi" fn( + this: *const Self, + device_path: *mut DevicePathProtocol, + target: *mut *mut u8, + lun: *mut u64, + ) -> Status, + + pub reset_channel: unsafe extern "efiapi" fn(this: *mut Self) -> Status, + pub reset_target_lun: + unsafe extern "efiapi" fn(this: *mut Self, target: *mut u8, lun: u64) -> Status, + pub get_next_target: + unsafe extern "efiapi" fn(this: *const Self, target: *mut *mut u8) -> Status, +} +/// 15.7. Extended SCSI Pass Thru Protocol +impl ExtScsiPassThruProtocol { + pub const GUID: Guid = guid!("143b7632-b81b-4cb7-abd3-b625a5b9bffe"); +} + +bitflags! { + /// Attributes + /// TODO: #define TARGET_MAX_BYTES 0x10 + #[repr(transparent)] + #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] + pub struct Attributes: u32 { + const EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL = 0x0001; + const EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL = 0x0002; + const EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO = 0x0004; + } +} + +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] +#[repr(C)] +pub struct ExtScsiPassThruMode { + pub adapter_id: u32, + pub attributes: Attributes, + pub io_align: u32, +} + +#[derive(Debug)] +#[repr(C)] +pub struct ExtScsiIoScsiRequestPacket { + pub timeout: u64, + + pub in_data_buffer: *mut c_void, + pub out_data_buffer: *mut c_void, + pub sense_data: *mut c_void, + pub cdb: *mut c_void, + + pub in_transfer_length: u32, + pub out_transfer_length: u32, + + pub cdb_length: u8, + pub data_direction: ExtDataDirection, + pub host_adapter_status: ExtHostAdapterStatus, + pub target_status: ExtTargetStatus, + pub sense_data_length: u8, +} + +bitflags! { + /// Ext DataDirection + #[repr(transparent)] + #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] + pub struct ExtDataDirection: u8 { + const EFI_EXT_SCSI_DATA_DIRECTION_READ = 0; + const EFI_EXT_SCSI_DATA_DIRECTION_WRITE = 1; + const EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL = 2; + } +} + +bitflags! { + /// Ext HostAdapterStatus + #[repr(transparent)] + #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] + pub struct ExtHostAdapterStatus: u8 { + const EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK =0x00; + const EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND =0x09; + const EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT =0x0b; + const EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT =0x0d; + const EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET =0x0e; + const EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR =0x0f; + const EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED =0x10; + const EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT =0x11; + const EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN =0x12; + const EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE =0x13; + const EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR =0x14; + const EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER =0x7f; + } +} + +bitflags! { + /// ExtTargetStatus + #[repr(transparent)] + #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] + pub struct ExtTargetStatus: u8 { + const EFI_EXT_SCSI_STATUS_TARGET_GOOD = 0x00; + const EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION = 0x02; + const EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET = 0x04; + const EFI_EXT_SCSI_STATUS_TARGET_BUSY = 0x08; + const EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE = 0x10; + const EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET = 0x14; + const EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT = 0x18; + const EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL = 0x28; + const EFI_EXT_SCSI_STATUS_TARGET_ACA_ACTIVE = 0x30; + const EFI_EXT_SCSI_STATUS_TARGET_TASK_ABORTED = 0x40; + } +} diff --git a/uefi/src/proto/mod.rs b/uefi/src/proto/mod.rs index 5919b7afc..dbb750c9f 100644 --- a/uefi/src/proto/mod.rs +++ b/uefi/src/proto/mod.rs @@ -9,9 +9,12 @@ //! //! [`BootServices`]: crate::table::boot::BootServices#accessing-protocols -use crate::Identify; use core::ffi::c_void; +pub use uefi_macros::unsafe_protocol; + +use crate::Identify; + /// Common trait implemented by all standard UEFI protocols. /// /// You can derive the `Protocol` trait and specify the protocol's GUID using @@ -64,8 +67,6 @@ where } } -pub use uefi_macros::unsafe_protocol; - pub mod console; pub mod debug; pub mod device_path; @@ -76,6 +77,7 @@ pub mod misc; pub mod network; pub mod pi; pub mod rng; +pub mod scsi; pub mod security; pub mod shell_params; pub mod shim; diff --git a/uefi/src/proto/scsi.rs b/uefi/src/proto/scsi.rs new file mode 100644 index 000000000..0c1199ff9 --- /dev/null +++ b/uefi/src/proto/scsi.rs @@ -0,0 +1,159 @@ +//! EFI SCSI I/O protocols. + +use core::ptr::null; + +use uefi_raw::protocol::device_path::DevicePathProtocol; +use uefi_raw::protocol::scsi; +use uefi_raw::protocol::scsi::{ + ExtScsiIoScsiRequestPacket, ExtScsiPassThruMode, ExtScsiPassThruProtocol, ScsiIoProtocol, + ScsiIoScsiRequestPacket, +}; + +use crate::{Event, Result, StatusExt}; + +/// Protocol for who running in the EFI boot services environment such as code, typically drivers, able to access SCSI devices. +#[derive(Debug)] +#[repr(transparent)] +#[unsafe_protocol(ScsiIoProtocol::GUID)] +pub struct ScsiIo(ScsiIoProtocol); + +/// Represents a scsi device location which {target, lun}. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[repr(transparent)] +pub struct ScsiDeviceLocation { + /// Target ID + pub target: *mut u8, + /// Logical Unit Number + pub lun: u64, +} + +impl Default for ScsiDeviceLocation { + fn default() -> Self { + ScsiDeviceLocation { + target: null() as *mut u8, + lun: 0, + } + } +} +impl ScsiIo { + /// Retrieves the device type information of the SCSI Device. + pub fn get_device_type(&self) -> Result { + let mut device_type = scsi::DeviceType::default(); + unsafe { (self.0.get_device_type)(&self.0, &mut device_type) } + .to_result_with_val(|| device_type) + } + + /// Retrieves the SCSI device location in the SCSI channel. + pub fn get_device_location(&self) -> Result { + let mut location = ScsiDeviceLocation::default(); + unsafe { (self.0.get_device_location)(&self.0, &mut location.target, &mut location.lun) } + .to_result_with_val(|| location) + } + /// Resets the SCSI Bus that the SCSI Device is attached to. + pub fn reset_bus(&mut self) -> Result { + unsafe { self.0.reset_bus(&mut self.0) }.to_result() + } + /// Resets the SCSI Device that is specified by the device handle that the SCSI I/O Protocol is attached. + pub fn reset_device(&mut self) -> Result { + unsafe { self.0.reset_bus(&mut self.0) }.to_result() + } + + /// Sends a SCSI Request Packet to the SCSI Device for execution. + ///TODO: ScsiIoScsiRequestPacket must to refactor + pub fn execute_scsi_command( + &self, + packet: *mut ScsiIoScsiRequestPacket, + event: Event, + ) -> Result { + unsafe { self.0.execute_scsi_command(&self.0, packet, event) }.to_result() + } + + pub fn io_align(&self) -> Result { + unsafe { self.0.io_align }.to_result() + } +} + +/// Extended SCSI Pass Thru Protocol. +#[derive(Debug)] +#[repr(transparent)] +#[unsafe_protocol(ExtScsiPassThruProtocol::GUID)] +pub struct ExtScsiPassThru(ExtScsiPassThruProtocol); + +impl ExtScsiPassThru { + pub fn mode(&self) -> Result { + unsafe { self.0.mode }.to_result() + } + /// Sends a SCSI Request Packet to a SCSI device that is attached to the SCSI channel. + pub fn pass_thru( + &mut self, + location: ScsiDeviceLocation, + packet: *mut ExtScsiIoScsiRequestPacket, + event: Event, + ) -> Result { + unsafe { + (self.0.pass_thru)( + &mut self.0, + location.target, + location.lun, + packet, + event.as_ptr(), + ) + } + .to_result() + } + + /// Used to translate a device path node to a Target ID and LUN. + pub fn get_next_target_lun(&mut self) -> Result { + let mut location = ScsiDeviceLocation::default(); + unsafe { (self.0.get_next_target_lun)(&self.0, &mut location.target, &mut location.lun) } + .to_result_with_val(|| location) + } + + /// Used to allocate and build a device path node for a SCSI device on a SCSI channel. + pub fn build_device_path( + &mut self, + location: ScsiDeviceLocation, + ) -> Result<*mut DevicePathProtocol> { + let mut path = &mut DevicePathProtocol { + major_type: 0, + sub_type: 0, + length: [0, 0], + } as *mut DevicePathProtocol; + unsafe { (self.0.build_device_path)(&mut self.0, location.target, location.lun, &mut path) } + .to_result_with_val(|| path) + } + + /// Used to translate a device path node to a Target ID and LUN. + pub fn get_target_lun( + &mut self, + device_path: *mut DevicePathProtocol, + ) -> Result { + let mut location = ScsiDeviceLocation::default(); + unsafe { + (self.0.get_target_lun)( + &self.0, + device_path, + &mut location.target, + &mut location.lun, + ) + } + .to_result_with_val(|| location) + } + + /// Resets a SCSI channel. This operation resets all the SCSI devices connected to the SCSI channel. + pub fn reset_channel(&mut self) -> Result { + unsafe { (self.0.reset_channel)(&mut self.0) }.to_result() + } + + /// Resets a SCSI logical unit that is connected to a SCSI channel. + pub fn reset_target_lun(&mut self, location: ScsiDeviceLocation) -> Result { + unsafe { (self.0.reset_target_lun)(&mut self.0, location.target, location.lun) }.to_result() + } + + /// Used to retrieve the list of legal Target IDs for SCSI devices on a SCSI channel. + pub fn get_next_target(&mut self) -> Result { + let mut location = ScsiDeviceLocation::default(); + unsafe { (self.0.get_next_target)(&self.0, &mut location.target) } + .to_result_with_val(|| location) + } +} From 76df1ed75f7ee12771b75545a82f79d502aaf019 Mon Sep 17 00:00:00 2001 From: sky5454 Date: Wed, 1 May 2024 20:03:27 +0800 Subject: [PATCH 02/10] [SCSI] build pass. --- uefi/src/proto/scsi.rs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/uefi/src/proto/scsi.rs b/uefi/src/proto/scsi.rs index 0c1199ff9..4ba9051af 100644 --- a/uefi/src/proto/scsi.rs +++ b/uefi/src/proto/scsi.rs @@ -1,6 +1,7 @@ //! EFI SCSI I/O protocols. -use core::ptr::null; + +use core::ptr::null_mut; use uefi_raw::protocol::device_path::DevicePathProtocol; use uefi_raw::protocol::scsi; @@ -10,6 +11,7 @@ use uefi_raw::protocol::scsi::{ }; use crate::{Event, Result, StatusExt}; +use crate::proto::unsafe_protocol; /// Protocol for who running in the EFI boot services environment such as code, typically drivers, able to access SCSI devices. #[derive(Debug)] @@ -19,7 +21,6 @@ pub struct ScsiIo(ScsiIoProtocol); /// Represents a scsi device location which {target, lun}. #[derive(Debug, Copy, Clone, Eq, PartialEq)] -#[repr(transparent)] pub struct ScsiDeviceLocation { /// Target ID pub target: *mut u8, @@ -30,7 +31,7 @@ pub struct ScsiDeviceLocation { impl Default for ScsiDeviceLocation { fn default() -> Self { ScsiDeviceLocation { - target: null() as *mut u8, + target: null_mut(), lun: 0, } } @@ -51,11 +52,11 @@ impl ScsiIo { } /// Resets the SCSI Bus that the SCSI Device is attached to. pub fn reset_bus(&mut self) -> Result { - unsafe { self.0.reset_bus(&mut self.0) }.to_result() + unsafe { (self.0.reset_bus)(&mut self.0) }.to_result() } /// Resets the SCSI Device that is specified by the device handle that the SCSI I/O Protocol is attached. pub fn reset_device(&mut self) -> Result { - unsafe { self.0.reset_bus(&mut self.0) }.to_result() + unsafe { (self.0.reset_device)(&mut self.0) }.to_result() } /// Sends a SCSI Request Packet to the SCSI Device for execution. @@ -65,11 +66,14 @@ impl ScsiIo { packet: *mut ScsiIoScsiRequestPacket, event: Event, ) -> Result { - unsafe { self.0.execute_scsi_command(&self.0, packet, event) }.to_result() + unsafe { (self.0.execute_scsi_command)(&self.0, packet, event.as_ptr()) }.to_result() } + /// the value of ioAlign pub fn io_align(&self) -> Result { - unsafe { self.0.io_align }.to_result() + let mut io_align: u32 = 0; + unsafe { io_align = self.0.io_align } + Ok(io_align) } } @@ -80,8 +84,11 @@ impl ScsiIo { pub struct ExtScsiPassThru(ExtScsiPassThruProtocol); impl ExtScsiPassThru { + /// the value of mode which is type ExtScsiPassThruMode. pub fn mode(&self) -> Result { - unsafe { self.0.mode }.to_result() + let mut mode = ExtScsiPassThruMode::default(); + unsafe { mode = self.0.mode } + Ok(mode) } /// Sends a SCSI Request Packet to a SCSI device that is attached to the SCSI channel. pub fn pass_thru( From 50633deeeb6a0666f5e6eb6d1a472ca619b03e27 Mon Sep 17 00:00:00 2001 From: sky5454 Date: Sat, 4 May 2024 01:20:18 +0800 Subject: [PATCH 03/10] [SCSI] use DevicePath replace DevicePathProtocol in FFI. --- uefi-raw/src/protocol/scsi.rs | 4 ++-- uefi/src/proto/scsi.rs | 20 +++++++++++++++----- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/uefi-raw/src/protocol/scsi.rs b/uefi-raw/src/protocol/scsi.rs index 931a53ace..193d7acbf 100644 --- a/uefi-raw/src/protocol/scsi.rs +++ b/uefi-raw/src/protocol/scsi.rs @@ -2,8 +2,8 @@ use core::ffi::c_void; use bitflags::bitflags; +use crate::{Event, guid, Guid, Status}; use crate::protocol::device_path::DevicePathProtocol; -use crate::{guid, Event, Guid, Status}; bitflags! { /// DataDirection @@ -159,7 +159,7 @@ pub struct ExtScsiPassThruProtocol { ) -> Status, pub get_target_lun: unsafe extern "efiapi" fn( this: *const Self, - device_path: *mut DevicePathProtocol, + device_path: *const DevicePathProtocol, target: *mut *mut u8, lun: *mut u64, ) -> Status, diff --git a/uefi/src/proto/scsi.rs b/uefi/src/proto/scsi.rs index 4ba9051af..ba062ffcd 100644 --- a/uefi/src/proto/scsi.rs +++ b/uefi/src/proto/scsi.rs @@ -11,6 +11,7 @@ use uefi_raw::protocol::scsi::{ }; use crate::{Event, Result, StatusExt}; +use crate::proto::device_path::DevicePath; use crate::proto::unsafe_protocol; /// Protocol for who running in the EFI boot services environment such as code, typically drivers, able to access SCSI devices. @@ -120,26 +121,35 @@ impl ExtScsiPassThru { pub fn build_device_path( &mut self, location: ScsiDeviceLocation, - ) -> Result<*mut DevicePathProtocol> { + ) -> Result<&DevicePath> { let mut path = &mut DevicePathProtocol { major_type: 0, sub_type: 0, length: [0, 0], } as *mut DevicePathProtocol; - unsafe { (self.0.build_device_path)(&mut self.0, location.target, location.lun, &mut path) } - .to_result_with_val(|| path) + unsafe { + let status = (self.0.build_device_path)(&mut self.0, location.target, location.lun, &mut path); + if status.is_success() { + Ok(DevicePath::from_ffi_ptr(path.cast())) + } else { + Err(status.into()) + } + } } /// Used to translate a device path node to a Target ID and LUN. pub fn get_target_lun( &mut self, - device_path: *mut DevicePathProtocol, + device_path: &DevicePath, ) -> Result { + let device_path_ptr: *const uefi_raw::protocol::device_path::DevicePathProtocol = + device_path.as_ffi_ptr().cast(); + let mut location = ScsiDeviceLocation::default(); unsafe { (self.0.get_target_lun)( &self.0, - device_path, + device_path_ptr, &mut location.target, &mut location.lun, ) From 472e3724454db38e595909bdc963c54df1cc3982 Mon Sep 17 00:00:00 2001 From: sky5454 Date: Sat, 4 May 2024 01:33:23 +0800 Subject: [PATCH 04/10] [SCSI] code format. --- uefi/src/proto/scsi.rs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/uefi/src/proto/scsi.rs b/uefi/src/proto/scsi.rs index ba062ffcd..142b5a3c6 100644 --- a/uefi/src/proto/scsi.rs +++ b/uefi/src/proto/scsi.rs @@ -1,6 +1,5 @@ //! EFI SCSI I/O protocols. - use core::ptr::null_mut; use uefi_raw::protocol::device_path::DevicePathProtocol; @@ -10,9 +9,9 @@ use uefi_raw::protocol::scsi::{ ScsiIoScsiRequestPacket, }; -use crate::{Event, Result, StatusExt}; use crate::proto::device_path::DevicePath; use crate::proto::unsafe_protocol; +use crate::{Event, Result, StatusExt}; /// Protocol for who running in the EFI boot services environment such as code, typically drivers, able to access SCSI devices. #[derive(Debug)] @@ -118,17 +117,15 @@ impl ExtScsiPassThru { } /// Used to allocate and build a device path node for a SCSI device on a SCSI channel. - pub fn build_device_path( - &mut self, - location: ScsiDeviceLocation, - ) -> Result<&DevicePath> { + pub fn build_device_path(&mut self, location: ScsiDeviceLocation) -> Result<&DevicePath> { let mut path = &mut DevicePathProtocol { major_type: 0, sub_type: 0, length: [0, 0], } as *mut DevicePathProtocol; unsafe { - let status = (self.0.build_device_path)(&mut self.0, location.target, location.lun, &mut path); + let status = + (self.0.build_device_path)(&mut self.0, location.target, location.lun, &mut path); if status.is_success() { Ok(DevicePath::from_ffi_ptr(path.cast())) } else { @@ -138,10 +135,7 @@ impl ExtScsiPassThru { } /// Used to translate a device path node to a Target ID and LUN. - pub fn get_target_lun( - &mut self, - device_path: &DevicePath, - ) -> Result { + pub fn get_target_lun(&mut self, device_path: &DevicePath) -> Result { let device_path_ptr: *const uefi_raw::protocol::device_path::DevicePathProtocol = device_path.as_ffi_ptr().cast(); From 35dd74fe2e7b7559daf29dc81b407aa78fe2b972 Mon Sep 17 00:00:00 2001 From: sky5454 Date: Sat, 4 May 2024 01:37:10 +0800 Subject: [PATCH 05/10] [SCSI][uefi-raw] add docs about raw packet `ScsiIoScsiRequestPacket` and `ExtScsiIoScsiRequestPacket`. refer to UEFI 2.10 spec docs. --- uefi-raw/src/protocol/scsi.rs | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/uefi-raw/src/protocol/scsi.rs b/uefi-raw/src/protocol/scsi.rs index 193d7acbf..e83b0760d 100644 --- a/uefi-raw/src/protocol/scsi.rs +++ b/uefi-raw/src/protocol/scsi.rs @@ -2,8 +2,8 @@ use core::ffi::c_void; use bitflags::bitflags; -use crate::{Event, guid, Guid, Status}; use crate::protocol::device_path::DevicePathProtocol; +use crate::{guid, Event, Guid, Status}; bitflags! { /// DataDirection @@ -54,23 +54,37 @@ bitflags! { } } +/// EFI_SCSI_IO_SCSI_REQUEST_PACKET #[derive(Debug)] #[repr(C)] pub struct ScsiIoScsiRequestPacket { + /// Timeout: The timeout, in 100 ns units, to use for the execution of this SCSI Request Packet. A Timeout value of 0 means that this function will wait indefinitely for the SCSI Request Packet to execute. If Timeout is greater than zero, then this function will return EFI_TIMEOUT if the time required to execute the SCSI Request Packet is greater than Timeout . pub timeout: u64, + /// []DataBuffer: A pointer to the data buffer to transfer from or to the SCSI device. + /// InDataBuffer: A pointer to the data buffer to transfer between the SCSI controller and the SCSI device for SCSI READ command. For all SCSI WRITE Commands this must point to NULL . pub in_data_buffer: *mut c_void, + /// OutDataBuffer: A pointer to the data buffer to transfer between the SCSI controller and the SCSI device for SCSI WRITE command. For all SCSI READ commands this field must point to NULL . pub out_data_buffer: *mut c_void, + /// SenseData: A pointer to the sense data that was generated by the execution of the SCSI Request Packet. pub sense_data: *mut c_void, + /// Cdb: A pointer to buffer that contains the Command Data Block to send to the SCSI device. pub cdb: *mut c_void, + /// InTransferLength: On Input, the size, in bytes, of InDataBuffer . On output, the number of bytes transferred between the SCSI controller and the SCSI device. If InTransferLength is larger than the SCSI controller can handle, no data will be transferred, InTransferLength will be updated to contain the number of bytes that the SCSI controller is able to transfer, and EFI_BAD_BUFFER_SIZE will be returned. pub in_transfer_length: u32, + /// OutTransferLength: On Input, the size, in bytes of OutDataBuffer . On Output, the Number of bytes transferred between SCSI Controller and the SCSI device. If OutTransferLength is larger than the SCSI controller can handle, no data will be transferred, OutTransferLength will be updated to contain the number of bytes that the SCSI controller is able to transfer, and EFI_BAD_BUFFER_SIZE will be returned. pub out_transfer_length: u32, + /// CdbLength: The length, in bytes, of the buffer Cdb . The standard values are 6, 10, 12, and 16, but other values are possible if a variable length CDB is used. pub cdb_length: u8, + /// DataDirection: The direction of the data transfer. 0 for reads, 1 for writes. A value of 2 is Reserved for Bi-Directional SCSI commands. For example XDREADWRITE. All other values are reserved, and must not be used. pub data_direction: DataDirection, + /// HostAdapterStatus: The status of the SCSI Host Controller that produces the SCSI bus where the SCSI device attached when the SCSI Request Packet was executed on the SCSI Controller. See the possible values listed below. pub host_adapter_status: HostAdapterStatus, + /// TargetStatus: The status returned by the SCSI device when the SCSI Request Packet was executed. See the possible values listed below. pub target_status: TargetStatus, + /// SenseDataLength: On input, the length in bytes of the SenseData buffer. On output, the number of bytes written to the SenseData buffer. pub sense_data_length: u8, } @@ -195,23 +209,36 @@ pub struct ExtScsiPassThruMode { pub io_align: u32, } +/// EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET #[derive(Debug)] #[repr(C)] pub struct ExtScsiIoScsiRequestPacket { + /// Timeout: The timeout, in 100 ns units, to use for the execution of this SCSI Request Packet. A Timeout value of 0 means that this function will wait indefinitely for the SCSI Request Packet to execute. If Timeout is greater than zero, then this function will return EFI_TIMEOUT if the time required to execute the SCSI Request Packet is greater than Timeout . pub timeout: u64, + /// InDataBuffer: A pointer to the data buffer to transfer between the SCSI controller and the SCSI device for read and bidirectional commands. For all write and non data commands where InTransferLength is 0 this field is optional and may be NULL . If this field is not NULL , then it must be aligned on the boundary specified by the IoAlign field in the EFI_EXT_SCSI_PASS_THRU_MODE structure. pub in_data_buffer: *mut c_void, + /// OutDataBuffer: A pointer to the data buffer to transfer between the SCSI controller and the SCSI device for write or bidirectional commands. For all read and non data commands where OutTransferLength is 0 this field is optional and may be NULL . If this field is not NULL , then it must be aligned on the boundary specified by the IoAlign field in the EFI_EXT_SCSI_PASS_THRU_MODE structure. pub out_data_buffer: *mut c_void, + /// SenseData: A pointer to the sense data that was generated by the execution of the SCSI Request Packet. If SenseDataLength is 0, then this field is optional and may be NULL . It is strongly recommended that a sense data buffer of at least 252 bytes be provided to guarantee the entire sense data buffer generated from the execution of the SCSI Request Packet can be returned. If this field is not NULL , then it must be aligned to the boundary specified in the IoAlign field in the EFI_EXT_SCSI_PASS_THRU_MODE structure. pub sense_data: *mut c_void, + /// Cdb: A pointer to buffer that contains the Command Data Block to send to the SCSI device specified by Target and Lun . pub cdb: *mut c_void, + /// InTransferLength: On Input, the size, in bytes, of InDataBuffer . On output, the number of bytes transferred between the SCSI controller and the SCSI device. If InTransferLength is larger than the SCSI controller can handle, no data will be transferred, InTransferLength will be updated to contain the number of bytes that the SCSI controller is able to transfer, and EFI_BAD_BUFFER_SIZE will be returned. pub in_transfer_length: u32, + /// OutTransferLength: On Input, the size, in bytes of OutDataBuffer . On Output, the Number of bytes transferred between SCSI Controller and the SCSI device. If OutTransferLength is larger than the SCSI controller can handle, no data will be transferred, OutTransferLength will be updated to contain the number of bytes that the SCSI controller is able to transfer, and EFI_BAD_BUFFER_SIZE will be returned. pub out_transfer_length: u32, + /// CdbLength: The length, in bytes, of the buffer Cdb . The standard values are 6, 10, 12, and 16, but other values are possible if a variable length CDB is used. pub cdb_length: u8, + /// DataDirection: The direction of the data transfer. 0 for reads, 1 for writes. A value of 2 is Reserved for Bi-Directional SCSI commands. For example XDREADWRITE. All other values are reserved, and must not be used. pub data_direction: ExtDataDirection, + /// HostAdapterStatus: The status of the host adapter specified by This when the SCSI Request Packet was executed on the target device. See the possible values listed below. If bit 7 of this field is set, then HostAdapterStatus is a vendor defined error code. pub host_adapter_status: ExtHostAdapterStatus, + /// TargetStatus: The status returned by the device specified by Target and Lun when the SCSI Request Packet was executed. See the possible values listed below. pub target_status: ExtTargetStatus, + /// SenseDataLength: On input, the length in bytes of the SenseData buffer. On output, the number of bytes written to the SenseData buffer. pub sense_data_length: u8, } From 08a229291d0f89388f0361aa8c509dc3bf9379bd Mon Sep 17 00:00:00 2001 From: sky5454 Date: Sat, 4 May 2024 05:30:20 +0800 Subject: [PATCH 06/10] [SCSI] FFI for scsi request packet; and docs. --- uefi-raw/src/protocol/scsi.rs | 74 ++++++++++---- uefi/src/proto/scsi.rs | 182 ++++++++++++++++++++++++++++++---- 2 files changed, 219 insertions(+), 37 deletions(-) diff --git a/uefi-raw/src/protocol/scsi.rs b/uefi-raw/src/protocol/scsi.rs index e83b0760d..68e37aad3 100644 --- a/uefi-raw/src/protocol/scsi.rs +++ b/uefi-raw/src/protocol/scsi.rs @@ -58,33 +58,48 @@ bitflags! { #[derive(Debug)] #[repr(C)] pub struct ScsiIoScsiRequestPacket { - /// Timeout: The timeout, in 100 ns units, to use for the execution of this SCSI Request Packet. A Timeout value of 0 means that this function will wait indefinitely for the SCSI Request Packet to execute. If Timeout is greater than zero, then this function will return EFI_TIMEOUT if the time required to execute the SCSI Request Packet is greater than Timeout . + /// Timeout: The timeout, in 100 ns units, to use for the execution of this SCSI Request Packet. + /// A Timeout value of 0 means that this function will wait indefinitely for the SCSI Request Packet to execute. + /// If Timeout is greater than zero, then this function will return EFI_TIMEOUT if the time required to execute the SCSI Request Packet is greater than Timeout . pub timeout: u64, /// []DataBuffer: A pointer to the data buffer to transfer from or to the SCSI device. - /// InDataBuffer: A pointer to the data buffer to transfer between the SCSI controller and the SCSI device for SCSI READ command. For all SCSI WRITE Commands this must point to NULL . + /// InDataBuffer: A pointer to the data buffer to transfer between the SCSI controller and the SCSI device for SCSI READ command. + /// For all SCSI WRITE Commands this must point to NULL . pub in_data_buffer: *mut c_void, - /// OutDataBuffer: A pointer to the data buffer to transfer between the SCSI controller and the SCSI device for SCSI WRITE command. For all SCSI READ commands this field must point to NULL . + /// OutDataBuffer: A pointer to the data buffer to transfer between the SCSI controller and the SCSI device for SCSI WRITE command. + /// For all SCSI READ commands this field must point to NULL . pub out_data_buffer: *mut c_void, /// SenseData: A pointer to the sense data that was generated by the execution of the SCSI Request Packet. pub sense_data: *mut c_void, /// Cdb: A pointer to buffer that contains the Command Data Block to send to the SCSI device. pub cdb: *mut c_void, - /// InTransferLength: On Input, the size, in bytes, of InDataBuffer . On output, the number of bytes transferred between the SCSI controller and the SCSI device. If InTransferLength is larger than the SCSI controller can handle, no data will be transferred, InTransferLength will be updated to contain the number of bytes that the SCSI controller is able to transfer, and EFI_BAD_BUFFER_SIZE will be returned. + /// InTransferLength: On Input, the size, in bytes, of InDataBuffer . + /// On output, the number of bytes transferred between the SCSI controller and the SCSI device. + /// If InTransferLength is larger than the SCSI controller can handle, no data will be transferred, + /// InTransferLength will be updated to contain the number of bytes that the SCSI controller is able to transfer, and EFI_BAD_BUFFER_SIZE will be returned. pub in_transfer_length: u32, - /// OutTransferLength: On Input, the size, in bytes of OutDataBuffer . On Output, the Number of bytes transferred between SCSI Controller and the SCSI device. If OutTransferLength is larger than the SCSI controller can handle, no data will be transferred, OutTransferLength will be updated to contain the number of bytes that the SCSI controller is able to transfer, and EFI_BAD_BUFFER_SIZE will be returned. + /// OutTransferLength: On Input, the size, in bytes of OutDataBuffer . + /// On Output, the Number of bytes transferred between SCSI Controller and the SCSI device. + /// If OutTransferLength is larger than the SCSI controller can handle, no data will be transferred, + /// OutTransferLength will be updated to contain the number of bytes that the SCSI controller is able to transfer, and EFI_BAD_BUFFER_SIZE will be returned. pub out_transfer_length: u32, - /// CdbLength: The length, in bytes, of the buffer Cdb . The standard values are 6, 10, 12, and 16, but other values are possible if a variable length CDB is used. + /// CdbLength: The length, in bytes, of the buffer Cdb . + /// The standard values are 6, 10, 12, and 16, but other values are possible if a variable length CDB is used. pub cdb_length: u8, - /// DataDirection: The direction of the data transfer. 0 for reads, 1 for writes. A value of 2 is Reserved for Bi-Directional SCSI commands. For example XDREADWRITE. All other values are reserved, and must not be used. + /// DataDirection: The direction of the data transfer. 0 for reads, 1 for writes. + /// A value of 2 is Reserved for Bi-Directional SCSI commands. For example XDREADWRITE. + /// All other values are reserved, and must not be used. pub data_direction: DataDirection, - /// HostAdapterStatus: The status of the SCSI Host Controller that produces the SCSI bus where the SCSI device attached when the SCSI Request Packet was executed on the SCSI Controller. See the possible values listed below. + /// HostAdapterStatus: The status of the SCSI Host Controller that produces the SCSI bus + /// where the SCSI device attached when the SCSI Request Packet was executed on the SCSI Controller. pub host_adapter_status: HostAdapterStatus, - /// TargetStatus: The status returned by the SCSI device when the SCSI Request Packet was executed. See the possible values listed below. + /// TargetStatus: The status returned by the SCSI device when the SCSI Request Packet was executed. pub target_status: TargetStatus, - /// SenseDataLength: On input, the length in bytes of the SenseData buffer. On output, the number of bytes written to the SenseData buffer. + /// SenseDataLength: On input, the length in bytes of the SenseData buffer. + /// On output, the number of bytes written to the SenseData buffer. pub sense_data_length: u8, } @@ -213,32 +228,51 @@ pub struct ExtScsiPassThruMode { #[derive(Debug)] #[repr(C)] pub struct ExtScsiIoScsiRequestPacket { - /// Timeout: The timeout, in 100 ns units, to use for the execution of this SCSI Request Packet. A Timeout value of 0 means that this function will wait indefinitely for the SCSI Request Packet to execute. If Timeout is greater than zero, then this function will return EFI_TIMEOUT if the time required to execute the SCSI Request Packet is greater than Timeout . + /// Timeout: The timeout, in 100 ns units, to use for the execution of this SCSI Request Packet. + /// A Timeout value of 0 means that this function will wait indefinitely for the SCSI Request Packet to execute. + /// If Timeout is greater than zero, then this function will return EFI_TIMEOUT if the time required to execute the SCSI Request Packet is greater than Timeout . pub timeout: u64, - /// InDataBuffer: A pointer to the data buffer to transfer between the SCSI controller and the SCSI device for read and bidirectional commands. For all write and non data commands where InTransferLength is 0 this field is optional and may be NULL . If this field is not NULL , then it must be aligned on the boundary specified by the IoAlign field in the EFI_EXT_SCSI_PASS_THRU_MODE structure. + /// InDataBuffer: A pointer to the data buffer to transfer between the SCSI controller and the SCSI device for read and bidirectional commands. + /// For all write and non data commands where InTransferLength is 0 this field is optional and may be NULL . + /// If this field is not NULL , then it must be aligned on the boundary specified by the IoAlign field in the EFI_EXT_SCSI_PASS_THRU_MODE structure. pub in_data_buffer: *mut c_void, - /// OutDataBuffer: A pointer to the data buffer to transfer between the SCSI controller and the SCSI device for write or bidirectional commands. For all read and non data commands where OutTransferLength is 0 this field is optional and may be NULL . If this field is not NULL , then it must be aligned on the boundary specified by the IoAlign field in the EFI_EXT_SCSI_PASS_THRU_MODE structure. + /// OutDataBuffer: A pointer to the data buffer to transfer between the SCSI controller and the SCSI device for write or bidirectional commands. + /// For all read and non data commands where OutTransferLength is 0 this field is optional and may be NULL . + /// If this field is not NULL , then it must be aligned on the boundary specified by the IoAlign field in the EFI_EXT_SCSI_PASS_THRU_MODE structure. pub out_data_buffer: *mut c_void, - /// SenseData: A pointer to the sense data that was generated by the execution of the SCSI Request Packet. If SenseDataLength is 0, then this field is optional and may be NULL . It is strongly recommended that a sense data buffer of at least 252 bytes be provided to guarantee the entire sense data buffer generated from the execution of the SCSI Request Packet can be returned. If this field is not NULL , then it must be aligned to the boundary specified in the IoAlign field in the EFI_EXT_SCSI_PASS_THRU_MODE structure. + /// SenseData: A pointer to the sense data that was generated by the execution of the SCSI Request Packet. + /// If SenseDataLength is 0, then this field is optional and may be NULL . + /// It is strongly recommended that a sense data buffer of at least 252 bytes be provided to guarantee the entire sense data buffer + /// generated from the execution of the SCSI Request Packet can be returned. + /// If this field is not NULL , then it must be aligned to the boundary specified in the IoAlign field in the EFI_EXT_SCSI_PASS_THRU_MODE structure. pub sense_data: *mut c_void, /// Cdb: A pointer to buffer that contains the Command Data Block to send to the SCSI device specified by Target and Lun . pub cdb: *mut c_void, - /// InTransferLength: On Input, the size, in bytes, of InDataBuffer . On output, the number of bytes transferred between the SCSI controller and the SCSI device. If InTransferLength is larger than the SCSI controller can handle, no data will be transferred, InTransferLength will be updated to contain the number of bytes that the SCSI controller is able to transfer, and EFI_BAD_BUFFER_SIZE will be returned. + /// InTransferLength: On Input, the size, in bytes, of InDataBuffer . + /// On output, the number of bytes transferred between the SCSI controller and the SCSI device. + /// If InTransferLength is larger than the SCSI controller can handle, no data will be transferred, + /// InTransferLength will be updated to contain the number of bytes that the SCSI controller is able to transfer, and EFI_BAD_BUFFER_SIZE will be returned. pub in_transfer_length: u32, - /// OutTransferLength: On Input, the size, in bytes of OutDataBuffer . On Output, the Number of bytes transferred between SCSI Controller and the SCSI device. If OutTransferLength is larger than the SCSI controller can handle, no data will be transferred, OutTransferLength will be updated to contain the number of bytes that the SCSI controller is able to transfer, and EFI_BAD_BUFFER_SIZE will be returned. + /// OutTransferLength: On Input, the size, in bytes of OutDataBuffer . On Output, the Number of bytes transferred between SCSI Controller and the SCSI device. + /// If OutTransferLength is larger than the SCSI controller can handle, no data will be transferred, + /// OutTransferLength will be updated to contain the number of bytes that the SCSI controller is able to transfer, + /// and EFI_BAD_BUFFER_SIZE will be returned. pub out_transfer_length: u32, /// CdbLength: The length, in bytes, of the buffer Cdb . The standard values are 6, 10, 12, and 16, but other values are possible if a variable length CDB is used. pub cdb_length: u8, - /// DataDirection: The direction of the data transfer. 0 for reads, 1 for writes. A value of 2 is Reserved for Bi-Directional SCSI commands. For example XDREADWRITE. All other values are reserved, and must not be used. + /// DataDirection: The direction of the data transfer. 0 for reads, 1 for writes. A value of 2 is Reserved for Bi-Directional SCSI commands. + /// For example XDREADWRITE. All other values are reserved, and must not be used. pub data_direction: ExtDataDirection, - /// HostAdapterStatus: The status of the host adapter specified by This when the SCSI Request Packet was executed on the target device. See the possible values listed below. If bit 7 of this field is set, then HostAdapterStatus is a vendor defined error code. + /// HostAdapterStatus: The status of the host adapter specified by This when the SCSI Request Packet was executed on the target device. + /// If bit 7 of this field is set, then HostAdapterStatus is a vendor defined error code. pub host_adapter_status: ExtHostAdapterStatus, - /// TargetStatus: The status returned by the device specified by Target and Lun when the SCSI Request Packet was executed. See the possible values listed below. + /// TargetStatus: The status returned by the device specified by Target and Lun when the SCSI Request Packet was executed. pub target_status: ExtTargetStatus, - /// SenseDataLength: On input, the length in bytes of the SenseData buffer. On output, the number of bytes written to the SenseData buffer. + /// SenseDataLength: On input, the length in bytes of the SenseData buffer. + /// On output, the number of bytes written to the SenseData buffer. pub sense_data_length: u8, } diff --git a/uefi/src/proto/scsi.rs b/uefi/src/proto/scsi.rs index 142b5a3c6..61f28a639 100644 --- a/uefi/src/proto/scsi.rs +++ b/uefi/src/proto/scsi.rs @@ -1,17 +1,20 @@ //! EFI SCSI I/O protocols. +use alloc::vec::Vec; +use core::ffi::c_void; use core::ptr::null_mut; use uefi_raw::protocol::device_path::DevicePathProtocol; use uefi_raw::protocol::scsi; use uefi_raw::protocol::scsi::{ - ExtScsiIoScsiRequestPacket, ExtScsiPassThruMode, ExtScsiPassThruProtocol, ScsiIoProtocol, - ScsiIoScsiRequestPacket, + DataDirection, ExtDataDirection, ExtHostAdapterStatus, ExtScsiIoScsiRequestPacket, + ExtScsiPassThruMode, ExtScsiPassThruProtocol, ExtTargetStatus, HostAdapterStatus, + ScsiIoProtocol, ScsiIoScsiRequestPacket, TargetStatus, }; +use crate::{Event, Result, StatusExt}; use crate::proto::device_path::DevicePath; use crate::proto::unsafe_protocol; -use crate::{Event, Result, StatusExt}; /// Protocol for who running in the EFI boot services environment such as code, typically drivers, able to access SCSI devices. #[derive(Debug)] @@ -61,19 +64,20 @@ impl ScsiIo { /// Sends a SCSI Request Packet to the SCSI Device for execution. ///TODO: ScsiIoScsiRequestPacket must to refactor - pub fn execute_scsi_command( - &self, - packet: *mut ScsiIoScsiRequestPacket, - event: Event, - ) -> Result { - unsafe { (self.0.execute_scsi_command)(&self.0, packet, event.as_ptr()) }.to_result() + pub fn execute_scsi_command(&self, packet: &mut ScsiRequestPacket, event: Event) -> Result { + unsafe { + (self.0.execute_scsi_command)( + &self.0, + &mut (packet.convert_to_request_packet()), + event.as_ptr(), + ) + } + .to_result() } /// the value of ioAlign pub fn io_align(&self) -> Result { - let mut io_align: u32 = 0; - unsafe { io_align = self.0.io_align } - Ok(io_align) + Ok(self.0.io_align) } } @@ -86,15 +90,13 @@ pub struct ExtScsiPassThru(ExtScsiPassThruProtocol); impl ExtScsiPassThru { /// the value of mode which is type ExtScsiPassThruMode. pub fn mode(&self) -> Result { - let mut mode = ExtScsiPassThruMode::default(); - unsafe { mode = self.0.mode } - Ok(mode) + Ok(self.0.mode) } /// Sends a SCSI Request Packet to a SCSI device that is attached to the SCSI channel. pub fn pass_thru( &mut self, location: ScsiDeviceLocation, - packet: *mut ExtScsiIoScsiRequestPacket, + mut packet: ScsiExtRequestPacket, event: Event, ) -> Result { unsafe { @@ -102,7 +104,7 @@ impl ExtScsiPassThru { &mut self.0, location.target, location.lun, - packet, + &mut (packet.convert_to_request_packet()), event.as_ptr(), ) } @@ -168,3 +170,149 @@ impl ExtScsiPassThru { .to_result_with_val(|| location) } } + +/// the rust FFI for `EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET` +#[derive(Debug, Default, Clone)] +pub struct ScsiExtRequestPacket { + /// whether the request is written scsi + pub is_a_write_packet: bool, + /// timeout + pub timeout: u64, + /// data_buffer is `in_data_buffer` or `out_data_buffer` + pub data_buffer: Vec, + /// SCSI's cdb, refer to T10 SPC + pub cdb: Vec, + /// SCSI's sense data, refer to T10 SPC + pub sense_data: Vec, + /// uefi_raw::protocol::scsi::ExtDataDirection + pub data_direction: ExtDataDirection, + /// uefi_raw::protocol::scsi::ExtHostAdapterStatus + pub host_adapter_status: ExtHostAdapterStatus, + /// uefi_raw::protocol::scsi::ExtTargetStatus + pub target_status: ExtTargetStatus, +} + +impl ScsiExtRequestPacket { + /// convert FFI `ScsiExtRequestPacket` to raw UEFI SCSI request packet `EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET` + pub fn convert_to_request_packet(&mut self) -> ExtScsiIoScsiRequestPacket { + if self.is_a_write_packet { + self._convert_to_write_request_packet() + } else { + self._convert_to_read_request_packet() + } + } + fn _convert_to_read_request_packet(&mut self) -> ExtScsiIoScsiRequestPacket { + let packet: ExtScsiIoScsiRequestPacket = ExtScsiIoScsiRequestPacket { + timeout: self.timeout, + + in_data_buffer: self.data_buffer.as_mut_ptr() as *mut c_void, + out_data_buffer: null_mut(), + sense_data: self.sense_data.as_mut_ptr() as *mut c_void, + cdb: self.cdb.as_mut_ptr() as *mut c_void, + + in_transfer_length: self.data_buffer.len() as u32, + out_transfer_length: 0, + sense_data_length: self.sense_data.len() as u8, + cdb_length: self.cdb.len() as u8, + + data_direction: self.data_direction, + host_adapter_status: self.host_adapter_status, + target_status: self.target_status, + }; + packet + } + + fn _convert_to_write_request_packet(&mut self) -> ExtScsiIoScsiRequestPacket { + let packet: ExtScsiIoScsiRequestPacket = ExtScsiIoScsiRequestPacket { + timeout: self.timeout, + + in_data_buffer: null_mut(), + out_data_buffer: self.data_buffer.as_mut_ptr() as *mut c_void, + sense_data: self.sense_data.as_mut_ptr() as *mut c_void, + cdb: self.cdb.as_mut_ptr() as *mut c_void, + + in_transfer_length: 0, + out_transfer_length: self.data_buffer.len() as u32, + sense_data_length: self.sense_data.len() as u8, + cdb_length: self.cdb.len() as u8, + + data_direction: self.data_direction, + host_adapter_status: self.host_adapter_status, + target_status: self.target_status, + }; + packet + } +} + +/// the rust FFI for `EFI_SCSI_IO_SCSI_REQUEST_PACKET` +#[derive(Debug, Default, Clone)] +pub struct ScsiRequestPacket { + /// whether the request is written scsi + is_a_write_packet: bool, + /// timeout + pub timeout: u64, + /// data_buffer is `in_data_buffer` or `out_data_buffer` + pub data_buffer: Vec, + /// SCSI's cdb, refer to T10 SPC + pub cdb: Vec, + /// SCSI's sense data, refer to T10 SPC + pub sense_data: Vec, + /// uefi_raw::protocol::scsi::DataDirection + pub data_direction: DataDirection, + /// uefi_raw::protocol::scsi::HostAdapterStatus + pub host_adapter_status: HostAdapterStatus, + /// uefi_raw::protocol::scsi::TargetStatus + pub target_status: TargetStatus, +} + +impl ScsiRequestPacket { + /// convert FFI `ScsiRequestPacket` to raw UEFI SCSI request packet `EFI_SCSI_IO_SCSI_REQUEST_PACKET` + pub fn convert_to_request_packet(&mut self) -> ScsiIoScsiRequestPacket { + if self.is_a_write_packet { + self._convert_to_write_request_packet() + } else { + self._convert_to_read_request_packet() + } + } + fn _convert_to_read_request_packet(&mut self) -> ScsiIoScsiRequestPacket { + let packet: ScsiIoScsiRequestPacket = ScsiIoScsiRequestPacket { + timeout: self.timeout, + + in_data_buffer: self.data_buffer.as_mut_ptr() as *mut c_void, + out_data_buffer: null_mut(), + sense_data: self.sense_data.as_mut_ptr() as *mut c_void, + cdb: self.cdb.as_mut_ptr() as *mut c_void, + + in_transfer_length: self.data_buffer.len() as u32, + out_transfer_length: 0, + sense_data_length: self.sense_data.len() as u8, + cdb_length: self.cdb.len() as u8, + + data_direction: self.data_direction, + host_adapter_status: self.host_adapter_status, + target_status: self.target_status, + }; + packet + } + + fn _convert_to_write_request_packet(&mut self) -> ScsiIoScsiRequestPacket { + let packet: ScsiIoScsiRequestPacket = ScsiIoScsiRequestPacket { + timeout: self.timeout, + + in_data_buffer: null_mut(), + out_data_buffer: self.data_buffer.as_mut_ptr() as *mut c_void, + sense_data: self.sense_data.as_mut_ptr() as *mut c_void, + cdb: self.cdb.as_mut_ptr() as *mut c_void, + + in_transfer_length: 0, + out_transfer_length: self.data_buffer.len() as u32, + sense_data_length: self.sense_data.len() as u8, + cdb_length: self.cdb.len() as u8, + + data_direction: self.data_direction, + host_adapter_status: self.host_adapter_status, + target_status: self.target_status, + }; + packet + } +} From b36ba067d772307481af49206730378fc0e0bcf6 Mon Sep 17 00:00:00 2001 From: sky5454 Date: Sat, 4 May 2024 20:38:38 +0800 Subject: [PATCH 07/10] [SCSI] use newtype_enum instead of bitflags. --- uefi-raw/src/protocol/scsi.rs | 231 ++++++++++++++++------------------ 1 file changed, 111 insertions(+), 120 deletions(-) diff --git a/uefi-raw/src/protocol/scsi.rs b/uefi-raw/src/protocol/scsi.rs index 68e37aad3..fe8bbee41 100644 --- a/uefi-raw/src/protocol/scsi.rs +++ b/uefi-raw/src/protocol/scsi.rs @@ -1,56 +1,58 @@ use core::ffi::c_void; -use bitflags::bitflags; - +use crate::{Event, guid, Guid, Status}; use crate::protocol::device_path::DevicePathProtocol; -use crate::{guid, Event, Guid, Status}; -bitflags! { +/// TODO: use #define TARGET_MAX_BYTES 0x10, the limit of target. +#[allow(unused)] +const TARGET_MAX_BYTES: u32 = 0x10; + + +newtype_enum! { /// DataDirection - #[repr(transparent)] - #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] - pub struct DataDirection: u8 { - const EFI_SCSI_IO_DATA_DIRECTION_READ = 0; - const EFI_SCSI_IO_DATA_DIRECTION_WRITE = 1; - const EFI_SCSI_IO_DATA_DIRECTION_BIDIRECTIONAL = 2; + #[derive(Default)] + pub enum DataDirection: u8 => { + READ = 0, + WRITE = 1, + BIDIRECTIONAL = 2, } } -bitflags! { +newtype_enum! { /// HostAdapterStatus - #[repr(transparent)] - #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] - pub struct HostAdapterStatus: u8 { - const EFI_SCSI_IO_STATUS_HOST_ADAPTER_OK = 0x00 ; - const EFI_SCSI_IO_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND =0x09 ; - const EFI_SCSI_IO_STATUS_HOST_ADAPTER_TIMEOUT =0x0b ; - const EFI_SCSI_IO_STATUS_HOST_ADAPTER_MESSAGE_REJECT =0x0d ; - const EFI_SCSI_IO_STATUS_HOST_ADAPTER_BUS_RESET =0x0e ; - const EFI_SCSI_IO_STATUS_HOST_ADAPTER_PARITY_ERROR =0x0f ; - const EFI_SCSI_IO_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED =0x10 ; - const EFI_SCSI_IO_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT =0x11 ; - const EFI_SCSI_IO_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN =0x12 ; - const EFI_SCSI_IO_STATUS_HOST_ADAPTER_BUS_FREE =0x13 ; - const EFI_SCSI_IO_STATUS_HOST_ADAPTER_PHASE_ERROR =0x14 ; - const EFI_SCSI_IO_STATUS_HOST_ADAPTER_OTHER =0x7f ; - + #[derive(Default)] + pub enum HostAdapterStatus: u8 => { + + /// EFI_SCSI_IO_STATUS_HOST_ADAPTER_OK + OK = 0x00, + TIMEOUT_COMMAND = 0x09, + TIMEOUT = 0x0b, + MESSAGE_REJECT = 0x0d, + BUS_RESET = 0x0e, + PARITY_ERROR = 0x0f, + REQUEST_SENSE_FAILED = 0x10, + SELECTION_TIMEOUT = 0x11, + DATA_OVERRUN_UNDERRUN = 0x12, + BUS_FREE = 0x13, + PHASE_ERROR = 0x14, + OTHER = 0x7f, } } -bitflags! { +newtype_enum! { /// TargetStatus - #[repr(transparent)] - #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] - pub struct TargetStatus: u8 { - const EFI_SCSI_IO_STATUS_TARGET_GOOD =0x00; - const EFI_SCSI_IO_STATUS_TARGET_CHECK_CONDITION =0x02; - const EFI_SCSI_IO_STATUS_TARGET_CONDITION_MET =0x04; - const EFI_SCSI_IO_STATUS_TARGET_BUSY =0x08; - const EFI_SCSI_IO_STATUS_TARGET_INTERMEDIATE =0x10; - const EFI_SCSI_IO_STATUS_TARGET_INTERMEDIATE_CONDITION_METn =0x14; - const EFI_SCSI_IO_STATUS_TARGET_RESERVATION_CONFLICT =0x18; - const EFI_SCSI_IO_STATUS_TARGET_COMMAND_TERMINATED =0x22; - const EFI_SCSI_IO_STATUS_TARGET_QUEUE_FULL =0x28; + #[derive(Default)] + pub enum TargetStatus: u8 => { + /// EFI_SCSI_IO_STATUS_TARGET_GOOD + GOOD = 0x00, + CHECK_CONDITION = 0x02, + CONDITION_MET = 0x04, + BUSY = 0x08, + INTERMEDIATE = 0x10, + INTERMEDIATE_CONDITION_MET = 0x14, + RESERVATION_CONFLICT = 0x18, + COMMAND_TERMINATED = 0x22, + QUEUE_FULL = 0x28, } } @@ -103,41 +105,35 @@ pub struct ScsiIoScsiRequestPacket { pub sense_data_length: u8, } -bitflags! { +newtype_enum! { /// DeviceType /// Defined in the SCSI Primary Commands standard (e.g., SPC-4) - #[repr(transparent)] - #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] - pub struct DeviceType: u8 { - const DISK = 0x00; // Disk device - const TAPE = 0x01; // Tape device - const PRINTER = 0x02;// Printer - const PROCESSOR = 0x03;// Processor - const WORM = 0x04;// Write-once read-multiple - const CDROM = 0x05;// CD or DVD device - const SCANNER = 0x06;// Scanner device - const OPTICAL = 0x07;// Optical memory device - const MEDIUMCHANGER = 0x08;// Medium Changer device - const COMMUNICATION = 0x09;// Communications device - - - const MFI_A = 0x0A; // Obsolete - const MFI_B = 0x0B; // Obsolete - const MFI_RAID = 0x0C; // Storage array controller - - const MFI_SES = 0x0D; // Enclosure services device - const MFI_RBC = 0x0E; // Simplified direct-access - - - const MFI_OCRW = 0x0F; // Optical card reader/ - - const MFI_BRIDGE = 0x10; // Bridge Controller - - const MFI_OSD = 0x11; // Object-based Storage - - const RESERVED_LOW = 0x12; // Reserved (low) - const RESERVED_HIGH = 0x1E; // Reserved (high) - const UNKNOWN = 0x1F; // Unknown no device type + #[derive(Default)] + pub enum DeviceType: u8 => { + DISK = 0x00, // Disk device + TAPE = 0x01, // Tape device + PRINTER = 0x02,// Printer + PROCESSOR = 0x03,// Processor + WORM = 0x04,// Write-once read-multiple + CDROM = 0x05,// CD or DVD device + SCANNER = 0x06,// Scanner device + OPTICAL = 0x07,// Optical memory device + MEDIUMCHANGER = 0x08,// Medium Changer device + COMMUNICATION = 0x09,// Communications device + + + MFI_A = 0x0A, // Obsolete + MFI_B = 0x0B, // Obsolete + MFI_RAID = 0x0C, // Storage array controller + MFI_SES = 0x0D, // Enclosure services device + MFI_RBC = 0x0E, // Simplified direct-access + MFI_OCRW = 0x0F, // Optical card reader/ + MFI_BRIDGE = 0x10, // Bridge Controller + MFI_OSD = 0x11, // Object-based Storage + + RESERVED_LOW = 0x12, // Reserved (low) + RESERVED_HIGH = 0x1E, // Reserved (high) + UNKNOWN = 0x1F, // Unknown no device type } } @@ -204,23 +200,21 @@ impl ExtScsiPassThruProtocol { pub const GUID: Guid = guid!("143b7632-b81b-4cb7-abd3-b625a5b9bffe"); } -bitflags! { +newtype_enum! { /// Attributes - /// TODO: #define TARGET_MAX_BYTES 0x10 - #[repr(transparent)] - #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] - pub struct Attributes: u32 { - const EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL = 0x0001; - const EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL = 0x0002; - const EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_NONBLOCKIO = 0x0004; + #[derive(Default)] + pub enum PassThruAttributes: u32 => { + PHYSICAL = 0x0001, + LOGICAL = 0x0002, + NONBLOCKIO = 0x0004, } } -#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] +#[derive(Clone, Copy, Default, Debug, Eq, PartialEq)] #[repr(C)] pub struct ExtScsiPassThruMode { pub adapter_id: u32, - pub attributes: Attributes, + pub attributes: PassThruAttributes, pub io_align: u32, } @@ -276,51 +270,48 @@ pub struct ExtScsiIoScsiRequestPacket { pub sense_data_length: u8, } -bitflags! { +newtype_enum! { /// Ext DataDirection - #[repr(transparent)] - #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] - pub struct ExtDataDirection: u8 { - const EFI_EXT_SCSI_DATA_DIRECTION_READ = 0; - const EFI_EXT_SCSI_DATA_DIRECTION_WRITE = 1; - const EFI_EXT_SCSI_DATA_DIRECTION_BIDIRECTIONAL = 2; + #[derive(Default)] + pub enum ExtDataDirection: u8 => { + READ = 0, + WRITE = 1, + BIDIRECTIONAL = 2, } } -bitflags! { +newtype_enum! { /// Ext HostAdapterStatus - #[repr(transparent)] - #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] - pub struct ExtHostAdapterStatus: u8 { - const EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK =0x00; - const EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND =0x09; - const EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT =0x0b; - const EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT =0x0d; - const EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET =0x0e; - const EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR =0x0f; - const EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED =0x10; - const EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT =0x11; - const EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN =0x12; - const EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE =0x13; - const EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR =0x14; - const EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER =0x7f; + #[derive(Default)] + pub enum ExtHostAdapterStatus: u8 => { + OK = 0x00, + TIMEOUT_COMMAND = 0x09, + TIMEOUT = 0x0b, + MESSAGE_REJECT = 0x0d, + BUS_RESET = 0x0e, + PARITY_ERROR = 0x0f, + REQUEST_SENSE_FAILED = 0x10, + SELECTION_TIMEOUT = 0x11, + DATA_OVERRUN_UNDERRUN = 0x12, + BUS_FREE = 0x13, + PHASE_ERROR = 0x14, + OTHER = 0x7f, } } -bitflags! { +newtype_enum! { /// ExtTargetStatus - #[repr(transparent)] - #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] - pub struct ExtTargetStatus: u8 { - const EFI_EXT_SCSI_STATUS_TARGET_GOOD = 0x00; - const EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION = 0x02; - const EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET = 0x04; - const EFI_EXT_SCSI_STATUS_TARGET_BUSY = 0x08; - const EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE = 0x10; - const EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET = 0x14; - const EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT = 0x18; - const EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL = 0x28; - const EFI_EXT_SCSI_STATUS_TARGET_ACA_ACTIVE = 0x30; - const EFI_EXT_SCSI_STATUS_TARGET_TASK_ABORTED = 0x40; + #[derive(Default)] + pub enum ExtTargetStatus: u8 => { + GOOD = 0x00, + CHECK_CONDITION = 0x02, + CONDITION_MET = 0x04, + BUSY = 0x08, + INTERMEDIATE = 0x10, + INTERMEDIATE_CONDITION_MET = 0x14, + RESERVATION_CONFLICT = 0x18, + TASK_SET_FULL = 0x28, + ACA_ACTIVE = 0x30, + TASK_ABORTED = 0x40, } } From ea3e4b1ed49f1264bc88e810abab2ee62d57a8fd Mon Sep 17 00:00:00 2001 From: sky5454 Date: Sun, 5 May 2024 09:10:56 +0800 Subject: [PATCH 08/10] [SCSI] refactor and add test. fixed ExtScsiPassThruProtocol::mode; now `execute_scsi_command` send req packet is ok. **PASSED**: - SCSI_IO all api, SCSI_THRU `mode()` and `reset()` api, are test passed. **PROBLEM**: 1. panic at allocator.rs while test_scsi_io return; 2. still problem with `DevicePath`,`target_id`,`pass_thru`; **UNKNOWN**: - scsi req ok but resp without test at `execute_scsi_command()`. --- uefi-raw/src/protocol/scsi.rs | 7 +- uefi-test-runner/examples/scsi.rs | 199 +++++++++++++++++++++ uefi/src/proto/scsi.rs | 288 ++++++++++++++++++++++++++---- 3 files changed, 457 insertions(+), 37 deletions(-) create mode 100644 uefi-test-runner/examples/scsi.rs diff --git a/uefi-raw/src/protocol/scsi.rs b/uefi-raw/src/protocol/scsi.rs index fe8bbee41..8d3aad99e 100644 --- a/uefi-raw/src/protocol/scsi.rs +++ b/uefi-raw/src/protocol/scsi.rs @@ -1,13 +1,12 @@ use core::ffi::c_void; -use crate::{Event, guid, Guid, Status}; use crate::protocol::device_path::DevicePathProtocol; +use crate::{guid, Event, Guid, Status}; /// TODO: use #define TARGET_MAX_BYTES 0x10, the limit of target. #[allow(unused)] const TARGET_MAX_BYTES: u32 = 0x10; - newtype_enum! { /// DataDirection #[derive(Default)] @@ -57,7 +56,7 @@ newtype_enum! { } /// EFI_SCSI_IO_SCSI_REQUEST_PACKET -#[derive(Debug)] +#[derive(Debug, Copy, Clone)] #[repr(C)] pub struct ScsiIoScsiRequestPacket { /// Timeout: The timeout, in 100 ns units, to use for the execution of this SCSI Request Packet. @@ -166,7 +165,7 @@ impl ScsiIoProtocol { #[derive(Debug)] #[repr(C)] pub struct ExtScsiPassThruProtocol { - pub mode: ExtScsiPassThruMode, + pub mode: *mut ExtScsiPassThruMode, pub pass_thru: unsafe extern "efiapi" fn( this: *const Self, target: *mut u8, diff --git a/uefi-test-runner/examples/scsi.rs b/uefi-test-runner/examples/scsi.rs new file mode 100644 index 000000000..a766fdb4a --- /dev/null +++ b/uefi-test-runner/examples/scsi.rs @@ -0,0 +1,199 @@ +// ANCHOR: all +// ANCHOR: features +#![no_main] +#![no_std] +// ANCHOR_END: features + +extern crate alloc; + +use alloc::vec; +use alloc::vec::Vec; + +use log::info; + +// ANCHOR: use +use uefi::prelude::*; +use uefi::proto::scsi::{ + ExtScsiPassThru, ScsiDeviceLocation, ScsiExtRequestPacket, ScsiIo, + ScsiRequestPacket, +}; + +// ANCHOR_END: use + +// ANCHOR: entry +#[entry] +fn main(image_handle: Handle, mut system_table: SystemTable) -> Status { + // ANCHOR_END: entry + // ANCHOR: services + uefi::helpers::init(&mut system_table).unwrap(); + let boot_services = system_table.boot_services(); + // ANCHOR_END: services + + // ANCHOR: params + /// all api OK, but memory panic when return, maybe the vec. + test_scsi_io(boot_services); + // test_ext_scsi_thru(boot_services); + // ANCHOR_END: params + + // ANCHOR: stall + boot_services.stall(10_000_000); + // ANCHOR_END: stall + + // ANCHOR: return + Status::SUCCESS +} +// ANCHOR_END: return + +pub fn test_scsi_io(bt: &BootServices) { + info!("Running loaded Scsi protocol test"); + + let handle = bt + .get_handle_for_protocol::() + .expect("Failed to get handles for `ScsiIo` protocol"); + + let mut scsi_protocol = bt + .open_protocol_exclusive::(handle) + .expect("Founded ScsiIo Protocol but open failed"); + + // value efi_reset_fn is the type of ResetSystemFn, a function pointer + + let result = scsi_protocol.get_device_type(); + info!("SCSI_IO Protocol get device_type: {:?}", result); + + let result = scsi_protocol.io_align(); + info!("SCSI_IO Protocol's io_align: {:?}", result); + + let result = scsi_protocol.get_device_location(); + info!("SCSI_IO Protocol get dev location: {:?}", result); + + let result = scsi_protocol.reset_bus(); + info!("SCSI_IO Protocol reset bus test: {:?}", result); + + let result = scsi_protocol.reset_device(); + info!("SCSI_IO Protocol reset dev test: {:?}", result); + + bt.stall(10_000); + // let mut data_buffer = vec![0; 40]; + // let scsicmd = commands::TestUnitReady::new(); + // scsicmd.push_to_buffer(&mut data_buffer).expect("TODO: panic message"); + // info!("the data buf = {:?}", data_buffer); + + let mut packet: ScsiRequestPacket = ScsiRequestPacket::default(); + packet.is_a_write_packet = false; + packet.cdb = vec![0x00, 0, 0, 0, 0, 0x00]; + packet.timeout = 0; + info!("packet: {:?}", packet); + let result = scsi_protocol.execute_scsi_command(&mut packet, None); + info!("=================SCSI_IO Protocol exec scsi command [TestUnitReady] test: {:?}", result); + + let mut packet: ScsiRequestPacket = ScsiRequestPacket::default(); + packet.is_a_write_packet = false; + packet.cdb = vec![0x12, 0x01, 0x00, 0, 0, 0x00]; + packet.data_buffer = vec![0; 96]; + packet.sense_data = vec![0; 18]; + packet.timeout = 0; + let result = scsi_protocol.execute_scsi_command(&mut packet, None); + info!("=================SCSI_IO Protocol exec scsi command [InquiryCommand] test: {:?}", result); + + // now send Req is ok. but seem couldn't receive Resp. +} + +/* +// The InquiryCommand + + +// sense_data with UINT8*18 +/// +/// Error codes 70h and 71h sense data format +/// +typedef struct { +UINT8 Error_Code : 7; +UINT8 Valid : 1; +UINT8 Segment_Number; +UINT8 Sense_Key : 4; +UINT8 Reserved_21 : 1; +UINT8 Ili : 1; +UINT8 Reserved_22 : 2; +UINT8 Information_3_6[4]; +UINT8 Addnl_Sense_Length; ///< Additional sense length (n-7) +UINT8 Vendor_Specific_8_11[4]; +UINT8 Addnl_Sense_Code; ///< Additional sense code +UINT8 Addnl_Sense_Code_Qualifier; ///< Additional sense code qualifier +UINT8 Field_Replaceable_Unit_Code; ///< Field replaceable unit code +UINT8 Reserved_15_17[3]; +} EFI_SCSI_SENSE_DATA; + + + +// in_data_buf with UINT8 * 96 +typedef struct { + UINT8 Peripheral_Type : 5; + UINT8 Peripheral_Qualifier : 3; + UINT8 DeviceType_Modifier : 7; + UINT8 Rmb : 1; + UINT8 Version; + UINT8 Response_Data_Format; + UINT8 Addnl_Length; + UINT8 Reserved_5_95[95 - 5 + 1]; +} EFI_SCSI_INQUIRY_DATA; +*/ + +pub fn test_ext_scsi_thru(bt: &BootServices) { + info!("Running loaded Ext Scsi Thru protocol test"); + + let handle = bt + .get_handle_for_protocol::() + .expect("Failed to get handles for `ExtScsiThru` protocol"); + + let mut escsi_protocol = bt + .open_protocol_exclusive::(handle) + .expect("Founded ExtScsiThru Protocol but open failed"); + + // value efi_reset_fn is the type of ResetSystemFn, a function pointer + + let result = escsi_protocol.mode(); + info!("EXT_SCSI_THRU Protocol's mode: {:?}", result); + + let mut targets: Vec = vec![0xFF; 10]; + let target = ScsiDeviceLocation::new(&mut targets[0], 0); + let result = escsi_protocol.build_device_path(target); + info!("EXT_SCSI_THRU Protocol build_device_path: {:?}", result); + + // let device_path = result.expect("couldn't got the dev path"); + // // DevicePath has DevicePathFromText ffi + // let result = escsi_protocol.get_target_lun(&*device_path); + // info!("EXT_SCSI_THRU Protocol build_device_path: {:?}", result); + + // let location = result.unwrap().clone(); + + let location = target; + + let result = escsi_protocol.get_next_target(); + info!("EXT_SCSI_THRU Protocol get_next_target: {:?}", result); + + // let result = escsi_protocol.reset_target_lun(location.clone()); + // info!("EXT_SCSI_THRU Protocol reset dev test: {:?}", result); + + let result = escsi_protocol.reset_channel(); + info!("EXT_SCSI_THRU Protocol reset bus test: {:?}", result); + + bt.stall(10_000); + + let mut ext_packet = ScsiExtRequestPacket::default(); + ext_packet.is_a_write_packet = false; + ext_packet.cdb = vec![0x00, 0, 0, 0, 0, 0x00]; + ext_packet.timeout = 0; + let result = escsi_protocol.pass_thru(location.clone(), ext_packet, None); + info!("=================EXT_SCSI_THRU Protocol exec scsi command [TestUnitReady] test: {:?}", result); + + let mut ext_packet = ScsiExtRequestPacket::default(); + ext_packet.is_a_write_packet = false; + ext_packet.cdb = vec![0x12, 0x01, 0x00, 0, 0, 0x00]; + ext_packet.data_buffer = vec![0; 96]; + ext_packet.sense_data = vec![0; 18]; + ext_packet.timeout = 0; + let result = escsi_protocol.pass_thru(location.clone(), ext_packet, None); + info!("=================EXT_SCSI_THRU Protocol exec scsi command [InquiryCommand] test: {:?}", result); + + // now send Req is ok. but seem couldn't receive Resp. +} diff --git a/uefi/src/proto/scsi.rs b/uefi/src/proto/scsi.rs index 61f28a639..eebd2da15 100644 --- a/uefi/src/proto/scsi.rs +++ b/uefi/src/proto/scsi.rs @@ -1,10 +1,13 @@ //! EFI SCSI I/O protocols. +use alloc::boxed::Box; use alloc::vec::Vec; use core::ffi::c_void; +use core::ptr; use core::ptr::null_mut; -use uefi_raw::protocol::device_path::DevicePathProtocol; +use log::info; + use uefi_raw::protocol::scsi; use uefi_raw::protocol::scsi::{ DataDirection, ExtDataDirection, ExtHostAdapterStatus, ExtScsiIoScsiRequestPacket, @@ -12,9 +15,10 @@ use uefi_raw::protocol::scsi::{ ScsiIoProtocol, ScsiIoScsiRequestPacket, TargetStatus, }; -use crate::{Event, Result, StatusExt}; +use crate::proto::device_path::build::{acpi, hardware, messaging, DevicePathBuilder}; use crate::proto::device_path::DevicePath; use crate::proto::unsafe_protocol; +use crate::{Event, Result, StatusExt}; /// Protocol for who running in the EFI boot services environment such as code, typically drivers, able to access SCSI devices. #[derive(Debug)] @@ -31,6 +35,13 @@ pub struct ScsiDeviceLocation { pub lun: u64, } +impl ScsiDeviceLocation { + /// constructor for ScsiDeviceLocation {target, lun} + pub fn new(target: *mut u8, lun: u64) -> Self { + ScsiDeviceLocation { target, lun } + } +} + impl Default for ScsiDeviceLocation { fn default() -> Self { ScsiDeviceLocation { @@ -64,15 +75,25 @@ impl ScsiIo { /// Sends a SCSI Request Packet to the SCSI Device for execution. ///TODO: ScsiIoScsiRequestPacket must to refactor - pub fn execute_scsi_command(&self, packet: &mut ScsiRequestPacket, event: Event) -> Result { - unsafe { - (self.0.execute_scsi_command)( - &self.0, - &mut (packet.convert_to_request_packet()), - event.as_ptr(), - ) - } - .to_result() + pub fn execute_scsi_command( + &self, + packet: &mut ScsiRequestPacket, + event: Option, + ) -> Result { + info!("before: ffi_packet = {:?}", packet); + let in_packet = &mut (packet.convert_auto_request_packet()); + info!("before: raw_packet = {:?}", in_packet); + + let event_arg = match event { + Some(event) => event.as_ptr(), + None => ptr::null_mut(), + }; + + let status = unsafe { (self.0.execute_scsi_command)(&self.0, in_packet, event_arg) }; + info!("after: raw_packet = {:?}", in_packet); + // TODO: print log with raw dat/len about `ScsiIoScsiRequestPacket` + + status.to_result_with_val(|| packet.sync_from_request_packet(in_packet)) } /// the value of ioAlign @@ -90,22 +111,29 @@ pub struct ExtScsiPassThru(ExtScsiPassThruProtocol); impl ExtScsiPassThru { /// the value of mode which is type ExtScsiPassThruMode. pub fn mode(&self) -> Result { - Ok(self.0.mode) + unsafe { Ok(*self.0.mode) } } /// Sends a SCSI Request Packet to a SCSI device that is attached to the SCSI channel. pub fn pass_thru( &mut self, location: ScsiDeviceLocation, mut packet: ScsiExtRequestPacket, - event: Event, + event: Option, ) -> Result { + let raw_packet = &mut (packet.convert_auto_request_packet()); + info!("raw_packet = {:?}", raw_packet); + let event_arg = match event { + Some(event) => event.as_ptr(), + None => ptr::null_mut(), + }; + unsafe { (self.0.pass_thru)( &mut self.0, location.target, location.lun, - &mut (packet.convert_to_request_packet()), - event.as_ptr(), + raw_packet, + event_arg, ) } .to_result() @@ -119,21 +147,38 @@ impl ExtScsiPassThru { } /// Used to allocate and build a device path node for a SCSI device on a SCSI channel. - pub fn build_device_path(&mut self, location: ScsiDeviceLocation) -> Result<&DevicePath> { - let mut path = &mut DevicePathProtocol { - major_type: 0, - sub_type: 0, - length: [0, 0], - } as *mut DevicePathProtocol; + pub fn build_device_path(&mut self, location: ScsiDeviceLocation) -> Result> { + let mut v = Vec::new(); + let path = DevicePathBuilder::with_vec(&mut v) + .push(&acpi::Acpi { + hid: 0x41d0_0a03, + uid: 0x0000_0000, + }) + .unwrap() + .push(&hardware::Pci { + function: 0x00, + device: 0x19, + }) + .unwrap() + .push(&messaging::Scsi { + target_id: 0, + logical_unit_number: 0, + }) + .unwrap() + .finalize() + .expect("failed to build dev path"); + let mut device_path_ptr: *mut uefi_raw::protocol::device_path::DevicePathProtocol = + unsafe { *path.as_ffi_ptr().cast() }; + // let path_ptr = &mut path?; unsafe { - let status = - (self.0.build_device_path)(&mut self.0, location.target, location.lun, &mut path); - if status.is_success() { - Ok(DevicePath::from_ffi_ptr(path.cast())) - } else { - Err(status.into()) - } + (self.0.build_device_path)( + &mut self.0, + location.target, + location.lun, + &mut device_path_ptr, + ) } + .to_result_with_val(|| path.to_boxed()) } /// Used to translate a device path node to a Target ID and LUN. @@ -165,7 +210,8 @@ impl ExtScsiPassThru { /// Used to retrieve the list of legal Target IDs for SCSI devices on a SCSI channel. pub fn get_next_target(&mut self) -> Result { - let mut location = ScsiDeviceLocation::default(); + let mut id = 0; + let mut location = ScsiDeviceLocation::new(&mut id, 0); unsafe { (self.0.get_next_target)(&self.0, &mut location.target) } .to_result_with_val(|| location) } @@ -193,6 +239,73 @@ pub struct ScsiExtRequestPacket { } impl ScsiExtRequestPacket { + /// auto convert FFI `ScsiExtRequestPacket` to raw UEFI SCSI request packet `EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET` + pub fn convert_zero_request_packet(&mut self) -> ExtScsiIoScsiRequestPacket { + let packet: ExtScsiIoScsiRequestPacket = ExtScsiIoScsiRequestPacket { + timeout: self.timeout, + + in_data_buffer: null_mut(), + out_data_buffer: null_mut(), + sense_data: self.sense_data.as_mut_ptr() as *mut c_void, + cdb: self.cdb.as_mut_ptr() as *mut c_void, + + in_transfer_length: 0, + out_transfer_length: 0, + sense_data_length: self.sense_data.len() as u8, + cdb_length: self.cdb.len() as u8, + + data_direction: self.data_direction, + host_adapter_status: self.host_adapter_status, + target_status: self.target_status, + }; + packet + } + + /// convert auto + pub fn convert_auto_request_packet(&mut self) -> ExtScsiIoScsiRequestPacket { + ExtScsiIoScsiRequestPacket { + timeout: 0, + + in_data_buffer: if (self.data_buffer.len() != 0) && !self.is_a_write_packet { + self.data_buffer.as_mut_ptr().cast::() + } else { + null_mut() + }, + out_data_buffer: if self.data_buffer.len() != 0 && self.is_a_write_packet { + self.data_buffer.as_mut_ptr().cast::() + } else { + null_mut() + }, + + sense_data: if self.sense_data.len() != 0 { + self.sense_data.as_mut_ptr().cast::() + } else { + null_mut() + }, + cdb: if self.cdb.len() != 0 { + self.cdb.as_mut_ptr().cast::() + } else { + null_mut() + }, + + in_transfer_length: if !self.is_a_write_packet { + self.data_buffer.len() as u32 + } else { + 0 + }, + out_transfer_length: if self.is_a_write_packet { + self.data_buffer.len() as u32 + } else { + 0 + }, + cdb_length: self.cdb.len() as u8, + sense_data_length: self.sense_data.len() as u8, + + data_direction: Default::default(), + host_adapter_status: Default::default(), + target_status: Default::default(), + } + } /// convert FFI `ScsiExtRequestPacket` to raw UEFI SCSI request packet `EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET` pub fn convert_to_request_packet(&mut self) -> ExtScsiIoScsiRequestPacket { if self.is_a_write_packet { @@ -248,24 +361,92 @@ impl ScsiExtRequestPacket { #[derive(Debug, Default, Clone)] pub struct ScsiRequestPacket { /// whether the request is written scsi - is_a_write_packet: bool, + pub is_a_write_packet: bool, /// timeout pub timeout: u64, /// data_buffer is `in_data_buffer` or `out_data_buffer` pub data_buffer: Vec, /// SCSI's cdb, refer to T10 SPC pub cdb: Vec, - /// SCSI's sense data, refer to T10 SPC + /// SCSI's sense data, refer to T10 SPC, scsi resp return it pub sense_data: Vec, /// uefi_raw::protocol::scsi::DataDirection pub data_direction: DataDirection, - /// uefi_raw::protocol::scsi::HostAdapterStatus + /// uefi_raw::protocol::scsi::HostAdapterStatus, scsi resp status pub host_adapter_status: HostAdapterStatus, - /// uefi_raw::protocol::scsi::TargetStatus + /// uefi_raw::protocol::scsi::TargetStatus, scsi resp status pub target_status: TargetStatus, } impl ScsiRequestPacket { + /// convert FFI `ScsiRequestPacket` to raw UEFI SCSI request packet `EFI_SCSI_IO_SCSI_REQUEST_PACKET` + pub fn convert_zero_request_packet(&mut self) -> ScsiIoScsiRequestPacket { + let packet: ScsiIoScsiRequestPacket = ScsiIoScsiRequestPacket { + timeout: self.timeout, + + in_data_buffer: null_mut(), + out_data_buffer: null_mut(), + sense_data: null_mut(), + cdb: self.cdb.as_mut_ptr() as *mut c_void, + + in_transfer_length: 0, + out_transfer_length: 0, + sense_data_length: 0, + cdb_length: self.cdb.len() as u8, + + data_direction: self.data_direction, + host_adapter_status: self.host_adapter_status, + target_status: self.target_status, + }; + packet + } + // auto convert + /// convert auto + pub fn convert_auto_request_packet(&mut self) -> ScsiIoScsiRequestPacket { + ScsiIoScsiRequestPacket { + timeout: 0, + + in_data_buffer: if (self.data_buffer.len() != 0) && !self.is_a_write_packet { + self.data_buffer.as_mut_ptr().cast::() + } else { + null_mut() + }, + out_data_buffer: if self.data_buffer.len() != 0 && self.is_a_write_packet { + self.data_buffer.as_mut_ptr().cast::() + } else { + null_mut() + }, + + sense_data: if self.sense_data.len() != 0 { + self.sense_data.as_mut_ptr().cast::() + } else { + null_mut() + }, + cdb: if self.cdb.len() != 0 { + self.cdb.as_mut_ptr().cast::() + } else { + null_mut() + }, + + in_transfer_length: if !self.is_a_write_packet { + self.data_buffer.len() as u32 + } else { + 0 + }, + out_transfer_length: if self.is_a_write_packet { + self.data_buffer.len() as u32 + } else { + 0 + }, + cdb_length: self.cdb.len() as u8, + sense_data_length: self.sense_data.len() as u8, + + data_direction: Default::default(), + host_adapter_status: Default::default(), + target_status: Default::default(), + } + } + /// convert FFI `ScsiRequestPacket` to raw UEFI SCSI request packet `EFI_SCSI_IO_SCSI_REQUEST_PACKET` pub fn convert_to_request_packet(&mut self) -> ScsiIoScsiRequestPacket { if self.is_a_write_packet { @@ -274,6 +455,47 @@ impl ScsiRequestPacket { self._convert_to_read_request_packet() } } + + /// `ScsiRequestPacket` FFI sync from raw_packet `ScsiIoScsiRequestPacket` by ptr. + pub fn sync_from_request_packet( + &mut self, + raw_packet: &mut ScsiIoScsiRequestPacket, + ) -> ScsiRequestPacket { + unsafe { + self.timeout = raw_packet.timeout; + // c (void* data, int len) => rust Vec + + self.cdb = Vec::from_raw_parts( + raw_packet.cdb as *mut u8, + raw_packet.cdb_length as usize, + isize::MAX as usize, + ); + self.sense_data = Vec::from_raw_parts( + raw_packet.sense_data as *mut u8, + raw_packet.sense_data_length as usize, + isize::MAX as usize, + ); + self.data_buffer = if self.is_a_write_packet { + Vec::from_raw_parts( + raw_packet.in_data_buffer as *mut u8, + raw_packet.in_transfer_length as usize, + isize::MAX as usize, + ) + } else { + Vec::from_raw_parts( + raw_packet.out_data_buffer as *mut u8, + raw_packet.out_transfer_length as usize, + isize::MAX as usize, + ) + }; + + self.data_direction = raw_packet.data_direction; + self.host_adapter_status = raw_packet.host_adapter_status; + self.target_status = raw_packet.target_status; + } + self.clone() + } + fn _convert_to_read_request_packet(&mut self) -> ScsiIoScsiRequestPacket { let packet: ScsiIoScsiRequestPacket = ScsiIoScsiRequestPacket { timeout: self.timeout, From c9777f34abdece813f8a5c77cce861597e29bf9a Mon Sep 17 00:00:00 2001 From: sky5454 Date: Sat, 11 May 2024 11:03:25 +0800 Subject: [PATCH 09/10] [scsi_io] add supported for `EFI SCSI I/O Protocol`. --- uefi-raw/CHANGELOG.md | 4 + uefi-raw/src/protocol/scsi.rs | 156 ------------------ uefi-test-runner/examples/scsi.rs | 113 +++---------- uefi/CHANGELOG.md | 4 + uefi/src/proto/scsi.rs | 265 +----------------------------- 5 files changed, 36 insertions(+), 506 deletions(-) diff --git a/uefi-raw/CHANGELOG.md b/uefi-raw/CHANGELOG.md index 15a8d793f..7dd2014d3 100644 --- a/uefi-raw/CHANGELOG.md +++ b/uefi-raw/CHANGELOG.md @@ -1,5 +1,9 @@ # uefi-raw - [Unreleased] +## Added + +- Added `ScsiIoProtocol`. + ## Changed - `maximum_capsule_size` of `query_capsule_capabilities` now takes a *mut u64 instead of a *mut usize. diff --git a/uefi-raw/src/protocol/scsi.rs b/uefi-raw/src/protocol/scsi.rs index 8d3aad99e..c90ba6b3c 100644 --- a/uefi-raw/src/protocol/scsi.rs +++ b/uefi-raw/src/protocol/scsi.rs @@ -1,6 +1,5 @@ use core::ffi::c_void; -use crate::protocol::device_path::DevicePathProtocol; use crate::{guid, Event, Guid, Status}; /// TODO: use #define TARGET_MAX_BYTES 0x10, the limit of target. @@ -159,158 +158,3 @@ pub struct ScsiIoProtocol { impl ScsiIoProtocol { pub const GUID: Guid = guid!("932f47e6-2362-4002-803e-3cd54b138f85"); } - -// TODO: see device_path.rs, then see 15.5. SCSI Device Paths and 15.6. SCSI Pass Thru Device Paths - -#[derive(Debug)] -#[repr(C)] -pub struct ExtScsiPassThruProtocol { - pub mode: *mut ExtScsiPassThruMode, - pub pass_thru: unsafe extern "efiapi" fn( - this: *const Self, - target: *mut u8, - lun: u64, - packet: *mut ExtScsiIoScsiRequestPacket, - event: Event, - ) -> Status, - pub get_next_target_lun: - unsafe extern "efiapi" fn(this: *const Self, target: *mut *mut u8, lun: *mut u64) -> Status, - pub build_device_path: unsafe extern "efiapi" fn( - this: *mut Self, - target: *mut u8, - lun: u64, - device_path: *mut *mut DevicePathProtocol, - ) -> Status, - pub get_target_lun: unsafe extern "efiapi" fn( - this: *const Self, - device_path: *const DevicePathProtocol, - target: *mut *mut u8, - lun: *mut u64, - ) -> Status, - - pub reset_channel: unsafe extern "efiapi" fn(this: *mut Self) -> Status, - pub reset_target_lun: - unsafe extern "efiapi" fn(this: *mut Self, target: *mut u8, lun: u64) -> Status, - pub get_next_target: - unsafe extern "efiapi" fn(this: *const Self, target: *mut *mut u8) -> Status, -} -/// 15.7. Extended SCSI Pass Thru Protocol -impl ExtScsiPassThruProtocol { - pub const GUID: Guid = guid!("143b7632-b81b-4cb7-abd3-b625a5b9bffe"); -} - -newtype_enum! { - /// Attributes - #[derive(Default)] - pub enum PassThruAttributes: u32 => { - PHYSICAL = 0x0001, - LOGICAL = 0x0002, - NONBLOCKIO = 0x0004, - } -} - -#[derive(Clone, Copy, Default, Debug, Eq, PartialEq)] -#[repr(C)] -pub struct ExtScsiPassThruMode { - pub adapter_id: u32, - pub attributes: PassThruAttributes, - pub io_align: u32, -} - -/// EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET -#[derive(Debug)] -#[repr(C)] -pub struct ExtScsiIoScsiRequestPacket { - /// Timeout: The timeout, in 100 ns units, to use for the execution of this SCSI Request Packet. - /// A Timeout value of 0 means that this function will wait indefinitely for the SCSI Request Packet to execute. - /// If Timeout is greater than zero, then this function will return EFI_TIMEOUT if the time required to execute the SCSI Request Packet is greater than Timeout . - pub timeout: u64, - - /// InDataBuffer: A pointer to the data buffer to transfer between the SCSI controller and the SCSI device for read and bidirectional commands. - /// For all write and non data commands where InTransferLength is 0 this field is optional and may be NULL . - /// If this field is not NULL , then it must be aligned on the boundary specified by the IoAlign field in the EFI_EXT_SCSI_PASS_THRU_MODE structure. - pub in_data_buffer: *mut c_void, - /// OutDataBuffer: A pointer to the data buffer to transfer between the SCSI controller and the SCSI device for write or bidirectional commands. - /// For all read and non data commands where OutTransferLength is 0 this field is optional and may be NULL . - /// If this field is not NULL , then it must be aligned on the boundary specified by the IoAlign field in the EFI_EXT_SCSI_PASS_THRU_MODE structure. - pub out_data_buffer: *mut c_void, - /// SenseData: A pointer to the sense data that was generated by the execution of the SCSI Request Packet. - /// If SenseDataLength is 0, then this field is optional and may be NULL . - /// It is strongly recommended that a sense data buffer of at least 252 bytes be provided to guarantee the entire sense data buffer - /// generated from the execution of the SCSI Request Packet can be returned. - /// If this field is not NULL , then it must be aligned to the boundary specified in the IoAlign field in the EFI_EXT_SCSI_PASS_THRU_MODE structure. - pub sense_data: *mut c_void, - /// Cdb: A pointer to buffer that contains the Command Data Block to send to the SCSI device specified by Target and Lun . - pub cdb: *mut c_void, - - /// InTransferLength: On Input, the size, in bytes, of InDataBuffer . - /// On output, the number of bytes transferred between the SCSI controller and the SCSI device. - /// If InTransferLength is larger than the SCSI controller can handle, no data will be transferred, - /// InTransferLength will be updated to contain the number of bytes that the SCSI controller is able to transfer, and EFI_BAD_BUFFER_SIZE will be returned. - pub in_transfer_length: u32, - /// OutTransferLength: On Input, the size, in bytes of OutDataBuffer . On Output, the Number of bytes transferred between SCSI Controller and the SCSI device. - /// If OutTransferLength is larger than the SCSI controller can handle, no data will be transferred, - /// OutTransferLength will be updated to contain the number of bytes that the SCSI controller is able to transfer, - /// and EFI_BAD_BUFFER_SIZE will be returned. - pub out_transfer_length: u32, - - /// CdbLength: The length, in bytes, of the buffer Cdb . The standard values are 6, 10, 12, and 16, but other values are possible if a variable length CDB is used. - pub cdb_length: u8, - /// DataDirection: The direction of the data transfer. 0 for reads, 1 for writes. A value of 2 is Reserved for Bi-Directional SCSI commands. - /// For example XDREADWRITE. All other values are reserved, and must not be used. - pub data_direction: ExtDataDirection, - /// HostAdapterStatus: The status of the host adapter specified by This when the SCSI Request Packet was executed on the target device. - /// If bit 7 of this field is set, then HostAdapterStatus is a vendor defined error code. - pub host_adapter_status: ExtHostAdapterStatus, - /// TargetStatus: The status returned by the device specified by Target and Lun when the SCSI Request Packet was executed. - pub target_status: ExtTargetStatus, - /// SenseDataLength: On input, the length in bytes of the SenseData buffer. - /// On output, the number of bytes written to the SenseData buffer. - pub sense_data_length: u8, -} - -newtype_enum! { - /// Ext DataDirection - #[derive(Default)] - pub enum ExtDataDirection: u8 => { - READ = 0, - WRITE = 1, - BIDIRECTIONAL = 2, - } -} - -newtype_enum! { - /// Ext HostAdapterStatus - #[derive(Default)] - pub enum ExtHostAdapterStatus: u8 => { - OK = 0x00, - TIMEOUT_COMMAND = 0x09, - TIMEOUT = 0x0b, - MESSAGE_REJECT = 0x0d, - BUS_RESET = 0x0e, - PARITY_ERROR = 0x0f, - REQUEST_SENSE_FAILED = 0x10, - SELECTION_TIMEOUT = 0x11, - DATA_OVERRUN_UNDERRUN = 0x12, - BUS_FREE = 0x13, - PHASE_ERROR = 0x14, - OTHER = 0x7f, - } -} - -newtype_enum! { - /// ExtTargetStatus - #[derive(Default)] - pub enum ExtTargetStatus: u8 => { - GOOD = 0x00, - CHECK_CONDITION = 0x02, - CONDITION_MET = 0x04, - BUSY = 0x08, - INTERMEDIATE = 0x10, - INTERMEDIATE_CONDITION_MET = 0x14, - RESERVATION_CONFLICT = 0x18, - TASK_SET_FULL = 0x28, - ACA_ACTIVE = 0x30, - TASK_ABORTED = 0x40, - } -} diff --git a/uefi-test-runner/examples/scsi.rs b/uefi-test-runner/examples/scsi.rs index a766fdb4a..9ee1357a0 100644 --- a/uefi-test-runner/examples/scsi.rs +++ b/uefi-test-runner/examples/scsi.rs @@ -7,16 +7,13 @@ extern crate alloc; use alloc::vec; -use alloc::vec::Vec; +use core::mem; use log::info; // ANCHOR: use use uefi::prelude::*; -use uefi::proto::scsi::{ - ExtScsiPassThru, ScsiDeviceLocation, ScsiExtRequestPacket, ScsiIo, - ScsiRequestPacket, -}; +use uefi::proto::scsi::{ScsiIo, ScsiRequestPacket}; // ANCHOR_END: use @@ -29,11 +26,10 @@ fn main(image_handle: Handle, mut system_table: SystemTable) -> Status { let boot_services = system_table.boot_services(); // ANCHOR_END: services - // ANCHOR: params - /// all api OK, but memory panic when return, maybe the vec. + // ANCHOR: params, all api OK, but memory panic when return, maybe the vec. test_scsi_io(boot_services); - // test_ext_scsi_thru(boot_services); - // ANCHOR_END: params + // ANCHOR_END: params, panic at uefi/src/allocator.rs#L130 (*boot_services()).free_pool(ptr).unwrap(); + // ANCHOR: stall boot_services.stall(10_000_000); @@ -73,29 +69,30 @@ pub fn test_scsi_io(bt: &BootServices) { info!("SCSI_IO Protocol reset dev test: {:?}", result); bt.stall(10_000); - // let mut data_buffer = vec![0; 40]; - // let scsicmd = commands::TestUnitReady::new(); - // scsicmd.push_to_buffer(&mut data_buffer).expect("TODO: panic message"); - // info!("the data buf = {:?}", data_buffer); - - let mut packet: ScsiRequestPacket = ScsiRequestPacket::default(); - packet.is_a_write_packet = false; - packet.cdb = vec![0x00, 0, 0, 0, 0, 0x00]; - packet.timeout = 0; - info!("packet: {:?}", packet); - let result = scsi_protocol.execute_scsi_command(&mut packet, None); + + let mut packet_tur: ScsiRequestPacket = ScsiRequestPacket::default(); + packet_tur.is_a_write_packet = false; + packet_tur.cdb = vec![0x00, 0, 0, 0, 0, 0x00]; + packet_tur.timeout = 0; + info!("packet_tur: {:?}", packet_tur); + mem::forget(packet_tur.cdb.as_mut_ptr()); + let result = scsi_protocol.execute_scsi_command(&mut packet_tur, None); info!("=================SCSI_IO Protocol exec scsi command [TestUnitReady] test: {:?}", result); - let mut packet: ScsiRequestPacket = ScsiRequestPacket::default(); - packet.is_a_write_packet = false; - packet.cdb = vec![0x12, 0x01, 0x00, 0, 0, 0x00]; - packet.data_buffer = vec![0; 96]; - packet.sense_data = vec![0; 18]; - packet.timeout = 0; - let result = scsi_protocol.execute_scsi_command(&mut packet, None); + let mut packet_icmd: ScsiRequestPacket = ScsiRequestPacket::default(); + packet_icmd.is_a_write_packet = false; + packet_icmd.cdb = vec![0x12, 0x01, 0x00, 0, 0, 0x00]; + packet_icmd.data_buffer = vec![0; 96]; + packet_icmd.sense_data = vec![0; 18]; + packet_icmd.timeout = 0; + mem::forget(packet_icmd.cdb.as_mut_ptr()); + mem::forget(packet_icmd.data_buffer.as_mut_ptr()); + mem::forget(packet_icmd.sense_data.as_mut_ptr()); + let result = scsi_protocol.execute_scsi_command(&mut packet_icmd, None); info!("=================SCSI_IO Protocol exec scsi command [InquiryCommand] test: {:?}", result); - // now send Req is ok. but seem couldn't receive Resp. + // drop(packet) + // now send Req is ok. but it seems couldn't receive Resp. } /* @@ -137,63 +134,3 @@ typedef struct { UINT8 Reserved_5_95[95 - 5 + 1]; } EFI_SCSI_INQUIRY_DATA; */ - -pub fn test_ext_scsi_thru(bt: &BootServices) { - info!("Running loaded Ext Scsi Thru protocol test"); - - let handle = bt - .get_handle_for_protocol::() - .expect("Failed to get handles for `ExtScsiThru` protocol"); - - let mut escsi_protocol = bt - .open_protocol_exclusive::(handle) - .expect("Founded ExtScsiThru Protocol but open failed"); - - // value efi_reset_fn is the type of ResetSystemFn, a function pointer - - let result = escsi_protocol.mode(); - info!("EXT_SCSI_THRU Protocol's mode: {:?}", result); - - let mut targets: Vec = vec![0xFF; 10]; - let target = ScsiDeviceLocation::new(&mut targets[0], 0); - let result = escsi_protocol.build_device_path(target); - info!("EXT_SCSI_THRU Protocol build_device_path: {:?}", result); - - // let device_path = result.expect("couldn't got the dev path"); - // // DevicePath has DevicePathFromText ffi - // let result = escsi_protocol.get_target_lun(&*device_path); - // info!("EXT_SCSI_THRU Protocol build_device_path: {:?}", result); - - // let location = result.unwrap().clone(); - - let location = target; - - let result = escsi_protocol.get_next_target(); - info!("EXT_SCSI_THRU Protocol get_next_target: {:?}", result); - - // let result = escsi_protocol.reset_target_lun(location.clone()); - // info!("EXT_SCSI_THRU Protocol reset dev test: {:?}", result); - - let result = escsi_protocol.reset_channel(); - info!("EXT_SCSI_THRU Protocol reset bus test: {:?}", result); - - bt.stall(10_000); - - let mut ext_packet = ScsiExtRequestPacket::default(); - ext_packet.is_a_write_packet = false; - ext_packet.cdb = vec![0x00, 0, 0, 0, 0, 0x00]; - ext_packet.timeout = 0; - let result = escsi_protocol.pass_thru(location.clone(), ext_packet, None); - info!("=================EXT_SCSI_THRU Protocol exec scsi command [TestUnitReady] test: {:?}", result); - - let mut ext_packet = ScsiExtRequestPacket::default(); - ext_packet.is_a_write_packet = false; - ext_packet.cdb = vec![0x12, 0x01, 0x00, 0, 0, 0x00]; - ext_packet.data_buffer = vec![0; 96]; - ext_packet.sense_data = vec![0; 18]; - ext_packet.timeout = 0; - let result = escsi_protocol.pass_thru(location.clone(), ext_packet, None); - info!("=================EXT_SCSI_THRU Protocol exec scsi command [InquiryCommand] test: {:?}", result); - - // now send Req is ok. but seem couldn't receive Resp. -} diff --git a/uefi/CHANGELOG.md b/uefi/CHANGELOG.md index 8e7e3930e..4298bedf1 100644 --- a/uefi/CHANGELOG.md +++ b/uefi/CHANGELOG.md @@ -1,5 +1,9 @@ # uefi - [Unreleased] +## Added + +- Added `ScsiIo` Protocol. + ## Added - Added `RuntimeServices::update_capsule`. diff --git a/uefi/src/proto/scsi.rs b/uefi/src/proto/scsi.rs index eebd2da15..c53d3f440 100644 --- a/uefi/src/proto/scsi.rs +++ b/uefi/src/proto/scsi.rs @@ -1,6 +1,5 @@ //! EFI SCSI I/O protocols. -use alloc::boxed::Box; use alloc::vec::Vec; use core::ffi::c_void; use core::ptr; @@ -10,17 +9,14 @@ use log::info; use uefi_raw::protocol::scsi; use uefi_raw::protocol::scsi::{ - DataDirection, ExtDataDirection, ExtHostAdapterStatus, ExtScsiIoScsiRequestPacket, - ExtScsiPassThruMode, ExtScsiPassThruProtocol, ExtTargetStatus, HostAdapterStatus, - ScsiIoProtocol, ScsiIoScsiRequestPacket, TargetStatus, + DataDirection, HostAdapterStatus, ScsiIoProtocol, ScsiIoScsiRequestPacket, TargetStatus, }; -use crate::proto::device_path::build::{acpi, hardware, messaging, DevicePathBuilder}; -use crate::proto::device_path::DevicePath; -use crate::proto::unsafe_protocol; use crate::{Event, Result, StatusExt}; +use crate::proto::unsafe_protocol; /// Protocol for who running in the EFI boot services environment such as code, typically drivers, able to access SCSI devices. +/// see example at `uefi-test-runner/examples/scsi.rs` #[derive(Debug)] #[repr(transparent)] #[unsafe_protocol(ScsiIoProtocol::GUID)] @@ -102,261 +98,6 @@ impl ScsiIo { } } -/// Extended SCSI Pass Thru Protocol. -#[derive(Debug)] -#[repr(transparent)] -#[unsafe_protocol(ExtScsiPassThruProtocol::GUID)] -pub struct ExtScsiPassThru(ExtScsiPassThruProtocol); - -impl ExtScsiPassThru { - /// the value of mode which is type ExtScsiPassThruMode. - pub fn mode(&self) -> Result { - unsafe { Ok(*self.0.mode) } - } - /// Sends a SCSI Request Packet to a SCSI device that is attached to the SCSI channel. - pub fn pass_thru( - &mut self, - location: ScsiDeviceLocation, - mut packet: ScsiExtRequestPacket, - event: Option, - ) -> Result { - let raw_packet = &mut (packet.convert_auto_request_packet()); - info!("raw_packet = {:?}", raw_packet); - let event_arg = match event { - Some(event) => event.as_ptr(), - None => ptr::null_mut(), - }; - - unsafe { - (self.0.pass_thru)( - &mut self.0, - location.target, - location.lun, - raw_packet, - event_arg, - ) - } - .to_result() - } - - /// Used to translate a device path node to a Target ID and LUN. - pub fn get_next_target_lun(&mut self) -> Result { - let mut location = ScsiDeviceLocation::default(); - unsafe { (self.0.get_next_target_lun)(&self.0, &mut location.target, &mut location.lun) } - .to_result_with_val(|| location) - } - - /// Used to allocate and build a device path node for a SCSI device on a SCSI channel. - pub fn build_device_path(&mut self, location: ScsiDeviceLocation) -> Result> { - let mut v = Vec::new(); - let path = DevicePathBuilder::with_vec(&mut v) - .push(&acpi::Acpi { - hid: 0x41d0_0a03, - uid: 0x0000_0000, - }) - .unwrap() - .push(&hardware::Pci { - function: 0x00, - device: 0x19, - }) - .unwrap() - .push(&messaging::Scsi { - target_id: 0, - logical_unit_number: 0, - }) - .unwrap() - .finalize() - .expect("failed to build dev path"); - let mut device_path_ptr: *mut uefi_raw::protocol::device_path::DevicePathProtocol = - unsafe { *path.as_ffi_ptr().cast() }; - // let path_ptr = &mut path?; - unsafe { - (self.0.build_device_path)( - &mut self.0, - location.target, - location.lun, - &mut device_path_ptr, - ) - } - .to_result_with_val(|| path.to_boxed()) - } - - /// Used to translate a device path node to a Target ID and LUN. - pub fn get_target_lun(&mut self, device_path: &DevicePath) -> Result { - let device_path_ptr: *const uefi_raw::protocol::device_path::DevicePathProtocol = - device_path.as_ffi_ptr().cast(); - - let mut location = ScsiDeviceLocation::default(); - unsafe { - (self.0.get_target_lun)( - &self.0, - device_path_ptr, - &mut location.target, - &mut location.lun, - ) - } - .to_result_with_val(|| location) - } - - /// Resets a SCSI channel. This operation resets all the SCSI devices connected to the SCSI channel. - pub fn reset_channel(&mut self) -> Result { - unsafe { (self.0.reset_channel)(&mut self.0) }.to_result() - } - - /// Resets a SCSI logical unit that is connected to a SCSI channel. - pub fn reset_target_lun(&mut self, location: ScsiDeviceLocation) -> Result { - unsafe { (self.0.reset_target_lun)(&mut self.0, location.target, location.lun) }.to_result() - } - - /// Used to retrieve the list of legal Target IDs for SCSI devices on a SCSI channel. - pub fn get_next_target(&mut self) -> Result { - let mut id = 0; - let mut location = ScsiDeviceLocation::new(&mut id, 0); - unsafe { (self.0.get_next_target)(&self.0, &mut location.target) } - .to_result_with_val(|| location) - } -} - -/// the rust FFI for `EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET` -#[derive(Debug, Default, Clone)] -pub struct ScsiExtRequestPacket { - /// whether the request is written scsi - pub is_a_write_packet: bool, - /// timeout - pub timeout: u64, - /// data_buffer is `in_data_buffer` or `out_data_buffer` - pub data_buffer: Vec, - /// SCSI's cdb, refer to T10 SPC - pub cdb: Vec, - /// SCSI's sense data, refer to T10 SPC - pub sense_data: Vec, - /// uefi_raw::protocol::scsi::ExtDataDirection - pub data_direction: ExtDataDirection, - /// uefi_raw::protocol::scsi::ExtHostAdapterStatus - pub host_adapter_status: ExtHostAdapterStatus, - /// uefi_raw::protocol::scsi::ExtTargetStatus - pub target_status: ExtTargetStatus, -} - -impl ScsiExtRequestPacket { - /// auto convert FFI `ScsiExtRequestPacket` to raw UEFI SCSI request packet `EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET` - pub fn convert_zero_request_packet(&mut self) -> ExtScsiIoScsiRequestPacket { - let packet: ExtScsiIoScsiRequestPacket = ExtScsiIoScsiRequestPacket { - timeout: self.timeout, - - in_data_buffer: null_mut(), - out_data_buffer: null_mut(), - sense_data: self.sense_data.as_mut_ptr() as *mut c_void, - cdb: self.cdb.as_mut_ptr() as *mut c_void, - - in_transfer_length: 0, - out_transfer_length: 0, - sense_data_length: self.sense_data.len() as u8, - cdb_length: self.cdb.len() as u8, - - data_direction: self.data_direction, - host_adapter_status: self.host_adapter_status, - target_status: self.target_status, - }; - packet - } - - /// convert auto - pub fn convert_auto_request_packet(&mut self) -> ExtScsiIoScsiRequestPacket { - ExtScsiIoScsiRequestPacket { - timeout: 0, - - in_data_buffer: if (self.data_buffer.len() != 0) && !self.is_a_write_packet { - self.data_buffer.as_mut_ptr().cast::() - } else { - null_mut() - }, - out_data_buffer: if self.data_buffer.len() != 0 && self.is_a_write_packet { - self.data_buffer.as_mut_ptr().cast::() - } else { - null_mut() - }, - - sense_data: if self.sense_data.len() != 0 { - self.sense_data.as_mut_ptr().cast::() - } else { - null_mut() - }, - cdb: if self.cdb.len() != 0 { - self.cdb.as_mut_ptr().cast::() - } else { - null_mut() - }, - - in_transfer_length: if !self.is_a_write_packet { - self.data_buffer.len() as u32 - } else { - 0 - }, - out_transfer_length: if self.is_a_write_packet { - self.data_buffer.len() as u32 - } else { - 0 - }, - cdb_length: self.cdb.len() as u8, - sense_data_length: self.sense_data.len() as u8, - - data_direction: Default::default(), - host_adapter_status: Default::default(), - target_status: Default::default(), - } - } - /// convert FFI `ScsiExtRequestPacket` to raw UEFI SCSI request packet `EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET` - pub fn convert_to_request_packet(&mut self) -> ExtScsiIoScsiRequestPacket { - if self.is_a_write_packet { - self._convert_to_write_request_packet() - } else { - self._convert_to_read_request_packet() - } - } - fn _convert_to_read_request_packet(&mut self) -> ExtScsiIoScsiRequestPacket { - let packet: ExtScsiIoScsiRequestPacket = ExtScsiIoScsiRequestPacket { - timeout: self.timeout, - - in_data_buffer: self.data_buffer.as_mut_ptr() as *mut c_void, - out_data_buffer: null_mut(), - sense_data: self.sense_data.as_mut_ptr() as *mut c_void, - cdb: self.cdb.as_mut_ptr() as *mut c_void, - - in_transfer_length: self.data_buffer.len() as u32, - out_transfer_length: 0, - sense_data_length: self.sense_data.len() as u8, - cdb_length: self.cdb.len() as u8, - - data_direction: self.data_direction, - host_adapter_status: self.host_adapter_status, - target_status: self.target_status, - }; - packet - } - - fn _convert_to_write_request_packet(&mut self) -> ExtScsiIoScsiRequestPacket { - let packet: ExtScsiIoScsiRequestPacket = ExtScsiIoScsiRequestPacket { - timeout: self.timeout, - - in_data_buffer: null_mut(), - out_data_buffer: self.data_buffer.as_mut_ptr() as *mut c_void, - sense_data: self.sense_data.as_mut_ptr() as *mut c_void, - cdb: self.cdb.as_mut_ptr() as *mut c_void, - - in_transfer_length: 0, - out_transfer_length: self.data_buffer.len() as u32, - sense_data_length: self.sense_data.len() as u8, - cdb_length: self.cdb.len() as u8, - - data_direction: self.data_direction, - host_adapter_status: self.host_adapter_status, - target_status: self.target_status, - }; - packet - } -} - /// the rust FFI for `EFI_SCSI_IO_SCSI_REQUEST_PACKET` #[derive(Debug, Default, Clone)] pub struct ScsiRequestPacket { From d443ac8a31a85db5477a76bec52df560c003e017 Mon Sep 17 00:00:00 2001 From: sky5454 Date: Sat, 11 May 2024 11:03:25 +0800 Subject: [PATCH 10/10] [scsi_io] add supported for `EFI SCSI I/O Protocol`. --- uefi-raw/CHANGELOG.md | 4 + uefi-raw/src/protocol/scsi.rs | 156 ------------------ uefi-test-runner/examples/scsi.rs | 109 +++--------- uefi/CHANGELOG.md | 4 + uefi/src/proto/scsi.rs | 265 +----------------------------- 5 files changed, 32 insertions(+), 506 deletions(-) diff --git a/uefi-raw/CHANGELOG.md b/uefi-raw/CHANGELOG.md index 15a8d793f..7dd2014d3 100644 --- a/uefi-raw/CHANGELOG.md +++ b/uefi-raw/CHANGELOG.md @@ -1,5 +1,9 @@ # uefi-raw - [Unreleased] +## Added + +- Added `ScsiIoProtocol`. + ## Changed - `maximum_capsule_size` of `query_capsule_capabilities` now takes a *mut u64 instead of a *mut usize. diff --git a/uefi-raw/src/protocol/scsi.rs b/uefi-raw/src/protocol/scsi.rs index 8d3aad99e..c90ba6b3c 100644 --- a/uefi-raw/src/protocol/scsi.rs +++ b/uefi-raw/src/protocol/scsi.rs @@ -1,6 +1,5 @@ use core::ffi::c_void; -use crate::protocol::device_path::DevicePathProtocol; use crate::{guid, Event, Guid, Status}; /// TODO: use #define TARGET_MAX_BYTES 0x10, the limit of target. @@ -159,158 +158,3 @@ pub struct ScsiIoProtocol { impl ScsiIoProtocol { pub const GUID: Guid = guid!("932f47e6-2362-4002-803e-3cd54b138f85"); } - -// TODO: see device_path.rs, then see 15.5. SCSI Device Paths and 15.6. SCSI Pass Thru Device Paths - -#[derive(Debug)] -#[repr(C)] -pub struct ExtScsiPassThruProtocol { - pub mode: *mut ExtScsiPassThruMode, - pub pass_thru: unsafe extern "efiapi" fn( - this: *const Self, - target: *mut u8, - lun: u64, - packet: *mut ExtScsiIoScsiRequestPacket, - event: Event, - ) -> Status, - pub get_next_target_lun: - unsafe extern "efiapi" fn(this: *const Self, target: *mut *mut u8, lun: *mut u64) -> Status, - pub build_device_path: unsafe extern "efiapi" fn( - this: *mut Self, - target: *mut u8, - lun: u64, - device_path: *mut *mut DevicePathProtocol, - ) -> Status, - pub get_target_lun: unsafe extern "efiapi" fn( - this: *const Self, - device_path: *const DevicePathProtocol, - target: *mut *mut u8, - lun: *mut u64, - ) -> Status, - - pub reset_channel: unsafe extern "efiapi" fn(this: *mut Self) -> Status, - pub reset_target_lun: - unsafe extern "efiapi" fn(this: *mut Self, target: *mut u8, lun: u64) -> Status, - pub get_next_target: - unsafe extern "efiapi" fn(this: *const Self, target: *mut *mut u8) -> Status, -} -/// 15.7. Extended SCSI Pass Thru Protocol -impl ExtScsiPassThruProtocol { - pub const GUID: Guid = guid!("143b7632-b81b-4cb7-abd3-b625a5b9bffe"); -} - -newtype_enum! { - /// Attributes - #[derive(Default)] - pub enum PassThruAttributes: u32 => { - PHYSICAL = 0x0001, - LOGICAL = 0x0002, - NONBLOCKIO = 0x0004, - } -} - -#[derive(Clone, Copy, Default, Debug, Eq, PartialEq)] -#[repr(C)] -pub struct ExtScsiPassThruMode { - pub adapter_id: u32, - pub attributes: PassThruAttributes, - pub io_align: u32, -} - -/// EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET -#[derive(Debug)] -#[repr(C)] -pub struct ExtScsiIoScsiRequestPacket { - /// Timeout: The timeout, in 100 ns units, to use for the execution of this SCSI Request Packet. - /// A Timeout value of 0 means that this function will wait indefinitely for the SCSI Request Packet to execute. - /// If Timeout is greater than zero, then this function will return EFI_TIMEOUT if the time required to execute the SCSI Request Packet is greater than Timeout . - pub timeout: u64, - - /// InDataBuffer: A pointer to the data buffer to transfer between the SCSI controller and the SCSI device for read and bidirectional commands. - /// For all write and non data commands where InTransferLength is 0 this field is optional and may be NULL . - /// If this field is not NULL , then it must be aligned on the boundary specified by the IoAlign field in the EFI_EXT_SCSI_PASS_THRU_MODE structure. - pub in_data_buffer: *mut c_void, - /// OutDataBuffer: A pointer to the data buffer to transfer between the SCSI controller and the SCSI device for write or bidirectional commands. - /// For all read and non data commands where OutTransferLength is 0 this field is optional and may be NULL . - /// If this field is not NULL , then it must be aligned on the boundary specified by the IoAlign field in the EFI_EXT_SCSI_PASS_THRU_MODE structure. - pub out_data_buffer: *mut c_void, - /// SenseData: A pointer to the sense data that was generated by the execution of the SCSI Request Packet. - /// If SenseDataLength is 0, then this field is optional and may be NULL . - /// It is strongly recommended that a sense data buffer of at least 252 bytes be provided to guarantee the entire sense data buffer - /// generated from the execution of the SCSI Request Packet can be returned. - /// If this field is not NULL , then it must be aligned to the boundary specified in the IoAlign field in the EFI_EXT_SCSI_PASS_THRU_MODE structure. - pub sense_data: *mut c_void, - /// Cdb: A pointer to buffer that contains the Command Data Block to send to the SCSI device specified by Target and Lun . - pub cdb: *mut c_void, - - /// InTransferLength: On Input, the size, in bytes, of InDataBuffer . - /// On output, the number of bytes transferred between the SCSI controller and the SCSI device. - /// If InTransferLength is larger than the SCSI controller can handle, no data will be transferred, - /// InTransferLength will be updated to contain the number of bytes that the SCSI controller is able to transfer, and EFI_BAD_BUFFER_SIZE will be returned. - pub in_transfer_length: u32, - /// OutTransferLength: On Input, the size, in bytes of OutDataBuffer . On Output, the Number of bytes transferred between SCSI Controller and the SCSI device. - /// If OutTransferLength is larger than the SCSI controller can handle, no data will be transferred, - /// OutTransferLength will be updated to contain the number of bytes that the SCSI controller is able to transfer, - /// and EFI_BAD_BUFFER_SIZE will be returned. - pub out_transfer_length: u32, - - /// CdbLength: The length, in bytes, of the buffer Cdb . The standard values are 6, 10, 12, and 16, but other values are possible if a variable length CDB is used. - pub cdb_length: u8, - /// DataDirection: The direction of the data transfer. 0 for reads, 1 for writes. A value of 2 is Reserved for Bi-Directional SCSI commands. - /// For example XDREADWRITE. All other values are reserved, and must not be used. - pub data_direction: ExtDataDirection, - /// HostAdapterStatus: The status of the host adapter specified by This when the SCSI Request Packet was executed on the target device. - /// If bit 7 of this field is set, then HostAdapterStatus is a vendor defined error code. - pub host_adapter_status: ExtHostAdapterStatus, - /// TargetStatus: The status returned by the device specified by Target and Lun when the SCSI Request Packet was executed. - pub target_status: ExtTargetStatus, - /// SenseDataLength: On input, the length in bytes of the SenseData buffer. - /// On output, the number of bytes written to the SenseData buffer. - pub sense_data_length: u8, -} - -newtype_enum! { - /// Ext DataDirection - #[derive(Default)] - pub enum ExtDataDirection: u8 => { - READ = 0, - WRITE = 1, - BIDIRECTIONAL = 2, - } -} - -newtype_enum! { - /// Ext HostAdapterStatus - #[derive(Default)] - pub enum ExtHostAdapterStatus: u8 => { - OK = 0x00, - TIMEOUT_COMMAND = 0x09, - TIMEOUT = 0x0b, - MESSAGE_REJECT = 0x0d, - BUS_RESET = 0x0e, - PARITY_ERROR = 0x0f, - REQUEST_SENSE_FAILED = 0x10, - SELECTION_TIMEOUT = 0x11, - DATA_OVERRUN_UNDERRUN = 0x12, - BUS_FREE = 0x13, - PHASE_ERROR = 0x14, - OTHER = 0x7f, - } -} - -newtype_enum! { - /// ExtTargetStatus - #[derive(Default)] - pub enum ExtTargetStatus: u8 => { - GOOD = 0x00, - CHECK_CONDITION = 0x02, - CONDITION_MET = 0x04, - BUSY = 0x08, - INTERMEDIATE = 0x10, - INTERMEDIATE_CONDITION_MET = 0x14, - RESERVATION_CONFLICT = 0x18, - TASK_SET_FULL = 0x28, - ACA_ACTIVE = 0x30, - TASK_ABORTED = 0x40, - } -} diff --git a/uefi-test-runner/examples/scsi.rs b/uefi-test-runner/examples/scsi.rs index a766fdb4a..2840bd8f5 100644 --- a/uefi-test-runner/examples/scsi.rs +++ b/uefi-test-runner/examples/scsi.rs @@ -7,16 +7,13 @@ extern crate alloc; use alloc::vec; -use alloc::vec::Vec; +use core::mem; use log::info; // ANCHOR: use use uefi::prelude::*; -use uefi::proto::scsi::{ - ExtScsiPassThru, ScsiDeviceLocation, ScsiExtRequestPacket, ScsiIo, - ScsiRequestPacket, -}; +use uefi::proto::scsi::{ScsiIo, ScsiRequestPacket}; // ANCHOR_END: use @@ -29,11 +26,10 @@ fn main(image_handle: Handle, mut system_table: SystemTable) -> Status { let boot_services = system_table.boot_services(); // ANCHOR_END: services - // ANCHOR: params - /// all api OK, but memory panic when return, maybe the vec. + // ANCHOR: params, all api OK, but memory panic when return, maybe the vec. test_scsi_io(boot_services); - // test_ext_scsi_thru(boot_services); - // ANCHOR_END: params + // ANCHOR_END: params, panic at uefi/src/allocator.rs#L130 (*boot_services()).free_pool(ptr).unwrap(); + // ANCHOR: stall boot_services.stall(10_000_000); @@ -73,29 +69,26 @@ pub fn test_scsi_io(bt: &BootServices) { info!("SCSI_IO Protocol reset dev test: {:?}", result); bt.stall(10_000); - // let mut data_buffer = vec![0; 40]; - // let scsicmd = commands::TestUnitReady::new(); - // scsicmd.push_to_buffer(&mut data_buffer).expect("TODO: panic message"); - // info!("the data buf = {:?}", data_buffer); - - let mut packet: ScsiRequestPacket = ScsiRequestPacket::default(); - packet.is_a_write_packet = false; - packet.cdb = vec![0x00, 0, 0, 0, 0, 0x00]; - packet.timeout = 0; - info!("packet: {:?}", packet); - let result = scsi_protocol.execute_scsi_command(&mut packet, None); + + let mut packet_tur: ScsiRequestPacket = ScsiRequestPacket::default(); + packet_tur.is_a_write_packet = false; + packet_tur.cdb = vec![0x00, 0, 0, 0, 0, 0x00]; + packet_tur.timeout = 0; + info!("packet_tur: {:?}", packet_tur); + let result = scsi_protocol.execute_scsi_command(&mut packet_tur, None); info!("=================SCSI_IO Protocol exec scsi command [TestUnitReady] test: {:?}", result); - let mut packet: ScsiRequestPacket = ScsiRequestPacket::default(); - packet.is_a_write_packet = false; - packet.cdb = vec![0x12, 0x01, 0x00, 0, 0, 0x00]; - packet.data_buffer = vec![0; 96]; - packet.sense_data = vec![0; 18]; - packet.timeout = 0; - let result = scsi_protocol.execute_scsi_command(&mut packet, None); + let mut packet_icmd: ScsiRequestPacket = ScsiRequestPacket::default(); + packet_icmd.is_a_write_packet = false; + packet_icmd.cdb = vec![0x12, 0x01, 0x00, 0, 0, 0x00]; + packet_icmd.data_buffer = vec![0; 96]; + packet_icmd.sense_data = vec![0; 18]; + packet_icmd.timeout = 0; + let result = scsi_protocol.execute_scsi_command(&mut packet_icmd, None); info!("=================SCSI_IO Protocol exec scsi command [InquiryCommand] test: {:?}", result); - // now send Req is ok. but seem couldn't receive Resp. + // drop(packet) + // now send Req is ok. but it seems couldn't receive Resp. } /* @@ -137,63 +130,3 @@ typedef struct { UINT8 Reserved_5_95[95 - 5 + 1]; } EFI_SCSI_INQUIRY_DATA; */ - -pub fn test_ext_scsi_thru(bt: &BootServices) { - info!("Running loaded Ext Scsi Thru protocol test"); - - let handle = bt - .get_handle_for_protocol::() - .expect("Failed to get handles for `ExtScsiThru` protocol"); - - let mut escsi_protocol = bt - .open_protocol_exclusive::(handle) - .expect("Founded ExtScsiThru Protocol but open failed"); - - // value efi_reset_fn is the type of ResetSystemFn, a function pointer - - let result = escsi_protocol.mode(); - info!("EXT_SCSI_THRU Protocol's mode: {:?}", result); - - let mut targets: Vec = vec![0xFF; 10]; - let target = ScsiDeviceLocation::new(&mut targets[0], 0); - let result = escsi_protocol.build_device_path(target); - info!("EXT_SCSI_THRU Protocol build_device_path: {:?}", result); - - // let device_path = result.expect("couldn't got the dev path"); - // // DevicePath has DevicePathFromText ffi - // let result = escsi_protocol.get_target_lun(&*device_path); - // info!("EXT_SCSI_THRU Protocol build_device_path: {:?}", result); - - // let location = result.unwrap().clone(); - - let location = target; - - let result = escsi_protocol.get_next_target(); - info!("EXT_SCSI_THRU Protocol get_next_target: {:?}", result); - - // let result = escsi_protocol.reset_target_lun(location.clone()); - // info!("EXT_SCSI_THRU Protocol reset dev test: {:?}", result); - - let result = escsi_protocol.reset_channel(); - info!("EXT_SCSI_THRU Protocol reset bus test: {:?}", result); - - bt.stall(10_000); - - let mut ext_packet = ScsiExtRequestPacket::default(); - ext_packet.is_a_write_packet = false; - ext_packet.cdb = vec![0x00, 0, 0, 0, 0, 0x00]; - ext_packet.timeout = 0; - let result = escsi_protocol.pass_thru(location.clone(), ext_packet, None); - info!("=================EXT_SCSI_THRU Protocol exec scsi command [TestUnitReady] test: {:?}", result); - - let mut ext_packet = ScsiExtRequestPacket::default(); - ext_packet.is_a_write_packet = false; - ext_packet.cdb = vec![0x12, 0x01, 0x00, 0, 0, 0x00]; - ext_packet.data_buffer = vec![0; 96]; - ext_packet.sense_data = vec![0; 18]; - ext_packet.timeout = 0; - let result = escsi_protocol.pass_thru(location.clone(), ext_packet, None); - info!("=================EXT_SCSI_THRU Protocol exec scsi command [InquiryCommand] test: {:?}", result); - - // now send Req is ok. but seem couldn't receive Resp. -} diff --git a/uefi/CHANGELOG.md b/uefi/CHANGELOG.md index 8e7e3930e..4298bedf1 100644 --- a/uefi/CHANGELOG.md +++ b/uefi/CHANGELOG.md @@ -1,5 +1,9 @@ # uefi - [Unreleased] +## Added + +- Added `ScsiIo` Protocol. + ## Added - Added `RuntimeServices::update_capsule`. diff --git a/uefi/src/proto/scsi.rs b/uefi/src/proto/scsi.rs index eebd2da15..c53d3f440 100644 --- a/uefi/src/proto/scsi.rs +++ b/uefi/src/proto/scsi.rs @@ -1,6 +1,5 @@ //! EFI SCSI I/O protocols. -use alloc::boxed::Box; use alloc::vec::Vec; use core::ffi::c_void; use core::ptr; @@ -10,17 +9,14 @@ use log::info; use uefi_raw::protocol::scsi; use uefi_raw::protocol::scsi::{ - DataDirection, ExtDataDirection, ExtHostAdapterStatus, ExtScsiIoScsiRequestPacket, - ExtScsiPassThruMode, ExtScsiPassThruProtocol, ExtTargetStatus, HostAdapterStatus, - ScsiIoProtocol, ScsiIoScsiRequestPacket, TargetStatus, + DataDirection, HostAdapterStatus, ScsiIoProtocol, ScsiIoScsiRequestPacket, TargetStatus, }; -use crate::proto::device_path::build::{acpi, hardware, messaging, DevicePathBuilder}; -use crate::proto::device_path::DevicePath; -use crate::proto::unsafe_protocol; use crate::{Event, Result, StatusExt}; +use crate::proto::unsafe_protocol; /// Protocol for who running in the EFI boot services environment such as code, typically drivers, able to access SCSI devices. +/// see example at `uefi-test-runner/examples/scsi.rs` #[derive(Debug)] #[repr(transparent)] #[unsafe_protocol(ScsiIoProtocol::GUID)] @@ -102,261 +98,6 @@ impl ScsiIo { } } -/// Extended SCSI Pass Thru Protocol. -#[derive(Debug)] -#[repr(transparent)] -#[unsafe_protocol(ExtScsiPassThruProtocol::GUID)] -pub struct ExtScsiPassThru(ExtScsiPassThruProtocol); - -impl ExtScsiPassThru { - /// the value of mode which is type ExtScsiPassThruMode. - pub fn mode(&self) -> Result { - unsafe { Ok(*self.0.mode) } - } - /// Sends a SCSI Request Packet to a SCSI device that is attached to the SCSI channel. - pub fn pass_thru( - &mut self, - location: ScsiDeviceLocation, - mut packet: ScsiExtRequestPacket, - event: Option, - ) -> Result { - let raw_packet = &mut (packet.convert_auto_request_packet()); - info!("raw_packet = {:?}", raw_packet); - let event_arg = match event { - Some(event) => event.as_ptr(), - None => ptr::null_mut(), - }; - - unsafe { - (self.0.pass_thru)( - &mut self.0, - location.target, - location.lun, - raw_packet, - event_arg, - ) - } - .to_result() - } - - /// Used to translate a device path node to a Target ID and LUN. - pub fn get_next_target_lun(&mut self) -> Result { - let mut location = ScsiDeviceLocation::default(); - unsafe { (self.0.get_next_target_lun)(&self.0, &mut location.target, &mut location.lun) } - .to_result_with_val(|| location) - } - - /// Used to allocate and build a device path node for a SCSI device on a SCSI channel. - pub fn build_device_path(&mut self, location: ScsiDeviceLocation) -> Result> { - let mut v = Vec::new(); - let path = DevicePathBuilder::with_vec(&mut v) - .push(&acpi::Acpi { - hid: 0x41d0_0a03, - uid: 0x0000_0000, - }) - .unwrap() - .push(&hardware::Pci { - function: 0x00, - device: 0x19, - }) - .unwrap() - .push(&messaging::Scsi { - target_id: 0, - logical_unit_number: 0, - }) - .unwrap() - .finalize() - .expect("failed to build dev path"); - let mut device_path_ptr: *mut uefi_raw::protocol::device_path::DevicePathProtocol = - unsafe { *path.as_ffi_ptr().cast() }; - // let path_ptr = &mut path?; - unsafe { - (self.0.build_device_path)( - &mut self.0, - location.target, - location.lun, - &mut device_path_ptr, - ) - } - .to_result_with_val(|| path.to_boxed()) - } - - /// Used to translate a device path node to a Target ID and LUN. - pub fn get_target_lun(&mut self, device_path: &DevicePath) -> Result { - let device_path_ptr: *const uefi_raw::protocol::device_path::DevicePathProtocol = - device_path.as_ffi_ptr().cast(); - - let mut location = ScsiDeviceLocation::default(); - unsafe { - (self.0.get_target_lun)( - &self.0, - device_path_ptr, - &mut location.target, - &mut location.lun, - ) - } - .to_result_with_val(|| location) - } - - /// Resets a SCSI channel. This operation resets all the SCSI devices connected to the SCSI channel. - pub fn reset_channel(&mut self) -> Result { - unsafe { (self.0.reset_channel)(&mut self.0) }.to_result() - } - - /// Resets a SCSI logical unit that is connected to a SCSI channel. - pub fn reset_target_lun(&mut self, location: ScsiDeviceLocation) -> Result { - unsafe { (self.0.reset_target_lun)(&mut self.0, location.target, location.lun) }.to_result() - } - - /// Used to retrieve the list of legal Target IDs for SCSI devices on a SCSI channel. - pub fn get_next_target(&mut self) -> Result { - let mut id = 0; - let mut location = ScsiDeviceLocation::new(&mut id, 0); - unsafe { (self.0.get_next_target)(&self.0, &mut location.target) } - .to_result_with_val(|| location) - } -} - -/// the rust FFI for `EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET` -#[derive(Debug, Default, Clone)] -pub struct ScsiExtRequestPacket { - /// whether the request is written scsi - pub is_a_write_packet: bool, - /// timeout - pub timeout: u64, - /// data_buffer is `in_data_buffer` or `out_data_buffer` - pub data_buffer: Vec, - /// SCSI's cdb, refer to T10 SPC - pub cdb: Vec, - /// SCSI's sense data, refer to T10 SPC - pub sense_data: Vec, - /// uefi_raw::protocol::scsi::ExtDataDirection - pub data_direction: ExtDataDirection, - /// uefi_raw::protocol::scsi::ExtHostAdapterStatus - pub host_adapter_status: ExtHostAdapterStatus, - /// uefi_raw::protocol::scsi::ExtTargetStatus - pub target_status: ExtTargetStatus, -} - -impl ScsiExtRequestPacket { - /// auto convert FFI `ScsiExtRequestPacket` to raw UEFI SCSI request packet `EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET` - pub fn convert_zero_request_packet(&mut self) -> ExtScsiIoScsiRequestPacket { - let packet: ExtScsiIoScsiRequestPacket = ExtScsiIoScsiRequestPacket { - timeout: self.timeout, - - in_data_buffer: null_mut(), - out_data_buffer: null_mut(), - sense_data: self.sense_data.as_mut_ptr() as *mut c_void, - cdb: self.cdb.as_mut_ptr() as *mut c_void, - - in_transfer_length: 0, - out_transfer_length: 0, - sense_data_length: self.sense_data.len() as u8, - cdb_length: self.cdb.len() as u8, - - data_direction: self.data_direction, - host_adapter_status: self.host_adapter_status, - target_status: self.target_status, - }; - packet - } - - /// convert auto - pub fn convert_auto_request_packet(&mut self) -> ExtScsiIoScsiRequestPacket { - ExtScsiIoScsiRequestPacket { - timeout: 0, - - in_data_buffer: if (self.data_buffer.len() != 0) && !self.is_a_write_packet { - self.data_buffer.as_mut_ptr().cast::() - } else { - null_mut() - }, - out_data_buffer: if self.data_buffer.len() != 0 && self.is_a_write_packet { - self.data_buffer.as_mut_ptr().cast::() - } else { - null_mut() - }, - - sense_data: if self.sense_data.len() != 0 { - self.sense_data.as_mut_ptr().cast::() - } else { - null_mut() - }, - cdb: if self.cdb.len() != 0 { - self.cdb.as_mut_ptr().cast::() - } else { - null_mut() - }, - - in_transfer_length: if !self.is_a_write_packet { - self.data_buffer.len() as u32 - } else { - 0 - }, - out_transfer_length: if self.is_a_write_packet { - self.data_buffer.len() as u32 - } else { - 0 - }, - cdb_length: self.cdb.len() as u8, - sense_data_length: self.sense_data.len() as u8, - - data_direction: Default::default(), - host_adapter_status: Default::default(), - target_status: Default::default(), - } - } - /// convert FFI `ScsiExtRequestPacket` to raw UEFI SCSI request packet `EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET` - pub fn convert_to_request_packet(&mut self) -> ExtScsiIoScsiRequestPacket { - if self.is_a_write_packet { - self._convert_to_write_request_packet() - } else { - self._convert_to_read_request_packet() - } - } - fn _convert_to_read_request_packet(&mut self) -> ExtScsiIoScsiRequestPacket { - let packet: ExtScsiIoScsiRequestPacket = ExtScsiIoScsiRequestPacket { - timeout: self.timeout, - - in_data_buffer: self.data_buffer.as_mut_ptr() as *mut c_void, - out_data_buffer: null_mut(), - sense_data: self.sense_data.as_mut_ptr() as *mut c_void, - cdb: self.cdb.as_mut_ptr() as *mut c_void, - - in_transfer_length: self.data_buffer.len() as u32, - out_transfer_length: 0, - sense_data_length: self.sense_data.len() as u8, - cdb_length: self.cdb.len() as u8, - - data_direction: self.data_direction, - host_adapter_status: self.host_adapter_status, - target_status: self.target_status, - }; - packet - } - - fn _convert_to_write_request_packet(&mut self) -> ExtScsiIoScsiRequestPacket { - let packet: ExtScsiIoScsiRequestPacket = ExtScsiIoScsiRequestPacket { - timeout: self.timeout, - - in_data_buffer: null_mut(), - out_data_buffer: self.data_buffer.as_mut_ptr() as *mut c_void, - sense_data: self.sense_data.as_mut_ptr() as *mut c_void, - cdb: self.cdb.as_mut_ptr() as *mut c_void, - - in_transfer_length: 0, - out_transfer_length: self.data_buffer.len() as u32, - sense_data_length: self.sense_data.len() as u8, - cdb_length: self.cdb.len() as u8, - - data_direction: self.data_direction, - host_adapter_status: self.host_adapter_status, - target_status: self.target_status, - }; - packet - } -} - /// the rust FFI for `EFI_SCSI_IO_SCSI_REQUEST_PACKET` #[derive(Debug, Default, Clone)] pub struct ScsiRequestPacket {