xref: /illumos-gate/usr/src/lib/libnvme/common/libnvme_impl.h (revision 5b080c3aadfabef156c72cedee796d7b3bac5180)
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 _LIBNVME_IMPL_H
17 #define	_LIBNVME_IMPL_H
18 
19 /*
20  * Implementation structures and related for libnvme.
21  */
22 
23 #include <libnvme.h>
24 #include <libdevinfo.h>
25 #include <stdbool.h>
26 #include <nvme_common.h>
27 #include <synch.h>
28 
29 #ifdef __cplusplus
30 extern "C" {
31 #endif
32 
33 /*
34  * Maximum size of an internal error message.
35  */
36 #define	NVME_ERR_LEN	1024
37 
38 typedef struct nvme_err_data {
39 	nvme_err_t ne_err;
40 	int32_t ne_syserr;
41 	char ne_errmsg[NVME_ERR_LEN];
42 	size_t ne_errlen;
43 	uint32_t ne_ctrl_sct;
44 	uint32_t ne_ctrl_sc;
45 } nvme_err_data_t;
46 
47 struct nvme {
48 	nvme_err_data_t nh_err;
49 	di_node_t nh_devinfo;
50 };
51 
52 struct nvme_ctrl_disc {
53 	di_node_t ncd_devi;
54 	di_minor_t ncd_minor;
55 };
56 
57 struct nvme_ctrl_iter {
58 	nvme_t *ni_nvme;
59 	bool ni_done;
60 	di_node_t ni_cur;
61 	nvme_ctrl_disc_t ni_disc;
62 };
63 
64 struct nvme_ctrl {
65 	nvme_t *nc_nvme;
66 	nvme_err_data_t nc_err;
67 	di_node_t nc_devi;
68 	di_minor_t nc_minor;
69 	char *nc_devi_path;
70 	int32_t nc_inst;
71 	int nc_fd;
72 	nvme_version_t nc_vers;
73 	nvme_identify_ctrl_t nc_info;
74 	const struct nvme_vsd *nc_vsd;
75 };
76 
77 struct nvme_ns_disc {
78 	uint32_t nnd_nsid;
79 	nvme_ns_disc_level_t nnd_level;
80 	nvme_ns_disc_flags_t nnd_flags;
81 	uint8_t nnd_eui64[8];
82 	uint8_t nnd_nguid[16];
83 };
84 
85 struct nvme_ns_iter {
86 	nvme_ctrl_t *nni_ctrl;
87 	nvme_ns_disc_level_t nni_level;
88 	bool nni_err;
89 	bool nni_done;
90 	size_t nni_cur_idx;
91 	nvme_ns_disc_t nni_disc;
92 };
93 
94 struct nvme_ns {
95 	nvme_ctrl_t *nn_ctrl;
96 	uint32_t nn_nsid;
97 };
98 
99 struct nvme_nvm_lba_fmt {
100 	uint32_t nnlf_id;
101 	uint32_t nnlf_ms;
102 	uint64_t nnlf_lbasz;
103 	uint32_t nnlf_rel;
104 };
105 
106 struct nvme_ctrl_info {
107 	nvme_info_err_t nci_err;
108 	int32_t nci_syserr;
109 	char nci_errmsg[NVME_ERR_LEN];
110 	size_t nci_errlen;
111 	/*
112 	 * The NVMe strings are generally ASCII strings that have trailing
113 	 * spaces on them ala SCSI. We transform that into a C style string
114 	 * without trailing padding. The +1 assumes we need to add a terminator.
115 	 */
116 	char nci_serial[NVME_SERIAL_SZ + 1];
117 	char nci_model[NVME_MODEL_SZ + 1];
118 	char nci_fwrev[NVME_FWVER_SZ + 1];
119 	bool nci_lbaf_valid[NVME_MAX_LBAF];
120 	nvme_nvm_lba_fmt_t nci_lbaf[NVME_MAX_LBAF];
121 	/*
122 	 * Only information below here should be persisted. That is, the above
123 	 * information is meant to be specific to the library.
124 	 */
125 	nvme_version_t nci_vers;
126 	int32_t nci_inst;
127 	char nci_dev_path[PATH_MAX];
128 	nvme_identify_ctrl_t nci_info;
129 	nvme_identify_nsid_t nci_ns;
130 	nvme_ctrl_transport_t nci_tport;
131 	uint16_t nci_vid;
132 	uint16_t nci_did;
133 	uint16_t nci_subvid;
134 	uint16_t nci_subsys;
135 	uint8_t nci_rev;
136 	uint32_t nci_mps_min;
137 	uint32_t nci_mps_max;
138 	uint32_t nci_nintrs;
139 };
140 
141 /*
142  * Internal nvlist_t keys for control information.
143  */
144 #define	NVME_NVL_CI_VERS	"version"
145 #define	NVME_NVL_CI_VERS_0	0
146 #define	NVME_NVL_CI_INST	"inst"
147 #define	NVME_NVL_CI_MAJOR	"nvme-major-version"
148 #define	NVME_NVL_CI_MINOR	"nvme-minor-version"
149 #define	NVME_NVL_CI_DEV_PATH	"dev-path"
150 #define	NVME_NVL_CI_ID_CTRL	"identify-controller"
151 #define	NVME_NVL_CI_ID_NS	"identify-namespace"
152 #define	NVME_NVL_CI_TPORT	"transport"
153 #define	NVME_NVL_CI_PCI_VID	"pci-vendor-id"
154 #define	NVME_NVL_CI_PCI_DID	"pci-device-id"
155 #define	NVME_NVL_CI_PCI_SUBVID	"pci-subsystem-vendor-id"
156 #define	NVME_NVL_CI_PCI_SUBSYS	"pci-subsystem-id"
157 #define	NVME_NVL_CI_PCI_REV	"pci-revision-id"
158 #define	NVME_NVL_CI_PCI_MPSMIN	"pci-memory-page-size-min"
159 #define	NVME_NVL_CI_PCI_MPSMAX	"pci-memory-page-size-max"
160 #define	NVME_NVL_CI_PCI_NINTRS	"pci-num-interrupts"
161 
162 struct nvme_ns_info {
163 	nvme_info_err_t nni_err;
164 	int32_t nni_syserr;
165 	char nni_errmsg[NVME_ERR_LEN];
166 	size_t nni_errlen;
167 	uint32_t nni_nsid;
168 	nvme_version_t nni_vers;
169 	nvme_ns_disc_level_t nni_level;
170 	nvme_ioctl_ns_info_t nni_info;
171 	bool nni_lbaf_valid[NVME_MAX_LBAF];
172 	nvme_nvm_lba_fmt_t nni_lbaf[NVME_MAX_LBAF];
173 };
174 
175 typedef enum {
176 	NVME_LOG_REQ_F_RAE		= 1 << 0,
177 	NVME_LOG_REQ_F_BCAST_NS_OK	= 1 << 1
178 } nvme_log_req_flags_t;
179 
180 struct nvme_log_req {
181 	nvme_ctrl_t *nlr_ctrl;
182 	uint32_t nlr_need;
183 	uint32_t nlr_allow;
184 	nvme_csi_t nlr_csi;
185 	uint32_t nlr_lid;
186 	uint32_t nlr_lsp;
187 	uint32_t nlr_lsi;
188 	uint32_t nlr_nsid;
189 	nvme_log_req_flags_t nlr_flags;
190 	void *nlr_output;
191 	size_t nlr_output_len;
192 	uint64_t nlr_offset;
193 };
194 
195 /*
196  * This structure is used internally to describe information about a given log
197  * page.
198  */
199 typedef enum {
200 	/*
201 	 * This indicates that the log page is actually implemented.
202 	 */
203 	NVME_LOG_DISC_F_IMPL		= 1 << 0
204 } nvme_log_disc_flags_t;
205 
206 struct nvme_log_disc {
207 	const char		*nld_short;
208 	const char		*nld_desc;
209 	uint32_t		nld_lid;
210 	nvme_csi_t		nld_csi;
211 	nvme_log_disc_kind_t	nld_kind;
212 	nvme_log_disc_source_t	nld_srcs;
213 	nvme_log_disc_fields_t	nld_fields;
214 	nvme_log_disc_scope_t	nld_scope;
215 	nvme_log_disc_flags_t	nld_flags;
216 	nvme_log_size_kind_t	nld_size_kind;
217 	uint64_t		nld_alloc_len;
218 	nvme_log_page_var_len_f	nld_var_func;
219 };
220 
221 struct nvme_log_iter {
222 	nvme_ctrl_t *nli_ctrl;
223 	nvme_log_disc_scope_t nli_scope;
224 	bool nli_std_done;
225 	bool nli_vs_done;
226 	size_t nli_cur_idx;
227 	nvme_log_disc_t nli_nld;
228 };
229 
230 /*
231  * Feature discovery and iteration.
232  */
233 struct nvme_feat_disc {
234 	const char *nfd_short;
235 	const char *nfd_spec;
236 	uint32_t nfd_fid;
237 	nvme_feat_kind_t nfd_kind;
238 	nvme_feat_scope_t nfd_scope;
239 	nvme_feat_flags_t nfd_flags;
240 	nvme_feat_csi_t nfd_csi;
241 	nvme_get_feat_fields_t nfd_in_get;
242 	nvme_set_feat_fields_t nfd_in_set;
243 	nvme_feat_output_t nfd_out_get;
244 	nvme_feat_output_t nfd_out_set;
245 	uint64_t nfd_len;
246 	nvme_feat_impl_t nfd_impl;
247 };
248 
249 struct nvme_feat_iter {
250 	nvme_ctrl_t *nfi_ctrl;
251 	nvme_feat_scope_t nfi_scope;
252 	size_t nfi_cur_idx;
253 	nvme_feat_disc_t nfi_disc;
254 };
255 
256 struct nvme_get_feat_req {
257 	nvme_ctrl_t *gfr_ctrl;
258 	uint32_t gfr_need;
259 	uint32_t gfr_allow;
260 	nvme_feat_flags_t gfr_flags;
261 	uint32_t gfr_fid;
262 	uint32_t gfr_sel;
263 	uint32_t gfr_nsid;
264 	uint32_t gfr_cdw11;
265 	void *gfr_buf;
266 	size_t gfr_len;
267 	uint64_t gfr_targ_len;
268 	/*
269 	 * The following are set on exec.
270 	 */
271 	bool gfr_results_valid;
272 	uint32_t gfr_cdw0;
273 };
274 
275 /*
276  * Identify command request
277  */
278 struct nvme_id_req {
279 	nvme_ctrl_t *nir_ctrl;
280 	const nvme_identify_info_t *nir_info;
281 	nvme_identify_req_field_t nir_need;
282 	nvme_identify_req_field_t nir_allow;
283 	uint32_t nir_nsid;
284 	uint32_t nir_ctrlid;
285 	void *nir_buf;
286 };
287 
288 /*
289  * Vendor unique command support.
290  */
291 struct nvme_vuc_disc {
292 	const char *nvd_short;
293 	const char *nvd_desc;
294 	uint8_t nvd_opc;
295 	nvme_vuc_disc_impact_t nvd_impact;
296 	nvme_vuc_disc_io_t nvd_dt;
297 	nvme_vuc_disc_lock_t nvd_lock;
298 };
299 
300 struct nvme_vuc_iter {
301 	nvme_ctrl_t *nvi_ctrl;
302 	size_t nvi_cur_idx;
303 };
304 
305 struct nvme_vuc_req {
306 	nvme_ctrl_t *nvr_ctrl;
307 	uint32_t nvr_need;
308 	uint32_t nvr_opcode;
309 	uint32_t nvr_timeout;
310 	uint32_t nvr_nsid;
311 	uint32_t nvr_cdw12;
312 	uint32_t nvr_cdw13;
313 	uint32_t nvr_cdw14;
314 	uint32_t nvr_cdw15;
315 	uint32_t nvr_impact;
316 	size_t nvr_outlen;
317 	size_t nvr_inlen;
318 	void *nvr_output;
319 	const void *nvr_input;
320 	/*
321 	 * The following values are set on exec.
322 	 */
323 	bool nvr_results_valid;
324 	uint32_t nvr_cdw0;
325 };
326 
327 /*
328  * If we ever support updating the boot partition ID, our expectation is that we
329  * end up doing that through other library interfaces even if it uses the same
330  * underlying ioctl. That ultimately will keep things simpler from a consumer
331  * perspective.
332  */
333 struct nvme_fw_commit_req {
334 	nvme_ctrl_t *fwc_ctrl;
335 	uint32_t fwc_need;
336 	uint32_t fwc_slot;
337 	uint32_t fwc_action;
338 };
339 
340 /*
341  * Format request data.
342  */
343 struct nvme_format_req {
344 	nvme_ctrl_t *nfr_ctrl;
345 	uint32_t nfr_need;
346 	bool nfr_ns;
347 	uint32_t nfr_lbaf;
348 	uint32_t nfr_ses;
349 	uint32_t nfr_nsid;
350 };
351 
352 /*
353  * WDC e6 request. This was made an opaque request style structure to try to
354  * safeguard us against future changes where something like the optional mode
355  * byte was required (right now it's just always zero).
356  */
357 struct nvme_wdc_e6_req {
358 	uint32_t wer_need;
359 	nvme_vuc_req_t *wer_vuc;
360 };
361 
362 /*
363  * Common interfaces for operation success and failure. There are currently
364  * errors that can exist on four different objects in the library and there is
365  * one success() and error() function for each of them. See the theory statement
366  * section on errors in libnvme.c for more information. Note, all namespace and
367  * request structures set errors on the controller.
368  *
369  * The controller has an extra error path that is used for converting ioctls to
370  * semantic errors. It takes care of translating the different kinds of kernel
371  * errors to the library's errors. Our goal is to never programmatically leak
372  * the kernel ioctls and their error codes as they do not promise stability
373  * unlike our aspirations. It also doesn't allow for variable arguments and only
374  * takes a single description.
375  */
376 extern bool nvme_error(nvme_t *, nvme_err_t, int32_t, const char *,
377     ...)  __PRINTFLIKE(4);
378 extern bool nvme_success(nvme_t *);
379 
380 extern bool nvme_ctrl_error(nvme_ctrl_t *, nvme_err_t, int32_t, const char *,
381     ...)  __PRINTFLIKE(4);
382 extern bool nvme_ioctl_error(nvme_ctrl_t *, const nvme_ioctl_common_t *,
383     const char *);
384 extern bool nvme_ioctl_syserror(nvme_ctrl_t *, int, const char *);
385 extern bool nvme_ctrl_success(nvme_ctrl_t *);
386 
387 extern bool nvme_info_error(nvme_ctrl_info_t *, nvme_info_err_t, int32_t,
388     const char *, ...)  __PRINTFLIKE(4);
389 extern bool nvme_info_success(nvme_ctrl_info_t *);
390 
391 extern bool nvme_ns_info_error(nvme_ns_info_t *, nvme_info_err_t, int32_t,
392     const char *, ...)  __PRINTFLIKE(4);
393 extern bool nvme_ns_info_success(nvme_ns_info_t *);
394 
395 /*
396  * Common functions for preserving and restoring error data. This comes up when
397  * utilizing callback functions for discovery where we call libnvme functions.
398  */
399 extern void nvme_err_save(const nvme_t *, nvme_err_data_t *);
400 extern void nvme_err_set(nvme_t *, const nvme_err_data_t *);
401 extern void nvme_ctrl_err_save(const nvme_ctrl_t *, nvme_err_data_t *);
402 extern void nvme_ctrl_err_set(nvme_ctrl_t *, const nvme_err_data_t *);
403 
404 /*
405  * Common functions for issuing ioctls to a controller.
406  */
407 extern bool nvme_ioc_ctrl_info(nvme_ctrl_t *, nvme_ioctl_ctrl_info_t *);
408 extern bool nvme_ioc_ns_info(nvme_ctrl_t *, uint32_t, nvme_ioctl_ns_info_t *);
409 
410 /*
411  * Common validation template functions.
412  */
413 extern bool nvme_field_miss_err(nvme_ctrl_t *, const nvme_field_info_t *,
414     size_t, nvme_err_t, const char *, uint32_t);
415 
416 typedef struct {
417 	const nvme_field_info_t *chk_fields;
418 	size_t chk_index;
419 	nvme_err_t chk_field_range;
420 	nvme_err_t chk_field_unsup;
421 	nvme_err_t chk_field_unuse;
422 } nvme_field_check_t;
423 
424 extern bool nvme_field_check_one(nvme_ctrl_t *, uint64_t, const char *,
425     const nvme_field_check_t *, uint32_t allow);
426 
427 /*
428  * Misc. functions.
429  */
430 extern const char *nvme_tporttostr(nvme_ctrl_transport_t);
431 extern nvme_ns_disc_level_t nvme_ns_state_to_disc_level(nvme_ns_state_t);
432 extern const char *nvme_nsleveltostr(nvme_ns_disc_level_t);
433 
434 /*
435  * Version related information and functions. There are statically declared
436  * version structures in the library for use for internal comparisons. Note, we
437  * have attempted to avoid a general comparison function in the internal API so
438  * that way it's always clear what we're comparing to a version and can't
439  * reverse things.
440  */
441 extern const nvme_version_t nvme_vers_1v0;
442 extern const nvme_version_t nvme_vers_1v1;
443 extern const nvme_version_t nvme_vers_1v2;
444 extern const nvme_version_t nvme_vers_1v3;
445 extern const nvme_version_t nvme_vers_1v4;
446 extern const nvme_version_t nvme_vers_2v0;
447 
448 extern bool nvme_vers_ctrl_atleast(const nvme_ctrl_t *, const nvme_version_t *);
449 extern bool nvme_vers_ctrl_info_atleast(const nvme_ctrl_info_t *,
450     const nvme_version_t *);
451 extern bool nvme_vers_ns_info_atleast(const nvme_ns_info_t *,
452     const nvme_version_t *);
453 
454 /*
455  * Vendor-specific information.
456  */
457 typedef struct nvme_vsd_ident {
458 	const char *nvdi_human;
459 	bool nvdi_subsys;
460 	uint16_t nvdi_vid;
461 	uint16_t nvdi_did;
462 	uint16_t nvdi_svid;
463 	uint16_t nvdi_sdid;
464 } nvme_vsd_ident_t;
465 
466 typedef struct nvme_vsd {
467 	const nvme_vsd_ident_t *nvd_ident;
468 	size_t nvd_nident;
469 	const nvme_log_page_info_t *const *nvd_logs;
470 	size_t nvd_nlogs;
471 	const nvme_vuc_disc_t *nvd_vuc;
472 	size_t nvd_nvuc;
473 } nvme_vsd_t;
474 
475 extern const nvme_log_page_info_t ocp_log_smart;
476 extern const nvme_log_page_info_t ocp_log_errrec;
477 extern const nvme_log_page_info_t ocp_log_fwact;
478 extern const nvme_log_page_info_t ocp_log_lat;
479 extern const nvme_log_page_info_t ocp_log_devcap;
480 extern const nvme_log_page_info_t ocp_log_unsup;
481 
482 extern const nvme_vsd_t wdc_sn840;
483 extern const nvme_vsd_t wdc_sn65x;
484 extern const nvme_vsd_t micron_7300;
485 extern const nvme_vsd_t micron_74x0;
486 extern const nvme_vsd_t micron_x500;
487 extern const nvme_vsd_t intel_p5510;
488 extern const nvme_vsd_t solidigm_p5x20;
489 extern const nvme_vsd_t solidigm_ps10x0;
490 extern const nvme_vsd_t kioxia_cd8;
491 
492 extern void nvme_vendor_map_ctrl(nvme_ctrl_t *);
493 extern bool nvme_vendor_vuc_supported(nvme_ctrl_t *, const char *);
494 
495 /*
496  * Internal formatting functions that probably could be external.
497  */
498 #define	NVME_NGUID_NAMELEN	33
499 #define	NVME_EUI64_NAMELEN	17
500 
501 extern int nvme_format_nguid(const uint8_t [16], char *, size_t);
502 extern int nvme_format_eui64(const uint8_t [8], char *, size_t);
503 
504 #ifdef __cplusplus
505 }
506 #endif
507 
508 #endif /* _LIBNVME_IMPL_H */
509