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 2024 Oxide Computer Company
14 */
15
16 /*
17 * Information about supported NVMe identify commands that can be issued.
18 */
19
20 #include "nvme_common.h"
21
22 #include <sys/sysmacros.h>
23
24 static bool
nvme_identify_field_valid_cns(const nvme_field_info_t * field,const nvme_valid_ctrl_data_t * data,uint64_t cns,char * msg,size_t msglen)25 nvme_identify_field_valid_cns(const nvme_field_info_t *field,
26 const nvme_valid_ctrl_data_t *data, uint64_t cns, char *msg, size_t msglen)
27 {
28 uint64_t max;
29
30 if (nvme_field_atleast(data, &nvme_vers_1v2)) {
31 max = NVME_IDENTIFY_MAX_CNS_1v2;
32 } else if (nvme_field_atleast(data, &nvme_vers_1v1)) {
33 max = NVME_IDENTIFY_MAX_CNS_1v1;
34 } else {
35 max = NVME_IDENTIFY_MAX_CNS;
36 }
37
38 return (nvme_field_range_check(field, 0, max, msg, msglen, cns));
39 }
40
41 static bool
nvme_identify_field_valid_buf(const nvme_field_info_t * field,const nvme_valid_ctrl_data_t * data,uint64_t len,char * msg,size_t msglen)42 nvme_identify_field_valid_buf(const nvme_field_info_t *field,
43 const nvme_valid_ctrl_data_t *data, uint64_t len, char *msg, size_t msglen)
44 {
45 return (nvme_field_range_check(field, NVME_IDENTIFY_BUFSIZE,
46 NVME_IDENTIFY_BUFSIZE, msg, msglen, len));
47 }
48
49 const nvme_field_info_t nvme_identify_fields[] = {
50 [NVME_ID_REQ_F_CNS] = {
51 .nlfi_vers = &nvme_vers_1v0,
52 .nlfi_valid = nvme_identify_field_valid_cns,
53 .nlfi_spec = "cns",
54 .nlfi_human = "Controller or Namespace Structure",
55 .nlfi_def_req = true,
56 .nlfi_def_allow = true
57 },
58 [NVME_ID_REQ_F_NSID] = {
59 .nlfi_vers = &nvme_vers_1v0,
60 .nlfi_spec = "nsid",
61 /*
62 * The NSID for an identify command can have several different
63 * forms.
64 */
65 .nlfi_max_size = NVME_IDENTIFY_MAX_NSID,
66 .nlfi_human = "namespace ID",
67 .nlfi_def_req = false,
68 .nlfi_def_allow = true
69 },
70 [NVME_ID_REQ_F_CTRLID] = {
71 .nlfi_vers = &nvme_vers_1v2,
72 .nlfi_max_size = NVME_IDENTIFY_MAX_CTRLID,
73 .nlfi_spec = "cntid",
74 .nlfi_human = "Controller ID",
75 .nlfi_def_req = false,
76 .nlfi_def_allow = true
77 },
78 [NVME_ID_REQ_F_BUF] = {
79 .nlfi_vers = &nvme_vers_1v0,
80 .nlfi_valid = nvme_identify_field_valid_buf,
81 .nlfi_spec = "dptr",
82 .nlfi_human = "output",
83 .nlfi_def_req = true,
84 .nlfi_def_allow = true
85 }
86 };
87
88 size_t nvme_identify_nfields = ARRAY_SIZE(nvme_identify_fields);
89
90 static bool
nvme_identify_support_nsid(const nvme_valid_ctrl_data_t * data)91 nvme_identify_support_nsid(const nvme_valid_ctrl_data_t *data)
92 {
93 return (data->vcd_id->id_oacs.oa_nsmgmt != 0);
94 }
95
96 const nvme_identify_info_t nvme_identify_cmds[] = { {
97 .nii_name = "identify namespace",
98 .nii_csi = NVME_CSI_NVM,
99 .nii_cns = NVME_IDENTIFY_NSID,
100 .nii_vers = &nvme_vers_1v0,
101 .nii_fields = 1 << NVME_ID_REQ_F_NSID,
102 .nii_flags = NVME_IDENTIFY_INFO_F_NS_OK | NVME_IDENTIFY_INFO_F_BCAST
103 }, {
104 .nii_name = "identify controller",
105 .nii_csi = NVME_CSI_NVM,
106 .nii_cns = NVME_IDENTIFY_CTRL,
107 .nii_vers = &nvme_vers_1v0,
108 }, {
109 .nii_name = "active namespace ID list",
110 .nii_csi = NVME_CSI_NVM,
111 .nii_cns = NVME_IDENTIFY_NSID_LIST,
112 .nii_vers = &nvme_vers_1v1,
113 .nii_fields = 1 << NVME_ID_REQ_F_NSID,
114 .nii_flags = NVME_IDENTIFY_INFO_F_NSID_LIST
115 }, {
116 .nii_name = "namespace identification descriptor list",
117 .nii_csi = NVME_CSI_NVM,
118 .nii_cns = NVME_IDENTIFY_NSID_DESC,
119 .nii_vers = &nvme_vers_1v3,
120 .nii_fields = (1 << NVME_ID_REQ_F_NSID),
121 .nii_flags = NVME_IDENTIFY_INFO_F_NS_OK
122 }, {
123 .nii_name = "allocated namespace id list",
124 .nii_csi = NVME_CSI_NVM,
125 .nii_cns = NVME_IDENTIFY_NSID_ALLOC_LIST,
126 .nii_vers = &nvme_vers_1v2,
127 .nii_sup_func = nvme_identify_support_nsid,
128 .nii_fields = 1 << NVME_ID_REQ_F_NSID,
129 .nii_flags = NVME_IDENTIFY_INFO_F_NSID_LIST
130 }, {
131 .nii_name = "identify allocated namespace",
132 .nii_csi = NVME_CSI_NVM,
133 .nii_cns = NVME_IDENTIFY_NSID_ALLOC,
134 .nii_vers = &nvme_vers_1v2,
135 .nii_sup_func = nvme_identify_support_nsid,
136 .nii_fields = 1 << NVME_ID_REQ_F_NSID,
137 .nii_flags = NVME_IDENTIFY_INFO_F_NS_OK
138 }, {
139 .nii_name = "namespace attached controller list",
140 .nii_csi = NVME_CSI_NVM,
141 .nii_cns = NVME_IDENTIFY_NSID_CTRL_LIST,
142 .nii_vers = &nvme_vers_1v2,
143 .nii_sup_func = nvme_identify_support_nsid,
144 .nii_fields = (1 << NVME_ID_REQ_F_NSID) | (1 << NVME_ID_REQ_F_CTRLID),
145 .nii_flags = NVME_IDENTIFY_INFO_F_NS_OK
146 }, {
147 .nii_name = "nvm subsystem controller list",
148 .nii_csi = NVME_CSI_NVM,
149 .nii_cns = NVME_IDENTIFY_CTRL_LIST,
150 .nii_vers = &nvme_vers_1v2,
151 .nii_sup_func = nvme_identify_support_nsid,
152 .nii_fields = (1 << NVME_ID_REQ_F_CTRLID)
153 } };
154
155 size_t nvme_identify_ncmds = ARRAY_SIZE(nvme_identify_cmds);
156
157 bool
nvme_identify_info_supported(const nvme_identify_info_t * info,const nvme_valid_ctrl_data_t * data)158 nvme_identify_info_supported(const nvme_identify_info_t *info,
159 const nvme_valid_ctrl_data_t *data)
160 {
161 if (info->nii_vers != NULL && !nvme_field_atleast(data,
162 info->nii_vers)) {
163 return (false);
164 }
165
166 if (info->nii_sup_func != NULL && !info->nii_sup_func(data)) {
167 return (false);
168 }
169
170 return (true);
171 }
172