use libnvme_sys::{
nvme_admin_passthru, nvme_dev_self_test, nvme_dev_self_test_args, nvme_get_lba_status,
nvme_get_lba_status_args, nvme_get_property, nvme_get_property_args, nvme_io_passthru,
nvme_lockdown, nvme_lockdown_args, nvme_sanitize_nvm, nvme_sanitize_nvm_args,
nvme_security_receive, nvme_security_receive_args, nvme_security_send, nvme_security_send_args,
nvme_set_property, nvme_set_property_args,
};
use crate::admin::{SanitizeAction, SelfTestAction};
use crate::error::check_ret;
use crate::{Controller, Result};
pub struct Sanitize<'a, 'r> {
ctrl: &'a Controller<'r>,
action: SanitizeAction,
ause: bool,
owpass: u8,
oipbp: bool,
nodas: bool,
emvs: bool,
ovrpat: u32,
timeout_ms: u32,
}
impl<'a, 'r> Sanitize<'a, 'r> {
pub(crate) fn new(ctrl: &'a Controller<'r>) -> Self {
Sanitize {
ctrl,
action: SanitizeAction::BlockErase,
ause: false,
owpass: 0,
oipbp: false,
nodas: false,
emvs: false,
ovrpat: 0,
timeout_ms: 0,
}
}
pub fn action(mut self, action: SanitizeAction) -> Self {
self.action = action;
self
}
pub fn ause(mut self, ause: bool) -> Self {
self.ause = ause;
self
}
pub fn overwrite_pass_count(mut self, n: u8) -> Self {
self.owpass = n;
self
}
pub fn overwrite_invert(mut self, oipbp: bool) -> Self {
self.oipbp = oipbp;
self
}
pub fn no_deallocate_after(mut self, nodas: bool) -> Self {
self.nodas = nodas;
self
}
pub fn emulated_media_verify(mut self, emvs: bool) -> Self {
self.emvs = emvs;
self
}
pub fn overwrite_pattern(mut self, pattern: u32) -> Self {
self.ovrpat = pattern;
self
}
pub fn timeout_ms(mut self, ms: u32) -> Self {
self.timeout_ms = ms;
self
}
#[allow(clippy::field_reassign_with_default)]
pub fn execute(self) -> Result<()> {
let fd = self.ctrl.open_fd()?;
let mut args = nvme_sanitize_nvm_args::default();
args.args_size = std::mem::size_of::<nvme_sanitize_nvm_args>() as i32;
args.fd = fd;
args.timeout = self.timeout_ms;
args.sanact = self.action.as_raw();
args.ovrpat = self.ovrpat;
args.ause = self.ause;
args.owpass = self.owpass;
args.oipbp = self.oipbp;
args.nodas = self.nodas;
#[cfg(has_sanitize_emvs)]
{
args.emvs = self.emvs;
}
let ret = unsafe { nvme_sanitize_nvm(&mut args) };
check_ret(ret)
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct LockdownArgs {
pub scope: u8,
pub prohibit: u8,
pub interface: u8,
pub opcode_or_fid: u8,
pub uuid_index: u8,
pub timeout_ms: u32,
}
#[derive(Debug, Default, Clone, Copy)]
pub struct GetLbaStatusArgs {
pub nsid: u32,
pub slba: u64,
pub mndw: u32,
pub atype: u32,
pub rl: u16,
pub timeout_ms: u32,
}
#[derive(Debug, Default)]
pub struct PassthruArgs<'a> {
pub opcode: u8,
pub flags: u8,
pub rsvd: u16,
pub nsid: u32,
pub cdw2: u32,
pub cdw3: u32,
pub cdw10: u32,
pub cdw11: u32,
pub cdw12: u32,
pub cdw13: u32,
pub cdw14: u32,
pub cdw15: u32,
pub data: Option<&'a mut [u8]>,
pub metadata: Option<&'a mut [u8]>,
pub timeout_ms: u32,
}
impl<'r> Controller<'r> {
pub fn sanitize(&self) -> Sanitize<'_, 'r> {
Sanitize::new(self)
}
pub fn self_test(&self, nsid: u32, action: SelfTestAction) -> Result<()> {
let fd = self.open_fd()?;
let mut args = nvme_dev_self_test_args {
result: std::ptr::null_mut(),
args_size: std::mem::size_of::<nvme_dev_self_test_args>() as i32,
fd,
timeout: 0,
nsid,
stc: action.as_raw(),
};
let ret = unsafe { nvme_dev_self_test(&mut args) };
check_ret(ret)
}
pub fn lockdown(&self, args: LockdownArgs) -> Result<()> {
let fd = self.open_fd()?;
let mut raw = nvme_lockdown_args {
result: std::ptr::null_mut(),
args_size: std::mem::size_of::<nvme_lockdown_args>() as i32,
fd,
timeout: args.timeout_ms,
scp: args.scope,
prhbt: args.prohibit,
ifc: args.interface,
ofi: args.opcode_or_fid,
uuidx: args.uuid_index,
};
let ret = unsafe { nvme_lockdown(&mut raw) };
check_ret(ret)
}
#[allow(clippy::too_many_arguments)]
pub fn security_send(
&self,
nsid: u32,
secp: u8,
spsp0: u8,
spsp1: u8,
nssf: u8,
tl: u32,
data: &mut [u8],
) -> Result<u32> {
let fd = self.open_fd()?;
let mut result = 0u32;
let mut args = nvme_security_send_args {
result: &mut result,
data: data.as_mut_ptr() as *mut std::ffi::c_void,
args_size: std::mem::size_of::<nvme_security_send_args>() as i32,
fd,
timeout: 0,
nsid,
tl,
data_len: data.len() as u32,
nssf,
spsp0,
spsp1,
secp,
};
let ret = unsafe { nvme_security_send(&mut args) };
check_ret(ret)?;
Ok(result)
}
#[allow(clippy::too_many_arguments)]
pub fn security_receive(
&self,
nsid: u32,
secp: u8,
spsp0: u8,
spsp1: u8,
nssf: u8,
al: u32,
data: &mut [u8],
) -> Result<u32> {
let fd = self.open_fd()?;
let mut result = 0u32;
let mut args = nvme_security_receive_args {
result: &mut result,
data: data.as_mut_ptr() as *mut std::ffi::c_void,
args_size: std::mem::size_of::<nvme_security_receive_args>() as i32,
fd,
timeout: 0,
nsid,
al,
data_len: data.len() as u32,
nssf,
spsp0,
spsp1,
secp,
};
let ret = unsafe { nvme_security_receive(&mut args) };
check_ret(ret)?;
Ok(result)
}
pub fn get_lba_status(&self, args: GetLbaStatusArgs, buf: &mut [u8]) -> Result<u32> {
let fd = self.open_fd()?;
let mut result = 0u32;
let mut raw = nvme_get_lba_status_args {
lbas: buf.as_mut_ptr() as *mut _,
result: &mut result,
slba: args.slba,
args_size: std::mem::size_of::<nvme_get_lba_status_args>() as i32,
fd,
timeout: args.timeout_ms,
nsid: args.nsid,
mndw: args.mndw,
atype: args.atype,
rl: args.rl,
};
let ret = unsafe { nvme_get_lba_status(&mut raw) };
check_ret(ret)?;
Ok(result)
}
pub fn set_property(&self, offset: i32, value: u64) -> Result<()> {
let fd = self.open_fd()?;
let mut args = nvme_set_property_args {
result: std::ptr::null_mut(),
args_size: std::mem::size_of::<nvme_set_property_args>() as i32,
fd,
timeout: 0,
offset,
value,
};
let ret = unsafe { nvme_set_property(&mut args) };
check_ret(ret)
}
pub fn get_property(&self, offset: i32) -> Result<u64> {
let fd = self.open_fd()?;
let mut value: u64 = 0;
let mut args = nvme_get_property_args {
value: &mut value,
args_size: std::mem::size_of::<nvme_get_property_args>() as i32,
fd,
timeout: 0,
offset,
};
let ret = unsafe { nvme_get_property(&mut args) };
check_ret(ret)?;
Ok(value)
}
pub fn admin_passthru(&self, args: PassthruArgs<'_>) -> Result<u32> {
let fd = self.open_fd()?;
let mut result = 0u32;
let (data_ptr, data_len) = match args.data {
Some(buf) => (buf.as_mut_ptr() as *mut std::ffi::c_void, buf.len() as u32),
None => (std::ptr::null_mut(), 0),
};
let (md_ptr, md_len) = match args.metadata {
Some(buf) => (buf.as_mut_ptr() as *mut std::ffi::c_void, buf.len() as u32),
None => (std::ptr::null_mut(), 0),
};
let ret = unsafe {
nvme_admin_passthru(
fd,
args.opcode,
args.flags,
args.rsvd,
args.nsid,
args.cdw2,
args.cdw3,
args.cdw10,
args.cdw11,
args.cdw12,
args.cdw13,
args.cdw14,
args.cdw15,
data_len,
data_ptr,
md_len,
md_ptr,
args.timeout_ms,
&mut result,
)
};
check_ret(ret)?;
Ok(result)
}
pub fn io_passthru(&self, args: PassthruArgs<'_>) -> Result<u32> {
let fd = self.open_fd()?;
let mut result = 0u32;
let (data_ptr, data_len) = match args.data {
Some(buf) => (buf.as_mut_ptr() as *mut std::ffi::c_void, buf.len() as u32),
None => (std::ptr::null_mut(), 0),
};
let (md_ptr, md_len) = match args.metadata {
Some(buf) => (buf.as_mut_ptr() as *mut std::ffi::c_void, buf.len() as u32),
None => (std::ptr::null_mut(), 0),
};
let ret = unsafe {
nvme_io_passthru(
fd,
args.opcode,
args.flags,
args.rsvd,
args.nsid,
args.cdw2,
args.cdw3,
args.cdw10,
args.cdw11,
args.cdw12,
args.cdw13,
args.cdw14,
args.cdw15,
data_len,
data_ptr,
md_len,
md_ptr,
args.timeout_ms,
&mut result,
)
};
check_ret(ret)?;
Ok(result)
}
}