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 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 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 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 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