use nvme_cli_sys::{
nvme_admin_cmd, nvme_admin_opcode::nvme_admin_get_log_page,
nvme_admin_opcode::nvme_admin_identify, nvme_error_log_page, nvme_id_ctrl, nvme_smart_log,
};
use std::fs::OpenOptions;
use std::io;
use std::mem::{size_of, zeroed};
use std::os::unix::io::AsRawFd;
pub fn read_nvme_id_ctrl(dev_path: &str) -> io::Result<nvme_id_ctrl> {
let file = OpenOptions::new()
.read(true)
.write(true) .open(dev_path)?;
let fd = file.as_raw_fd();
let mut id: nvme_id_ctrl = unsafe { zeroed() };
let id_ptr = &mut id as *mut nvme_id_ctrl as u64;
let id_len = size_of::<nvme_id_ctrl>() as u32;
let cns: u8 = 0x01;
let cntlid: u16 = 0x0000;
let cdw10: u32 = (cns as u32) | ((cntlid as u32) << 16);
let mut cmd: nvme_admin_cmd = unsafe { zeroed() };
cmd.opcode = nvme_admin_identify as u8; cmd.nsid = 0x0000_0000;
cmd.addr = id_ptr;
cmd.data_len = id_len;
cmd.cdw10 = cdw10;
cmd.cdw11 = 0;
cmd.timeout_ms = 1000;
let ret = unsafe { nvme_cli_sys::nvme_ioctl_admin_cmd(fd, &mut cmd) };
match ret {
Ok(0) => Ok(id),
Ok(status) => Err(io::Error::other(format!(
"NVMe admin command failed, status={:#x}",
status
))),
Err(e) => Err(io::Error::other(e.to_string())),
}
}
pub fn read_nvme_smart_log(dev_path: &str) -> io::Result<nvme_smart_log> {
let file = OpenOptions::new()
.read(true)
.write(true) .open(dev_path)?;
let fd = file.as_raw_fd();
let mut log: nvme_smart_log = unsafe { zeroed() };
let log_ptr = &mut log as *mut nvme_smart_log as u64;
let log_len = size_of::<nvme_smart_log>() as u32;
let log_id: u8 = 0x02; let numd: u32 = log_len / 4 - 1;
let cdw10: u32 = (log_id as u32) | (numd << 16);
let mut cmd: nvme_admin_cmd = unsafe { zeroed() };
cmd.opcode = nvme_admin_get_log_page as u8;
cmd.nsid = 0xFFFF_FFFF;
cmd.addr = log_ptr;
cmd.data_len = log_len;
cmd.cdw10 = cdw10;
cmd.cdw11 = 0;
cmd.timeout_ms = 1000;
let ret = unsafe { nvme_cli_sys::nvme_ioctl_admin_cmd(fd, &mut cmd) };
match ret {
Ok(0) => Ok(log),
Ok(status) => Err(io::Error::other(format!(
"NVMe admin command failed, status={:#x}",
status
))),
Err(e) => Err(io::Error::other(e.to_string())),
}
}
pub(super) fn read_error_log_raw(
dev_path: &str,
num_entries: u16,
) -> io::Result<Vec<nvme_error_log_page>> {
let file = OpenOptions::new().read(true).write(true).open(dev_path)?;
let fd = file.as_raw_fd();
let entries_count = num_entries as usize;
let mut entries = vec![unsafe { zeroed::<nvme_error_log_page>() }; entries_count];
let log_ptr = entries.as_mut_ptr() as u64;
let log_len = (entries_count * size_of::<nvme_error_log_page>()) as u32;
let log_id: u8 = 0x01; let numd: u32 = log_len / 4 - 1;
let cdw10: u32 = (log_id as u32) | (numd << 16);
let mut cmd: nvme_admin_cmd = unsafe { zeroed() };
cmd.opcode = nvme_admin_get_log_page as u8;
cmd.nsid = 0xFFFF_FFFF;
cmd.addr = log_ptr;
cmd.data_len = log_len;
cmd.cdw10 = cdw10;
cmd.cdw11 = 0;
cmd.timeout_ms = 5000;
let ret = unsafe { nvme_cli_sys::nvme_ioctl_admin_cmd(fd, &mut cmd) };
match ret {
Ok(0) => Ok(entries),
Ok(status) => Err(io::Error::other(format!(
"Error log command failed, status={:#x}",
status
))),
Err(e) => Err(io::Error::other(e.to_string())),
}
}