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>