xref: /titanic_52/usr/src/lib/fm/topo/modules/sun4v/motherboard/motherboard.c (revision 9c94f155585ea35e938fea603bc227c685223abd)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <stdlib.h>
28 #include <string.h>
29 #include <strings.h>
30 #include <fm/topo_mod.h>
31 #include <fm/topo_hc.h>
32 #include <libdevinfo.h>
33 #include <limits.h>
34 #include <sys/fm/protocol.h>
35 #include <sys/param.h>
36 #include <sys/systeminfo.h>
37 #include <assert.h>
38 #include <sys/utsname.h>
39 #include <sys/systeminfo.h>
40 #include <fm/fmd_fmri.h>
41 #include <sys/types.h>
42 #include <sys/mdesc.h>
43 #include <sys/fm/ldom.h>
44 
45 /*
46  * motherboard.c
47  *	sun4v specific motherboard enumerators
48  */
49 
50 #ifdef __cplusplus
51 extern "C" {
52 #endif
53 
54 #define	MB_VERSION	TOPO_VERSION
55 
56 static int mb_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t,
57 		topo_instance_t, void *, void *);
58 
59 static const topo_modops_t Mb_ops =
60 	{ mb_enum, NULL};
61 static const topo_modinfo_t mb_info =
62 	{ MOTHERBOARD, FM_FMRI_SCHEME_HC, MB_VERSION, &Mb_ops};
63 
64 static const topo_pgroup_info_t mb_auth_pgroup = {
65 	FM_FMRI_AUTHORITY,
66 	TOPO_STABILITY_PRIVATE,
67 	TOPO_STABILITY_PRIVATE,
68 	1
69 };
70 
71 static const topo_pgroup_info_t mb_sys_pgroup = {
72 	TOPO_PGROUP_SYSTEM,
73 	TOPO_STABILITY_PRIVATE,
74 	TOPO_STABILITY_PRIVATE,
75 	1
76 };
77 
78 static topo_mod_t *mb_mod_hdl = NULL;
79 
80 /*ARGSUSED*/
81 void
82 _topo_init(topo_mod_t *mod, topo_version_t version)
83 {
84 	/*
85 	 * Turn on module debugging output
86 	 */
87 	if (getenv("TOPOMBDBG") != NULL)
88 		topo_mod_setdebug(mod);
89 	topo_mod_dprintf(mod, "initializing motherboard enumerator\n");
90 
91 	if (topo_mod_register(mod, &mb_info, TOPO_VERSION) < 0) {
92 		topo_mod_dprintf(mod, "motherboard registration failed: %s\n",
93 		    topo_mod_errmsg(mod));
94 		return; /* mod errno already set */
95 	}
96 	topo_mod_dprintf(mod, "MB enumr initd\n");
97 }
98 
99 void
100 _topo_fini(topo_mod_t *mod)
101 {
102 	topo_mod_unregister(mod);
103 }
104 
105 static void *
106 mb_topo_alloc(size_t size)
107 {
108 	assert(mb_mod_hdl != NULL);
109 	return (topo_mod_alloc(mb_mod_hdl, size));
110 }
111 
112 static void
113 mb_topo_free(void *data, size_t size)
114 {
115 	assert(mb_mod_hdl != NULL);
116 	topo_mod_free(mb_mod_hdl, data, size);
117 }
118 
119 static int
120 mb_get_pri_info(topo_mod_t *mod, char **serialp, char **partp, char **csnp,
121     char **psnp)
122 {
123 	char isa[MAXNAMELEN];
124 	md_t *mdp;
125 	mde_cookie_t *listp;
126 	uint64_t *bufp;
127 	ssize_t bufsize = 0;
128 	int  nfrus, num_nodes, i;
129 	char *pstr = NULL;
130 	char *sn, *pn, *dn, *csn, *psn;
131 	uint32_t type = 0;
132 	ldom_hdl_t *lhp;
133 
134 	lhp = ldom_init(mb_topo_alloc, mb_topo_free);
135 	if (lhp == NULL) {
136 		topo_mod_dprintf(mod, "ldom_init failed\n");
137 		return (-1);
138 	}
139 
140 	(void) sysinfo(SI_MACHINE, isa, MAXNAMELEN);
141 	if (strcmp(isa, "sun4v") != 0) {
142 		topo_mod_dprintf(mod, "not sun4v architecture%s\n",
143 		    isa);
144 		ldom_fini(lhp);
145 		return (-1);
146 	}
147 
148 	(void) ldom_get_type(lhp, &type);
149 	if ((type & LDOM_TYPE_CONTROL) != 0) {
150 		bufsize = ldom_get_core_md(lhp, &bufp);
151 	} else {
152 		bufsize = ldom_get_local_md(lhp, &bufp);
153 	}
154 	if (bufsize < 1) {
155 		topo_mod_dprintf(mod, "Failed to get the pri/md (bufsize=%d)\n",
156 		    bufsize);
157 		ldom_fini(lhp);
158 		return (-1);
159 	}
160 	topo_mod_dprintf(mod, "pri/md bufsize=%d\n", bufsize);
161 
162 	if ((mdp = md_init_intern(bufp, mb_topo_alloc, mb_topo_free)) == NULL ||
163 	    (num_nodes = md_node_count(mdp)) < 1) {
164 		topo_mod_dprintf(mod, "md_init_intern error\n");
165 		mb_topo_free(bufp, (size_t)bufsize);
166 		ldom_fini(lhp);
167 		return (-1);
168 	}
169 	topo_mod_dprintf(mod, "num_nodes=%d\n", num_nodes);
170 
171 	if ((listp = (mde_cookie_t *)mb_topo_alloc(
172 	    sizeof (mde_cookie_t) * num_nodes)) == NULL) {
173 		topo_mod_dprintf(mod, "alloc listp error\n");
174 		mb_topo_free(bufp, (size_t)bufsize);
175 		(void) md_fini(mdp);
176 		ldom_fini(lhp);
177 		return (-1);
178 	}
179 
180 	nfrus = md_scan_dag(mdp, MDE_INVAL_ELEM_COOKIE,
181 	    md_find_name(mdp, "component"),
182 	    md_find_name(mdp, "fwd"), listp);
183 	if (nfrus <= 0) {
184 		topo_mod_dprintf(mod, "error: nfrus=%d\n", nfrus);
185 		mb_topo_free(listp, sizeof (mde_cookie_t) * num_nodes);
186 		mb_topo_free(bufp, (size_t)bufsize);
187 		(void) md_fini(mdp);
188 		ldom_fini(lhp);
189 		return (-1);
190 	}
191 	topo_mod_dprintf(mod, "nfrus=%d\n", nfrus);
192 
193 	sn = pn = dn = psn = csn = NULL;
194 
195 	for (i = 0; i < nfrus; i++) {
196 		if (md_get_prop_str(mdp, listp[i], "type", &pstr) == 0) {
197 			/* systemboard/motherboard component */
198 			if (strcmp("systemboard", pstr) == 0) {
199 				if (md_get_prop_str(mdp, listp[i],
200 				    "serial_number", &sn) < 0)
201 					sn = NULL;
202 				if (md_get_prop_str(mdp, listp[i],
203 				    "part_number", &pn) < 0)
204 					pn = NULL;
205 				if (md_get_prop_str(mdp, listp[i],
206 				    "dash_number", &dn) < 0)
207 					dn = NULL;
208 			} else if (strcmp("product", pstr) == 0) {
209 				if (md_get_prop_str(mdp, listp[i],
210 				    "serial_number", &psn) < 0)
211 					psn = NULL;
212 			}
213 		}
214 		/* redefined access method for chassis serial number */
215 		if (md_get_prop_str(mdp, listp[i], "nac", &pstr) == 0) {
216 			if (strcmp("SYS", pstr) == 0) {
217 				if (md_get_prop_str(mdp, listp[i],
218 				    "serial_number", &csn) < 0)
219 					csn = NULL;
220 			}
221 		}
222 	}
223 
224 	*serialp = topo_mod_strdup(mod, sn);
225 
226 	i = (pn ? strlen(pn) : 0) + (dn ? strlen(dn) : 0) + 1;
227 	pstr = mb_topo_alloc(i);
228 	(void) snprintf(pstr, i, "%s%s", pn ? pn : "", dn ? dn : "");
229 	*partp = topo_mod_strdup(mod, pstr);
230 	mb_topo_free(pstr, i);
231 
232 	*csnp = topo_mod_strdup(mod, csn);
233 	*psnp = topo_mod_strdup(mod, psn);
234 
235 	mb_topo_free(listp, sizeof (mde_cookie_t) * num_nodes);
236 	mb_topo_free(bufp, (size_t)bufsize);
237 	(void) md_fini(mdp);
238 	ldom_fini(lhp);
239 
240 	return (0);
241 }
242 
243 static void
244 mb_prop_set(tnode_t *node, nvlist_t *auth)
245 {
246 	int err;
247 	char isa[MAXNAMELEN];
248 	struct utsname uts;
249 	char *prod, *psn, *csn, *server;
250 
251 	if ((topo_pgroup_create(node, &mb_auth_pgroup, &err) != 0) &&
252 	    (err != ETOPO_PROP_DEFD))
253 		return;
254 
255 	if (nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT, &prod) == 0)
256 		(void) topo_prop_set_string(node, FM_FMRI_AUTHORITY,
257 		    FM_FMRI_AUTH_PRODUCT, TOPO_PROP_IMMUTABLE, prod, &err);
258 	if (nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT_SN, &psn) == 0)
259 		(void) topo_prop_set_string(node, FM_FMRI_AUTHORITY,
260 		    FM_FMRI_AUTH_PRODUCT_SN, TOPO_PROP_IMMUTABLE, psn, &err);
261 	if (nvlist_lookup_string(auth, FM_FMRI_AUTH_CHASSIS, &csn) == 0)
262 		(void) topo_prop_set_string(node, FM_FMRI_AUTHORITY,
263 		    FM_FMRI_AUTH_CHASSIS, TOPO_PROP_IMMUTABLE, csn, &err);
264 	if (nvlist_lookup_string(auth, FM_FMRI_AUTH_SERVER, &server) == 0)
265 		(void) topo_prop_set_string(node, FM_FMRI_AUTHORITY,
266 		    FM_FMRI_AUTH_SERVER, TOPO_PROP_IMMUTABLE, server, &err);
267 
268 	if (topo_pgroup_create(node, &mb_sys_pgroup, &err) != 0)
269 		return;
270 
271 	isa[0] = '\0';
272 	(void) sysinfo(SI_ARCHITECTURE, isa, sizeof (isa));
273 	(void) uname(&uts);
274 	(void) topo_prop_set_string(node, TOPO_PGROUP_SYSTEM, TOPO_PROP_ISA,
275 	    TOPO_PROP_IMMUTABLE, isa, &err);
276 	(void) topo_prop_set_string(node, TOPO_PGROUP_SYSTEM, TOPO_PROP_MACHINE,
277 	    TOPO_PROP_IMMUTABLE, uts.machine, &err);
278 }
279 
280 static tnode_t *
281 mb_tnode_create(topo_mod_t *mod, tnode_t *parent,
282     const char *name, topo_instance_t i, void *priv)
283 {
284 	nvlist_t *fmri;
285 	tnode_t *ntn;
286 	char *serial = NULL, *part = NULL;
287 	char *psn = NULL, *csn = NULL, *pstr = NULL;
288 	nvlist_t *auth = topo_mod_auth(mod, parent);
289 
290 	/*
291 	 * Get Product Serial Number, Chassis ID, MB Serial Number and
292 	 * Part Number from PRI.
293 	 */
294 	(void) mb_get_pri_info(mod, &serial, &part, &csn, &psn);
295 
296 	if (nvlist_lookup_string(auth, FM_FMRI_AUTH_CHASSIS, &pstr) != 0 &&
297 	    csn != NULL) {
298 		if (nvlist_add_string(auth, FM_FMRI_AUTH_CHASSIS, csn) != 0) {
299 			topo_mod_dprintf(mod,
300 			    "failed to add chassis to auth");
301 			nvlist_free(auth);
302 			return (NULL);
303 		}
304 	}
305 
306 	if (nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT_SN, &pstr) != 0 &&
307 	    psn != NULL) {
308 		if (nvlist_add_string(auth, FM_FMRI_AUTH_PRODUCT_SN, psn)
309 		    != 0) {
310 			topo_mod_dprintf(mod,
311 			    "failed to add product-sn to auth");
312 			nvlist_free(auth);
313 			return (NULL);
314 		}
315 	}
316 
317 	fmri = topo_mod_hcfmri(mod, NULL, FM_HC_SCHEME_VERSION, name, i,
318 	    NULL, auth, part, NULL, serial);
319 
320 	topo_mod_strfree(mod, serial);
321 	topo_mod_strfree(mod, part);
322 	topo_mod_strfree(mod, csn);
323 	topo_mod_strfree(mod, psn);
324 
325 	if (fmri == NULL) {
326 		topo_mod_dprintf(mod,
327 		    "Unable to make nvlist for %s bind: %s.\n",
328 		    name, topo_mod_errmsg(mod));
329 		nvlist_free(auth);
330 		return (NULL);
331 	}
332 
333 	ntn = topo_node_bind(mod, parent, name, i, fmri);
334 	if (ntn == NULL) {
335 		topo_mod_dprintf(mod,
336 		    "topo_node_bind (%s%d/%s%d) failed: %s\n",
337 		    topo_node_name(parent), topo_node_instance(parent),
338 		    name, i,
339 		    topo_strerror(topo_mod_errno(mod)));
340 		nvlist_free(auth);
341 		nvlist_free(fmri);
342 		return (NULL);
343 	}
344 
345 	mb_prop_set(ntn, auth);
346 
347 	nvlist_free(auth);
348 	nvlist_free(fmri);
349 
350 	topo_node_setspecific(ntn, priv);
351 
352 	return (ntn);
353 }
354 
355 /*ARGSUSED*/
356 static tnode_t *
357 mb_declare(tnode_t *parent, const char *name, topo_instance_t i,
358 	void *priv, topo_mod_t *mp)
359 {
360 	tnode_t *ntn;
361 	nvlist_t *fmri;
362 	char *label = "MB";
363 	int err;
364 
365 	if ((ntn = mb_tnode_create(mp, parent, name, 0, NULL)) == NULL)
366 		return (NULL);
367 
368 	/* Set FRU */
369 	if (topo_node_resource(ntn, &fmri, &err) < 0) {
370 		(void) topo_mod_seterrno(mp, err);
371 		topo_node_unbind(ntn);
372 		return (NULL);
373 	}
374 	if (topo_node_fru_set(ntn, fmri, 0, &err) < 0)
375 		(void) topo_mod_seterrno(mp, err);
376 	nvlist_free(fmri);
377 
378 	/* Label is MB */
379 	if (topo_prop_set_string(ntn, TOPO_PGROUP_PROTOCOL,
380 	    TOPO_PROP_LABEL,  TOPO_PROP_IMMUTABLE, label, &err) < 0) {
381 		(void) topo_mod_seterrno(mp, err);
382 	}
383 
384 	return (ntn);
385 }
386 
387 /*ARGSUSED*/
388 static int
389 mb_enum(topo_mod_t *mod, tnode_t *pn, const char *name,
390 	topo_instance_t min, topo_instance_t max, void *arg, void *notused)
391 {
392 	tnode_t *mbn;
393 
394 	if (strcmp(name, MOTHERBOARD) != 0) {
395 		topo_mod_dprintf(mod,
396 		    "Currently only know how to enumerate %s components.\n",
397 		    MOTHERBOARD);
398 		return (0);
399 	}
400 
401 	mb_mod_hdl = mod;
402 
403 	mbn = mb_declare(pn, name, 0, NULL, mod);
404 
405 	if (mbn == NULL) {
406 		topo_mod_dprintf(mod, "Enumeration of motherboard "
407 		    "failed: %s\n",
408 		    topo_strerror(topo_mod_errno(mod)));
409 		return (-1); /* mod_errno already set */
410 	}
411 
412 	return (0);
413 }
414