xref: /illumos-gate/usr/src/common/nvme/nvme_log.c (revision 7001e2dfbde60ab6bfa231a6025776e173dc4657)
1533affcbSRobert Mustacchi /*
2533affcbSRobert Mustacchi  * This file and its contents are supplied under the terms of the
3533affcbSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4533affcbSRobert Mustacchi  * You may only use this file in accordance with the terms of version
5533affcbSRobert Mustacchi  * 1.0 of the CDDL.
6533affcbSRobert Mustacchi  *
7533affcbSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8533affcbSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9533affcbSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10533affcbSRobert Mustacchi  */
11533affcbSRobert Mustacchi 
12533affcbSRobert Mustacchi /*
13533affcbSRobert Mustacchi  * Copyright 2024 Oxide Computer Company
14533affcbSRobert Mustacchi  */
15533affcbSRobert Mustacchi 
16533affcbSRobert Mustacchi /*
17533affcbSRobert Mustacchi  * This file deals with validating and issuing various log page requests to an
18533affcbSRobert Mustacchi  * NVMe target. This contains information about all spec-based log pages. The
19533affcbSRobert Mustacchi  * get log page command has added a number of fields that have evolved over
20533affcbSRobert Mustacchi  * time. We validate that we're only sending commands to a device that we expect
21533affcbSRobert Mustacchi  * it to have a chance of understanding. In general, we only allow through
22533affcbSRobert Mustacchi  * unknown log pages that correspond to vendor-specific commands.
23533affcbSRobert Mustacchi  *
24533affcbSRobert Mustacchi  * We have two different tables of information that we use to drive and validate
25533affcbSRobert Mustacchi  * things here:
26533affcbSRobert Mustacchi  *
27533affcbSRobert Mustacchi  * 1) We have a list of fields that exist which include minimum controller
28533affcbSRobert Mustacchi  * versions and related functionality validation routines that operate off of
29533affcbSRobert Mustacchi  * the nvme_t. While tihs list includes things like the CSI and LID, these are
30533affcbSRobert Mustacchi  * things that may only be specified when we have a non-standard log page.
31533affcbSRobert Mustacchi  *
32533affcbSRobert Mustacchi  * 2) We then have a table of log pages that are supported which list which
33533affcbSRobert Mustacchi  * fields we allow for the device. Not all of this can be static.
34533affcbSRobert Mustacchi  *
35533affcbSRobert Mustacchi  * This file has been designed to be shareable between both userland and the
36533affcbSRobert Mustacchi  * kernel since the logic that libnvme wants to use is quite similar.
37533affcbSRobert Mustacchi  */
38533affcbSRobert Mustacchi 
39533affcbSRobert Mustacchi #include "nvme_common.h"
40533affcbSRobert Mustacchi 
41533affcbSRobert Mustacchi #include <sys/sysmacros.h>
42533affcbSRobert Mustacchi #ifdef	_KERNEL
43533affcbSRobert Mustacchi #include <sys/sunddi.h>
44533affcbSRobert Mustacchi #include <sys/stdint.h>
45533affcbSRobert Mustacchi #else
46533affcbSRobert Mustacchi #include <stdio.h>
47533affcbSRobert Mustacchi #include <inttypes.h>
48533affcbSRobert Mustacchi #endif
49533affcbSRobert Mustacchi 
50533affcbSRobert Mustacchi static bool
nvme_log_field_valid_lsp(const nvme_field_info_t * field,const nvme_valid_ctrl_data_t * data,uint64_t lsp,char * msg,size_t msglen)51533affcbSRobert Mustacchi nvme_log_field_valid_lsp(const nvme_field_info_t *field,
52533affcbSRobert Mustacchi     const nvme_valid_ctrl_data_t *data, uint64_t lsp, char *msg, size_t msglen)
53533affcbSRobert Mustacchi {
54533affcbSRobert Mustacchi 	uint64_t max;
55533affcbSRobert Mustacchi 
56533affcbSRobert Mustacchi 	if (nvme_field_atleast(data, &nvme_vers_2v0)) {
57533affcbSRobert Mustacchi 		max = NVME_LOG_MAX_LSP_2v0;
58533affcbSRobert Mustacchi 	} else {
59533affcbSRobert Mustacchi 		max = NVME_LOG_MAX_LSP;
60533affcbSRobert Mustacchi 	}
61533affcbSRobert Mustacchi 
62533affcbSRobert Mustacchi 	return (nvme_field_range_check(field, 0, max, msg, msglen, lsp));
63533affcbSRobert Mustacchi }
64533affcbSRobert Mustacchi 
65533affcbSRobert Mustacchi static bool
nvme_log_field_supported_offset(const nvme_field_info_t * field,const nvme_valid_ctrl_data_t * data,char * msg,size_t msglen)66533affcbSRobert Mustacchi nvme_log_field_supported_offset(const nvme_field_info_t *field,
67533affcbSRobert Mustacchi     const nvme_valid_ctrl_data_t *data, char *msg, size_t msglen)
68533affcbSRobert Mustacchi {
69533affcbSRobert Mustacchi 	if (data->vcd_id->id_lpa.lp_extsup != 0) {
70533affcbSRobert Mustacchi 		return (true);
71533affcbSRobert Mustacchi 	}
72533affcbSRobert Mustacchi 
73533affcbSRobert Mustacchi 	(void) snprintf(msg, msglen, "controller does not support field %s "
74533affcbSRobert Mustacchi 	    "(%s): missing extended data support in Log Page Attributes (LPA)",
75533affcbSRobert Mustacchi 	    field->nlfi_human, field->nlfi_spec);
76533affcbSRobert Mustacchi 	return (false);
77533affcbSRobert Mustacchi }
78533affcbSRobert Mustacchi 
79533affcbSRobert Mustacchi /*
80533affcbSRobert Mustacchi  * The offset is a full 64-bit byte value; however, it must be 4-byte aligned.
81533affcbSRobert Mustacchi  */
82533affcbSRobert Mustacchi static bool
nvme_log_field_valid_offset(const nvme_field_info_t * field,const nvme_valid_ctrl_data_t * data,uint64_t size,char * msg,size_t msglen)83533affcbSRobert Mustacchi nvme_log_field_valid_offset(const nvme_field_info_t *field,
84533affcbSRobert Mustacchi     const nvme_valid_ctrl_data_t *data, uint64_t size, char *msg, size_t msglen)
85533affcbSRobert Mustacchi {
86533affcbSRobert Mustacchi 	if ((size % NVME_DWORD_SIZE) != 0) {
87533affcbSRobert Mustacchi 		(void) snprintf(msg, msglen, "%s (%s) value 0x%" PRIx64 " is "
88533affcbSRobert Mustacchi 		    "invalid: value must be %u-byte aligned", field->nlfi_human,
89533affcbSRobert Mustacchi 		    field->nlfi_spec, size, NVME_DWORD_SIZE);
90533affcbSRobert Mustacchi 		return (false);
91533affcbSRobert Mustacchi 	}
92533affcbSRobert Mustacchi 
93533affcbSRobert Mustacchi 	return (true);
94533affcbSRobert Mustacchi }
95533affcbSRobert Mustacchi 
96533affcbSRobert Mustacchi static bool
nvme_log_field_valid_size(const nvme_field_info_t * field,const nvme_valid_ctrl_data_t * data,uint64_t size,char * msg,size_t msglen)97533affcbSRobert Mustacchi nvme_log_field_valid_size(const nvme_field_info_t *field,
98533affcbSRobert Mustacchi     const nvme_valid_ctrl_data_t *data, uint64_t size, char *msg, size_t msglen)
99533affcbSRobert Mustacchi {
100533affcbSRobert Mustacchi 	uint64_t max = NVME_LOG_MAX_SIZE;
101533affcbSRobert Mustacchi 
102533affcbSRobert Mustacchi 	if (nvme_field_atleast(data, &nvme_vers_1v2) &&
103533affcbSRobert Mustacchi 	    data->vcd_id->id_lpa.lp_extsup != 0) {
104533affcbSRobert Mustacchi 		max = NVME_LOG_MAX_SIZE_1v2;
105533affcbSRobert Mustacchi 	}
106533affcbSRobert Mustacchi 
107533affcbSRobert Mustacchi 	/*
108533affcbSRobert Mustacchi 	 * The NVMe specification operates in terms of uint32_t (dword) units.
109533affcbSRobert Mustacchi 	 * Make sure that we are operating within that constraint.
110533affcbSRobert Mustacchi 	 */
111533affcbSRobert Mustacchi 	if ((size % 4) != 0) {
112533affcbSRobert Mustacchi 		(void) snprintf(msg, msglen, "%s (%s) value 0x%" PRIx64 " is "
113533affcbSRobert Mustacchi 		    "invalid: value must be 4-byte aligned", field->nlfi_human,
114533affcbSRobert Mustacchi 		    field->nlfi_spec, size);
115533affcbSRobert Mustacchi 		return (false);
116533affcbSRobert Mustacchi 	}
117533affcbSRobert Mustacchi 
118533affcbSRobert Mustacchi 	return (nvme_field_range_check(field, 4, max, msg, msglen, size));
119533affcbSRobert Mustacchi }
120533affcbSRobert Mustacchi 
121533affcbSRobert Mustacchi const nvme_field_info_t nvme_log_fields[] = {
122533affcbSRobert Mustacchi 	[NVME_LOG_REQ_FIELD_LID] = {
123533affcbSRobert Mustacchi 		.nlfi_vers = &nvme_vers_1v0,
124533affcbSRobert Mustacchi 		.nlfi_max_size = NVME_LOG_MAX_LID,
125533affcbSRobert Mustacchi 		.nlfi_spec = "lid",
126533affcbSRobert Mustacchi 		.nlfi_human = "log ID",
127533affcbSRobert Mustacchi 		.nlfi_def_req = true,
128533affcbSRobert Mustacchi 		.nlfi_def_allow = true
129533affcbSRobert Mustacchi 	},
130533affcbSRobert Mustacchi 	[NVME_LOG_REQ_FIELD_LSP] = {
131533affcbSRobert Mustacchi 		.nlfi_vers = &nvme_vers_1v3,
132533affcbSRobert Mustacchi 		.nlfi_valid = nvme_log_field_valid_lsp,
133533affcbSRobert Mustacchi 		.nlfi_spec = "lsp",
134533affcbSRobert Mustacchi 		.nlfi_human = "log specific field",
135533affcbSRobert Mustacchi 		.nlfi_def_req = false,
136533affcbSRobert Mustacchi 		.nlfi_def_allow = true
137533affcbSRobert Mustacchi 	},
138533affcbSRobert Mustacchi 	[NVME_LOG_REQ_FIELD_LSI] = {
139533affcbSRobert Mustacchi 		.nlfi_vers = &nvme_vers_1v4,
140533affcbSRobert Mustacchi 		.nlfi_max_size = NVME_LOG_MAX_LSI,
141533affcbSRobert Mustacchi 		.nlfi_spec = "lsi",
142533affcbSRobert Mustacchi 		.nlfi_human = "log specific ID",
143533affcbSRobert Mustacchi 		.nlfi_def_req = false,
144533affcbSRobert Mustacchi 		.nlfi_def_allow = true
145533affcbSRobert Mustacchi 	},
146533affcbSRobert Mustacchi 	[NVME_LOG_REQ_FIELD_SIZE] = {
147533affcbSRobert Mustacchi 		.nlfi_vers = &nvme_vers_1v0,
148533affcbSRobert Mustacchi 		.nlfi_valid = nvme_log_field_valid_size,
149533affcbSRobert Mustacchi 		.nlfi_spec = "dptr/numd",
150533affcbSRobert Mustacchi 		.nlfi_human = "output",
151533affcbSRobert Mustacchi 		.nlfi_def_req = true,
152533affcbSRobert Mustacchi 		.nlfi_def_allow = true
153533affcbSRobert Mustacchi 	},
154533affcbSRobert Mustacchi 	[NVME_LOG_REQ_FIELD_CSI] = {
155533affcbSRobert Mustacchi 		.nlfi_vers = &nvme_vers_2v0,
156533affcbSRobert Mustacchi 		/*
157533affcbSRobert Mustacchi 		 * This has the field's maximum range right now, though NVMe 2.0
158533affcbSRobert Mustacchi 		 * only defines a few values. Because the kernel only allows
159533affcbSRobert Mustacchi 		 * through known log pages, we don't really bother to check the
160533affcbSRobert Mustacchi 		 * condensed range and allow vendor-specific logs to go wild.
161533affcbSRobert Mustacchi 		 */
162533affcbSRobert Mustacchi 		.nlfi_max_size = NVME_LOG_MAX_CSI,
163533affcbSRobert Mustacchi 		.nlfi_spec = "csi",
164533affcbSRobert Mustacchi 		.nlfi_human = "command set ID",
165533affcbSRobert Mustacchi 		.nlfi_def_req = false,
166533affcbSRobert Mustacchi 		.nlfi_def_allow = true
167533affcbSRobert Mustacchi 	},
168533affcbSRobert Mustacchi 	[NVME_LOG_REQ_FIELD_RAE] = {
169533affcbSRobert Mustacchi 		.nlfi_vers = &nvme_vers_1v3,
170533affcbSRobert Mustacchi 		.nlfi_max_size = NVME_LOG_MAX_RAE,
171533affcbSRobert Mustacchi 		.nlfi_spec = "rae",
172533affcbSRobert Mustacchi 		.nlfi_human = "retain asynchronous event",
173533affcbSRobert Mustacchi 		.nlfi_def_req = false,
174533affcbSRobert Mustacchi 		.nlfi_def_allow = true
175533affcbSRobert Mustacchi 	},
176533affcbSRobert Mustacchi 	[NVME_LOG_REQ_FIELD_OFFSET] = {
177533affcbSRobert Mustacchi 		.nlfi_vers = &nvme_vers_1v2,
178533affcbSRobert Mustacchi 		.nlfi_sup = nvme_log_field_supported_offset,
179533affcbSRobert Mustacchi 		.nlfi_valid = nvme_log_field_valid_offset,
180533affcbSRobert Mustacchi 		.nlfi_max_size = NVME_LOG_MAX_OFFSET,
181533affcbSRobert Mustacchi 		.nlfi_spec = "lpo",
182533affcbSRobert Mustacchi 		.nlfi_human = "log offset",
183533affcbSRobert Mustacchi 		.nlfi_def_req = false,
184533affcbSRobert Mustacchi 		.nlfi_def_allow = true
185533affcbSRobert Mustacchi 	},
186533affcbSRobert Mustacchi 	[NVME_LOG_REQ_FIELD_NSID] = {
187*7001e2dfSRobert Mustacchi 		.nlfi_vers = &nvme_vers_1v0,
188533affcbSRobert Mustacchi 		.nlfi_valid = nvme_field_valid_nsid,
189533affcbSRobert Mustacchi 		.nlfi_spec = "nsid",
190533affcbSRobert Mustacchi 		.nlfi_human = "namespace ID",
191533affcbSRobert Mustacchi 		.nlfi_def_req = false,
192533affcbSRobert Mustacchi 		.nlfi_def_allow = true
193533affcbSRobert Mustacchi 	}
194533affcbSRobert Mustacchi };
195533affcbSRobert Mustacchi 
196533affcbSRobert Mustacchi size_t nvme_log_nfields = ARRAY_SIZE(nvme_log_fields);
197533affcbSRobert Mustacchi 
198533affcbSRobert Mustacchi static uint64_t
nvme_lpd_error_len(const nvme_valid_ctrl_data_t * data,const nvme_log_page_info_t * lpi)199533affcbSRobert Mustacchi nvme_lpd_error_len(const nvme_valid_ctrl_data_t *data,
200533affcbSRobert Mustacchi     const nvme_log_page_info_t *lpi)
201533affcbSRobert Mustacchi {
202533affcbSRobert Mustacchi 	const uint64_t nents = data->vcd_id->id_elpe + 1;
203533affcbSRobert Mustacchi 	const uint64_t logsz = nents * sizeof (nvme_error_log_entry_t);
204533affcbSRobert Mustacchi 
205533affcbSRobert Mustacchi 	return (logsz);
206533affcbSRobert Mustacchi }
207533affcbSRobert Mustacchi 
208533affcbSRobert Mustacchi static nvme_log_disc_scope_t
nvme_lpd_health_scope(const nvme_valid_ctrl_data_t * data,const nvme_log_page_info_t * lpi)209533affcbSRobert Mustacchi nvme_lpd_health_scope(const nvme_valid_ctrl_data_t *data,
210533affcbSRobert Mustacchi     const nvme_log_page_info_t *lpi)
211533affcbSRobert Mustacchi {
212533affcbSRobert Mustacchi 	nvme_log_disc_scope_t ret = NVME_LOG_SCOPE_CTRL;
213533affcbSRobert Mustacchi 
214533affcbSRobert Mustacchi 	if (nvme_field_atleast(data, &nvme_vers_1v0) &&
215533affcbSRobert Mustacchi 	    data->vcd_id->id_lpa.lp_smart != 0) {
216533affcbSRobert Mustacchi 		ret |= NVME_LOG_SCOPE_NS;
217533affcbSRobert Mustacchi 	}
218533affcbSRobert Mustacchi 
219533affcbSRobert Mustacchi 	return (ret);
220533affcbSRobert Mustacchi }
221533affcbSRobert Mustacchi 
222533affcbSRobert Mustacchi static bool
nvme_lpd_changens_sup(const nvme_valid_ctrl_data_t * data,const nvme_log_page_info_t * lpi)223533affcbSRobert Mustacchi nvme_lpd_changens_sup(const nvme_valid_ctrl_data_t *data,
224533affcbSRobert Mustacchi     const nvme_log_page_info_t *lpi)
225533affcbSRobert Mustacchi {
226533affcbSRobert Mustacchi 	return (nvme_field_atleast(data, &nvme_vers_1v2) &&
227533affcbSRobert Mustacchi 	    data->vcd_id->id_oaes.oaes_nsan != 0);
228533affcbSRobert Mustacchi }
229533affcbSRobert Mustacchi 
230046911ebSRobert Mustacchi static bool
nvme_lpd_cmdeff_sup(const nvme_valid_ctrl_data_t * data,const nvme_log_page_info_t * lpi)231046911ebSRobert Mustacchi nvme_lpd_cmdeff_sup(const nvme_valid_ctrl_data_t *data,
232046911ebSRobert Mustacchi     const nvme_log_page_info_t *lpi)
233046911ebSRobert Mustacchi {
234046911ebSRobert Mustacchi 	return (nvme_field_atleast(data, &nvme_vers_1v2) &&
235046911ebSRobert Mustacchi 	    data->vcd_id->id_lpa.lp_cmdeff != 0);
236046911ebSRobert Mustacchi }
237046911ebSRobert Mustacchi 
238533affcbSRobert Mustacchi /*
239533affcbSRobert Mustacchi  * The short names here correspond to the well defined names in nvmeadm(8) and
240533affcbSRobert Mustacchi  * libnvme(3LIB) that users expect to be able to use. Please do not change them
241533affcbSRobert Mustacchi  * without accounting for aliases and backwards compatibility.
242533affcbSRobert Mustacchi  */
243533affcbSRobert Mustacchi const nvme_log_page_info_t nvme_std_log_pages[] = { {
244046911ebSRobert Mustacchi 	.nlpi_short = "suplog",
245046911ebSRobert Mustacchi 	.nlpi_human = "Supported Log Pages",
246046911ebSRobert Mustacchi 	.nlpi_lid = NVME_LOGPAGE_SUP,
247046911ebSRobert Mustacchi 	.nlpi_csi = NVME_CSI_NVM,
248046911ebSRobert Mustacchi 	.nlpi_vers = &nvme_vers_2v0,
249046911ebSRobert Mustacchi 	.nlpi_kind = NVME_LOG_ID_MANDATORY,
250046911ebSRobert Mustacchi 	.nlpi_source = NVME_LOG_DISC_S_SPEC,
251046911ebSRobert Mustacchi 	.nlpi_scope = NVME_LOG_SCOPE_CTRL,
252046911ebSRobert Mustacchi 	.nlpi_len = sizeof (nvme_suplog_log_t)
253046911ebSRobert Mustacchi }, {
254533affcbSRobert Mustacchi 	.nlpi_short = "error",
255533affcbSRobert Mustacchi 	.nlpi_human = "Error information",
256533affcbSRobert Mustacchi 	.nlpi_lid = NVME_LOGPAGE_ERROR,
257533affcbSRobert Mustacchi 	.nlpi_csi = NVME_CSI_NVM,
258533affcbSRobert Mustacchi 	.nlpi_vers = &nvme_vers_1v0,
259533affcbSRobert Mustacchi 	.nlpi_kind = NVME_LOG_ID_MANDATORY,
260533affcbSRobert Mustacchi 	.nlpi_source = NVME_LOG_DISC_S_SPEC,
261533affcbSRobert Mustacchi 	.nlpi_disc = NVME_LOG_DISC_F_NEED_RAE,
262533affcbSRobert Mustacchi 	.nlpi_scope = NVME_LOG_SCOPE_CTRL,
263533affcbSRobert Mustacchi 	.nlpi_len_func = nvme_lpd_error_len
264533affcbSRobert Mustacchi }, {
265533affcbSRobert Mustacchi 	.nlpi_short = "health",
266533affcbSRobert Mustacchi 	.nlpi_human = "SMART / Health information",
267533affcbSRobert Mustacchi 	.nlpi_lid = NVME_LOGPAGE_HEALTH,
268533affcbSRobert Mustacchi 	.nlpi_csi = NVME_CSI_NVM,
269533affcbSRobert Mustacchi 	.nlpi_vers = &nvme_vers_1v0,
270533affcbSRobert Mustacchi 	.nlpi_kind = NVME_LOG_ID_MANDATORY,
271533affcbSRobert Mustacchi 	.nlpi_source = NVME_LOG_DISC_S_SPEC | NVME_LOG_DISC_S_ID_CTRL,
272533affcbSRobert Mustacchi 	.nlpi_disc = NVME_LOG_DISC_F_NEED_RAE,
273533affcbSRobert Mustacchi 	.nlpi_scope_func = nvme_lpd_health_scope,
274533affcbSRobert Mustacchi 	.nlpi_len = sizeof (nvme_health_log_t)
275533affcbSRobert Mustacchi }, {
276533affcbSRobert Mustacchi 	.nlpi_short = "firmware",
277533affcbSRobert Mustacchi 	.nlpi_human = "Firmware Slot Information",
278533affcbSRobert Mustacchi 	.nlpi_lid = NVME_LOGPAGE_FWSLOT,
279533affcbSRobert Mustacchi 	.nlpi_csi = NVME_CSI_NVM,
280533affcbSRobert Mustacchi 	.nlpi_vers = &nvme_vers_1v0,
281533affcbSRobert Mustacchi 	.nlpi_kind = NVME_LOG_ID_MANDATORY,
282533affcbSRobert Mustacchi 	.nlpi_source = NVME_LOG_DISC_S_SPEC,
283533affcbSRobert Mustacchi 	.nlpi_disc = 0,
284533affcbSRobert Mustacchi 	.nlpi_scope = NVME_LOG_SCOPE_NVM,
285533affcbSRobert Mustacchi 	.nlpi_len = sizeof (nvme_fwslot_log_t),
286533affcbSRobert Mustacchi }, {
287533affcbSRobert Mustacchi 	.nlpi_short = "changens",
288533affcbSRobert Mustacchi 	.nlpi_human = "changed namespaces",
289533affcbSRobert Mustacchi 	.nlpi_lid = NVME_LOGPAGE_NSCHANGE,
290533affcbSRobert Mustacchi 	.nlpi_csi = NVME_CSI_NVM,
291533affcbSRobert Mustacchi 	.nlpi_vers = &nvme_vers_1v2,
292533affcbSRobert Mustacchi 	.nlpi_sup_func = nvme_lpd_changens_sup,
293533affcbSRobert Mustacchi 	.nlpi_kind = NVME_LOG_ID_OPTIONAL,
294533affcbSRobert Mustacchi 	.nlpi_source = NVME_LOG_DISC_S_ID_CTRL,
295533affcbSRobert Mustacchi 	.nlpi_disc = NVME_LOG_DISC_F_NEED_RAE,
296533affcbSRobert Mustacchi 	.nlpi_scope = NVME_LOG_SCOPE_CTRL,
297533affcbSRobert Mustacchi 	.nlpi_len = sizeof (nvme_nschange_list_t)
298046911ebSRobert Mustacchi }, {
299046911ebSRobert Mustacchi 	.nlpi_short = "cmdeff",
300046911ebSRobert Mustacchi 	.nlpi_human = "commands supported and effects",
301046911ebSRobert Mustacchi 	.nlpi_lid = NVME_LOGPAGE_CMDSUP,
302046911ebSRobert Mustacchi 	.nlpi_csi = NVME_CSI_NVM,
303046911ebSRobert Mustacchi 	.nlpi_vers = &nvme_vers_1v2,
304046911ebSRobert Mustacchi 	.nlpi_sup_func = nvme_lpd_cmdeff_sup,
305046911ebSRobert Mustacchi 	.nlpi_kind = NVME_LOG_ID_OPTIONAL,
306046911ebSRobert Mustacchi 	.nlpi_source = NVME_LOG_DISC_S_ID_CTRL,
307046911ebSRobert Mustacchi 	.nlpi_scope = NVME_LOG_SCOPE_CTRL,
308046911ebSRobert Mustacchi 	.nlpi_len = sizeof (nvme_cmdeff_log_t)
309533affcbSRobert Mustacchi }  };
310533affcbSRobert Mustacchi 
311533affcbSRobert Mustacchi size_t nvme_std_log_npages = ARRAY_SIZE(nvme_std_log_pages);
312533affcbSRobert Mustacchi 
313533affcbSRobert Mustacchi nvme_log_disc_scope_t
nvme_log_page_info_scope(const nvme_log_page_info_t * info,const nvme_valid_ctrl_data_t * data)314533affcbSRobert Mustacchi nvme_log_page_info_scope(const nvme_log_page_info_t *info,
315533affcbSRobert Mustacchi     const nvme_valid_ctrl_data_t *data)
316533affcbSRobert Mustacchi {
317533affcbSRobert Mustacchi 	if (info->nlpi_scope_func != NULL) {
318533affcbSRobert Mustacchi 		return (info->nlpi_scope_func(data, info));
319533affcbSRobert Mustacchi 	} else {
320533affcbSRobert Mustacchi 		return (info->nlpi_scope);
321533affcbSRobert Mustacchi 	}
322533affcbSRobert Mustacchi }
323533affcbSRobert Mustacchi 
324533affcbSRobert Mustacchi uint64_t
nvme_log_page_info_size(const nvme_log_page_info_t * info,const nvme_valid_ctrl_data_t * data,bool * var)325533affcbSRobert Mustacchi nvme_log_page_info_size(const nvme_log_page_info_t *info,
326533affcbSRobert Mustacchi     const nvme_valid_ctrl_data_t *data, bool *var)
327533affcbSRobert Mustacchi {
328e0c5eaa0SRobert Mustacchi 	uint64_t len;
329533affcbSRobert Mustacchi 	*var = info->nlpi_var_func != NULL;
330533affcbSRobert Mustacchi 
331533affcbSRobert Mustacchi 	if (info->nlpi_len_func != NULL) {
332e0c5eaa0SRobert Mustacchi 		len = info->nlpi_len_func(data, info);
333533affcbSRobert Mustacchi 	} else {
334e0c5eaa0SRobert Mustacchi 		len = info->nlpi_len;
335533affcbSRobert Mustacchi 	}
336e0c5eaa0SRobert Mustacchi 
337e0c5eaa0SRobert Mustacchi 	/*
338e0c5eaa0SRobert Mustacchi 	 * Some vendor-specific log pages are not documented to have 4-byte
339e0c5eaa0SRobert Mustacchi 	 * aligned lengths. This means that to get the full log page you must
340e0c5eaa0SRobert Mustacchi 	 * round this up to ensure that you end up with a valid request. We opt
341e0c5eaa0SRobert Mustacchi 	 * to do this here rather than have to check every single log page data
342e0c5eaa0SRobert Mustacchi 	 * structure and fix it up manually. While it means consumers that are
343e0c5eaa0SRobert Mustacchi 	 * using this to ignore information about the type itself may
344e0c5eaa0SRobert Mustacchi 	 * erroneously display extra bytes (e.g. nvmeadm's default hex dumper),
345e0c5eaa0SRobert Mustacchi 	 * that's better than getting an error or truncating the data.
346e0c5eaa0SRobert Mustacchi 	 */
347e0c5eaa0SRobert Mustacchi 	return (P2ROUNDUP(len, NVME_DWORD_SIZE));
348533affcbSRobert Mustacchi }
349533affcbSRobert Mustacchi 
350533affcbSRobert Mustacchi bool
nvme_log_page_info_supported(const nvme_log_page_info_t * info,const nvme_valid_ctrl_data_t * data)351533affcbSRobert Mustacchi nvme_log_page_info_supported(const nvme_log_page_info_t *info,
352533affcbSRobert Mustacchi     const nvme_valid_ctrl_data_t *data)
353533affcbSRobert Mustacchi {
354533affcbSRobert Mustacchi 	bool vers, sup_func;
355533affcbSRobert Mustacchi 
356533affcbSRobert Mustacchi 	if (info->nlpi_vers != NULL) {
357533affcbSRobert Mustacchi 		vers = nvme_field_atleast(data, info->nlpi_vers);
358533affcbSRobert Mustacchi 	} else {
359533affcbSRobert Mustacchi 		vers = true;
360533affcbSRobert Mustacchi 	}
361533affcbSRobert Mustacchi 
362533affcbSRobert Mustacchi 	if (info->nlpi_sup_func != NULL) {
363533affcbSRobert Mustacchi 		sup_func = info->nlpi_sup_func(data, info);
364533affcbSRobert Mustacchi 	} else {
365533affcbSRobert Mustacchi 		sup_func = true;
366533affcbSRobert Mustacchi 	}
367533affcbSRobert Mustacchi 
368533affcbSRobert Mustacchi 	return (vers && sup_func);
369533affcbSRobert Mustacchi }
370