]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/nvmecontrol/format.c
Update our devicetree to 4.19 for arm and arm64
[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 static void
47 format_usage(void)
48 {
49         fprintf(stderr, "usage:\n");
50         fprintf(stderr, FORMAT_USAGE);
51         exit(1);
52 }
53
54 void
55 format(int argc, char *argv[])
56 {
57         struct nvme_controller_data     cd;
58         struct nvme_namespace_data      nsd;
59         struct nvme_pt_command          pt;
60         char                            path[64];
61         char                            *target;
62         uint32_t                        nsid;
63         int                             ch, fd;
64         int lbaf = -1, mset = -1, pi = -1, pil = -1, ses = 0;
65
66         if (argc < 2)
67                 format_usage();
68
69         while ((ch = getopt(argc, argv, "f:m:p:l:EC")) != -1) {
70                 switch ((char)ch) {
71                 case 'f':
72                         lbaf = strtol(optarg, NULL, 0);
73                         break;
74                 case 'm':
75                         mset = strtol(optarg, NULL, 0);
76                         break;
77                 case 'p':
78                         pi = strtol(optarg, NULL, 0);
79                         break;
80                 case 'l':
81                         pil = strtol(optarg, NULL, 0);
82                         break;
83                 case 'E':
84                         if (ses == 2)
85                                 errx(1, "-E and -C are mutually exclusive");
86                         ses = 1;
87                         break;
88                 case 'C':
89                         if (ses == 1)
90                                 errx(1, "-E and -C are mutually exclusive");
91                         ses = 2;
92                         break;
93                 default:
94                         format_usage();
95                 }
96         }
97
98         /* Check that a controller or namespace was specified. */
99         if (optind >= argc)
100                 format_usage();
101         target = argv[optind];
102
103         /*
104          * Check if the specified device node exists before continuing.
105          * This is a cleaner check for cases where the correct controller
106          * is specified, but an invalid namespace on that controller.
107          */
108         open_dev(target, &fd, 1, 1);
109
110         /*
111          * If device node contains "ns", we consider it a namespace,
112          * otherwise, consider it a controller.
113          */
114         if (strstr(target, NVME_NS_PREFIX) == NULL) {
115                 nsid = NVME_GLOBAL_NAMESPACE_TAG;
116         } else {
117                 /*
118                  * We send FORMAT commands to the controller, not the namespace,
119                  * since it is an admin cmd.  The namespace ID will be specified
120                  * in the command itself.  So parse the namespace's device node
121                  * string to get the controller substring and namespace ID.
122                  */
123                 close(fd);
124                 parse_ns_str(target, path, &nsid);
125                 open_dev(path, &fd, 1, 1);
126         }
127
128         /* Check that controller can execute this command. */
129         read_controller_data(fd, &cd);
130         if (((cd.oacs >> NVME_CTRLR_DATA_OACS_FORMAT_SHIFT) &
131             NVME_CTRLR_DATA_OACS_FORMAT_MASK) == 0)
132                 errx(1, "controller does not support format");
133         if (((cd.fna >> NVME_CTRLR_DATA_FNA_CRYPTO_ERASE_SHIFT) &
134             NVME_CTRLR_DATA_FNA_CRYPTO_ERASE_MASK) == 0 && ses == 2)
135                 errx(1, "controller does not support cryptographic erase");
136
137         if (nsid != NVME_GLOBAL_NAMESPACE_TAG) {
138                 if (((cd.fna >> NVME_CTRLR_DATA_FNA_FORMAT_ALL_SHIFT) &
139                     NVME_CTRLR_DATA_FNA_FORMAT_ALL_MASK) && ses == 0)
140                         errx(1, "controller does not support per-NS format");
141                 if (((cd.fna >> NVME_CTRLR_DATA_FNA_ERASE_ALL_SHIFT) &
142                     NVME_CTRLR_DATA_FNA_ERASE_ALL_MASK) && ses != 0)
143                         errx(1, "controller does not support per-NS erase");
144
145                 /* Try to keep previous namespace parameters. */
146                 read_namespace_data(fd, nsid, &nsd);
147                 if (lbaf < 0)
148                         lbaf = (nsd.flbas >> NVME_NS_DATA_FLBAS_FORMAT_SHIFT)
149                             & NVME_NS_DATA_FLBAS_FORMAT_MASK;
150                 if (lbaf > nsd.nlbaf)
151                         errx(1, "LBA format is out of range");
152                 if (mset < 0)
153                         mset = (nsd.flbas >> NVME_NS_DATA_FLBAS_EXTENDED_SHIFT)
154                             & NVME_NS_DATA_FLBAS_EXTENDED_MASK;
155                 if (pi < 0)
156                         pi = (nsd.dps >> NVME_NS_DATA_DPS_MD_START_SHIFT)
157                             & NVME_NS_DATA_DPS_MD_START_MASK;
158                 if (pil < 0)
159                         pil = (nsd.dps >> NVME_NS_DATA_DPS_PIT_SHIFT)
160                             & NVME_NS_DATA_DPS_PIT_MASK;
161         } else {
162
163                 /* We have no previous parameters, so default to zeroes. */
164                 if (lbaf < 0)
165                         lbaf = 0;
166                 if (mset < 0)
167                         mset = 0;
168                 if (pi < 0)
169                         pi = 0;
170                 if (pil < 0)
171                         pil = 0;
172         }
173
174         memset(&pt, 0, sizeof(pt));
175         pt.cmd.opc = NVME_OPC_FORMAT_NVM;
176         pt.cmd.nsid = htole32(nsid);
177         pt.cmd.cdw10 = htole32((ses << 9) + (pil << 8) + (pi << 5) +
178             (mset << 4) + lbaf);
179
180         if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
181                 err(1, "format request failed");
182
183         if (nvme_completion_is_error(&pt.cpl))
184                 errx(1, "format request returned error");
185         close(fd);
186         exit(0);
187 }