From 1e446235993a188a74fdd502385fdb55087fc2b4 Mon Sep 17 00:00:00 2001 From: Steven Seungcheol Lee Date: Fri, 23 Jan 2026 17:46:32 +0900 Subject: [PATCH] mi: Add ISH bit (admin command cflags) Add ish bit for mi admin commands that access media Spec NVM-Express-Management-Interface-Specification -Revision-2.1-2025.08.01-Ratified Figure 136: NVMe Admin Command Request Description Command Flags (CFLGS): Bit 2 : Ignore Shutdown (ISH) This bit shall have no effect on the value of the CSTS.SHST field. (193 page from spec) If an NVMe Admin Command does not require access to media, then the ISH bit shall have no effect on the processing of that NVMe Admin Command. spec NVM-Express-Base-Specification-Revision-2.3-2025.08.01-Ratified Figure 84: Admin Commands Permitted to Return a Status Code of Admin Command Media Not Ready From Figure 84, we can assume that below Admin commands access media Capacity Management, Device Self-test, Firmware Commit, Firmware Image Download, Get LBA Status, Get Log Page, Namespace Attachment, Namespace Management, Format NVM, Sanitize, Sanitize Namespace, Security Receive, Security Send, Vendor Specific Signed-off-by: Steven Seungcheol Lee Reported-by: Hojin Ahn --- src/nvme/api-types.h | 18 ++++++++++++ src/nvme/ioctl.c | 37 ++++++++++++++++++------- src/nvme/mi.c | 66 +++++++++++++++++++++++++++++++++++--------- 3 files changed, 98 insertions(+), 23 deletions(-) diff --git a/src/nvme/api-types.h b/src/nvme/api-types.h index 149ba22c7..08c584a2f 100644 --- a/src/nvme/api-types.h +++ b/src/nvme/api-types.h @@ -74,6 +74,7 @@ struct nvme_identify_args { * @ot: Offset Type; if set @lpo specifies the index into the list * of data structures, otherwise @lpo specifies the byte offset * into the log page. + * @ish: Ignore Shutdown (for NVMe-MI command) */ struct nvme_get_log_args { __u64 lpo; @@ -91,6 +92,7 @@ struct nvme_get_log_args { __u8 uuidx; bool rae; bool ot; + bool ish; }; /** @@ -171,6 +173,7 @@ struct nvme_get_features_args { * @lbaf: Logical block address format least significant 4 bits * @rsvd1: Reserved * @lbafu: Logical block address format most significant 2 bits + * @ish: Ignore Shutdown (for NVMe-MI command) */ struct nvme_format_nvm_args { __u32 *result; @@ -185,6 +188,7 @@ struct nvme_format_nvm_args { __u8 lbaf; __u8 rsvd1[7]; __u8 lbafu; + bool ish; }; /** @@ -200,6 +204,7 @@ struct nvme_format_nvm_args { * @rsvd1: Reserved * @rsvd2: Reserved * @data: Host Software Specified Fields + * @ish: Ignore Shutdown (for NVMe-MI command) */ struct nvme_ns_mgmt_args { __u32 *result; @@ -213,6 +218,7 @@ struct nvme_ns_mgmt_args { __u8 rsvd1[3]; void *rsvd2; struct nvme_ns_mgmt_host_sw_specified *data; + bool ish; }; /** @@ -224,6 +230,7 @@ struct nvme_ns_mgmt_args { * @timeout: Timeout in ms * @nsid: Namespace ID to execute attach selection * @sel: Attachment selection, see &enum nvme_ns_attach_sel + * @ish: Ignore Shutdown (for NVMe-MI command) */ struct nvme_ns_attach_args { __u32 *result; @@ -233,6 +240,7 @@ struct nvme_ns_attach_args { __u32 timeout; __u32 nsid; enum nvme_ns_attach_sel sel; + bool ish; }; /** @@ -244,6 +252,7 @@ struct nvme_ns_attach_args { * @offset: Offset in the firmware data * @data: Userspace address of the firmware data * @data_len: Length of data in this command in bytes + * @ish: Ignore Shutdown (for NVMe-MI command) */ struct nvme_fw_download_args { __u32 *result; @@ -253,6 +262,7 @@ struct nvme_fw_download_args { __u32 timeout; __u32 offset; __u32 data_len; + bool ish; }; /** @@ -264,6 +274,7 @@ struct nvme_fw_download_args { * @result: The command completion result from CQE dword0 * @slot: Firmware slot to commit the downloaded image * @bpid: Set to true to select the boot partition id + * @ish: Ignore Shutdown (for NVMe-MI command) */ struct nvme_fw_commit_args { __u32 *result; @@ -273,6 +284,7 @@ struct nvme_fw_commit_args { enum nvme_fw_commit_ca action; __u8 slot; bool bpid; + bool ish; }; /** @@ -289,6 +301,7 @@ struct nvme_fw_commit_args { * @spsp0: Security Protocol Specific field * @spsp1: Security Protocol Specific field * @secp: Security Protocol + * @ish: Ignore Shutdown (for NVMe-MI command) */ struct nvme_security_send_args { __u32 *result; @@ -303,6 +316,7 @@ struct nvme_security_send_args { __u8 spsp0; __u8 spsp1; __u8 secp; + bool ish; }; /** @@ -319,6 +333,7 @@ struct nvme_security_send_args { * @spsp0: Security Protocol Specific field * @spsp1: Security Protocol Specific field * @secp: Security Protocol + * @ish: Ignore Shutdown (for NVMe-MI command) */ struct nvme_security_receive_args { __u32 *result; @@ -333,6 +348,7 @@ struct nvme_security_receive_args { __u8 spsp0; __u8 spsp1; __u8 secp; + bool ish; }; /** @@ -513,6 +529,7 @@ struct nvme_get_property_args { * @oipbp: Set to overwrite invert pattern between passes * @nodas: Set to not deallocate blocks after sanitizing * @emvs: Set to enter media verification state + * @ish: Ignore Shutdown (for NVMe-MI command) */ struct nvme_sanitize_nvm_args { __u32 *result; @@ -526,6 +543,7 @@ struct nvme_sanitize_nvm_args { bool oipbp; bool nodas; bool emvs; + bool ish; }; /** diff --git a/src/nvme/ioctl.c b/src/nvme/ioctl.c index a887ae483..7fc14bd9c 100644 --- a/src/nvme/ioctl.c +++ b/src/nvme/ioctl.c @@ -285,6 +285,8 @@ int nvme_identify(struct nvme_identify_args *args) int nvme_get_log(struct nvme_get_log_args *args) { + const size_t size_v1 = sizeof_args(struct nvme_get_log_args, ot, __u64); + const size_t size_v2 = sizeof_args(struct nvme_get_log_args, ish, __u64); __u32 numd = (args->len >> 2) - 1; __u16 numdu = numd >> 16, numdl = numd & 0xffff; @@ -313,7 +315,7 @@ int nvme_get_log(struct nvme_get_log_args *args) .timeout_ms = args->timeout, }; - if (args->args_size < sizeof(struct nvme_get_log_args)) { + if (args->args_size < size_v1 || args->args_size > size_v2) { errno = EINVAL; return -1; } @@ -373,6 +375,8 @@ static void nvme_uring_cmd_exit(struct io_uring *ring) static int nvme_uring_cmd_admin_passthru_async(struct io_uring *ring, struct nvme_get_log_args *args) { + const size_t size_v1 = sizeof_args(struct nvme_get_log_args, ot, __u64); + const size_t size_v2 = sizeof_args(struct nvme_get_log_args, ish, __u64); struct io_uring_sqe *sqe; struct nvme_uring_cmd *cmd; int ret; @@ -392,7 +396,7 @@ static int nvme_uring_cmd_admin_passthru_async(struct io_uring *ring, struct nvm NVME_SET(!!args->ot, LOG_CDW14_OT) | NVME_SET(args->csi, LOG_CDW14_CSI); - if (args->args_size < sizeof(struct nvme_get_log_args)) { + if (args->args_size < size_v1 || args->args_size > size_v2) { errno = EINVAL; return -1; } @@ -1501,9 +1505,10 @@ int nvme_format_nvm(struct nvme_format_nvm_args *args) { 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); + const size_t size_v3 = sizeof_args(struct nvme_format_nvm_args, ish, __u64); __u32 cdw10; - if (args->args_size < size_v1 || args->args_size > size_v2) { + if (args->args_size < size_v1 || args->args_size > size_v3) { errno = EINVAL; return -1; } @@ -1533,10 +1538,11 @@ int nvme_ns_mgmt(struct nvme_ns_mgmt_args *args) { const size_t size_v1 = sizeof_args(struct nvme_ns_mgmt_args, csi, __u64); const size_t size_v2 = sizeof_args(struct nvme_ns_mgmt_args, data, __u64); + const size_t size_v3 = sizeof_args(struct nvme_ns_mgmt_args, ish, __u64); __u32 cdw10 = NVME_SET(args->sel, NAMESPACE_MGMT_CDW10_SEL); __u32 cdw11 = NVME_SET(args->csi, NAMESPACE_MGMT_CDW11_CSI); - if (args->args_size < size_v1 || args->args_size > size_v2) { + if (args->args_size < size_v1 || args->args_size > size_v3) { errno = EINVAL; return -1; } @@ -1566,6 +1572,8 @@ int nvme_ns_mgmt(struct nvme_ns_mgmt_args *args) int nvme_ns_attach(struct nvme_ns_attach_args *args) { + const size_t size_v1 = sizeof_args(struct nvme_ns_attach_args, sel, __u64); + const size_t size_v2 = sizeof_args(struct nvme_ns_attach_args, ish, __u64); __u32 cdw10 = NVME_SET(args->sel, NAMESPACE_ATTACH_CDW10_SEL); struct nvme_passthru_cmd cmd = { @@ -1577,7 +1585,7 @@ int nvme_ns_attach(struct nvme_ns_attach_args *args) .timeout_ms = args->timeout, }; - if (args->args_size < sizeof(*args)) { + if (args->args_size < size_v1 || args->args_size > size_v2) { errno = EINVAL; return -1; } @@ -1586,6 +1594,8 @@ int nvme_ns_attach(struct nvme_ns_attach_args *args) int nvme_fw_download(struct nvme_fw_download_args *args) { + const size_t size_v1 = sizeof_args(struct nvme_fw_download_args, data_len, __u64); + const size_t size_v2 = sizeof_args(struct nvme_fw_download_args, ish, __u64); __u32 cdw10 = (args->data_len >> 2) - 1; __u32 cdw11 = args->offset >> 2; @@ -1598,7 +1608,7 @@ int nvme_fw_download(struct nvme_fw_download_args *args) .timeout_ms = args->timeout, }; - if (args->args_size < sizeof(*args)) { + if (args->args_size < size_v1 || args->args_size > size_v2) { errno = EINVAL; return -1; } @@ -1607,6 +1617,8 @@ int nvme_fw_download(struct nvme_fw_download_args *args) int nvme_fw_commit(struct nvme_fw_commit_args *args) { + const size_t size_v1 = sizeof_args(struct nvme_fw_commit_args, bpid, __u64); + const size_t size_v2 = sizeof_args(struct nvme_fw_commit_args, ish, __u64); __u32 cdw10 = NVME_SET(args->slot, FW_COMMIT_CDW10_FS) | NVME_SET(args->action, FW_COMMIT_CDW10_CA) | NVME_SET(args->bpid, FW_COMMIT_CDW10_BPID); @@ -1617,7 +1629,7 @@ int nvme_fw_commit(struct nvme_fw_commit_args *args) .timeout_ms = args->timeout, }; - if (args->args_size < sizeof(*args)) { + if (args->args_size < size_v1 || args->args_size > size_v2) { errno = EINVAL; return -1; } @@ -1626,6 +1638,8 @@ int nvme_fw_commit(struct nvme_fw_commit_args *args) int nvme_security_send(struct nvme_security_send_args *args) { + const size_t size_v1 = sizeof_args(struct nvme_security_send_args, secp, __u64); + const size_t size_v2 = sizeof_args(struct nvme_security_send_args, ish, __u64); __u32 cdw10 = NVME_SET(args->secp, SECURITY_SECP) | NVME_SET(args->spsp0, SECURITY_SPSP0) | NVME_SET(args->spsp1, SECURITY_SPSP1) | @@ -1642,7 +1656,7 @@ int nvme_security_send(struct nvme_security_send_args *args) .timeout_ms = args->timeout, }; - if (args->args_size < sizeof(*args)) { + if (args->args_size < size_v1 || args->args_size > size_v2) { errno = EINVAL; return -1; } @@ -1651,6 +1665,8 @@ int nvme_security_send(struct nvme_security_send_args *args) int nvme_security_receive(struct nvme_security_receive_args *args) { + const size_t size_v1 = sizeof_args(struct nvme_security_receive_args, secp, __u64); + const size_t size_v2 = sizeof_args(struct nvme_security_receive_args, ish, __u64); __u32 cdw10 = NVME_SET(args->secp, SECURITY_SECP) | NVME_SET(args->spsp0, SECURITY_SPSP0) | NVME_SET(args->spsp1, SECURITY_SPSP1) | @@ -1667,7 +1683,7 @@ int nvme_security_receive(struct nvme_security_receive_args *args) .timeout_ms = args->timeout, }; - if (args->args_size < sizeof(*args)) { + if (args->args_size < size_v1 || args->args_size > size_v2) { errno = EINVAL; return -1; } @@ -1858,9 +1874,10 @@ int nvme_sanitize_nvm(struct nvme_sanitize_nvm_args *args) { const size_t size_v1 = sizeof_args(struct nvme_sanitize_nvm_args, nodas, __u64); const size_t size_v2 = sizeof_args(struct nvme_sanitize_nvm_args, emvs, __u64); + const size_t size_v3 = sizeof_args(struct nvme_sanitize_nvm_args, ish, __u64); __u32 cdw10, cdw11; - if (args->args_size < size_v1 || args->args_size > size_v2) { + if (args->args_size < size_v1 || args->args_size > size_v3) { errno = EINVAL; return -1; } diff --git a/src/nvme/mi.c b/src/nvme/mi.c index 14c71d75e..8ce839515 100644 --- a/src/nvme/mi.c +++ b/src/nvme/mi.c @@ -852,7 +852,7 @@ int nvme_mi_admin_admin_passthru(nvme_mi_ctrl_t ctrl, __u8 opcode, __u8 flags, __u32 data_len, void *data, __u32 metadata_len, void *metadata, __u32 timeout_ms, __u32 *result) { - /* Input parameters flags, rsvd, metadata, metadata_len are not used */ + /* Input parameters rsvd, metadata, metadata_len are not used */ struct nvme_mi_admin_resp_hdr resp_hdr; struct nvme_mi_admin_req_hdr req_hdr; struct nvme_mi_resp resp; @@ -895,10 +895,11 @@ int nvme_mi_admin_admin_passthru(nvme_mi_ctrl_t ctrl, __u8 opcode, __u8 flags, req_hdr.cdw14 = cpu_to_le32(cdw14); req_hdr.cdw15 = cpu_to_le32(cdw15); req_hdr.doff = 0; + req_hdr.flags = flags; if (data_len != 0) { req_hdr.dlen = cpu_to_le32(data_len); /* Bit 0 set to 1 means DLEN contains a value */ - req_hdr.flags = 0x1; + req_hdr.flags |= 0x1; } if (has_write_data) { @@ -1030,6 +1031,8 @@ static int __nvme_mi_admin_get_log(nvme_mi_ctrl_t ctrl, const struct nvme_get_log_args *args, off_t offset, size_t *lenp, bool final) { + const size_t size_v1 = sizeof_args(struct nvme_get_log_args, ot, __u64); + const size_t size_v2 = sizeof_args(struct nvme_get_log_args, ish, __u64); __u64 log_page_offset = args->lpo + offset; struct nvme_mi_admin_resp_hdr resp_hdr; struct nvme_mi_admin_req_hdr req_hdr; @@ -1039,6 +1042,11 @@ static int __nvme_mi_admin_get_log(nvme_mi_ctrl_t ctrl, __u32 ndw; int rc; + if (args->args_size < size_v1 || args->args_size > size_v2) { + errno = EINVAL; + return -1; + } + /* MI spec requires that the data length field is less than or equal * to 4096 */ len = *lenp; @@ -1069,8 +1077,10 @@ static int __nvme_mi_admin_get_log(nvme_mi_ctrl_t ctrl, (args->ot ? 1 : 0) << 23 | args->uuidx); req_hdr.flags = 0x1; - req_hdr.dlen = cpu_to_le32(len & 0xffffffff); + if (args->args_size == size_v2) + req_hdr.flags |= (((args->ish) ? 1 : 0) << 0x2); + req_hdr.dlen = cpu_to_le32(len & 0xffffffff); nvme_mi_admin_init_resp(&resp, &resp_hdr); resp.data = args->log + offset; resp.data_len = len; @@ -1268,14 +1278,15 @@ int nvme_mi_admin_get_ana_log_atomic(nvme_mi_ctrl_t ctrl, bool rgo, bool rae, int nvme_mi_admin_security_send(nvme_mi_ctrl_t ctrl, struct nvme_security_send_args *args) { - + const size_t size_v1 = sizeof_args(struct nvme_security_send_args, secp, __u64); + const size_t size_v2 = sizeof_args(struct nvme_security_send_args, ish, __u64); struct nvme_mi_admin_resp_hdr resp_hdr; struct nvme_mi_admin_req_hdr req_hdr; struct nvme_mi_resp resp; struct nvme_mi_req req; int rc; - if (args->args_size < sizeof(*args)) { + if (args->args_size < size_v1 || args->args_size > size_v2) { errno = EINVAL; return -1; } @@ -1296,6 +1307,8 @@ int nvme_mi_admin_security_send(nvme_mi_ctrl_t ctrl, req_hdr.cdw11 = cpu_to_le32(args->data_len & 0xffffffff); req_hdr.flags = 0x1; + if (args->args_size == size_v2) + req_hdr.flags |= (((args->ish) ? 1 : 0) << 0x2); req_hdr.dlen = cpu_to_le32(args->data_len & 0xffffffff); req.data = args->data; req.data_len = args->data_len; @@ -1312,14 +1325,15 @@ int nvme_mi_admin_security_send(nvme_mi_ctrl_t ctrl, int nvme_mi_admin_security_recv(nvme_mi_ctrl_t ctrl, struct nvme_security_receive_args *args) { - + const size_t size_v1 = sizeof_args(struct nvme_security_receive_args, secp, __u64); + const size_t size_v2 = sizeof_args(struct nvme_security_receive_args, ish, __u64); struct nvme_mi_admin_resp_hdr resp_hdr; struct nvme_mi_admin_req_hdr req_hdr; struct nvme_mi_resp resp; struct nvme_mi_req req; int rc; - if (args->args_size < sizeof(*args)) { + if (args->args_size < size_v1 || args->args_size > size_v2) { errno = EINVAL; return -1; } @@ -1340,6 +1354,8 @@ int nvme_mi_admin_security_recv(nvme_mi_ctrl_t ctrl, req_hdr.cdw11 = cpu_to_le32(args->data_len & 0xffffffff); req_hdr.flags = 0x1; + if (args->args_size == size_v2) + req_hdr.flags |= (((args->ish) ? 1 : 0) << 0x2); req_hdr.dlen = cpu_to_le32(args->data_len & 0xffffffff); nvme_mi_admin_init_resp(&resp, &resp_hdr); @@ -1505,6 +1521,7 @@ int nvme_mi_admin_ns_mgmt(nvme_mi_ctrl_t ctrl, { const size_t size_v1 = sizeof_args(struct nvme_ns_mgmt_args, csi, __u64); const size_t size_v2 = sizeof_args(struct nvme_ns_mgmt_args, data, __u64); + const size_t size_v3 = sizeof_args(struct nvme_ns_mgmt_args, ish, __u64); struct nvme_mi_admin_resp_hdr resp_hdr; struct nvme_mi_admin_req_hdr req_hdr; struct nvme_mi_resp resp; @@ -1512,7 +1529,7 @@ int nvme_mi_admin_ns_mgmt(nvme_mi_ctrl_t ctrl, int rc; size_t data_len; - if (args->args_size < size_v1 || args->args_size > size_v2) { + if (args->args_size < size_v1 || args->args_size > size_v3) { errno = EINVAL; return -1; } @@ -1543,6 +1560,9 @@ int nvme_mi_admin_ns_mgmt(nvme_mi_ctrl_t ctrl, req_hdr.flags = 0x1; } + if (args->args_size == size_v3) + req_hdr.flags |= (((args->ish) ? 1 : 0) << 0x2); + nvme_mi_admin_init_resp(&resp, &resp_hdr); rc = nvme_mi_submit(ctrl->ep, &req, &resp); @@ -1555,13 +1575,15 @@ int nvme_mi_admin_ns_mgmt(nvme_mi_ctrl_t ctrl, int nvme_mi_admin_ns_attach(nvme_mi_ctrl_t ctrl, struct nvme_ns_attach_args *args) { + const size_t size_v1 = sizeof_args(struct nvme_ns_attach_args, sel, __u64); + const size_t size_v2 = sizeof_args(struct nvme_ns_attach_args, ish, __u64); struct nvme_mi_admin_resp_hdr resp_hdr; struct nvme_mi_admin_req_hdr req_hdr; struct nvme_mi_resp resp; struct nvme_mi_req req; int rc; - if (args->args_size < sizeof(*args)) { + if (args->args_size < size_v1 || args->args_size > size_v2) { errno = EINVAL; return -1; } @@ -1575,6 +1597,8 @@ int nvme_mi_admin_ns_attach(nvme_mi_ctrl_t ctrl, req.data_len = sizeof(*args->ctrlist); req_hdr.dlen = cpu_to_le32(sizeof(*args->ctrlist)); req_hdr.flags = 0x1; + if (args->args_size == size_v2) + req_hdr.flags |= (((args->ish) ? 1 : 0) << 0x2); nvme_mi_admin_init_resp(&resp, &resp_hdr); @@ -1588,13 +1612,15 @@ int nvme_mi_admin_ns_attach(nvme_mi_ctrl_t ctrl, int nvme_mi_admin_fw_download(nvme_mi_ctrl_t ctrl, struct nvme_fw_download_args *args) { + const size_t size_v1 = sizeof_args(struct nvme_fw_download_args, data_len, __u64); + const size_t size_v2 = sizeof_args(struct nvme_fw_download_args, ish, __u64); struct nvme_mi_admin_resp_hdr resp_hdr; struct nvme_mi_admin_req_hdr req_hdr; struct nvme_mi_resp resp; struct nvme_mi_req req; int rc; - if (args->args_size < sizeof(*args)) { + if (args->args_size < size_v1 || args->args_size > size_v2) { errno = EINVAL; return -1; } @@ -1618,6 +1644,8 @@ int nvme_mi_admin_fw_download(nvme_mi_ctrl_t ctrl, req.data_len = args->data_len; req_hdr.dlen = cpu_to_le32(args->data_len); req_hdr.flags = 0x1; + if (args->args_size == size_v2) + req_hdr.flags |= (((args->ish) ? 1 : 0) << 0x2); nvme_mi_admin_init_resp(&resp, &resp_hdr); @@ -1631,13 +1659,15 @@ int nvme_mi_admin_fw_download(nvme_mi_ctrl_t ctrl, int nvme_mi_admin_fw_commit(nvme_mi_ctrl_t ctrl, struct nvme_fw_commit_args *args) { + const size_t size_v1 = sizeof_args(struct nvme_fw_commit_args, bpid, __u64); + const size_t size_v2 = sizeof_args(struct nvme_fw_commit_args, ish, __u64); struct nvme_mi_admin_resp_hdr resp_hdr; struct nvme_mi_admin_req_hdr req_hdr; struct nvme_mi_resp resp; struct nvme_mi_req req; int rc; - if (args->args_size < sizeof(*args)) { + if (args->args_size < size_v1 || args->args_size > size_v2) { errno = EINVAL; return -1; } @@ -1648,6 +1678,8 @@ int nvme_mi_admin_fw_commit(nvme_mi_ctrl_t ctrl, req_hdr.cdw10 = cpu_to_le32(((__u32)(args->bpid & 0x1) << 31) | ((args->action & 0x7) << 3) | ((args->slot & 0x7) << 0)); + if (args->args_size == size_v2) + req_hdr.flags = (((args->ish) ? 1 : 0) << 0x2); nvme_mi_admin_init_resp(&resp, &resp_hdr); @@ -1661,13 +1693,15 @@ int nvme_mi_admin_fw_commit(nvme_mi_ctrl_t ctrl, int nvme_mi_admin_format_nvm(nvme_mi_ctrl_t ctrl, struct nvme_format_nvm_args *args) { + const size_t size_v1 = sizeof_args(struct nvme_format_nvm_args, lbafu, __u64); + const size_t size_v2 = sizeof_args(struct nvme_format_nvm_args, ish, __u64); struct nvme_mi_admin_resp_hdr resp_hdr; struct nvme_mi_admin_req_hdr req_hdr; struct nvme_mi_resp resp; struct nvme_mi_req req; int rc; - if (args->args_size < sizeof(*args)) { + if (args->args_size < size_v1 || args->args_size > size_v2) { errno = EINVAL; return -1; } @@ -1682,6 +1716,8 @@ int nvme_mi_admin_format_nvm(nvme_mi_ctrl_t ctrl, | ((args->pi & 0x7) << 5) | ((args->mset & 0x1) << 4) | ((args->lbaf & 0xf) << 0)); + if (args->args_size == size_v2) + req_hdr.flags = (((args->ish) ? 1 : 0) << 0x2); nvme_mi_admin_init_resp(&resp, &resp_hdr); @@ -1695,13 +1731,15 @@ int nvme_mi_admin_format_nvm(nvme_mi_ctrl_t ctrl, int nvme_mi_admin_sanitize_nvm(nvme_mi_ctrl_t ctrl, struct nvme_sanitize_nvm_args *args) { + const size_t size_v1 = sizeof_args(struct nvme_sanitize_nvm_args, emvs, __u64); + const size_t size_v2 = sizeof_args(struct nvme_sanitize_nvm_args, ish, __u64); struct nvme_mi_admin_resp_hdr resp_hdr; struct nvme_mi_admin_req_hdr req_hdr; struct nvme_mi_resp resp; struct nvme_mi_req req; int rc; - if (args->args_size < sizeof(*args)) { + if (args->args_size < size_v1 || args->args_size > size_v2) { errno = EINVAL; return -1; } @@ -1715,6 +1753,8 @@ int nvme_mi_admin_sanitize_nvm(nvme_mi_ctrl_t ctrl, | ((args->ause ? 1 : 0) << 3) | ((args->sanact & 0x7) << 0)); req_hdr.cdw11 = cpu_to_le32(args->ovrpat); + if (args->args_size == size_v2) + req_hdr.flags = (((args->ish) ? 1 : 0) << 0x2); nvme_mi_admin_init_resp(&resp, &resp_hdr);