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
_topo_init(topo_mod_t * mod,topo_version_t version)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
_topo_fini(topo_mod_t * mod)100 _topo_fini(topo_mod_t *mod)
101 {
102 topo_mod_unregister(mod);
103 }
104
105 static void *
mb_topo_alloc(size_t size)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
mb_topo_free(void * data,size_t size)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
mb_get_pri_info(topo_mod_t * mod,char ** serialp,char ** partp,char ** csnp,char ** psnp)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
mb_prop_set(tnode_t * node,nvlist_t * auth)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 *
mb_tnode_create(topo_mod_t * mod,tnode_t * parent,const char * name,topo_instance_t i,void * priv)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 *
mb_declare(tnode_t * parent,const char * name,topo_instance_t i,void * priv,topo_mod_t * mp)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
mb_enum(topo_mod_t * mod,tnode_t * pn,const char * name,topo_instance_t min,topo_instance_t max,void * arg,void * notused)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