[PATCH 1/4] nvme-cli : add support for sanitize command.

Chaitanya Kulkarni chaitanya.kulkarni at hgst.com
Wed Jun 28 19:19:25 PDT 2017


This adds support for NVMe sanitize command execution including
NVMe status codes, command opcode and help text.

For more details please refer to NVM Express 1.3 specification.

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at hgst.com>
---
 linux/nvme.h   | 16 ++++++++++
 nvme-builtin.h |  1 +
 nvme-print.c   |  2 ++
 nvme.c         | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 111 insertions(+)

diff --git a/linux/nvme.h b/linux/nvme.h
index c05d819..28ab9b8 100644
--- a/linux/nvme.h
+++ b/linux/nvme.h
@@ -660,6 +660,7 @@ enum nvme_admin_opcode {
 	nvme_admin_format_nvm		= 0x80,
 	nvme_admin_security_send	= 0x81,
 	nvme_admin_security_recv	= 0x82,
+	nvme_admin_sanitize			= 0x84,
 };
 
 enum {
@@ -697,6 +698,18 @@ enum {
 	NVME_FWACT_ACTV		= (2 << 3),
 };
 
+/* Sanitize */
+enum {
+	NVME_SANITIZE_NO_DEALLOC		= 0x00000200,
+	NVME_SANITIZE_OIPBP				= 0x00000100,
+	NVME_SANITIZE_OWPASS_SHIFT		= 0x00000004,
+	NVME_SANITIZE_AUSE				= 0x00000008,
+	NVME_SANITIZE_ACT_CRYPTO_ERASE	= 0x00000004,
+	NVME_SANITIZE_ACT_OVERWRITE		= 0x00000003,
+	NVME_SANITIZE_ACT_BLOCK_ERASE	= 0x00000002,
+	NVME_SANITIZE_ACT_EXIT			= 0x00000001,
+};
+
 struct nvme_identify {
 	__u8			opcode;
 	__u8			flags;
@@ -1010,6 +1023,9 @@ enum {
 	NVME_SC_SGL_INVALID_OFFSET	= 0x16,
 	NVME_SC_SGL_INVALID_SUBTYPE	= 0x17,
 
+	NVME_SC_SANITIZE_FAILED			= 0x1C,
+	NVME_SC_SANITIZE_IN_PROGRESS	= 0x1D,
+
 	NVME_SC_LBA_RANGE		= 0x80,
 	NVME_SC_CAP_EXCEEDED		= 0x81,
 	NVME_SC_NS_NOT_READY		= 0x82,
diff --git a/nvme-builtin.h b/nvme-builtin.h
index 2bb01cb..b4cd3ba 100644
--- a/nvme-builtin.h
+++ b/nvme-builtin.h
@@ -42,6 +42,7 @@ COMMAND_LIST(
 	ENTRY("write", "Submit a write command, return results", write_cmd)
 	ENTRY("write-zeroes", "Submit a write zeroes command, return results", write_zeroes)
 	ENTRY("write-uncor", "Submit a write uncorrectable command, return results", write_uncor)
+	ENTRY("sanitize", "Submit a sanitize command", sanitize)
 	ENTRY("reset", "Resets the controller", reset)
 	ENTRY("subsystem-reset", "Resets the controller", subsystem_reset)
 	ENTRY("show-regs", "Shows the controller registers. Requires admin character device", show_registers)
diff --git a/nvme-print.c b/nvme-print.c
index bf78d4a..f03382f 100644
--- a/nvme-print.c
+++ b/nvme-print.c
@@ -1102,6 +1102,8 @@ char *nvme_status_to_string(__u32 status)
 	case NVME_SC_FUSED_MISSING:		return "FUSED_MISSING";
 	case NVME_SC_INVALID_NS:		return "INVALID_NS";
 	case NVME_SC_CMD_SEQ_ERROR:		return "CMD_SEQ_ERROR";
+	case NVME_SC_SANITIZE_FAILED:		return "SANITIZE_FAILED";
+	case NVME_SC_SANITIZE_IN_PROGRESS:	return "SANITIZE_IN_PROGRESS";
 	case NVME_SC_LBA_RANGE:			return "LBA_RANGE";
 	case NVME_SC_CAP_EXCEEDED:		return "CAP_EXCEEDED";
 	case NVME_SC_NS_NOT_READY:		return "NS_NOT_READY";
diff --git a/nvme.c b/nvme.c
index 7e07ffd..8507cd3 100644
--- a/nvme.c
+++ b/nvme.c
@@ -1428,6 +1428,98 @@ static int reset(int argc, char **argv, struct command *cmd, struct plugin *plug
 	return err;
 }
 
+static int sanitize(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+	char *desc = "Send a sanitize command.";
+	char *no_dealloc_desc = "No deallocate after sanitize.";
+	char *oipbp_desc = "Overwrite invert pattern between passes.";
+	char *owpass_desc = "Overwrite pass count.";
+	char *ause_desc = "Allow unrestricted sanitize exit.";
+	char *sanact_desc = "Sanitize action.";
+	char *ovrpat_desc = "Overwrite pattern.";
+
+	int fd;
+	int ret;
+	__u32 sanitize_cdw10 = 0;
+	__u32 sanitize_cdw11 = 0;
+
+	struct nvme_passthru_cmd admin_cmd;
+
+	struct config {
+		uint8_t no_dealloc;
+		uint8_t oipbp;
+		uint8_t owpass;
+		uint8_t ause;
+		uint8_t sanact;
+		uint32_t ovrpat;
+	};
+
+	struct config cfg = {
+		.no_dealloc = 0,
+		.oipbp = 0,
+		.owpass = 0,
+		.ause = 0,
+		.sanact = 0,
+		.ovrpat = 0,
+	};
+
+	const struct argconfig_commandline_options command_line_options[] = {
+		{"no_dealloc", 'd', "", CFG_NONE, &cfg.no_dealloc, no_argument, no_dealloc_desc},
+		{"oipbp", 'i', "", CFG_NONE, &cfg.oipbp, no_argument, oipbp_desc},
+		{"owpass", 'n', "NUM", CFG_POSITIVE, &cfg.owpass, required_argument, owpass_desc},
+		{"ause", 'u', "", CFG_NONE, &cfg.ause, no_argument, ause_desc},
+		{"sanact", 'a', "NUM", CFG_POSITIVE, &cfg.sanact, required_argument, sanact_desc},
+		{"ovrpat", 'p', "NUM", CFG_POSITIVE, &cfg.ovrpat, required_argument, ovrpat_desc},
+		{NULL}
+	};
+
+	fd = parse_and_open(argc, argv, desc, command_line_options, NULL, 0);
+	if (fd < 0)
+		return fd;
+
+	switch (cfg.sanact) {
+	case NVME_SANITIZE_ACT_CRYPTO_ERASE:
+	case NVME_SANITIZE_ACT_BLOCK_ERASE:
+	case NVME_SANITIZE_ACT_EXIT:
+		sanitize_cdw10 = cfg.sanact;
+		break;
+	case NVME_SANITIZE_ACT_OVERWRITE:
+		sanitize_cdw10 = cfg.sanact;
+		sanitize_cdw11 = cfg.ovrpat;
+		break;
+	default:
+		fprintf(stderr, "Invalid Sanitize Action\n");
+		return -1;
+	}
+
+	if (cfg.ause)
+		sanitize_cdw10 |= NVME_SANITIZE_AUSE;
+
+	if (cfg.sanact == NVME_SANITIZE_ACT_OVERWRITE) {
+		if (cfg.owpass >= 0 && cfg.owpass <= 16) {
+			sanitize_cdw10 |= (cfg.owpass << NVME_SANITIZE_OWPASS_SHIFT);
+		} else {
+			fprintf(stderr, "owpass out of range [0-16] or sanitize action is not set to overwrite\n");
+			return -1;
+		}
+		if (cfg.oipbp)
+			sanitize_cdw10 |= NVME_SANITIZE_OIPBP;
+	}
+
+	if (cfg.sanact != NVME_SANITIZE_ACT_EXIT && cfg.no_dealloc)
+		sanitize_cdw10 |= NVME_SANITIZE_NO_DEALLOC;
+
+	memset(&admin_cmd, 0, sizeof (admin_cmd));
+	admin_cmd.opcode = nvme_admin_sanitize;
+	admin_cmd.cdw10 = sanitize_cdw10;
+	admin_cmd.cdw11 = sanitize_cdw11;
+
+	ret = nvme_submit_passthru(fd, NVME_IOCTL_ADMIN_CMD, &admin_cmd);
+
+	fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+	return ret;
+}
+
 static int show_registers(int argc, char **argv, struct command *cmd, struct plugin *plugin)
 {
 	const char *desc = "Reads and shows the defined NVMe controller registers "\
-- 
2.7.4




More information about the Linux-nvme mailing list