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