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  * Manage NVMe feature detection and feature queries.
18*533affcbSRobert Mustacchi  */
19*533affcbSRobert Mustacchi 
20*533affcbSRobert Mustacchi #include <stdlib.h>
21*533affcbSRobert Mustacchi #include <string.h>
22*533affcbSRobert Mustacchi #include <unistd.h>
23*533affcbSRobert Mustacchi 
24*533affcbSRobert Mustacchi #include "libnvme_impl.h"
25*533affcbSRobert Mustacchi 
26*533affcbSRobert Mustacchi const char *
nvme_feat_disc_short(const nvme_feat_disc_t * disc)27*533affcbSRobert Mustacchi nvme_feat_disc_short(const nvme_feat_disc_t *disc)
28*533affcbSRobert Mustacchi {
29*533affcbSRobert Mustacchi 	return (disc->nfd_short);
30*533affcbSRobert Mustacchi }
31*533affcbSRobert Mustacchi 
32*533affcbSRobert Mustacchi const char *
nvme_feat_disc_spec(const nvme_feat_disc_t * disc)33*533affcbSRobert Mustacchi nvme_feat_disc_spec(const nvme_feat_disc_t *disc)
34*533affcbSRobert Mustacchi {
35*533affcbSRobert Mustacchi 	return (disc->nfd_spec);
36*533affcbSRobert Mustacchi }
37*533affcbSRobert Mustacchi 
38*533affcbSRobert Mustacchi uint32_t
nvme_feat_disc_fid(const nvme_feat_disc_t * disc)39*533affcbSRobert Mustacchi nvme_feat_disc_fid(const nvme_feat_disc_t *disc)
40*533affcbSRobert Mustacchi {
41*533affcbSRobert Mustacchi 	return (disc->nfd_fid);
42*533affcbSRobert Mustacchi }
43*533affcbSRobert Mustacchi 
44*533affcbSRobert Mustacchi nvme_feat_scope_t
nvme_feat_disc_scope(const nvme_feat_disc_t * disc)45*533affcbSRobert Mustacchi nvme_feat_disc_scope(const nvme_feat_disc_t *disc)
46*533affcbSRobert Mustacchi {
47*533affcbSRobert Mustacchi 	return (disc->nfd_scope);
48*533affcbSRobert Mustacchi }
49*533affcbSRobert Mustacchi 
50*533affcbSRobert Mustacchi nvme_feat_kind_t
nvme_feat_disc_kind(const nvme_feat_disc_t * disc)51*533affcbSRobert Mustacchi nvme_feat_disc_kind(const nvme_feat_disc_t *disc)
52*533affcbSRobert Mustacchi {
53*533affcbSRobert Mustacchi 	return (disc->nfd_kind);
54*533affcbSRobert Mustacchi }
55*533affcbSRobert Mustacchi 
56*533affcbSRobert Mustacchi nvme_feat_csi_t
nvme_feat_disc_csi(const nvme_feat_disc_t * disc)57*533affcbSRobert Mustacchi nvme_feat_disc_csi(const nvme_feat_disc_t *disc)
58*533affcbSRobert Mustacchi {
59*533affcbSRobert Mustacchi 	return (disc->nfd_csi);
60*533affcbSRobert Mustacchi }
61*533affcbSRobert Mustacchi 
62*533affcbSRobert Mustacchi nvme_feat_flags_t
nvme_feat_disc_flags(const nvme_feat_disc_t * disc)63*533affcbSRobert Mustacchi nvme_feat_disc_flags(const nvme_feat_disc_t *disc)
64*533affcbSRobert Mustacchi {
65*533affcbSRobert Mustacchi 	return (disc->nfd_flags);
66*533affcbSRobert Mustacchi }
67*533affcbSRobert Mustacchi 
68*533affcbSRobert Mustacchi nvme_get_feat_fields_t
nvme_feat_disc_fields_get(const nvme_feat_disc_t * disc)69*533affcbSRobert Mustacchi nvme_feat_disc_fields_get(const nvme_feat_disc_t *disc)
70*533affcbSRobert Mustacchi {
71*533affcbSRobert Mustacchi 	return (disc->nfd_in_get);
72*533affcbSRobert Mustacchi }
73*533affcbSRobert Mustacchi 
74*533affcbSRobert Mustacchi nvme_set_feat_fields_t
nvme_feat_disc_fields_set(const nvme_feat_disc_t * disc)75*533affcbSRobert Mustacchi nvme_feat_disc_fields_set(const nvme_feat_disc_t *disc)
76*533affcbSRobert Mustacchi {
77*533affcbSRobert Mustacchi 	return (disc->nfd_in_set);
78*533affcbSRobert Mustacchi }
79*533affcbSRobert Mustacchi 
80*533affcbSRobert Mustacchi nvme_feat_output_t
nvme_feat_disc_output_get(const nvme_feat_disc_t * disc)81*533affcbSRobert Mustacchi nvme_feat_disc_output_get(const nvme_feat_disc_t *disc)
82*533affcbSRobert Mustacchi {
83*533affcbSRobert Mustacchi 	return (disc->nfd_out_get);
84*533affcbSRobert Mustacchi }
85*533affcbSRobert Mustacchi 
86*533affcbSRobert Mustacchi nvme_feat_output_t
nvme_feat_disc_output_set(const nvme_feat_disc_t * disc)87*533affcbSRobert Mustacchi nvme_feat_disc_output_set(const nvme_feat_disc_t *disc)
88*533affcbSRobert Mustacchi {
89*533affcbSRobert Mustacchi 	return (disc->nfd_out_set);
90*533affcbSRobert Mustacchi }
91*533affcbSRobert Mustacchi 
92*533affcbSRobert Mustacchi uint64_t
nvme_feat_disc_data_size(const nvme_feat_disc_t * disc)93*533affcbSRobert Mustacchi nvme_feat_disc_data_size(const nvme_feat_disc_t *disc)
94*533affcbSRobert Mustacchi {
95*533affcbSRobert Mustacchi 	return (disc->nfd_len);
96*533affcbSRobert Mustacchi }
97*533affcbSRobert Mustacchi 
98*533affcbSRobert Mustacchi static bool
nvme_feat_discover_validate(nvme_ctrl_t * ctrl,nvme_feat_scope_t scopes,uint32_t flags)99*533affcbSRobert Mustacchi nvme_feat_discover_validate(nvme_ctrl_t *ctrl, nvme_feat_scope_t scopes,
100*533affcbSRobert Mustacchi     uint32_t flags)
101*533affcbSRobert Mustacchi {
102*533affcbSRobert Mustacchi 	const nvme_feat_scope_t valid_scopes = NVME_FEAT_SCOPE_CTRL |
103*533affcbSRobert Mustacchi 	    NVME_FEAT_SCOPE_NS;
104*533affcbSRobert Mustacchi 
105*533affcbSRobert Mustacchi 	/*
106*533affcbSRobert Mustacchi 	 * See the note in nvme_log_discover_validate() on why we don't support
107*533affcbSRobert Mustacchi 	 * a zeroed scope.
108*533affcbSRobert Mustacchi 	 */
109*533affcbSRobert Mustacchi 	if (scopes == 0) {
110*533affcbSRobert Mustacchi 		return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_FLAG, 0,  "no "
111*533affcbSRobert Mustacchi 		    "feature scope specified (given 0), a scope must be "
112*533affcbSRobert Mustacchi 		    "requested"));
113*533affcbSRobert Mustacchi 	}
114*533affcbSRobert Mustacchi 
115*533affcbSRobert Mustacchi 	if ((scopes & ~valid_scopes) != 0) {
116*533affcbSRobert Mustacchi 		return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_FLAG, 0,
117*533affcbSRobert Mustacchi 		    "encountered invalid scope for the nvme_feat_disc_scope_t: "
118*533affcbSRobert Mustacchi 		    "0x%x", scopes & ~valid_scopes));
119*533affcbSRobert Mustacchi 	}
120*533affcbSRobert Mustacchi 
121*533affcbSRobert Mustacchi 	/*
122*533affcbSRobert Mustacchi 	 * The flags are meant for future expansion here, hence the all zero
123*533affcbSRobert Mustacchi 	 * requirement.
124*533affcbSRobert Mustacchi 	 */
125*533affcbSRobert Mustacchi 	if (flags != 0) {
126*533affcbSRobert Mustacchi 		return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_FLAG, 0,
127*533affcbSRobert Mustacchi 		    "encountered invalid feature discovery flags: 0x%x",
128*533affcbSRobert Mustacchi 		    flags));
129*533affcbSRobert Mustacchi 	}
130*533affcbSRobert Mustacchi 
131*533affcbSRobert Mustacchi 	return (true);
132*533affcbSRobert Mustacchi }
133*533affcbSRobert Mustacchi 
134*533affcbSRobert Mustacchi nvme_feat_impl_t
nvme_feat_disc_impl(const nvme_feat_disc_t * disc)135*533affcbSRobert Mustacchi nvme_feat_disc_impl(const nvme_feat_disc_t *disc)
136*533affcbSRobert Mustacchi {
137*533affcbSRobert Mustacchi 	return (disc->nfd_impl);
138*533affcbSRobert Mustacchi }
139*533affcbSRobert Mustacchi 
140*533affcbSRobert Mustacchi void
nvme_feat_disc_free(nvme_feat_disc_t * disc)141*533affcbSRobert Mustacchi nvme_feat_disc_free(nvme_feat_disc_t *disc)
142*533affcbSRobert Mustacchi {
143*533affcbSRobert Mustacchi 	free(disc);
144*533affcbSRobert Mustacchi }
145*533affcbSRobert Mustacchi 
146*533affcbSRobert Mustacchi bool
nvme_feat_disc_dup(nvme_ctrl_t * ctrl,const nvme_feat_disc_t * src,nvme_feat_disc_t ** discp)147*533affcbSRobert Mustacchi nvme_feat_disc_dup(nvme_ctrl_t *ctrl, const nvme_feat_disc_t *src,
148*533affcbSRobert Mustacchi     nvme_feat_disc_t **discp)
149*533affcbSRobert Mustacchi {
150*533affcbSRobert Mustacchi 	nvme_feat_disc_t *disc;
151*533affcbSRobert Mustacchi 
152*533affcbSRobert Mustacchi 	if (src == NULL) {
153*533affcbSRobert Mustacchi 		return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
154*533affcbSRobert Mustacchi 		    "encountered invalid nvme_feat_disc_t pointer to "
155*533affcbSRobert Mustacchi 		    "duplicate: %p", src));
156*533affcbSRobert Mustacchi 	}
157*533affcbSRobert Mustacchi 
158*533affcbSRobert Mustacchi 	if (discp == NULL) {
159*533affcbSRobert Mustacchi 		return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
160*533affcbSRobert Mustacchi 		    "encountered invalid nvme_feat_disc_t output pointer: %p",
161*533affcbSRobert Mustacchi 		    discp));
162*533affcbSRobert Mustacchi 	}
163*533affcbSRobert Mustacchi 
164*533affcbSRobert Mustacchi 	disc = calloc(1, sizeof (nvme_feat_disc_t));
165*533affcbSRobert Mustacchi 	if (disc == NULL) {
166*533affcbSRobert Mustacchi 		int e = errno;
167*533affcbSRobert Mustacchi 		return (nvme_ctrl_error(ctrl, NVME_ERR_NO_MEM, e, "failed to "
168*533affcbSRobert Mustacchi 		    "allocate memory for a new nvme_feat_disc_t: %s",
169*533affcbSRobert Mustacchi 		    strerror(e)));
170*533affcbSRobert Mustacchi 	}
171*533affcbSRobert Mustacchi 
172*533affcbSRobert Mustacchi 	(void) memcpy(disc, src, sizeof (nvme_feat_disc_t));
173*533affcbSRobert Mustacchi 	*discp = disc;
174*533affcbSRobert Mustacchi 	return (nvme_ctrl_success(ctrl));
175*533affcbSRobert Mustacchi }
176*533affcbSRobert Mustacchi 
177*533affcbSRobert Mustacchi void
nvme_feat_discover_fini(nvme_feat_iter_t * iter)178*533affcbSRobert Mustacchi nvme_feat_discover_fini(nvme_feat_iter_t *iter)
179*533affcbSRobert Mustacchi {
180*533affcbSRobert Mustacchi 	free(iter);
181*533affcbSRobert Mustacchi }
182*533affcbSRobert Mustacchi 
183*533affcbSRobert Mustacchi static bool
nvme_feat_discover_one(nvme_feat_iter_t * iter,const nvme_feat_info_t * info)184*533affcbSRobert Mustacchi nvme_feat_discover_one(nvme_feat_iter_t *iter, const nvme_feat_info_t *info)
185*533affcbSRobert Mustacchi {
186*533affcbSRobert Mustacchi 	nvme_feat_disc_t *disc = &iter->nfi_disc;
187*533affcbSRobert Mustacchi 	nvme_valid_ctrl_data_t data;
188*533affcbSRobert Mustacchi 
189*533affcbSRobert Mustacchi 	data.vcd_vers = &iter->nfi_ctrl->nc_vers;
190*533affcbSRobert Mustacchi 	data.vcd_id = &iter->nfi_ctrl->nc_info;
191*533affcbSRobert Mustacchi 
192*533affcbSRobert Mustacchi 	/*
193*533affcbSRobert Mustacchi 	 * The user is not interested in this feature. Do not include it.
194*533affcbSRobert Mustacchi 	 */
195*533affcbSRobert Mustacchi 	if ((iter->nfi_scope & info->nfeat_scope) == 0) {
196*533affcbSRobert Mustacchi 		return (false);
197*533affcbSRobert Mustacchi 	}
198*533affcbSRobert Mustacchi 
199*533affcbSRobert Mustacchi 	(void) memset(disc, 0, sizeof (nvme_feat_disc_t));
200*533affcbSRobert Mustacchi 
201*533affcbSRobert Mustacchi 	disc->nfd_short = info->nfeat_short;
202*533affcbSRobert Mustacchi 	disc->nfd_spec = info->nfeat_spec;
203*533affcbSRobert Mustacchi 	disc->nfd_fid = info->nfeat_fid;
204*533affcbSRobert Mustacchi 	disc->nfd_kind = info->nfeat_kind;
205*533affcbSRobert Mustacchi 	disc->nfd_scope = info->nfeat_scope;
206*533affcbSRobert Mustacchi 	disc->nfd_flags = info->nfeat_flags;
207*533affcbSRobert Mustacchi 	disc->nfd_csi = info->nfeat_csi;
208*533affcbSRobert Mustacchi 	disc->nfd_in_get = info->nfeat_in_get;
209*533affcbSRobert Mustacchi 	disc->nfd_in_set = info->nfeat_in_set;
210*533affcbSRobert Mustacchi 	disc->nfd_out_get = info->nfeat_out_get;
211*533affcbSRobert Mustacchi 	disc->nfd_out_set = info->nfeat_out_set;
212*533affcbSRobert Mustacchi 	disc->nfd_len = info->nfeat_len;
213*533affcbSRobert Mustacchi 	disc->nfd_impl = nvme_feat_supported(info, &data);
214*533affcbSRobert Mustacchi 
215*533affcbSRobert Mustacchi 	return (true);
216*533affcbSRobert Mustacchi }
217*533affcbSRobert Mustacchi 
218*533affcbSRobert Mustacchi nvme_iter_t
nvme_feat_discover_step(nvme_feat_iter_t * iter,const nvme_feat_disc_t ** outp)219*533affcbSRobert Mustacchi nvme_feat_discover_step(nvme_feat_iter_t *iter, const nvme_feat_disc_t **outp)
220*533affcbSRobert Mustacchi {
221*533affcbSRobert Mustacchi 	*outp = NULL;
222*533affcbSRobert Mustacchi 
223*533affcbSRobert Mustacchi 	if (iter->nfi_cur_idx == nvme_std_nfeats) {
224*533affcbSRobert Mustacchi 		return (NVME_ITER_DONE);
225*533affcbSRobert Mustacchi 	}
226*533affcbSRobert Mustacchi 
227*533affcbSRobert Mustacchi 	while (iter->nfi_cur_idx < nvme_std_nfeats) {
228*533affcbSRobert Mustacchi 		const nvme_feat_info_t *feat =
229*533affcbSRobert Mustacchi 		    &nvme_std_feats[iter->nfi_cur_idx];
230*533affcbSRobert Mustacchi 		iter->nfi_cur_idx++;
231*533affcbSRobert Mustacchi 
232*533affcbSRobert Mustacchi 		if (nvme_feat_discover_one(iter, feat)) {
233*533affcbSRobert Mustacchi 			*outp = &iter->nfi_disc;
234*533affcbSRobert Mustacchi 			return (NVME_ITER_VALID);
235*533affcbSRobert Mustacchi 		}
236*533affcbSRobert Mustacchi 	}
237*533affcbSRobert Mustacchi 
238*533affcbSRobert Mustacchi 	/*
239*533affcbSRobert Mustacchi 	 * When we add support for vendor-specific features, then we will want
240*533affcbSRobert Mustacchi 	 * to check NVME_LOG_DISC_F_NO_DB here and if it is not set, proceed to
241*533affcbSRobert Mustacchi 	 * move past the standard features onto the vendor-specific features
242*533affcbSRobert Mustacchi 	 * like we do in the log page work right now.
243*533affcbSRobert Mustacchi 	 */
244*533affcbSRobert Mustacchi 	ASSERT3U(iter->nfi_cur_idx, ==, nvme_std_nfeats);
245*533affcbSRobert Mustacchi 	return (NVME_ITER_DONE);
246*533affcbSRobert Mustacchi }
247*533affcbSRobert Mustacchi 
248*533affcbSRobert Mustacchi bool
nvme_feat_discover_init(nvme_ctrl_t * ctrl,nvme_feat_scope_t scope,uint32_t flags,nvme_feat_iter_t ** iterp)249*533affcbSRobert Mustacchi nvme_feat_discover_init(nvme_ctrl_t *ctrl, nvme_feat_scope_t scope,
250*533affcbSRobert Mustacchi     uint32_t flags, nvme_feat_iter_t **iterp)
251*533affcbSRobert Mustacchi {
252*533affcbSRobert Mustacchi 	nvme_feat_iter_t *iter;
253*533affcbSRobert Mustacchi 
254*533affcbSRobert Mustacchi 	if (!nvme_feat_discover_validate(ctrl, scope, flags)) {
255*533affcbSRobert Mustacchi 		return (false);
256*533affcbSRobert Mustacchi 	}
257*533affcbSRobert Mustacchi 
258*533affcbSRobert Mustacchi 	if (iterp == NULL) {
259*533affcbSRobert Mustacchi 		return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
260*533affcbSRobert Mustacchi 		    "encountered invalid nvme_feat_iter_t output pointer: %p",
261*533affcbSRobert Mustacchi 		    iterp));
262*533affcbSRobert Mustacchi 	}
263*533affcbSRobert Mustacchi 
264*533affcbSRobert Mustacchi 	iter = calloc(1, sizeof (nvme_feat_iter_t));
265*533affcbSRobert Mustacchi 	if (iter == NULL) {
266*533affcbSRobert Mustacchi 		int e = errno;
267*533affcbSRobert Mustacchi 		return (nvme_ctrl_error(ctrl, NVME_ERR_NO_MEM, e, "failed to "
268*533affcbSRobert Mustacchi 		    "allocate memory for a new nvme_feat_iter_t: %s",
269*533affcbSRobert Mustacchi 		    strerror(e)));
270*533affcbSRobert Mustacchi 	}
271*533affcbSRobert Mustacchi 
272*533affcbSRobert Mustacchi 	iter->nfi_ctrl = ctrl;
273*533affcbSRobert Mustacchi 	iter->nfi_scope = scope;
274*533affcbSRobert Mustacchi 
275*533affcbSRobert Mustacchi 	*iterp = iter;
276*533affcbSRobert Mustacchi 	return (nvme_ctrl_success(ctrl));
277*533affcbSRobert Mustacchi }
278*533affcbSRobert Mustacchi 
279*533affcbSRobert Mustacchi bool
nvme_feat_discover(nvme_ctrl_t * ctrl,nvme_feat_scope_t scope,uint32_t flags,nvme_feat_disc_f func,void * arg)280*533affcbSRobert Mustacchi nvme_feat_discover(nvme_ctrl_t *ctrl, nvme_feat_scope_t scope, uint32_t flags,
281*533affcbSRobert Mustacchi     nvme_feat_disc_f func, void *arg)
282*533affcbSRobert Mustacchi {
283*533affcbSRobert Mustacchi 	nvme_feat_iter_t *iter;
284*533affcbSRobert Mustacchi 	nvme_iter_t ret;
285*533affcbSRobert Mustacchi 	const nvme_feat_disc_t *disc;
286*533affcbSRobert Mustacchi 
287*533affcbSRobert Mustacchi 
288*533affcbSRobert Mustacchi 	if (func == NULL) {
289*533affcbSRobert Mustacchi 		return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
290*533affcbSRobert Mustacchi 		    "encountered invalid nvme_feat_disc_f function pointer: %p",
291*533affcbSRobert Mustacchi 		    func));
292*533affcbSRobert Mustacchi 	}
293*533affcbSRobert Mustacchi 
294*533affcbSRobert Mustacchi 	if (!nvme_feat_discover_init(ctrl, scope, flags, &iter)) {
295*533affcbSRobert Mustacchi 		return (false);
296*533affcbSRobert Mustacchi 	}
297*533affcbSRobert Mustacchi 
298*533affcbSRobert Mustacchi 	while ((ret = nvme_feat_discover_step(iter, &disc)) ==
299*533affcbSRobert Mustacchi 	    NVME_ITER_VALID) {
300*533affcbSRobert Mustacchi 		if (!func(ctrl, disc, arg))
301*533affcbSRobert Mustacchi 			break;
302*533affcbSRobert Mustacchi 	}
303*533affcbSRobert Mustacchi 
304*533affcbSRobert Mustacchi 	nvme_feat_discover_fini(iter);
305*533affcbSRobert Mustacchi 	if (ret == NVME_ITER_ERROR) {
306*533affcbSRobert Mustacchi 		return (false);
307*533affcbSRobert Mustacchi 	}
308*533affcbSRobert Mustacchi 
309*533affcbSRobert Mustacchi 	return (nvme_ctrl_success(ctrl));
310*533affcbSRobert Mustacchi }
311*533affcbSRobert Mustacchi 
312*533affcbSRobert Mustacchi void
nvme_get_feat_req_fini(nvme_get_feat_req_t * req)313*533affcbSRobert Mustacchi nvme_get_feat_req_fini(nvme_get_feat_req_t *req)
314*533affcbSRobert Mustacchi {
315*533affcbSRobert Mustacchi 	free(req);
316*533affcbSRobert Mustacchi }
317*533affcbSRobert Mustacchi 
318*533affcbSRobert Mustacchi /*
319*533affcbSRobert Mustacchi  * This instantiates a simple get features request that allows most fields to be
320*533affcbSRobert Mustacchi  * specified.
321*533affcbSRobert Mustacchi  */
322*533affcbSRobert Mustacchi bool
nvme_get_feat_req_init(nvme_ctrl_t * ctrl,nvme_get_feat_req_t ** reqp)323*533affcbSRobert Mustacchi nvme_get_feat_req_init(nvme_ctrl_t *ctrl, nvme_get_feat_req_t **reqp)
324*533affcbSRobert Mustacchi {
325*533affcbSRobert Mustacchi 	nvme_get_feat_req_t *req;
326*533affcbSRobert Mustacchi 
327*533affcbSRobert Mustacchi 	if (reqp == NULL) {
328*533affcbSRobert Mustacchi 		return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
329*533affcbSRobert Mustacchi 		    "encountered invalid nvme_get_feat_req_t output pointer: "
330*533affcbSRobert Mustacchi 		    "%p", reqp));
331*533affcbSRobert Mustacchi 	}
332*533affcbSRobert Mustacchi 
333*533affcbSRobert Mustacchi 	req = calloc(1, sizeof (nvme_get_feat_req_t));
334*533affcbSRobert Mustacchi 	if (req == NULL) {
335*533affcbSRobert Mustacchi 		int e = errno;
336*533affcbSRobert Mustacchi 		return (nvme_ctrl_error(ctrl, NVME_ERR_NO_MEM, e, "failed to "
337*533affcbSRobert Mustacchi 		    "allocate memory for a new nvme_get_feat_req_t: %s",
338*533affcbSRobert Mustacchi 		    strerror(e)));
339*533affcbSRobert Mustacchi 	}
340*533affcbSRobert Mustacchi 
341*533affcbSRobert Mustacchi 	req->gfr_ctrl = ctrl;
342*533affcbSRobert Mustacchi 	for (size_t i = 0; i < nvme_get_feat_nfields; i++) {
343*533affcbSRobert Mustacchi 		if (nvme_get_feat_fields[i].nlfi_def_req) {
344*533affcbSRobert Mustacchi 			req->gfr_need |= 1 << i;
345*533affcbSRobert Mustacchi 		}
346*533affcbSRobert Mustacchi 
347*533affcbSRobert Mustacchi 		if (nvme_get_feat_fields[i].nlfi_def_allow) {
348*533affcbSRobert Mustacchi 			req->gfr_allow |= 1 << i;
349*533affcbSRobert Mustacchi 		}
350*533affcbSRobert Mustacchi 	}
351*533affcbSRobert Mustacchi 
352*533affcbSRobert Mustacchi 	/*
353*533affcbSRobert Mustacchi 	 * For a generic get feature request, we don't know if this is true or
354*533affcbSRobert Mustacchi 	 * not. Even though none of the features the kernel supports at this
355*533affcbSRobert Mustacchi 	 * moment support this, we still want to enable this for the future for
356*533affcbSRobert Mustacchi 	 * when they do. The kernel will enforce this.
357*533affcbSRobert Mustacchi 	 */
358*533affcbSRobert Mustacchi 	req->gfr_flags = NVME_FEAT_F_GET_BCAST_NSID;
359*533affcbSRobert Mustacchi 
360*533affcbSRobert Mustacchi 	*reqp = req;
361*533affcbSRobert Mustacchi 	return (nvme_ctrl_success(ctrl));
362*533affcbSRobert Mustacchi }
363*533affcbSRobert Mustacchi 
364*533affcbSRobert Mustacchi bool
nvme_get_feat_req_init_by_disc(nvme_ctrl_t * ctrl,const nvme_feat_disc_t * disc,nvme_get_feat_req_t ** reqp)365*533affcbSRobert Mustacchi nvme_get_feat_req_init_by_disc(nvme_ctrl_t *ctrl, const nvme_feat_disc_t *disc,
366*533affcbSRobert Mustacchi     nvme_get_feat_req_t **reqp)
367*533affcbSRobert Mustacchi {
368*533affcbSRobert Mustacchi 	nvme_get_feat_req_t *req;
369*533affcbSRobert Mustacchi 
370*533affcbSRobert Mustacchi 	if (disc == NULL) {
371*533affcbSRobert Mustacchi 		return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
372*533affcbSRobert Mustacchi 		    "encountered invalid nvme_feat_disc_t pointer: %p", disc));
373*533affcbSRobert Mustacchi 	}
374*533affcbSRobert Mustacchi 
375*533affcbSRobert Mustacchi 	if (reqp == NULL) {
376*533affcbSRobert Mustacchi 		return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
377*533affcbSRobert Mustacchi 		    "encountered invalid nvme_get_feat_req_t output pointer: "
378*533affcbSRobert Mustacchi 		    "%p", reqp));
379*533affcbSRobert Mustacchi 	}
380*533affcbSRobert Mustacchi 
381*533affcbSRobert Mustacchi 	if (disc->nfd_impl == NVME_FEAT_IMPL_UNSUPPORTED) {
382*533affcbSRobert Mustacchi 		return (nvme_ctrl_error(ctrl, NVME_ERR_FEAT_UNSUP_BY_DEV, 0,
383*533affcbSRobert Mustacchi 		    "cannot create get feature request for feature %s "
384*533affcbSRobert Mustacchi 		    "(FID 0x%x) because it is not supported by the device",
385*533affcbSRobert Mustacchi 		    disc->nfd_short, disc->nfd_fid));
386*533affcbSRobert Mustacchi 
387*533affcbSRobert Mustacchi 	}
388*533affcbSRobert Mustacchi 
389*533affcbSRobert Mustacchi 	req = calloc(1, sizeof (nvme_get_feat_req_t));
390*533affcbSRobert Mustacchi 	if (req == NULL) {
391*533affcbSRobert Mustacchi 		int e = errno;
392*533affcbSRobert Mustacchi 		return (nvme_ctrl_error(ctrl, NVME_ERR_NO_MEM, e, "failed to "
393*533affcbSRobert Mustacchi 		    "allocate memory for a new nvme_get_feat_req_t: %s",
394*533affcbSRobert Mustacchi 		    strerror(e)));
395*533affcbSRobert Mustacchi 	}
396*533affcbSRobert Mustacchi 
397*533affcbSRobert Mustacchi 	req->gfr_ctrl = ctrl;
398*533affcbSRobert Mustacchi 
399*533affcbSRobert Mustacchi 	/*
400*533affcbSRobert Mustacchi 	 * Unlike the more generic get feature initialization, we only allow
401*533affcbSRobert Mustacchi 	 * items to be set if they're actually required. We do not require a
402*533affcbSRobert Mustacchi 	 * selector to be set and will default to just getting the current
403*533affcbSRobert Mustacchi 	 * value. Otherwise every other field that is settable is required. We
404*533affcbSRobert Mustacchi 	 * don't let someone change the fid on us, because that would be quite
405*533affcbSRobert Mustacchi 	 * confusing.
406*533affcbSRobert Mustacchi 	 */
407*533affcbSRobert Mustacchi 	req->gfr_fid = disc->nfd_fid;
408*533affcbSRobert Mustacchi 	req->gfr_flags = disc->nfd_flags;
409*533affcbSRobert Mustacchi 	req->gfr_targ_len = disc->nfd_len;
410*533affcbSRobert Mustacchi 	req->gfr_allow |= 1 << NVME_GET_FEAT_REQ_FIELD_SEL;
411*533affcbSRobert Mustacchi 
412*533affcbSRobert Mustacchi 	if ((disc->nfd_in_get & NVME_GET_FEAT_F_CDW11) != 0) {
413*533affcbSRobert Mustacchi 		req->gfr_need |= 1 << NVME_GET_FEAT_REQ_FIELD_CDW11;
414*533affcbSRobert Mustacchi 		req->gfr_allow |= 1 << NVME_GET_FEAT_REQ_FIELD_CDW11;
415*533affcbSRobert Mustacchi 	}
416*533affcbSRobert Mustacchi 
417*533affcbSRobert Mustacchi 	if ((disc->nfd_in_get & NVME_GET_FEAT_F_DATA) != 0) {
418*533affcbSRobert Mustacchi 		req->gfr_need |= 1 << NVME_GET_FEAT_REQ_FIELD_DPTR;
419*533affcbSRobert Mustacchi 		req->gfr_allow |= 1 << NVME_GET_FEAT_REQ_FIELD_DPTR;
420*533affcbSRobert Mustacchi 	}
421*533affcbSRobert Mustacchi 
422*533affcbSRobert Mustacchi 	if ((disc->nfd_in_get & NVME_GET_FEAT_F_NSID) != 0) {
423*533affcbSRobert Mustacchi 		req->gfr_need |= 1 << NVME_GET_FEAT_REQ_FIELD_NSID;
424*533affcbSRobert Mustacchi 		req->gfr_allow |= 1 << NVME_GET_FEAT_REQ_FIELD_NSID;
425*533affcbSRobert Mustacchi 	}
426*533affcbSRobert Mustacchi 
427*533affcbSRobert Mustacchi 	*reqp = req;
428*533affcbSRobert Mustacchi 	return (nvme_ctrl_success(ctrl));
429*533affcbSRobert Mustacchi }
430*533affcbSRobert Mustacchi 
431*533affcbSRobert Mustacchi typedef struct {
432*533affcbSRobert Mustacchi 	bool ngfi_found;
433*533affcbSRobert Mustacchi 	const char *ngfi_name;
434*533affcbSRobert Mustacchi 	nvme_get_feat_req_t *ngfi_req;
435*533affcbSRobert Mustacchi 	nvme_feat_disc_t **ngfi_discp;
436*533affcbSRobert Mustacchi 	nvme_err_data_t ngfi_err;
437*533affcbSRobert Mustacchi } nvme_get_feat_init_arg_t;
438*533affcbSRobert Mustacchi 
439*533affcbSRobert Mustacchi static bool
nvme_get_feat_req_init_by_name_cb(nvme_ctrl_t * ctrl,const nvme_feat_disc_t * disc,void * arg)440*533affcbSRobert Mustacchi nvme_get_feat_req_init_by_name_cb(nvme_ctrl_t *ctrl,
441*533affcbSRobert Mustacchi     const nvme_feat_disc_t *disc, void *arg)
442*533affcbSRobert Mustacchi {
443*533affcbSRobert Mustacchi 	nvme_get_feat_init_arg_t *init = arg;
444*533affcbSRobert Mustacchi 
445*533affcbSRobert Mustacchi 	if (strcmp(init->ngfi_name, disc->nfd_short) != 0 &&
446*533affcbSRobert Mustacchi 	    strcmp(init->ngfi_name, disc->nfd_spec) != 0) {
447*533affcbSRobert Mustacchi 		return (true);
448*533affcbSRobert Mustacchi 	}
449*533affcbSRobert Mustacchi 
450*533affcbSRobert Mustacchi 	init->ngfi_found = true;
451*533affcbSRobert Mustacchi 	if (!nvme_get_feat_req_init_by_disc(ctrl, disc, &init->ngfi_req)) {
452*533affcbSRobert Mustacchi 		nvme_ctrl_err_save(ctrl, &init->ngfi_err);
453*533affcbSRobert Mustacchi 		init->ngfi_req = NULL;
454*533affcbSRobert Mustacchi 	} else if (init->ngfi_discp != NULL) {
455*533affcbSRobert Mustacchi 		if (!nvme_feat_disc_dup(ctrl, disc, init->ngfi_discp)) {
456*533affcbSRobert Mustacchi 			nvme_ctrl_err_save(ctrl, &init->ngfi_err);
457*533affcbSRobert Mustacchi 			nvme_get_feat_req_fini(init->ngfi_req);
458*533affcbSRobert Mustacchi 			init->ngfi_req = NULL;
459*533affcbSRobert Mustacchi 		}
460*533affcbSRobert Mustacchi 	}
461*533affcbSRobert Mustacchi 
462*533affcbSRobert Mustacchi 	return (false);
463*533affcbSRobert Mustacchi }
464*533affcbSRobert Mustacchi 
465*533affcbSRobert Mustacchi bool
nvme_get_feat_req_init_by_name(nvme_ctrl_t * ctrl,const char * name,uint32_t df,nvme_feat_disc_t ** discp,nvme_get_feat_req_t ** reqp)466*533affcbSRobert Mustacchi nvme_get_feat_req_init_by_name(nvme_ctrl_t *ctrl, const char *name,
467*533affcbSRobert Mustacchi     uint32_t df, nvme_feat_disc_t **discp, nvme_get_feat_req_t **reqp)
468*533affcbSRobert Mustacchi {
469*533affcbSRobert Mustacchi 	nvme_get_feat_init_arg_t init;
470*533affcbSRobert Mustacchi 
471*533affcbSRobert Mustacchi 	/*
472*533affcbSRobert Mustacchi 	 * Note, we consider discp optional unlikely the name and reqp. The
473*533affcbSRobert Mustacchi 	 * discover flags, df, will be validated by the discover functions we
474*533affcbSRobert Mustacchi 	 * call.
475*533affcbSRobert Mustacchi 	 */
476*533affcbSRobert Mustacchi 	if (name == NULL) {
477*533affcbSRobert Mustacchi 		return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
478*533affcbSRobert Mustacchi 		    "encountered invalid pointer for log page name: %p", name));
479*533affcbSRobert Mustacchi 	}
480*533affcbSRobert Mustacchi 
481*533affcbSRobert Mustacchi 	if (reqp == NULL) {
482*533affcbSRobert Mustacchi 		return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
483*533affcbSRobert Mustacchi 		    "encountered invalid nvme_get_feat_req_t output pointer: "
484*533affcbSRobert Mustacchi 		    "%p", reqp));
485*533affcbSRobert Mustacchi 	}
486*533affcbSRobert Mustacchi 
487*533affcbSRobert Mustacchi 	(void) memset(&init, 0, sizeof (init));
488*533affcbSRobert Mustacchi 	init.ngfi_name = name;
489*533affcbSRobert Mustacchi 	init.ngfi_discp = discp;
490*533affcbSRobert Mustacchi 
491*533affcbSRobert Mustacchi 	if (!nvme_feat_discover(ctrl, NVME_FEAT_SCOPE_CTRL | NVME_FEAT_SCOPE_NS,
492*533affcbSRobert Mustacchi 	    df, nvme_get_feat_req_init_by_name_cb, &init)) {
493*533affcbSRobert Mustacchi 		return (false);
494*533affcbSRobert Mustacchi 	}
495*533affcbSRobert Mustacchi 
496*533affcbSRobert Mustacchi 	if (!init.ngfi_found) {
497*533affcbSRobert Mustacchi 		return (nvme_ctrl_error(ctrl, NVME_ERR_FEAT_NAME_UNKNOWN, 0,
498*533affcbSRobert Mustacchi 		    "failed to find feature with name %s", name));
499*533affcbSRobert Mustacchi 	}
500*533affcbSRobert Mustacchi 
501*533affcbSRobert Mustacchi 	if (init.ngfi_req == NULL) {
502*533affcbSRobert Mustacchi 		nvme_ctrl_err_set(ctrl, &init.ngfi_err);
503*533affcbSRobert Mustacchi 		return (false);
504*533affcbSRobert Mustacchi 	}
505*533affcbSRobert Mustacchi 
506*533affcbSRobert Mustacchi 	*reqp = init.ngfi_req;
507*533affcbSRobert Mustacchi 	return (nvme_ctrl_success(ctrl));
508*533affcbSRobert Mustacchi }
509*533affcbSRobert Mustacchi 
510*533affcbSRobert Mustacchi 
511*533affcbSRobert Mustacchi static void
nvme_get_feat_req_clear_need(nvme_get_feat_req_t * req,nvme_get_feat_req_field_t field)512*533affcbSRobert Mustacchi nvme_get_feat_req_clear_need(nvme_get_feat_req_t *req,
513*533affcbSRobert Mustacchi     nvme_get_feat_req_field_t field)
514*533affcbSRobert Mustacchi {
515*533affcbSRobert Mustacchi 	req->gfr_need &= ~(1 << field);
516*533affcbSRobert Mustacchi }
517*533affcbSRobert Mustacchi 
518*533affcbSRobert Mustacchi static const nvme_field_check_t nvme_get_feat_check_fid = {
519*533affcbSRobert Mustacchi 	nvme_get_feat_fields, NVME_GET_FEAT_REQ_FIELD_FID,
520*533affcbSRobert Mustacchi 	NVME_ERR_FEAT_FID_RANGE, 0, 0
521*533affcbSRobert Mustacchi };
522*533affcbSRobert Mustacchi 
523*533affcbSRobert Mustacchi bool
nvme_get_feat_req_set_fid(nvme_get_feat_req_t * req,uint32_t fid)524*533affcbSRobert Mustacchi nvme_get_feat_req_set_fid(nvme_get_feat_req_t *req, uint32_t fid)
525*533affcbSRobert Mustacchi {
526*533affcbSRobert Mustacchi 	if (!nvme_field_check_one(req->gfr_ctrl, fid, "get feature",
527*533affcbSRobert Mustacchi 	    &nvme_get_feat_check_fid, req->gfr_allow)) {
528*533affcbSRobert Mustacchi 		return (false);
529*533affcbSRobert Mustacchi 	}
530*533affcbSRobert Mustacchi 
531*533affcbSRobert Mustacchi 	req->gfr_fid = fid;
532*533affcbSRobert Mustacchi 	nvme_get_feat_req_clear_need(req, NVME_GET_FEAT_REQ_FIELD_FID);
533*533affcbSRobert Mustacchi 	return (nvme_ctrl_success(req->gfr_ctrl));
534*533affcbSRobert Mustacchi }
535*533affcbSRobert Mustacchi 
536*533affcbSRobert Mustacchi static const nvme_field_check_t nvme_get_feat_check_sel = {
537*533affcbSRobert Mustacchi 	nvme_get_feat_fields, NVME_GET_FEAT_REQ_FIELD_SEL,
538*533affcbSRobert Mustacchi 	NVME_ERR_FEAT_SEL_RANGE, NVME_ERR_FEAT_SEL_UNSUP, 0
539*533affcbSRobert Mustacchi };
540*533affcbSRobert Mustacchi 
541*533affcbSRobert Mustacchi bool
nvme_get_feat_req_set_sel(nvme_get_feat_req_t * req,uint32_t sel)542*533affcbSRobert Mustacchi nvme_get_feat_req_set_sel(nvme_get_feat_req_t *req, uint32_t sel)
543*533affcbSRobert Mustacchi {
544*533affcbSRobert Mustacchi 	if (!nvme_field_check_one(req->gfr_ctrl, sel, "get feature",
545*533affcbSRobert Mustacchi 	    &nvme_get_feat_check_sel, req->gfr_allow)) {
546*533affcbSRobert Mustacchi 		return (false);
547*533affcbSRobert Mustacchi 	}
548*533affcbSRobert Mustacchi 
549*533affcbSRobert Mustacchi 	if (sel == NVME_FEATURE_SEL_SUPPORTED) {
550*533affcbSRobert Mustacchi 		return (nvme_ctrl_error(req->gfr_ctrl,
551*533affcbSRobert Mustacchi 		    NVME_ERR_FEAT_SEL_RANGE, 0, "the get feature APIs do "
552*533affcbSRobert Mustacchi 		    "not support supported capabilities selector"));
553*533affcbSRobert Mustacchi 	}
554*533affcbSRobert Mustacchi 
555*533affcbSRobert Mustacchi 	req->gfr_sel = sel;
556*533affcbSRobert Mustacchi 	nvme_get_feat_req_clear_need(req, NVME_GET_FEAT_REQ_FIELD_SEL);
557*533affcbSRobert Mustacchi 	return (nvme_ctrl_success(req->gfr_ctrl));
558*533affcbSRobert Mustacchi }
559*533affcbSRobert Mustacchi 
560*533affcbSRobert Mustacchi static const nvme_field_check_t nvme_get_feat_check_cdw11 = {
561*533affcbSRobert Mustacchi 	nvme_get_feat_fields, NVME_GET_FEAT_REQ_FIELD_CDW11,
562*533affcbSRobert Mustacchi 	NVME_ERR_FEAT_CDW11_RANGE, 0, NVME_ERR_FEAT_CDW11_UNUSE
563*533affcbSRobert Mustacchi };
564*533affcbSRobert Mustacchi 
565*533affcbSRobert Mustacchi bool
nvme_get_feat_req_set_cdw11(nvme_get_feat_req_t * req,uint32_t cdw11)566*533affcbSRobert Mustacchi nvme_get_feat_req_set_cdw11(nvme_get_feat_req_t *req, uint32_t cdw11)
567*533affcbSRobert Mustacchi {
568*533affcbSRobert Mustacchi 	if (!nvme_field_check_one(req->gfr_ctrl, cdw11, "get feature",
569*533affcbSRobert Mustacchi 	    &nvme_get_feat_check_cdw11, req->gfr_allow)) {
570*533affcbSRobert Mustacchi 		return (false);
571*533affcbSRobert Mustacchi 	}
572*533affcbSRobert Mustacchi 
573*533affcbSRobert Mustacchi 	req->gfr_cdw11 = cdw11;
574*533affcbSRobert Mustacchi 	nvme_get_feat_req_clear_need(req, NVME_GET_FEAT_REQ_FIELD_CDW11);
575*533affcbSRobert Mustacchi 	return (nvme_ctrl_success(req->gfr_ctrl));
576*533affcbSRobert Mustacchi }
577*533affcbSRobert Mustacchi 
578*533affcbSRobert Mustacchi static const nvme_field_check_t nvme_get_feat_check_nsid = {
579*533affcbSRobert Mustacchi 	nvme_get_feat_fields, NVME_GET_FEAT_REQ_FIELD_NSID,
580*533affcbSRobert Mustacchi 	NVME_ERR_NS_RANGE, 0, NVME_ERR_NS_UNUSE
581*533affcbSRobert Mustacchi };
582*533affcbSRobert Mustacchi 
583*533affcbSRobert Mustacchi bool
nvme_get_feat_req_set_nsid(nvme_get_feat_req_t * req,uint32_t nsid)584*533affcbSRobert Mustacchi nvme_get_feat_req_set_nsid(nvme_get_feat_req_t *req, uint32_t nsid)
585*533affcbSRobert Mustacchi {
586*533affcbSRobert Mustacchi 	nvme_ctrl_t *ctrl = req->gfr_ctrl;
587*533affcbSRobert Mustacchi 
588*533affcbSRobert Mustacchi 	/*
589*533affcbSRobert Mustacchi 	 * Check the NSID first before we go into the generic validation code so
590*533affcbSRobert Mustacchi 	 * we can get a better error message.
591*533affcbSRobert Mustacchi 	 */
592*533affcbSRobert Mustacchi 	if (nsid == NVME_NSID_BCAST &&
593*533affcbSRobert Mustacchi 	    (req->gfr_flags & NVME_FEAT_F_GET_BCAST_NSID) == 0) {
594*533affcbSRobert Mustacchi 		return (nvme_ctrl_error(ctrl, NVME_ERR_NS_RANGE, 0, "the all "
595*533affcbSRobert Mustacchi 		    "namespaces/controller nsid (0x%x) is not allowed for this "
596*533affcbSRobert Mustacchi 		    "feature, valid namespaces are [0x%x, 0x%x]", nsid,
597*533affcbSRobert Mustacchi 		    NVME_NSID_MIN, req->gfr_ctrl->nc_info.id_nn));
598*533affcbSRobert Mustacchi 	}
599*533affcbSRobert Mustacchi 
600*533affcbSRobert Mustacchi 	if (!nvme_field_check_one(req->gfr_ctrl, nsid, "get feature",
601*533affcbSRobert Mustacchi 	    &nvme_get_feat_check_nsid, req->gfr_allow)) {
602*533affcbSRobert Mustacchi 		return (false);
603*533affcbSRobert Mustacchi 	}
604*533affcbSRobert Mustacchi 
605*533affcbSRobert Mustacchi 	req->gfr_nsid = nsid;
606*533affcbSRobert Mustacchi 	nvme_get_feat_req_clear_need(req, NVME_GET_FEAT_REQ_FIELD_NSID);
607*533affcbSRobert Mustacchi 	return (nvme_ctrl_success(ctrl));
608*533affcbSRobert Mustacchi }
609*533affcbSRobert Mustacchi 
610*533affcbSRobert Mustacchi bool
nvme_get_feat_req_set_output(nvme_get_feat_req_t * req,void * buf,size_t len)611*533affcbSRobert Mustacchi nvme_get_feat_req_set_output(nvme_get_feat_req_t *req, void *buf, size_t len)
612*533affcbSRobert Mustacchi {
613*533affcbSRobert Mustacchi 	if (buf == NULL) {
614*533affcbSRobert Mustacchi 		return (nvme_ctrl_error(req->gfr_ctrl, NVME_ERR_BAD_PTR, 0,
615*533affcbSRobert Mustacchi 		    "get feature output buffer cannot be NULL"));
616*533affcbSRobert Mustacchi 	}
617*533affcbSRobert Mustacchi 
618*533affcbSRobert Mustacchi 	if (len == 0) {
619*533affcbSRobert Mustacchi 		return (nvme_ctrl_error(req->gfr_ctrl,
620*533affcbSRobert Mustacchi 		    NVME_ERR_FEAT_DATA_RANGE, 0, "get feature output length "
621*533affcbSRobert Mustacchi 		    "cannot be zero"));
622*533affcbSRobert Mustacchi 	}
623*533affcbSRobert Mustacchi 
624*533affcbSRobert Mustacchi 	/*
625*533affcbSRobert Mustacchi 	 * Something to consider for the future here is that we know the fixed
626*533affcbSRobert Mustacchi 	 * size data that we're expecting for the feature. It would be nice if
627*533affcbSRobert Mustacchi 	 * we validated that we have that size now versus later.
628*533affcbSRobert Mustacchi 	 */
629*533affcbSRobert Mustacchi 
630*533affcbSRobert Mustacchi 	req->gfr_buf = buf;
631*533affcbSRobert Mustacchi 	req->gfr_len = len;
632*533affcbSRobert Mustacchi 	nvme_get_feat_req_clear_need(req, NVME_GET_FEAT_REQ_FIELD_DPTR);
633*533affcbSRobert Mustacchi 	return (nvme_ctrl_success(req->gfr_ctrl));
634*533affcbSRobert Mustacchi }
635*533affcbSRobert Mustacchi 
636*533affcbSRobert Mustacchi bool
nvme_get_feat_req_get_cdw0(nvme_get_feat_req_t * req,uint32_t * cdw0)637*533affcbSRobert Mustacchi nvme_get_feat_req_get_cdw0(nvme_get_feat_req_t *req, uint32_t *cdw0)
638*533affcbSRobert Mustacchi {
639*533affcbSRobert Mustacchi 	if (cdw0 == NULL) {
640*533affcbSRobert Mustacchi 		return (nvme_ctrl_error(req->gfr_ctrl, NVME_ERR_BAD_PTR, 0,
641*533affcbSRobert Mustacchi 		    "encountered invalid cdw0 output pointer: %p", cdw0));
642*533affcbSRobert Mustacchi 	}
643*533affcbSRobert Mustacchi 
644*533affcbSRobert Mustacchi 	if (!req->gfr_results_valid) {
645*533affcbSRobert Mustacchi 		return (nvme_ctrl_error(req->gfr_ctrl,
646*533affcbSRobert Mustacchi 		    NVME_ERR_FEAT_NO_RESULTS, 0, "get feature results are not "
647*533affcbSRobert Mustacchi 		    "currently valid and cannot be returned"));
648*533affcbSRobert Mustacchi 	}
649*533affcbSRobert Mustacchi 
650*533affcbSRobert Mustacchi 	*cdw0 = req->gfr_cdw0;
651*533affcbSRobert Mustacchi 	return (nvme_ctrl_success(req->gfr_ctrl));
652*533affcbSRobert Mustacchi }
653*533affcbSRobert Mustacchi 
654*533affcbSRobert Mustacchi bool
nvme_get_feat_req_exec(nvme_get_feat_req_t * req)655*533affcbSRobert Mustacchi nvme_get_feat_req_exec(nvme_get_feat_req_t *req)
656*533affcbSRobert Mustacchi {
657*533affcbSRobert Mustacchi 	nvme_ctrl_t *ctrl = req->gfr_ctrl;
658*533affcbSRobert Mustacchi 	nvme_ioctl_get_feature_t feat;
659*533affcbSRobert Mustacchi 
660*533affcbSRobert Mustacchi 	/*
661*533affcbSRobert Mustacchi 	 * Because this has been called, we need to immediately invalidate our
662*533affcbSRobert Mustacchi 	 * stored cdw0 results. We do this as a precaution regardless of whether
663*533affcbSRobert Mustacchi 	 * or not it is valid.
664*533affcbSRobert Mustacchi 	 */
665*533affcbSRobert Mustacchi 	req->gfr_results_valid = false;
666*533affcbSRobert Mustacchi 	req->gfr_cdw0 = 0;
667*533affcbSRobert Mustacchi 
668*533affcbSRobert Mustacchi 	if (req->gfr_need != 0) {
669*533affcbSRobert Mustacchi 		return (nvme_field_miss_err(ctrl, nvme_get_feat_fields,
670*533affcbSRobert Mustacchi 		    nvme_get_feat_nfields, NVME_ERR_GET_FEAT_REQ_MISSING_FIELDS,
671*533affcbSRobert Mustacchi 		    "get feature", req->gfr_need));
672*533affcbSRobert Mustacchi 	}
673*533affcbSRobert Mustacchi 
674*533affcbSRobert Mustacchi 	(void) memset(&feat, 0, sizeof (nvme_ioctl_get_feature_t));
675*533affcbSRobert Mustacchi 	feat.nigf_common.nioc_nsid = req->gfr_nsid;
676*533affcbSRobert Mustacchi 	feat.nigf_fid = req->gfr_fid;
677*533affcbSRobert Mustacchi 	feat.nigf_sel = req->gfr_sel;
678*533affcbSRobert Mustacchi 	feat.nigf_cdw11 = req->gfr_cdw11;
679*533affcbSRobert Mustacchi 	if (req->gfr_buf != NULL) {
680*533affcbSRobert Mustacchi 		feat.nigf_data = (uintptr_t)req->gfr_buf;
681*533affcbSRobert Mustacchi 		feat.nigf_len = req->gfr_len;
682*533affcbSRobert Mustacchi 	}
683*533affcbSRobert Mustacchi 
684*533affcbSRobert Mustacchi 	if (ioctl(ctrl->nc_fd, NVME_IOC_GET_FEATURE, &feat) != 0) {
685*533affcbSRobert Mustacchi 		int e = errno;
686*533affcbSRobert Mustacchi 		return (nvme_ioctl_syserror(ctrl, e, "get feature"));
687*533affcbSRobert Mustacchi 	}
688*533affcbSRobert Mustacchi 
689*533affcbSRobert Mustacchi 	if (feat.nigf_common.nioc_drv_err != NVME_IOCTL_E_OK) {
690*533affcbSRobert Mustacchi 		return (nvme_ioctl_error(ctrl, &feat.nigf_common,
691*533affcbSRobert Mustacchi 		    "get feature"));
692*533affcbSRobert Mustacchi 	}
693*533affcbSRobert Mustacchi 
694*533affcbSRobert Mustacchi 	req->gfr_results_valid = true;
695*533affcbSRobert Mustacchi 	req->gfr_cdw0 = feat.nigf_cdw0;
696*533affcbSRobert Mustacchi 
697*533affcbSRobert Mustacchi 	return (nvme_ctrl_success(ctrl));
698*533affcbSRobert Mustacchi }
699