xref: /illumos-gate/usr/src/common/nvme/nvme_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  * Common field and validation for NVMe Namespace related commands. This covers
18*f5f0964cSRobert Mustacchi  * attaching and detaching controllers to namespaces as well as creating and
19*f5f0964cSRobert Mustacchi  * deleting namespaces.
20*f5f0964cSRobert Mustacchi  */
21*f5f0964cSRobert Mustacchi 
22*f5f0964cSRobert Mustacchi #include "nvme_common.h"
23*f5f0964cSRobert Mustacchi 
24*f5f0964cSRobert Mustacchi #include <sys/sysmacros.h>
25*f5f0964cSRobert Mustacchi 
26*f5f0964cSRobert Mustacchi static bool
nvme_ns_attach_field_valid_sel(const nvme_field_info_t * field,const nvme_valid_ctrl_data_t * data,uint64_t act,char * msg,size_t msglen)27*f5f0964cSRobert Mustacchi nvme_ns_attach_field_valid_sel(const nvme_field_info_t *field,
28*f5f0964cSRobert Mustacchi     const nvme_valid_ctrl_data_t *data, uint64_t act, char *msg, size_t msglen)
29*f5f0964cSRobert Mustacchi {
30*f5f0964cSRobert Mustacchi 	const uint64_t min = NVME_NS_ATTACH_CTRL_ATTACH;
31*f5f0964cSRobert Mustacchi 	const uint64_t max = NVME_NS_ATTACH_CTRL_DETACH;
32*f5f0964cSRobert Mustacchi 
33*f5f0964cSRobert Mustacchi 	return (nvme_field_range_check(field, min, max, msg, msglen, act));
34*f5f0964cSRobert Mustacchi }
35*f5f0964cSRobert Mustacchi 
36*f5f0964cSRobert Mustacchi const nvme_field_info_t nvme_ns_attach_fields[] = {
37*f5f0964cSRobert Mustacchi 	[NVME_NS_ATTACH_REQ_FIELD_SEL] = {
38*f5f0964cSRobert Mustacchi 		.nlfi_vers = &nvme_vers_1v2,
39*f5f0964cSRobert Mustacchi 		.nlfi_valid = nvme_ns_attach_field_valid_sel,
40*f5f0964cSRobert Mustacchi 		.nlfi_spec = "sel",
41*f5f0964cSRobert Mustacchi 		.nlfi_human = "select",
42*f5f0964cSRobert Mustacchi 		.nlfi_def_req = true,
43*f5f0964cSRobert Mustacchi 		.nlfi_def_allow = false
44*f5f0964cSRobert Mustacchi 	},
45*f5f0964cSRobert Mustacchi 	[NVME_NS_ATTACH_REQ_FIELD_NSID] = {
46*f5f0964cSRobert Mustacchi 		.nlfi_vers = &nvme_vers_1v2,
47*f5f0964cSRobert Mustacchi 		.nlfi_valid = nvme_field_valid_nsid,
48*f5f0964cSRobert Mustacchi 		.nlfi_spec = "nsid",
49*f5f0964cSRobert Mustacchi 		.nlfi_human = "namespace ID",
50*f5f0964cSRobert Mustacchi 		.nlfi_def_req = true,
51*f5f0964cSRobert Mustacchi 		.nlfi_def_allow = true
52*f5f0964cSRobert Mustacchi 	},
53*f5f0964cSRobert Mustacchi 	/*
54*f5f0964cSRobert Mustacchi 	 * The interpretation of the data pointer is technically specific to the
55*f5f0964cSRobert Mustacchi 	 * select command. As we don't actually accept any data, right now this
56*f5f0964cSRobert Mustacchi 	 * is here just for libnvme tracking purposes.
57*f5f0964cSRobert Mustacchi 	 */
58*f5f0964cSRobert Mustacchi 	[NVME_NS_ATTACH_REQ_FIELD_DPTR] = {
59*f5f0964cSRobert Mustacchi 		.nlfi_vers = &nvme_vers_1v2,
60*f5f0964cSRobert Mustacchi 		.nlfi_spec = "dptr",
61*f5f0964cSRobert Mustacchi 		.nlfi_human = "data pointer",
62*f5f0964cSRobert Mustacchi 		.nlfi_def_req = true,
63*f5f0964cSRobert Mustacchi 		.nlfi_def_allow = true
64*f5f0964cSRobert Mustacchi 	}
65*f5f0964cSRobert Mustacchi };
66*f5f0964cSRobert Mustacchi 
67*f5f0964cSRobert Mustacchi const size_t nvme_ns_attach_nfields = ARRAY_SIZE(nvme_ns_attach_fields);
68*f5f0964cSRobert Mustacchi 
69*f5f0964cSRobert Mustacchi const nvme_field_info_t nvme_ns_delete_fields[] = {
70*f5f0964cSRobert Mustacchi 	[NVME_NS_DELETE_REQ_FIELD_NSID] = {
71*f5f0964cSRobert Mustacchi 		.nlfi_vers = &nvme_vers_1v2,
72*f5f0964cSRobert Mustacchi 		.nlfi_valid = nvme_field_valid_nsid,
73*f5f0964cSRobert Mustacchi 		.nlfi_spec = "nsid",
74*f5f0964cSRobert Mustacchi 		.nlfi_human = "namespace ID",
75*f5f0964cSRobert Mustacchi 		.nlfi_def_req = true,
76*f5f0964cSRobert Mustacchi 		.nlfi_def_allow = true
77*f5f0964cSRobert Mustacchi 	}
78*f5f0964cSRobert Mustacchi };
79*f5f0964cSRobert Mustacchi 
80*f5f0964cSRobert Mustacchi const size_t nvme_ns_delete_nfields = ARRAY_SIZE(nvme_ns_delete_fields);
81*f5f0964cSRobert Mustacchi 
82*f5f0964cSRobert Mustacchi /*
83*f5f0964cSRobert Mustacchi  * This is an integer which currently has only a single bit defined, bit 0.
84*f5f0964cSRobert Mustacchi  * Though NVMe 2.1 will change this.
85*f5f0964cSRobert Mustacchi  */
86*f5f0964cSRobert Mustacchi static bool
nvme_ns_create_field_valid_nmic(const nvme_field_info_t * field,const nvme_valid_ctrl_data_t * data,uint64_t act,char * msg,size_t msglen)87*f5f0964cSRobert Mustacchi nvme_ns_create_field_valid_nmic(const nvme_field_info_t *field,
88*f5f0964cSRobert Mustacchi     const nvme_valid_ctrl_data_t *data, uint64_t act, char *msg, size_t msglen)
89*f5f0964cSRobert Mustacchi {
90*f5f0964cSRobert Mustacchi 	return (nvme_field_mask_check(field, NVME_NS_MGMT_NMIC_MASK, msg,
91*f5f0964cSRobert Mustacchi 	    msglen, act));
92*f5f0964cSRobert Mustacchi }
93*f5f0964cSRobert Mustacchi 
94*f5f0964cSRobert Mustacchi /*
95*f5f0964cSRobert Mustacchi  * The NSZE and NCAP fields are related. Because these are in terms of a
96*f5f0964cSRobert Mustacchi  * formatted LBA which we don't have quite at this moment, we can't confirm the
97*f5f0964cSRobert Mustacchi  * maximum value; however, we do know enough to know a value of zero is wrong.
98*f5f0964cSRobert Mustacchi  */
99*f5f0964cSRobert Mustacchi static bool
nvme_ns_attach_field_valid_nsze(const nvme_field_info_t * field,const nvme_valid_ctrl_data_t * data,uint64_t act,char * msg,size_t msglen)100*f5f0964cSRobert Mustacchi nvme_ns_attach_field_valid_nsze(const nvme_field_info_t *field,
101*f5f0964cSRobert Mustacchi     const nvme_valid_ctrl_data_t *data, uint64_t act, char *msg, size_t msglen)
102*f5f0964cSRobert Mustacchi {
103*f5f0964cSRobert Mustacchi 	return (nvme_field_range_check(field, 1, UINT64_MAX, msg, msglen, act));
104*f5f0964cSRobert Mustacchi }
105*f5f0964cSRobert Mustacchi 
106*f5f0964cSRobert Mustacchi /*
107*f5f0964cSRobert Mustacchi  * The set of fields that are required to be allowed or defaults varies based
108*f5f0964cSRobert Mustacchi  * upon the CSI that is used. For example the NVM and K/V command sets have
109*f5f0964cSRobert Mustacchi  * different required fields. As such, the notion of what's required and
110*f5f0964cSRobert Mustacchi  * settable is something that is determined by the CSI, hence why the required
111*f5f0964cSRobert Mustacchi  * and allowed fields are missing for everything that isn't the CSI.
112*f5f0964cSRobert Mustacchi  */
113*f5f0964cSRobert Mustacchi const nvme_field_info_t nvme_ns_create_fields[] = {
114*f5f0964cSRobert Mustacchi 	[NVME_NS_CREATE_REQ_FIELD_CSI] = {
115*f5f0964cSRobert Mustacchi 		/*
116*f5f0964cSRobert Mustacchi 		 * The libnvme APIs require that a CSI is passed to create this,
117*f5f0964cSRobert Mustacchi 		 * so this 2.0 isn't quite truly enforced.
118*f5f0964cSRobert Mustacchi 		 */
119*f5f0964cSRobert Mustacchi 		.nlfi_vers = &nvme_vers_2v0,
120*f5f0964cSRobert Mustacchi 		.nlfi_max_size = NVME_NS_MGMT_MAX_CSI,
121*f5f0964cSRobert Mustacchi 		.nlfi_spec = "csi",
122*f5f0964cSRobert Mustacchi 		.nlfi_human = "command set ID",
123*f5f0964cSRobert Mustacchi 		.nlfi_def_req = true,
124*f5f0964cSRobert Mustacchi 		.nlfi_def_allow = false
125*f5f0964cSRobert Mustacchi 	},
126*f5f0964cSRobert Mustacchi 	[NVME_NS_CREATE_REQ_FIELD_NSZE] = {
127*f5f0964cSRobert Mustacchi 		.nlfi_vers = &nvme_vers_1v2,
128*f5f0964cSRobert Mustacchi 		/*
129*f5f0964cSRobert Mustacchi 		 * The NSZE and NCAP fields are required to be related by a
130*f5f0964cSRobert Mustacchi 		 * namespace granularity record; however, this was not
131*f5f0964cSRobert Mustacchi 		 * introduced until NVMe 1.4. Absent this information, the main
132*f5f0964cSRobert Mustacchi 		 * constraint is that the two are equivalent unless thin
133*f5f0964cSRobert Mustacchi 		 * provisioning is supported. In addition, when setting the
134*f5f0964cSRobert Mustacchi 		 * field, we don't know what LBA size someone has selected, so
135*f5f0964cSRobert Mustacchi 		 * this can only be checked at command execution time.
136*f5f0964cSRobert Mustacchi 		 */
137*f5f0964cSRobert Mustacchi 		.nlfi_valid = nvme_ns_attach_field_valid_nsze,
138*f5f0964cSRobert Mustacchi 		.nlfi_spec = "nsze",
139*f5f0964cSRobert Mustacchi 		.nlfi_human = "namespace size"
140*f5f0964cSRobert Mustacchi 	},
141*f5f0964cSRobert Mustacchi 	[NVME_NS_CREATE_REQ_FIELD_NCAP] = {
142*f5f0964cSRobert Mustacchi 		.nlfi_vers = &nvme_vers_1v2,
143*f5f0964cSRobert Mustacchi 		.nlfi_valid = nvme_ns_attach_field_valid_nsze,
144*f5f0964cSRobert Mustacchi 		.nlfi_spec = "ncap",
145*f5f0964cSRobert Mustacchi 		.nlfi_human = "namespace capacity"
146*f5f0964cSRobert Mustacchi 	},
147*f5f0964cSRobert Mustacchi 	[NVME_NS_CREATE_REQ_FIELD_FLBAS] = {
148*f5f0964cSRobert Mustacchi 		.nlfi_vers = &nvme_vers_1v2,
149*f5f0964cSRobert Mustacchi 		/*
150*f5f0964cSRobert Mustacchi 		 * See the notes in common/nvme/nvme_format.c around this choice
151*f5f0964cSRobert Mustacchi 		 * of maximum.
152*f5f0964cSRobert Mustacchi 		 */
153*f5f0964cSRobert Mustacchi 		.nlfi_max_size = NVME_NS_MGMT_MAX_FLBAS,
154*f5f0964cSRobert Mustacchi 		.nlfi_spec = "flbas",
155*f5f0964cSRobert Mustacchi 		.nlfi_human = "formatted LBA size"
156*f5f0964cSRobert Mustacchi 	},
157*f5f0964cSRobert Mustacchi 	[NVME_NS_CREATE_REQ_FIELD_NMIC] = {
158*f5f0964cSRobert Mustacchi 		.nlfi_vers = &nvme_vers_1v2,
159*f5f0964cSRobert Mustacchi 		.nlfi_valid = nvme_ns_create_field_valid_nmic,
160*f5f0964cSRobert Mustacchi 		.nlfi_max_size = NVME_NS_MGMT_MAX_FLBAS,
161*f5f0964cSRobert Mustacchi 		.nlfi_spec = "nmic",
162*f5f0964cSRobert Mustacchi 		.nlfi_human = "namespace multi-path I/O and namespace sharing "
163*f5f0964cSRobert Mustacchi 		    "capabilities"
164*f5f0964cSRobert Mustacchi 	}
165*f5f0964cSRobert Mustacchi };
166*f5f0964cSRobert Mustacchi 
167*f5f0964cSRobert Mustacchi const size_t nvme_ns_create_nfields = ARRAY_SIZE(nvme_ns_create_fields);
168*f5f0964cSRobert Mustacchi 
169*f5f0964cSRobert Mustacchi /*
170*f5f0964cSRobert Mustacchi  * These are the default fields that are required for an NVM command. The CSI
171*f5f0964cSRobert Mustacchi  * cannot be set. The we allow to default to zero, unshared, and therefore is
172*f5f0964cSRobert Mustacchi  * optional.
173*f5f0964cSRobert Mustacchi  */
174*f5f0964cSRobert Mustacchi const nvme_ns_create_req_field_t nvme_ns_create_fields_nvm_req[] = {
175*f5f0964cSRobert Mustacchi 	NVME_NS_CREATE_REQ_FIELD_NSZE, NVME_NS_CREATE_REQ_FIELD_NCAP,
176*f5f0964cSRobert Mustacchi 	NVME_NS_CREATE_REQ_FIELD_FLBAS
177*f5f0964cSRobert Mustacchi };
178*f5f0964cSRobert Mustacchi const size_t nvme_ns_create_fields_nvm_nreq =
179*f5f0964cSRobert Mustacchi     ARRAY_SIZE(nvme_ns_create_fields_nvm_req);
180*f5f0964cSRobert Mustacchi 
181*f5f0964cSRobert Mustacchi const nvme_ns_create_req_field_t nvme_ns_create_fields_nvm_allow[] = {
182*f5f0964cSRobert Mustacchi 	NVME_NS_CREATE_REQ_FIELD_NSZE, NVME_NS_CREATE_REQ_FIELD_NCAP,
183*f5f0964cSRobert Mustacchi 	NVME_NS_CREATE_REQ_FIELD_FLBAS, NVME_NS_CREATE_REQ_FIELD_NMIC
184*f5f0964cSRobert Mustacchi };
185*f5f0964cSRobert Mustacchi const size_t nvme_ns_create_fields_nvm_nallow =
186*f5f0964cSRobert Mustacchi     ARRAY_SIZE(nvme_ns_create_fields_nvm_allow);
187*f5f0964cSRobert Mustacchi 
188*f5f0964cSRobert Mustacchi bool
nvme_nsmgmt_cmds_supported(const nvme_valid_ctrl_data_t * data)189*f5f0964cSRobert Mustacchi nvme_nsmgmt_cmds_supported(const nvme_valid_ctrl_data_t *data)
190*f5f0964cSRobert Mustacchi {
191*f5f0964cSRobert Mustacchi 	if (nvme_vers_atleast(data->vcd_vers, &nvme_vers_1v2)) {
192*f5f0964cSRobert Mustacchi 		return (data->vcd_id->id_oacs.oa_nsmgmt != 0);
193*f5f0964cSRobert Mustacchi 	}
194*f5f0964cSRobert Mustacchi 
195*f5f0964cSRobert Mustacchi 	return (false);
196*f5f0964cSRobert Mustacchi }
197