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 #ifndef _SYS_NVME_DISCOVERY_H
17 #define	_SYS_NVME_DISCOVERY_H
18 
19 /*
20  * This defines common types that are used for discovering features of NVMe
21  * devices. The primary way for users to consume these types is through the
22  * libnvme discovery APIs.
23  */
24 
25 #ifdef __cplusplus
26 extern "C" {
27 #endif
28 
29 typedef enum {
30 	NVME_LOG_ID_MANDATORY,
31 	NVME_LOG_ID_OPTIONAL,
32 	NVME_LOG_ID_VENDOR_SPECIFIC
33 } nvme_log_disc_kind_t;
34 
35 /*
36  * Different logs cover different aspects of a device. These are listed below
37  * referring to the NVMe controller, the NVM subsystem itself, and then
38  * particular namespaces. NVMe 2.x adds the notion of a domain. From a
39  * specification perspective, the NVM subsystem is instead sometimes referred to
40  * as a domain. A controller can only access a single domain so while the 2.x
41  * specifications suggest the scope is slightly different for the NVM subsystem
42  * below, they're basically the same for our purposes.
43  */
44 typedef enum {
45 	NVME_LOG_SCOPE_CTRL	= 1 << 0,
46 	NVME_LOG_SCOPE_NVM	= 1 << 1,
47 	NVME_LOG_SCOPE_NS	= 1 << 2
48 } nvme_log_disc_scope_t;
49 
50 typedef enum {
51 	/*
52 	 * This indicates that the implementation information is based on
53 	 * knowledge from a base spec.
54 	 */
55 	NVME_LOG_DISC_S_SPEC	= 1 << 0,
56 	/*
57 	 * This indicates that the knowledge is from the identify controller
58 	 * data structure.
59 	 */
60 	NVME_LOG_DISC_S_ID_CTRL	= 1 << 1,
61 	/*
62 	 * This indicates that we have used our internal information database
63 	 * about devices from a vendor's datasheets to determine that something
64 	 * is supported.
65 	 */
66 	NVME_LOG_DISC_S_DB	= 1 << 2,
67 	/*
68 	 * This indicates that we have used a command (whether vendor-specific
69 	 * or the NVMe 2.x Supported Log Pages) to get additional information
70 	 * about this.
71 	 */
72 	NVME_LOG_DISC_S_CMD	= 1 << 3
73 } nvme_log_disc_source_t;
74 
75 typedef enum {
76 	/*
77 	 * These next three flags indicate that the log page requires additional
78 	 * information for it to complete successfully. These are specifically
79 	 * the log specific parameter or a log specific indicator (e.g. an
80 	 * endurance group, NVM set, domain, etc.). RAE was introduced in NVMe
81 	 * 1.3 and applied to logs that already existed. It will not be possible
82 	 * to set RAE on a log request that operates on a controller prior to
83 	 * NVMe 1.3.
84 	 */
85 	NVME_LOG_DISC_F_NEED_LSP	= 1 << 0,
86 	NVME_LOG_DISC_F_NEED_LSI	= 1 << 1,
87 	NVME_LOG_DISC_F_NEED_RAE	= 1 << 2,
88 	/*
89 	 * Log pages whose only scope is a namespace are required to specify a
90 	 * namespace. Otherwise, when the scope includes a controller or NVM
91 	 * subsystem then it is assumed that the default is to target the
92 	 * controller (e.g.  the health log page).
93 	 */
94 	NVME_LOG_DISC_F_NEED_NSID	= 1 << 3
95 } nvme_log_disc_fields_t;
96 
97 
98 typedef enum {
99 	NVME_FEAT_SCOPE_CTRL	= 1 << 0,
100 	NVME_FEAT_SCOPE_NS	= 1 << 1
101 } nvme_feat_scope_t;
102 
103 typedef enum {
104 	/*
105 	 * Indicates that this feature requires an argument to select some part
106 	 * of the feature in cdw11.
107 	 */
108 	NVME_GET_FEAT_F_CDW11	= 1 << 0,
109 	/*
110 	 * Indicates that this feature will output data to a specific buffer and
111 	 * therefore a data argument is required for this feature.
112 	 */
113 	NVME_GET_FEAT_F_DATA	= 1 << 1,
114 	/*
115 	 * Indicates that this feature requires a namespace ID to be specified
116 	 * when getting this feature. In general, while one can usually set a
117 	 * feature to target the broadcast namespace, the same is not true of
118 	 * getting a feature.
119 	 */
120 	NVME_GET_FEAT_F_NSID	= 1 << 2,
121 } nvme_get_feat_fields_t;
122 
123 typedef enum {
124 	/*
125 	 * These indicate that the feature requires fields set in the various
126 	 * control words to set the feature.
127 	 */
128 	NVME_SET_FEAT_F_CDW11	= 1 << 0,
129 	NVME_SET_FEAT_F_CDW12	= 1 << 1,
130 	NVME_SET_FEAT_F_CDW13	= 1 << 2,
131 	NVME_SET_FEAT_F_CDW14	= 1 << 3,
132 	NVME_SET_FEAT_F_CDW15	= 1 << 4,
133 	/*
134 	 * Indicates that there is a data payload component to this feature that
135 	 * must be set.
136 	 */
137 	NVME_SET_FEAT_F_DATA	= 1 << 5,
138 	/*
139 	 * Indicates that this feature requires a namespace ID. Broadcast IDs
140 	 * are more often allowed than with getting a feature, but it still
141 	 * depends.
142 	 */
143 	NVME_SET_FEAT_F_NSID	= 1 << 6
144 } nvme_set_feat_fields_t;
145 
146 typedef enum {
147 	/*
148 	 * Indicates that getting the feature outputs data in cdw0 for
149 	 * consumption. This is the most common form of data output for getting
150 	 * features. Setting features usually doesn't output data in cdw0;
151 	 * however, a few are defined to.
152 	 */
153 	NVME_FEAT_OUTPUT_CDW0	= 1 << 0,
154 	/*
155 	 * Indicates that data is output in the data buffer that was passed in.
156 	 * This is only ever used for get features.
157 	 */
158 	NVME_FEAT_OUTPUT_DATA	= 1 << 1
159 } nvme_feat_output_t;
160 
161 typedef enum {
162 	/*
163 	 * Indicates that when getting or setting this feature that requires a
164 	 * namespace ID, the broadcast namespace is allowed.
165 	 */
166 	NVME_FEAT_F_GET_BCAST_NSID	= 1 << 0,
167 	NVME_FEAT_F_SET_BCAST_NSID	= 1 << 1
168 } nvme_feat_flags_t;
169 
170 typedef enum {
171 	NVME_FEAT_MANDATORY	= 0,
172 	NVME_FEAT_OPTIONAL,
173 	NVME_FEAT_VENDOR_SPECIFIC
174 } nvme_feat_kind_t;
175 
176 /*
177  * This enumeration indicates whether or not a given feature is specific to a
178  * command set, and if so what one. The default is that most features are
179  * present for all command sets, which uses the NVME_FEAT_CSI_NONE value.
180  * Otherwise, it uses a bit-field to indicate what it is present in.
181  */
182 typedef enum {
183 	NVME_FEAT_CSI_NONE	= 0,
184 	NVME_FEAT_CSI_NVM	= 1 << 0,
185 } nvme_feat_csi_t;
186 
187 /*
188  * Prior to NVMe 2.x, there was no standard way to determine if a given log page
189  * was actually implemented or not. While several features had bits in the
190  * identify controller namespace, some (e.g. LBA Range Type) are optional,
191  * command-set specific, and have no such way of knowing if they're supported
192  * short of saying so. If we cannot determine this from the controller's
193  * version, type, and identify controller information, then we will indicate
194  * that we don't know. When we have full support for leveraging the NVMe 2.x
195  * Feature Identifiers Supported and Effects log pages and someone is
196  * interrogating an NVMe 2.x controller, then ideally one should not see
197  * unknown.
198  */
199 typedef enum {
200 	NVME_FEAT_IMPL_UNKNOWN = 0,
201 	NVME_FEAT_IMPL_UNSUPPORTED,
202 	NVME_FEAT_IMPL_SUPPORTED
203 } nvme_feat_impl_t;
204 
205 #ifdef __cplusplus
206 }
207 #endif
208 
209 #endif /* _SYS_NVME_DISCOVERY_H */
210