1*744642a2SRobert Mustacchi /*
2*744642a2SRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*744642a2SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*744642a2SRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*744642a2SRobert Mustacchi  * 1.0 of the CDDL.
6*744642a2SRobert Mustacchi  *
7*744642a2SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*744642a2SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*744642a2SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*744642a2SRobert Mustacchi  */
11*744642a2SRobert Mustacchi 
12*744642a2SRobert Mustacchi /*
13*744642a2SRobert Mustacchi  * Copyright 2023 Oxide Computer Company
14*744642a2SRobert Mustacchi  */
15*744642a2SRobert Mustacchi 
16*744642a2SRobert Mustacchi /*
17*744642a2SRobert Mustacchi  * This implements logic to enumerate UFM nodes based on different data sources
18*744642a2SRobert Mustacchi  * in the system. Being in a module allows it to be used by several other
19*744642a2SRobert Mustacchi  * modules in the system and means that we can encapsulate all of the messy
20*744642a2SRobert Mustacchi  * logic here.
21*744642a2SRobert Mustacchi  *
22*744642a2SRobert Mustacchi  * Our module is not designed to operate from a topo map right now. Instead, it
23*744642a2SRobert Mustacchi  * is expected that callers are going to pass the enumeration argument in.
24*744642a2SRobert Mustacchi  */
25*744642a2SRobert Mustacchi 
26*744642a2SRobert Mustacchi #include <sys/fm/protocol.h>
27*744642a2SRobert Mustacchi #include <fm/topo_mod.h>
28*744642a2SRobert Mustacchi #include <fm/topo_hc.h>
29*744642a2SRobert Mustacchi #include <string.h>
30*744642a2SRobert Mustacchi #include <sys/ddi_ufm.h>
31*744642a2SRobert Mustacchi #include <sys/types.h>
32*744642a2SRobert Mustacchi #include <sys/stat.h>
33*744642a2SRobert Mustacchi #include <fcntl.h>
34*744642a2SRobert Mustacchi #include <unistd.h>
35*744642a2SRobert Mustacchi #include <errno.h>
36*744642a2SRobert Mustacchi 
37*744642a2SRobert Mustacchi #include "topo_ufm.h"
38*744642a2SRobert Mustacchi 
39*744642a2SRobert Mustacchi /*
40*744642a2SRobert Mustacchi  * Attempt to create the specific UFM image that is listed in the nvl.
41*744642a2SRobert Mustacchi  */
42*744642a2SRobert Mustacchi static int
topo_ufm_devinfo_image(topo_mod_t * mod,tnode_t * pn,topo_instance_t inst,nvlist_t * nvl)43*744642a2SRobert Mustacchi topo_ufm_devinfo_image(topo_mod_t *mod, tnode_t *pn, topo_instance_t inst,
44*744642a2SRobert Mustacchi     nvlist_t *nvl)
45*744642a2SRobert Mustacchi {
46*744642a2SRobert Mustacchi 	int ret;
47*744642a2SRobert Mustacchi 	char *desc;
48*744642a2SRobert Mustacchi 	tnode_t *img_tn;
49*744642a2SRobert Mustacchi 	nvlist_t **slots;
50*744642a2SRobert Mustacchi 	uint_t nslots;
51*744642a2SRobert Mustacchi 
52*744642a2SRobert Mustacchi 	ret = nvlist_lookup_string(nvl, DDI_UFM_NV_IMAGE_DESC, &desc);
53*744642a2SRobert Mustacchi 	if (ret != 0) {
54*744642a2SRobert Mustacchi 		topo_mod_dprintf(mod, "failed to look up %s: %s",
55*744642a2SRobert Mustacchi 		    DDI_UFM_NV_IMAGE_DESC, strerror(ret));
56*744642a2SRobert Mustacchi 		return (topo_mod_seterrno(mod, EMOD_UNKNOWN));
57*744642a2SRobert Mustacchi 	}
58*744642a2SRobert Mustacchi 
59*744642a2SRobert Mustacchi 	ret = nvlist_lookup_nvlist_array(nvl, DDI_UFM_NV_IMAGE_SLOTS, &slots,
60*744642a2SRobert Mustacchi 	    &nslots);
61*744642a2SRobert Mustacchi 	if (ret != 0) {
62*744642a2SRobert Mustacchi 		topo_mod_dprintf(mod, "failed to look up %s: %s",
63*744642a2SRobert Mustacchi 		    DDI_UFM_NV_IMAGE_SLOTS, strerror(ret));
64*744642a2SRobert Mustacchi 		return (topo_mod_seterrno(mod, EMOD_UNKNOWN));
65*744642a2SRobert Mustacchi 	}
66*744642a2SRobert Mustacchi 
67*744642a2SRobert Mustacchi 	if (nslots == 0) {
68*744642a2SRobert Mustacchi 		topo_mod_dprintf(mod, "refusing to create UFM image with zero "
69*744642a2SRobert Mustacchi 		    "slots");
70*744642a2SRobert Mustacchi 		return (topo_mod_seterrno(mod, EMOD_UNKNOWN));
71*744642a2SRobert Mustacchi 	}
72*744642a2SRobert Mustacchi 
73*744642a2SRobert Mustacchi 	img_tn = topo_mod_create_ufm(mod, pn, inst, desc, NULL);
74*744642a2SRobert Mustacchi 	if (img_tn == NULL) {
75*744642a2SRobert Mustacchi 		topo_mod_dprintf(mod, "failed to create ufm image %" PRIu64
76*744642a2SRobert Mustacchi 		    "on %s[%" PRIu64 "]: %s", inst, topo_node_name(pn),
77*744642a2SRobert Mustacchi 		    topo_node_instance(pn), topo_mod_errmsg(mod));
78*744642a2SRobert Mustacchi 		return (-1);
79*744642a2SRobert Mustacchi 	}
80*744642a2SRobert Mustacchi 
81*744642a2SRobert Mustacchi 	if (topo_node_range_create(mod, img_tn, SLOT, 0, nslots - 1) != 0) {
82*744642a2SRobert Mustacchi 		topo_mod_dprintf(mod, "failed to create node range %s[0, %u]: "
83*744642a2SRobert Mustacchi 		    "%s", SLOT, nslots - 1, topo_mod_errmsg(mod));
84*744642a2SRobert Mustacchi 		topo_node_unbind(img_tn);
85*744642a2SRobert Mustacchi 		return (-1);
86*744642a2SRobert Mustacchi 	}
87*744642a2SRobert Mustacchi 
88*744642a2SRobert Mustacchi 	/*
89*744642a2SRobert Mustacchi 	 * Go through and create the slots. Once we've reached this part, it's
90*744642a2SRobert Mustacchi 	 * hard to clean up the UFM image node as it will have ranges and
91*744642a2SRobert Mustacchi 	 * potentially children (because we've been looping). We'll have to hope
92*744642a2SRobert Mustacchi 	 * that the enumeration error is sufficient for someone taking a
93*744642a2SRobert Mustacchi 	 * snapshot.
94*744642a2SRobert Mustacchi 	 *
95*744642a2SRobert Mustacchi 	 * A slot must have an attributes property. If that is not there, we
96*744642a2SRobert Mustacchi 	 * can't do much more than that. It must have a version, but only if the
97*744642a2SRobert Mustacchi 	 * empty attribute is not set! There may be misc. extra data, which
98*744642a2SRobert Mustacchi 	 * we'll include but don't care if we can get it or not.
99*744642a2SRobert Mustacchi 	 */
100*744642a2SRobert Mustacchi 	for (uint_t i = 0; i < nslots; i++) {
101*744642a2SRobert Mustacchi 		topo_ufm_slot_info_t slot = { 0 };
102*744642a2SRobert Mustacchi 		uint32_t attr, rw;
103*744642a2SRobert Mustacchi 		char *vers;
104*744642a2SRobert Mustacchi 
105*744642a2SRobert Mustacchi 		slot.usi_slotid = i;
106*744642a2SRobert Mustacchi 		ret = nvlist_lookup_uint32(slots[i], DDI_UFM_NV_SLOT_ATTR,
107*744642a2SRobert Mustacchi 		    &attr);
108*744642a2SRobert Mustacchi 		if (ret != 0) {
109*744642a2SRobert Mustacchi 			topo_mod_dprintf(mod, "failed to get required %s "
110*744642a2SRobert Mustacchi 			    "property from slot %u: %s", DDI_UFM_NV_SLOT_ATTR,
111*744642a2SRobert Mustacchi 			    i, strerror(errno));
112*744642a2SRobert Mustacchi 			return (topo_mod_seterrno(mod, EMOD_UNKNOWN));
113*744642a2SRobert Mustacchi 		}
114*744642a2SRobert Mustacchi 
115*744642a2SRobert Mustacchi 		slot.usi_version = vers;
116*744642a2SRobert Mustacchi 		rw = attr & (DDI_UFM_ATTR_READABLE | DDI_UFM_ATTR_WRITEABLE);
117*744642a2SRobert Mustacchi 		switch (rw) {
118*744642a2SRobert Mustacchi 		case DDI_UFM_ATTR_READABLE | DDI_UFM_ATTR_WRITEABLE:
119*744642a2SRobert Mustacchi 			slot.usi_mode = TOPO_UFM_SLOT_MODE_RW;
120*744642a2SRobert Mustacchi 			break;
121*744642a2SRobert Mustacchi 		case DDI_UFM_ATTR_READABLE:
122*744642a2SRobert Mustacchi 			slot.usi_mode = TOPO_UFM_SLOT_MODE_RO;
123*744642a2SRobert Mustacchi 			break;
124*744642a2SRobert Mustacchi 		case DDI_UFM_ATTR_WRITEABLE:
125*744642a2SRobert Mustacchi 			slot.usi_mode = TOPO_UFM_SLOT_MODE_WO;
126*744642a2SRobert Mustacchi 			break;
127*744642a2SRobert Mustacchi 		default:
128*744642a2SRobert Mustacchi 			slot.usi_mode = TOPO_UFM_SLOT_MODE_NONE;
129*744642a2SRobert Mustacchi 			break;
130*744642a2SRobert Mustacchi 		}
131*744642a2SRobert Mustacchi 
132*744642a2SRobert Mustacchi 		slot.usi_active = (attr & DDI_UFM_ATTR_ACTIVE) != 0;
133*744642a2SRobert Mustacchi 
134*744642a2SRobert Mustacchi 		vers = NULL;
135*744642a2SRobert Mustacchi 		if ((attr & DDI_UFM_ATTR_EMPTY) == 0 &&
136*744642a2SRobert Mustacchi 		    (ret = nvlist_lookup_string(slots[i],
137*744642a2SRobert Mustacchi 		    DDI_UFM_NV_SLOT_VERSION, &vers)) != 0) {
138*744642a2SRobert Mustacchi 			topo_mod_dprintf(mod, "failed to get required %s "
139*744642a2SRobert Mustacchi 			    "property from non-empty slot %u: %s",
140*744642a2SRobert Mustacchi 			    DDI_UFM_NV_SLOT_VERSION, i, strerror(errno));
141*744642a2SRobert Mustacchi 			return (topo_mod_seterrno(mod, EMOD_UNKNOWN));
142*744642a2SRobert Mustacchi 		}
143*744642a2SRobert Mustacchi 		slot.usi_version = vers;
144*744642a2SRobert Mustacchi 
145*744642a2SRobert Mustacchi 		/*
146*744642a2SRobert Mustacchi 		 * If there are additional attributes that exist, then leverage
147*744642a2SRobert Mustacchi 		 * those. However, we'll ignore failures of this because it's
148*744642a2SRobert Mustacchi 		 * optional.
149*744642a2SRobert Mustacchi 		 */
150*744642a2SRobert Mustacchi 		slot.usi_extra = NULL;
151*744642a2SRobert Mustacchi 		(void) nvlist_lookup_nvlist(slots[i], DDI_UFM_NV_SLOT_MISC,
152*744642a2SRobert Mustacchi 		    &slot.usi_extra);
153*744642a2SRobert Mustacchi 
154*744642a2SRobert Mustacchi 		if (topo_mod_create_ufm_slot(mod, img_tn, &slot) == NULL) {
155*744642a2SRobert Mustacchi 			topo_mod_dprintf(mod, "failed to create ufm slot %u on "
156*744642a2SRobert Mustacchi 			    "image %" PRIu64 ": %s", i, inst,
157*744642a2SRobert Mustacchi 			    topo_mod_errmsg(mod));
158*744642a2SRobert Mustacchi 			return (-1);
159*744642a2SRobert Mustacchi 		}
160*744642a2SRobert Mustacchi 	}
161*744642a2SRobert Mustacchi 
162*744642a2SRobert Mustacchi 	return (0);
163*744642a2SRobert Mustacchi }
164*744642a2SRobert Mustacchi 
165*744642a2SRobert Mustacchi /*
166*744642a2SRobert Mustacchi  * Utlilizing the devinfo tree create information about the given ufm. We use
167*744642a2SRobert Mustacchi  * [min, max] as a way to figure out which UFMs to create and treat this as a
168*744642a2SRobert Mustacchi  * way to slice up parts of the range. We will only actually create nodes based
169*744642a2SRobert Mustacchi  * on how many are present.
170*744642a2SRobert Mustacchi  */
171*744642a2SRobert Mustacchi static int
topo_ufm_devinfo(topo_mod_t * mod,tnode_t * pn,topo_instance_t min,topo_instance_t max,topo_ufm_devinfo_t * tud)172*744642a2SRobert Mustacchi topo_ufm_devinfo(topo_mod_t *mod, tnode_t *pn, topo_instance_t min,
173*744642a2SRobert Mustacchi     topo_instance_t max, topo_ufm_devinfo_t *tud)
174*744642a2SRobert Mustacchi {
175*744642a2SRobert Mustacchi 	int fd = -1;
176*744642a2SRobert Mustacchi 	int ret;
177*744642a2SRobert Mustacchi 	ufm_ioc_getcaps_t caps = { 0 };
178*744642a2SRobert Mustacchi 	ufm_ioc_bufsz_t bufsz = { 0 };
179*744642a2SRobert Mustacchi 	ufm_ioc_report_t report = { 0 };
180*744642a2SRobert Mustacchi 	nvlist_t *nvl = NULL, **img_nvl;
181*744642a2SRobert Mustacchi 	uint_t nimg;
182*744642a2SRobert Mustacchi 
183*744642a2SRobert Mustacchi 	if (tud->tud_path == NULL) {
184*744642a2SRobert Mustacchi 		topo_mod_dprintf(mod, "missing required devfs path");
185*744642a2SRobert Mustacchi 		return (topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM));
186*744642a2SRobert Mustacchi 	}
187*744642a2SRobert Mustacchi 
188*744642a2SRobert Mustacchi 	/*
189*744642a2SRobert Mustacchi 	 * We check the path size here now so we can guarantee that all of the
190*744642a2SRobert Mustacchi 	 * rest of the string copying will fit inside our buffers and therefore
191*744642a2SRobert Mustacchi 	 * we ignore the strlcpy() result.
192*744642a2SRobert Mustacchi 	 */
193*744642a2SRobert Mustacchi 	if (strlen(tud->tud_path) >= MAXPATHLEN) {
194*744642a2SRobert Mustacchi 		topo_mod_dprintf(mod, "given devfs path exceeds MAXPATHLEN "
195*744642a2SRobert Mustacchi 		    "buffers, cannot continue");
196*744642a2SRobert Mustacchi 		return (topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM));
197*744642a2SRobert Mustacchi 	}
198*744642a2SRobert Mustacchi 
199*744642a2SRobert Mustacchi 	fd = open(DDI_UFM_DEV, O_RDONLY);
200*744642a2SRobert Mustacchi 	if (fd < 0) {
201*744642a2SRobert Mustacchi 		topo_mod_dprintf(mod, "failed to open %s: %s", DDI_UFM_DEV,
202*744642a2SRobert Mustacchi 		    strerror(errno));
203*744642a2SRobert Mustacchi 		return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
204*744642a2SRobert Mustacchi 	}
205*744642a2SRobert Mustacchi 
206*744642a2SRobert Mustacchi 	caps.ufmg_version = DDI_UFM_CURRENT_VERSION;
207*744642a2SRobert Mustacchi 	(void) strlcpy(caps.ufmg_devpath, tud->tud_path,
208*744642a2SRobert Mustacchi 	    sizeof (caps.ufmg_devpath));
209*744642a2SRobert Mustacchi 
210*744642a2SRobert Mustacchi 	/*
211*744642a2SRobert Mustacchi 	 * We swallow ioctl errors on purpose. The device driver may not support
212*744642a2SRobert Mustacchi 	 * UFMs at all. Similarly, if it doesn't actually support reporting UFM
213*744642a2SRobert Mustacchi 	 * information, then we're done here.
214*744642a2SRobert Mustacchi 	 */
215*744642a2SRobert Mustacchi 	if (ioctl(fd, UFM_IOC_GETCAPS, &caps) != 0) {
216*744642a2SRobert Mustacchi 		topo_mod_dprintf(mod, "failed to get UFM capabilities for "
217*744642a2SRobert Mustacchi 		    "%s: %s", tud->tud_path, strerror(errno));
218*744642a2SRobert Mustacchi 		ret = 0;
219*744642a2SRobert Mustacchi 		goto out;
220*744642a2SRobert Mustacchi 	}
221*744642a2SRobert Mustacchi 
222*744642a2SRobert Mustacchi 	if ((caps.ufmg_caps & DDI_UFM_CAP_REPORT) == 0) {
223*744642a2SRobert Mustacchi 		topo_mod_dprintf(mod, "path %s does not support UFM reporting",
224*744642a2SRobert Mustacchi 		    tud->tud_path);
225*744642a2SRobert Mustacchi 		ret = 0;
226*744642a2SRobert Mustacchi 		goto out;
227*744642a2SRobert Mustacchi 	}
228*744642a2SRobert Mustacchi 
229*744642a2SRobert Mustacchi 	bufsz.ufbz_version = DDI_UFM_CURRENT_VERSION;
230*744642a2SRobert Mustacchi 	(void) strlcpy(bufsz.ufbz_devpath, tud->tud_path,
231*744642a2SRobert Mustacchi 	    sizeof (bufsz.ufbz_devpath));
232*744642a2SRobert Mustacchi 	if (ioctl(fd, UFM_IOC_REPORTSZ, &bufsz) != 0) {
233*744642a2SRobert Mustacchi 		topo_mod_dprintf(mod, "failed to get UFM buffer size for "
234*744642a2SRobert Mustacchi 		    "%s: %s", tud->tud_path, strerror(errno));
235*744642a2SRobert Mustacchi 		ret = topo_mod_seterrno(mod, EMOD_UNKNOWN);
236*744642a2SRobert Mustacchi 		goto out;
237*744642a2SRobert Mustacchi 	}
238*744642a2SRobert Mustacchi 
239*744642a2SRobert Mustacchi 	report.ufmr_version = DDI_UFM_CURRENT_VERSION;
240*744642a2SRobert Mustacchi 	report.ufmr_bufsz = bufsz.ufbz_size;
241*744642a2SRobert Mustacchi 	report.ufmr_buf = topo_mod_alloc(mod, bufsz.ufbz_size);
242*744642a2SRobert Mustacchi 	if (report.ufmr_buf == NULL) {
243*744642a2SRobert Mustacchi 		ret = topo_mod_seterrno(mod, EMOD_NOMEM);
244*744642a2SRobert Mustacchi 		goto out;
245*744642a2SRobert Mustacchi 	}
246*744642a2SRobert Mustacchi 	(void) strlcpy(report.ufmr_devpath, tud->tud_path,
247*744642a2SRobert Mustacchi 	    sizeof (report.ufmr_devpath));
248*744642a2SRobert Mustacchi 	if (ioctl(fd, UFM_IOC_REPORT, &report) != 0) {
249*744642a2SRobert Mustacchi 		topo_mod_dprintf(mod, "failed to retrieve UFM report for "
250*744642a2SRobert Mustacchi 		    "%s: %s", tud->tud_path, strerror(errno));
251*744642a2SRobert Mustacchi 		ret = topo_mod_seterrno(mod, EMOD_UNKNOWN);
252*744642a2SRobert Mustacchi 		goto out;
253*744642a2SRobert Mustacchi 	}
254*744642a2SRobert Mustacchi 
255*744642a2SRobert Mustacchi 	ret = nvlist_unpack(report.ufmr_buf, report.ufmr_bufsz, &nvl, 0);
256*744642a2SRobert Mustacchi 	if (ret != 0) {
257*744642a2SRobert Mustacchi 		topo_mod_dprintf(mod, "failed to unpack report nvlist from "
258*744642a2SRobert Mustacchi 		    "%s: %s", tud->tud_path, strerror(ret));
259*744642a2SRobert Mustacchi 		ret = topo_mod_seterrno(mod, EMOD_UNKNOWN);
260*744642a2SRobert Mustacchi 		goto out;
261*744642a2SRobert Mustacchi 	}
262*744642a2SRobert Mustacchi 
263*744642a2SRobert Mustacchi 	/*
264*744642a2SRobert Mustacchi 	 * First see if the report actually gave us images. If there are no
265*744642a2SRobert Mustacchi 	 * images, then there is nothing to do.
266*744642a2SRobert Mustacchi 	 */
267*744642a2SRobert Mustacchi 	ret = nvlist_lookup_nvlist_array(nvl, DDI_UFM_NV_IMAGES, &img_nvl,
268*744642a2SRobert Mustacchi 	    &nimg);
269*744642a2SRobert Mustacchi 	if (ret != 0) {
270*744642a2SRobert Mustacchi 		topo_mod_dprintf(mod, "failed to retrieve key %s from "
271*744642a2SRobert Mustacchi 		    "report: %s", DDI_UFM_NV_IMAGES, strerror(ret));
272*744642a2SRobert Mustacchi 		ret = topo_mod_seterrno(mod, EMOD_UNKNOWN);
273*744642a2SRobert Mustacchi 		goto out;
274*744642a2SRobert Mustacchi 	}
275*744642a2SRobert Mustacchi 
276*744642a2SRobert Mustacchi 	if (nimg == 0) {
277*744642a2SRobert Mustacchi 		ret = 0;
278*744642a2SRobert Mustacchi 		goto out;
279*744642a2SRobert Mustacchi 	}
280*744642a2SRobert Mustacchi 
281*744642a2SRobert Mustacchi 	max = MIN(max, nimg - 1);
282*744642a2SRobert Mustacchi 	if (topo_node_range_create(mod, pn, UFM, min, max) != 0) {
283*744642a2SRobert Mustacchi 		topo_mod_dprintf(mod, "failed to create node range %s[%" PRIu64
284*744642a2SRobert Mustacchi 		    ", %" PRIu64 "]: %s", UFM, min, max, topo_mod_errmsg(mod));
285*744642a2SRobert Mustacchi 		ret = -1;
286*744642a2SRobert Mustacchi 		goto out;
287*744642a2SRobert Mustacchi 	}
288*744642a2SRobert Mustacchi 
289*744642a2SRobert Mustacchi 	for (topo_instance_t i = min; i <= max; i++) {
290*744642a2SRobert Mustacchi 		ret = topo_ufm_devinfo_image(mod, pn, i, img_nvl[i]);
291*744642a2SRobert Mustacchi 		if (ret != 0) {
292*744642a2SRobert Mustacchi 			goto out;
293*744642a2SRobert Mustacchi 		}
294*744642a2SRobert Mustacchi 	}
295*744642a2SRobert Mustacchi 
296*744642a2SRobert Mustacchi out:
297*744642a2SRobert Mustacchi 	nvlist_free(nvl);
298*744642a2SRobert Mustacchi 	if (report.ufmr_buf != NULL) {
299*744642a2SRobert Mustacchi 		topo_mod_free(mod, report.ufmr_buf, bufsz.ufbz_size);
300*744642a2SRobert Mustacchi 	}
301*744642a2SRobert Mustacchi 
302*744642a2SRobert Mustacchi 	if (fd >= 0) {
303*744642a2SRobert Mustacchi 		(void) close(fd);
304*744642a2SRobert Mustacchi 	}
305*744642a2SRobert Mustacchi 	return (ret);
306*744642a2SRobert Mustacchi }
307*744642a2SRobert Mustacchi 
308*744642a2SRobert Mustacchi static int
topo_ufm_enum(topo_mod_t * mod,tnode_t * pnode,const char * name,topo_instance_t min,topo_instance_t max,void * modarg,void * data)309*744642a2SRobert Mustacchi topo_ufm_enum(topo_mod_t *mod, tnode_t *pnode, const char *name,
310*744642a2SRobert Mustacchi     topo_instance_t min, topo_instance_t max, void *modarg, void *data)
311*744642a2SRobert Mustacchi {
312*744642a2SRobert Mustacchi 	topo_ufm_method_t *mp;
313*744642a2SRobert Mustacchi 
314*744642a2SRobert Mustacchi 	topo_mod_dprintf(mod, "asked to enum %s [%" PRIu64 ", %" PRIu64 "] on "
315*744642a2SRobert Mustacchi 	    "%s%" PRIu64 "\n", name, min, max, topo_node_name(pnode),
316*744642a2SRobert Mustacchi 	    topo_node_instance(pnode));
317*744642a2SRobert Mustacchi 
318*744642a2SRobert Mustacchi 	if (strcmp(name, UFM) != 0) {
319*744642a2SRobert Mustacchi 		topo_mod_dprintf(mod, "cannot enumerate %s: unknown type",
320*744642a2SRobert Mustacchi 		    name);
321*744642a2SRobert Mustacchi 		return (-1);
322*744642a2SRobert Mustacchi 	}
323*744642a2SRobert Mustacchi 
324*744642a2SRobert Mustacchi 	if (data == NULL) {
325*744642a2SRobert Mustacchi 		topo_mod_dprintf(mod, "cannot enumerate %s: missing required "
326*744642a2SRobert Mustacchi 		    "data", name);
327*744642a2SRobert Mustacchi 		return (-1);
328*744642a2SRobert Mustacchi 	}
329*744642a2SRobert Mustacchi 
330*744642a2SRobert Mustacchi 	mp = data;
331*744642a2SRobert Mustacchi 	switch (*mp) {
332*744642a2SRobert Mustacchi 	case TOPO_UFM_M_DEVINFO:
333*744642a2SRobert Mustacchi 		return (topo_ufm_devinfo(mod, pnode, min, max, data));
334*744642a2SRobert Mustacchi 	default:
335*744642a2SRobert Mustacchi 		topo_mod_dprintf(mod, "encountered unknown UFM enum method: "
336*744642a2SRobert Mustacchi 		    "0x%x, bailing", *mp);
337*744642a2SRobert Mustacchi 		return (-1);
338*744642a2SRobert Mustacchi 	}
339*744642a2SRobert Mustacchi 
340*744642a2SRobert Mustacchi }
341*744642a2SRobert Mustacchi 
342*744642a2SRobert Mustacchi static const topo_modops_t topo_ufm_ops = {
343*744642a2SRobert Mustacchi 	topo_ufm_enum, NULL
344*744642a2SRobert Mustacchi };
345*744642a2SRobert Mustacchi 
346*744642a2SRobert Mustacchi static topo_modinfo_t topo_ufm_mod = {
347*744642a2SRobert Mustacchi 	"UFM Enumerator", FM_FMRI_SCHEME_HC, TOPO_MOD_UFM_VERS, &topo_ufm_ops
348*744642a2SRobert Mustacchi };
349*744642a2SRobert Mustacchi 
350*744642a2SRobert Mustacchi int
_topo_init(topo_mod_t * mod,topo_version_t version)351*744642a2SRobert Mustacchi _topo_init(topo_mod_t *mod, topo_version_t version)
352*744642a2SRobert Mustacchi {
353*744642a2SRobert Mustacchi 	if (getenv("TOPOUFMDEBUG") != NULL) {
354*744642a2SRobert Mustacchi 		topo_mod_setdebug(mod);
355*744642a2SRobert Mustacchi 	}
356*744642a2SRobert Mustacchi 
357*744642a2SRobert Mustacchi 	return (topo_mod_register(mod, &topo_ufm_mod, TOPO_VERSION));
358*744642a2SRobert Mustacchi }
359*744642a2SRobert Mustacchi 
360*744642a2SRobert Mustacchi void
_topo_fini(topo_mod_t * mod)361*744642a2SRobert Mustacchi _topo_fini(topo_mod_t *mod)
362*744642a2SRobert Mustacchi {
363*744642a2SRobert Mustacchi 	topo_mod_unregister(mod);
364*744642a2SRobert Mustacchi }
365