Home | History | Annotate | Download | only in motherboard
      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