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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 /*
27  * Create Base Board (MB) topology node from SMBIOS Type 2 structure
28  */
29 
30 #include <sys/types.h>
31 #include <strings.h>
32 #include <fm/topo_mod.h>
33 #include <fm/topo_hc.h>
34 #include <sys/systeminfo.h>
35 #include <sys/smbios_impl.h>
36 #include <sys/smbios.h>
37 #include <x86pi_impl.h>
38 
39 /* base baoed type values to hc-canonical-name */
40 static const struct x86pi_bb_name {
41 	int type;
42 	const char *name;
43 } x86pi_bb_names[] = {
44 	{ SMB_BBT_SBLADE,	"systemboard" },
45 	{ SMB_BBT_PROC,		"cpuboard" },
46 	{ SMB_BBT_IO,		"ioboard" },
47 	{ SMB_BBT_MEM,		"memboard" },
48 	{ SMB_BBT_DAUGHTER,	"systemboard" },
49 	{ SMB_BBT_MOTHER,	"motherboard" },
50 	{ SMB_BBT_PROCMEM,	"systemboard" },
51 	{ SMB_BBT_PROCIO,	"systemboard" },
52 	{ SMB_BBT_INTER,	"systemboard" },
53 	{ 0x00 }
54 };
55 
56 tnode_t *
57 x86pi_gen_bboard(topo_mod_t *mod, tnode_t *t_parent, int smb_id,
58     int instance, int psmb_id)
59 {
60 	int		rv;
61 	smbios_info_t	ip;
62 	smbios_bboard_t	bb;
63 	smbios_struct_t	sp;
64 	x86pi_hcfmri_t	bb_hcfmri;
65 	tnode_t		*bb_node;
66 	const struct x86pi_bb_name *bbnp;
67 	static int	cpuboard = 0;
68 	static int	memboard = 0;
69 	static int	ioboard = 0;
70 	static int	systemboard = 0;
71 	static int	motherboard = 0;
72 	char		*f = "x86pi_gen_bboard";
73 	smbios_hdl_t    *shp;
74 
75 	topo_mod_dprintf(mod, "%s\n", f);
76 
77 	shp = topo_mod_smbios(mod);
78 	if (shp == NULL) {
79 		topo_mod_dprintf(mod, "%s: failed to load SMBIOS\n", f);
80 		return (NULL);
81 	}
82 
83 	/* SMBIOS Base Board struct */
84 	rv = smbios_info_bboard(shp, smb_id, &bb);
85 	if (rv != 0) {
86 		topo_mod_dprintf(mod, "%s: smbios_info_bboard() failed\n", f);
87 		return (NULL);
88 	}
89 	(void) smbios_lookup_id(shp, psmb_id, &sp);
90 	if (sp.smbstr_type == SMB_TYPE_CHASSIS &&
91 	    bb.smbb_chassis != psmb_id) {
92 		topo_mod_dprintf(mod, "%s: base board (%d) does not belong to "
93 		    "chassis (%d)\n", f, smb_id, psmb_id);
94 		return (NULL);
95 	}
96 
97 	/* SMBIOS Base Board strings */
98 	rv = smbios_info_common(shp, smb_id, &ip);
99 	if (rv != 0) {
100 		return (NULL);
101 	}
102 
103 	/*
104 	 * populate string entries
105 	 *
106 	 * We don't set "product" because it may contain characters
107 	 * unacceptable by fmri.   topo_mod_auth() will set the product-id
108 	 * for us and call topo_cleanup_auth_str() when necessary.
109 	 */
110 	bb_hcfmri.serial_number = x86pi_cleanup_smbios_str(mod,
111 	    ip.smbi_serial, 0);
112 	bb_hcfmri.version = x86pi_cleanup_smbios_str(mod, ip.smbi_version, 0);
113 	/* asset tag string contains the part number */
114 	bb_hcfmri.part_number = x86pi_cleanup_smbios_str(mod,
115 	    ip.smbi_asset, 0);
116 	bb_hcfmri.location = x86pi_cleanup_smbios_str(mod, ip.smbi_location, 0);
117 
118 	/* determine the hc-name */
119 	for (bbnp = x86pi_bb_names; bbnp->type != 0x00; bbnp++) {
120 		if (bbnp->type == bb.smbb_type) {
121 			switch (bbnp->type) {
122 				case SMB_BBT_PROC :
123 					instance = cpuboard++;
124 					break;
125 				case SMB_BBT_IO :
126 					instance = ioboard++;
127 					break;
128 				case SMB_BBT_MEM :
129 					instance = memboard++;
130 					break;
131 				case SMB_BBT_MOTHER :
132 					instance = motherboard++;
133 					break;
134 				default :
135 					/*
136 					 * Enumerate any other baseboard type
137 					 * as systemboard.
138 					 *
139 					 * SMB_BBT_UNKNOWN
140 					 * SMB_BBT_OTHER
141 					 * SMB_BBT_SBLADE
142 					 * SMB_BBT_CSWITCH
143 					 * SMB_BBT_SMM
144 					 * SMB_BBT_DAUGHTER
145 					 * SMB_BBT_PROCMEM
146 					 * SMB_BBT_PROCIO
147 					 * SMB_BBT_INTER
148 					 */
149 					instance = systemboard++;
150 					break;
151 			}
152 			break;
153 		}
154 	}
155 
156 	bb_hcfmri.instance = instance;
157 	if (bbnp->type != 0x00)
158 		bb_hcfmri.hc_name = topo_mod_strdup(mod, bbnp->name);
159 	else
160 		bb_hcfmri.hc_name = topo_mod_strdup(mod, "NULL");
161 
162 	topo_mod_dprintf(mod, "%s: S/N (%s)\n", f, bb_hcfmri.serial_number);
163 	topo_mod_dprintf(mod, "%s: version/N (%s)\n", f, bb_hcfmri.version);
164 	topo_mod_dprintf(mod, "%s: Part/N (%s)\n", f, bb_hcfmri.part_number);
165 	topo_mod_dprintf(mod, "%s: location (%s)\n", f, bb_hcfmri.location);
166 	topo_mod_dprintf(mod, "%s: instance (%d)\n", f, bb_hcfmri.instance);
167 	topo_mod_dprintf(mod, "%s: hc_name (%s)\n", f, bb_hcfmri.hc_name);
168 
169 	rv = x86pi_enum_generic(mod, &bb_hcfmri, t_parent, t_parent, &bb_node,
170 	    X86PI_ENUM_FRU);
171 	if (rv != 0) {
172 		topo_mod_dprintf(mod, "%s: failed to create tnode %d\n", f,
173 		    instance);
174 		bb_node = NULL;
175 	}
176 
177 	/* free up strings */
178 	if (bb_hcfmri.hc_name != NULL) {
179 		topo_mod_strfree(mod, (char *)bb_hcfmri.hc_name);
180 	}
181 	if (bb_hcfmri.part_number != NULL) {
182 		topo_mod_strfree(mod, (char *)bb_hcfmri.part_number);
183 	}
184 	if (bb_hcfmri.serial_number != NULL) {
185 		topo_mod_strfree(mod, (char *)bb_hcfmri.serial_number);
186 	}
187 	if (bb_hcfmri.version != NULL) {
188 		topo_mod_strfree(mod, (char *)bb_hcfmri.version);
189 	}
190 	if (bb_hcfmri.location != NULL) {
191 		topo_mod_strfree(mod, (char *)bb_hcfmri.location);
192 	}
193 
194 	return (bb_node);
195 }
196 
197 
198 int
199 x86pi_bb_getchips(topo_mod_t *mod, int index, int nboards)
200 {
201 	id_t		*cid;
202 	int		count;
203 	int		ncmp = 0;
204 	smbios_struct_t	sp;
205 	smbs_cnt_t	*smbc = NULL;
206 	smbios_hdl_t *shp;
207 
208 	shp = topo_mod_smbios(mod);
209 	if (shp == NULL)
210 		return (ncmp);
211 
212 	cid = stypes[SMB_TYPE_BASEBOARD].ids[index].con_ids;
213 	count = stypes[SMB_TYPE_BASEBOARD].ids[index].con_cnt;
214 
215 	for (int i = 0; i < count; i++) {
216 		(void) smbios_lookup_id(shp, cid[i], &sp);
217 		if (sp.smbstr_type == SMB_TYPE_PROCESSOR) {
218 			ncmp++;
219 		}
220 	}
221 
222 	/*
223 	 * If there are missing SMB_TYPE_PROCESSOR structures
224 	 * contained within SMB_TYPE_BASEBOARD, and if the
225 	 * system has only one baseboard we enumerate
226 	 * all processors under it.
227 	 */
228 	smbc = &stypes[SMB_TYPE_PROCESSOR];
229 	smbc->type = SMB_TYPE_PROCESSOR;
230 	x86pi_smb_strcnt(mod, smbc);
231 
232 	if (nboards == 1) {
233 		if (ncmp != stypes[SMB_TYPE_PROCESSOR].count)
234 			ncmp = stypes[SMB_TYPE_PROCESSOR].count;
235 	} else {
236 		if (ncmp == 0) {
237 			topo_mod_dprintf(mod, "failed to get processors"
238 			    " (or) no processors are contained"
239 			    " within baseboard instance %d, unable to"
240 			    " enumerate chips\n", index);
241 		}
242 	}
243 
244 	return (ncmp);
245 }
246 
247 
248 id_t
249 x86pi_bb_topparent(topo_mod_t *mod, int index, tnode_t **pnode, id_t *psmbid)
250 {
251 
252 	id_t	top_bb_smbid = -1;
253 	id_t	smb_id;
254 	int	bb_count, ch_count;
255 	smbios_struct_t	sp;
256 	smbios_hdl_t *shp;
257 
258 	shp = topo_mod_smbios(mod);
259 	if (shp == NULL)
260 		return (top_bb_smbid);
261 
262 	smb_id = stypes[SMB_TYPE_BASEBOARD].ids[index].con_by_id;
263 	(void) smbios_lookup_id(shp, smb_id, &sp);
264 
265 	if (sp.smbstr_type == SMB_TYPE_CHASSIS) {
266 		top_bb_smbid = stypes[SMB_TYPE_BASEBOARD].ids[index].id;
267 		*psmbid = smb_id;
268 		ch_count = stypes[SMB_TYPE_CHASSIS].count;
269 		for (int i = 0; i < ch_count; i++)
270 			if (stypes[SMB_TYPE_CHASSIS].ids[i].id == *psmbid)
271 				*pnode = stypes[SMB_TYPE_CHASSIS].ids[i].node;
272 
273 		return (top_bb_smbid);
274 
275 	} else if (sp.smbstr_type == SMB_TYPE_BASEBOARD) {
276 		bb_count = stypes[SMB_TYPE_BASEBOARD].count;
277 		for (int i = 0; i < bb_count; i++) {
278 			if (stypes[SMB_TYPE_BASEBOARD].ids[i].id == smb_id) {
279 				if (stypes[SMB_TYPE_BASEBOARD].ids[i].visited
280 				    == X86PI_VISITED) {
281 					top_bb_smbid =
282 					    stypes[SMB_TYPE_BASEBOARD].\
283 					    ids[index].id;
284 					*pnode =
285 					    stypes[SMB_TYPE_BASEBOARD].ids[i].\
286 					    node;
287 					*psmbid =
288 					    stypes[SMB_TYPE_BASEBOARD].ids[i].\
289 					    id;
290 					break;
291 				}
292 				top_bb_smbid = x86pi_bb_topparent(mod,
293 				    i, pnode, psmbid);
294 				break;
295 			}
296 		}
297 	}
298 
299 	return (top_bb_smbid);
300 }
301 
302 
303 id_t
304 x86pi_bb_chassis(topo_mod_t *mod, id_t bb_smbid)
305 {
306 	smbios_bboard_t	bb;
307 	int		rv;
308 	smbios_hdl_t *shp;
309 
310 	shp = topo_mod_smbios(mod);
311 	if (shp == NULL)
312 		return (-1);
313 
314 	rv = smbios_info_bboard(shp, bb_smbid, &bb);
315 	if (rv != 0)
316 		return (-1);
317 
318 	return (bb.smbb_chassis);
319 }
320 
321 
322 int
323 x86pi_bb_contains(topo_mod_t *mod)
324 {
325 	int		rv;
326 	id_t		smb_id;
327 	smbios_bboard_t	bb;
328 	int		bb_count = 0;
329 	uint_t		cont_cnt = 0;
330 	smbios_struct_t	sp;
331 	smbios_hdl_t *shp;
332 
333 	shp = topo_mod_smbios(mod);
334 	if (shp == NULL)
335 		return (-1);
336 
337 	bb_count = stypes[SMB_TYPE_BASEBOARD].count;
338 	for (int i = 0; i < bb_count; i++) {
339 		smb_id = stypes[SMB_TYPE_BASEBOARD].ids[i].id;
340 		/* SMBIOS Base Board struct */
341 		rv = smbios_info_bboard(shp, smb_id, &bb);
342 		if (rv != 0)
343 			return (-1);
344 		/* Set Baseboard - Chassis Relationship */
345 		if (stypes[SMB_TYPE_BASEBOARD].ids[i].con_by_id == 0) {
346 			stypes[SMB_TYPE_BASEBOARD].ids[i].con_by_id =
347 			    rv = x86pi_bb_chassis(mod, smb_id);
348 			if (rv == -1) {
349 				topo_mod_dprintf(mod, " failed to get"
350 				    " the chassis handle\n");
351 				return (rv);
352 			}
353 		}
354 
355 		/* SMBIOS contained object handles */
356 		cont_cnt = bb.smbb_contn;
357 		if (cont_cnt > 0) {
358 			id_t *cont_hdl;
359 			uint16_t hdl;
360 
361 			/* allocate space for and get contained handles */
362 			cont_hdl = topo_mod_alloc(mod, cont_cnt *
363 			    sizeof (id_t));
364 			rv = smbios_info_contains(shp, smb_id, cont_cnt,
365 			    cont_hdl);
366 			if (rv > SMB_CONT_MAX) {
367 				topo_mod_free(mod, cont_hdl, cont_cnt *
368 				    sizeof (id_t));
369 				return (-1);
370 			}
371 			cont_cnt = MIN(rv, cont_cnt);
372 
373 			/* attach contained handles */
374 			stypes[SMB_TYPE_BASEBOARD].ids[i].con_cnt = cont_cnt;
375 			for (int j = 0; j < cont_cnt; j++) {
376 				hdl = (uint16_t)cont_hdl[j];
377 				topo_mod_dprintf(mod, "id %d contained handle"
378 				    " %d: %d\n", i, j, hdl);
379 				stypes[SMB_TYPE_BASEBOARD].ids[i].\
380 				    con_ids[j] = hdl;
381 				(void) smbios_lookup_id(shp, hdl, &sp);
382 				if (sp.smbstr_type == SMB_TYPE_BASEBOARD) {
383 					for (int k = 0; k < bb_count; k++)
384 						if (stypes[SMB_TYPE_BASEBOARD].\
385 						    ids[k].id == hdl)
386 							stypes[\
387 							    SMB_TYPE_BASEBOARD\
388 							    ].ids[k].con_by_id =
389 							    smb_id;
390 				}
391 			}
392 			topo_mod_free(mod, cont_hdl, cont_cnt * sizeof (id_t));
393 		}
394 	}
395 	return (0);
396 }
397