Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 12 Aug 2019 19:43:25 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org
Subject:   svn commit: r350951 - stable/12/sbin/nvmecontrol
Message-ID:  <201908121943.x7CJhPin096354@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Mon Aug 12 19:43:25 2019
New Revision: 350951
URL: https://svnweb.freebsd.org/changeset/base/350951

Log:
  MFC r350563: Add `nvmecontrol sanitize` command.
  
  It allows to delete all user data from NVM subsystem in one of 3 methods.
  It is a close equivalent of SCSI SANITIZE command of `camcontrol sanitize`,
  so I tried to keep arguments as close as possible.
  
  While there, fix supported sanitize methods reporting in `identify`.
  
  MFC after:	yes

Added:
  stable/12/sbin/nvmecontrol/sanitize.c
     - copied unchanged from r350563, head/sbin/nvmecontrol/sanitize.c
Modified:
  stable/12/sbin/nvmecontrol/Makefile
  stable/12/sbin/nvmecontrol/identify_ext.c
  stable/12/sbin/nvmecontrol/nvmecontrol.8
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sbin/nvmecontrol/Makefile
==============================================================================
--- stable/12/sbin/nvmecontrol/Makefile	Mon Aug 12 19:42:43 2019	(r350950)
+++ stable/12/sbin/nvmecontrol/Makefile	Mon Aug 12 19:43:25 2019	(r350951)
@@ -4,7 +4,7 @@ PACKAGE=runtime
 PROG=	nvmecontrol
 SRCS=	comnd.c nvmecontrol.c
 SRCS+=	devlist.c firmware.c format.c identify.c logpage.c ns.c nsid.c
-SRCS+=	perftest.c power.c reset.c
+SRCS+=	perftest.c power.c reset.c sanitize.c
 #SRCS+=	passthru.c
 SRCS+=	identify_ext.c nvme_util.c nc_util.c
 MAN=	nvmecontrol.8

Modified: stable/12/sbin/nvmecontrol/identify_ext.c
==============================================================================
--- stable/12/sbin/nvmecontrol/identify_ext.c	Mon Aug 12 19:42:43 2019	(r350950)
+++ stable/12/sbin/nvmecontrol/identify_ext.c	Mon Aug 12 19:43:25 2019	(r350951)
@@ -160,11 +160,11 @@ nvme_print_controller(struct nvme_controller_data *cda
 	if (cdata->sanicap != 0) {
 		printf("%s%s%s\n",
 		    ((cdata->sanicap >> NVME_CTRLR_DATA_SANICAP_CES_SHIFT) &
-		     NVME_CTRLR_DATA_SANICAP_CES_SHIFT) ? "crypto, " : "",
+		     NVME_CTRLR_DATA_SANICAP_CES_MASK) ? "crypto, " : "",
 		    ((cdata->sanicap >> NVME_CTRLR_DATA_SANICAP_BES_SHIFT) &
-		     NVME_CTRLR_DATA_SANICAP_BES_SHIFT) ? "block, " : "",
+		     NVME_CTRLR_DATA_SANICAP_BES_MASK) ? "block, " : "",
 		    ((cdata->sanicap >> NVME_CTRLR_DATA_SANICAP_OWS_SHIFT) &
-		     NVME_CTRLR_DATA_SANICAP_OWS_SHIFT) ? "overwrite" : "");
+		     NVME_CTRLR_DATA_SANICAP_OWS_MASK) ? "overwrite" : "");
 	} else {
 		printf("Not Supported\n");
 	}

Modified: stable/12/sbin/nvmecontrol/nvmecontrol.8
==============================================================================
--- stable/12/sbin/nvmecontrol/nvmecontrol.8	Mon Aug 12 19:42:43 2019	(r350950)
+++ stable/12/sbin/nvmecontrol/nvmecontrol.8	Mon Aug 12 19:43:25 2019	(r350951)
@@ -34,7 +34,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd August 2, 2019
+.Dd August 3, 2019
 .Dt NVMECONTROL 8
 .Os
 .Sh NAME
@@ -137,6 +137,16 @@
 .Aq device id
 .Aq namespace id
 .Nm
+.Ic sanitize
+.Aq Fl a Ar sanact
+.Op Fl c Ar owpass
+.Op Fl p Ar ovrpat
+.Op Fl r
+.Op Fl D
+.Op Fl I
+.Op Fl U
+.Aq device id
+.Nm
 .Ic power
 .Op Fl l
 .Op Fl p power_state
@@ -234,6 +244,65 @@ enables User Data Erase during format.
 Option
 .Fl C
 enables Cryptographic Erase during format.
