xref: /illumos-gate/usr/src/cmd/nvmeadm/nvmeadm_nsmgmt.c (revision f5f0964ce91892f7482efc86903b0ec7c7b6ba66)
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