1*f5f0964cSRobert Mustacchi /*
2*f5f0964cSRobert Mustacchi * This file and its contents are supplied under the terms of the
3*f5f0964cSRobert Mustacchi * Common Development and Distribution License ("CDDL"), version 1.0.
4*f5f0964cSRobert Mustacchi * You may only use this file in accordance with the terms of version
5*f5f0964cSRobert Mustacchi * 1.0 of the CDDL.
6*f5f0964cSRobert Mustacchi *
7*f5f0964cSRobert Mustacchi * A full copy of the text of the CDDL should have accompanied this
8*f5f0964cSRobert Mustacchi * source. A copy of the CDDL is also available via the Internet at
9*f5f0964cSRobert Mustacchi * http://www.illumos.org/license/CDDL.
10*f5f0964cSRobert Mustacchi */
11*f5f0964cSRobert Mustacchi
12*f5f0964cSRobert Mustacchi /*
13*f5f0964cSRobert Mustacchi * Copyright 2025 Oxide Computer Company
14*f5f0964cSRobert Mustacchi */
15*f5f0964cSRobert Mustacchi
16*f5f0964cSRobert Mustacchi /*
17*f5f0964cSRobert Mustacchi * NVMe Namespace Management Commands
18*f5f0964cSRobert Mustacchi */
19*f5f0964cSRobert Mustacchi
20*f5f0964cSRobert Mustacchi #include <err.h>
21*f5f0964cSRobert Mustacchi #include <string.h>
22*f5f0964cSRobert Mustacchi #include <sys/sysmacros.h>
23*f5f0964cSRobert Mustacchi
24*f5f0964cSRobert Mustacchi #include "nvmeadm.h"
25*f5f0964cSRobert Mustacchi
26*f5f0964cSRobert Mustacchi /*
27*f5f0964cSRobert Mustacchi * Attempt to parse a string with a power of 2 unit suffix into a uint64_t. We
28*f5f0964cSRobert Mustacchi * stop allowing suffixes at PiB as we're trying to fit this into a uint64_t and
29*f5f0964cSRobert Mustacchi * there aren't really many valid values of EiB. In the future when we have
30*f5f0964cSRobert Mustacchi * devices with such large capacities, we should change this to return a
31*f5f0964cSRobert Mustacchi * uint128_t style value as it's possible that with a larger block size, that
32*f5f0964cSRobert Mustacchi * this will make more sense. When we do that, we should probably also figure
33*f5f0964cSRobert Mustacchi * out how we want to commonize this function across the tree.
34*f5f0964cSRobert Mustacchi */
35*f5f0964cSRobert Mustacchi static uint64_t
nvmeadm_parse_units(const char * str,const char * desc)36*f5f0964cSRobert Mustacchi nvmeadm_parse_units(const char *str, const char *desc)
37*f5f0964cSRobert Mustacchi {
38*f5f0964cSRobert Mustacchi unsigned long long l;
39*f5f0964cSRobert Mustacchi char *eptr;
40*f5f0964cSRobert Mustacchi const char units[] = { 'B', 'K', 'M', 'G', 'T', 'P' };
41*f5f0964cSRobert Mustacchi
42*f5f0964cSRobert Mustacchi errno = 0;
43*f5f0964cSRobert Mustacchi l = strtoull(str, &eptr, 0);
44*f5f0964cSRobert Mustacchi if (errno != 0) {
45*f5f0964cSRobert Mustacchi err(-1, "failed to parse %s: %s", desc, str);
46*f5f0964cSRobert Mustacchi }
47*f5f0964cSRobert Mustacchi
48*f5f0964cSRobert Mustacchi if (*eptr == '\0') {
49*f5f0964cSRobert Mustacchi return ((uint64_t)l);
50*f5f0964cSRobert Mustacchi }
51*f5f0964cSRobert Mustacchi
52*f5f0964cSRobert Mustacchi if (eptr[1] != '\0') {
53*f5f0964cSRobert Mustacchi errx(-1, "failed to parse %s unit suffix: %s", desc, eptr);
54*f5f0964cSRobert Mustacchi }
55*f5f0964cSRobert Mustacchi
56*f5f0964cSRobert Mustacchi for (size_t i = 0; i < ARRAY_SIZE(units); i++) {
57*f5f0964cSRobert Mustacchi if (strncasecmp(eptr, &units[i], 1) != 0) {
58*f5f0964cSRobert Mustacchi continue;
59*f5f0964cSRobert Mustacchi }
60*f5f0964cSRobert Mustacchi
61*f5f0964cSRobert Mustacchi for (; i > 0; i--) {
62*f5f0964cSRobert Mustacchi const uint64_t max = UINT64_MAX / 1024;
63*f5f0964cSRobert Mustacchi
64*f5f0964cSRobert Mustacchi if (l > max) {
65*f5f0964cSRobert Mustacchi errx(-1, "%s value %s would overflow a "
66*f5f0964cSRobert Mustacchi "uint64_t", desc, str);
67*f5f0964cSRobert Mustacchi }
68*f5f0964cSRobert Mustacchi
69*f5f0964cSRobert Mustacchi l *= 1024;
70*f5f0964cSRobert Mustacchi }
71*f5f0964cSRobert Mustacchi
72*f5f0964cSRobert Mustacchi return ((uint64_t)l);
73*f5f0964cSRobert Mustacchi }
74*f5f0964cSRobert Mustacchi
75*f5f0964cSRobert Mustacchi errx(-1, "invalid %s unit suffix: %s", desc, eptr);
76*f5f0964cSRobert Mustacchi }
77*f5f0964cSRobert Mustacchi
78*f5f0964cSRobert Mustacchi /*
79*f5f0964cSRobert Mustacchi * Today create-namespace takes a limited number of arguments. Here is how we
80*f5f0964cSRobert Mustacchi * expect it to continue to change over time:
81*f5f0964cSRobert Mustacchi *
82*f5f0964cSRobert Mustacchi * 1) First, we have a limited number of short options that we support. If we
83*f5f0964cSRobert Mustacchi * ever support long options, these should match the NVMe name for the option,
84*f5f0964cSRobert Mustacchi * e.g. --nsze, --ncap, --nmic, etc.
85*f5f0964cSRobert Mustacchi *
86*f5f0964cSRobert Mustacchi * 2) Today we require that this operates only when the namespace is already
87*f5f0964cSRobert Mustacchi * detached from a controller. If we want to change this behavior then we should
88*f5f0964cSRobert Mustacchi * add something such as a [-R] flag to indicate that it should take all the
89*f5f0964cSRobert Mustacchi * other steps necessary recursively.
90*f5f0964cSRobert Mustacchi *
91*f5f0964cSRobert Mustacchi * 3) Most other options have a default that indicates that they're unused or
92*f5f0964cSRobert Mustacchi * similar. This allows us to add additional option arguments. Some of these may
93*f5f0964cSRobert Mustacchi * end up with aliases for the default case, e.g. -t nvm for the default NVM
94*f5f0964cSRobert Mustacchi * CSI.
95*f5f0964cSRobert Mustacchi *
96*f5f0964cSRobert Mustacchi * 4) We only support specifying the size of a namespace in bytes today. If we
97*f5f0964cSRobert Mustacchi * want to change this we should add a flag like a -B that specifies that all
98*f5f0964cSRobert Mustacchi * sizes are in units of the logical block.
99*f5f0964cSRobert Mustacchi */
100*f5f0964cSRobert Mustacchi void
usage_create_ns(const char * c_name)101*f5f0964cSRobert Mustacchi usage_create_ns(const char *c_name)
102*f5f0964cSRobert Mustacchi {
103*f5f0964cSRobert Mustacchi (void) fprintf(stderr, "%s -f flbas | -b block-size [-c cap] "
104*f5f0964cSRobert Mustacchi "[-n nmic]\n\t [-t type] <ctl> <size>\n\n"
105*f5f0964cSRobert Mustacchi " Create a new namespace on the specified controller of the "
106*f5f0964cSRobert Mustacchi "requested size. The\n size is specified in bytes and may use "
107*f5f0964cSRobert Mustacchi "any suffix such as B (bytes), K\n (kibibytes, 2^10), M "
108*f5f0964cSRobert Mustacchi "(mibibytes, 2^20), G (gibibytes, 2^30), T (tebibytes,\n 2^40), "
109*f5f0964cSRobert Mustacchi "etc. The size must be a multiple of the selected block size. The\n"
110*f5f0964cSRobert Mustacchi " controller may impose additional alignment constraints.\n",
111*f5f0964cSRobert Mustacchi c_name);
112*f5f0964cSRobert Mustacchi }
113*f5f0964cSRobert Mustacchi
114*f5f0964cSRobert Mustacchi void
optparse_create_ns(nvme_process_arg_t * npa)115*f5f0964cSRobert Mustacchi optparse_create_ns(nvme_process_arg_t *npa)
116*f5f0964cSRobert Mustacchi {
117*f5f0964cSRobert Mustacchi int c;
118*f5f0964cSRobert Mustacchi nvmeadm_create_ns_t *ncn;
119*f5f0964cSRobert Mustacchi const char *nmic = NULL, *type = NULL, *cap = NULL;
120*f5f0964cSRobert Mustacchi const char *bs = NULL, *flbas = NULL;
121*f5f0964cSRobert Mustacchi
122*f5f0964cSRobert Mustacchi if ((ncn = calloc(1, sizeof (nvmeadm_create_ns_t))) == NULL) {
123*f5f0964cSRobert Mustacchi err(-1, "failed to allocate memory to track create-namespace "
124*f5f0964cSRobert Mustacchi "information");
125*f5f0964cSRobert Mustacchi }
126*f5f0964cSRobert Mustacchi
127*f5f0964cSRobert Mustacchi npa->npa_cmd_arg = ncn;
128*f5f0964cSRobert Mustacchi
129*f5f0964cSRobert Mustacchi while ((c = getopt(npa->npa_argc, npa->npa_argv, ":b:c:f:n:t:")) !=
130*f5f0964cSRobert Mustacchi -1) {
131*f5f0964cSRobert Mustacchi switch (c) {
132*f5f0964cSRobert Mustacchi case 'b':
133*f5f0964cSRobert Mustacchi bs = optarg;
134*f5f0964cSRobert Mustacchi break;
135*f5f0964cSRobert Mustacchi case 'c':
136*f5f0964cSRobert Mustacchi cap = optarg;
137*f5f0964cSRobert Mustacchi break;
138*f5f0964cSRobert Mustacchi case 'f':
139*f5f0964cSRobert Mustacchi flbas = optarg;
140*f5f0964cSRobert Mustacchi break;
141*f5f0964cSRobert Mustacchi case 'n':
142*f5f0964cSRobert Mustacchi nmic = optarg;
143*f5f0964cSRobert Mustacchi break;
144*f5f0964cSRobert Mustacchi case 't':
145*f5f0964cSRobert Mustacchi type = optarg;
146*f5f0964cSRobert Mustacchi break;
147*f5f0964cSRobert Mustacchi case '?':
148*f5f0964cSRobert Mustacchi errx(-1, "unknown option: -%c", optopt);
149*f5f0964cSRobert Mustacchi case ':':
150*f5f0964cSRobert Mustacchi errx(-1, "option -%c requires an argument", optopt);
151*f5f0964cSRobert Mustacchi }
152*f5f0964cSRobert Mustacchi }
153*f5f0964cSRobert Mustacchi
154*f5f0964cSRobert Mustacchi if (flbas != NULL && bs != NULL) {
155*f5f0964cSRobert Mustacchi errx(-1, "only one of -b and -f may be specified");
156*f5f0964cSRobert Mustacchi }
157*f5f0964cSRobert Mustacchi
158*f5f0964cSRobert Mustacchi if (flbas == NULL && bs == NULL) {
159*f5f0964cSRobert Mustacchi errx(-1, "at least one of -b and -f must be specified");
160*f5f0964cSRobert Mustacchi }
161*f5f0964cSRobert Mustacchi
162*f5f0964cSRobert Mustacchi if (flbas != NULL) {
163*f5f0964cSRobert Mustacchi const char *err;
164*f5f0964cSRobert Mustacchi ncn->ncn_use_flbas = B_TRUE;
165*f5f0964cSRobert Mustacchi ncn->ncn_lba = strtonumx(flbas, 0, NVME_MAX_LBAF - 1, &err, 0);
166*f5f0964cSRobert Mustacchi if (err != NULL) {
167*f5f0964cSRobert Mustacchi errx(-1, "failed to parse formatted LBA index: %s is "
168*f5f0964cSRobert Mustacchi "%s, valid values are between 0 and %u",
169*f5f0964cSRobert Mustacchi flbas, err, NVME_MAX_LBAF - 1);
170*f5f0964cSRobert Mustacchi }
171*f5f0964cSRobert Mustacchi }
172*f5f0964cSRobert Mustacchi
173*f5f0964cSRobert Mustacchi if (bs != NULL) {
174*f5f0964cSRobert Mustacchi ncn->ncn_use_flbas = B_FALSE;
175*f5f0964cSRobert Mustacchi ncn->ncn_lba = nvmeadm_parse_units(bs, "block-size");
176*f5f0964cSRobert Mustacchi }
177*f5f0964cSRobert Mustacchi
178*f5f0964cSRobert Mustacchi if (cap != NULL) {
179*f5f0964cSRobert Mustacchi ncn->ncn_cap = nvmeadm_parse_units(cap, "block-size");
180*f5f0964cSRobert Mustacchi } else {
181*f5f0964cSRobert Mustacchi ncn->ncn_cap = UINT64_MAX;
182*f5f0964cSRobert Mustacchi }
183*f5f0964cSRobert Mustacchi
184*f5f0964cSRobert Mustacchi if (type != NULL) {
185*f5f0964cSRobert Mustacchi if (strcasecmp(type, "nvm") == 0) {
186*f5f0964cSRobert Mustacchi ncn->ncn_csi = NVME_CSI_NVM;
187*f5f0964cSRobert Mustacchi } else if (strcasecmp(type, "kv") == 0) {
188*f5f0964cSRobert Mustacchi ncn->ncn_csi = NVME_CSI_KV;
189*f5f0964cSRobert Mustacchi } else if (strcasecmp(type, "zns") == 0) {
190*f5f0964cSRobert Mustacchi ncn->ncn_csi = NVME_CSI_ZNS;
191*f5f0964cSRobert Mustacchi } else {
192*f5f0964cSRobert Mustacchi errx(-1, "unknown CSI type string: '%s'; valid values "
193*f5f0964cSRobert Mustacchi "are 'nvm', 'kv', and 'zns'", type);
194*f5f0964cSRobert Mustacchi }
195*f5f0964cSRobert Mustacchi } else {
196*f5f0964cSRobert Mustacchi ncn->ncn_csi = NVME_CSI_NVM;
197*f5f0964cSRobert Mustacchi }
198*f5f0964cSRobert Mustacchi
199*f5f0964cSRobert Mustacchi if (nmic != NULL) {
200*f5f0964cSRobert Mustacchi if (strcasecmp(nmic, "none") == 0) {
201*f5f0964cSRobert Mustacchi ncn->ncn_nmic = NVME_NS_NMIC_T_NONE;
202*f5f0964cSRobert Mustacchi } else if (strcasecmp(nmic, "shared") == 0) {
203*f5f0964cSRobert Mustacchi ncn->ncn_nmic = NVME_NS_NMIC_T_SHARED;
204*f5f0964cSRobert Mustacchi } else {
205*f5f0964cSRobert Mustacchi errx(-1, "unknown nmic string: '%s'; valid values are "
206*f5f0964cSRobert Mustacchi "'none' and 'shared'", nmic);
207*f5f0964cSRobert Mustacchi }
208*f5f0964cSRobert Mustacchi } else {
209*f5f0964cSRobert Mustacchi ncn->ncn_nmic = NVME_NS_NMIC_T_NONE;
210*f5f0964cSRobert Mustacchi }
211*f5f0964cSRobert Mustacchi
212*f5f0964cSRobert Mustacchi if (npa->npa_argc - optind > 2) {
213*f5f0964cSRobert Mustacchi errx(-1, "%s passed extraneous arguments starting with %s",
214*f5f0964cSRobert Mustacchi npa->npa_cmd->c_name, npa->npa_argv[optind + 2]);
215*f5f0964cSRobert Mustacchi } else if (npa->npa_argc - optind != 2) {
216*f5f0964cSRobert Mustacchi errx(-1, "missing required size parameter");
217*f5f0964cSRobert Mustacchi }
218*f5f0964cSRobert Mustacchi
219*f5f0964cSRobert Mustacchi ncn->ncn_size = nvmeadm_parse_units(npa->npa_argv[optind + 1],
220*f5f0964cSRobert Mustacchi "namespace size");
221*f5f0964cSRobert Mustacchi if (cap == NULL) {
222*f5f0964cSRobert Mustacchi ncn->ncn_cap = ncn->ncn_size;
223*f5f0964cSRobert Mustacchi }
224*f5f0964cSRobert Mustacchi }
225*f5f0964cSRobert Mustacchi
226*f5f0964cSRobert Mustacchi static const nvme_nvm_lba_fmt_t *
do_create_ns_find_lba(const nvme_process_arg_t * npa,const nvmeadm_create_ns_t * ncn)227*f5f0964cSRobert Mustacchi do_create_ns_find_lba(const nvme_process_arg_t *npa,
228*f5f0964cSRobert Mustacchi const nvmeadm_create_ns_t *ncn)
229*f5f0964cSRobert Mustacchi {
230*f5f0964cSRobert Mustacchi const uint32_t nfmts = nvme_ctrl_info_nformats(npa->npa_ctrl_info);
231*f5f0964cSRobert Mustacchi const nvme_nvm_lba_fmt_t *best = NULL;
232*f5f0964cSRobert Mustacchi uint32_t best_rp = UINT32_MAX;
233*f5f0964cSRobert Mustacchi
234*f5f0964cSRobert Mustacchi for (size_t i = 0; i < nfmts; i++) {
235*f5f0964cSRobert Mustacchi const nvme_nvm_lba_fmt_t *fmt;
236*f5f0964cSRobert Mustacchi uint32_t rp;
237*f5f0964cSRobert Mustacchi
238*f5f0964cSRobert Mustacchi if (!nvme_ctrl_info_format(npa->npa_ctrl_info, i, &fmt)) {
239*f5f0964cSRobert Mustacchi continue;
240*f5f0964cSRobert Mustacchi }
241*f5f0964cSRobert Mustacchi
242*f5f0964cSRobert Mustacchi if (nvme_nvm_lba_fmt_meta_size(fmt) != 0)
243*f5f0964cSRobert Mustacchi continue;
244*f5f0964cSRobert Mustacchi
245*f5f0964cSRobert Mustacchi if (nvme_nvm_lba_fmt_data_size(fmt) != ncn->ncn_lba)
246*f5f0964cSRobert Mustacchi continue;
247*f5f0964cSRobert Mustacchi
248*f5f0964cSRobert Mustacchi rp = nvme_nvm_lba_fmt_rel_perf(fmt);
249*f5f0964cSRobert Mustacchi if (rp < best_rp) {
250*f5f0964cSRobert Mustacchi best_rp = rp;
251*f5f0964cSRobert Mustacchi best = fmt;
252*f5f0964cSRobert Mustacchi }
253*f5f0964cSRobert Mustacchi }
254*f5f0964cSRobert Mustacchi
255*f5f0964cSRobert Mustacchi if (best == NULL) {
256*f5f0964cSRobert Mustacchi errx(-1, "failed to find an LBA format with %u byte block size",
257*f5f0964cSRobert Mustacchi ncn->ncn_lba);
258*f5f0964cSRobert Mustacchi }
259*f5f0964cSRobert Mustacchi
260*f5f0964cSRobert Mustacchi return (best);
261*f5f0964cSRobert Mustacchi }
262*f5f0964cSRobert Mustacchi
263*f5f0964cSRobert Mustacchi int
do_create_ns(const nvme_process_arg_t * npa)264*f5f0964cSRobert Mustacchi do_create_ns(const nvme_process_arg_t *npa)
265*f5f0964cSRobert Mustacchi {
266*f5f0964cSRobert Mustacchi const nvmeadm_create_ns_t *ncn = npa->npa_cmd_arg;
267*f5f0964cSRobert Mustacchi nvme_ns_create_req_t *req;
268*f5f0964cSRobert Mustacchi const nvme_nvm_lba_fmt_t *lba;
269*f5f0964cSRobert Mustacchi uint32_t nsid, flbas, ds;
270*f5f0964cSRobert Mustacchi uint64_t size;
271*f5f0964cSRobert Mustacchi
272*f5f0964cSRobert Mustacchi if (npa->npa_ns != NULL) {
273*f5f0964cSRobert Mustacchi errx(-1, "%s cannot be used on namespaces",
274*f5f0964cSRobert Mustacchi npa->npa_cmd->c_name);
275*f5f0964cSRobert Mustacchi }
276*f5f0964cSRobert Mustacchi
277*f5f0964cSRobert Mustacchi /*
278*f5f0964cSRobert Mustacchi * This should have been checked above.
279*f5f0964cSRobert Mustacchi */
280*f5f0964cSRobert Mustacchi if (npa->npa_argc > 1) {
281*f5f0964cSRobert Mustacchi errx(-1, "%s passed extraneous arguments starting with %s",
282*f5f0964cSRobert Mustacchi npa->npa_cmd->c_name, npa->npa_argv[1]);
283*f5f0964cSRobert Mustacchi }
284*f5f0964cSRobert Mustacchi
285*f5f0964cSRobert Mustacchi /*
286*f5f0964cSRobert Mustacchi * If we were given a block size rather than the formatted LBA size, go
287*f5f0964cSRobert Mustacchi * deal with converting that now.
288*f5f0964cSRobert Mustacchi */
289*f5f0964cSRobert Mustacchi if (!ncn->ncn_use_flbas) {
290*f5f0964cSRobert Mustacchi lba = do_create_ns_find_lba(npa, ncn);
291*f5f0964cSRobert Mustacchi } else {
292*f5f0964cSRobert Mustacchi if (!nvme_ctrl_info_format(npa->npa_ctrl_info, ncn->ncn_lba,
293*f5f0964cSRobert Mustacchi &lba)) {
294*f5f0964cSRobert Mustacchi nvmeadm_fatal(npa, "failed to look up LBA format index "
295*f5f0964cSRobert Mustacchi "%u", ncn->ncn_lba);
296*f5f0964cSRobert Mustacchi }
297*f5f0964cSRobert Mustacchi }
298*f5f0964cSRobert Mustacchi
299*f5f0964cSRobert Mustacchi if (!nvme_ns_create_req_init_by_csi(npa->npa_ctrl, ncn->ncn_csi,
300*f5f0964cSRobert Mustacchi &req)) {
301*f5f0964cSRobert Mustacchi nvmeadm_fatal(npa, "failed to initialize namespace create "
302*f5f0964cSRobert Mustacchi "request");
303*f5f0964cSRobert Mustacchi }
304*f5f0964cSRobert Mustacchi
305*f5f0964cSRobert Mustacchi ds = nvme_nvm_lba_fmt_data_size(lba);
306*f5f0964cSRobert Mustacchi flbas = nvme_nvm_lba_fmt_id(lba);
307*f5f0964cSRobert Mustacchi if (!nvme_ns_create_req_set_flbas(req, flbas)) {
308*f5f0964cSRobert Mustacchi nvmeadm_fatal(npa, "failed to set namespace create request "
309*f5f0964cSRobert Mustacchi "formatted LBA index to %u", flbas);
310*f5f0964cSRobert Mustacchi }
311*f5f0964cSRobert Mustacchi
312*f5f0964cSRobert Mustacchi if (ncn->ncn_size % ds != 0) {
313*f5f0964cSRobert Mustacchi nvmeadm_fatal(npa, "requested namespace size 0x%lx is not a "
314*f5f0964cSRobert Mustacchi "multiple of the requested LBA block size (0x%x)",
315*f5f0964cSRobert Mustacchi ncn->ncn_size, ds);
316*f5f0964cSRobert Mustacchi }
317*f5f0964cSRobert Mustacchi size = ncn->ncn_size / ds;
318*f5f0964cSRobert Mustacchi if (!nvme_ns_create_req_set_nsze(req, size)) {
319*f5f0964cSRobert Mustacchi nvmeadm_fatal(npa, "failed to set namespace create request "
320*f5f0964cSRobert Mustacchi "namespace size to 0x%lx", size);
321*f5f0964cSRobert Mustacchi }
322*f5f0964cSRobert Mustacchi
323*f5f0964cSRobert Mustacchi if (ncn->ncn_cap % ds != 0) {
324*f5f0964cSRobert Mustacchi nvmeadm_fatal(npa, "requested namespace capacity 0x%lx is not "
325*f5f0964cSRobert Mustacchi "a multiple of the requested LBA block size (0x%x)",
326*f5f0964cSRobert Mustacchi ncn->ncn_cap, ds);
327*f5f0964cSRobert Mustacchi }
328*f5f0964cSRobert Mustacchi size = ncn->ncn_cap/ ds;
329*f5f0964cSRobert Mustacchi if (!nvme_ns_create_req_set_ncap(req, size)) {
330*f5f0964cSRobert Mustacchi nvmeadm_fatal(npa, "failed to set namespace create request "
331*f5f0964cSRobert Mustacchi "namespace capacity to 0x%lx", size);
332*f5f0964cSRobert Mustacchi }
333*f5f0964cSRobert Mustacchi
334*f5f0964cSRobert Mustacchi if (!nvme_ns_create_req_set_nmic(req, ncn->ncn_nmic)) {
335*f5f0964cSRobert Mustacchi nvmeadm_fatal(npa, "failed to set namespace multipath I/O and "
336*f5f0964cSRobert Mustacchi "sharing capabilities to 0x%x", ncn->ncn_nmic);
337*f5f0964cSRobert Mustacchi }
338*f5f0964cSRobert Mustacchi
339*f5f0964cSRobert Mustacchi if (!nvme_ns_create_req_exec(req)) {
340*f5f0964cSRobert Mustacchi nvmeadm_fatal(npa, "failed to execute namespace create "
341*f5f0964cSRobert Mustacchi "request");
342*f5f0964cSRobert Mustacchi }
343*f5f0964cSRobert Mustacchi
344*f5f0964cSRobert Mustacchi if (!nvme_ns_create_req_get_nsid(req, &nsid)) {
345*f5f0964cSRobert Mustacchi nvmeadm_fatal(npa, "Failed to retrieve the new namespace ID");
346*f5f0964cSRobert Mustacchi }
347*f5f0964cSRobert Mustacchi
348*f5f0964cSRobert Mustacchi nvme_ns_create_req_fini(req);
349*f5f0964cSRobert Mustacchi
350*f5f0964cSRobert Mustacchi (void) printf("created namespace %s/%u\n", npa->npa_ctrl_name, nsid);
351*f5f0964cSRobert Mustacchi return (EXIT_SUCCESS);
352*f5f0964cSRobert Mustacchi }
353*f5f0964cSRobert Mustacchi
354*f5f0964cSRobert Mustacchi void
usage_delete_ns(const char * c_name)355*f5f0964cSRobert Mustacchi usage_delete_ns(const char *c_name)
356*f5f0964cSRobert Mustacchi {
357*f5f0964cSRobert Mustacchi (void) fprintf(stderr, "%s <ctl>/<ns>\n\n"
358*f5f0964cSRobert Mustacchi " Delete the specified namespace. It must be first detached from "
359*f5f0964cSRobert Mustacchi "all\n controllers. Controllers can be detached from a namespace "
360*f5f0964cSRobert Mustacchi "with the\n detach-namespace sub-command.\n", c_name);
361*f5f0964cSRobert Mustacchi }
362*f5f0964cSRobert Mustacchi
363*f5f0964cSRobert Mustacchi int
do_delete_ns(const nvme_process_arg_t * npa)364*f5f0964cSRobert Mustacchi do_delete_ns(const nvme_process_arg_t *npa)
365*f5f0964cSRobert Mustacchi {
366*f5f0964cSRobert Mustacchi nvme_ns_delete_req_t *req;
367*f5f0964cSRobert Mustacchi
368*f5f0964cSRobert Mustacchi if (npa->npa_ns == NULL) {
369*f5f0964cSRobert Mustacchi errx(-1, "%s cannot be used on controllers",
370*f5f0964cSRobert Mustacchi npa->npa_cmd->c_name);
371*f5f0964cSRobert Mustacchi }
372*f5f0964cSRobert Mustacchi
373*f5f0964cSRobert Mustacchi if (npa->npa_argc > 0) {
374*f5f0964cSRobert Mustacchi errx(-1, "%s passed extraneous arguments starting with %s",
375*f5f0964cSRobert Mustacchi npa->npa_cmd->c_name, npa->npa_argv[0]);
376*f5f0964cSRobert Mustacchi }
377*f5f0964cSRobert Mustacchi
378*f5f0964cSRobert Mustacchi if (!nvme_ns_delete_req_init(npa->npa_ctrl, &req)) {
379*f5f0964cSRobert Mustacchi nvmeadm_fatal(npa, "failed to initialize namespace delete "
380*f5f0964cSRobert Mustacchi "request");
381*f5f0964cSRobert Mustacchi }
382*f5f0964cSRobert Mustacchi
383*f5f0964cSRobert Mustacchi const uint32_t nsid = nvme_ns_info_nsid(npa->npa_ns_info);
384*f5f0964cSRobert Mustacchi if (!nvme_ns_delete_req_set_nsid(req, nsid)) {
385*f5f0964cSRobert Mustacchi nvmeadm_fatal(npa, "failed to set namespace delete request "
386*f5f0964cSRobert Mustacchi "namespace ID to 0x%x", nsid);
387*f5f0964cSRobert Mustacchi }
388*f5f0964cSRobert Mustacchi
389*f5f0964cSRobert Mustacchi if (!nvme_ns_delete_req_exec(req)) {
390*f5f0964cSRobert Mustacchi nvmeadm_fatal(npa, "failed to execute namespace delete "
391*f5f0964cSRobert Mustacchi "request");
392*f5f0964cSRobert Mustacchi }
393*f5f0964cSRobert Mustacchi
394*f5f0964cSRobert Mustacchi nvme_ns_delete_req_fini(req);
395*f5f0964cSRobert Mustacchi return (EXIT_SUCCESS);
396*f5f0964cSRobert Mustacchi }
397*f5f0964cSRobert Mustacchi
398*f5f0964cSRobert Mustacchi /*
399*f5f0964cSRobert Mustacchi * Currently both attach namespace and detach namespace only will perform an
400*f5f0964cSRobert Mustacchi * attach or detach of the namespace from the current controller in the system.
401*f5f0964cSRobert Mustacchi * In the future, we should probably support an argument to provide an explicit
402*f5f0964cSRobert Mustacchi * controller list either in the form of IDs or device names, probably with -c
403*f5f0964cSRobert Mustacchi * or -C.
404*f5f0964cSRobert Mustacchi */
405*f5f0964cSRobert Mustacchi void
usage_attach_ns(const char * c_name)406*f5f0964cSRobert Mustacchi usage_attach_ns(const char *c_name)
407*f5f0964cSRobert Mustacchi {
408*f5f0964cSRobert Mustacchi (void) fprintf(stderr, "%s <ctl>/<ns>\n\n"
409*f5f0964cSRobert Mustacchi " Attach the specified namespace to the current controller.\n",
410*f5f0964cSRobert Mustacchi c_name);
411*f5f0964cSRobert Mustacchi }
412*f5f0964cSRobert Mustacchi
413*f5f0964cSRobert Mustacchi void
usage_detach_ns(const char * c_name)414*f5f0964cSRobert Mustacchi usage_detach_ns(const char *c_name)
415*f5f0964cSRobert Mustacchi {
416*f5f0964cSRobert Mustacchi (void) fprintf(stderr, "%s <ctl>/<ns>\n\n"
417*f5f0964cSRobert Mustacchi " Detach the specified namespace from its current controller. The "
418*f5f0964cSRobert Mustacchi "namespace\n must have its blkdev instances detached with the "
419*f5f0964cSRobert Mustacchi "detach sub-command.\n", c_name);
420*f5f0964cSRobert Mustacchi }
421*f5f0964cSRobert Mustacchi
422*f5f0964cSRobert Mustacchi static int
do_attach_ns_common(const nvme_process_arg_t * npa,uint32_t sel)423*f5f0964cSRobert Mustacchi do_attach_ns_common(const nvme_process_arg_t *npa, uint32_t sel)
424*f5f0964cSRobert Mustacchi {
425*f5f0964cSRobert Mustacchi const char *desc = sel == NVME_NS_ATTACH_CTRL_ATTACH ? "attach" :
426*f5f0964cSRobert Mustacchi "detach";
427*f5f0964cSRobert Mustacchi nvme_ns_attach_req_t *req;
428*f5f0964cSRobert Mustacchi
429*f5f0964cSRobert Mustacchi if (npa->npa_ns == NULL) {
430*f5f0964cSRobert Mustacchi errx(-1, "%s cannot be used on controllers",
431*f5f0964cSRobert Mustacchi npa->npa_cmd->c_name);
432*f5f0964cSRobert Mustacchi }
433*f5f0964cSRobert Mustacchi
434*f5f0964cSRobert Mustacchi if (npa->npa_argc > 0) {
435*f5f0964cSRobert Mustacchi errx(-1, "%s passed extraneous arguments starting with %s",
436*f5f0964cSRobert Mustacchi npa->npa_cmd->c_name, npa->npa_argv[0]);
437*f5f0964cSRobert Mustacchi }
438*f5f0964cSRobert Mustacchi
439*f5f0964cSRobert Mustacchi if (!nvme_ns_attach_req_init_by_sel(npa->npa_ctrl, sel, &req)) {
440*f5f0964cSRobert Mustacchi nvmeadm_fatal(npa, "failed to initialize controller "
441*f5f0964cSRobert Mustacchi "%s request for %s", desc, npa->npa_name);
442*f5f0964cSRobert Mustacchi }
443*f5f0964cSRobert Mustacchi
444*f5f0964cSRobert Mustacchi const uint32_t nsid = nvme_ns_info_nsid(npa->npa_ns_info);
445*f5f0964cSRobert Mustacchi if (!nvme_ns_attach_req_set_nsid(req, nsid)) {
446*f5f0964cSRobert Mustacchi nvmeadm_fatal(npa, "failed to set namespace to %s to %u",
447*f5f0964cSRobert Mustacchi desc, nsid);
448*f5f0964cSRobert Mustacchi }
449*f5f0964cSRobert Mustacchi
450*f5f0964cSRobert Mustacchi if (!nvme_ns_attach_req_set_ctrlid_self(req)) {
451*f5f0964cSRobert Mustacchi nvmeadm_fatal(npa, "failed to set controller to %s for %s",
452*f5f0964cSRobert Mustacchi desc, npa->npa_name);
453*f5f0964cSRobert Mustacchi }
454*f5f0964cSRobert Mustacchi
455*f5f0964cSRobert Mustacchi if (!nvme_ns_attach_req_exec(req)) {
456*f5f0964cSRobert Mustacchi nvmeadm_fatal(npa, "failed to execute controller %s request",
457*f5f0964cSRobert Mustacchi desc);
458*f5f0964cSRobert Mustacchi }
459*f5f0964cSRobert Mustacchi
460*f5f0964cSRobert Mustacchi nvme_ns_attach_req_fini(req);
461*f5f0964cSRobert Mustacchi return (EXIT_SUCCESS);
462*f5f0964cSRobert Mustacchi }
463*f5f0964cSRobert Mustacchi
464*f5f0964cSRobert Mustacchi int
do_attach_ns(const nvme_process_arg_t * npa)465*f5f0964cSRobert Mustacchi do_attach_ns(const nvme_process_arg_t *npa)
466*f5f0964cSRobert Mustacchi {
467*f5f0964cSRobert Mustacchi return (do_attach_ns_common(npa, NVME_NS_ATTACH_CTRL_ATTACH));
468*f5f0964cSRobert Mustacchi }
469*f5f0964cSRobert Mustacchi
470*f5f0964cSRobert Mustacchi int
do_detach_ns(const nvme_process_arg_t * npa)471*f5f0964cSRobert Mustacchi do_detach_ns(const nvme_process_arg_t *npa)
472*f5f0964cSRobert Mustacchi {
473*f5f0964cSRobert Mustacchi return (do_attach_ns_common(npa, NVME_NS_ATTACH_CTRL_DETACH));
474*f5f0964cSRobert Mustacchi }
475