--- /dev/null
+#include <endian.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <endian.h>
+#include <errno.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <math.h>
+
+#include <linux/types.h>
+
+#include "nvme-ioctl.h"
+
+int nvme_get_nsid(int fd)
+{
+ return ioctl(fd, NVME_IOCTL_ID);
+}
+
+int nvme_submit_passthru(int fd, int ioctl_cmd, struct nvme_passthru_cmd *cmd)
+{
+ return ioctl(fd, ioctl_cmd, cmd);
+}
+
+int nvme_submit_admin_passthru(int fd, struct nvme_passthru_cmd *cmd)
+{
+ return ioctl(fd, NVME_IOCTL_ADMIN_CMD, cmd);
+}
+
+int nvme_submit_io_passthru(int fd, struct nvme_passthru_cmd *cmd)
+{
+ return ioctl(fd, NVME_IOCTL_IO_CMD, cmd);
+}
+
+int nvme_passthru(int fd, int ioctl_cmd, __u8 opcode, __u8 flags, __u16 rsvd,
+ __u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10, __u32 cdw11,
+ __u32 cdw12, __u32 cdw13, __u32 cdw14, __u32 cdw15,
+ __u32 data_len, void *data, __u32 metadata_len,
+ void *metadata, __u32 timeout_ms, __u32 *result)
+{
+ struct nvme_passthru_cmd cmd = {
+ .opcode = opcode,
+ .flags = flags,
+ .rsvd1 = rsvd,
+ .nsid = nsid,
+ .cdw2 = cdw2,
+ .cdw3 = cdw3,
+ .metadata = (__u64) metadata,
+ .addr = (__u64) data,
+ .metadata_len = metadata_len,
+ .data_len = data_len,
+ .cdw10 = cdw10,
+ .cdw11 = cdw11,
+ .cdw12 = cdw12,
+ .cdw13 = cdw13,
+ .cdw14 = cdw14,
+ .cdw15 = cdw15,
+ .timeout_ms = timeout_ms,
+ .result = 0,
+ };
+ int err;
+
+ err = nvme_submit_passthru(fd, ioctl_cmd, &cmd);
+ if (!err && result)
+ *result = cmd.result;
+ return err;
+}
+
+int nvme_io(int fd, __u8 opcode, __u64 slba, __u16 nblocks, __u16 control,
+ __u32 dsmgmt, __u32 reftag, __u16 apptag, __u16 appmask, void *data,
+ void *metadata)
+{
+ struct nvme_user_io io = {
+ .opcode = opcode,
+ .flags = 0,
+ .control = control,
+ .nblocks = nblocks,
+ .rsvd = 0,
+ .metadata = (__u64) metadata,
+ .addr = (__u64) data,
+ .slba = slba,
+ .dsmgmt = dsmgmt,
+ .reftag = reftag,
+ .appmask = apptag,
+ .apptag = appmask,
+ };
+ return ioctl(fd, NVME_IOCTL_SUBMIT_IO, &io);
+}
+
+int nvme_read(int fd, __u64 slba, __u16 nblocks, __u16 control, __u32 dsmgmt,
+ __u32 reftag, __u16 apptag, __u16 appmask, void *data,
+ void *metadata)
+{
+ return nvme_io(fd, nvme_cmd_read, slba, nblocks, control, dsmgmt,
+ reftag, apptag, appmask, data, metadata);
+}
+
+int nvme_write(int fd, __u64 slba, __u16 nblocks, __u16 control, __u32 dsmgmt,
+ __u32 reftag, __u16 apptag, __u16 appmask, void *data,
+ void *metadata)
+{
+ return nvme_io(fd, nvme_cmd_write, slba, nblocks, control, dsmgmt,
+ reftag, apptag, appmask, data, metadata);
+}
+
+int nvme_compare(int fd, __u64 slba, __u16 nblocks, __u16 control, __u32 dsmgmt,
+ __u32 reftag, __u16 apptag, __u16 appmask, void *data,
+ void *metadata)
+{
+ return nvme_io(fd, nvme_cmd_compare, slba, nblocks, control, dsmgmt,
+ reftag, apptag, appmask, data, metadata);
+}
+
+int nvme_passthru_io(int fd, __u8 opcode, __u8 flags, __u16 rsvd,
+ __u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10,
+ __u32 cdw11, __u32 cdw12, __u32 cdw13, __u32 cdw14,
+ __u32 cdw15, __u32 data_len, void *data,
+ __u32 metadata_len, void *metadata, __u32 timeout_ms)
+{
+ return nvme_passthru(fd, NVME_IOCTL_IO_CMD, opcode, flags, rsvd, nsid,
+ cdw2, cdw3, cdw10, cdw11, cdw12, cdw13, cdw14,
+ cdw15, data_len, data, metadata_len, metadata,
+ timeout_ms, NULL);
+}
+
+int nvme_write_zeros(int fd, __u32 nsid, __u64 slba, __u16 nlb,
+ __u16 control, __u32 reftag, __u16 apptag, __u16 appmask)
+{
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_cmd_write_zeroes,
+ .nsid = nsid,
+ .cdw10 = slba & 0xffffffff,
+ .cdw11 = slba >> 32,
+ .cdw12 = nlb | (control << 16),
+ .cdw14 = reftag,
+ .cdw15 = apptag | (appmask << 16),
+ };
+
+ return nvme_submit_io_passthru(fd, &cmd);
+}
+
+int nvme_write_uncorrectable(int fd, __u32 nsid, __u64 slba, __u16 nlb)
+{
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_cmd_write_uncor,
+ .nsid = nsid,
+ .cdw10 = slba & 0xffffffff,
+ .cdw11 = slba >> 32,
+ .cdw12 = nlb,
+ };
+
+ return nvme_submit_io_passthru(fd, &cmd);
+}
+
+int nvme_flush(int fd, __u32 nsid)
+{
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_cmd_flush,
+ .nsid = nsid,
+ };
+
+ return nvme_submit_io_passthru(fd, &cmd);
+}
+
+int nvme_dsm(int fd, __u32 nsid, __u32 cdw11, struct nvme_dsm_range *dsm,
+ __u16 nr_ranges)
+{
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_cmd_dsm,
+ .nsid = nsid,
+ .addr = (__u64) dsm,
+ .data_len = nr_ranges * sizeof(*dsm),
+ .cdw10 = nr_ranges - 1,
+ .cdw11 = cdw11,
+ };
+
+ return nvme_submit_io_passthru(fd, &cmd);
+}
+
+struct nvme_dsm_range *nvme_setup_dsm_range(__u32 *ctx_attrs, __u32 *llbas,
+ __u64 *slbas, __u16 nr_ranges)
+{
+ int i;
+ struct nvme_dsm_range *dsm = malloc(nr_ranges * sizeof(*dsm));
+
+ if (!dsm)
+ exit(ENOMEM);
+ for (i = 0; i < nr_ranges; i++) {
+ dsm[i].cattr = htole32(ctx_attrs[i]);
+ dsm[i].nlb = htole32(llbas[i]);
+ dsm[i].slba = htole64(slbas[i]);
+ }
+ return dsm;
+}
+
+int nvme_resv_acquire(int fd, __u32 nsid, __u8 rtype, __u8 racqa,
+ bool iekey, __u64 crkey, __u64 nrkey)
+{
+ __le64 payload[2] = { htole64(crkey), htole64(nrkey) };
+ __u32 cdw10 = racqa | (iekey ? 1 << 3 : 0) | rtype << 8;
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_cmd_resv_acquire,
+ .nsid = nsid,
+ .cdw10 = cdw10,
+ .addr = (__u64) (payload),
+ .data_len = sizeof(payload),
+ };
+
+ return nvme_submit_io_passthru(fd, &cmd);
+}
+
+int nvme_resv_register(int fd, __u32 nsid, __u8 rrega, __u8 cptpl,
+ bool iekey, __u64 crkey, __u64 nrkey)
+{
+ __le64 payload[2] = { htole64(crkey), htole64(nrkey) };
+ __u32 cdw10 = rrega | (iekey ? 1 << 3 : 0) | cptpl << 30;
+
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_cmd_resv_register,
+ .nsid = nsid,
+ .cdw10 = cdw10,
+ .addr = (__u64) (payload),
+ .data_len = sizeof(payload),
+ };
+
+ return nvme_submit_io_passthru(fd, &cmd);
+}
+
+int nvme_resv_release(int fd, __u32 nsid, __u8 rtype, __u8 rrela,
+ bool iekey, __u64 crkey)
+{
+ __le64 payload[1] = { htole64(crkey) };
+ __u32 cdw10 = rrela | (iekey ? 1 << 3 : 0) | rtype << 8;
+
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_cmd_resv_register,
+ .nsid = nsid,
+ .cdw10 = cdw10,
+ .addr = (__u64) (payload),
+ .data_len = sizeof(payload),
+ };
+
+ return nvme_submit_io_passthru(fd, &cmd);
+}
+
+int nvme_resv_report(int fd, __u32 nsid, __u32 numd, void *data)
+{
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_cmd_resv_report,
+ .nsid = nsid,
+ .addr = (__u64) data,
+ .data_len = numd << 2,
+ };
+
+ return nvme_submit_io_passthru(fd, &cmd);
+}
+
+int nvme_passthru_admin(int fd, __u8 opcode, __u8 flags, __u16 rsvd,
+ __u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10,
+ __u32 cdw11, __u32 cdw12, __u32 cdw13, __u32 cdw14,
+ __u32 cdw15, __u32 data_len, void *data,
+ __u32 metadata_len, void *metadata, __u32 timeout_ms)
+{
+ return nvme_passthru(fd, NVME_IOCTL_ADMIN_CMD, opcode, flags, rsvd,
+ nsid, cdw2, cdw3, cdw10, cdw11, cdw12, cdw13,
+ cdw14, cdw15, data_len, data, metadata_len,
+ metadata, timeout_ms, NULL);
+}
+
+int nvme_identify(int fd, __u32 nsid, __u32 cdw10, void *data)
+{
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_admin_identify,
+ .nsid = nsid,
+ .addr = (__u64) data,
+ .data_len = 0x1000,
+ .cdw10 = cdw10,
+ };
+
+ return nvme_submit_admin_passthru(fd, &cmd);
+}
+
+int nvme_identify_ctrl(int fd, void *data)
+{
+ return nvme_identify(fd, 0, 1, data);
+}
+
+int nvme_identify_ns(int fd, __u32 nsid, bool present, void *data)
+{
+ return nvme_identify(fd, nsid, present ? 0x11 : 0, data);
+}
+
+int nvme_identify_ns_list(int fd, __u32 nsid, bool all, void *data)
+{
+ return nvme_identify(fd, nsid, all ? 0x10 : 0x2, data);
+}
+
+int nvme_identify_ctrl_list(int fd, __u32 nsid, __u16 cntid, void *data)
+{
+ return nvme_identify(fd, nsid, (cntid << 16) | (nsid ? 0x13 : 0x12), data);
+}
+
+int nvme_get_log(int fd, __u32 nsid, __u32 cdw10, __u32 data_len, void *data)
+{
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_admin_get_log_page,
+ .nsid = nsid,
+ .addr = (__u64) data,
+ .data_len = data_len,
+ .cdw10 = cdw10,
+ };
+ return nvme_submit_admin_passthru(fd, &cmd);
+}
+
+int nvme_log(int fd, __u32 nsid, __u8 log_id, __u32 data_len, void *data)
+{
+ __u32 cdw10 = log_id | ((data_len >> 2) - 1) << 16;
+
+ return nvme_get_log(fd, nsid, cdw10, data_len, data);
+}
+
+int nvme_fw_log(int fd, struct nvme_firmware_log_page *fw_log)
+{
+ return nvme_log(fd, 0xffffffff, 3, sizeof(*fw_log), fw_log);
+}
+
+int nvme_error_log(int fd, __u32 nsid, int entries,
+ struct nvme_error_log_page *err_log)
+{
+ return nvme_log(fd, nsid, 1, entries * sizeof(*err_log), err_log);
+}
+
+int nvme_smart_log(int fd, __u32 nsid, struct nvme_smart_log *smart_log)
+{
+ return nvme_log(fd, nsid, 2, sizeof(*smart_log), smart_log);
+}
+
+int nvme_intel_smart_log(int fd, __u32 nsid,
+ struct nvme_additional_smart_log *intel_smart_log)
+{
+ return nvme_log(fd, nsid, 0xca, sizeof(*intel_smart_log),
+ intel_smart_log);
+}
+
+int nvme_feature(int fd, __u8 opcode, __u32 nsid, __u32 cdw10, __u32 cdw11,
+ __u32 data_len, void *data, __u32 *result)
+{
+ struct nvme_admin_cmd cmd = {
+ .opcode = opcode,
+ .nsid = nsid,
+ .cdw10 = cdw10,
+ .cdw11 = cdw11,
+ .addr = (__u64) data,
+ .data_len = data_len,
+ };
+ int err;
+
+ err = nvme_submit_admin_passthru(fd, &cmd);
+ if (!err && result)
+ *result = cmd.result;
+ return err;
+}
+
+int nvme_set_feature(int fd, __u32 nsid, __u8 fid, __u32 value, bool save,
+ __u32 data_len, void *data, __u32 *result)
+{
+ __u32 cdw10 = fid | (save ? 1 << 31 : 0);
+
+ return nvme_feature(fd, nvme_admin_set_features, nsid, cdw10, value,
+ data_len, data, result);
+}
+
+int nvme_get_feature(int fd, __u32 nsid, __u8 fid, __u8 sel, __u32 cdw11,
+ __u32 data_len, void *data, __u32 *result)
+{
+ __u32 cdw10 = fid | sel << 8;
+
+ return nvme_feature(fd, nvme_admin_set_features, nsid, cdw10, cdw11,
+ data_len, data, result);
+}
+
+int nvme_format(int fd, __u32 nsid, __u8 lbaf, __u8 ses, __u8 pi,
+ __u8 pil, __u8 ms, __u32 timeout)
+{
+ __u32 cdw10 = lbaf | ms << 4 | pi << 5 | pil << 8 | ses << 9;
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_admin_format_nvm,
+ .nsid = nsid,
+ .cdw10 = cdw10,
+ .timeout_ms = timeout,
+ };
+
+ return nvme_submit_admin_passthru(fd, &cmd);
+}
+
+int nvme_ns_create(int fd, __u64 nsze, __u64 ncap, __u8 flbas,
+ __u8 dps, __u8 nmic, __u32 *result)
+{
+ struct nvme_id_ns ns = {
+ .nsze = htole64(nsze),
+ .ncap = htole64(ncap),
+ .flbas = flbas,
+ .dps = dps,
+ .nmic = nmic,
+ };
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_admin_ns_mgmt,
+ .addr = (__u64) ((void *)&ns),
+ .cdw10 = 0,
+ .data_len = 0x1000,
+ };
+ int err;
+
+ err = nvme_submit_admin_passthru(fd, &cmd);
+ if (!err && result)
+ *result = cmd.result;
+ return err;
+}
+
+int nvme_ns_delete(int fd, __u32 nsid)
+{
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_admin_ns_mgmt,
+ .nsid = nsid,
+ .cdw10 = 1,
+ };
+
+ return nvme_submit_admin_passthru(fd, &cmd);
+}
+
+int nvme_ns_attachment(int fd, __u32 nsid, __u16 num_ctrls, __u16 *ctrlist,
+ bool attach)
+{
+ int i;
+ __u8 buf[0x1000];
+ struct nvme_controller_list *cntlist =
+ (struct nvme_controller_list *)buf;
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_admin_ns_attach,
+ .addr = (__u64) cntlist,
+ .cdw10 = attach ? 0 : 1,
+ .data_len = 0x1000,
+ };
+
+ memset(buf, 0, sizeof(buf));
+ cntlist->num = num_ctrls;
+ for (i = 0; i < cntlist->num; i++)
+ cntlist->identifier[i] = htole16((__u16) ctrlist[i]);
+
+ return nvme_submit_admin_passthru(fd, &cmd);
+}
+
+int nvme_ns_attach_ctrls(int fd, __u32 nsid, __u16 num_ctrls, __u16 *ctrlist)
+{
+ return nvme_ns_attachment(fd, nsid, num_ctrls, ctrlist, true);
+}
+
+int nvme_ns_detach_ctrls(int fd, __u32 nsid, __u16 num_ctrls, __u16 *ctrlist)
+{
+ return nvme_ns_attachment(fd, nsid, num_ctrls, ctrlist, false);
+}
+
+int nvme_fw_download(int fd, __u32 offset, __u32 data_len, void *data)
+{
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_admin_download_fw,
+ .addr = (__u64) data,
+ .data_len = data_len,
+ .cdw10 = (data_len >> 2) - 1,
+ .cdw11 = offset >> 2,
+ };
+
+ return nvme_submit_admin_passthru(fd, &cmd);
+}
+
+int nvme_fw_activate(int fd, __u8 slot, __u8 action)
+{
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_admin_activate_fw,
+ .cdw10 = (action << 3) | slot,
+ };
+
+ return nvme_submit_admin_passthru(fd, &cmd);
+}
+
+int nvme_sec_send(int fd, __u32 nsid, __u8 nssf, __u16 spsp,
+ __u8 secp, __u32 tl, __u32 data_len, void *data, __u32 *result)
+{
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_admin_security_send,
+ .addr = (__u64) data,
+ .data_len = data_len,
+ .nsid = nsid,
+ .cdw10 = secp << 24 | spsp << 8 | nssf,
+ .cdw11 = tl,
+ };
+ int err;
+
+ err = nvme_submit_admin_passthru(fd, &cmd);
+ if (!err && result)
+ *result = cmd.result;
+ return err;
+}
+
+int nvme_sec_recv(int fd, __u32 nsid, __u8 nssf, __u16 spsp,
+ __u8 secp, __u32 al, __u32 data_len, void *data, __u32 *result)
+{
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_admin_security_recv,
+ .cdw10 = secp << 24 | spsp << 8 | nssf,
+ .cdw11 = al,
+ .addr = (__u64) data,
+ .data_len = data_len,
+ };
+ int err;
+
+ err = nvme_submit_admin_passthru(fd, &cmd);
+ if (!err && result)
+ *result = cmd.result;
+ return err;
+}
--- /dev/null
+#ifndef _NVME_LIB_H
+#define _NVME_LIB_H
+
+#include <stdbool.h>
+#include "linux/nvme.h"
+
+int nvme_get_nsid(int fd);
+
+/* Generic passthrough */
+int nvme_submit_passthru(int fd, int ioctl_cmd, struct nvme_passthru_cmd *cmd);
+
+int nvme_passthru(int fd, int ioctl_cmd, __u8 opcode, __u8 flags,
+ __u16 rsvd, __u32 nsid, __u32 cdw2, __u32 cdw3,
+ __u32 cdw10, __u32 cdw11, __u32 cdw12,
+ __u32 cdw13, __u32 cdw14, __u32 cdw15,
+ __u32 data_len, void *data, __u32 metadata_len,
+ void *metadata, __u32 timeout_ms, __u32 *result);
+
+/* NVME_SUBMIT_IO */
+int nvme_io(int fd, __u8 opcode, __u64 slba, __u16 nblocks, __u16 control,
+ __u32 dsmgmt, __u32 reftag, __u16 apptag,
+ __u16 appmask, void *data, void *metadata);
+
+int nvme_read(int fd, __u64 slba, __u16 nblocks, __u16 control,
+ __u32 dsmgmt, __u32 reftag, __u16 apptag,
+ __u16 appmask, void *data, void *metadata);
+
+int nvme_write(int fd, __u64 slba, __u16 nblocks, __u16 control,
+ __u32 dsmgmt, __u32 reftag, __u16 apptag,
+ __u16 appmask, void *data, void *metadata);
+
+int nvme_compare(int fd, __u64 slba, __u16 nblocks, __u16 control,
+ __u32 dsmgmt, __u32 reftag, __u16 apptag,
+ __u16 appmask, void *data, void *metadata);
+
+/* NVME_IO_CMD */
+int nvme_passthru_io(int fd, __u8 opcode, __u8 flags, __u16 rsvd,
+ __u32 nsid, __u32 cdw2, __u32 cdw3,
+ __u32 cdw10, __u32 cdw11, __u32 cdw12,
+ __u32 cdw13, __u32 cdw14, __u32 cdw15,
+ __u32 data_len, void *data, __u32 metadata_len,
+ void *metadata, __u32 timeout);
+
+int nvme_write_zeros(int fd, __u32 nsid, __u64 slba, __u16 nlb,
+ __u16 control, __u32 reftag, __u16 apptag, __u16 appmask);
+
+int nvme_write_uncorrectable(int fd, __u32 nsid, __u64 slba, __u16 nlb);
+
+int nvme_flush(int fd, __u32 nsid);
+
+int nvme_dsm(int fd, __u32 nsid, __u32 cdw11, struct nvme_dsm_range *dsm,
+ __u16 nr_ranges);
+struct nvme_dsm_range *nvme_setup_dsm_range(__u32 *ctx_attrs,
+ __u32 *llbas, __u64 *slbas,
+ __u16 nr_ranges);
+
+int nvme_resv_acquire(int fd, __u32 nsid, __u8 rtype, __u8 racqa,
+ bool iekey, __u64 crkey, __u64 nrkey);
+int nvme_resv_register(int fd, __u32 nsid, __u8 rrega, __u8 cptpl,
+ bool iekey, __u64 crkey, __u64 nrkey);
+int nvme_resv_release(int fd, __u32 nsid, __u8 rtype, __u8 rrela,
+ bool iekey, __u64 crkey);
+int nvme_resv_report(int fd, __u32 nsid, __u32 numd, void *data);
+
+/* NVME_ADMIN_CMD */
+int nvme_passthru_admin(int fd, __u8 opcode, __u8 flags, __u16 rsvd,
+ __u32 nsid, __u32 cdw2, __u32 cdw3,
+ __u32 cdw10, __u32 cdw11, __u32 cdw12,
+ __u32 cdw13, __u32 cdw14, __u32 cdw15,
+ __u32 data_len, void *data, __u32 metadata_len,
+ void *metadata, __u32 timeout);
+
+int nvme_identify(int fd, __u32 nsid, __u32 cdw10, void *data);
+int nvme_identify_ctrl(int fd, void *data);
+int nvme_identify_ns(int fd, __u32 nsid, bool present, void *data);
+int nvme_identify_ns_list(int fd, __u32 nsid, bool all, void *data);
+int nvme_identify_ctrl_list(int fd, __u32 nsid, __u16 cntid, void *data);
+
+int nvme_get_log(int fd, __u32 nsid, __u32 cdw10, __u32 data_len, void *data);
+int nvme_log(int fd, __u32 nsid, __u8 log_id, __u32 data_len, void *data);
+int nvme_fw_log(int fd, struct nvme_firmware_log_page *fw_log);
+int nvme_error_log(int fd, __u32 nsid, int entries,
+ struct nvme_error_log_page *err_log);
+int nvme_smart_log(int fd, __u32 nsid, struct nvme_smart_log *smart_log);
+int nvme_intel_smart_log(int fd, __u32 nsid,
+ struct nvme_additional_smart_log *intel_smart_log);
+
+int nvme_feature(int fd, __u8 opcode, __u32 nsid, __u32 cdw10,
+ __u32 cdw11, __u32 data_len, void *data, __u32 *result);
+int nvme_set_feature(int fd, __u32 nsid, __u8 fid, __u32 value,
+ bool save, __u32 data_len, void *data, __u32 *result);
+int nvme_get_feature(int fd, __u32 nsid, __u8 fid, __u8 sel,
+ __u32 cdw11, __u32 data_len, void *data, __u32 *result);
+
+int nvme_format(int fd, __u32 nsid, __u8 lbaf, __u8 ses, __u8 pi,
+ __u8 pil, __u8 ms, __u32 timeout);
+
+int nvme_ns_create(int fd, __u64 nsze, __u64 ncap, __u8 flbas,
+ __u8 dps, __u8 nmic, __u32 *result);
+int nvme_ns_delete(int fd, __u32 nsid);
+
+int nvme_ns_attachment(int fd, __u32 nsid, __u16 num_ctrls,
+ __u16 *ctrlist, bool attach);
+int nvme_ns_attach_ctrls(int fd, __u32 nsid, __u16 num_ctrls, __u16 *ctrlist);
+int nvme_ns_detach_ctrls(int fd, __u32 nsid, __u16 num_ctrls, __u16 *ctrlist);
+
+int nvme_fw_download(int fd, __u32 offset, __u32 data_len, void *data);
+int nvme_fw_activate(int fd, __u8 slot, __u8 action);
+
+int nvme_sec_send(int fd, __u32 nsid, __u8 nssf, __u16 spsp,
+ __u8 secp, __u32 tl, __u32 data_len, void *data, __u32 *result);
+int nvme_sec_recv(int fd, __u32 nsid, __u8 nssf, __u16 spsp,
+ __u8 secp, __u32 al, __u32 data_len, void *data, __u32 *result);
+
+#endif /* _NVME_LIB_H */
#include <sys/time.h>
#include "common.h"
+#include "nvme-ioctl.h"
#include "src/argconfig.h"
#include "src/suffix.h"
-#define array_len(x) ((size_t)(sizeof(x) / sizeof(0[x])))
+#define array_len(x) ((size_t)(sizeof(x) / sizeof(x[0])))
#define min(x, y) (x) > (y) ? (y) : (x)
#define max(x, y) (x) > (y) ? (x) : (y)
}
}
-static int identify(int namespace, void *ptr, __u32 cns)
-{
- struct nvme_admin_cmd cmd;
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.opcode = nvme_admin_identify;
- cmd.nsid = namespace;
- cmd.addr = (__u64)((unsigned long)ptr);
- cmd.data_len = 4096;
- cmd.cdw10 = cns;
- return ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd);
-}
-
-static int nvme_get_log(void *log_addr, __u32 data_len, __u32 dw10, __u32 nsid)
-{
- struct nvme_admin_cmd cmd;
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.opcode = nvme_admin_get_log_page;
- cmd.addr = (__u64)((unsigned long)log_addr);
- cmd.data_len = data_len;
- cmd.cdw10 = dw10;
- cmd.nsid = nsid;
- return ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd);
-}
-
static void d_raw(unsigned char *buf, unsigned len)
{
unsigned i;
get_dev(1, argc, argv);
- err = nvme_get_log(&smart_log,
- sizeof(smart_log), 0x2 | (((sizeof(smart_log) / 4) - 1) << 16),
- cfg.namespace_id);
+ err = nvme_smart_log(fd, cfg.namespace_id, &smart_log);
if (!err) {
if (!cfg.raw_binary)
show_smart_log(&smart_log, cfg.namespace_id);
&defaults, &cfg, sizeof(cfg));
get_dev(1, argc, argv);
- err = nvme_get_log(&smart_log,
- sizeof(smart_log), 0xCA | (((sizeof(smart_log) / 4) - 1) << 16),
- cfg.namespace_id);
+ err = nvme_intel_smart_log(fd, cfg.namespace_id, &smart_log);
if (!err) {
if (!cfg.raw_binary)
show_additional_smart_log(&smart_log, cfg.namespace_id);
fprintf(stderr, "non-zero log-entries is required param\n");
return EINVAL;
}
- err = identify(0, &ctrl, 1);
+
+ err = nvme_identify_ctrl(fd, &ctrl);
cfg.log_entries = min(cfg.log_entries, ctrl.elpe + 1);
if (err) {
fprintf(stderr, "could not identify controller\n");
return ENODEV;
} else {
struct nvme_error_log_page err_log[cfg.log_entries];
- err = nvme_get_log(err_log,
- sizeof(err_log), 0x1 | (((sizeof(err_log) / 4) - 1) << 16),
- cfg.namespace_id);
+
+ err = nvme_error_log(fd, cfg.namespace_id, cfg.log_entries, err_log);
if (!err) {
if (!cfg.raw_binary)
show_error_log(err_log, cfg.log_entries);
get_dev(1, argc, argv);
- err = nvme_get_log(&fw_log,
- sizeof(fw_log), 0x3 | (((sizeof(fw_log) / 4) - 1) << 16),
- 0xffffffff);
+ err = nvme_fw_log(fd, &fw_log);
if (!err) {
if (!cfg.raw_binary)
show_fw_log(&fw_log);
} else {
unsigned char log[cfg.log_len];
- err = nvme_get_log(log, cfg.log_len, cfg.log_id | (((cfg.log_len / 4) - 1) << 16),
- cfg.namespace_id);
+ err = nvme_log(fd, cfg.namespace_id, cfg.log_id, cfg.log_len, log);
if (!err) {
if (!cfg.raw_binary) {
printf("Device:%s log-id:%d namespace-id:%#x\n",
if (posix_memalign((void *)&cntlist, getpagesize(), 0x1000))
return ENOMEM;
- err = identify(cfg.namespace_id, cntlist,
- cfg.cntid << 16 | cfg.namespace_id ? 0x12 : 0x13);
+ err = nvme_identify_ctrl_list(fd, cfg.namespace_id, cfg.cntid, cntlist);
if (!err) {
for (i = 0; i < (min(cntlist->num, 2048)); i++)
printf("[%4u]:%#x\n", i, cntlist->identifier[i]);
get_dev(1, argc, argv);
- err = identify(cfg.namespace_id, ns_list, cfg.all ? 0x10 : 2);
+ err = nvme_identify_ns_list(fd, cfg.namespace_id, !!cfg.all, ns_list);
if (!err) {
for (i = 0; i < 1024; i++)
if (ns_list[i])
static int delete_ns(int argc, char **argv)
{
- struct nvme_admin_cmd cmd;
const char *desc = "delete-ns: delete the given namespace by "\
"sending a namespace management command to "\
"the given device. All controllers should be detached from "\
}
get_dev(1, argc, argv);
- memset(&cmd, 0, sizeof(cmd));
- cmd.opcode = nvme_admin_ns_mgmt;
- cmd.nsid = cfg.namespace_id;
- cmd.cdw10 = 1;
-
- err = ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd);
+ err = nvme_ns_delete(fd, cfg.namespace_id);
if (!err)
printf("%s: Success, deleted nsid:%d\n", commands[DELETE_NS].name,
cfg.namespace_id);
static int nvme_attach_ns(int argc, char **argv, int attach, const char *desc)
{
- struct nvme_controller_list *cntlist;
- struct nvme_admin_cmd cmd;
char *name = commands[attach ? ATTACH_NS : DETACH_NS].name;
- int err, i, list[2048];
+ int err, num, i, list[2048];
+ __u16 ctrlist[2048];
const char *namespace_id = "namespace to attach";
const char *cont = "optional comma-sep controllers list";
{0}
};
- if (posix_memalign((void *)&cntlist, getpagesize(), 0x1000))
- return ENOMEM;
- memset(cntlist, 0, sizeof(*cntlist));
-
argconfig_parse(argc, argv, desc, command_line_options,
&defaults, &cfg, sizeof(cfg));
-
if (!cfg.namespace_id) {
fprintf(stderr, "%s: namespace-id parameter required\n",
name);
return EINVAL;
}
- cntlist->num = argconfig_parse_comma_sep_array(cfg.cntlist,
+ num = argconfig_parse_comma_sep_array(cfg.cntlist,
list, 2047);
- for (i = 0; i < cntlist->num; i++)
- cntlist->identifier[i] = htole16((uint16_t)list[i]);
+ for (i = 0; i < num; i++)
+ ctrlist[i] = ((uint16_t)list[i]);
get_dev(1, argc, argv);
- memset(&cmd, 0, sizeof(cmd));
- cmd.opcode = nvme_admin_ns_attach;
- cmd.addr = (__u64)((unsigned long)cntlist);
- cmd.data_len = 4096;
- cmd.nsid = cfg.namespace_id;
- cmd.cdw10 = attach ? 0 : 1;
+ if (attach)
+ err = nvme_ns_attach_ctrls(fd, cfg.namespace_id, num, ctrlist);
+ else
+ err = nvme_ns_detach_ctrls(fd, cfg.namespace_id, num, ctrlist);
- err = ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd);
if (!err)
printf("%s: Success, nsid:%d\n", name, cfg.namespace_id);
else if (err > 0)
static int create_ns(int argc, char **argv)
{
- struct nvme_admin_cmd cmd;
- struct nvme_id_ns *ns;
const char *desc = "create-ns: send a namespace management command "\
"to the specified device to create a namespace with the given "\
"parameters. The next available namespace ID is used for the "\
"create operation. Note that create-ns does not attach the "\
"namespace to a controller, the attach-ns command is needed.";
int err = 0;
+ __u32 nsid;
struct config {
__u64 nsze;
get_dev(1, argc, argv);
- if (posix_memalign((void *)&ns, getpagesize(), 4096))
- return -ENOMEM;
- memset(ns, 0, sizeof(*ns));
- memset(&cmd, 0, sizeof(cmd));
-
- ns->nsze = cfg.nsze;
- ns->ncap = cfg.ncap;
- ns->flbas = cfg.flbas;
- ns->dps = cfg.dps;
- ns->nmic = cfg.nmic;
-
- cmd.opcode = nvme_admin_ns_mgmt;
- cmd.addr = (unsigned long)ns;
- cmd.data_len = 4096;
-
- err = ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd);
+ err = nvme_ns_create(fd, cfg.nsze, cfg.ncap, cfg.flbas, cfg.dps, cfg.nmic, &nsid);
if (!err)
printf("%s: Success, created nsid:%d\n", commands[CREATE_NS].name,
- cmd.result);
+ nsid);
else if (err > 0)
fprintf(stderr, "NVMe Status:%s(%x)\n",
nvme_status_to_string(err), err);
udev_enumerate_scan_devices(enumerate);
devices = udev_enumerate_get_list_entry(enumerate);
udev_list_entry_foreach(dev_list_entry, devices) {
-
+ int err;
const char *path, *node;
path = udev_list_entry_get_name(dev_list_entry);
dev = udev_device_new_from_syspath(udev, path);
node = udev_device_get_devnode(dev);
if (strstr(node,"nvme")!=NULL){
open_dev(node);
- int err = identify(0, &list_items[count].ctrl, 1);
+ err = nvme_identify_ctrl(fd, &list_items[count].ctrl);
if (err > 0)
return err;
- list_items[count].nsid = ioctl(fd, NVME_IOCTL_ID);
- err = identify(list_items[count].nsid,
- &list_items[count].ns, 0);
+ list_items[count].nsid = nvme_get_nsid(fd);
+ err = nvme_identify_ns(fd, list_items[count].nsid,
+ 0, &list_items[count].ns);
if (err > 0)
return err;
strcpy(list_items[count].node, node);
get_dev(1, argc, argv);
- err = identify(0, &ctrl, 1);
+ err = nvme_identify_ctrl(fd, &ctrl);
if (!err) {
if (cfg.raw_binary) {
d_raw((unsigned char *)&ctrl, sizeof(ctrl));
devicename);
exit(ENOTBLK);
}
- cfg.namespace_id = ioctl(fd, NVME_IOCTL_ID);
+ cfg.namespace_id = nvme_get_nsid(fd);
if (cfg.namespace_id <= 0) {
perror(devicename);
exit(errno);
}
}
- err = identify(cfg.namespace_id, &ns, 0);
+ err = nvme_identify_ns(fd, cfg.namespace_id, 0, &ns);
if (!err) {
if (cfg.raw_binary)
d_raw((unsigned char *)&ns, sizeof(ns));
devicename);
exit(ENOTBLK);
}
- nsid = ioctl(fd, NVME_IOCTL_ID);
+ nsid = nvme_get_nsid(fd);
if (nsid <= 0) {
perror(devicename);
exit(errno);
}
}
-static int nvme_feature(int opcode, void *buf, int data_len, __u32 fid,
- __u32 nsid, __u32 cdw11, __u32 *result)
-{
- int err;
- struct nvme_admin_cmd cmd;
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.opcode = opcode;
- cmd.nsid = nsid;
- cmd.cdw10 = fid;
- cmd.cdw11 = cdw11;
- cmd.addr = (__u64)((unsigned long)buf);
- cmd.data_len = data_len;
-
- err = ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd);
- if (err >= 0 && result)
- *result = cmd.result;
- return err;
-}
-
static int get_feature(int argc, char **argv)
{
const char *desc = "get-feature: read operating parameters of the "\
const char *cdw11 = "dword 11 for interrupt vector config";
const char *human_readable = "show infos in readable format";
int err;
- unsigned int result, cdw10 = 0;
+ __u32 result;
void *buf = NULL;
struct config {
if (cfg.data_len)
buf = malloc(cfg.data_len);
- cdw10 = cfg.sel << 8 | cfg.feature_id;
- err = nvme_feature(nvme_admin_get_features, buf, cfg.data_len, cdw10,
- cfg.namespace_id, cfg.cdw11, &result);
+ err = nvme_get_feature(fd, cfg.namespace_id, cfg.feature_id, cfg.sel, cfg.cdw11,
+ cfg.data_len, buf, &result);
if (!err) {
printf("get-feature: 0x%02X (%s), %s value: %#08x\n", cfg.feature_id,
nvme_feature_to_string(cfg.feature_id), nvme_select_to_string(cfg.sel), result);
int err, fw_fd = -1;
unsigned int fw_size;
struct stat sb;
- struct nvme_admin_cmd cmd;
void *fw_buf;
struct config {
while (fw_size > 0) {
cfg.xfer = min(cfg.xfer, fw_size);
- memset(&cmd, 0, sizeof(cmd));
- cmd.opcode = nvme_admin_download_fw;
- cmd.addr = (__u64)((unsigned long)fw_buf);
- cmd.data_len = cfg.xfer;
- cmd.cdw10 = (cfg.xfer >> 2) - 1;
- cmd.cdw11 = cfg.offset >> 2;
-
- err = ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd);
+ err = nvme_fw_download(fd, cfg.offset, cfg.xfer, fw_buf);
if (err < 0) {
- perror("ioctl");
+ perror("fw-download");
exit(errno);
} else if (err != 0) {
fprintf(stderr, "NVME Admin command error:%s(%x)\n",
const char *slot = "firmware slot to activate";
const char *action = "[0-2]: replacement action";
int err;
- struct nvme_admin_cmd cmd;
struct config {
__u8 slot;
return EINVAL;
}
- memset(&cmd, 0, sizeof(cmd));
- cmd.opcode = nvme_admin_activate_fw;
- cmd.cdw10 = (cfg.action << 3) | cfg.slot;
-
- err = ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd);
+ err = nvme_fw_activate(fd, cfg.slot, cfg.action);
if (err < 0)
- perror("ioctl");
+ perror("fw-activate");
else if (err != 0)
if (err == NVME_SC_FIRMWARE_NEEDS_RESET)
printf("Success activating firmware action:%d slot:%d, but a conventional reset is required\n",
return EINVAL;
}
if (S_ISBLK(nvme_stat.st_mode)) {
- cfg.namespace_id = ioctl(fd, NVME_IOCTL_ID);
+ cfg.namespace_id = nvme_get_nsid(fd);
if (cfg.namespace_id <= 0) {
fprintf(stderr,
"%s: failed to return namespace id\n",
cmd.cdw10 = (cfg.lbaf << 0) | (cfg.ms << 4) | (cfg.pi << 5) | (cfg.pil << 8) | (cfg.ses << 9);
cmd.timeout_ms = cfg.timeout;
- err = ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd);
+ err = nvme_format(fd, cfg.namespace_id, cfg.lbaf, cfg.ses, cfg.pi,
+ cfg.pil, cfg.ms, cfg.timeout);
if (err < 0)
- perror("ioctl");
+ perror("format");
else if (err != 0)
fprintf(stderr, "NVME Admin command error:%s(%x)\n",
nvme_status_to_string(err), err);
const char *data = "optional file (default stdin)";
const char *value = "new value of feature (req'd)";
int err;
- unsigned int result;
+ __u32 result;
void *buf = NULL;
int fd = STDIN_FILENO;
}
}
- err = nvme_feature(nvme_admin_set_features, buf, cfg.data_len, cfg.feature_id,
- cfg.namespace_id, cfg.value, &result);
+ err = nvme_set_feature(fd, cfg.namespace_id, cfg.feature_id, cfg.value, 0,
+ cfg.data_len, buf, &result);
if (!err) {
printf("set-feature:%d(%s), value:%#08x\n", cfg.feature_id,
nvme_feature_to_string(cfg.feature_id), result);
static int sec_send(int argc, char **argv)
{
struct stat sb;
- struct nvme_admin_cmd cmd;
const char *desc = "security-send: transfer security protocol data to "\
"a controller. Security Receives for the same protocol should be "\
"performed after Security Sends. The security protocol field "\
int err, sec_fd = -1;
void *sec_buf;
unsigned int sec_size;
+ __u32 result;
struct config {
char *file;
fprintf(stderr, "no firmware file provided\n");
return EINVAL;
}
+
err = fstat(sec_fd, &sb);
if (err < 0) {
perror("fstat");
return errno;
}
+
sec_size = sb.st_size;
if (posix_memalign(&sec_buf, getpagesize(), sec_size)) {
fprintf(stderr, "No memory for security size:%d\n", sec_size);
return ENOMEM;
}
- memset(&cmd, 0, sizeof(cmd));
- cmd.opcode = nvme_admin_security_send;
- cmd.cdw10 = cfg.secp << 24 | cfg.spsp << 8;
- cmd.cdw11 = cfg.tl;
- cmd.data_len = sec_size;
- cmd.addr = (__u64)((unsigned long)sec_buf);
-
- err = ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd);
+ err = nvme_sec_send(fd,
+ 0 /* FIXME: add nsid param */,
+ 0 /* FIXME: add nssf */,
+ cfg.spsp, cfg.secp, cfg.tl, sec_size, sec_buf, &result);
if (err < 0)
return errno;
else if (err != 0)
fprintf(stderr, "NVME Security Send Command Error:%d\n", err);
else
- printf("NVME Security Send Command Success:%d\n", cmd.result);
+ printf("NVME Security Send Command Success:%d\n", result);
return err;
}
static int dsm(int argc, char **argv)
{
- struct nvme_passthru_cmd cmd;
const char *desc = "dsm: The Dataset Management command is used by the host to "\
"indicate attributes for ranges of logical blocks. This includes attributes "\
"like frequency that data is read or written, access size, and other "\
const char *idr = "Attribute Integral Dataset for Read";
const char *cdw11 = "All the command command dword 11 attribuets. Use instead of specifying individual attributes";
- int i, err;
+ int err;
uint16_t nr, nc, nb, ns;
int ctx_attrs[256] = {0,};
int nlbs[256] = {0,};
unsigned long long slbas[256] = {0,};
- void *buffer;
struct nvme_dsm_range *dsm;
struct config {
devicename);
exit(ENOTBLK);
}
- cfg.namespace_id = ioctl(fd, NVME_IOCTL_ID);
+ cfg.namespace_id = nvme_get_nsid(fd);
if (cfg.namespace_id <= 0) {
fprintf(stderr,
"%s: failed to return namespace id\n",
if (!cfg.cdw11)
cfg.cdw11 = (cfg.ad << 2) | (cfg.idw << 1) | (cfg.idr << 0);
- buffer = malloc(nr * sizeof (struct nvme_dsm_range));
- if (!buffer)
- return ENOMEM;
-
- dsm = buffer;
- for (i = 0; i < nr; i++) {
- dsm[i].cattr = htole32((uint32_t)ctx_attrs[i]);
- dsm[i].nlb = htole32((uint32_t)nlbs[i]);
- dsm[i].slba = htole64((uint64_t)slbas[i]);
- }
+ dsm = nvme_setup_dsm_range((__u32 *)ctx_attrs, (__u32 *)nlbs, (__u64 *)slbas, nr);
- memset(&cmd, 0, sizeof(cmd));
- cmd.nsid = cfg.namespace_id;
- cmd.opcode = nvme_cmd_dsm;
- cmd.addr = (__u64)((unsigned long)buffer);
- cmd.data_len = nr * sizeof(struct nvme_dsm_range);
- cmd.cdw10 = nr - 1;
- cmd.cdw11 = cfg.cdw11;
-
- err = ioctl(fd, NVME_IOCTL_IO_CMD, &cmd);
+ err = nvme_dsm(fd, cfg.namespace_id, cfg.cdw11, dsm, nr);
if (err < 0) {
fprintf(stderr, "error:%x\n", err);
return errno;
static int flush(int argc, char **argv)
{
- struct nvme_passthru_cmd cmd;
const char *desc = "flush: commit data and metadata associated with "\
"given namespaces to nonvolatile media. Applies to all commands "\
"finished before the flush was submitted. Additional data may also be "\
get_dev(1, argc, argv);
- memset(&cmd, 0, sizeof(cmd));
- cmd.opcode = nvme_cmd_flush;
- cmd.nsid = cfg.namespace_id;
-
- err = ioctl(fd, NVME_IOCTL_IO_CMD, &cmd);
+ err = nvme_flush(fd, cfg.namespace_id);
if (err < 0)
return errno;
else if (err != 0)
static int resv_acquire(int argc, char **argv)
{
- struct nvme_passthru_cmd cmd;
const char *desc = "resv-acquire: obtain a reservation on a given "\
"namespace. Only one reservation is allowed at a time on a "\
"given namespace, though multiple controllers may register "\
const char *racqa = "reservation acquiry action";
const char *iekey = "ignore existing res. key";
int err;
- __u64 payload[2];
struct config {
__u32 namespace_id;
devicename);
exit(ENOTBLK);
}
- cfg.namespace_id = ioctl(fd, NVME_IOCTL_ID);
+ cfg.namespace_id = nvme_get_nsid(fd);
if (cfg.namespace_id <= 0) {
fprintf(stderr,
"%s: failed to return namespace id\n",
return EINVAL;
}
- payload[0] = cfg.crkey;
- payload[1] = cfg.prkey;
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.opcode = nvme_cmd_resv_acquire;
- cmd.nsid = cfg.namespace_id;
- cmd.cdw10 = cfg.rtype << 8 | cfg.iekey << 3 | cfg.racqa;
- cmd.addr = (__u64)((unsigned long)payload);
- cmd.data_len = sizeof(payload);
-
- err = ioctl(fd, NVME_IOCTL_IO_CMD, &cmd);
+ err = nvme_resv_acquire(fd, cfg.namespace_id, cfg.rtype, cfg.racqa,
+ !!cfg.iekey, cfg.crkey, cfg.prkey);
if (err < 0)
return errno;
else if (err != 0)
static int resv_register(int argc, char **argv)
{
- struct nvme_passthru_cmd cmd;
const char *desc = "resv-register: register, de-register, or "\
"replace a controller's reservation on a given namespace. "\
"Only one reservation at a time is allowed on any namespace.";
const char *rrega = "reservation registration action";
const char *cptpl = "change persistence through power loss setting";
int err;
- __u64 payload[2];
struct config {
__u32 namespace_id;
devicename);
exit(ENOTBLK);
}
- cfg.namespace_id = ioctl(fd, NVME_IOCTL_ID);
+ cfg.namespace_id = nvme_get_nsid(fd);
if (cfg.namespace_id <= 0) {
fprintf(stderr,
"%s: failed to return namespace id\n",
return EINVAL;
}
- payload[0] = cfg.crkey;
- payload[1] = cfg.nrkey;
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.opcode = nvme_cmd_resv_register;
- cmd.nsid = cfg.namespace_id;
- cmd.cdw10 = cfg.cptpl << 30 | cfg.iekey << 3 | cfg.rrega;
- cmd.addr = (__u64)((unsigned long)payload);
- cmd.data_len = sizeof(payload);
-
- err = ioctl(fd, NVME_IOCTL_IO_CMD, &cmd);
+ err = nvme_resv_register(fd, cfg.namespace_id, cfg.rrega, cfg.cptpl,
+ !!cfg.iekey, cfg.crkey, cfg.nrkey);
if (err < 0)
return errno;
else if (err != 0)
static int resv_release(int argc, char **argv)
{
- struct nvme_passthru_cmd cmd;
const char *desc = "resv-release: releases reservation held on a "\
"namespace by the given controller. If rtype != current reser"\
"vation type, release fails. If the given controller holds no "\
devicename);
exit(ENOTBLK);
}
- cfg.namespace_id = ioctl(fd, NVME_IOCTL_ID);
+ cfg.namespace_id = nvme_get_nsid(fd);
if (cfg.namespace_id <= 0) {
fprintf(stderr,
"%s: failed to return namespace id\n",
return EINVAL;
}
- memset(&cmd, 0, sizeof(cmd));
- cmd.opcode = nvme_cmd_resv_release;
- cmd.nsid = cfg.namespace_id;
- cmd.cdw10 = cfg.rtype << 8 | cfg.iekey << 3 | cfg.rrela;
- cmd.addr = (__u64)((unsigned long)&cfg.crkey);
- cmd.data_len = sizeof(cfg.crkey);
-
- err = ioctl(fd, NVME_IOCTL_IO_CMD, &cmd);
+ err = nvme_resv_release(fd, cfg.namespace_id, cfg.rtype, cfg.rrela,
+ !!cfg.iekey, cfg.crkey);
if (err < 0)
return errno;
else if (err != 0)
static int resv_report(int argc, char **argv)
{
- struct nvme_passthru_cmd cmd;
const char *desc = "resv-report: returns Reservation Status data "\
"structure describing any existing reservations on and the "\
"status of a given namespace. Namespace Reservation Status "\
devicename);
exit(ENOTBLK);
}
- cfg.namespace_id = ioctl(fd, NVME_IOCTL_ID);
+ cfg.namespace_id = nvme_get_nsid(fd);
if (cfg.namespace_id <= 0) {
fprintf(stderr,
"%s: failed to return namespace id\n",
return ENOMEM;
}
- memset(&cmd, 0, sizeof(cmd));
- cmd.opcode = nvme_cmd_resv_report;
- cmd.nsid = cfg.namespace_id;
- cmd.cdw10 = cfg.numd;
- cmd.addr = (__u64)((unsigned long)status);
- cmd.data_len = cfg.numd << 2;
-
- err = ioctl(fd, NVME_IOCTL_IO_CMD, &cmd);
+ err = nvme_resv_report(fd, cfg.namespace_id, cfg.numd, status);
if (err < 0)
return errno;
else if (err != 0)
static int submit_io(int opcode, char *command, const char *desc,
int argc, char **argv)
{
- struct nvme_user_io io;
struct timeval start_time, end_time;
void *buffer, *mbuffer = NULL;
int err = 0;
int dfd, mfd;
int flags = opcode & 1 ? O_RDONLY : O_WRONLY | O_CREAT;
int mode = S_IRUSR | S_IWUSR |S_IRGRP | S_IWGRP| S_IROTH;
+ __u16 control = 0;
const char *start_block = "64-bit addr of first block to access";
const char *block_count = "number of blocks on device to access";
argconfig_parse(argc, argv, desc, command_line_options,
&defaults, &cfg, sizeof(cfg));
- memset(&io, 0, sizeof(io));
-
- io.slba = cfg.start_block;
- io.nblocks = cfg.block_count;
- io.reftag = cfg.ref_tag;
- io.appmask = cfg.app_tag_mask;
- io.apptag = cfg.app_tag;
if (cfg.prinfo > 0xf)
return EINVAL;
- io.control |= (cfg.prinfo << 10);
+ control |= (cfg.prinfo << 10);
if (cfg.limited_retry)
- io.control |= NVME_RW_LR;
+ control |= NVME_RW_LR;
if (cfg.force_unit_access)
- io.control |= NVME_RW_FUA;
+ control |= NVME_RW_FUA;
if (strlen(cfg.data)){
dfd = open(cfg.data, flags, mode);
if (dfd < 0) {
fprintf(stderr, "data size not provided\n");
return EINVAL;
}
+
buffer = malloc(cfg.data_size);
- if (cfg.metadata_size)
+ if (!buffer)
+ return ENOMEM;
+
+ if (cfg.metadata_size) {
mbuffer = malloc(cfg.metadata_size);
+ if (!mbuffer)
+ return ENOMEM;
+ }
+
if ((opcode & 1) && read(dfd, (void *)buffer, cfg.data_size) < 0) {
fprintf(stderr, "failed to read data buffer from input file\n");
free(buffer);
return EINVAL;
}
+
if ((opcode & 1) && cfg.metadata_size &&
read(mfd, (void *)mbuffer, cfg.metadata_size) < 0) {
fprintf(stderr, "failed to read meta-data buffer from input file\n");
goto free_and_return;
}
- io.opcode = opcode;
- io.addr = (__u64)((unsigned long)buffer);
- if (cfg.metadata_size)
- io.metadata = (__u64)((unsigned long)mbuffer);
if (cfg.show) {
- printf("opcode : %02x\n", io.opcode);
- printf("flags : %02x\n", io.flags);
- printf("control : %04x\n", io.control);
- printf("nblocks : %04x\n", io.nblocks);
- printf("rsvd : %04x\n", io.rsvd);
- printf("metadata : %"PRIx64"\n", (uint64_t)io.metadata);
- printf("addr : %"PRIx64"\n", (uint64_t)io.addr);
- printf("sbla : %"PRIx64"\n", (uint64_t)io.slba);
- printf("dsmgmt : %08x\n", io.dsmgmt);
- printf("reftag : %08x\n", io.reftag);
- printf("apptag : %04x\n", io.apptag);
- printf("appmask : %04x\n", io.appmask);
+ printf("opcode : %02x\n", opcode);
+ printf("flags : %02x\n", 0);
+ printf("control : %04x\n", control);
+ printf("nblocks : %04x\n", cfg.block_count);
+ printf("rsvd : %04x\n", 0);
+ printf("metadata : %"PRIx64"\n", (uint64_t)mbuffer);
+ printf("addr : %"PRIx64"\n", (uint64_t)buffer);
+ printf("sbla : %"PRIx64"\n", (uint64_t)cfg.start_block);
+ printf("dsmgmt : %08x\n", 0);
+ printf("reftag : %08x\n", cfg.ref_tag);
+ printf("apptag : %04x\n", cfg.app_tag);
+ printf("appmask : %04x\n", cfg.app_tag_mask);
if (cfg.dry_run)
goto free_and_return;
}
gettimeofday(&start_time, NULL);
- err = ioctl(fd, NVME_IOCTL_SUBMIT_IO, &io);
+ err = nvme_io(fd, opcode, cfg.start_block, cfg.block_count, control, 0,
+ cfg.ref_tag, cfg.app_tag, cfg.app_tag_mask, buffer, mbuffer);
gettimeofday(&end_time, NULL);
if (cfg.latency)
fprintf(stdout, " latency: %s: %llu us\n",
command, elapsed_utime(start_time, end_time));
if (err < 0)
- perror("ioctl");
+ perror("submit-io");
else if (err)
printf("%s:%s(%04x)\n", command, nvme_status_to_string(err), err);
else {
const char *al = "allocation length (cf. SPC-4)";
const char *raw_binary = "dump output in binary format";
int err;
- struct nvme_admin_cmd cmd;
void *sec_buf = NULL;
+ __u32 result;
struct config {
__u32 size;
return ENOMEM;
}
}
- memset(&cmd, 0, sizeof(cmd));
- cmd.opcode = nvme_admin_security_recv;
- cmd.cdw10 = cfg.secp << 24 | cfg.spsp << 8;
- cmd.cdw11 = cfg.al;
- cmd.data_len = cfg.size;
- cmd.addr = (__u64)((unsigned long)sec_buf);
- err = ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd);
+ err = nvme_sec_recv(fd,
+ 0 /* FIXME: namespace_id */,
+ 0 /* FIXME: nssf */,
+ cfg.spsp, cfg.secp, cfg.al, cfg.size, sec_buf, &result);
if (err < 0)
return errno;
else if (err != 0)
else {
if (!cfg.raw_binary) {
printf("NVME Security Receive Command Success:%d\n",
- cmd.result);
+ result);
d(sec_buf, cfg.size, 16, 1);
} else if (cfg.size)
d_raw((unsigned char *)&sec_buf, cfg.size);
return err;
}
-static int nvme_passthru(int argc, char **argv, int ioctl_cmd)
+static int passthru(int argc, char **argv, int ioctl_cmd)
{
int err = 0, wfd = STDIN_FILENO;
const char *desc = "[io/admin]-passthru: send a user-specified IO or "\
"admin command to the specified device via IOCTL passthrough, "\
"return results";
- struct nvme_passthru_cmd cmd;
void *data = NULL, *metadata = NULL;
+ __u32 result;
struct config {
__u8 opcode;
{0}
};
- memset(&cmd, 0, sizeof(cmd));
argconfig_parse(argc, argv, desc, command_line_options,
&defaults, &cfg, sizeof(cfg));
- cmd.cdw2 = cfg.cdw2;
- cmd.cdw3 = cfg.cdw3;
- cmd.cdw10 = cfg.cdw10;
- cmd.cdw11 = cfg.cdw11;
- cmd.cdw12 = cfg.cdw12;
- cmd.cdw13 = cfg.cdw13;
- cmd.cdw14 = cfg.cdw14;
- cmd.cdw15 = cfg.cdw15;
- cmd.opcode = cfg.opcode;
- cmd.flags = cfg.flags;
- cmd.rsvd1 = cfg.rsvd;
- cmd.nsid = cfg.namespace_id;
- cmd.data_len = cfg.data_len;
- cmd.metadata_len = cfg.metadata_len;
- cmd.timeout_ms = cfg.timeout;
if (strlen(cfg.input_file)){
wfd = open(cfg.input_file, O_RDONLY,
S_IRUSR | S_IRGRP | S_IROTH);
return EINVAL;
}
}
+
get_dev(1, argc, argv);
- if (cmd.metadata_len) {
- metadata = malloc(cmd.metadata_len);
- cmd.metadata = (__u64)((unsigned long)metadata);
- }
- if (cmd.data_len) {
- data = malloc(cmd.data_len);
+ if (cfg.metadata_len)
+ metadata = malloc(cfg.metadata_len);
+ if (cfg.data_len) {
+ data = malloc(cfg.data_len);
if (!cfg.read && !cfg.write) {
fprintf(stderr, "data direction not given\n");
err = EINVAL;
goto free_and_return;
}
if (cfg.write) {
- if (read(wfd, data, cmd.data_len) < 0) {
+ if (read(wfd, data, cfg.data_len) < 0) {
fprintf(stderr, "failed to read write buffer\n");
err = EINVAL;
goto free_and_return;
}
}
- cmd.addr = (__u64)((unsigned long)data);
}
+
if (cfg.show_command) {
- printf("opcode : %02x\n", cmd.opcode);
- printf("flags : %02x\n", cmd.flags);
- printf("rsvd1 : %04x\n", cmd.rsvd1);
- printf("nsid : %08x\n", cmd.nsid);
- printf("cdw2 : %08x\n", cmd.cdw2);
- printf("cdw3 : %08x\n", cmd.cdw3);
- printf("data_len : %08x\n", cmd.data_len);
- printf("metadata_len : %08x\n", cmd.metadata_len);
- printf("addr : %"PRIx64"\n", (uint64_t)cmd.addr);
- printf("metadata : %"PRIx64"\n", (uint64_t)cmd.metadata);
- printf("cdw10 : %08x\n", cmd.cdw10);
- printf("cdw11 : %08x\n", cmd.cdw11);
- printf("cdw12 : %08x\n", cmd.cdw12);
- printf("cdw13 : %08x\n", cmd.cdw13);
- printf("cdw14 : %08x\n", cmd.cdw14);
- printf("cdw15 : %08x\n", cmd.cdw15);
- printf("timeout_ms : %08x\n", cmd.timeout_ms);
- if (cfg.dry_run) {
- err = 0;
+ printf("opcode : %02x\n", cfg.opcode);
+ printf("flags : %02x\n", cfg.flags);
+ printf("rsvd1 : %04x\n", cfg.rsvd);
+ printf("nsid : %08x\n", cfg.namespace_id);
+ printf("cdw2 : %08x\n", cfg.cdw2);
+ printf("cdw3 : %08x\n", cfg.cdw3);
+ printf("data_len : %08x\n", cfg.data_len);
+ printf("metadata_len : %08x\n", cfg.metadata_len);
+ printf("addr : %"PRIx64"\n", (uint64_t)data);
+ printf("metadata : %"PRIx64"\n", (uint64_t)metadata);
+ printf("cdw10 : %08x\n", cfg.cdw10);
+ printf("cdw11 : %08x\n", cfg.cdw11);
+ printf("cdw12 : %08x\n", cfg.cdw12);
+ printf("cdw13 : %08x\n", cfg.cdw13);
+ printf("cdw14 : %08x\n", cfg.cdw14);
+ printf("cdw15 : %08x\n", cfg.cdw15);
+ printf("timeout_ms : %08x\n", cfg.timeout);
+ if (cfg.dry_run)
goto free_and_return;
- }
}
- err = ioctl(fd, ioctl_cmd, &cmd);
- if (err >= 0) {
+
+ err = nvme_passthru(fd, ioctl_cmd, cfg.opcode, cfg.flags, cfg.rsvd,
+ cfg.namespace_id, cfg.cdw2, cfg.cdw3, cfg.cdw10,
+ cfg.cdw11, cfg.cdw12, cfg.cdw13, cfg.cdw14, cfg.cdw15,
+ cfg.data_len, data, cfg.metadata_len, metadata,
+ cfg.timeout, &result);
+ if (err < 0)
+ perror("passthru");
+ else if (err)
+ printf("NVMe Status:%s Command Result:%08x\n",
+ nvme_status_to_string(err), result);
+ else {
if (!cfg.raw_binary) {
- printf("NVMe Status:%s Command Result:%08x\n",
- nvme_status_to_string(err), cmd.result);
+ printf("NVMe command result:%08x\n", result);
if (data && cfg.read && !err)
- d((unsigned char *)data, cmd.data_len, 16, 1);
- } else if (!err && data && cfg.read)
- d_raw((unsigned char *)data, cmd.data_len);
- } else
- perror("ioctl");
+ d((unsigned char *)data, cfg.data_len, 16, 1);
+ } else if (data && cfg.read)
+ d_raw((unsigned char *)data, cfg.data_len);
+ }
return err;
free_and_return:
free(data);
static int io_passthru(int argc, char **argv)
{
- return nvme_passthru(argc, argv, NVME_IOCTL_IO_CMD);
+ return passthru(argc, argv, NVME_IOCTL_IO_CMD);
}
static int admin_passthru(int argc, char **argv)
{
- return nvme_passthru(argc, argv, NVME_IOCTL_ADMIN_CMD);
+ return passthru(argc, argv, NVME_IOCTL_ADMIN_CMD);
}
static void usage(char *cmd)