]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/nvmecontrol/format.c
Integrate capsicum-test into the FreeBSD test suite
[FreeBSD/FreeBSD.git] / sbin / nvmecontrol / format.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (C) 2018 Alexander Motin <mav@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/ioccom.h>
34
35 #include <ctype.h>
36 #include <err.h>
37 #include <fcntl.h>
38 #include <stddef.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43
44 #include "nvmecontrol.h"
45
46 #define FORMAT_USAGE                                                           \
47         "format [-f fmt] [-m mset] [-p pi] [-l pil] [-E] [-C] <controller id|namespace id>\n"
48
49 static void
50 format(const struct nvme_function *nf, int argc, char *argv[])
51 {
52         struct nvme_controller_data     cd;
53         struct nvme_namespace_data      nsd;
54         struct nvme_pt_command          pt;
55         char                            path[64];
56         char                            *target;
57         uint32_t                        nsid;
58         int                             ch, fd;
59         int lbaf = -1, mset = -1, pi = -1, pil = -1, ses = 0;
60
61         if (argc < 2)
62                 usage(nf);
63
64         while ((ch = getopt(argc, argv, "f:m:p:l:EC")) != -1) {
65                 switch ((char)ch) {
66                 case 'f':
67                         lbaf = strtol(optarg, NULL, 0);
68                         break;
69                 case 'm':
70                         mset = strtol(optarg, NULL, 0);
71                         break;
72                 case 'p':
73                         pi = strtol(optarg, NULL, 0);
74                         break;
75                 case 'l':
76                         pil = strtol(optarg, NULL, 0);
77                         break;
78                 case 'E':
79                         if (ses == 2)
80                                 errx(1, "-E and -C are mutually exclusive");
81                         ses = 1;
82                         break;
83                 case 'C':
84                         if (ses == 1)
85                                 errx(1, "-E and -C are mutually exclusive");
86                         ses = 2;
87                         break;
88                 default:
89                         usage(nf);
90                 }
91         }
92
93         /* Check that a controller or namespace was specified. */
94         if (optind >= argc)
95                 usage(nf);
96         target = argv[optind];
97
98         /*
99          * Check if the specified device node exists before continuing.
100          * This is a cleaner check for cases where the correct controller
101          * is specified, but an invalid namespace on that controller.
102          */
103         open_dev(target, &fd, 1, 1);
104
105         /*
106          * If device node contains "ns", we consider it a namespace,
107          * otherwise, consider it a controller.
108          */
109         if (strstr(target, NVME_NS_PREFIX) == NULL) {
110                 nsid = NVME_GLOBAL_NAMESPACE_TAG;
111         } else {
112                 /*
113                  * We send FORMAT commands to the controller, not the namespace,
114                  * since it is an admin cmd.  The namespace ID will be specified
115                  * in the command itself.  So parse the namespace's device node
116                  * string to get the controller substring and namespace ID.
117                  */
118                 close(fd);
119                 parse_ns_str(target, path, &nsid);
120                 open_dev(path, &fd, 1, 1);
121         }
122
123         /* Check that controller can execute this command. */
124         read_controller_data(fd, &cd);
125         if (((cd.oacs >> NVME_CTRLR_DATA_OACS_FORMAT_SHIFT) &
126             NVME_CTRLR_DATA_OACS_FORMAT_MASK) == 0)
127                 errx(1, "controller does not support format");
128         if (((cd.fna >> NVME_CTRLR_DATA_FNA_CRYPTO_ERASE_SHIFT) &
129             NVME_CTRLR_DATA_FNA_CRYPTO_ERASE_MASK) == 0 && ses == 2)
130                 errx(1, "controller does not support cryptographic erase");
131
132         if (nsid != NVME_GLOBAL_NAMESPACE_TAG) {
133                 if (((cd.fna >> NVME_CTRLR_DATA_FNA_FORMAT_ALL_SHIFT) &
134                     NVME_CTRLR_DATA_FNA_FORMAT_ALL_MASK) && ses == 0)
135                         errx(1, "controller does not support per-NS format");
136                 if (((cd.fna >> NVME_CTRLR_DATA_FNA_ERASE_ALL_SHIFT) &
137                     NVME_CTRLR_DATA_FNA_ERASE_ALL_MASK) && ses != 0)
138                         errx(1, "controller does not support per-NS erase");
139
140                 /* Try to keep previous namespace parameters. */
141                 read_namespace_data(fd, nsid, &nsd);
142                 if (lbaf < 0)
143                         lbaf = (nsd.flbas >> NVME_NS_DATA_FLBAS_FORMAT_SHIFT)
144                             & NVME_NS_DATA_FLBAS_FORMAT_MASK;
145                 if (lbaf > nsd.nlbaf)
146                         errx(1, "LBA format is out of range");
147                 if (mset < 0)
148                         mset = (nsd.flbas >> NVME_NS_DATA_FLBAS_EXTENDED_SHIFT)
149                             & NVME_NS_DATA_FLBAS_EXTENDED_MASK;
150                 if (pi < 0)
151                         pi = (nsd.dps >> NVME_NS_DATA_DPS_MD_START_SHIFT)
152                             & NVME_NS_DATA_DPS_MD_START_MASK;
153                 if (pil < 0)
154                         pil = (nsd.dps >> NVME_NS_DATA_DPS_PIT_SHIFT)
155                             & NVME_NS_DATA_DPS_PIT_MASK;
156         } else {
157
158                 /* We have no previous parameters, so default to zeroes. */
159                 if (lbaf < 0)
160                         lbaf = 0;
161                 if (mset < 0)
162                         mset = 0;
163                 if (pi < 0)
164                         pi = 0;
165                 if (pil < 0)
166                         pil = 0;
167         }
168
169         memset(&pt, 0, sizeof(pt));
170         pt.cmd.opc = NVME_OPC_FORMAT_NVM;
171         pt.cmd.nsid = htole32(nsid);
172         pt.cmd.cdw10 = htole32((ses << 9) + (pil << 8) + (pi << 5) +
173             (mset << 4) + lbaf);
174
175         if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
176                 err(1, "format request failed");
177
178         if (nvme_completion_is_error(&pt.cpl))
179                 errx(1, "format request returned error");
180         close(fd);
181         exit(0);
182 }
183
184 NVME_COMMAND(top, format, format, FORMAT_USAGE);