+.Ss sanitize
+Sanitize NVM subsystem of specified controller,
+using specified parameters:
+.Bl -tag -width 6n
+.It Fl a Ar operation
+Specify the sanitize operation to perform.
+.Bl -tag -width 16n
+.It overwrite
+Perform an overwrite operation by writing a user supplied
+data pattern to the device one or more times.
+The pattern is given by the
+.Fl p
+argument.
+The number of times is given by the
+.Fl c
+argument.
+.It block
+Perform a block erase operation.
+All the device's blocks are set to a vendor defined
+value, typically zero.
+.It crypto
+Perform a cryptographic erase operation.
+The encryption keys are changed to prevent the decryption
+of the data.
+.It exitfailure
+Exits a previously failed sanitize operation.
+A failed sanitize operation can only be exited if it was
+run in the unrestricted completion mode, as provided by the
+.Fl U
+argument.
+.El
+.It Fl c Ar passes
+The number of passes when performing an
+.Sq overwrite
+operation.
+Valid values are between 1 and 16.
+The default is 1.
+.It Fl D
+No Deallocate After Sanitize.
+.It Fl I
+When performing an
+.Sq overwrite
+operation, the pattern is inverted between consecutive passes.
+.It Fl p Ar pattern
+32 bits of pattern to use when performing an
+.Sq overwrite
+operation.
+The pattern is repeated as needed to fill each block.
+.It Fl U
+Perform the sanitize in the unrestricted completion mode.
+If the operation fails, it can later be exited with the
+.Sq exitfailure
+operation.
+.It Fl r
+Run in
+.Dq report only
+mode.
+This will report status on a sanitize that is already running on the drive.
+.El
 .Ss wdc
 The various wdc command retrieve log data from the wdc/hgst drives.
 The

