summaryrefslogtreecommitdiffstats
path: root/src/nvme/ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvme/ioctl.c')
-rw-r--r--src/nvme/ioctl.c272
1 files changed, 230 insertions, 42 deletions
diff --git a/src/nvme/ioctl.c b/src/nvme/ioctl.c
index b9710b3..9090b7e 100644
--- a/src/nvme/ioctl.c
+++ b/src/nvme/ioctl.c
@@ -13,9 +13,11 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <inttypes.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
+#include <sys/time.h>
#include <ccan/build_assert/build_assert.h>
#include <ccan/endian/endian.h>
@@ -23,6 +25,8 @@
#include "ioctl.h"
#include "util.h"
+static bool nvme_debug;
+
static int nvme_verify_chr(int fd)
{
static struct stat nvme_stat;
@@ -86,13 +90,62 @@ static int nvme_submit_passthru64(int fd, unsigned long ioctl_cmd,
return err;
}
+static void nvme_show_command(struct nvme_passthru_cmd *cmd, int err, struct timeval start,
+ struct timeval end)
+{
+ 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)(uintptr_t)cmd->addr);
+ printf("metadata : %"PRIx64"\n", (uint64_t)(uintptr_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);
+ printf("result : %08x\n", cmd->result);
+ printf("err : %d\n", err);
+ printf("latency : %lu us\n",
+ (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec));
+}
+
+void nvme_set_debug(bool debug)
+{
+ nvme_debug = debug;
+}
+
+bool nvme_get_debug(void)
+{
+ return nvme_debug;
+}
+
static int nvme_submit_passthru(int fd, unsigned long ioctl_cmd,
struct nvme_passthru_cmd *cmd, __u32 *result)
{
- int err = ioctl(fd, ioctl_cmd, cmd);
+ struct timeval start;
+ struct timeval end;
+ int err;
+
+ if (nvme_get_debug())
+ gettimeofday(&start, NULL);
+
+ err = ioctl(fd, ioctl_cmd, cmd);
+
+ if (nvme_get_debug()) {
+ gettimeofday(&end, NULL);
+ nvme_show_command(cmd, err, start, end);
+ }
if (err >= 0 && result)
*result = cmd->result;
+
return err;
}
@@ -532,16 +585,18 @@ int nvme_set_features_power_mgmt(int fd, __u8 ps, __u8 wh, bool save,
__u32 *result)
{
__u32 value = NVME_SET(ps, FEAT_PWRMGMT_PS) |
- NVME_SET(wh, FEAT_PWRMGMT_PS);
+ NVME_SET(wh, FEAT_PWRMGMT_WH);
return __nvme_set_features(fd, NVME_FEAT_FID_POWER_MGMT, value, save,
result);
}
-int nvme_set_features_lba_range(int fd, __u32 nsid, __u32 nr_ranges, bool save,
+int nvme_set_features_lba_range(int fd, __u32 nsid, __u8 nr_ranges, bool save,
struct nvme_lba_range_type *data, __u32 *result)
{
- return -1;
+ return nvme_set_features_data(
+ fd, NVME_FEAT_FID_LBA_RANGE, nsid, nr_ranges - 1, save,
+ sizeof(*data), data, result);
}
int nvme_set_features_temp_thresh(int fd, __u16 tmpth, __u8 tmpsel,
@@ -562,8 +617,8 @@ int nvme_set_features_err_recovery(int fd, __u32 nsid, __u16 tler, bool dulbe,
__u32 value = NVME_SET(tler, FEAT_ERROR_RECOVERY_TLER) |
NVME_SET(!!dulbe, FEAT_ERROR_RECOVERY_DULBE);
- return __nvme_set_features(fd, NVME_FEAT_FID_ERR_RECOVERY, value, save,
- result);
+ return nvme_set_features_simple(
+ fd, NVME_FEAT_FID_ERR_RECOVERY, nsid, value, save, result);
}
int nvme_set_features_volatile_wc(int fd, bool wce, bool save, __u32 *result)
@@ -577,8 +632,8 @@ int nvme_set_features_volatile_wc(int fd, bool wce, bool save, __u32 *result)
int nvme_set_features_irq_coalesce(int fd, __u8 thr, __u8 time, bool save,
__u32 *result)
{
- __u32 value = NVME_SET(thr, FEAT_IRQC_TIME) |
- NVME_SET(time, FEAT_IRQC_THR);
+ __u32 value = NVME_SET(thr, FEAT_IRQC_THR) |
+ NVME_SET(time, FEAT_IRQC_TIME);
return __nvme_set_features(fd, NVME_FEAT_FID_IRQ_COALESCE, value, save,
result);
@@ -612,19 +667,31 @@ int nvme_set_features_async_event(int fd, __u32 events,
int nvme_set_features_auto_pst(int fd, bool apste, bool save,
struct nvme_feat_auto_pst *apst, __u32 *result)
{
- __u32 value = NVME_SET(!!apste, FEAT_APST_APSTE);
+ struct nvme_set_features_args args = {
+ .args_size = sizeof(args),
+ .fd = fd,
+ .fid = NVME_FEAT_FID_AUTO_PST,
+ .nsid = NVME_NSID_NONE,
+ .cdw11 = NVME_SET(!!apste, FEAT_APST_APSTE),
+ .save = save,
+ .uuidx = NVME_UUID_NONE,
+ .data = apst,
+ .data_len = sizeof(*apst),
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = result,
+ };
- return __nvme_set_features(fd, NVME_FEAT_FID_AUTO_PST, value, save,
- result);
+ return nvme_set_features(&args);
}
int nvme_set_features_timestamp(int fd, bool save, __u64 timestamp)
{
__le64 t = cpu_to_le64(timestamp);
- struct nvme_timestamp ts;
+ struct nvme_timestamp ts = {};
struct nvme_set_features_args args = {
.args_size = sizeof(args),
.fd = fd,
+ .fid = NVME_FEAT_FID_TIMESTAMP,
.nsid = NVME_NSID_NONE,
.cdw11 = 0,
.cdw12 = 0,
@@ -694,8 +761,8 @@ int nvme_set_features_plm_config(int fd, bool plm, __u16 nvmsetid, bool save,
.save = save,
.uuidx = NVME_UUID_NONE,
.cdw15 = 0,
- .data_len = 0,
- .data = NULL,
+ .data_len = sizeof(*data),
+ .data = data,
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
.result = result,
};
@@ -746,7 +813,7 @@ int nvme_set_features_host_behavior(int fd, bool save,
.nsid = NVME_NSID_NONE,
.cdw11 = 0,
.cdw12 = 0,
- .save = save,
+ .save = false,
.uuidx = NVME_UUID_NONE,
.cdw15 = 0,
.data_len = sizeof(*data),
@@ -780,7 +847,7 @@ int nvme_set_features_sw_progress(int fd, __u8 pbslc, bool save,
result);
}
-int nvme_set_features_host_id(int fd, bool save, bool exhid, __u8 *hostid)
+int nvme_set_features_host_id(int fd, bool exhid, bool save, __u8 *hostid)
{
__u32 len = exhid ? 16 : 8;
__u32 value = !!exhid;
@@ -809,20 +876,42 @@ int nvme_set_features_resv_mask(int fd, __u32 mask, bool save, __u32 *result)
result);
}
+int nvme_set_features_resv_mask2(int fd, __u32 nsid, __u32 mask, bool save,
+ __u32 *result)
+{
+ return nvme_set_features_simple(
+ fd, NVME_FEAT_FID_RESV_MASK, nsid, mask, save, result);
+}
+
int nvme_set_features_resv_persist(int fd, bool ptpl, bool save, __u32 *result)
{
return __nvme_set_features(fd, NVME_FEAT_FID_RESV_PERSIST, !!ptpl, save,
result);
}
+int nvme_set_features_resv_persist2(int fd, __u32 nsid, bool ptpl, bool save,
+ __u32 *result)
+{
+ return nvme_set_features_simple(
+ fd, NVME_FEAT_FID_RESV_PERSIST, nsid, !!ptpl, save, result);
+}
+
int nvme_set_features_write_protect(int fd, enum nvme_feat_nswpcfg_state state,
bool save, __u32 *result)
{
return __nvme_set_features(fd, NVME_FEAT_FID_WRITE_PROTECT, state,
- save, result);
+ false, result);
+}
+
+int nvme_set_features_write_protect2(int fd, __u32 nsid,
+ enum nvme_feat_nswpcfg_state state,
+ bool save, __u32 *result)
+{
+ return nvme_set_features_simple(
+ fd, NVME_FEAT_FID_WRITE_PROTECT, nsid, state, false, result);
}
-int nvme_set_features_iocs_profile(int fd, __u8 iocsi, bool save)
+int nvme_set_features_iocs_profile(int fd, __u16 iocsi, bool save)
{
__u32 value = NVME_SET(iocsi, FEAT_IOCSP_IOCSCI);
@@ -898,8 +987,28 @@ int nvme_get_features_lba_range(int fd, enum nvme_get_features_sel sel,
.sel = sel,
.cdw11 = 0,
.uuidx = NVME_UUID_NONE,
- .data_len = 0,
- .data = NULL,
+ .data_len = sizeof(*data),
+ .data = data,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = result,
+ };
+
+ return nvme_get_features(&args);
+}
+
+int nvme_get_features_lba_range2(int fd, enum nvme_get_features_sel sel,
+ __u32 nsid, struct nvme_lba_range_type *data,
+ __u32 *result)
+{
+ struct nvme_get_features_args args = {
+ .args_size = sizeof(args),
+ .fd = fd,
+ .fid = NVME_FEAT_FID_LBA_RANGE,
+ .nsid = nsid,
+ .sel = sel,
+ .uuidx = NVME_UUID_NONE,
+ .data = data,
+ .data_len = sizeof(*data),
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
.result = result,
};
@@ -920,6 +1029,24 @@ int nvme_get_features_err_recovery(int fd, enum nvme_get_features_sel sel,
result);
}
+int nvme_get_features_err_recovery2(int fd, enum nvme_get_features_sel sel,
+ __u32 nsid, __u32 *result)
+{
+
+ struct nvme_get_features_args args = {
+ .args_size = sizeof(args),
+ .fd = fd,
+ .fid = NVME_FEAT_FID_ERR_RECOVERY,
+ .nsid = nsid,
+ .sel = sel,
+ .uuidx = NVME_UUID_NONE,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = result,
+ };
+
+ return nvme_get_features(&args);
+}
+
int nvme_get_features_volatile_wc(int fd, enum nvme_get_features_sel sel,
__u32 *result)
{
@@ -945,7 +1072,7 @@ int nvme_get_features_irq_config(int fd, enum nvme_get_features_sel sel,
struct nvme_get_features_args args = {
.args_size = sizeof(args),
.fd = fd,
- .fid = NVME_FEAT_FID_LBA_RANGE,
+ .fid = NVME_FEAT_FID_IRQ_CONFIG,
.nsid = NVME_NSID_NONE,
.sel = sel,
.cdw11 = iv,
@@ -978,13 +1105,13 @@ int nvme_get_features_auto_pst(int fd, enum nvme_get_features_sel sel,
struct nvme_get_features_args args = {
.args_size = sizeof(args),
.fd = fd,
- .fid = NVME_FEAT_FID_LBA_RANGE,
+ .fid = NVME_FEAT_FID_AUTO_PST,
.nsid = NVME_NSID_NONE,
.sel = sel,
.cdw11 = 0,
.uuidx = NVME_UUID_NONE,
- .data_len = 0,
- .data = NULL,
+ .data_len = sizeof(*apst),
+ .data = apst,
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
.result = result,
};
@@ -998,6 +1125,26 @@ int nvme_get_features_host_mem_buf(int fd, enum nvme_get_features_sel sel,
return __nvme_get_features(fd, NVME_FEAT_FID_HOST_MEM_BUF, sel, result);
}
+int nvme_get_features_host_mem_buf2(int fd, enum nvme_get_features_sel sel,
+ struct nvme_host_mem_buf_attrs *attrs,
+ __u32 *result)
+{
+ struct nvme_get_features_args args = {
+ .args_size = sizeof(args),
+ .fd = fd,
+ .fid = NVME_FEAT_FID_HOST_MEM_BUF,
+ .nsid = NVME_NSID_NONE,
+ .sel = sel,
+ .uuidx = NVME_UUID_NONE,
+ .data = attrs,
+ .data_len = sizeof(*attrs),
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = result,
+ };
+
+ return nvme_get_features(&args);
+}
+
int nvme_get_features_timestamp(int fd, enum nvme_get_features_sel sel,
struct nvme_timestamp *ts)
{
@@ -1050,8 +1197,8 @@ int nvme_get_features_plm_config(int fd, enum nvme_get_features_sel sel,
.sel = sel,
.cdw11 = nvmsetid,
.uuidx = NVME_UUID_NONE,
- .data_len = 0,
- .data = NULL,
+ .data_len = sizeof(*data),
+ .data = data,
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
.result = result,
};
@@ -1098,8 +1245,8 @@ int nvme_get_features_host_behavior(int fd, enum nvme_get_features_sel sel,
.sel = sel,
.cdw11 = 0,
.uuidx = NVME_UUID_NONE,
- .data_len = 0,
- .data = NULL,
+ .data_len = sizeof(*data),
+ .data = data,
.timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
.result = result,
};
@@ -1122,7 +1269,7 @@ int nvme_get_features_endurance_event_cfg(int fd, enum nvme_get_features_sel sel
.fid = NVME_FEAT_FID_ENDURANCE_EVT_CFG,
.nsid = NVME_NSID_NONE,
.sel = sel,
- .cdw11 = 0,
+ .cdw11 = endgid,
.uuidx = NVME_UUID_NONE,
.data_len = 0,
.data = NULL,
@@ -1165,12 +1312,46 @@ int nvme_get_features_resv_mask(int fd, enum nvme_get_features_sel sel,
return __nvme_get_features(fd, NVME_FEAT_FID_RESV_MASK, sel, result);
}
+int nvme_get_features_resv_mask2(int fd, enum nvme_get_features_sel sel,
+ __u32 nsid, __u32 *result)
+{
+ struct nvme_get_features_args args = {
+ .args_size = sizeof(args),
+ .fd = fd,
+ .fid = NVME_FEAT_FID_RESV_MASK,
+ .nsid = nsid,
+ .sel = sel,
+ .uuidx = NVME_UUID_NONE,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = result,
+ };
+
+ return nvme_get_features(&args);
+}
+
int nvme_get_features_resv_persist(int fd, enum nvme_get_features_sel sel,
__u32 *result)
{
return __nvme_get_features(fd, NVME_FEAT_FID_RESV_PERSIST, sel, result);
}
+int nvme_get_features_resv_persist2(int fd, enum nvme_get_features_sel sel,
+ __u32 nsid, __u32 *result)
+{
+ struct nvme_get_features_args args = {
+ .args_size = sizeof(args),
+ .fd = fd,
+ .fid = NVME_FEAT_FID_RESV_PERSIST,
+ .nsid = nsid,
+ .sel = sel,
+ .uuidx = NVME_UUID_NONE,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = result,
+ };
+
+ return nvme_get_features(&args);
+}
+
int nvme_get_features_write_protect(int fd, __u32 nsid,
enum nvme_get_features_sel sel,
__u32 *result)
@@ -1387,6 +1568,7 @@ int nvme_get_lba_status(struct nvme_get_lba_status_args *args)
.opcode = nvme_admin_get_lba_status,
.nsid = args->nsid,
.addr = (__u64)(uintptr_t)args->lbas,
+ .data_len = (args->mndw + 1) << 2,
.cdw10 = cdw10,
.cdw11 = cdw11,
.cdw12 = cdw12,
@@ -1655,33 +1837,35 @@ static int nvme_set_var_size_tags(__u32 *cmd_dw2, __u32 *cmd_dw3, __u32 *cmd_dw1
__u8 pif, __u8 sts, __u64 reftag, __u64 storage_tag)
{
__u32 cdw2 = 0, cdw3 = 0, cdw14;
+ beint64_t be_reftag = cpu_to_be64(reftag);
+ beint64_t be_storage_tag = cpu_to_be64(storage_tag);
switch (pif) {
/* 16b Protection Information */
case 0:
- cdw14 = reftag & 0xffffffff;
- cdw14 |= ((storage_tag << (32 - sts)) & 0xffffffff);
+ cdw14 = be_reftag & 0xffffffff;
+ cdw14 |= ((be_storage_tag << (32 - sts)) & 0xffffffff);
break;
/* 32b Protection Information */
case 1:
- cdw14 = reftag & 0xffffffff;
- cdw3 = reftag >> 32;
- cdw14 |= ((storage_tag << (80 - sts)) & 0xffff0000);
+ cdw14 = be_reftag & 0xffffffff;
+ cdw3 = be_reftag >> 32;
+ cdw14 |= ((be_storage_tag << (80 - sts)) & 0xffff0000);
if (sts >= 48)
- cdw3 |= ((storage_tag >> (sts - 48)) & 0xffffffff);
+ cdw3 |= ((be_storage_tag >> (sts - 48)) & 0xffffffff);
else
- cdw3 |= ((storage_tag << (48 - sts)) & 0xffffffff);
- cdw2 = (storage_tag >> (sts - 16)) & 0xffff;
+ cdw3 |= ((be_storage_tag << (48 - sts)) & 0xffffffff);
+ cdw2 = (be_storage_tag >> (sts - 16)) & 0xffff;
break;
/* 64b Protection Information */
case 2:
- cdw14 = reftag & 0xffffffff;
- cdw3 = (reftag >> 32) & 0xffff;
- cdw14 |= ((storage_tag << (48 - sts)) & 0xffffffff);
+ cdw14 = be_reftag & 0xffffffff;
+ cdw3 = (be_reftag >> 32) & 0xffff;
+ cdw14 |= ((be_storage_tag << (48 - sts)) & 0xffffffff);
if (sts >= 16)
- cdw3 |= ((storage_tag >> (sts - 16)) & 0xffff);
+ cdw3 |= ((be_storage_tag >> (sts - 16)) & 0xffff);
else
- cdw3 |= ((storage_tag << (16 - sts)) & 0xffff);
+ cdw3 |= ((be_storage_tag << (16 - sts)) & 0xffff);
break;
default:
perror("Unsupported Protection Information Format");
@@ -1793,6 +1977,10 @@ int nvme_copy(struct nvme_copy_args *args)
if (args->format == 1)
data_len = args->nr * sizeof(struct nvme_copy_range_f1);
+ else if (args->format == 2)
+ data_len = args->nr * sizeof(struct nvme_copy_range_f2);
+ else if (args->format == 3)
+ data_len = args->nr * sizeof(struct nvme_copy_range_f3);
else
data_len = args->nr * sizeof(struct nvme_copy_range);