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