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