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.c185
1 files changed, 145 insertions, 40 deletions
diff --git a/src/nvme/ioctl.c b/src/nvme/ioctl.c
index f48b465..3333993 100644
--- a/src/nvme/ioctl.c
+++ b/src/nvme/ioctl.c
@@ -195,7 +195,7 @@ int nvme_admin_passthru(int fd, __u8 opcode, __u8 flags, __u16 rsvd,
enum nvme_cmd_dword_fields {
NVME_DEVICE_SELF_TEST_CDW10_STC_SHIFT = 0,
- NVME_DEVICE_SELF_TEST_CDW10_STC_MASK = 0x7,
+ NVME_DEVICE_SELF_TEST_CDW10_STC_MASK = 0xf,
NVME_DIRECTIVE_CDW11_DOPER_SHIFT = 0,
NVME_DIRECTIVE_CDW11_DTYPE_SHIFT = 8,
NVME_DIRECTIVE_CDW11_DPSEC_SHIFT = 16,
@@ -230,11 +230,11 @@ enum nvme_cmd_dword_fields {
NVME_LOG_CDW14_CSI_SHIFT = 24,
NVME_LOG_CDW14_OT_SHIFT = 23,
NVME_LOG_CDW10_LID_MASK = 0xff,
- NVME_LOG_CDW10_LSP_MASK = 0xf,
+ NVME_LOG_CDW10_LSP_MASK = 0x7f,
NVME_LOG_CDW10_RAE_MASK = 0x1,
NVME_LOG_CDW10_NUMDL_MASK = 0xffff,
NVME_LOG_CDW11_NUMDU_MASK = 0xffff,
- NVME_LOG_CDW11_LSI_MASK = 0xff,
+ NVME_LOG_CDW11_LSI_MASK = 0xffff,
NVME_LOG_CDW14_UUID_MASK = 0x7f,
NVME_LOG_CDW14_CSI_MASK = 0xff,
NVME_LOG_CDW14_OT_MASK = 0x1,
@@ -267,11 +267,13 @@ enum nvme_cmd_dword_fields {
NVME_FORMAT_CDW10_PI_SHIFT = 5,
NVME_FORMAT_CDW10_PIL_SHIFT = 8,
NVME_FORMAT_CDW10_SES_SHIFT = 9,
+ NVME_FORMAT_CDW10_LBAFU_SHIFT = 12,
NVME_FORMAT_CDW10_LBAF_MASK = 0xf,
NVME_FORMAT_CDW10_MSET_MASK = 0x1,
NVME_FORMAT_CDW10_PI_MASK = 0x7,
NVME_FORMAT_CDW10_PIL_MASK = 0x1,
NVME_FORMAT_CDW10_SES_MASK = 0x7,
+ NVME_FORMAT_CDW10_LBAFU_MASK = 0x3,
NVME_SANITIZE_CDW10_SANACT_SHIFT = 0,
NVME_SANITIZE_CDW10_AUSE_SHIFT = 3,
NVME_SANITIZE_CDW10_OWPASS_SHIFT = 4,
@@ -1159,11 +1161,25 @@ int nvme_get_features_iocs_profile(int fd, enum nvme_get_features_sel sel,
int nvme_format_nvm(struct nvme_format_nvm_args *args)
{
- __u32 cdw10 = NVME_SET(args->lbaf, FORMAT_CDW10_LBAF) |
- NVME_SET(args->mset, FORMAT_CDW10_MSET) |
- NVME_SET(args->pi, FORMAT_CDW10_PI) |
- NVME_SET(args->pil, FORMAT_CDW10_PIL) |
- NVME_SET(args->ses, FORMAT_CDW10_SES);
+ const size_t size_v1 = sizeof_args(struct nvme_format_nvm_args, lbaf, __u64);
+ const size_t size_v2 = sizeof_args(struct nvme_format_nvm_args, lbafu, __u64);
+ __u32 cdw10;
+
+ if (args->args_size < size_v1 || args->args_size > size_v2) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ cdw10 = NVME_SET(args->lbaf, FORMAT_CDW10_LBAF) |
+ NVME_SET(args->mset, FORMAT_CDW10_MSET) |
+ NVME_SET(args->pi, FORMAT_CDW10_PI) |
+ NVME_SET(args->pil, FORMAT_CDW10_PIL) |
+ NVME_SET(args->ses, FORMAT_CDW10_SES);
+
+ if (args->args_size == size_v2) {
+ /* set lbafu extension */
+ cdw10 |= NVME_SET(args->lbafu, FORMAT_CDW10_LBAFU);
+ }
struct nvme_passthru_cmd cmd = {
.opcode = nvme_admin_format_nvm,
@@ -1172,10 +1188,6 @@ int nvme_format_nvm(struct nvme_format_nvm_args *args)
.timeout_ms = args->timeout,
};
- if (args->args_size < sizeof(*args)) {
- errno = EINVAL;
- return -1;
- }
return nvme_submit_admin_passthru(args->fd, &cmd, args->result);
}
@@ -1588,16 +1600,81 @@ int nvme_io_passthru(int fd, __u8 opcode, __u8 flags, __u16 rsvd,
timeout_ms, result);
}
+static int nvme_set_var_size_tags(__u32 *cmd_dw2, __u32 *cmd_dw3, __u32 *cmd_dw14,
+ __u8 pif, __u8 sts, __u64 reftag, __u64 storage_tag)
+{
+ __u32 cdw2 = 0, cdw3 = 0, cdw14;
+
+ switch (pif) {
+ /* 16b Protection Information */
+ case 0:
+ cdw14 = reftag & 0xffffffff;
+ cdw14 |= ((storage_tag << (32 - sts)) & 0xffffffff);
+ break;
+ /* 32b Protection Information */
+ case 1:
+ cdw14 = reftag & 0xffffffff;
+ cdw3 = reftag >> 32;
+ cdw14 |= ((storage_tag << (80 - sts)) & 0xffff0000);
+ if (sts >= 48)
+ cdw3 |= ((storage_tag >> (sts - 48)) & 0xffffffff);
+ else
+ cdw3 |= ((storage_tag << (48 - sts)) & 0xffffffff);
+ cdw2 = (storage_tag >> (sts - 16)) & 0xffff;
+ break;
+ /* 64b Protection Information */
+ case 2:
+ cdw14 = reftag & 0xffffffff;
+ cdw3 = (reftag >> 32) & 0xffff;
+ cdw14 |= ((storage_tag << (48 - sts)) & 0xffffffff);
+ if (sts >= 16)
+ cdw3 |= ((storage_tag >> (sts - 16)) & 0xffff);
+ else
+ cdw3 |= ((storage_tag << (16 - sts)) & 0xffff);
+ break;
+ default:
+ perror("Unsupported Protection Information Format");
+ errno = EINVAL;
+ return -1;
+ }
+
+ *cmd_dw2 = cdw2;
+ *cmd_dw3 = cdw3;
+ *cmd_dw14 = cdw14;
+ return 0;
+}
+
int nvme_io(struct nvme_io_args *args, __u8 opcode)
{
- __u32 cdw2 = args->storage_tag & 0xffffffff;
- __u32 cdw3 = (args->storage_tag >> 32) & 0xffff;
- __u32 cdw10 = args->slba & 0xffffffff;
- __u32 cdw11 = args->slba >> 32;
- __u32 cdw12 = args->nlb | (args->control << 16);
- __u32 cdw13 = args->dsm | (args->dspec << 16);
- __u32 cdw14 = args->reftag;
- __u32 cdw15 = args->apptag | (args->appmask << 16);
+ const size_t size_v1 = sizeof_args(struct nvme_io_args, dsm, __u64);
+ const size_t size_v2 = sizeof_args(struct nvme_io_args, pif, __u64);
+ __u32 cdw2, cdw3, cdw10, cdw11, cdw12, cdw13, cdw14, cdw15;
+
+ if (args->args_size < size_v1 || args->args_size > size_v2) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ cdw10 = args->slba & 0xffffffff;
+ cdw11 = args->slba >> 32;
+ cdw12 = args->nlb | (args->control << 16);
+ cdw13 = args->dsm | (args->dspec << 16);
+ cdw15 = args->apptag | (args->appmask << 16);
+
+ if (args->args_size == size_v1) {
+ cdw2 = (args->storage_tag >> 32) & 0xffff;
+ cdw3 = args->storage_tag & 0xffffffff;
+ cdw14 = args->reftag;
+ } else {
+ if (nvme_set_var_size_tags(&cdw2, &cdw3, &cdw14,
+ args->pif,
+ args->sts,
+ args->reftag_u64,
+ args->storage_tag)) {
+ errno = EINVAL;
+ return -1;
+ }
+ }
struct nvme_passthru_cmd cmd = {
.opcode = opcode,
@@ -1617,10 +1694,6 @@ int nvme_io(struct nvme_io_args *args, __u8 opcode)
.timeout_ms = args->timeout,
};
- if (args->args_size < sizeof(*args)) {
- errno = EINVAL;
- return -1;
- }
return nvme_submit_io_passthru(args->fd, &cmd, args->result);
}
@@ -1645,29 +1718,48 @@ int nvme_dsm(struct nvme_dsm_args *args)
int nvme_copy(struct nvme_copy_args *args)
{
- __u32 cdw12 = ((args->nr - 1) & 0xff) | ((args->format & 0xf) << 8) |
+ const size_t size_v1 = sizeof_args(struct nvme_copy_args, format, __u64);
+ const size_t size_v2 = sizeof_args(struct nvme_copy_args, ilbrt_u64, __u64);
+ __u32 cdw3, cdw12, cdw14, data_len;
+
+ if (args->args_size < size_v1 || args->args_size > size_v2) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ cdw12 = ((args->nr - 1) & 0xff) | ((args->format & 0xf) << 8) |
((args->prinfor & 0xf) << 12) | ((args->dtype & 0xf) << 20) |
((args->prinfow & 0xf) << 26) | ((args->fua & 0x1) << 30) |
((args->lr & 0x1) << 31);
+ if (args->args_size == size_v1) {
+ cdw3 = 0;
+ cdw14 = args->ilbrt;
+ } else {
+ cdw3 = (args->ilbrt_u64 >> 32) & 0xffffffff;
+ cdw14 = args->ilbrt_u64 & 0xffffffff;
+ }
+
+ if (args->format == 1)
+ data_len = args->nr * sizeof(struct nvme_copy_range_f1);
+ else
+ data_len = args->nr * sizeof(struct nvme_copy_range);
+
struct nvme_passthru_cmd cmd = {
.opcode = nvme_cmd_copy,
.nsid = args->nsid,
.addr = (__u64)(uintptr_t)args->copy,
- .data_len = args->nr * sizeof(*args->copy),
+ .data_len = data_len,
+ .cdw3 = cdw3,
.cdw10 = args->sdlba & 0xffffffff,
.cdw11 = args->sdlba >> 32,
.cdw12 = cdw12,
.cdw13 = (args->dspec & 0xffff) << 16,
- .cdw14 = args->ilbrt,
+ .cdw14 = cdw14,
.cdw15 = (args->lbatm << 16) | args->lbat,
.timeout_ms = args->timeout,
};
- if (args->args_size < sizeof(*args)) {
- errno = EINVAL;
- return -1;
- }
return nvme_submit_io_passthru(args->fd, &cmd, args->result);
}
@@ -1821,15 +1913,32 @@ int nvme_zns_mgmt_recv(struct nvme_zns_mgmt_recv_args *args)
int nvme_zns_append(struct nvme_zns_append_args *args)
{
- __u32 cdw10 = args->zslba & 0xffffffff;
- __u32 cdw11 = args->zslba >> 32;
- __u32 cdw12 = args->nlb | (args->control << 16);
- __u32 cdw14 = args->ilbrt;
- __u32 cdw15 = args->lbat | (args->lbatm << 16);
+ const size_t size_v1 = sizeof_args(struct nvme_zns_append_args, lbatm, __u64);
+ const size_t size_v2 = sizeof_args(struct nvme_zns_append_args, ilbrt_u64, __u64);
+ __u32 cdw3, cdw10, cdw11, cdw12, cdw14, cdw15;
+
+ if (args->args_size < size_v1 || args->args_size > size_v2) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ cdw10 = args->zslba & 0xffffffff;
+ cdw11 = args->zslba >> 32;
+ cdw12 = args->nlb | (args->control << 16);
+ cdw15 = args->lbat | (args->lbatm << 16);
+
+ if (args->args_size == size_v1) {
+ cdw3 = 0;
+ cdw14 = args->ilbrt;
+ } else {
+ cdw3 = (args->ilbrt_u64 >> 32) & 0xffffffff;
+ cdw14 = args->ilbrt_u64 & 0xffffffff;
+ }
struct nvme_passthru_cmd64 cmd = {
.opcode = nvme_zns_cmd_append,
.nsid = args->nsid,
+ .cdw3 = cdw3,
.cdw10 = cdw10,
.cdw11 = cdw11,
.cdw12 = cdw12,
@@ -1842,10 +1951,6 @@ int nvme_zns_append(struct nvme_zns_append_args *args)
.timeout_ms = args->timeout,
};
- if (args->args_size < sizeof(*args)) {
- errno = EINVAL;
- return -1;
- }
return nvme_submit_io_passthru64(args->fd, &cmd, args->result);
}