Copied: stable/12/sbin/nvmecontrol/sanitize.c (from r350563, head/sbin/nvmecontrol/sanitize.c)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ stable/12/sbin/nvmecontrol/sanitize.c	Mon Aug 12 19:43:25 2019	(r350951, copy of r350563, head/sbin/nvmecontrol/sanitize.c)
@@ -0,0 +1,222 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (C) 2019 Alexander Motin <mav@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/ioccom.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "nvmecontrol.h"
+
+/* Tables for command line parsing */
+
+static cmd_fn_t sanitize;
+
+static struct options {
+	bool		ause;
+	bool		ndas;
+	bool		oipbp;
+	bool		reportonly;
+	uint8_t		owpass;
+	uint32_t	ovrpat;
+	const char	*sanact;
+	const char	*dev;
+} opt = {
+	.ause = false,
+	.ndas = false,
+	.oipbp = false,
+	.reportonly = false,
+	.owpass = 1,
+	.ovrpat = 0,
+	.sanact = NULL,
+	.dev = NULL,
+};
+
+static const struct opts sanitize_opts[] = {
+#define OPT(l, s, t, opt, addr, desc) { l, s, t, &opt.addr, desc }
+	OPT("ause", 'U', arg_none, opt, ause,
+	    "Allow Unrestricted Sanitize Exit"),
+	OPT("ndas", 'D', arg_none, opt, ndas,
+	    "No Deallocate After Sanitize"),
+	OPT("oipbp", 'I', arg_none, opt, oipbp,
+	    "Overwrite Invert Pattern Between Passes"),
+	OPT("reportonly", 'r', arg_none, opt, reportonly,
+	    "Report previous sanitize status"),
+	OPT("owpass", 'c', arg_uint8, opt, owpass,
+	    "Overwrite Pass Count"),
+	OPT("ovrpat", 'p', arg_uint32, opt, ovrpat,
+	    "Overwrite Pattern"),
+	OPT("sanact", 'a', arg_string, opt, sanact,
+	    "Sanitize Action (block, overwrite, crypto)"),
+	{ NULL, 0, arg_none, NULL, NULL }
+};
+#undef OPT
+
+static const struct args sanitize_args[] = {
+	{ arg_string, &opt.dev, "controller-id" },
+	{ arg_none, NULL, NULL },
+};
+
+static struct cmd sanitize_cmd = {
+	.name = "sanitize",
+	.fn = sanitize,
+	.descr = "Sanitize NVM subsystem",
+	.ctx_size = sizeof(opt),
+	.opts = sanitize_opts,
+	.args = sanitize_args,
+};
+
+CMD_COMMAND(sanitize_cmd);
+
+/* End of tables for command line parsing */
+
+static void
+sanitize(const struct cmd *f, int argc, char *argv[])
+{
+	struct nvme_controller_data	cd;
+	struct nvme_pt_command		pt;
+	struct nvme_sanitize_status_page ss;
+	char				*path;
+	uint32_t			nsid;
+	int				sanact = 0, fd, delay = 1;
+
+	if (arg_parse(argc, argv, f))
+		return;
+
+	if (opt.sanact == NULL) {
+		if (!opt.reportonly) {
+			fprintf(stderr, "Sanitize Action is not specified\n");
+			arg_help(argc, argv, f);
+		}
+	} else {
+		if (strcmp(opt.sanact, "exitfailure") == 0)
+			sanact = 1;
+		else if (strcmp(opt.sanact, "block") == 0)
+			sanact = 2;
+		else if (strcmp(opt.sanact, "overwrite") == 0)
+			sanact = 3;
+		else if (strcmp(opt.sanact, "crypto") == 0)
+			sanact = 4;
+		else {
+			fprintf(stderr, "Incorrect Sanitize Action value\n");
+			arg_help(argc, argv, f);
+		}
+	}
+	if (opt.owpass == 0 || opt.owpass > 16) {
+		fprintf(stderr, "Incorrect Overwrite Pass Count value\n");
+		arg_help(argc, argv, f);
+	}
+
+	open_dev(opt.dev, &fd, 1, 1);
+	get_nsid(fd, &path, &nsid);
+	if (nsid != 0) {
+		close(fd);
+		open_dev(path, &fd, 1, 1);
+	}
+	free(path);
+
+	if (opt.reportonly)
+		goto wait;
+
+	/* Check that controller can execute this command. */
+	read_controller_data(fd, &cd);
+	if (((cd.sanicap >> NVME_CTRLR_DATA_SANICAP_BES_SHIFT) &
+	     NVME_CTRLR_DATA_SANICAP_BES_MASK) == 0 && sanact == 2)
+		errx(1, "controller does not support Block Erase");
+	if (((cd.sanicap >> NVME_CTRLR_DATA_SANICAP_OWS_SHIFT) &
+	     NVME_CTRLR_DATA_SANICAP_OWS_MASK) == 0 && sanact == 3)
+		errx(1, "controller does not support Overwrite");
+	if (((cd.sanicap >> NVME_CTRLR_DATA_SANICAP_CES_SHIFT) &
+	     NVME_CTRLR_DATA_SANICAP_CES_MASK) == 0 && sanact == 4)
+		errx(1, "controller does not support Crypto Erase");
+
+	/*
+	 * If controller supports only one namespace, we may sanitize it.
+	 * If there can be more, make user explicit in his commands.
+	 */
+	if (nsid != 0 && cd.nn > 1)
+		errx(1, "can't sanitize one of namespaces, specify controller");
+
+	memset(&pt, 0, sizeof(pt));
+	pt.cmd.opc = NVME_OPC_SANITIZE;
+	pt.cmd.cdw10 = htole32((opt.ndas << 9) | (opt.oipbp << 8) |
+	    ((opt.owpass & 0xf) << 4) | (opt.ause << 3) | sanact);
+	pt.cmd.cdw11 = htole32(opt.ovrpat);
+
+	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
+		err(1, "sanitize request failed");
+
+	if (nvme_completion_is_error(&pt.cpl))
+		errx(1, "sanitize request returned error");
+
+wait:
+	read_logpage(fd, NVME_LOG_SANITIZE_STATUS,
+	    NVME_GLOBAL_NAMESPACE_TAG, 0, 0, 0, &ss, sizeof(ss));
+	switch ((ss.sstat >> NVME_SS_PAGE_SSTAT_STATUS_SHIFT) &
+	    NVME_SS_PAGE_SSTAT_STATUS_MASK) {
+	case NVME_SS_PAGE_SSTAT_STATUS_NEVER:
+		printf("Never sanitized");
+		break;
+	case NVME_SS_PAGE_SSTAT_STATUS_COMPLETED:
+		printf("Sanitize completed");
+		break;
+	case NVME_SS_PAGE_SSTAT_STATUS_INPROG:
+		printf("Sanitize in progress: %u%% (%u/65535)\r",
+		    (ss.sprog * 100 + 32768) / 65536, ss.sprog);
+		fflush(stdout);
+		if (delay < 16)
+			delay++;
+		sleep(delay);
+		goto wait;
+	case NVME_SS_PAGE_SSTAT_STATUS_FAILED:
+		printf("Sanitize failed");
+		break;
+	case NVME_SS_PAGE_SSTAT_STATUS_COMPLETEDWD:
+		printf("Sanitize completed with deallocation");
+		break;
+	default:
+		printf("Sanitize status unknown");
+		break;
+	}
+	if (delay > 1)
+		printf("                       ");
+	printf("\n");
+
+	close(fd);
+	exit(0);
+}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201908121943.x7CJhPin096354>