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 implements all of the libnvme log discovery and log page execution
18*533affcbSRobert Mustacchi * functions.
19*533affcbSRobert Mustacchi *
20*533affcbSRobert Mustacchi * In NVMe 1.0 there were just three mandatory log pages. These are the classic
21*533affcbSRobert Mustacchi * Error, SMART, and firmware log pages. NVMe 1.1 added an optional log page for
22*533affcbSRobert Mustacchi * NVM devices. Specifically this is the Reservation Log page. This was
23*533affcbSRobert Mustacchi * indicated by the controller's ONCS field. Version 1.1 also introduced the Log
24*533affcbSRobert Mustacchi * Page Attributes (LPA) field which is how additional pages were indicated as
25*533affcbSRobert Mustacchi * being supported when not part of something like ONCS.
26*533affcbSRobert Mustacchi *
27*533affcbSRobert Mustacchi * Beginning in NVMe 1.2, many more log pages were added that were optional. In
28*533affcbSRobert Mustacchi * particular, the changed namespace list and command effects log. The former
29*533affcbSRobert Mustacchi * has support indicated via a bit in OAES (though this was not clarified until
30*533affcbSRobert Mustacchi * NVMe 1.3) while the latter is in the LPA field. NVMe 1.2 also added the
31*533affcbSRobert Mustacchi * ability for the Get Log Page to support larger amounts of data. The last
32*533affcbSRobert Mustacchi * major piece of 1.2 was the addition of fabrics related log pages. Those are
33*533affcbSRobert Mustacchi * not currently supported here.
34*533affcbSRobert Mustacchi *
35*533affcbSRobert Mustacchi * NVMe 1.3 and 1.4 continued the trend of adding log pages that are generally
36*533affcbSRobert Mustacchi * optional, but may be required given a specific set of features being enabled.
37*533affcbSRobert Mustacchi *
38*533affcbSRobert Mustacchi * The largest change for log pages is in NVMe 2.0. It added a specific means of
39*533affcbSRobert Mustacchi * indicating a command set for a given log page and also added the ability to
40*533affcbSRobert Mustacchi * query all the supported log pages. This has existed previously, but only
41*533affcbSRobert Mustacchi * through vendor specific means.
42*533affcbSRobert Mustacchi */
43*533affcbSRobert Mustacchi
44*533affcbSRobert Mustacchi #include <string.h>
45*533affcbSRobert Mustacchi #include <upanic.h>
46*533affcbSRobert Mustacchi #include <sys/sysmacros.h>
47*533affcbSRobert Mustacchi #include <sys/debug.h>
48*533affcbSRobert Mustacchi #include <unistd.h>
49*533affcbSRobert Mustacchi
50*533affcbSRobert Mustacchi #include "libnvme_impl.h"
51*533affcbSRobert Mustacchi
52*533affcbSRobert Mustacchi void
nvme_log_disc_free(nvme_log_disc_t * disc)53*533affcbSRobert Mustacchi nvme_log_disc_free(nvme_log_disc_t *disc)
54*533affcbSRobert Mustacchi {
55*533affcbSRobert Mustacchi free(disc);
56*533affcbSRobert Mustacchi }
57*533affcbSRobert Mustacchi
58*533affcbSRobert Mustacchi const char *
nvme_log_disc_name(const nvme_log_disc_t * disc)59*533affcbSRobert Mustacchi nvme_log_disc_name(const nvme_log_disc_t *disc)
60*533affcbSRobert Mustacchi {
61*533affcbSRobert Mustacchi return (disc->nld_short);
62*533affcbSRobert Mustacchi }
63*533affcbSRobert Mustacchi
64*533affcbSRobert Mustacchi const char *
nvme_log_disc_desc(const nvme_log_disc_t * disc)65*533affcbSRobert Mustacchi nvme_log_disc_desc(const nvme_log_disc_t *disc)
66*533affcbSRobert Mustacchi {
67*533affcbSRobert Mustacchi return (disc->nld_desc);
68*533affcbSRobert Mustacchi }
69*533affcbSRobert Mustacchi
70*533affcbSRobert Mustacchi nvme_csi_t
nvme_log_disc_csi(const nvme_log_disc_t * disc)71*533affcbSRobert Mustacchi nvme_log_disc_csi(const nvme_log_disc_t *disc)
72*533affcbSRobert Mustacchi {
73*533affcbSRobert Mustacchi return (disc->nld_csi);
74*533affcbSRobert Mustacchi }
75*533affcbSRobert Mustacchi
76*533affcbSRobert Mustacchi uint32_t
nvme_log_disc_lid(const nvme_log_disc_t * disc)77*533affcbSRobert Mustacchi nvme_log_disc_lid(const nvme_log_disc_t *disc)
78*533affcbSRobert Mustacchi {
79*533affcbSRobert Mustacchi return (disc->nld_lid);
80*533affcbSRobert Mustacchi }
81*533affcbSRobert Mustacchi
82*533affcbSRobert Mustacchi nvme_log_disc_kind_t
nvme_log_disc_kind(const nvme_log_disc_t * disc)83*533affcbSRobert Mustacchi nvme_log_disc_kind(const nvme_log_disc_t *disc)
84*533affcbSRobert Mustacchi {
85*533affcbSRobert Mustacchi return (disc->nld_kind);
86*533affcbSRobert Mustacchi }
87*533affcbSRobert Mustacchi
88*533affcbSRobert Mustacchi nvme_log_disc_source_t
nvme_log_disc_sources(const nvme_log_disc_t * disc)89*533affcbSRobert Mustacchi nvme_log_disc_sources(const nvme_log_disc_t *disc)
90*533affcbSRobert Mustacchi {
91*533affcbSRobert Mustacchi return (disc->nld_srcs);
92*533affcbSRobert Mustacchi }
93*533affcbSRobert Mustacchi
94*533affcbSRobert Mustacchi nvme_log_disc_fields_t
nvme_log_disc_fields(const nvme_log_disc_t * disc)95*533affcbSRobert Mustacchi nvme_log_disc_fields(const nvme_log_disc_t *disc)
96*533affcbSRobert Mustacchi {
97*533affcbSRobert Mustacchi return (disc->nld_fields);
98*533affcbSRobert Mustacchi }
99*533affcbSRobert Mustacchi
100*533affcbSRobert Mustacchi nvme_log_disc_scope_t
nvme_log_disc_scopes(const nvme_log_disc_t * disc)101*533affcbSRobert Mustacchi nvme_log_disc_scopes(const nvme_log_disc_t *disc)
102*533affcbSRobert Mustacchi {
103*533affcbSRobert Mustacchi return (disc->nld_scope);
104*533affcbSRobert Mustacchi }
105*533affcbSRobert Mustacchi
106*533affcbSRobert Mustacchi bool
nvme_log_disc_impl(const nvme_log_disc_t * disc)107*533affcbSRobert Mustacchi nvme_log_disc_impl(const nvme_log_disc_t *disc)
108*533affcbSRobert Mustacchi {
109*533affcbSRobert Mustacchi return ((disc->nld_flags & NVME_LOG_DISC_F_IMPL) != 0);
110*533affcbSRobert Mustacchi }
111*533affcbSRobert Mustacchi
112*533affcbSRobert Mustacchi nvme_log_size_kind_t
nvme_log_disc_size(const nvme_log_disc_t * disc,uint64_t * sizep)113*533affcbSRobert Mustacchi nvme_log_disc_size(const nvme_log_disc_t *disc, uint64_t *sizep)
114*533affcbSRobert Mustacchi {
115*533affcbSRobert Mustacchi *sizep = disc->nld_alloc_len;
116*533affcbSRobert Mustacchi return (disc->nld_size_kind);
117*533affcbSRobert Mustacchi }
118*533affcbSRobert Mustacchi
119*533affcbSRobert Mustacchi /*
120*533affcbSRobert Mustacchi * For a variable length log page, presuming we've been given sufficient data
121*533affcbSRobert Mustacchi * actually determine the overall length that should now be used to get all
122*533affcbSRobert Mustacchi * data in the log.
123*533affcbSRobert Mustacchi */
124*533affcbSRobert Mustacchi bool
nvme_log_disc_calc_size(const nvme_log_disc_t * disc,uint64_t * act,const void * buf,size_t buflen)125*533affcbSRobert Mustacchi nvme_log_disc_calc_size(const nvme_log_disc_t *disc, uint64_t *act,
126*533affcbSRobert Mustacchi const void *buf, size_t buflen)
127*533affcbSRobert Mustacchi {
128*533affcbSRobert Mustacchi if (disc->nld_var_func == NULL) {
129*533affcbSRobert Mustacchi *act = disc->nld_alloc_len;
130*533affcbSRobert Mustacchi }
131*533affcbSRobert Mustacchi
132*533affcbSRobert Mustacchi return (disc->nld_var_func(act, buf, buflen));
133*533affcbSRobert Mustacchi }
134*533affcbSRobert Mustacchi
135*533affcbSRobert Mustacchi bool
nvme_log_disc_dup(nvme_ctrl_t * ctrl,const nvme_log_disc_t * src,nvme_log_disc_t ** discp)136*533affcbSRobert Mustacchi nvme_log_disc_dup(nvme_ctrl_t *ctrl, const nvme_log_disc_t *src,
137*533affcbSRobert Mustacchi nvme_log_disc_t **discp)
138*533affcbSRobert Mustacchi {
139*533affcbSRobert Mustacchi nvme_log_disc_t *disc;
140*533affcbSRobert Mustacchi
141*533affcbSRobert Mustacchi if (src == NULL) {
142*533affcbSRobert Mustacchi return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
143*533affcbSRobert Mustacchi "encountered invalid nvme_log_disc_t pointer to duplicate: "
144*533affcbSRobert Mustacchi "%p", src));
145*533affcbSRobert Mustacchi }
146*533affcbSRobert Mustacchi
147*533affcbSRobert Mustacchi if (discp == NULL) {
148*533affcbSRobert Mustacchi return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
149*533affcbSRobert Mustacchi "encountered invalid nvme_log_disc_t output pointer: %p",
150*533affcbSRobert Mustacchi discp));
151*533affcbSRobert Mustacchi }
152*533affcbSRobert Mustacchi
153*533affcbSRobert Mustacchi disc = calloc(1, sizeof (nvme_log_disc_t));
154*533affcbSRobert Mustacchi if (disc == NULL) {
155*533affcbSRobert Mustacchi int e = errno;
156*533affcbSRobert Mustacchi return (nvme_ctrl_error(ctrl, NVME_ERR_NO_MEM, e, "failed to "
157*533affcbSRobert Mustacchi "allocate memory for a new nvme_log_disc_t: %s",
158*533affcbSRobert Mustacchi strerror(e)));
159*533affcbSRobert Mustacchi }
160*533affcbSRobert Mustacchi
161*533affcbSRobert Mustacchi (void) memcpy(disc, src, sizeof (nvme_log_disc_t));
162*533affcbSRobert Mustacchi *discp = disc;
163*533affcbSRobert Mustacchi return (nvme_ctrl_success(ctrl));
164*533affcbSRobert Mustacchi }
165*533affcbSRobert Mustacchi
166*533affcbSRobert Mustacchi /*
167*533affcbSRobert Mustacchi * Log Page Discovery logic
168*533affcbSRobert Mustacchi */
169*533affcbSRobert Mustacchi static bool
nvme_log_discover_validate(nvme_ctrl_t * ctrl,nvme_log_disc_scope_t scopes,uint32_t flags)170*533affcbSRobert Mustacchi nvme_log_discover_validate(nvme_ctrl_t *ctrl, nvme_log_disc_scope_t scopes,
171*533affcbSRobert Mustacchi uint32_t flags)
172*533affcbSRobert Mustacchi {
173*533affcbSRobert Mustacchi const nvme_log_disc_scope_t valid_scopes = NVME_LOG_SCOPE_CTRL |
174*533affcbSRobert Mustacchi NVME_LOG_SCOPE_NVM | NVME_LOG_SCOPE_NS;
175*533affcbSRobert Mustacchi
176*533affcbSRobert Mustacchi /*
177*533affcbSRobert Mustacchi * For now require an explicit scope. Perhaps 0 should be an alias for
178*533affcbSRobert Mustacchi * allow all. That means if something gets added no one has to update to
179*533affcbSRobert Mustacchi * get new things, but on the other hand that means they might see
180*533affcbSRobert Mustacchi * unexpected scopes.
181*533affcbSRobert Mustacchi */
182*533affcbSRobert Mustacchi if (scopes == 0) {
183*533affcbSRobert Mustacchi return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_FLAG, 0, "no log "
184*533affcbSRobert Mustacchi "scope specified (given 0), a scope must be requested"));
185*533affcbSRobert Mustacchi }
186*533affcbSRobert Mustacchi
187*533affcbSRobert Mustacchi if ((scopes & ~valid_scopes) != 0) {
188*533affcbSRobert Mustacchi return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_FLAG, 0,
189*533affcbSRobert Mustacchi "encountered invalid scope for the nvme_log_disc_scope_t: "
190*533affcbSRobert Mustacchi "0x%x", scopes & ~valid_scopes));
191*533affcbSRobert Mustacchi }
192*533affcbSRobert Mustacchi
193*533affcbSRobert Mustacchi if (flags != 0) {
194*533affcbSRobert Mustacchi return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_FLAG, 0,
195*533affcbSRobert Mustacchi "encountered invalid log discovery flags: 0x%x", flags));
196*533affcbSRobert Mustacchi }
197*533affcbSRobert Mustacchi
198*533affcbSRobert Mustacchi return (true);
199*533affcbSRobert Mustacchi }
200*533affcbSRobert Mustacchi
201*533affcbSRobert Mustacchi void
nvme_log_discover_fini(nvme_log_iter_t * iter)202*533affcbSRobert Mustacchi nvme_log_discover_fini(nvme_log_iter_t *iter)
203*533affcbSRobert Mustacchi {
204*533affcbSRobert Mustacchi free(iter);
205*533affcbSRobert Mustacchi }
206*533affcbSRobert Mustacchi
207*533affcbSRobert Mustacchi static bool
nvme_log_discover_one(nvme_log_iter_t * iter,const nvme_log_page_info_t * info)208*533affcbSRobert Mustacchi nvme_log_discover_one(nvme_log_iter_t *iter, const nvme_log_page_info_t *info)
209*533affcbSRobert Mustacchi {
210*533affcbSRobert Mustacchi bool var;
211*533affcbSRobert Mustacchi nvme_log_disc_t *disc = &iter->nli_nld;
212*533affcbSRobert Mustacchi nvme_log_disc_scope_t scope;
213*533affcbSRobert Mustacchi nvme_valid_ctrl_data_t data;
214*533affcbSRobert Mustacchi
215*533affcbSRobert Mustacchi data.vcd_vers = &iter->nli_ctrl->nc_vers;
216*533affcbSRobert Mustacchi data.vcd_id = &iter->nli_ctrl->nc_info;
217*533affcbSRobert Mustacchi
218*533affcbSRobert Mustacchi /*
219*533affcbSRobert Mustacchi * Determine the scope of the log page so we can understand if the user
220*533affcbSRobert Mustacchi * cares about this or not.
221*533affcbSRobert Mustacchi */
222*533affcbSRobert Mustacchi scope = nvme_log_page_info_scope(info, &data);
223*533affcbSRobert Mustacchi if ((iter->nli_scope & scope) == 0) {
224*533affcbSRobert Mustacchi return (false);
225*533affcbSRobert Mustacchi }
226*533affcbSRobert Mustacchi
227*533affcbSRobert Mustacchi (void) memset(disc, 0, sizeof (nvme_log_disc_t));
228*533affcbSRobert Mustacchi
229*533affcbSRobert Mustacchi /*
230*533affcbSRobert Mustacchi * Now that we know that this applies, fill in the remaining information
231*533affcbSRobert Mustacchi * that we need.
232*533affcbSRobert Mustacchi */
233*533affcbSRobert Mustacchi disc->nld_short = info->nlpi_short;
234*533affcbSRobert Mustacchi disc->nld_desc = info->nlpi_human;
235*533affcbSRobert Mustacchi disc->nld_lid = info->nlpi_lid;
236*533affcbSRobert Mustacchi disc->nld_csi = info->nlpi_csi;
237*533affcbSRobert Mustacchi disc->nld_kind = info->nlpi_kind;
238*533affcbSRobert Mustacchi disc->nld_srcs = info->nlpi_source;
239*533affcbSRobert Mustacchi disc->nld_scope = scope;
240*533affcbSRobert Mustacchi disc->nld_fields = info->nlpi_disc;
241*533affcbSRobert Mustacchi
242*533affcbSRobert Mustacchi disc->nld_alloc_len = nvme_log_page_info_size(info, &data, &var);
243*533affcbSRobert Mustacchi if (disc->nld_alloc_len != 0) {
244*533affcbSRobert Mustacchi if (var) {
245*533affcbSRobert Mustacchi disc->nld_var_func = info->nlpi_var_func;
246*533affcbSRobert Mustacchi disc->nld_size_kind = NVME_LOG_SIZE_K_VAR;
247*533affcbSRobert Mustacchi } else {
248*533affcbSRobert Mustacchi disc->nld_size_kind = NVME_LOG_SIZE_K_FIXED;
249*533affcbSRobert Mustacchi }
250*533affcbSRobert Mustacchi } else {
251*533affcbSRobert Mustacchi disc->nld_size_kind = NVME_LOG_SIZE_K_UNKNOWN;
252*533affcbSRobert Mustacchi disc->nld_alloc_len = NVME_LOG_MAX_SIZE;
253*533affcbSRobert Mustacchi }
254*533affcbSRobert Mustacchi
255*533affcbSRobert Mustacchi if (nvme_log_page_info_supported(info, &data)) {
256*533affcbSRobert Mustacchi disc->nld_flags |= NVME_LOG_DISC_F_IMPL;
257*533affcbSRobert Mustacchi }
258*533affcbSRobert Mustacchi
259*533affcbSRobert Mustacchi return (true);
260*533affcbSRobert Mustacchi }
261*533affcbSRobert Mustacchi
262*533affcbSRobert Mustacchi nvme_iter_t
nvme_log_discover_step(nvme_log_iter_t * iter,const nvme_log_disc_t ** outp)263*533affcbSRobert Mustacchi nvme_log_discover_step(nvme_log_iter_t *iter, const nvme_log_disc_t **outp)
264*533affcbSRobert Mustacchi {
265*533affcbSRobert Mustacchi *outp = NULL;
266*533affcbSRobert Mustacchi nvme_ctrl_t *ctrl = iter->nli_ctrl;
267*533affcbSRobert Mustacchi
268*533affcbSRobert Mustacchi if (iter->nli_std_done && iter->nli_vs_done) {
269*533affcbSRobert Mustacchi return (NVME_ITER_DONE);
270*533affcbSRobert Mustacchi }
271*533affcbSRobert Mustacchi
272*533affcbSRobert Mustacchi /*
273*533affcbSRobert Mustacchi * We start by walking the list of spec pages and then check the device
274*533affcbSRobert Mustacchi * specific ones. In the NVMe 2.x era or when we have support for a
275*533affcbSRobert Mustacchi * vendor-specific method for getting supported log pages then we should
276*533affcbSRobert Mustacchi * prefer executing that and using that info to provide information
277*533affcbSRobert Mustacchi * where possible.
278*533affcbSRobert Mustacchi */
279*533affcbSRobert Mustacchi if (!iter->nli_std_done) {
280*533affcbSRobert Mustacchi while (iter->nli_cur_idx < nvme_std_log_npages) {
281*533affcbSRobert Mustacchi const nvme_log_page_info_t *info =
282*533affcbSRobert Mustacchi &nvme_std_log_pages[iter->nli_cur_idx];
283*533affcbSRobert Mustacchi iter->nli_cur_idx++;
284*533affcbSRobert Mustacchi if (nvme_log_discover_one(iter, info)) {
285*533affcbSRobert Mustacchi *outp = &iter->nli_nld;
286*533affcbSRobert Mustacchi return (NVME_ITER_VALID);
287*533affcbSRobert Mustacchi }
288*533affcbSRobert Mustacchi }
289*533affcbSRobert Mustacchi iter->nli_std_done = true;
290*533affcbSRobert Mustacchi iter->nli_cur_idx = 0;
291*533affcbSRobert Mustacchi }
292*533affcbSRobert Mustacchi
293*533affcbSRobert Mustacchi if (ctrl->nc_vsd == NULL) {
294*533affcbSRobert Mustacchi iter->nli_vs_done = true;
295*533affcbSRobert Mustacchi return (NVME_ITER_DONE);
296*533affcbSRobert Mustacchi }
297*533affcbSRobert Mustacchi
298*533affcbSRobert Mustacchi while (iter->nli_cur_idx < ctrl->nc_vsd->nvd_nlogs) {
299*533affcbSRobert Mustacchi const nvme_log_page_info_t *info =
300*533affcbSRobert Mustacchi &ctrl->nc_vsd->nvd_logs[iter->nli_cur_idx];
301*533affcbSRobert Mustacchi iter->nli_cur_idx++;
302*533affcbSRobert Mustacchi if (nvme_log_discover_one(iter, info)) {
303*533affcbSRobert Mustacchi *outp = &iter->nli_nld;
304*533affcbSRobert Mustacchi return (NVME_ITER_VALID);
305*533affcbSRobert Mustacchi }
306*533affcbSRobert Mustacchi }
307*533affcbSRobert Mustacchi
308*533affcbSRobert Mustacchi iter->nli_vs_done = true;
309*533affcbSRobert Mustacchi iter->nli_cur_idx = 0;
310*533affcbSRobert Mustacchi return (NVME_ITER_DONE);
311*533affcbSRobert Mustacchi }
312*533affcbSRobert Mustacchi
313*533affcbSRobert Mustacchi bool
nvme_log_discover_init(nvme_ctrl_t * ctrl,nvme_log_disc_scope_t scopes,uint32_t flags,nvme_log_iter_t ** iterp)314*533affcbSRobert Mustacchi nvme_log_discover_init(nvme_ctrl_t *ctrl, nvme_log_disc_scope_t scopes,
315*533affcbSRobert Mustacchi uint32_t flags, nvme_log_iter_t **iterp)
316*533affcbSRobert Mustacchi {
317*533affcbSRobert Mustacchi nvme_log_iter_t *iter;
318*533affcbSRobert Mustacchi
319*533affcbSRobert Mustacchi if (!nvme_log_discover_validate(ctrl, scopes, flags)) {
320*533affcbSRobert Mustacchi return (false);
321*533affcbSRobert Mustacchi }
322*533affcbSRobert Mustacchi
323*533affcbSRobert Mustacchi if (iterp == NULL) {
324*533affcbSRobert Mustacchi return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
325*533affcbSRobert Mustacchi "encountered invalid nvme_log_iter_t output pointer: %p",
326*533affcbSRobert Mustacchi iterp));
327*533affcbSRobert Mustacchi }
328*533affcbSRobert Mustacchi
329*533affcbSRobert Mustacchi iter = calloc(1, sizeof (nvme_log_iter_t));
330*533affcbSRobert Mustacchi if (iter == NULL) {
331*533affcbSRobert Mustacchi int e = errno;
332*533affcbSRobert Mustacchi return (nvme_ctrl_error(ctrl, NVME_ERR_NO_MEM, e, "failed to "
333*533affcbSRobert Mustacchi "allocate memory for a new nvme_log_iter_t: %s",
334*533affcbSRobert Mustacchi strerror(e)));
335*533affcbSRobert Mustacchi }
336*533affcbSRobert Mustacchi
337*533affcbSRobert Mustacchi iter->nli_ctrl = ctrl;
338*533affcbSRobert Mustacchi iter->nli_scope = scopes;
339*533affcbSRobert Mustacchi
340*533affcbSRobert Mustacchi *iterp = iter;
341*533affcbSRobert Mustacchi return (nvme_ctrl_success(ctrl));
342*533affcbSRobert Mustacchi }
343*533affcbSRobert Mustacchi
344*533affcbSRobert Mustacchi /*
345*533affcbSRobert Mustacchi * Walk all of the requested log pages that match and fill out the information
346*533affcbSRobert Mustacchi * for the discovery form.
347*533affcbSRobert Mustacchi */
348*533affcbSRobert Mustacchi bool
nvme_log_discover(nvme_ctrl_t * ctrl,nvme_log_disc_scope_t scopes,uint32_t flags,nvme_log_disc_f func,void * arg)349*533affcbSRobert Mustacchi nvme_log_discover(nvme_ctrl_t *ctrl, nvme_log_disc_scope_t scopes,
350*533affcbSRobert Mustacchi uint32_t flags, nvme_log_disc_f func, void *arg)
351*533affcbSRobert Mustacchi {
352*533affcbSRobert Mustacchi nvme_log_iter_t *iter;
353*533affcbSRobert Mustacchi nvme_iter_t ret;
354*533affcbSRobert Mustacchi const nvme_log_disc_t *disc;
355*533affcbSRobert Mustacchi
356*533affcbSRobert Mustacchi if (func == NULL) {
357*533affcbSRobert Mustacchi return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
358*533affcbSRobert Mustacchi "encountered invalid nvme_log_disc_f function pointer: %p",
359*533affcbSRobert Mustacchi func));
360*533affcbSRobert Mustacchi }
361*533affcbSRobert Mustacchi
362*533affcbSRobert Mustacchi if (!nvme_log_discover_init(ctrl, scopes, flags, &iter)) {
363*533affcbSRobert Mustacchi return (false);
364*533affcbSRobert Mustacchi }
365*533affcbSRobert Mustacchi
366*533affcbSRobert Mustacchi while ((ret = nvme_log_discover_step(iter, &disc)) == NVME_ITER_VALID) {
367*533affcbSRobert Mustacchi if (!func(ctrl, disc, arg))
368*533affcbSRobert Mustacchi break;
369*533affcbSRobert Mustacchi }
370*533affcbSRobert Mustacchi
371*533affcbSRobert Mustacchi nvme_log_discover_fini(iter);
372*533affcbSRobert Mustacchi if (ret == NVME_ITER_ERROR) {
373*533affcbSRobert Mustacchi return (false);
374*533affcbSRobert Mustacchi }
375*533affcbSRobert Mustacchi
376*533affcbSRobert Mustacchi return (nvme_ctrl_success(ctrl));
377*533affcbSRobert Mustacchi }
378*533affcbSRobert Mustacchi
379*533affcbSRobert Mustacchi
380*533affcbSRobert Mustacchi void
nvme_log_req_fini(nvme_log_req_t * req)381*533affcbSRobert Mustacchi nvme_log_req_fini(nvme_log_req_t *req)
382*533affcbSRobert Mustacchi {
383*533affcbSRobert Mustacchi free(req);
384*533affcbSRobert Mustacchi }
385*533affcbSRobert Mustacchi
386*533affcbSRobert Mustacchi /*
387*533affcbSRobert Mustacchi * This is the totally manual path that occurs. When this is used, we require
388*533affcbSRobert Mustacchi * that people specify a subset of the fields here, primarily just the actual
389*533affcbSRobert Mustacchi * log page, output, and CSI. We don't try to be clever here and use the
390*533affcbSRobert Mustacchi * discovery information to know what to set. That's reserved for creating this
391*533affcbSRobert Mustacchi * request based upon discovery information.
392*533affcbSRobert Mustacchi */
393*533affcbSRobert Mustacchi bool
nvme_log_req_init(nvme_ctrl_t * ctrl,nvme_log_req_t ** reqp)394*533affcbSRobert Mustacchi nvme_log_req_init(nvme_ctrl_t *ctrl, nvme_log_req_t **reqp)
395*533affcbSRobert Mustacchi {
396*533affcbSRobert Mustacchi nvme_log_req_t *req;
397*533affcbSRobert Mustacchi
398*533affcbSRobert Mustacchi if (reqp == NULL) {
399*533affcbSRobert Mustacchi return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
400*533affcbSRobert Mustacchi "encountered invalid nvme_log_req_t output pointer: %p",
401*533affcbSRobert Mustacchi reqp));
402*533affcbSRobert Mustacchi }
403*533affcbSRobert Mustacchi
404*533affcbSRobert Mustacchi req = calloc(1, sizeof (nvme_log_req_t));
405*533affcbSRobert Mustacchi if (req == NULL) {
406*533affcbSRobert Mustacchi int e = errno;
407*533affcbSRobert Mustacchi return (nvme_ctrl_error(ctrl, NVME_ERR_NO_MEM, e, "failed to "
408*533affcbSRobert Mustacchi "allocate memory for a new nvme_log_req_t: %s",
409*533affcbSRobert Mustacchi strerror(e)));
410*533affcbSRobert Mustacchi }
411*533affcbSRobert Mustacchi
412*533affcbSRobert Mustacchi req->nlr_ctrl = ctrl;
413*533affcbSRobert Mustacchi for (size_t i = 0; i < nvme_log_nfields; i++) {
414*533affcbSRobert Mustacchi if (nvme_log_fields[i].nlfi_def_req) {
415*533affcbSRobert Mustacchi req->nlr_need |= 1 << i;
416*533affcbSRobert Mustacchi }
417*533affcbSRobert Mustacchi
418*533affcbSRobert Mustacchi if (nvme_log_fields[i].nlfi_def_allow) {
419*533affcbSRobert Mustacchi req->nlr_allow |= 1 << i;
420*533affcbSRobert Mustacchi }
421*533affcbSRobert Mustacchi }
422*533affcbSRobert Mustacchi
423*533affcbSRobert Mustacchi /*
424*533affcbSRobert Mustacchi * Because we don't know anything about this log request, indicate that
425*533affcbSRobert Mustacchi * if we're given the all namespaces nsid that's fine. We'll still
426*533affcbSRobert Mustacchi * check the controller version when this is set first.
427*533affcbSRobert Mustacchi */
428*533affcbSRobert Mustacchi req->nlr_flags |= NVME_LOG_REQ_F_BCAST_NS_OK;
429*533affcbSRobert Mustacchi
430*533affcbSRobert Mustacchi *reqp = req;
431*533affcbSRobert Mustacchi return (nvme_ctrl_success(ctrl));
432*533affcbSRobert Mustacchi }
433*533affcbSRobert Mustacchi
434*533affcbSRobert Mustacchi bool
nvme_log_req_init_by_disc(nvme_ctrl_t * ctrl,const nvme_log_disc_t * disc,nvme_log_req_t ** reqp)435*533affcbSRobert Mustacchi nvme_log_req_init_by_disc(nvme_ctrl_t *ctrl, const nvme_log_disc_t *disc,
436*533affcbSRobert Mustacchi nvme_log_req_t **reqp)
437*533affcbSRobert Mustacchi {
438*533affcbSRobert Mustacchi nvme_log_req_t *req;
439*533affcbSRobert Mustacchi
440*533affcbSRobert Mustacchi if (disc == NULL) {
441*533affcbSRobert Mustacchi return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
442*533affcbSRobert Mustacchi "encountered invalid nvme_log_disc_t pointer: %p", disc));
443*533affcbSRobert Mustacchi }
444*533affcbSRobert Mustacchi
445*533affcbSRobert Mustacchi if (reqp == NULL) {
446*533affcbSRobert Mustacchi return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
447*533affcbSRobert Mustacchi "encountered invalid nvme_log_req_t output pointer: %p",
448*533affcbSRobert Mustacchi reqp));
449*533affcbSRobert Mustacchi }
450*533affcbSRobert Mustacchi
451*533affcbSRobert Mustacchi if ((disc->nld_flags & NVME_LOG_DISC_F_IMPL) == 0) {
452*533affcbSRobert Mustacchi return (nvme_ctrl_error(ctrl, NVME_ERR_LOG_UNSUP_BY_DEV, 0,
453*533affcbSRobert Mustacchi "cannot create log request for log %s (CSI/LID 0x%x/0x%x) "
454*533affcbSRobert Mustacchi "because it is not supported by the device",
455*533affcbSRobert Mustacchi disc->nld_short, disc->nld_csi, disc->nld_lid));
456*533affcbSRobert Mustacchi }
457*533affcbSRobert Mustacchi
458*533affcbSRobert Mustacchi req = calloc(1, sizeof (nvme_log_req_t));
459*533affcbSRobert Mustacchi if (req == NULL) {
460*533affcbSRobert Mustacchi int e = errno;
461*533affcbSRobert Mustacchi return (nvme_ctrl_error(ctrl, NVME_ERR_NO_MEM, e, "failed to "
462*533affcbSRobert Mustacchi "allocate memory for a new nvme_log_req_t: %s",
463*533affcbSRobert Mustacchi strerror(e)));
464*533affcbSRobert Mustacchi }
465*533affcbSRobert Mustacchi
466*533affcbSRobert Mustacchi req->nlr_ctrl = ctrl;
467*533affcbSRobert Mustacchi req->nlr_lid = disc->nld_lid;
468*533affcbSRobert Mustacchi req->nlr_csi = disc->nld_csi;
469*533affcbSRobert Mustacchi
470*533affcbSRobert Mustacchi /*
471*533affcbSRobert Mustacchi * Setting the size is always required here, because this is how we
472*533affcbSRobert Mustacchi * track that the output pointer is actually set. We will always allow
473*533affcbSRobert Mustacchi * setting the offset though it's possible the controller won't support
474*533affcbSRobert Mustacchi * that.
475*533affcbSRobert Mustacchi */
476*533affcbSRobert Mustacchi req->nlr_need = req->nlr_allow = 1 << NVME_LOG_REQ_FIELD_SIZE;
477*533affcbSRobert Mustacchi req->nlr_allow |= 1 << NVME_LOG_REQ_FIELD_OFFSET;
478*533affcbSRobert Mustacchi
479*533affcbSRobert Mustacchi /*
480*533affcbSRobert Mustacchi * Initialize our needed and allowed fields. Because we have the actual
481*533affcbSRobert Mustacchi * lid/csi from the above, we don't allow the user to overwrite them at
482*533affcbSRobert Mustacchi * all. For the LSP and LSI, right now these are all our nothing, but
483*533affcbSRobert Mustacchi * this may break. RAE is a bit special and discussed below.
484*533affcbSRobert Mustacchi */
485*533affcbSRobert Mustacchi if ((disc->nld_fields & NVME_LOG_DISC_F_NEED_LSP) != 0) {
486*533affcbSRobert Mustacchi req->nlr_need |= 1 << NVME_LOG_REQ_FIELD_LSP;
487*533affcbSRobert Mustacchi req->nlr_allow |= 1 << NVME_LOG_REQ_FIELD_LSP;
488*533affcbSRobert Mustacchi }
489*533affcbSRobert Mustacchi
490*533affcbSRobert Mustacchi if ((disc->nld_fields & NVME_LOG_DISC_F_NEED_LSI) != 0) {
491*533affcbSRobert Mustacchi req->nlr_need |= 1 << NVME_LOG_REQ_FIELD_LSI;
492*533affcbSRobert Mustacchi req->nlr_allow |= 1 << NVME_LOG_REQ_FIELD_LSI;
493*533affcbSRobert Mustacchi }
494*533affcbSRobert Mustacchi
495*533affcbSRobert Mustacchi /*
496*533affcbSRobert Mustacchi * Because RAE wasn't added until NVMe 1.3, we can't do much with it
497*533affcbSRobert Mustacchi * before that. However, once it's here we definitely want to default to
498*533affcbSRobert Mustacchi * setting it by default so that way we can minimize the chance that
499*533affcbSRobert Mustacchi * we'll steal an alert that the kernel needs to read and acknowledge.
500*533affcbSRobert Mustacchi */
501*533affcbSRobert Mustacchi if ((disc->nld_fields & NVME_LOG_DISC_F_NEED_RAE) != 0 &&
502*533affcbSRobert Mustacchi nvme_vers_ctrl_atleast(ctrl,
503*533affcbSRobert Mustacchi nvme_log_fields[NVME_LOG_REQ_FIELD_RAE].nlfi_vers)) {
504*533affcbSRobert Mustacchi req->nlr_flags |= NVME_LOG_REQ_F_RAE;
505*533affcbSRobert Mustacchi req->nlr_allow |= 1 << NVME_LOG_REQ_FIELD_RAE;
506*533affcbSRobert Mustacchi }
507*533affcbSRobert Mustacchi
508*533affcbSRobert Mustacchi /*
509*533affcbSRobert Mustacchi * Check the log page scope setting. If the log is said to be namespace
510*533affcbSRobert Mustacchi * scoped, then we'll allow the namespace to be specified. If it
511*533affcbSRobert Mustacchi * supports a different scope as well, then we'll default to the
512*533affcbSRobert Mustacchi * controller scope and this field is optional. Otherwise, it'll be
513*533affcbSRobert Mustacchi * required and it will be a mandatory field.
514*533affcbSRobert Mustacchi */
515*533affcbSRobert Mustacchi if ((disc->nld_scope & NVME_LOG_SCOPE_NS) != 0) {
516*533affcbSRobert Mustacchi req->nlr_allow |= 1 << NVME_LOG_REQ_FIELD_NSID;
517*533affcbSRobert Mustacchi if ((disc->nld_scope & ~NVME_LOG_SCOPE_NS) != 0) {
518*533affcbSRobert Mustacchi req->nlr_flags |= NVME_LOG_REQ_F_BCAST_NS_OK;
519*533affcbSRobert Mustacchi req->nlr_nsid = NVME_NSID_BCAST;
520*533affcbSRobert Mustacchi } else {
521*533affcbSRobert Mustacchi req->nlr_need |= 1 << NVME_LOG_REQ_FIELD_NSID;
522*533affcbSRobert Mustacchi }
523*533affcbSRobert Mustacchi }
524*533affcbSRobert Mustacchi
525*533affcbSRobert Mustacchi *reqp = req;
526*533affcbSRobert Mustacchi return (nvme_ctrl_success(ctrl));
527*533affcbSRobert Mustacchi }
528*533affcbSRobert Mustacchi
529*533affcbSRobert Mustacchi typedef struct {
530*533affcbSRobert Mustacchi bool nlia_found;
531*533affcbSRobert Mustacchi const char *nlia_name;
532*533affcbSRobert Mustacchi nvme_log_req_t *nlia_req;
533*533affcbSRobert Mustacchi nvme_log_disc_t **nlia_discp;
534*533affcbSRobert Mustacchi nvme_err_data_t nlia_err;
535*533affcbSRobert Mustacchi } nvme_log_init_arg_t;
536*533affcbSRobert Mustacchi
537*533affcbSRobert Mustacchi static bool
nvme_log_req_init_by_name_cb(nvme_ctrl_t * ctrl,const nvme_log_disc_t * disc,void * arg)538*533affcbSRobert Mustacchi nvme_log_req_init_by_name_cb(nvme_ctrl_t *ctrl, const nvme_log_disc_t *disc,
539*533affcbSRobert Mustacchi void *arg)
540*533affcbSRobert Mustacchi {
541*533affcbSRobert Mustacchi nvme_log_init_arg_t *init = arg;
542*533affcbSRobert Mustacchi
543*533affcbSRobert Mustacchi if (strcmp(init->nlia_name, disc->nld_short) != 0) {
544*533affcbSRobert Mustacchi return (true);
545*533affcbSRobert Mustacchi }
546*533affcbSRobert Mustacchi
547*533affcbSRobert Mustacchi init->nlia_found = true;
548*533affcbSRobert Mustacchi if (!nvme_log_req_init_by_disc(ctrl, disc, &init->nlia_req)) {
549*533affcbSRobert Mustacchi nvme_ctrl_err_save(ctrl, &init->nlia_err);
550*533affcbSRobert Mustacchi init->nlia_req = NULL;
551*533affcbSRobert Mustacchi } else if (init->nlia_discp != NULL) {
552*533affcbSRobert Mustacchi if (!nvme_log_disc_dup(ctrl, disc, init->nlia_discp)) {
553*533affcbSRobert Mustacchi nvme_ctrl_err_save(ctrl, &init->nlia_err);
554*533affcbSRobert Mustacchi nvme_log_req_fini(init->nlia_req);
555*533affcbSRobert Mustacchi init->nlia_req = NULL;
556*533affcbSRobert Mustacchi }
557*533affcbSRobert Mustacchi }
558*533affcbSRobert Mustacchi
559*533affcbSRobert Mustacchi return (false);
560*533affcbSRobert Mustacchi }
561*533affcbSRobert Mustacchi
562*533affcbSRobert Mustacchi bool
nvme_log_req_init_by_name(nvme_ctrl_t * ctrl,const char * name,uint32_t flags,nvme_log_disc_t ** discp,nvme_log_req_t ** reqp)563*533affcbSRobert Mustacchi nvme_log_req_init_by_name(nvme_ctrl_t *ctrl, const char *name, uint32_t flags,
564*533affcbSRobert Mustacchi nvme_log_disc_t **discp, nvme_log_req_t **reqp)
565*533affcbSRobert Mustacchi {
566*533affcbSRobert Mustacchi nvme_log_init_arg_t init;
567*533affcbSRobert Mustacchi
568*533affcbSRobert Mustacchi /*
569*533affcbSRobert Mustacchi * We consider discp an optional argument and therefore do not check it
570*533affcbSRobert Mustacchi * unlike name and reqp.
571*533affcbSRobert Mustacchi */
572*533affcbSRobert Mustacchi if (reqp == NULL) {
573*533affcbSRobert Mustacchi return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
574*533affcbSRobert Mustacchi "encountered invalid nvme_log_req_t output pointer: %p",
575*533affcbSRobert Mustacchi reqp));
576*533affcbSRobert Mustacchi }
577*533affcbSRobert Mustacchi
578*533affcbSRobert Mustacchi if (name == NULL) {
579*533affcbSRobert Mustacchi return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
580*533affcbSRobert Mustacchi "encountered invalid pointer for log page name: %p", name));
581*533affcbSRobert Mustacchi }
582*533affcbSRobert Mustacchi
583*533affcbSRobert Mustacchi (void) memset(&init, 0, sizeof (init));
584*533affcbSRobert Mustacchi init.nlia_name = name;
585*533affcbSRobert Mustacchi init.nlia_discp = discp;
586*533affcbSRobert Mustacchi
587*533affcbSRobert Mustacchi if (!nvme_log_discover(ctrl, NVME_LOG_SCOPE_CTRL |
588*533affcbSRobert Mustacchi NVME_LOG_SCOPE_NVM | NVME_LOG_SCOPE_NS, flags,
589*533affcbSRobert Mustacchi nvme_log_req_init_by_name_cb, &init)) {
590*533affcbSRobert Mustacchi return (false);
591*533affcbSRobert Mustacchi }
592*533affcbSRobert Mustacchi
593*533affcbSRobert Mustacchi if (!init.nlia_found) {
594*533affcbSRobert Mustacchi return (nvme_ctrl_error(ctrl, NVME_ERR_LOG_NAME_UNKNOWN, 0,
595*533affcbSRobert Mustacchi "failed to find log page with name %s", name));
596*533affcbSRobert Mustacchi }
597*533affcbSRobert Mustacchi
598*533affcbSRobert Mustacchi /*
599*533affcbSRobert Mustacchi * If we failed to create the request, but we did find it, then that
600*533affcbSRobert Mustacchi * means something went wrong and we can go ahead and already return an
601*533affcbSRobert Mustacchi * error.
602*533affcbSRobert Mustacchi */
603*533affcbSRobert Mustacchi if (init.nlia_req == NULL) {
604*533affcbSRobert Mustacchi nvme_ctrl_err_set(ctrl, &init.nlia_err);
605*533affcbSRobert Mustacchi return (false);
606*533affcbSRobert Mustacchi }
607*533affcbSRobert Mustacchi
608*533affcbSRobert Mustacchi *reqp = init.nlia_req;
609*533affcbSRobert Mustacchi return (nvme_ctrl_success(ctrl));
610*533affcbSRobert Mustacchi }
611*533affcbSRobert Mustacchi
612*533affcbSRobert Mustacchi static void
nvme_log_req_clear_need(nvme_log_req_t * req,nvme_log_req_field_t field)613*533affcbSRobert Mustacchi nvme_log_req_clear_need(nvme_log_req_t *req, nvme_log_req_field_t field)
614*533affcbSRobert Mustacchi {
615*533affcbSRobert Mustacchi req->nlr_need &= ~(1 << field);
616*533affcbSRobert Mustacchi }
617*533affcbSRobert Mustacchi
618*533affcbSRobert Mustacchi static const nvme_field_check_t nvme_log_check_lid = {
619*533affcbSRobert Mustacchi nvme_log_fields, NVME_LOG_REQ_FIELD_LID,
620*533affcbSRobert Mustacchi NVME_ERR_LOG_LID_RANGE, 0, 0
621*533affcbSRobert Mustacchi };
622*533affcbSRobert Mustacchi
623*533affcbSRobert Mustacchi bool
nvme_log_req_set_lid(nvme_log_req_t * req,uint32_t lid)624*533affcbSRobert Mustacchi nvme_log_req_set_lid(nvme_log_req_t *req, uint32_t lid)
625*533affcbSRobert Mustacchi {
626*533affcbSRobert Mustacchi if (!nvme_field_check_one(req->nlr_ctrl, lid, "get log page",
627*533affcbSRobert Mustacchi &nvme_log_check_lid, req->nlr_allow)) {
628*533affcbSRobert Mustacchi return (false);
629*533affcbSRobert Mustacchi }
630*533affcbSRobert Mustacchi
631*533affcbSRobert Mustacchi req->nlr_lid = lid;
632*533affcbSRobert Mustacchi nvme_log_req_clear_need(req, NVME_LOG_REQ_FIELD_LID);
633*533affcbSRobert Mustacchi return (nvme_ctrl_success(req->nlr_ctrl));
634*533affcbSRobert Mustacchi }
635*533affcbSRobert Mustacchi
636*533affcbSRobert Mustacchi static const nvme_field_check_t nvme_log_check_lsp = {
637*533affcbSRobert Mustacchi nvme_log_fields, NVME_LOG_REQ_FIELD_LSP,
638*533affcbSRobert Mustacchi NVME_ERR_LOG_LSP_RANGE, NVME_ERR_LOG_LSP_UNSUP,
639*533affcbSRobert Mustacchi NVME_ERR_LOG_LSP_UNUSE
640*533affcbSRobert Mustacchi };
641*533affcbSRobert Mustacchi
642*533affcbSRobert Mustacchi bool
nvme_log_req_set_lsp(nvme_log_req_t * req,uint32_t lsp)643*533affcbSRobert Mustacchi nvme_log_req_set_lsp(nvme_log_req_t *req, uint32_t lsp)
644*533affcbSRobert Mustacchi {
645*533affcbSRobert Mustacchi if (!nvme_field_check_one(req->nlr_ctrl, lsp, "get log page",
646*533affcbSRobert Mustacchi &nvme_log_check_lsp, req->nlr_allow)) {
647*533affcbSRobert Mustacchi return (false);
648*533affcbSRobert Mustacchi }
649*533affcbSRobert Mustacchi
650*533affcbSRobert Mustacchi req->nlr_lsp = lsp;
651*533affcbSRobert Mustacchi nvme_log_req_clear_need(req, NVME_LOG_REQ_FIELD_LSP);
652*533affcbSRobert Mustacchi return (nvme_ctrl_success(req->nlr_ctrl));
653*533affcbSRobert Mustacchi }
654*533affcbSRobert Mustacchi
655*533affcbSRobert Mustacchi static const nvme_field_check_t nvme_log_check_lsi = {
656*533affcbSRobert Mustacchi nvme_log_fields, NVME_LOG_REQ_FIELD_LSI,
657*533affcbSRobert Mustacchi NVME_ERR_LOG_LSI_RANGE, NVME_ERR_LOG_LSI_UNSUP,
658*533affcbSRobert Mustacchi NVME_ERR_LOG_LSI_UNUSE
659*533affcbSRobert Mustacchi };
660*533affcbSRobert Mustacchi
661*533affcbSRobert Mustacchi bool
nvme_log_req_set_lsi(nvme_log_req_t * req,uint32_t lsi)662*533affcbSRobert Mustacchi nvme_log_req_set_lsi(nvme_log_req_t *req, uint32_t lsi)
663*533affcbSRobert Mustacchi {
664*533affcbSRobert Mustacchi if (!nvme_field_check_one(req->nlr_ctrl, lsi, "get log page",
665*533affcbSRobert Mustacchi &nvme_log_check_lsi, req->nlr_allow)) {
666*533affcbSRobert Mustacchi return (false);
667*533affcbSRobert Mustacchi }
668*533affcbSRobert Mustacchi
669*533affcbSRobert Mustacchi req->nlr_lsi = lsi;
670*533affcbSRobert Mustacchi nvme_log_req_clear_need(req, NVME_LOG_REQ_FIELD_LSI);
671*533affcbSRobert Mustacchi return (nvme_ctrl_success(req->nlr_ctrl));
672*533affcbSRobert Mustacchi }
673*533affcbSRobert Mustacchi
674*533affcbSRobert Mustacchi static const nvme_field_check_t nvme_log_check_csi = {
675*533affcbSRobert Mustacchi nvme_log_fields, NVME_LOG_REQ_FIELD_CSI,
676*533affcbSRobert Mustacchi NVME_ERR_LOG_CSI_RANGE, NVME_ERR_LOG_CSI_UNSUP, 0
677*533affcbSRobert Mustacchi };
678*533affcbSRobert Mustacchi
679*533affcbSRobert Mustacchi bool
nvme_log_req_set_csi(nvme_log_req_t * req,uint32_t csi)680*533affcbSRobert Mustacchi nvme_log_req_set_csi(nvme_log_req_t *req, uint32_t csi)
681*533affcbSRobert Mustacchi {
682*533affcbSRobert Mustacchi if (!nvme_field_check_one(req->nlr_ctrl, csi, "get log page",
683*533affcbSRobert Mustacchi &nvme_log_check_csi, req->nlr_allow)) {
684*533affcbSRobert Mustacchi return (false);
685*533affcbSRobert Mustacchi }
686*533affcbSRobert Mustacchi
687*533affcbSRobert Mustacchi req->nlr_csi = csi;
688*533affcbSRobert Mustacchi nvme_log_req_clear_need(req, NVME_LOG_REQ_FIELD_CSI);
689*533affcbSRobert Mustacchi return (nvme_ctrl_success(req->nlr_ctrl));
690*533affcbSRobert Mustacchi }
691*533affcbSRobert Mustacchi
692*533affcbSRobert Mustacchi static const nvme_field_check_t nvme_log_check_size = {
693*533affcbSRobert Mustacchi nvme_log_fields, NVME_LOG_REQ_FIELD_SIZE,
694*533affcbSRobert Mustacchi NVME_ERR_LOG_SIZE_RANGE, 0, 0
695*533affcbSRobert Mustacchi };
696*533affcbSRobert Mustacchi
697*533affcbSRobert Mustacchi bool
nvme_log_req_set_output(nvme_log_req_t * req,void * buf,size_t buflen)698*533affcbSRobert Mustacchi nvme_log_req_set_output(nvme_log_req_t *req, void *buf, size_t buflen)
699*533affcbSRobert Mustacchi {
700*533affcbSRobert Mustacchi if (buf == NULL) {
701*533affcbSRobert Mustacchi return (nvme_ctrl_error(req->nlr_ctrl, NVME_ERR_BAD_PTR, 0,
702*533affcbSRobert Mustacchi "log request output buffer cannot be NULL"));
703*533affcbSRobert Mustacchi }
704*533affcbSRobert Mustacchi
705*533affcbSRobert Mustacchi if (!nvme_field_check_one(req->nlr_ctrl, buflen, "get log page",
706*533affcbSRobert Mustacchi &nvme_log_check_size, req->nlr_allow)) {
707*533affcbSRobert Mustacchi return (false);
708*533affcbSRobert Mustacchi }
709*533affcbSRobert Mustacchi
710*533affcbSRobert Mustacchi req->nlr_output = buf;
711*533affcbSRobert Mustacchi req->nlr_output_len = buflen;
712*533affcbSRobert Mustacchi nvme_log_req_clear_need(req, NVME_LOG_REQ_FIELD_SIZE);
713*533affcbSRobert Mustacchi return (nvme_ctrl_success(req->nlr_ctrl));
714*533affcbSRobert Mustacchi }
715*533affcbSRobert Mustacchi
716*533affcbSRobert Mustacchi static const nvme_field_check_t nvme_log_check_offset = {
717*533affcbSRobert Mustacchi nvme_log_fields, NVME_LOG_REQ_FIELD_OFFSET,
718*533affcbSRobert Mustacchi NVME_ERR_LOG_OFFSET_RANGE, 0, 0
719*533affcbSRobert Mustacchi };
720*533affcbSRobert Mustacchi
721*533affcbSRobert Mustacchi bool
nvme_log_req_set_offset(nvme_log_req_t * req,uint64_t off)722*533affcbSRobert Mustacchi nvme_log_req_set_offset(nvme_log_req_t *req, uint64_t off)
723*533affcbSRobert Mustacchi {
724*533affcbSRobert Mustacchi if (!nvme_field_check_one(req->nlr_ctrl, off, "get log page",
725*533affcbSRobert Mustacchi &nvme_log_check_offset, req->nlr_allow)) {
726*533affcbSRobert Mustacchi return (false);
727*533affcbSRobert Mustacchi }
728*533affcbSRobert Mustacchi
729*533affcbSRobert Mustacchi req->nlr_offset = off;
730*533affcbSRobert Mustacchi nvme_log_req_clear_need(req, NVME_LOG_REQ_FIELD_OFFSET);
731*533affcbSRobert Mustacchi return (nvme_ctrl_success(req->nlr_ctrl));
732*533affcbSRobert Mustacchi }
733*533affcbSRobert Mustacchi
734*533affcbSRobert Mustacchi static const nvme_field_check_t nvme_log_check_nsid = {
735*533affcbSRobert Mustacchi nvme_log_fields, NVME_LOG_REQ_FIELD_NSID, NVME_ERR_NS_RANGE, 0, 0
736*533affcbSRobert Mustacchi };
737*533affcbSRobert Mustacchi
738*533affcbSRobert Mustacchi bool
nvme_log_req_set_nsid(nvme_log_req_t * req,uint32_t nsid)739*533affcbSRobert Mustacchi nvme_log_req_set_nsid(nvme_log_req_t *req, uint32_t nsid)
740*533affcbSRobert Mustacchi {
741*533affcbSRobert Mustacchi nvme_ctrl_t *ctrl = req->nlr_ctrl;
742*533affcbSRobert Mustacchi
743*533affcbSRobert Mustacchi if (nsid == NVME_NSID_BCAST &&
744*533affcbSRobert Mustacchi (req->nlr_flags & NVME_LOG_REQ_F_BCAST_NS_OK) == 0) {
745*533affcbSRobert Mustacchi return (nvme_ctrl_error(ctrl, NVME_ERR_NS_RANGE, 0, "the all "
746*533affcbSRobert Mustacchi "namespaces/controller nsid (0x%x) is not allowed for this "
747*533affcbSRobert Mustacchi "log page, valid namespaces are [0x%x, 0x%x]", nsid,
748*533affcbSRobert Mustacchi NVME_NSID_MIN, req->nlr_ctrl->nc_info.id_nn));
749*533affcbSRobert Mustacchi }
750*533affcbSRobert Mustacchi
751*533affcbSRobert Mustacchi if (!nvme_field_check_one(req->nlr_ctrl, nsid, "get log page",
752*533affcbSRobert Mustacchi &nvme_log_check_nsid, req->nlr_allow)) {
753*533affcbSRobert Mustacchi return (false);
754*533affcbSRobert Mustacchi }
755*533affcbSRobert Mustacchi
756*533affcbSRobert Mustacchi req->nlr_nsid = nsid;
757*533affcbSRobert Mustacchi nvme_log_req_clear_need(req, NVME_LOG_REQ_FIELD_NSID);
758*533affcbSRobert Mustacchi return (nvme_ctrl_success(req->nlr_ctrl));
759*533affcbSRobert Mustacchi }
760*533affcbSRobert Mustacchi
761*533affcbSRobert Mustacchi static const nvme_field_check_t nvme_log_check_rae = {
762*533affcbSRobert Mustacchi nvme_log_fields, NVME_LOG_REQ_FIELD_RAE,
763*533affcbSRobert Mustacchi NVME_ERR_LOG_RAE_RANGE, NVME_ERR_LOG_RAE_UNSUP,
764*533affcbSRobert Mustacchi NVME_ERR_LOG_RAE_UNUSE
765*533affcbSRobert Mustacchi };
766*533affcbSRobert Mustacchi
767*533affcbSRobert Mustacchi bool
nvme_log_req_set_rae(nvme_log_req_t * req,bool rae)768*533affcbSRobert Mustacchi nvme_log_req_set_rae(nvme_log_req_t *req, bool rae)
769*533affcbSRobert Mustacchi {
770*533affcbSRobert Mustacchi if (!nvme_field_check_one(req->nlr_ctrl, rae, "get log page",
771*533affcbSRobert Mustacchi &nvme_log_check_rae, req->nlr_allow)) {
772*533affcbSRobert Mustacchi return (false);
773*533affcbSRobert Mustacchi }
774*533affcbSRobert Mustacchi
775*533affcbSRobert Mustacchi if (rae) {
776*533affcbSRobert Mustacchi req->nlr_flags |= NVME_LOG_REQ_F_RAE;
777*533affcbSRobert Mustacchi } else {
778*533affcbSRobert Mustacchi req->nlr_flags &= ~NVME_LOG_REQ_F_RAE;
779*533affcbSRobert Mustacchi }
780*533affcbSRobert Mustacchi nvme_log_req_clear_need(req, NVME_LOG_REQ_FIELD_RAE);
781*533affcbSRobert Mustacchi return (nvme_ctrl_success(req->nlr_ctrl));
782*533affcbSRobert Mustacchi }
783*533affcbSRobert Mustacchi
784*533affcbSRobert Mustacchi bool
nvme_log_req_exec(nvme_log_req_t * req)785*533affcbSRobert Mustacchi nvme_log_req_exec(nvme_log_req_t *req)
786*533affcbSRobert Mustacchi {
787*533affcbSRobert Mustacchi nvme_ctrl_t *ctrl = req->nlr_ctrl;
788*533affcbSRobert Mustacchi nvme_ioctl_get_logpage_t log;
789*533affcbSRobert Mustacchi
790*533affcbSRobert Mustacchi if (req->nlr_need != 0) {
791*533affcbSRobert Mustacchi return (nvme_field_miss_err(ctrl, nvme_log_fields,
792*533affcbSRobert Mustacchi nvme_log_nfields, NVME_ERR_LOG_REQ_MISSING_FIELDS,
793*533affcbSRobert Mustacchi "get log page", req->nlr_need));
794*533affcbSRobert Mustacchi }
795*533affcbSRobert Mustacchi
796*533affcbSRobert Mustacchi (void) memset(&log, 0, sizeof (nvme_ioctl_get_logpage_t));
797*533affcbSRobert Mustacchi log.nigl_common.nioc_nsid = req->nlr_nsid;
798*533affcbSRobert Mustacchi log.nigl_csi = req->nlr_csi;
799*533affcbSRobert Mustacchi log.nigl_lid = req->nlr_lid;
800*533affcbSRobert Mustacchi log.nigl_lsp = req->nlr_lsp;
801*533affcbSRobert Mustacchi log.nigl_lsi = req->nlr_lsi;
802*533affcbSRobert Mustacchi if ((req->nlr_flags & NVME_LOG_REQ_F_RAE) != 0) {
803*533affcbSRobert Mustacchi log.nigl_rae = 1;
804*533affcbSRobert Mustacchi }
805*533affcbSRobert Mustacchi log.nigl_len = req->nlr_output_len;
806*533affcbSRobert Mustacchi log.nigl_offset = req->nlr_offset;
807*533affcbSRobert Mustacchi log.nigl_data = (uintptr_t)req->nlr_output;
808*533affcbSRobert Mustacchi
809*533affcbSRobert Mustacchi if (ioctl(ctrl->nc_fd, NVME_IOC_GET_LOGPAGE, &log) != 0) {
810*533affcbSRobert Mustacchi int e = errno;
811*533affcbSRobert Mustacchi return (nvme_ioctl_syserror(ctrl, e, "get log page"));
812*533affcbSRobert Mustacchi }
813*533affcbSRobert Mustacchi
814*533affcbSRobert Mustacchi if (log.nigl_common.nioc_drv_err != NVME_IOCTL_E_OK) {
815*533affcbSRobert Mustacchi return (nvme_ioctl_error(ctrl, &log.nigl_common,
816*533affcbSRobert Mustacchi "get log page"));
817*533affcbSRobert Mustacchi }
818*533affcbSRobert Mustacchi
819*533affcbSRobert Mustacchi return (nvme_ctrl_success(ctrl));
820*533affcbSRobert Mustacchi }
821