source: rtems-libbsd/freebsd/sbin/nvmecontrol/sanitize.c @ ddc8c35

5
Last change on this file since ddc8c35 was ddc8c35, checked in by Sebastian Huber <sebastian.huber@…>, on 11/13/19 at 11:57:55

NVMECONTROL(8): Import from FreeBSD

Update #3821.

  • Property mode set to 100644
File size: 6.3 KB
Line 
1#include <machine/rtems-bsd-user-space.h>
2
3/*-
4 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
5 *
6 * Copyright (C) 2019 Alexander Motin <mav@FreeBSD.org>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD$");
32
33#include <sys/param.h>
34#include <sys/ioccom.h>
35
36#include <ctype.h>
37#include <err.h>
38#include <fcntl.h>
39#include <stdbool.h>
40#include <stddef.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <string.h>
44#include <unistd.h>
45
46#include "nvmecontrol.h"
47
48/* Tables for command line parsing */
49
50static cmd_fn_t sanitize;
51
52static struct options {
53        bool            ause;
54        bool            ndas;
55        bool            oipbp;
56        bool            reportonly;
57        uint8_t         owpass;
58        uint32_t        ovrpat;
59        const char      *sanact;
60        const char      *dev;
61} opt = {
62        .ause = false,
63        .ndas = false,
64        .oipbp = false,
65        .reportonly = false,
66        .owpass = 1,
67        .ovrpat = 0,
68        .sanact = NULL,
69        .dev = NULL,
70};
71
72static const struct opts sanitize_opts[] = {
73#define OPT(l, s, t, opt, addr, desc) { l, s, t, &opt.addr, desc }
74        OPT("ause", 'U', arg_none, opt, ause,
75            "Allow Unrestricted Sanitize Exit"),
76        OPT("ndas", 'd', arg_none, opt, ndas,
77            "No Deallocate After Sanitize"),
78        OPT("oipbp", 'I', arg_none, opt, oipbp,
79            "Overwrite Invert Pattern Between Passes"),
80        OPT("reportonly", 'r', arg_none, opt, reportonly,
81            "Report previous sanitize status"),
82        OPT("owpass", 'c', arg_uint8, opt, owpass,
83            "Overwrite Pass Count"),
84        OPT("ovrpat", 'p', arg_uint32, opt, ovrpat,
85            "Overwrite Pattern"),
86        OPT("sanact", 'a', arg_string, opt, sanact,
87            "Sanitize Action (block, overwrite, crypto)"),
88        { NULL, 0, arg_none, NULL, NULL }
89};
90#undef OPT
91
92static const struct args sanitize_args[] = {
93        { arg_string, &opt.dev, "controller-id" },
94        { arg_none, NULL, NULL },
95};
96
97static struct cmd sanitize_cmd = {
98        .name = "sanitize",
99        .fn = sanitize,
100        .descr = "Sanitize NVM subsystem",
101        .ctx_size = sizeof(opt),
102        .opts = sanitize_opts,
103        .args = sanitize_args,
104};
105
106CMD_COMMAND(sanitize_cmd);
107
108/* End of tables for command line parsing */
109
110static void
111sanitize(const struct cmd *f, int argc, char *argv[])
112{
113        struct nvme_controller_data     cd;
114        struct nvme_pt_command          pt;
115        struct nvme_sanitize_status_page ss;
116        char                            *path;
117        uint32_t                        nsid;
118        int                             sanact = 0, fd, delay = 1;
119
120        if (arg_parse(argc, argv, f))
121                return;
122
123        if (opt.sanact == NULL) {
124                if (!opt.reportonly) {
125                        fprintf(stderr, "Sanitize Action is not specified\n");
126                        arg_help(argc, argv, f);
127                }
128        } else {
129                if (strcmp(opt.sanact, "exitfailure") == 0)
130                        sanact = 1;
131                else if (strcmp(opt.sanact, "block") == 0)
132                        sanact = 2;
133                else if (strcmp(opt.sanact, "overwrite") == 0)
134                        sanact = 3;
135                else if (strcmp(opt.sanact, "crypto") == 0)
136                        sanact = 4;
137                else {
138                        fprintf(stderr, "Incorrect Sanitize Action value\n");
139                        arg_help(argc, argv, f);
140                }
141        }
142        if (opt.owpass == 0 || opt.owpass > 16) {
143                fprintf(stderr, "Incorrect Overwrite Pass Count value\n");
144                arg_help(argc, argv, f);
145        }
146
147        open_dev(opt.dev, &fd, 1, 1);
148        get_nsid(fd, &path, &nsid);
149        if (nsid != 0) {
150                close(fd);
151                open_dev(path, &fd, 1, 1);
152        }
153        free(path);
154
155        if (opt.reportonly)
156                goto wait;
157
158        /* Check that controller can execute this command. */
159        read_controller_data(fd, &cd);
160        if (((cd.sanicap >> NVME_CTRLR_DATA_SANICAP_BES_SHIFT) &
161             NVME_CTRLR_DATA_SANICAP_BES_MASK) == 0 && sanact == 2)
162                errx(1, "controller does not support Block Erase");
163        if (((cd.sanicap >> NVME_CTRLR_DATA_SANICAP_OWS_SHIFT) &
164             NVME_CTRLR_DATA_SANICAP_OWS_MASK) == 0 && sanact == 3)
165                errx(1, "controller does not support Overwrite");
166        if (((cd.sanicap >> NVME_CTRLR_DATA_SANICAP_CES_SHIFT) &
167             NVME_CTRLR_DATA_SANICAP_CES_MASK) == 0 && sanact == 4)
168                errx(1, "controller does not support Crypto Erase");
169
170        /*
171         * If controller supports only one namespace, we may sanitize it.
172         * If there can be more, make user explicit in his commands.
173         */
174        if (nsid != 0 && cd.nn > 1)
175                errx(1, "can't sanitize one of namespaces, specify controller");
176
177        memset(&pt, 0, sizeof(pt));
178        pt.cmd.opc = NVME_OPC_SANITIZE;
179        pt.cmd.cdw10 = htole32((opt.ndas << 9) | (opt.oipbp << 8) |
180            ((opt.owpass & 0xf) << 4) | (opt.ause << 3) | sanact);
181        pt.cmd.cdw11 = htole32(opt.ovrpat);
182
183        if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
184                err(1, "sanitize request failed");
185
186        if (nvme_completion_is_error(&pt.cpl))
187                errx(1, "sanitize request returned error");
188
189wait:
190        read_logpage(fd, NVME_LOG_SANITIZE_STATUS,
191            NVME_GLOBAL_NAMESPACE_TAG, 0, 0, 0, &ss, sizeof(ss));
192        switch ((ss.sstat >> NVME_SS_PAGE_SSTAT_STATUS_SHIFT) &
193            NVME_SS_PAGE_SSTAT_STATUS_MASK) {
194        case NVME_SS_PAGE_SSTAT_STATUS_NEVER:
195                printf("Never sanitized");
196                break;
197        case NVME_SS_PAGE_SSTAT_STATUS_COMPLETED:
198                printf("Sanitize completed");
199                break;
200        case NVME_SS_PAGE_SSTAT_STATUS_INPROG:
201                printf("Sanitize in progress: %u%% (%u/65535)\r",
202                    (ss.sprog * 100 + 32768) / 65536, ss.sprog);
203                fflush(stdout);
204                if (delay < 16)
205                        delay++;
206                sleep(delay);
207                goto wait;
208        case NVME_SS_PAGE_SSTAT_STATUS_FAILED:
209                printf("Sanitize failed");
210                break;
211        case NVME_SS_PAGE_SSTAT_STATUS_COMPLETEDWD:
212                printf("Sanitize completed with deallocation");
213                break;
214        default:
215                printf("Sanitize status unknown");
216                break;
217        }
218        if (delay > 1)
219                printf("                       ");
220        printf("\n");
221
222        close(fd);
223        exit(0);
224}
Note: See TracBrowser for help on using the repository browser.