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 2026 Oxide Computer Company 14 */ 15 16 #ifndef _NVME_COMMON_H 17 #define _NVME_COMMON_H 18 19 /* 20 * Collection of common files and utilities that can be used for NVMe related 21 * functionality. Broadly, these are meant so that the kernel and userland have 22 * consistent validation routines. 23 * 24 * When we perform error checking and validation we use the kernel's set of 25 * ioctl errors for more semantic errors. These semantic errors are translated 26 * into ones that the library wishes to expose. Our goal is to try to use a 27 * mostly uniform error checking framework between the two entities. 28 * 29 * A consumer must build nvme_version.o and nvme_field.o. Other pieces can be 30 * added based on their needs. 31 */ 32 33 #include <sys/stdbool.h> 34 #include <sys/nvme.h> 35 #include <sys/nvme/discovery.h> 36 37 #ifdef __cplusplus 38 extern "C" { 39 #endif 40 41 /* 42 * Version related pieces from nvme_version.c. The main idea is that consumers 43 * such as the kernel and libnvme will wrap up the nvme_vers_atleast() function 44 * with an object that contains an NVMe version, thus reducing the likelihood 45 * that we'll confuse versions. 46 */ 47 extern const nvme_version_t nvme_vers_1v0; 48 extern const nvme_version_t nvme_vers_1v1; 49 extern const nvme_version_t nvme_vers_1v2; 50 extern const nvme_version_t nvme_vers_1v3; 51 extern const nvme_version_t nvme_vers_1v4; 52 extern const nvme_version_t nvme_vers_2v0; 53 extern const nvme_version_t nvme_vers_2v1; 54 55 extern bool nvme_vers_atleast(const nvme_version_t *, const nvme_version_t *); 56 57 /* 58 * This structure contains information about the controller that must be 59 * supplied to the various validation functions. 60 */ 61 typedef struct nvme_valid_ctrl_data { 62 const nvme_version_t *vcd_vers; 63 const nvme_identify_ctrl_t *vcd_id; 64 } nvme_valid_ctrl_data_t; 65 66 /* 67 * This structure is used to represent a field that is in use in a given 68 * command. This allows us to use common validation logic for different classes 69 * of commands such as IDENTIFY, GET LOG PAGE, etc. If everything is fine about 70 * a field, then it should return true. Otherwise, it should return false and 71 * fill out the error message. It is optional to override the specifics of the 72 * nvme_ioctl_err_t with a more specific error where appropriate and known. If 73 * it is not filled in, the validation default will be used. 74 */ 75 struct nvme_field_info; 76 typedef bool (*nvme_field_sup_f)(const struct nvme_field_info *, 77 const nvme_valid_ctrl_data_t *, char *, size_t); 78 typedef bool (*nvme_field_valid_f)(const struct nvme_field_info *, 79 const nvme_valid_ctrl_data_t *, uint64_t, char *, size_t); 80 81 typedef struct nvme_field_info { 82 const nvme_version_t *nlfi_vers; 83 nvme_field_sup_f nlfi_sup; 84 uint64_t nlfi_max_size; 85 nvme_field_valid_f nlfi_valid; 86 /* 87 * Fields below this point are mostly meant to be used by libnvme and by 88 * our printing logic, which we assume is not executed in the kernel. 89 */ 90 const char *nlfi_spec; 91 const char *nlfi_human; 92 bool nlfi_def_req; 93 bool nlfi_def_allow; 94 } nvme_field_info_t; 95 96 typedef enum { 97 NVME_FIELD_ERR_OK = 0, 98 NVME_FIELD_ERR_UNSUP_VERSION, 99 NVME_FIELD_ERR_UNSUP_FIELD, 100 NVME_FIELD_ERR_BAD_VALUE 101 } nvme_field_error_t; 102 103 extern nvme_field_error_t nvme_field_validate(const nvme_field_info_t *, 104 const nvme_valid_ctrl_data_t *, uint64_t, char *, size_t); 105 106 /* 107 * Various common utility routines for field validation and implementation. This 108 * version of NSID checking treats the NSID as valid. Currently checking for the 109 * validity of the broadcast namespace ID is left to consumers. 110 */ 111 extern bool nvme_field_atleast(const nvme_valid_ctrl_data_t *, 112 const nvme_version_t *); 113 extern bool nvme_field_valid_nsid(const nvme_field_info_t *, 114 const nvme_valid_ctrl_data_t *, uint64_t, char *, size_t); 115 extern bool nvme_field_range_check(const nvme_field_info_t *, uint64_t, 116 uint64_t, char *, size_t, uint64_t); 117 extern bool nvme_field_mask_check(const nvme_field_info_t *, uint64_t, char *, 118 size_t, uint64_t); 119 120 /* 121 * Log page request information. The goal with these structures and fields is to 122 * be able to validate whether something is valid, both in user/kernel context. 123 * This phrasing also makes this much easier to unit test. Because information 124 * is shared between libnvme and the kernel, some things are not needed for the 125 * kernel. We do not ifdef it out for the moment, to simplify things. 126 */ 127 128 /* 129 * This is the set of fields that the driver knows about how to validate that 130 * can end up in an NVMe log request. Items should be added here once the kernel 131 * knows how to put them in a log request command. 132 */ 133 typedef enum { 134 NVME_LOG_REQ_FIELD_LID = 0, 135 NVME_LOG_REQ_FIELD_LSP, 136 NVME_LOG_REQ_FIELD_LSI, 137 NVME_LOG_REQ_FIELD_SIZE, 138 NVME_LOG_REQ_FIELD_CSI, 139 NVME_LOG_REQ_FIELD_RAE, 140 NVME_LOG_REQ_FIELD_OFFSET, 141 NVME_LOG_REQ_FIELD_NSID 142 } nvme_log_req_field_t; 143 144 extern const nvme_field_info_t nvme_log_fields[]; 145 extern const size_t nvme_log_nfields; 146 147 /* 148 * We now use the field based information to have a common structure to define 149 * information about standard log pages. 150 */ 151 typedef struct nvme_log_page_info nvme_log_page_info_t; 152 typedef bool (*nvme_log_page_sup_f)(const nvme_valid_ctrl_data_t *, 153 const nvme_log_page_info_t *); 154 typedef uint64_t (*nvme_log_page_len_f)(const nvme_valid_ctrl_data_t *, 155 const nvme_log_page_info_t *); 156 typedef nvme_log_disc_scope_t (*nvme_log_page_scope_f)( 157 const nvme_valid_ctrl_data_t *, const nvme_log_page_info_t *); 158 typedef bool (*nvme_log_page_var_len_f)(uint64_t *, const void *, size_t); 159 160 struct nvme_log_page_info { 161 const char *nlpi_short; 162 const char *nlpi_human; 163 const char *const *nlpi_aliases; 164 size_t nlpi_naliases; 165 uint32_t nlpi_lid; 166 nvme_csi_t nlpi_csi; 167 /* 168 * These two entries can be used to determine whether a log page is 169 * supported based upon its version or with a supplemental function. A 170 * NULL item means it doesn't need to be checked. This would be the case 171 * for vendor-specific logs. 172 */ 173 const nvme_version_t *nlpi_vers; 174 const nvme_log_page_sup_f nlpi_sup_func; 175 nvme_log_disc_kind_t nlpi_kind; 176 nvme_log_disc_source_t nlpi_source; 177 nvme_log_disc_fields_t nlpi_disc; 178 /* 179 * Log pages are valid in certain contexts. This is generally static 180 * information, but if the scope function is implemented, we will use 181 * that and ignore the contents of nlpi_scope. 182 */ 183 nvme_log_disc_scope_t nlpi_scope; 184 nvme_log_page_scope_f nlpi_scope_func; 185 /* 186 * The lengths for a log page come in three forms. The first form is 187 * ones where we can determine based on information in the controller 188 * (or at build time) the length of the log page. Many log pages have a 189 * fixed length or they include information in the identify controller 190 * data structure as to their length (e.g. the error log page). To 191 * communicate the log page's length, we will first check if 192 * nlpi_len_func is non-NULL and call that to determine the log page 193 * length. Otherwise we will use the value in nlpi_len. If these return 194 * a non-zero value, the NVME_LOG_DISC_F_SIZE_FIXED will be set 195 * automatically. 196 * 197 * The second form of log pages are those whose length is variable, but 198 * we cannot determine it based on information present in the 199 * controller. Rather we must read some amount of data from the log page 200 * to figure this out at all. For example, many vendor specific logs 201 * have a first uint32_t that indicates the number of valid samples and 202 * therefore you must read that to determine the overall length of the 203 * log page. This case follows the same path as the first case; however, 204 * one must also set the nlpi_var_func function pointer. This results 205 * in the NVME_LOG_DISC_F_SIZE_VAR flag being set. 206 * 207 * The third set of these are ones we just don't know about. In this 208 * case, leave nlpi_len set to zero and nlpi_len_func to NULL. If this 209 * happens or neither path returns a valid size (i.e. 0) then we will 210 * set this to a general size that should be large enough (i.e. the 211 * non-extended NVMe log page size) and not set either size flag. 212 */ 213 uint64_t nlpi_len; 214 nvme_log_page_len_f nlpi_len_func; 215 nvme_log_page_var_len_f nlpi_var_func; 216 }; 217 218 extern const nvme_log_page_info_t nvme_std_log_pages[]; 219 extern const size_t nvme_std_log_npages; 220 221 /* 222 * These are functions that can be used to compute information about what's 223 * supported and similar information that sometimes requires dynamic support. 224 */ 225 extern nvme_log_disc_scope_t nvme_log_page_info_scope( 226 const nvme_log_page_info_t *, const nvme_valid_ctrl_data_t *); 227 extern uint64_t nvme_log_page_info_size(const nvme_log_page_info_t *, 228 const nvme_valid_ctrl_data_t *, bool *); 229 extern bool nvme_log_page_info_supported(const nvme_log_page_info_t *, 230 const nvme_valid_ctrl_data_t *); 231 232 /* 233 * This next section identifies the various fields that make up the NVMe 234 * IDENTIFY command and the corresponding pieces that are in use throughout. 235 */ 236 typedef enum { 237 NVME_ID_REQ_F_CNS = 0, 238 NVME_ID_REQ_F_NSID, 239 NVME_ID_REQ_F_CTRLID, 240 NVME_ID_REQ_F_BUF, 241 } nvme_identify_req_field_t; 242 243 typedef enum { 244 /* 245 * Indicates that we allow this identify command to operate on a 246 * namespace minor. 247 */ 248 NVME_IDENTIFY_INFO_F_NS_OK = 1 << 0, 249 /* 250 * Indicates that if we support namespace management we should attempt 251 * to use the broadcast nsid when asking about the controller. 252 */ 253 NVME_IDENTIFY_INFO_F_BCAST = 1 << 1, 254 /* 255 * This indicates that we are performing an operation which lists 256 * namespace IDs. As such, we don't need to validate the namespace 257 * against the controller's list. In addition, a zero namespace ID is 258 * allowed. 259 */ 260 NVME_IDENTIFY_INFO_F_NSID_LIST = 1 << 2 261 } nvme_identify_info_flags_t; 262 263 typedef struct nvme_identify_info nvme_identify_info_t; 264 typedef bool (*nvme_identify_sup_f)(const nvme_valid_ctrl_data_t *); 265 struct nvme_identify_info { 266 const char *nii_name; 267 nvme_csi_t nii_csi; 268 uint32_t nii_cns; 269 const nvme_version_t *nii_vers; 270 nvme_identify_sup_f nii_sup_func; 271 nvme_identify_req_field_t nii_fields; 272 nvme_identify_info_flags_t nii_flags; 273 }; 274 275 extern const nvme_field_info_t nvme_identify_fields[]; 276 extern const size_t nvme_identify_nfields; 277 extern const nvme_identify_info_t nvme_identify_cmds[]; 278 extern const size_t nvme_identify_ncmds; 279 280 extern bool nvme_identify_info_supported(const nvme_identify_info_t *, 281 const nvme_valid_ctrl_data_t *); 282 283 /* 284 * NVMe Vendor Unique Commands. Note, unlike others this hasn't really changed 285 * since it was introduced in NVMe 1.0. While libnvme wraps these up a bit to 286 * construct commands, there is no common vendor unique command discovery 287 * information as the kernel more or less stays out of it. 288 */ 289 typedef enum { 290 NVME_VUC_REQ_FIELD_OPC = 0, 291 NVME_VUC_REQ_FIELD_NSID, 292 NVME_VUC_REQ_FIELD_CDW12, 293 NVME_VUC_REQ_FIELD_CDW13, 294 NVME_VUC_REQ_FIELD_CDW14, 295 NVME_VUC_REQ_FIELD_CDW15, 296 NVME_VUC_REQ_FIELD_NDT, 297 /* 298 * While the timeout field here is not actually part of the standard, we 299 * require it as part of the command execution and therefore include it 300 * in here. 301 */ 302 NVME_VUC_REQ_FIELD_TO 303 } nvme_vuc_req_field_t; 304 305 extern const nvme_field_info_t nvme_vuc_fields[]; 306 extern const size_t nvme_vuc_nfields; 307 308 /* 309 * Firmware download and commit related fields and routines. 310 */ 311 typedef enum { 312 NVME_FW_LOAD_REQ_FIELD_NUMD = 0, 313 NVME_FW_LOAD_REQ_FIELD_OFFSET 314 } nvme_fw_load_req_field_t; 315 316 extern const nvme_field_info_t nvme_fw_load_fields[]; 317 extern const size_t nvme_fw_load_nfields; 318 319 extern bool nvme_fw_cmds_supported(const nvme_valid_ctrl_data_t *); 320 extern uint32_t nvme_fw_load_granularity(const nvme_valid_ctrl_data_t *); 321 322 typedef enum { 323 NVME_FW_COMMIT_REQ_FIELD_SLOT = 0, 324 NVME_FW_COMMIT_REQ_FIELD_ACT 325 } nvme_fw_commit_req_field_t; 326 327 extern const nvme_field_info_t nvme_fw_commit_fields[]; 328 extern const size_t nvme_fw_commit_nfields; 329 330 /* 331 * Format NVM operations 332 */ 333 typedef enum { 334 NVME_FORMAT_REQ_FIELD_LBAF = 0, 335 NVME_FORMAT_REQ_FIELD_SES, 336 NVME_FORMAT_REQ_FIELD_NSID 337 } nvme_format_req_field_t; 338 339 extern const nvme_field_info_t nvme_format_fields[]; 340 extern const size_t nvme_format_nfields; 341 342 extern bool nvme_format_cmds_supported(const nvme_valid_ctrl_data_t *); 343 344 /* 345 * Feature related requests 346 */ 347 typedef enum { 348 NVME_GET_FEAT_REQ_FIELD_FID = 0, 349 NVME_GET_FEAT_REQ_FIELD_SEL, 350 NVME_GET_FEAT_REQ_FIELD_DPTR, 351 NVME_GET_FEAT_REQ_FIELD_CDW11, 352 NVME_GET_FEAT_REQ_FIELD_NSID 353 } nvme_get_feat_req_field_t; 354 355 extern const nvme_field_info_t nvme_get_feat_fields[]; 356 extern const size_t nvme_get_feat_nfields; 357 358 /* 359 * Common feature information. 360 */ 361 typedef struct nvme_feat_info nvme_feat_info_t; 362 typedef bool (*nvme_feat_sup_f)(const nvme_valid_ctrl_data_t *, 363 const nvme_feat_info_t *); 364 365 struct nvme_feat_info { 366 const char *nfeat_short; 367 const char *nfeat_spec; 368 uint32_t nfeat_fid; 369 /* 370 * These three entries can be used to determine whether a feature is 371 * supported or not based upon its version or supplemental information. 372 */ 373 const nvme_version_t *nfeat_vers; 374 const nvme_feat_sup_f nfeat_sup_func; 375 nvme_feat_kind_t nfeat_kind; 376 /* 377 * These describe whether the feature operates on namespaces or the 378 * controller and misc. flags and information about them. 379 */ 380 nvme_feat_scope_t nfeat_scope; 381 nvme_feat_csi_t nfeat_csi; 382 nvme_feat_flags_t nfeat_flags; 383 /* 384 * These four entries describe what an NVMe device uses as input and 385 * output fields. 386 */ 387 nvme_get_feat_fields_t nfeat_in_get; 388 nvme_set_feat_fields_t nfeat_in_set; 389 nvme_feat_output_t nfeat_out_get; 390 nvme_feat_output_t nfeat_out_set; 391 /* 392 * Feature data size. This should be zero if the feature does not use a 393 * data payload. Right now we assume the get and set sizes are identical 394 * as that's how this normally works. 395 */ 396 uint64_t nfeat_len; 397 }; 398 399 extern const nvme_feat_info_t nvme_std_feats[]; 400 extern const size_t nvme_std_nfeats; 401 402 extern nvme_feat_impl_t nvme_feat_supported(const nvme_feat_info_t *, 403 const nvme_valid_ctrl_data_t *); 404 405 /* 406 * Namespace Management and Namespace Attach Commands. 407 * 408 * These operations have their own sets of NVMe admin operations codes. 409 * Separately, they then each have a means of selecting what they operate on in 410 * dw10. Unlike other operations like Get Features or Get Log Page, these are 411 * broken into separate ioctls in the kernel. In libnvme, namespace attach has a 412 * single command, but namespace create and delete are treated separately. 413 */ 414 415 typedef enum { 416 NVME_NS_CREATE_REQ_FIELD_CSI = 0, 417 NVME_NS_CREATE_REQ_FIELD_NSZE, 418 NVME_NS_CREATE_REQ_FIELD_NCAP, 419 NVME_NS_CREATE_REQ_FIELD_FLBAS, 420 NVME_NS_CREATE_REQ_FIELD_NMIC 421 } nvme_ns_create_req_field_t; 422 423 typedef enum { 424 NVME_NS_DELETE_REQ_FIELD_NSID = 0 425 } nvme_ns_delete_req_field_t; 426 427 /* 428 * Strictly speaking some of these fields, such as the controller list, are 429 * specific to the type of sub-command put into the SEL field. 430 */ 431 typedef enum { 432 NVME_NS_ATTACH_REQ_FIELD_SEL = 0, 433 NVME_NS_ATTACH_REQ_FIELD_NSID, 434 NVME_NS_ATTACH_REQ_FIELD_DPTR 435 } nvme_ns_attach_req_field_t; 436 437 extern bool nvme_nsmgmt_cmds_supported(const nvme_valid_ctrl_data_t *); 438 extern const nvme_field_info_t nvme_ns_attach_fields[]; 439 extern const size_t nvme_ns_attach_nfields; 440 extern const nvme_field_info_t nvme_ns_create_fields[]; 441 extern const size_t nvme_ns_create_nfields; 442 extern const nvme_field_info_t nvme_ns_delete_fields[]; 443 extern const size_t nvme_ns_delete_nfields; 444 445 /* 446 * Allowed and required fields by CSI. 447 */ 448 extern const nvme_ns_create_req_field_t nvme_ns_create_fields_nvm_req[]; 449 extern const size_t nvme_ns_create_fields_nvm_nreq; 450 extern const nvme_ns_create_req_field_t nvme_ns_create_fields_nvm_allow[]; 451 extern const size_t nvme_ns_create_fields_nvm_nallow; 452 453 #ifdef __cplusplus 454 } 455 #endif 456 457 #endif /* _NVME_COMMON_H */ 458