xref: /illumos-gate/usr/src/common/nvme/nvme_identify.c (revision 8119dad84d6416f13557b0ba8e2aaf9064cbcfd3)
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
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
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
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
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