xref: /illumos-gate/usr/src/common/nvme/nvme_log.c (revision 533affcbc7fc4d0c8132976ea454aaa715fe2307)
1*533affcbSRobert Mustacchi /*
2*533affcbSRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*533affcbSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*533affcbSRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*533affcbSRobert Mustacchi  * 1.0 of the CDDL.
6*533affcbSRobert Mustacchi  *
7*533affcbSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*533affcbSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*533affcbSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*533affcbSRobert Mustacchi  */
11*533affcbSRobert Mustacchi 
12*533affcbSRobert Mustacchi /*
13*533affcbSRobert Mustacchi  * Copyright 2024 Oxide Computer Company
14*533affcbSRobert Mustacchi  */
15*533affcbSRobert Mustacchi 
16*533affcbSRobert Mustacchi /*
17*533affcbSRobert Mustacchi  * This file deals with validating and issuing various log page requests to an
18*533affcbSRobert Mustacchi  * NVMe target. This contains information about all spec-based log pages. The
19*533affcbSRobert Mustacchi  * get log page command has added a number of fields that have evolved over
20*533affcbSRobert Mustacchi  * time. We validate that we're only sending commands to a device that we expect
21*533affcbSRobert Mustacchi  * it to have a chance of understanding. In general, we only allow through
22*533affcbSRobert Mustacchi  * unknown log pages that correspond to vendor-specific commands.
23*533affcbSRobert Mustacchi  *
24*533affcbSRobert Mustacchi  * We have two different tables of information that we use to drive and validate
25*533affcbSRobert Mustacchi  * things here:
26*533affcbSRobert Mustacchi  *
27*533affcbSRobert Mustacchi  * 1) We have a list of fields that exist which include minimum controller
28*533affcbSRobert Mustacchi  * versions and related functionality validation routines that operate off of
29*533affcbSRobert Mustacchi  * the nvme_t. While tihs list includes things like the CSI and LID, these are
30*533affcbSRobert Mustacchi  * things that may only be specified when we have a non-standard log page.
31*533affcbSRobert Mustacchi  *
32*533affcbSRobert Mustacchi  * 2) We then have a table of log pages that are supported which list which
33*533affcbSRobert Mustacchi  * fields we allow for the device. Not all of this can be static.
34*533affcbSRobert Mustacchi  *
35*533affcbSRobert Mustacchi  * This file has been designed to be shareable between both userland and the
36*533affcbSRobert Mustacchi  * kernel since the logic that libnvme wants to use is quite similar.
37*533affcbSRobert Mustacchi  */
38*533affcbSRobert Mustacchi 
39*533affcbSRobert Mustacchi #include "nvme_common.h"
40*533affcbSRobert Mustacchi 
41*533affcbSRobert Mustacchi #include <sys/sysmacros.h>
42*533affcbSRobert Mustacchi #ifdef	_KERNEL
43*533affcbSRobert Mustacchi #include <sys/sunddi.h>
44*533affcbSRobert Mustacchi #include <sys/stdint.h>
45*533affcbSRobert Mustacchi #else
46*533affcbSRobert Mustacchi #include <stdio.h>
47*533affcbSRobert Mustacchi #include <inttypes.h>
48*533affcbSRobert Mustacchi #endif
49*533affcbSRobert Mustacchi 
50*533affcbSRobert Mustacchi static bool
51*533affcbSRobert Mustacchi nvme_log_field_valid_lsp(const nvme_field_info_t *field,
52*533affcbSRobert Mustacchi     const nvme_valid_ctrl_data_t *data, uint64_t lsp, char *msg, size_t msglen)
53*533affcbSRobert Mustacchi {
54*533affcbSRobert Mustacchi 	uint64_t max;
55*533affcbSRobert Mustacchi 
56*533affcbSRobert Mustacchi 	if (nvme_field_atleast(data, &nvme_vers_2v0)) {
57*533affcbSRobert Mustacchi 		max = NVME_LOG_MAX_LSP_2v0;
58*533affcbSRobert Mustacchi 	} else {
59*533affcbSRobert Mustacchi 		max = NVME_LOG_MAX_LSP;
60*533affcbSRobert Mustacchi 	}
61*533affcbSRobert Mustacchi 
62*533affcbSRobert Mustacchi 	return (nvme_field_range_check(field, 0, max, msg, msglen, lsp));
63*533affcbSRobert Mustacchi }
64*533affcbSRobert Mustacchi 
65*533affcbSRobert Mustacchi static bool
66*533affcbSRobert Mustacchi nvme_log_field_supported_offset(const nvme_field_info_t *field,
67*533affcbSRobert Mustacchi     const nvme_valid_ctrl_data_t *data, char *msg, size_t msglen)
68*533affcbSRobert Mustacchi {
69*533affcbSRobert Mustacchi 	if (data->vcd_id->id_lpa.lp_extsup != 0) {
70*533affcbSRobert Mustacchi 		return (true);
71*533affcbSRobert Mustacchi 	}
72*533affcbSRobert Mustacchi 
73*533affcbSRobert Mustacchi 	(void) snprintf(msg, msglen, "controller does not support field %s "
74*533affcbSRobert Mustacchi 	    "(%s): missing extended data support in Log Page Attributes (LPA)",
75*533affcbSRobert Mustacchi 	    field->nlfi_human, field->nlfi_spec);
76*533affcbSRobert Mustacchi 	return (false);
77*533affcbSRobert Mustacchi }
78*533affcbSRobert Mustacchi 
79*533affcbSRobert Mustacchi /*
80*533affcbSRobert Mustacchi  * The offset is a full 64-bit byte value; however, it must be 4-byte aligned.
81*533affcbSRobert Mustacchi  */
82*533affcbSRobert Mustacchi static bool
83*533affcbSRobert Mustacchi nvme_log_field_valid_offset(const nvme_field_info_t *field,
84*533affcbSRobert Mustacchi     const nvme_valid_ctrl_data_t *data, uint64_t size, char *msg, size_t msglen)
85*533affcbSRobert Mustacchi {
86*533affcbSRobert Mustacchi 	if ((size % NVME_DWORD_SIZE) != 0) {
87*533affcbSRobert Mustacchi 		(void) snprintf(msg, msglen, "%s (%s) value 0x%" PRIx64 " is "
88*533affcbSRobert Mustacchi 		    "invalid: value must be %u-byte aligned", field->nlfi_human,
89*533affcbSRobert Mustacchi 		    field->nlfi_spec, size, NVME_DWORD_SIZE);
90*533affcbSRobert Mustacchi 		return (false);
91*533affcbSRobert Mustacchi 	}
92*533affcbSRobert Mustacchi 
93*533affcbSRobert Mustacchi 	return (true);
94*533affcbSRobert Mustacchi }
95*533affcbSRobert Mustacchi 
96*533affcbSRobert Mustacchi static bool
97*533affcbSRobert Mustacchi nvme_log_field_valid_size(const nvme_field_info_t *field,
98*533affcbSRobert Mustacchi     const nvme_valid_ctrl_data_t *data, uint64_t size, char *msg, size_t msglen)
99*533affcbSRobert Mustacchi {
100*533affcbSRobert Mustacchi 	uint64_t max = NVME_LOG_MAX_SIZE;
101*533affcbSRobert Mustacchi 
102*533affcbSRobert Mustacchi 	if (nvme_field_atleast(data, &nvme_vers_1v2) &&
103*533affcbSRobert Mustacchi 	    data->vcd_id->id_lpa.lp_extsup != 0) {
104*533affcbSRobert Mustacchi 		max = NVME_LOG_MAX_SIZE_1v2;
105*533affcbSRobert Mustacchi 	}
106*533affcbSRobert Mustacchi 
107*533affcbSRobert Mustacchi 	/*
108*533affcbSRobert Mustacchi 	 * The NVMe specification operates in terms of uint32_t (dword) units.
109*533affcbSRobert Mustacchi 	 * Make sure that we are operating within that constraint.
110*533affcbSRobert Mustacchi 	 */
111*533affcbSRobert Mustacchi 	if ((size % 4) != 0) {
112*533affcbSRobert Mustacchi 		(void) snprintf(msg, msglen, "%s (%s) value 0x%" PRIx64 " is "
113*533affcbSRobert Mustacchi 		    "invalid: value must be 4-byte aligned", field->nlfi_human,
114*533affcbSRobert Mustacchi 		    field->nlfi_spec, size);
115*533affcbSRobert Mustacchi 		return (false);
116*533affcbSRobert Mustacchi 	}
117*533affcbSRobert Mustacchi 
118*533affcbSRobert Mustacchi 	return (nvme_field_range_check(field, 4, max, msg, msglen, size));
119*533affcbSRobert Mustacchi }
120*533affcbSRobert Mustacchi 
121*533affcbSRobert Mustacchi const nvme_field_info_t nvme_log_fields[] = {
122*533affcbSRobert Mustacchi 	[NVME_LOG_REQ_FIELD_LID] = {
123*533affcbSRobert Mustacchi 		.nlfi_vers = &nvme_vers_1v0,
124*533affcbSRobert Mustacchi 		.nlfi_max_size = NVME_LOG_MAX_LID,
125*533affcbSRobert Mustacchi 		.nlfi_spec = "lid",
126*533affcbSRobert Mustacchi 		.nlfi_human = "log ID",
127*533affcbSRobert Mustacchi 		.nlfi_def_req = true,
128*533affcbSRobert Mustacchi 		.nlfi_def_allow = true
129*533affcbSRobert Mustacchi 	},
130*533affcbSRobert Mustacchi 	[NVME_LOG_REQ_FIELD_LSP] = {
131*533affcbSRobert Mustacchi 		.nlfi_vers = &nvme_vers_1v3,
132*533affcbSRobert Mustacchi 		.nlfi_valid = nvme_log_field_valid_lsp,
133*533affcbSRobert Mustacchi 		.nlfi_spec = "lsp",
134*533affcbSRobert Mustacchi 		.nlfi_human = "log specific field",
135*533affcbSRobert Mustacchi 		.nlfi_def_req = false,
136*533affcbSRobert Mustacchi 		.nlfi_def_allow = true
137*533affcbSRobert Mustacchi 	},
138*533affcbSRobert Mustacchi 	[NVME_LOG_REQ_FIELD_LSI] = {
139*533affcbSRobert Mustacchi 		.nlfi_vers = &nvme_vers_1v4,
140*533affcbSRobert Mustacchi 		.nlfi_max_size = NVME_LOG_MAX_LSI,
141*533affcbSRobert Mustacchi 		.nlfi_spec = "lsi",
142*533affcbSRobert Mustacchi 		.nlfi_human = "log specific ID",
143*533affcbSRobert Mustacchi 		.nlfi_def_req = false,
144*533affcbSRobert Mustacchi 		.nlfi_def_allow = true
145*533affcbSRobert Mustacchi 	},
146*533affcbSRobert Mustacchi 	[NVME_LOG_REQ_FIELD_SIZE] = {
147*533affcbSRobert Mustacchi 		.nlfi_vers = &nvme_vers_1v0,
148*533affcbSRobert Mustacchi 		.nlfi_valid = nvme_log_field_valid_size,
149*533affcbSRobert Mustacchi 		.nlfi_spec = "dptr/numd",
150*533affcbSRobert Mustacchi 		.nlfi_human = "output",
151*533affcbSRobert Mustacchi 		.nlfi_def_req = true,
152*533affcbSRobert Mustacchi 		.nlfi_def_allow = true
153*533affcbSRobert Mustacchi 	},
154*533affcbSRobert Mustacchi 	[NVME_LOG_REQ_FIELD_CSI] = {
155*533affcbSRobert Mustacchi 		.nlfi_vers = &nvme_vers_2v0,
156*533affcbSRobert Mustacchi 		/*
157*533affcbSRobert Mustacchi 		 * This has the field's maximum range right now, though NVMe 2.0
158*533affcbSRobert Mustacchi 		 * only defines a few values. Because the kernel only allows
159*533affcbSRobert Mustacchi 		 * through known log pages, we don't really bother to check the
160*533affcbSRobert Mustacchi 		 * condensed range and allow vendor-specific logs to go wild.
161*533affcbSRobert Mustacchi 		 */
162*533affcbSRobert Mustacchi 		.nlfi_max_size = NVME_LOG_MAX_CSI,
163*533affcbSRobert Mustacchi 		.nlfi_spec = "csi",
164*533affcbSRobert Mustacchi 		.nlfi_human = "command set ID",
165*533affcbSRobert Mustacchi 		.nlfi_def_req = false,
166*533affcbSRobert Mustacchi 		.nlfi_def_allow = true
167*533affcbSRobert Mustacchi 	},
168*533affcbSRobert Mustacchi 	[NVME_LOG_REQ_FIELD_RAE] = {
169*533affcbSRobert Mustacchi 		.nlfi_vers = &nvme_vers_1v3,
170*533affcbSRobert Mustacchi 		.nlfi_max_size = NVME_LOG_MAX_RAE,
171*533affcbSRobert Mustacchi 		.nlfi_spec = "rae",
172*533affcbSRobert Mustacchi 		.nlfi_human = "retain asynchronous event",
173*533affcbSRobert Mustacchi 		.nlfi_def_req = false,
174*533affcbSRobert Mustacchi 		.nlfi_def_allow = true
175*533affcbSRobert Mustacchi 	},
176*533affcbSRobert Mustacchi 	[NVME_LOG_REQ_FIELD_OFFSET] = {
177*533affcbSRobert Mustacchi 		.nlfi_vers = &nvme_vers_1v2,
178*533affcbSRobert Mustacchi 		.nlfi_sup = nvme_log_field_supported_offset,
179*533affcbSRobert Mustacchi 		.nlfi_valid = nvme_log_field_valid_offset,
180*533affcbSRobert Mustacchi 		.nlfi_max_size = NVME_LOG_MAX_OFFSET,
181*533affcbSRobert Mustacchi 		.nlfi_spec = "lpo",
182*533affcbSRobert Mustacchi 		.nlfi_human = "log offset",
183*533affcbSRobert Mustacchi 		.nlfi_def_req = false,
184*533affcbSRobert Mustacchi 		.nlfi_def_allow = true
185*533affcbSRobert Mustacchi 	},
186*533affcbSRobert Mustacchi 	[NVME_LOG_REQ_FIELD_NSID] = {
187*533affcbSRobert Mustacchi 		.nlfi_vers = &nvme_vers_1v2,
188*533affcbSRobert Mustacchi 		.nlfi_sup = nvme_field_supported_nsid,
189*533affcbSRobert Mustacchi 		.nlfi_valid = nvme_field_valid_nsid,
190*533affcbSRobert Mustacchi 		.nlfi_spec = "nsid",
191*533affcbSRobert Mustacchi 		.nlfi_human = "namespace ID",
192*533affcbSRobert Mustacchi 		.nlfi_def_req = false,
193*533affcbSRobert Mustacchi 		.nlfi_def_allow = true
194*533affcbSRobert Mustacchi 	}
195*533affcbSRobert Mustacchi };
196*533affcbSRobert Mustacchi 
197*533affcbSRobert Mustacchi size_t nvme_log_nfields = ARRAY_SIZE(nvme_log_fields);
198*533affcbSRobert Mustacchi 
199*533affcbSRobert Mustacchi static uint64_t
200*533affcbSRobert Mustacchi nvme_lpd_error_len(const nvme_valid_ctrl_data_t *data,
201*533affcbSRobert Mustacchi     const nvme_log_page_info_t *lpi)
202*533affcbSRobert Mustacchi {
203*533affcbSRobert Mustacchi 	const uint64_t nents = data->vcd_id->id_elpe + 1;
204*533affcbSRobert Mustacchi 	const uint64_t logsz = nents * sizeof (nvme_error_log_entry_t);
205*533affcbSRobert Mustacchi 
206*533affcbSRobert Mustacchi 	return (logsz);
207*533affcbSRobert Mustacchi }
208*533affcbSRobert Mustacchi 
209*533affcbSRobert Mustacchi static nvme_log_disc_scope_t
210*533affcbSRobert Mustacchi nvme_lpd_health_scope(const nvme_valid_ctrl_data_t *data,
211*533affcbSRobert Mustacchi     const nvme_log_page_info_t *lpi)
212*533affcbSRobert Mustacchi {
213*533affcbSRobert Mustacchi 	nvme_log_disc_scope_t ret = NVME_LOG_SCOPE_CTRL;
214*533affcbSRobert Mustacchi 
215*533affcbSRobert Mustacchi 	if (nvme_field_atleast(data, &nvme_vers_1v0) &&
216*533affcbSRobert Mustacchi 	    data->vcd_id->id_lpa.lp_smart != 0) {
217*533affcbSRobert Mustacchi 		ret |= NVME_LOG_SCOPE_NS;
218*533affcbSRobert Mustacchi 	}
219*533affcbSRobert Mustacchi 
220*533affcbSRobert Mustacchi 	return (ret);
221*533affcbSRobert Mustacchi }
222*533affcbSRobert Mustacchi 
223*533affcbSRobert Mustacchi static bool
224*533affcbSRobert Mustacchi nvme_lpd_changens_sup(const nvme_valid_ctrl_data_t *data,
225*533affcbSRobert Mustacchi     const nvme_log_page_info_t *lpi)
226*533affcbSRobert Mustacchi {
227*533affcbSRobert Mustacchi 	return (nvme_field_atleast(data, &nvme_vers_1v2) &&
228*533affcbSRobert Mustacchi 	    data->vcd_id->id_oaes.oaes_nsan != 0);
229*533affcbSRobert Mustacchi }
230*533affcbSRobert Mustacchi 
231*533affcbSRobert Mustacchi /*
232*533affcbSRobert Mustacchi  * The short names here correspond to the well defined names in nvmeadm(8) and
233*533affcbSRobert Mustacchi  * libnvme(3LIB) that users expect to be able to use. Please do not change them
234*533affcbSRobert Mustacchi  * without accounting for aliases and backwards compatibility.
235*533affcbSRobert Mustacchi  */
236*533affcbSRobert Mustacchi const nvme_log_page_info_t nvme_std_log_pages[] = { {
237*533affcbSRobert Mustacchi 	.nlpi_short = "error",
238*533affcbSRobert Mustacchi 	.nlpi_human = "Error information",
239*533affcbSRobert Mustacchi 	.nlpi_lid = NVME_LOGPAGE_ERROR,
240*533affcbSRobert Mustacchi 	.nlpi_csi = NVME_CSI_NVM,
241*533affcbSRobert Mustacchi 	.nlpi_vers = &nvme_vers_1v0,
242*533affcbSRobert Mustacchi 	.nlpi_kind = NVME_LOG_ID_MANDATORY,
243*533affcbSRobert Mustacchi 	.nlpi_source = NVME_LOG_DISC_S_SPEC,
244*533affcbSRobert Mustacchi 	.nlpi_disc = NVME_LOG_DISC_F_NEED_RAE,
245*533affcbSRobert Mustacchi 	.nlpi_scope = NVME_LOG_SCOPE_CTRL,
246*533affcbSRobert Mustacchi 	.nlpi_len_func = nvme_lpd_error_len
247*533affcbSRobert Mustacchi }, {
248*533affcbSRobert Mustacchi 	.nlpi_short = "health",
249*533affcbSRobert Mustacchi 	.nlpi_human = "SMART / Health information",
250*533affcbSRobert Mustacchi 	.nlpi_lid = NVME_LOGPAGE_HEALTH,
251*533affcbSRobert Mustacchi 	.nlpi_csi = NVME_CSI_NVM,
252*533affcbSRobert Mustacchi 	.nlpi_vers = &nvme_vers_1v0,
253*533affcbSRobert Mustacchi 	.nlpi_kind = NVME_LOG_ID_MANDATORY,
254*533affcbSRobert Mustacchi 	.nlpi_source = NVME_LOG_DISC_S_SPEC | NVME_LOG_DISC_S_ID_CTRL,
255*533affcbSRobert Mustacchi 	.nlpi_disc = NVME_LOG_DISC_F_NEED_RAE,
256*533affcbSRobert Mustacchi 	.nlpi_scope_func = nvme_lpd_health_scope,
257*533affcbSRobert Mustacchi 	.nlpi_len = sizeof (nvme_health_log_t)
258*533affcbSRobert Mustacchi }, {
259*533affcbSRobert Mustacchi 	.nlpi_short = "firmware",
260*533affcbSRobert Mustacchi 	.nlpi_human = "Firmware Slot Information",
261*533affcbSRobert Mustacchi 	.nlpi_lid = NVME_LOGPAGE_FWSLOT,
262*533affcbSRobert Mustacchi 	.nlpi_csi = NVME_CSI_NVM,
263*533affcbSRobert Mustacchi 	.nlpi_vers = &nvme_vers_1v0,
264*533affcbSRobert Mustacchi 	.nlpi_kind = NVME_LOG_ID_MANDATORY,
265*533affcbSRobert Mustacchi 	.nlpi_source = NVME_LOG_DISC_S_SPEC,
266*533affcbSRobert Mustacchi 	.nlpi_disc = 0,
267*533affcbSRobert Mustacchi 	.nlpi_scope = NVME_LOG_SCOPE_NVM,
268*533affcbSRobert Mustacchi 	.nlpi_len = sizeof (nvme_fwslot_log_t),
269*533affcbSRobert Mustacchi }, {
270*533affcbSRobert Mustacchi 	.nlpi_short = "changens",
271*533affcbSRobert Mustacchi 	.nlpi_human = "changed namespaces",
272*533affcbSRobert Mustacchi 	.nlpi_lid = NVME_LOGPAGE_NSCHANGE,
273*533affcbSRobert Mustacchi 	.nlpi_csi = NVME_CSI_NVM,
274*533affcbSRobert Mustacchi 	.nlpi_vers = &nvme_vers_1v2,
275*533affcbSRobert Mustacchi 	.nlpi_sup_func = nvme_lpd_changens_sup,
276*533affcbSRobert Mustacchi 	.nlpi_kind = NVME_LOG_ID_OPTIONAL,
277*533affcbSRobert Mustacchi 	.nlpi_source = NVME_LOG_DISC_S_ID_CTRL,
278*533affcbSRobert Mustacchi 	.nlpi_disc = NVME_LOG_DISC_F_NEED_RAE,
279*533affcbSRobert Mustacchi 	.nlpi_scope = NVME_LOG_SCOPE_CTRL,
280*533affcbSRobert Mustacchi 	.nlpi_len = sizeof (nvme_nschange_list_t)
281*533affcbSRobert Mustacchi } };
282*533affcbSRobert Mustacchi 
283*533affcbSRobert Mustacchi size_t nvme_std_log_npages = ARRAY_SIZE(nvme_std_log_pages);
284*533affcbSRobert Mustacchi 
285*533affcbSRobert Mustacchi nvme_log_disc_scope_t
286*533affcbSRobert Mustacchi nvme_log_page_info_scope(const nvme_log_page_info_t *info,
287*533affcbSRobert Mustacchi     const nvme_valid_ctrl_data_t *data)
288*533affcbSRobert Mustacchi {
289*533affcbSRobert Mustacchi 	if (info->nlpi_scope_func != NULL) {
290*533affcbSRobert Mustacchi 		return (info->nlpi_scope_func(data, info));
291*533affcbSRobert Mustacchi 	} else {
292*533affcbSRobert Mustacchi 		return (info->nlpi_scope);
293*533affcbSRobert Mustacchi 	}
294*533affcbSRobert Mustacchi }
295*533affcbSRobert Mustacchi 
296*533affcbSRobert Mustacchi uint64_t
297*533affcbSRobert Mustacchi nvme_log_page_info_size(const nvme_log_page_info_t *info,
298*533affcbSRobert Mustacchi     const nvme_valid_ctrl_data_t *data, bool *var)
299*533affcbSRobert Mustacchi {
300*533affcbSRobert Mustacchi 	*var = info->nlpi_var_func != NULL;
301*533affcbSRobert Mustacchi 
302*533affcbSRobert Mustacchi 	if (info->nlpi_len_func != NULL) {
303*533affcbSRobert Mustacchi 		return (info->nlpi_len_func(data, info));
304*533affcbSRobert Mustacchi 	} else {
305*533affcbSRobert Mustacchi 		return (info->nlpi_len);
306*533affcbSRobert Mustacchi 	}
307*533affcbSRobert Mustacchi }
308*533affcbSRobert Mustacchi 
309*533affcbSRobert Mustacchi bool
310*533affcbSRobert Mustacchi nvme_log_page_info_supported(const nvme_log_page_info_t *info,
311*533affcbSRobert Mustacchi     const nvme_valid_ctrl_data_t *data)
312*533affcbSRobert Mustacchi {
313*533affcbSRobert Mustacchi 	bool vers, sup_func;
314*533affcbSRobert Mustacchi 
315*533affcbSRobert Mustacchi 	if (info->nlpi_vers != NULL) {
316*533affcbSRobert Mustacchi 		vers = nvme_field_atleast(data, info->nlpi_vers);
317*533affcbSRobert Mustacchi 	} else {
318*533affcbSRobert Mustacchi 		vers = true;
319*533affcbSRobert Mustacchi 	}
320*533affcbSRobert Mustacchi 
321*533affcbSRobert Mustacchi 	if (info->nlpi_sup_func != NULL) {
322*533affcbSRobert Mustacchi 		sup_func = info->nlpi_sup_func(data, info);
323*533affcbSRobert Mustacchi 	} else {
324*533affcbSRobert Mustacchi 		sup_func = true;
325*533affcbSRobert Mustacchi 	}
326*533affcbSRobert Mustacchi 
327*533affcbSRobert Mustacchi 	return (vers && sup_func);
328*533affcbSRobert Mustacchi }
329