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 implements the logic behind the NVMe controller information
18*533affcbSRobert Mustacchi * interface.
19*533affcbSRobert Mustacchi *
20*533affcbSRobert Mustacchi * The idea behind controller information is to gather all of the information
21*533affcbSRobert Mustacchi * related to controller information in one structure that can then be
22*533affcbSRobert Mustacchi * interrogated. This data should have its own lifetime and represents a point
23*533affcbSRobert Mustacchi * in time snapshot. This then allows this information to be saved and restored
24*533affcbSRobert Mustacchi * across systems.
25*533affcbSRobert Mustacchi */
26*533affcbSRobert Mustacchi
27*533affcbSRobert Mustacchi #include <stdlib.h>
28*533affcbSRobert Mustacchi #include <string.h>
29*533affcbSRobert Mustacchi #include <stdarg.h>
30*533affcbSRobert Mustacchi #include <sys/sysmacros.h>
31*533affcbSRobert Mustacchi
32*533affcbSRobert Mustacchi #include "libnvme_impl.h"
33*533affcbSRobert Mustacchi
34*533affcbSRobert Mustacchi bool
nvme_info_error(nvme_ctrl_info_t * ci,nvme_info_err_t err,int32_t sys,const char * fmt,...)35*533affcbSRobert Mustacchi nvme_info_error(nvme_ctrl_info_t *ci, nvme_info_err_t err, int32_t sys,
36*533affcbSRobert Mustacchi const char *fmt, ...)
37*533affcbSRobert Mustacchi {
38*533affcbSRobert Mustacchi int ret;
39*533affcbSRobert Mustacchi va_list ap;
40*533affcbSRobert Mustacchi
41*533affcbSRobert Mustacchi ci->nci_err = err;
42*533affcbSRobert Mustacchi ci->nci_syserr = sys;
43*533affcbSRobert Mustacchi va_start(ap, fmt);
44*533affcbSRobert Mustacchi ret = vsnprintf(ci->nci_errmsg, sizeof (ci->nci_errmsg), fmt, ap);
45*533affcbSRobert Mustacchi va_end(ap);
46*533affcbSRobert Mustacchi if (ret >= sizeof (ci->nci_errmsg)) {
47*533affcbSRobert Mustacchi ci->nci_errlen = sizeof (ci->nci_errmsg) - 1;
48*533affcbSRobert Mustacchi } else if (ret <= 0) {
49*533affcbSRobert Mustacchi ci->nci_errlen = 0;
50*533affcbSRobert Mustacchi ci->nci_errmsg[0] = '\0';
51*533affcbSRobert Mustacchi } else {
52*533affcbSRobert Mustacchi ci->nci_errlen = (size_t)ret;
53*533affcbSRobert Mustacchi }
54*533affcbSRobert Mustacchi
55*533affcbSRobert Mustacchi return (false);
56*533affcbSRobert Mustacchi }
57*533affcbSRobert Mustacchi
58*533affcbSRobert Mustacchi bool
nvme_info_success(nvme_ctrl_info_t * ci)59*533affcbSRobert Mustacchi nvme_info_success(nvme_ctrl_info_t *ci)
60*533affcbSRobert Mustacchi {
61*533affcbSRobert Mustacchi ci->nci_err = NVME_INFO_ERR_OK;
62*533affcbSRobert Mustacchi ci->nci_syserr = 0;
63*533affcbSRobert Mustacchi ci->nci_errmsg[0] = '\0';
64*533affcbSRobert Mustacchi ci->nci_errlen = 0;
65*533affcbSRobert Mustacchi
66*533affcbSRobert Mustacchi return (true);
67*533affcbSRobert Mustacchi }
68*533affcbSRobert Mustacchi
69*533affcbSRobert Mustacchi nvme_info_err_t
nvme_ctrl_info_err(nvme_ctrl_info_t * ci)70*533affcbSRobert Mustacchi nvme_ctrl_info_err(nvme_ctrl_info_t *ci)
71*533affcbSRobert Mustacchi {
72*533affcbSRobert Mustacchi return (ci->nci_err);
73*533affcbSRobert Mustacchi }
74*533affcbSRobert Mustacchi
75*533affcbSRobert Mustacchi int32_t
nvme_ctrl_info_syserr(nvme_ctrl_info_t * ci)76*533affcbSRobert Mustacchi nvme_ctrl_info_syserr(nvme_ctrl_info_t *ci)
77*533affcbSRobert Mustacchi {
78*533affcbSRobert Mustacchi return (ci->nci_syserr);
79*533affcbSRobert Mustacchi }
80*533affcbSRobert Mustacchi
81*533affcbSRobert Mustacchi const char *
nvme_ctrl_info_errmsg(nvme_ctrl_info_t * ci)82*533affcbSRobert Mustacchi nvme_ctrl_info_errmsg(nvme_ctrl_info_t *ci)
83*533affcbSRobert Mustacchi {
84*533affcbSRobert Mustacchi return (ci->nci_errmsg);
85*533affcbSRobert Mustacchi }
86*533affcbSRobert Mustacchi
87*533affcbSRobert Mustacchi size_t
nvme_ctrl_info_errlen(nvme_ctrl_info_t * ci)88*533affcbSRobert Mustacchi nvme_ctrl_info_errlen(nvme_ctrl_info_t *ci)
89*533affcbSRobert Mustacchi {
90*533affcbSRobert Mustacchi return (ci->nci_errlen);
91*533affcbSRobert Mustacchi }
92*533affcbSRobert Mustacchi
93*533affcbSRobert Mustacchi /*
94*533affcbSRobert Mustacchi * These errors are shared with the nvme_ns_info_t structures. While they both
95*533affcbSRobert Mustacchi * allow for us to pass in their respective information objects, that's mostly
96*533affcbSRobert Mustacchi * for future API changes. The namespace information variant of this just calls
97*533affcbSRobert Mustacchi * this function with the control information set to NULL.
98*533affcbSRobert Mustacchi */
99*533affcbSRobert Mustacchi const char *
nvme_ctrl_info_errtostr(nvme_ctrl_info_t * ci,nvme_info_err_t err)100*533affcbSRobert Mustacchi nvme_ctrl_info_errtostr(nvme_ctrl_info_t *ci, nvme_info_err_t err)
101*533affcbSRobert Mustacchi {
102*533affcbSRobert Mustacchi switch (err) {
103*533affcbSRobert Mustacchi case NVME_INFO_ERR_OK:
104*533affcbSRobert Mustacchi return ("NVME_INFO_ERR_OK");
105*533affcbSRobert Mustacchi case NVME_INFO_ERR_TRANSPORT:
106*533affcbSRobert Mustacchi return ("NVME_INFO_ERR_TRANSPORT");
107*533affcbSRobert Mustacchi case NVME_INFO_ERR_VERSION:
108*533affcbSRobert Mustacchi return ("NVME_INFO_ERR_VERSION");
109*533affcbSRobert Mustacchi case NVME_INFO_ERR_MISSING_CAP:
110*533affcbSRobert Mustacchi return ("NVME_INFO_ERR_MISSING_CAP");
111*533affcbSRobert Mustacchi case NVME_INFO_ERR_BAD_LBA_FMT:
112*533affcbSRobert Mustacchi return ("NVME_INFO_ERR_BAD_LBA_FMT");
113*533affcbSRobert Mustacchi case NVME_INFO_ERR_PERSIST_NVL:
114*533affcbSRobert Mustacchi return ("NVME_INFO_ERR_PERSIST_NVL");
115*533affcbSRobert Mustacchi case NVME_INFO_ERR_BAD_FMT:
116*533affcbSRobert Mustacchi return ("NVME_INFO_ERR_BAD_FMT");
117*533affcbSRobert Mustacchi case NVME_INFO_ERR_BAD_FMT_DATA:
118*533affcbSRobert Mustacchi return ("NVME_INFO_ERR_BAD_FMT_DATA");
119*533affcbSRobert Mustacchi case NVME_INFO_ERR_NS_INACTIVE:
120*533affcbSRobert Mustacchi return ("NVME_INFO_ERR_NS_INACTIVE");
121*533affcbSRobert Mustacchi case NVME_INFO_ERR_NS_NO_BLKDEV:
122*533affcbSRobert Mustacchi return ("NVME_INFO_ERR_NS_NO_BLKDEV");
123*533affcbSRobert Mustacchi default:
124*533affcbSRobert Mustacchi return ("unknown error");
125*533affcbSRobert Mustacchi }
126*533affcbSRobert Mustacchi }
127*533affcbSRobert Mustacchi
128*533affcbSRobert Mustacchi void
nvme_ctrl_info_free(nvme_ctrl_info_t * ci)129*533affcbSRobert Mustacchi nvme_ctrl_info_free(nvme_ctrl_info_t *ci)
130*533affcbSRobert Mustacchi {
131*533affcbSRobert Mustacchi free(ci);
132*533affcbSRobert Mustacchi }
133*533affcbSRobert Mustacchi
134*533affcbSRobert Mustacchi /*
135*533affcbSRobert Mustacchi * The caller is required to ensure that out is at least max_src + 1 bytes long.
136*533affcbSRobert Mustacchi */
137*533affcbSRobert Mustacchi static void
nvme_ctrl_info_init_ident_str(const char * src,size_t max_src,char * out)138*533affcbSRobert Mustacchi nvme_ctrl_info_init_ident_str(const char *src, size_t max_src,
139*533affcbSRobert Mustacchi char *out)
140*533affcbSRobert Mustacchi {
141*533affcbSRobert Mustacchi while (max_src > 0 && src[max_src - 1] == ' ') {
142*533affcbSRobert Mustacchi max_src--;
143*533affcbSRobert Mustacchi }
144*533affcbSRobert Mustacchi
145*533affcbSRobert Mustacchi if (max_src == 0) {
146*533affcbSRobert Mustacchi *out = '\0';
147*533affcbSRobert Mustacchi return;
148*533affcbSRobert Mustacchi }
149*533affcbSRobert Mustacchi
150*533affcbSRobert Mustacchi (void) memcpy(out, src, max_src);
151*533affcbSRobert Mustacchi out[max_src] = '\0';
152*533affcbSRobert Mustacchi }
153*533affcbSRobert Mustacchi
154*533affcbSRobert Mustacchi static void
nvme_ctrl_info_init_ident(nvme_ctrl_info_t * ci)155*533affcbSRobert Mustacchi nvme_ctrl_info_init_ident(nvme_ctrl_info_t *ci)
156*533affcbSRobert Mustacchi {
157*533affcbSRobert Mustacchi nvme_ctrl_info_init_ident_str(ci->nci_info.id_serial,
158*533affcbSRobert Mustacchi sizeof (ci->nci_info.id_serial), ci->nci_serial);
159*533affcbSRobert Mustacchi nvme_ctrl_info_init_ident_str(ci->nci_info.id_model,
160*533affcbSRobert Mustacchi sizeof (ci->nci_info.id_model), ci->nci_model);
161*533affcbSRobert Mustacchi nvme_ctrl_info_init_ident_str(ci->nci_info.id_fwrev,
162*533affcbSRobert Mustacchi sizeof (ci->nci_info.id_fwrev), ci->nci_fwrev);
163*533affcbSRobert Mustacchi }
164*533affcbSRobert Mustacchi
165*533affcbSRobert Mustacchi bool
nvme_ctrl_info_restore(nvme_t * nvme,nvlist_t * nvl,nvme_ctrl_info_t ** outp)166*533affcbSRobert Mustacchi nvme_ctrl_info_restore(nvme_t *nvme, nvlist_t *nvl, nvme_ctrl_info_t **outp)
167*533affcbSRobert Mustacchi {
168*533affcbSRobert Mustacchi int ret;
169*533affcbSRobert Mustacchi uint32_t vers;
170*533affcbSRobert Mustacchi nvme_ctrl_info_t *ci;
171*533affcbSRobert Mustacchi char *path;
172*533affcbSRobert Mustacchi uchar_t *ctrl, *ns;
173*533affcbSRobert Mustacchi uint_t ctrl_len, ns_len;
174*533affcbSRobert Mustacchi
175*533affcbSRobert Mustacchi if (nvl == NULL) {
176*533affcbSRobert Mustacchi return (nvme_error(nvme, NVME_ERR_BAD_PTR, 0, "encountered "
177*533affcbSRobert Mustacchi "invalid nvlist_t input pointer: %p", nvl));
178*533affcbSRobert Mustacchi }
179*533affcbSRobert Mustacchi
180*533affcbSRobert Mustacchi if (outp == NULL) {
181*533affcbSRobert Mustacchi return (nvme_error(nvme, NVME_ERR_BAD_PTR, 0, "encountered "
182*533affcbSRobert Mustacchi "invalid nvme_ctrl_info_t output pointer: %p", outp));
183*533affcbSRobert Mustacchi }
184*533affcbSRobert Mustacchi *outp = NULL;
185*533affcbSRobert Mustacchi
186*533affcbSRobert Mustacchi ci = calloc(1, sizeof (nvme_ctrl_info_t));
187*533affcbSRobert Mustacchi if (ci == NULL) {
188*533affcbSRobert Mustacchi int e = errno;
189*533affcbSRobert Mustacchi return (nvme_error(nvme, NVME_ERR_NO_MEM, e, "failed to "
190*533affcbSRobert Mustacchi "allocate memory for a new nvme_ctrl_info: %s",
191*533affcbSRobert Mustacchi strerror(e)));
192*533affcbSRobert Mustacchi }
193*533affcbSRobert Mustacchi
194*533affcbSRobert Mustacchi if ((ret = nvlist_lookup_uint32(nvl, NVME_NVL_CI_VERS, &vers)) != 0) {
195*533affcbSRobert Mustacchi (void) nvme_error(nvme, NVME_ERR_BAD_RESTORE, ret, "failed "
196*533affcbSRobert Mustacchi "to get version key: %s", strerror(ret));
197*533affcbSRobert Mustacchi goto err;
198*533affcbSRobert Mustacchi }
199*533affcbSRobert Mustacchi
200*533affcbSRobert Mustacchi if (vers != NVME_NVL_CI_VERS_0) {
201*533affcbSRobert Mustacchi (void) nvme_error(nvme, NVME_ERR_BAD_RESTORE, 0,
202*533affcbSRobert Mustacchi "found unsupported version key: 0x%x", vers);
203*533affcbSRobert Mustacchi goto err;
204*533affcbSRobert Mustacchi }
205*533affcbSRobert Mustacchi
206*533affcbSRobert Mustacchi ret = nvlist_lookup_pairs(nvl, 0,
207*533affcbSRobert Mustacchi NVME_NVL_CI_MAJOR, DATA_TYPE_UINT16, &ci->nci_vers.v_major,
208*533affcbSRobert Mustacchi NVME_NVL_CI_MINOR, DATA_TYPE_UINT16, &ci->nci_vers.v_minor,
209*533affcbSRobert Mustacchi NVME_NVL_CI_INST, DATA_TYPE_INT32, &ci->nci_inst,
210*533affcbSRobert Mustacchi NVME_NVL_CI_DEV_PATH, DATA_TYPE_STRING, &path,
211*533affcbSRobert Mustacchi NVME_NVL_CI_ID_CTRL, DATA_TYPE_BYTE_ARRAY, &ctrl, &ctrl_len,
212*533affcbSRobert Mustacchi NVME_NVL_CI_ID_NS, DATA_TYPE_BYTE_ARRAY, &ns, &ns_len,
213*533affcbSRobert Mustacchi NVME_NVL_CI_TPORT, DATA_TYPE_UINT32, &ci->nci_tport, NULL);
214*533affcbSRobert Mustacchi if (ret != 0) {
215*533affcbSRobert Mustacchi (void) nvme_error(nvme, NVME_ERR_BAD_RESTORE, ret,
216*533affcbSRobert Mustacchi "failed to retrieve required keys: %s", strerror(ret));
217*533affcbSRobert Mustacchi goto err;
218*533affcbSRobert Mustacchi }
219*533affcbSRobert Mustacchi
220*533affcbSRobert Mustacchi if (ci->nci_inst < 0) {
221*533affcbSRobert Mustacchi (void) nvme_error(nvme, NVME_ERR_BAD_RESTORE, 0,
222*533affcbSRobert Mustacchi "instance data is negative");
223*533affcbSRobert Mustacchi goto err;
224*533affcbSRobert Mustacchi }
225*533affcbSRobert Mustacchi
226*533affcbSRobert Mustacchi if (ctrl_len != sizeof (ci->nci_info)) {
227*533affcbSRobert Mustacchi (void) nvme_error(nvme, NVME_ERR_BAD_RESTORE, 0, "identify "
228*533affcbSRobert Mustacchi "controller information is the wrong length, expected "
229*533affcbSRobert Mustacchi "0x%zx bytes, found 0x%x", sizeof (ci->nci_info), ctrl_len);
230*533affcbSRobert Mustacchi goto err;
231*533affcbSRobert Mustacchi }
232*533affcbSRobert Mustacchi
233*533affcbSRobert Mustacchi if (ns_len != sizeof (ci->nci_ns)) {
234*533affcbSRobert Mustacchi (void) nvme_error(nvme, NVME_ERR_BAD_RESTORE, 0, "identify "
235*533affcbSRobert Mustacchi "namespace information is the wrong length, expected "
236*533affcbSRobert Mustacchi "0x%zx bytes, found 0x%x", sizeof (ci->nci_info), ctrl_len);
237*533affcbSRobert Mustacchi goto err;
238*533affcbSRobert Mustacchi }
239*533affcbSRobert Mustacchi
240*533affcbSRobert Mustacchi (void) memcpy(&ci->nci_info, ctrl, ctrl_len);
241*533affcbSRobert Mustacchi (void) memcpy(&ci->nci_ns, ns, ns_len);
242*533affcbSRobert Mustacchi
243*533affcbSRobert Mustacchi if (strlcpy(ci->nci_dev_path, path, sizeof (ci->nci_dev_path)) >=
244*533affcbSRobert Mustacchi sizeof (ci->nci_dev_path)) {
245*533affcbSRobert Mustacchi (void) nvme_error(nvme, NVME_ERR_BAD_RESTORE, 0, "device "
246*533affcbSRobert Mustacchi "path would have overflowed");
247*533affcbSRobert Mustacchi goto err;
248*533affcbSRobert Mustacchi }
249*533affcbSRobert Mustacchi
250*533affcbSRobert Mustacchi if (ci->nci_tport != NVME_CTRL_TRANSPORT_PCI) {
251*533affcbSRobert Mustacchi (void) nvme_error(nvme, NVME_ERR_BAD_RESTORE, 0, "found "
252*533affcbSRobert Mustacchi "unknown transport type: 0x%x", ci->nci_tport);
253*533affcbSRobert Mustacchi goto err;
254*533affcbSRobert Mustacchi }
255*533affcbSRobert Mustacchi
256*533affcbSRobert Mustacchi ret = nvlist_lookup_pairs(nvl, 0,
257*533affcbSRobert Mustacchi NVME_NVL_CI_PCI_VID, DATA_TYPE_UINT16, &ci->nci_vid,
258*533affcbSRobert Mustacchi NVME_NVL_CI_PCI_DID, DATA_TYPE_UINT16, &ci->nci_did,
259*533affcbSRobert Mustacchi NVME_NVL_CI_PCI_SUBVID, DATA_TYPE_UINT16, &ci->nci_subvid,
260*533affcbSRobert Mustacchi NVME_NVL_CI_PCI_SUBSYS, DATA_TYPE_UINT16, &ci->nci_subsys,
261*533affcbSRobert Mustacchi NVME_NVL_CI_PCI_REV, DATA_TYPE_UINT8, &ci->nci_rev,
262*533affcbSRobert Mustacchi NVME_NVL_CI_PCI_MPSMIN, DATA_TYPE_UINT32, &ci->nci_mps_min,
263*533affcbSRobert Mustacchi NVME_NVL_CI_PCI_MPSMAX, DATA_TYPE_UINT32, &ci->nci_mps_max,
264*533affcbSRobert Mustacchi NVME_NVL_CI_PCI_NINTRS, DATA_TYPE_UINT32, &ci->nci_nintrs, NULL);
265*533affcbSRobert Mustacchi if (ret != 0) {
266*533affcbSRobert Mustacchi (void) nvme_error(nvme, NVME_ERR_BAD_RESTORE, ret,
267*533affcbSRobert Mustacchi "failed to retrieve required PCI-specific keys: %s",
268*533affcbSRobert Mustacchi strerror(ret));
269*533affcbSRobert Mustacchi goto err;
270*533affcbSRobert Mustacchi }
271*533affcbSRobert Mustacchi
272*533affcbSRobert Mustacchi nvme_ctrl_info_init_ident(ci);
273*533affcbSRobert Mustacchi *outp = ci;
274*533affcbSRobert Mustacchi return (true);
275*533affcbSRobert Mustacchi
276*533affcbSRobert Mustacchi err:
277*533affcbSRobert Mustacchi nvme_ctrl_info_free(ci);
278*533affcbSRobert Mustacchi return (false);
279*533affcbSRobert Mustacchi }
280*533affcbSRobert Mustacchi
281*533affcbSRobert Mustacchi bool
nvme_ctrl_info_persist(nvme_ctrl_info_t * ci,nvlist_t ** nvlp)282*533affcbSRobert Mustacchi nvme_ctrl_info_persist(nvme_ctrl_info_t *ci, nvlist_t **nvlp)
283*533affcbSRobert Mustacchi {
284*533affcbSRobert Mustacchi int ret;
285*533affcbSRobert Mustacchi nvlist_t *nvl;
286*533affcbSRobert Mustacchi
287*533affcbSRobert Mustacchi if ((ret = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0) {
288*533affcbSRobert Mustacchi return (nvme_info_error(ci, NVME_INFO_ERR_PERSIST_NVL,
289*533affcbSRobert Mustacchi ret, "failed to create initial nvlist_t *: %s",
290*533affcbSRobert Mustacchi strerror(ret)));
291*533affcbSRobert Mustacchi }
292*533affcbSRobert Mustacchi
293*533affcbSRobert Mustacchi if ((ret = nvlist_add_uint32(nvl, NVME_NVL_CI_VERS,
294*533affcbSRobert Mustacchi NVME_NVL_CI_VERS_0)) != 0) {
295*533affcbSRobert Mustacchi return (nvme_info_error(ci, NVME_INFO_ERR_PERSIST_NVL, ret,
296*533affcbSRobert Mustacchi "failed to persist %s to nvlist: %s", NVME_NVL_CI_VERS,
297*533affcbSRobert Mustacchi strerror(ret)));
298*533affcbSRobert Mustacchi }
299*533affcbSRobert Mustacchi
300*533affcbSRobert Mustacchi if ((ret = nvlist_add_int32(nvl, NVME_NVL_CI_INST, ci->nci_inst)) !=
301*533affcbSRobert Mustacchi 0) {
302*533affcbSRobert Mustacchi return (nvme_info_error(ci, NVME_INFO_ERR_PERSIST_NVL, ret,
303*533affcbSRobert Mustacchi "failed to persist %s to nvlist: %s", NVME_NVL_CI_INST,
304*533affcbSRobert Mustacchi strerror(ret)));
305*533affcbSRobert Mustacchi }
306*533affcbSRobert Mustacchi
307*533affcbSRobert Mustacchi if ((ret = nvlist_add_uint16(nvl, NVME_NVL_CI_MAJOR,
308*533affcbSRobert Mustacchi ci->nci_vers.v_major)) != 0 ||
309*533affcbSRobert Mustacchi (ret = nvlist_add_uint16(nvl, NVME_NVL_CI_MINOR,
310*533affcbSRobert Mustacchi ci->nci_vers.v_minor)) != 0) {
311*533affcbSRobert Mustacchi return (nvme_info_error(ci, NVME_INFO_ERR_PERSIST_NVL, ret,
312*533affcbSRobert Mustacchi "failed to persist version data to nvlist: %s",
313*533affcbSRobert Mustacchi strerror(ret)));
314*533affcbSRobert Mustacchi }
315*533affcbSRobert Mustacchi
316*533affcbSRobert Mustacchi if ((ret = nvlist_add_string(nvl, NVME_NVL_CI_DEV_PATH,
317*533affcbSRobert Mustacchi ci->nci_dev_path)) != 0) {
318*533affcbSRobert Mustacchi return (nvme_info_error(ci, NVME_INFO_ERR_PERSIST_NVL, ret,
319*533affcbSRobert Mustacchi "failed to persist %s to nvlist: %s", NVME_NVL_CI_DEV_PATH,
320*533affcbSRobert Mustacchi strerror(ret)));
321*533affcbSRobert Mustacchi }
322*533affcbSRobert Mustacchi
323*533affcbSRobert Mustacchi if ((ret = nvlist_add_byte_array(nvl, NVME_NVL_CI_ID_CTRL,
324*533affcbSRobert Mustacchi (void *)&ci->nci_info, sizeof (ci->nci_info))) != 0) {
325*533affcbSRobert Mustacchi return (nvme_info_error(ci, NVME_INFO_ERR_PERSIST_NVL, ret,
326*533affcbSRobert Mustacchi "failed to persist %s to nvlist: %s", NVME_NVL_CI_ID_CTRL,
327*533affcbSRobert Mustacchi strerror(ret)));
328*533affcbSRobert Mustacchi }
329*533affcbSRobert Mustacchi
330*533affcbSRobert Mustacchi if ((ret = nvlist_add_byte_array(nvl, NVME_NVL_CI_ID_NS,
331*533affcbSRobert Mustacchi (void *)&ci->nci_ns, sizeof (ci->nci_ns))) != 0) {
332*533affcbSRobert Mustacchi return (nvme_info_error(ci, NVME_INFO_ERR_PERSIST_NVL, ret,
333*533affcbSRobert Mustacchi "failed to persist %s to nvlist: %s", NVME_NVL_CI_ID_NS,
334*533affcbSRobert Mustacchi strerror(ret)));
335*533affcbSRobert Mustacchi }
336*533affcbSRobert Mustacchi
337*533affcbSRobert Mustacchi if ((ret = nvlist_add_uint32(nvl, NVME_NVL_CI_TPORT, ci->nci_tport)) !=
338*533affcbSRobert Mustacchi 0) {
339*533affcbSRobert Mustacchi return (nvme_info_error(ci, NVME_INFO_ERR_PERSIST_NVL, ret,
340*533affcbSRobert Mustacchi "failed to persist %s to nvlist: %s", NVME_NVL_CI_TPORT,
341*533affcbSRobert Mustacchi strerror(ret)));
342*533affcbSRobert Mustacchi }
343*533affcbSRobert Mustacchi
344*533affcbSRobert Mustacchi if ((ret = nvlist_add_uint16(nvl, NVME_NVL_CI_PCI_VID,
345*533affcbSRobert Mustacchi ci->nci_vid)) != 0 ||
346*533affcbSRobert Mustacchi (ret = nvlist_add_uint16(nvl, NVME_NVL_CI_PCI_DID,
347*533affcbSRobert Mustacchi ci->nci_did)) != 0 ||
348*533affcbSRobert Mustacchi (ret = nvlist_add_uint16(nvl, NVME_NVL_CI_PCI_SUBVID,
349*533affcbSRobert Mustacchi ci->nci_subvid)) != 0 ||
350*533affcbSRobert Mustacchi (ret = nvlist_add_uint16(nvl, NVME_NVL_CI_PCI_SUBSYS,
351*533affcbSRobert Mustacchi ci->nci_subsys)) != 0 ||
352*533affcbSRobert Mustacchi (ret = nvlist_add_uint8(nvl, NVME_NVL_CI_PCI_REV,
353*533affcbSRobert Mustacchi ci->nci_rev)) != 0 ||
354*533affcbSRobert Mustacchi (ret = nvlist_add_uint32(nvl, NVME_NVL_CI_PCI_MPSMIN,
355*533affcbSRobert Mustacchi ci->nci_mps_min)) != 0 ||
356*533affcbSRobert Mustacchi (ret = nvlist_add_uint32(nvl, NVME_NVL_CI_PCI_MPSMAX,
357*533affcbSRobert Mustacchi ci->nci_mps_max)) != 0 ||
358*533affcbSRobert Mustacchi (ret = nvlist_add_uint32(nvl, NVME_NVL_CI_PCI_NINTRS,
359*533affcbSRobert Mustacchi ci->nci_nintrs)) != 0) {
360*533affcbSRobert Mustacchi return (nvme_info_error(ci, NVME_INFO_ERR_PERSIST_NVL, ret,
361*533affcbSRobert Mustacchi "failed to persist PCI data to nvlist: %s", strerror(ret)));
362*533affcbSRobert Mustacchi }
363*533affcbSRobert Mustacchi
364*533affcbSRobert Mustacchi *nvlp = nvl;
365*533affcbSRobert Mustacchi return (true);
366*533affcbSRobert Mustacchi }
367*533affcbSRobert Mustacchi
368*533affcbSRobert Mustacchi static bool
nvme_ctrl_get_udi(nvme_ctrl_t * ctrl,di_node_t di,const char * prop,uint32_t * outp,uint32_t max)369*533affcbSRobert Mustacchi nvme_ctrl_get_udi(nvme_ctrl_t *ctrl, di_node_t di, const char *prop,
370*533affcbSRobert Mustacchi uint32_t *outp, uint32_t max)
371*533affcbSRobert Mustacchi {
372*533affcbSRobert Mustacchi int *vals, nvals;
373*533affcbSRobert Mustacchi
374*533affcbSRobert Mustacchi nvals = di_prop_lookup_ints(DDI_DEV_T_ANY, di, prop, &vals);
375*533affcbSRobert Mustacchi if (nvals < 0) {
376*533affcbSRobert Mustacchi int e = errno;
377*533affcbSRobert Mustacchi return (nvme_ctrl_error(ctrl, NVME_ERR_LIBDEVINFO, e, "failed "
378*533affcbSRobert Mustacchi "to get property %s while constructing controller "
379*533affcbSRobert Mustacchi "information: %s", prop, strerror(e)));
380*533affcbSRobert Mustacchi } else if (nvals != 1) {
381*533affcbSRobert Mustacchi return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_DEVI_PROP, 0,
382*533affcbSRobert Mustacchi "found unexpected number of property values for %s while "
383*533affcbSRobert Mustacchi "constructing controller information, expected 1, found %d",
384*533affcbSRobert Mustacchi prop, nvals));
385*533affcbSRobert Mustacchi }
386*533affcbSRobert Mustacchi
387*533affcbSRobert Mustacchi if (vals[0] < 0 || vals[0] > max) {
388*533affcbSRobert Mustacchi return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_DEVI_PROP, 0,
389*533affcbSRobert Mustacchi "property %s has value 0x%x outside the allowed range "
390*533affcbSRobert Mustacchi "[0x0, 0x%x]", prop, vals[0], max));
391*533affcbSRobert Mustacchi }
392*533affcbSRobert Mustacchi
393*533affcbSRobert Mustacchi *outp = (uint32_t)vals[0];
394*533affcbSRobert Mustacchi return (true);
395*533affcbSRobert Mustacchi }
396*533affcbSRobert Mustacchi
397*533affcbSRobert Mustacchi bool
nvme_ctrl_info_snap(nvme_ctrl_t * ctrl,nvme_ctrl_info_t ** outp)398*533affcbSRobert Mustacchi nvme_ctrl_info_snap(nvme_ctrl_t *ctrl, nvme_ctrl_info_t **outp)
399*533affcbSRobert Mustacchi {
400*533affcbSRobert Mustacchi nvme_ctrl_info_t *ci;
401*533affcbSRobert Mustacchi uint32_t val;
402*533affcbSRobert Mustacchi nvme_ioctl_ctrl_info_t info;
403*533affcbSRobert Mustacchi
404*533affcbSRobert Mustacchi if (outp == NULL) {
405*533affcbSRobert Mustacchi return (nvme_ctrl_error(ctrl, NVME_ERR_BAD_PTR, 0,
406*533affcbSRobert Mustacchi "encountered invalid nvme_ctrl_info_t output pointer: %p",
407*533affcbSRobert Mustacchi outp));
408*533affcbSRobert Mustacchi }
409*533affcbSRobert Mustacchi *outp = NULL;
410*533affcbSRobert Mustacchi
411*533affcbSRobert Mustacchi ci = calloc(1, sizeof (nvme_ctrl_info_t));
412*533affcbSRobert Mustacchi if (ci == NULL) {
413*533affcbSRobert Mustacchi int e = errno;
414*533affcbSRobert Mustacchi return (nvme_ctrl_error(ctrl, NVME_ERR_NO_MEM, e, "failed to "
415*533affcbSRobert Mustacchi "allocate memory for a new nvme_ctrl_info: %s",
416*533affcbSRobert Mustacchi strerror(e)));
417*533affcbSRobert Mustacchi }
418*533affcbSRobert Mustacchi
419*533affcbSRobert Mustacchi if (!nvme_ctrl_get_udi(ctrl, ctrl->nc_devi, "vendor-id", &val,
420*533affcbSRobert Mustacchi UINT16_MAX)) {
421*533affcbSRobert Mustacchi goto err;
422*533affcbSRobert Mustacchi }
423*533affcbSRobert Mustacchi ci->nci_vid = (uint16_t)val;
424*533affcbSRobert Mustacchi
425*533affcbSRobert Mustacchi if (!nvme_ctrl_get_udi(ctrl, ctrl->nc_devi, "device-id", &val,
426*533affcbSRobert Mustacchi UINT16_MAX)) {
427*533affcbSRobert Mustacchi goto err;
428*533affcbSRobert Mustacchi }
429*533affcbSRobert Mustacchi ci->nci_did = (uint16_t)val;
430*533affcbSRobert Mustacchi
431*533affcbSRobert Mustacchi /*
432*533affcbSRobert Mustacchi * The system will not create a subsystem-vendor-id or a subsystem-id if
433*533affcbSRobert Mustacchi * the subsytem vendor is zero. This should not be a fatal error.
434*533affcbSRobert Mustacchi * However, if a subsytem-vendor-id is present then we should expect a
435*533affcbSRobert Mustacchi * subsystem-id.
436*533affcbSRobert Mustacchi */
437*533affcbSRobert Mustacchi if (nvme_ctrl_get_udi(ctrl, ctrl->nc_devi, "subsystem-vendor-id", &val,
438*533affcbSRobert Mustacchi UINT16_MAX)) {
439*533affcbSRobert Mustacchi ci->nci_subvid = (uint16_t)val;
440*533affcbSRobert Mustacchi
441*533affcbSRobert Mustacchi if (!nvme_ctrl_get_udi(ctrl, ctrl->nc_devi, "subsystem-id",
442*533affcbSRobert Mustacchi &val, UINT16_MAX)) {
443*533affcbSRobert Mustacchi goto err;
444*533affcbSRobert Mustacchi }
445*533affcbSRobert Mustacchi } else {
446*533affcbSRobert Mustacchi ci->nci_subvid = 0;
447*533affcbSRobert Mustacchi ci->nci_subsys = 0;
448*533affcbSRobert Mustacchi }
449*533affcbSRobert Mustacchi
450*533affcbSRobert Mustacchi if (!nvme_ctrl_get_udi(ctrl, ctrl->nc_devi, "revision-id", &val,
451*533affcbSRobert Mustacchi UINT8_MAX)) {
452*533affcbSRobert Mustacchi goto err;
453*533affcbSRobert Mustacchi }
454*533affcbSRobert Mustacchi ci->nci_rev = (uint8_t)val;
455*533affcbSRobert Mustacchi
456*533affcbSRobert Mustacchi /*
457*533affcbSRobert Mustacchi * As we only support PCI based NVMe devices right now, we simply always
458*533affcbSRobert Mustacchi * identify everything as PCI based. In the future, this would be
459*533affcbSRobert Mustacchi * something we'd want to get from either an ioctl or a devinfo
460*533affcbSRobert Mustacchi * property.
461*533affcbSRobert Mustacchi */
462*533affcbSRobert Mustacchi ci->nci_tport = NVME_CTRL_TRANSPORT_PCI;
463*533affcbSRobert Mustacchi
464*533affcbSRobert Mustacchi if (!nvme_ioc_ctrl_info(ctrl, &info)) {
465*533affcbSRobert Mustacchi goto err;
466*533affcbSRobert Mustacchi }
467*533affcbSRobert Mustacchi
468*533affcbSRobert Mustacchi ci->nci_vers = info.nci_vers;
469*533affcbSRobert Mustacchi ci->nci_info = info.nci_ctrl_id;
470*533affcbSRobert Mustacchi ci->nci_ns = info.nci_common_ns;
471*533affcbSRobert Mustacchi ci->nci_mps_min = info.nci_caps.cap_mpsmin;
472*533affcbSRobert Mustacchi ci->nci_mps_max = info.nci_caps.cap_mpsmax;
473*533affcbSRobert Mustacchi ci->nci_nintrs = info.nci_nintrs;
474*533affcbSRobert Mustacchi
475*533affcbSRobert Mustacchi nvme_ctrl_info_init_ident(ci);
476*533affcbSRobert Mustacchi *outp = ci;
477*533affcbSRobert Mustacchi return (nvme_ctrl_success(ctrl));
478*533affcbSRobert Mustacchi
479*533affcbSRobert Mustacchi err:
480*533affcbSRobert Mustacchi nvme_ctrl_info_free(ci);
481*533affcbSRobert Mustacchi return (false);
482*533affcbSRobert Mustacchi }
483*533affcbSRobert Mustacchi
484*533affcbSRobert Mustacchi uint16_t
nvme_ctrl_info_vendor(nvme_ctrl_info_t * ci)485*533affcbSRobert Mustacchi nvme_ctrl_info_vendor(nvme_ctrl_info_t *ci)
486*533affcbSRobert Mustacchi {
487*533affcbSRobert Mustacchi return (ci->nci_info.id_vid);
488*533affcbSRobert Mustacchi }
489*533affcbSRobert Mustacchi
490*533affcbSRobert Mustacchi const char *
nvme_ctrl_info_model(nvme_ctrl_info_t * ci)491*533affcbSRobert Mustacchi nvme_ctrl_info_model(nvme_ctrl_info_t *ci)
492*533affcbSRobert Mustacchi {
493*533affcbSRobert Mustacchi return (ci->nci_model);
494*533affcbSRobert Mustacchi }
495*533affcbSRobert Mustacchi
496*533affcbSRobert Mustacchi const char *
nvme_ctrl_info_serial(nvme_ctrl_info_t * ci)497*533affcbSRobert Mustacchi nvme_ctrl_info_serial(nvme_ctrl_info_t *ci)
498*533affcbSRobert Mustacchi {
499*533affcbSRobert Mustacchi return (ci->nci_serial);
500*533affcbSRobert Mustacchi }
501*533affcbSRobert Mustacchi
502*533affcbSRobert Mustacchi const char *
nvme_ctrl_info_fwrev(nvme_ctrl_info_t * ci)503*533affcbSRobert Mustacchi nvme_ctrl_info_fwrev(nvme_ctrl_info_t *ci)
504*533affcbSRobert Mustacchi {
505*533affcbSRobert Mustacchi return (ci->nci_fwrev);
506*533affcbSRobert Mustacchi }
507*533affcbSRobert Mustacchi
508*533affcbSRobert Mustacchi const nvme_identify_ctrl_t *
nvme_ctrl_info_identify(nvme_ctrl_info_t * ci)509*533affcbSRobert Mustacchi nvme_ctrl_info_identify(nvme_ctrl_info_t *ci)
510*533affcbSRobert Mustacchi {
511*533affcbSRobert Mustacchi return (&ci->nci_info);
512*533affcbSRobert Mustacchi }
513*533affcbSRobert Mustacchi
514*533affcbSRobert Mustacchi const nvme_version_t *
nvme_ctrl_info_version(nvme_ctrl_info_t * ci)515*533affcbSRobert Mustacchi nvme_ctrl_info_version(nvme_ctrl_info_t *ci)
516*533affcbSRobert Mustacchi {
517*533affcbSRobert Mustacchi return (&ci->nci_vers);
518*533affcbSRobert Mustacchi }
519*533affcbSRobert Mustacchi
520*533affcbSRobert Mustacchi nvme_ctrl_transport_t
nvme_ctrl_info_transport(nvme_ctrl_info_t * ci)521*533affcbSRobert Mustacchi nvme_ctrl_info_transport(nvme_ctrl_info_t *ci)
522*533affcbSRobert Mustacchi {
523*533affcbSRobert Mustacchi return (ci->nci_tport);
524*533affcbSRobert Mustacchi }
525*533affcbSRobert Mustacchi
526*533affcbSRobert Mustacchi nvme_ctrl_type_t
nvme_ctrl_info_type(nvme_ctrl_info_t * ci)527*533affcbSRobert Mustacchi nvme_ctrl_info_type(nvme_ctrl_info_t *ci)
528*533affcbSRobert Mustacchi {
529*533affcbSRobert Mustacchi if (nvme_vers_ctrl_info_atleast(ci, &nvme_vers_1v4)) {
530*533affcbSRobert Mustacchi switch (ci->nci_info.id_cntrltype) {
531*533affcbSRobert Mustacchi case NVME_CNTRLTYPE_IO:
532*533affcbSRobert Mustacchi return (NVME_CTRL_TYPE_IO);
533*533affcbSRobert Mustacchi case NVME_CNTRLTYPE_DISC:
534*533affcbSRobert Mustacchi return (NVME_CTRL_TYPE_DISCOVERY);
535*533affcbSRobert Mustacchi case NVME_CNTRLTYPE_ADMIN:
536*533affcbSRobert Mustacchi return (NVME_CTRL_TYPE_ADMIN);
537*533affcbSRobert Mustacchi default:
538*533affcbSRobert Mustacchi return (NVME_CTRL_TYPE_UNKNOWN);
539*533affcbSRobert Mustacchi }
540*533affcbSRobert Mustacchi } else {
541*533affcbSRobert Mustacchi return (NVME_CTRL_TYPE_IO);
542*533affcbSRobert Mustacchi }
543*533affcbSRobert Mustacchi }
544*533affcbSRobert Mustacchi
545*533affcbSRobert Mustacchi static bool
nvme_ctrl_info_pci_tport(nvme_ctrl_info_t * ci)546*533affcbSRobert Mustacchi nvme_ctrl_info_pci_tport(nvme_ctrl_info_t *ci)
547*533affcbSRobert Mustacchi {
548*533affcbSRobert Mustacchi if (ci->nci_tport != NVME_CTRL_TRANSPORT_PCI) {
549*533affcbSRobert Mustacchi return (nvme_info_error(ci, NVME_INFO_ERR_TRANSPORT, 0,
550*533affcbSRobert Mustacchi "cannot get PCI data from device with type %s (0x%x)",
551*533affcbSRobert Mustacchi nvme_tporttostr(ci->nci_tport), ci->nci_tport));
552*533affcbSRobert Mustacchi }
553*533affcbSRobert Mustacchi
554*533affcbSRobert Mustacchi return (true);
555*533affcbSRobert Mustacchi }
556*533affcbSRobert Mustacchi
557*533affcbSRobert Mustacchi bool
nvme_ctrl_info_pci_vid(nvme_ctrl_info_t * ci,uint16_t * u16p)558*533affcbSRobert Mustacchi nvme_ctrl_info_pci_vid(nvme_ctrl_info_t *ci, uint16_t *u16p)
559*533affcbSRobert Mustacchi {
560*533affcbSRobert Mustacchi if (!nvme_ctrl_info_pci_tport(ci))
561*533affcbSRobert Mustacchi return (false);
562*533affcbSRobert Mustacchi
563*533affcbSRobert Mustacchi *u16p = ci->nci_vid;
564*533affcbSRobert Mustacchi return (nvme_info_success(ci));
565*533affcbSRobert Mustacchi }
566*533affcbSRobert Mustacchi
567*533affcbSRobert Mustacchi bool
nvme_ctrl_info_pci_did(nvme_ctrl_info_t * ci,uint16_t * u16p)568*533affcbSRobert Mustacchi nvme_ctrl_info_pci_did(nvme_ctrl_info_t *ci, uint16_t *u16p)
569*533affcbSRobert Mustacchi {
570*533affcbSRobert Mustacchi if (!nvme_ctrl_info_pci_tport(ci))
571*533affcbSRobert Mustacchi return (false);
572*533affcbSRobert Mustacchi
573*533affcbSRobert Mustacchi *u16p = ci->nci_did;
574*533affcbSRobert Mustacchi return (nvme_info_success(ci));
575*533affcbSRobert Mustacchi }
576*533affcbSRobert Mustacchi
577*533affcbSRobert Mustacchi bool
nvme_ctrl_info_pci_subvid(nvme_ctrl_info_t * ci,uint16_t * u16p)578*533affcbSRobert Mustacchi nvme_ctrl_info_pci_subvid(nvme_ctrl_info_t *ci, uint16_t *u16p)
579*533affcbSRobert Mustacchi {
580*533affcbSRobert Mustacchi if (!nvme_ctrl_info_pci_tport(ci))
581*533affcbSRobert Mustacchi return (false);
582*533affcbSRobert Mustacchi
583*533affcbSRobert Mustacchi *u16p = ci->nci_subvid;
584*533affcbSRobert Mustacchi return (nvme_info_success(ci));
585*533affcbSRobert Mustacchi }
586*533affcbSRobert Mustacchi
587*533affcbSRobert Mustacchi bool
nvme_ctrl_info_pci_subsys(nvme_ctrl_info_t * ci,uint16_t * u16p)588*533affcbSRobert Mustacchi nvme_ctrl_info_pci_subsys(nvme_ctrl_info_t *ci, uint16_t *u16p)
589*533affcbSRobert Mustacchi {
590*533affcbSRobert Mustacchi if (!nvme_ctrl_info_pci_tport(ci))
591*533affcbSRobert Mustacchi return (false);
592*533affcbSRobert Mustacchi
593*533affcbSRobert Mustacchi *u16p = ci->nci_subsys;
594*533affcbSRobert Mustacchi return (nvme_info_success(ci));
595*533affcbSRobert Mustacchi }
596*533affcbSRobert Mustacchi
597*533affcbSRobert Mustacchi bool
nvme_ctrl_info_pci_rev(nvme_ctrl_info_t * ci,uint8_t * u8p)598*533affcbSRobert Mustacchi nvme_ctrl_info_pci_rev(nvme_ctrl_info_t *ci, uint8_t *u8p)
599*533affcbSRobert Mustacchi {
600*533affcbSRobert Mustacchi if (!nvme_ctrl_info_pci_tport(ci))
601*533affcbSRobert Mustacchi return (false);
602*533affcbSRobert Mustacchi
603*533affcbSRobert Mustacchi *u8p = ci->nci_rev;
604*533affcbSRobert Mustacchi return (nvme_info_success(ci));
605*533affcbSRobert Mustacchi }
606*533affcbSRobert Mustacchi
607*533affcbSRobert Mustacchi bool
nvme_ctrl_info_pci_mps_min(nvme_ctrl_info_t * ci,uint32_t * u32p)608*533affcbSRobert Mustacchi nvme_ctrl_info_pci_mps_min(nvme_ctrl_info_t *ci, uint32_t *u32p)
609*533affcbSRobert Mustacchi {
610*533affcbSRobert Mustacchi if (!nvme_ctrl_info_pci_tport(ci))
611*533affcbSRobert Mustacchi return (false);
612*533affcbSRobert Mustacchi
613*533affcbSRobert Mustacchi *u32p = ci->nci_mps_min;
614*533affcbSRobert Mustacchi return (nvme_info_success(ci));
615*533affcbSRobert Mustacchi }
616*533affcbSRobert Mustacchi
617*533affcbSRobert Mustacchi bool
nvme_ctrl_info_pci_mps_max(nvme_ctrl_info_t * ci,uint32_t * u32p)618*533affcbSRobert Mustacchi nvme_ctrl_info_pci_mps_max(nvme_ctrl_info_t *ci, uint32_t *u32p)
619*533affcbSRobert Mustacchi {
620*533affcbSRobert Mustacchi if (!nvme_ctrl_info_pci_tport(ci))
621*533affcbSRobert Mustacchi return (false);
622*533affcbSRobert Mustacchi
623*533affcbSRobert Mustacchi *u32p = ci->nci_mps_max;
624*533affcbSRobert Mustacchi return (nvme_info_success(ci));
625*533affcbSRobert Mustacchi }
626*533affcbSRobert Mustacchi
627*533affcbSRobert Mustacchi bool
nvme_ctrl_info_pci_nintrs(nvme_ctrl_info_t * ci,uint32_t * u32p)628*533affcbSRobert Mustacchi nvme_ctrl_info_pci_nintrs(nvme_ctrl_info_t *ci, uint32_t *u32p)
629*533affcbSRobert Mustacchi {
630*533affcbSRobert Mustacchi if (!nvme_ctrl_info_pci_tport(ci))
631*533affcbSRobert Mustacchi return (false);
632*533affcbSRobert Mustacchi
633*533affcbSRobert Mustacchi *u32p = ci->nci_nintrs;
634*533affcbSRobert Mustacchi return (nvme_info_success(ci));
635*533affcbSRobert Mustacchi }
636*533affcbSRobert Mustacchi
637*533affcbSRobert Mustacchi static bool
nvme_ctrl_info_nsmgmt(nvme_ctrl_info_t * ci)638*533affcbSRobert Mustacchi nvme_ctrl_info_nsmgmt(nvme_ctrl_info_t *ci)
639*533affcbSRobert Mustacchi {
640*533affcbSRobert Mustacchi if (!nvme_vers_ctrl_info_atleast(ci, &nvme_vers_1v2)) {
641*533affcbSRobert Mustacchi return (nvme_info_error(ci, NVME_INFO_ERR_VERSION, 0,
642*533affcbSRobert Mustacchi "cannot provide information, device must be at least "
643*533affcbSRobert Mustacchi "version 1.2, but is %u.%u", ci->nci_vers.v_major,
644*533affcbSRobert Mustacchi ci->nci_vers.v_minor));
645*533affcbSRobert Mustacchi }
646*533affcbSRobert Mustacchi
647*533affcbSRobert Mustacchi if (ci->nci_info.id_oacs.oa_nsmgmt == 0) {
648*533affcbSRobert Mustacchi return (nvme_info_error(ci, NVME_INFO_ERR_MISSING_CAP, 0,
649*533affcbSRobert Mustacchi "cannot provide information, device does not support "
650*533affcbSRobert Mustacchi "namespace management"));
651*533affcbSRobert Mustacchi
652*533affcbSRobert Mustacchi }
653*533affcbSRobert Mustacchi
654*533affcbSRobert Mustacchi return (true);
655*533affcbSRobert Mustacchi }
656*533affcbSRobert Mustacchi
657*533affcbSRobert Mustacchi bool
nvme_ctrl_info_cap(nvme_ctrl_info_t * ci,nvme_uint128_t * u128p)658*533affcbSRobert Mustacchi nvme_ctrl_info_cap(nvme_ctrl_info_t *ci, nvme_uint128_t *u128p)
659*533affcbSRobert Mustacchi {
660*533affcbSRobert Mustacchi if (!nvme_ctrl_info_nsmgmt(ci)) {
661*533affcbSRobert Mustacchi return (false);
662*533affcbSRobert Mustacchi }
663*533affcbSRobert Mustacchi
664*533affcbSRobert Mustacchi (void) memcpy(u128p, &ci->nci_info.ap_tnvmcap, sizeof (nvme_uint128_t));
665*533affcbSRobert Mustacchi return (nvme_info_success(ci));
666*533affcbSRobert Mustacchi }
667*533affcbSRobert Mustacchi
668*533affcbSRobert Mustacchi bool
nvme_ctrl_info_unalloc_cap(nvme_ctrl_info_t * ci,nvme_uint128_t * u128p)669*533affcbSRobert Mustacchi nvme_ctrl_info_unalloc_cap(nvme_ctrl_info_t *ci, nvme_uint128_t *u128p)
670*533affcbSRobert Mustacchi {
671*533affcbSRobert Mustacchi if (!nvme_ctrl_info_nsmgmt(ci)) {
672*533affcbSRobert Mustacchi return (false);
673*533affcbSRobert Mustacchi }
674*533affcbSRobert Mustacchi
675*533affcbSRobert Mustacchi (void) memcpy(u128p, &ci->nci_info.ap_unvmcap, sizeof (nvme_uint128_t));
676*533affcbSRobert Mustacchi return (nvme_info_success(ci));
677*533affcbSRobert Mustacchi }
678*533affcbSRobert Mustacchi
679*533affcbSRobert Mustacchi bool
nvme_ctrl_info_common_ns(nvme_ctrl_info_t * ci,const nvme_identify_nsid_t ** idp)680*533affcbSRobert Mustacchi nvme_ctrl_info_common_ns(nvme_ctrl_info_t *ci, const nvme_identify_nsid_t **idp)
681*533affcbSRobert Mustacchi {
682*533affcbSRobert Mustacchi if (!nvme_ctrl_info_nsmgmt(ci)) {
683*533affcbSRobert Mustacchi return (false);
684*533affcbSRobert Mustacchi }
685*533affcbSRobert Mustacchi
686*533affcbSRobert Mustacchi *idp = &ci->nci_ns;
687*533affcbSRobert Mustacchi return (nvme_info_success(ci));
688*533affcbSRobert Mustacchi }
689*533affcbSRobert Mustacchi
690*533affcbSRobert Mustacchi uint32_t
nvme_ctrl_info_nformats(nvme_ctrl_info_t * ci)691*533affcbSRobert Mustacchi nvme_ctrl_info_nformats(nvme_ctrl_info_t *ci)
692*533affcbSRobert Mustacchi {
693*533affcbSRobert Mustacchi return (MIN(ci->nci_ns.id_nlbaf + 1, NVME_MAX_LBAF));
694*533affcbSRobert Mustacchi }
695*533affcbSRobert Mustacchi
696*533affcbSRobert Mustacchi uint32_t
nvme_ctrl_info_nns(nvme_ctrl_info_t * ci)697*533affcbSRobert Mustacchi nvme_ctrl_info_nns(nvme_ctrl_info_t *ci)
698*533affcbSRobert Mustacchi {
699*533affcbSRobert Mustacchi return (ci->nci_info.id_nn);
700*533affcbSRobert Mustacchi }
701*533affcbSRobert Mustacchi
702*533affcbSRobert Mustacchi bool
nvme_ctrl_info_format(nvme_ctrl_info_t * ci,uint32_t idx,const nvme_nvm_lba_fmt_t ** outp)703*533affcbSRobert Mustacchi nvme_ctrl_info_format(nvme_ctrl_info_t *ci, uint32_t idx,
704*533affcbSRobert Mustacchi const nvme_nvm_lba_fmt_t **outp)
705*533affcbSRobert Mustacchi {
706*533affcbSRobert Mustacchi const uint32_t max = nvme_ctrl_info_nformats(ci);
707*533affcbSRobert Mustacchi if (idx >= max) {
708*533affcbSRobert Mustacchi return (nvme_info_error(ci, NVME_INFO_ERR_BAD_FMT, 0,
709*533affcbSRobert Mustacchi "requested index %u is invalid: valid range is [0, %u]",
710*533affcbSRobert Mustacchi idx, max - 1));
711*533affcbSRobert Mustacchi }
712*533affcbSRobert Mustacchi
713*533affcbSRobert Mustacchi if (!ci->nci_lbaf_valid[idx]) {
714*533affcbSRobert Mustacchi uint8_t lbads = ci->nci_ns.id_lbaf[idx].lbaf_lbads;
715*533affcbSRobert Mustacchi
716*533affcbSRobert Mustacchi if (lbads == 0) {
717*533affcbSRobert Mustacchi return (nvme_info_error(ci, NVME_INFO_ERR_BAD_FMT, 0,
718*533affcbSRobert Mustacchi "format %u is not actually valid due to 0 LBA "
719*533affcbSRobert Mustacchi "data size even though it is considered a valid "
720*533affcbSRobert Mustacchi "LBA format by NLBAF", lbads));
721*533affcbSRobert Mustacchi }
722*533affcbSRobert Mustacchi
723*533affcbSRobert Mustacchi if (lbads < 9) {
724*533affcbSRobert Mustacchi return (nvme_info_error(ci, NVME_INFO_ERR_BAD_FMT_DATA,
725*533affcbSRobert Mustacchi 0, "NVMe devices are not allowed to have a LBA "
726*533affcbSRobert Mustacchi "data size of less than 512 bytes, found raw "
727*533affcbSRobert Mustacchi "shift value of %u for format %u", lbads, idx));
728*533affcbSRobert Mustacchi }
729*533affcbSRobert Mustacchi
730*533affcbSRobert Mustacchi if (lbads >= 64) {
731*533affcbSRobert Mustacchi return (nvme_info_error(ci, NVME_INFO_ERR_BAD_FMT_DATA,
732*533affcbSRobert Mustacchi 0, "LBA format %u has LBA data size greater "
733*533affcbSRobert Mustacchi "than 64 (%u), cannot be represented as a byte "
734*533affcbSRobert Mustacchi "size", idx, lbads));
735*533affcbSRobert Mustacchi }
736*533affcbSRobert Mustacchi
737*533affcbSRobert Mustacchi ci->nci_lbaf[idx].nnlf_id = idx;
738*533affcbSRobert Mustacchi ci->nci_lbaf[idx].nnlf_ms = ci->nci_ns.id_lbaf[idx].lbaf_ms;
739*533affcbSRobert Mustacchi ci->nci_lbaf[idx].nnlf_lbasz = 1ULL << lbads;
740*533affcbSRobert Mustacchi ci->nci_lbaf[idx].nnlf_rel = ci->nci_ns.id_lbaf[idx].lbaf_rp;
741*533affcbSRobert Mustacchi ci->nci_lbaf_valid[idx] = true;
742*533affcbSRobert Mustacchi }
743*533affcbSRobert Mustacchi
744*533affcbSRobert Mustacchi *outp = &ci->nci_lbaf[idx];
745*533affcbSRobert Mustacchi return (nvme_info_success(ci));
746*533affcbSRobert Mustacchi }
747*533affcbSRobert Mustacchi
748*533affcbSRobert Mustacchi uint32_t
nvme_nvm_lba_fmt_id(const nvme_nvm_lba_fmt_t * lbaf)749*533affcbSRobert Mustacchi nvme_nvm_lba_fmt_id(const nvme_nvm_lba_fmt_t *lbaf)
750*533affcbSRobert Mustacchi {
751*533affcbSRobert Mustacchi return (lbaf->nnlf_id);
752*533affcbSRobert Mustacchi }
753*533affcbSRobert Mustacchi
754*533affcbSRobert Mustacchi uint32_t
nvme_nvm_lba_fmt_meta_size(const nvme_nvm_lba_fmt_t * lbaf)755*533affcbSRobert Mustacchi nvme_nvm_lba_fmt_meta_size(const nvme_nvm_lba_fmt_t *lbaf)
756*533affcbSRobert Mustacchi {
757*533affcbSRobert Mustacchi return (lbaf->nnlf_ms);
758*533affcbSRobert Mustacchi }
759*533affcbSRobert Mustacchi
760*533affcbSRobert Mustacchi uint64_t
nvme_nvm_lba_fmt_data_size(const nvme_nvm_lba_fmt_t * lbaf)761*533affcbSRobert Mustacchi nvme_nvm_lba_fmt_data_size(const nvme_nvm_lba_fmt_t *lbaf)
762*533affcbSRobert Mustacchi {
763*533affcbSRobert Mustacchi return (lbaf->nnlf_lbasz);
764*533affcbSRobert Mustacchi }
765*533affcbSRobert Mustacchi
766*533affcbSRobert Mustacchi uint32_t
nvme_nvm_lba_fmt_rel_perf(const nvme_nvm_lba_fmt_t * lbaf)767*533affcbSRobert Mustacchi nvme_nvm_lba_fmt_rel_perf(const nvme_nvm_lba_fmt_t *lbaf)
768*533affcbSRobert Mustacchi {
769*533affcbSRobert Mustacchi return (lbaf->nnlf_rel);
770*533affcbSRobert Mustacchi }
771