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