xref: /illumos-gate/usr/src/uts/intel/os/fmsmb.c (revision f76de749)
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  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/types.h>
27 #include <sys/time.h>
28 #include <sys/nvpair.h>
29 #include <sys/cmn_err.h>
30 #include <sys/fm/util.h>
31 #include <sys/fm/protocol.h>
32 #include <sys/smbios.h>
33 #include <sys/smbios_impl.h>
34 
35 /*
36  * Variable used to determine if the x86 generic topology enumerator will
37  * revert to legacy enumeration. I.E. Big Kill Switch... tunable via
38  * /etc/system
39  */
40 int x86gentopo_legacy = 0;
41 
42 #define	MC		0
43 #define	PROC		1
44 #define	MAX_PAIRS	20
45 #define	MAX_CONT	40
46 
47 typedef struct bbindex  {
48 	int count;
49 	uint16_t index[MAX_PAIRS];
50 } bbindex_t;
51 
52 /*
53  * the enum values come from DMTF
54  */
55 typedef enum baseb {
56 	BB_BAD = 0,		/* There is no bb value 0 */
57 	BB_UNKNOWN,		/* Unknown */
58 	BB_OTHER,		/* Other */
59 	BB_BLADE,		/* Server Blade */
60 	BB_CONNSW,		/* Connectivity Switch */
61 	BB_SMM,			/* System Management Module */
62 	BB_PROCMOD,		/* Processor Module */
63 	BB_IOMOD,		/* I/O Module */
64 	BB_MEMMOD,		/* Memory Module */
65 	BB_DBOARD,		/* Daughter Board */
66 	BB_MBOARD,		/* Motherboard */
67 	BB_PROCMMOD,		/* Processor/Memory Module */
68 	BB_PROCIOMOD,		/* Processor/IO Module */
69 	BB_ICONNBD		/* Interconnect Board */
70 } bbd_t;
71 
72 static struct bboard_type {
73 	bbd_t		baseb;
74 	const char	*name;
75 } bbd_type[] = {
76 	{BB_BAD,		NULL},
77 	{BB_UNKNOWN,		"unknown"},
78 	{BB_OTHER,		"other"},
79 	{BB_BLADE,		"systemboard"},
80 	{BB_CONNSW,		"connswitch"},
81 	{BB_SMM,		"smmodule"},
82 	{BB_PROCMOD,		"cpuboard"},
83 	{BB_IOMOD,		"ioboard"},
84 	{BB_MEMMOD,		"memboard"},
85 	{BB_DBOARD,		"systemboard"},
86 	{BB_MBOARD,		"motherboard"},
87 	{BB_PROCMMOD,		"systemboard"},
88 	{BB_PROCIOMOD,		"systemboard"},
89 	{BB_ICONNBD,		"systemboard"}
90 };
91 
92 typedef struct smbs_con_ids {
93 	int id;
94 	int inst;
95 	int cont_count;
96 	uint16_t **cont_ids;
97 	int cont_by_id;
98 	int visited;
99 } smbs_con_ids_t;
100 
101 typedef struct smbs_cnt {
102 	int type;			/* SMBIOS stucture type */
103 	int count;			/* number of table entries */
104 	smbs_con_ids_t **ids;		/* SMBIOS table entry id(s) */
105 } smbs_cnt_t;
106 
107 /*
108  * dynamically allocate the storage for the smbs_cnt_t
109  */
110 static smbs_cnt_t *
111 smb_create_strcnt(int count)
112 {
113 	smbs_cnt_t *types = NULL;
114 	int i, j;
115 
116 	types = kmem_zalloc(sizeof (smbs_cnt_t), KM_SLEEP);
117 
118 	types->ids = (smbs_con_ids_t **)kmem_zalloc(
119 	    count * sizeof (smbs_con_ids_t *), KM_SLEEP);
120 
121 	for (i = 0; i < count; i++) {
122 		types->ids[i] = (smbs_con_ids_t *)kmem_zalloc(
123 		    sizeof (smbs_con_ids_t), KM_SLEEP);
124 	}
125 
126 	for (i = 0; i < count; i++) {
127 		types->ids[i]->cont_ids = (uint16_t **)kmem_zalloc(
128 		    MAX_CONT * sizeof (uint16_t *), KM_SLEEP);
129 	}
130 
131 	for (i = 0; i < count; i++) {
132 		for (j = 0; j < MAX_CONT; j++) {
133 			types->ids[i]->cont_ids[j] = (uint16_t *)kmem_zalloc(
134 			    sizeof (uint16_t), KM_SLEEP);
135 		}
136 	}
137 	return (types);
138 }
139 
140 /*
141  * free the smbs_cnt_t memory
142  */
143 static void
144 smb_free_strcnt(smbs_cnt_t *types, int count)
145 {
146 	int i, j;
147 
148 	if (types == NULL)
149 		return;
150 
151 	for (i = 0; i < count; i++) {
152 		for (j = 0; j < MAX_CONT; j++) {
153 			if (types->ids[i]->cont_ids[j] != NULL)
154 				kmem_free(types->ids[i]->cont_ids[j],
155 				    sizeof (uint16_t));
156 		}
157 	}
158 
159 	for (i = 0; i < count; i++) {
160 		if (types->ids[i]->cont_ids != NULL)
161 			kmem_free(types->ids[i]->cont_ids,
162 			    MAX_CONT * sizeof (uint16_t *));
163 	}
164 
165 	for (i = 0; i < count; i++) {
166 		if (types->ids[i] != NULL)
167 			kmem_free(types->ids[i], sizeof (smbs_con_ids_t));
168 	}
169 
170 	if (types->ids != NULL)
171 		kmem_free(types->ids, count * sizeof (smbs_con_ids_t *));
172 
173 	if (types != NULL)
174 		kmem_free(types, sizeof (smbs_cnt_t));
175 
176 }
177 
178 /*
179  * count number of the structure type in the ksmbios
180  */
181 static int
182 smb_cnttypes(smbios_hdl_t *shp, int type)
183 {
184 	const smb_struct_t *sp = shp->sh_structs;
185 	int nstructs = shp->sh_nstructs;
186 	int i;
187 	int cnt = 0;
188 
189 	for (i = 0, cnt = 0; i < nstructs; i++, sp++) {
190 		if (sp->smbst_hdr->smbh_type == type)
191 			cnt++;
192 	}
193 	return (cnt);
194 }
195 
196 static void
197 smb_strcnt(smbios_hdl_t *shp, smbs_cnt_t *stype)
198 {
199 	const smb_struct_t *sp = shp->sh_structs;
200 	int nstructs = shp->sh_nstructs;
201 	smbios_bboard_t bb;
202 	int i, cnt;
203 	int mb_cnt = 0;
204 	int cpub_cnt = 0;
205 	int sysb_cnt = 0;
206 	int memb_cnt = 0;
207 	int iob_cnt = 0;
208 	int inst = 0;
209 	int rc = 0;
210 
211 	for (i = 0, cnt = 0; i < nstructs; i++, sp++) {
212 		if (sp->smbst_hdr->smbh_type == stype->type) {
213 			stype->ids[cnt]->id = sp->smbst_hdr->smbh_hdl;
214 			stype->ids[cnt]->inst = cnt;
215 			stype->ids[cnt]->visited = 0;
216 			stype->ids[cnt]->cont_by_id = -1;
217 			if (stype->type == SMB_TYPE_BASEBOARD) {
218 				rc = smbios_info_bboard(shp,
219 				    stype->ids[cnt]->id, &bb);
220 				if (rc == 0) {
221 					switch (bb.smbb_type) {
222 						case SMB_BBT_PROC :
223 							inst = cpub_cnt++;
224 							break;
225 						case SMB_BBT_IO :
226 							inst = iob_cnt++;
227 							break;
228 						case SMB_BBT_MEM :
229 							inst = memb_cnt++;
230 							break;
231 						case SMB_BBT_MOTHER :
232 							inst = mb_cnt++;
233 							break;
234 						default:
235 							/*
236 							 * SMB_BBT_UNKNOWN
237 							 * SMB_BBT_OTHER
238 							 * SMB_BBT_SBLADE
239 							 * SMB_BBT_CSWITCH
240 							 * SMB_BBT_SMM
241 							 * SMB_BBT_DAUGHTER
242 							 * SMB_BBT_PROCMEM
243 							 * SMB_BBT_PROCIO
244 							 * SMB_BBT_INTER
245 							 */
246 							inst = sysb_cnt++;
247 							break;
248 					}
249 					stype->ids[cnt]->inst = inst;
250 				}
251 			}
252 			cnt++;
253 		}
254 	}
255 	stype->count = cnt;
256 }
257 
258 /*
259  * Go through the smbios structures looking for type 2. Fill in
260  * the cont_id and cont_by_id for each type 2
261  *
262  */
263 static void
264 smb_bb_contains(smbios_hdl_t *shp, smbs_cnt_t *stype)
265 {
266 	int i, j, cnt, c;
267 	uint_t cont_count;
268 	const smb_struct_t *spt;
269 	smbios_bboard_t smb_bb;
270 	uint16_t bb_id, cont_id;
271 	uint_t cont_len;
272 	id_t *cont_hdl = NULL;
273 	int rc;
274 
275 	for (cnt = 0; cnt < stype->count; cnt++) {
276 		bb_id = stype->ids[cnt]->id;
277 		(void) smbios_info_bboard(shp, stype->ids[cnt]->id, &smb_bb);
278 		cont_count = (uint_t)smb_bb.smbb_contn;
279 		if (cont_count == 0) {
280 			continue;
281 		}
282 
283 		cont_len = sizeof (id_t);
284 		cont_hdl = kmem_zalloc(cont_count * cont_len, KM_SLEEP);
285 		if (cont_hdl == NULL)
286 			continue;
287 
288 		rc = smbios_info_contains(shp, stype->ids[cnt]->id,
289 		    cont_count, cont_hdl);
290 		if (rc > SMB_CONT_MAX) {
291 			kmem_free(cont_hdl, cont_count * cont_len);
292 			continue;
293 		}
294 		cont_count = MIN(rc, cont_count);
295 
296 		/*
297 		 * fill in the type 2 and type 4 ids which are
298 		 * contained in this type 2
299 		 */
300 		c = 0;
301 		for (j = 0; j < cont_count; j++) {
302 			cont_id = (uint16_t)cont_hdl[j];
303 			spt = smb_lookup_id(shp, cont_id);
304 			if (spt->smbst_hdr->smbh_type == SMB_TYPE_BASEBOARD ||
305 			    spt->smbst_hdr->smbh_type == SMB_TYPE_PROCESSOR) {
306 				*stype->ids[cnt]->cont_ids[c] = cont_id;
307 				c++;
308 			}
309 
310 			if (spt->smbst_hdr->smbh_type == SMB_TYPE_BASEBOARD) {
311 				for (i = 0; i < stype->count; i++) {
312 					if (stype->ids[i]->id == cont_id) {
313 						stype->ids[i]->cont_by_id =
314 						    bb_id;
315 					}
316 				}
317 			}
318 
319 		}
320 		stype->ids[cnt]->cont_count = c;
321 		if (cont_hdl != NULL)
322 			kmem_free(cont_hdl, cont_count * cont_len);
323 	}
324 }
325 
326 /*
327  * Verify SMBIOS structures for x86 generic topology.
328  *
329  * Return (0) on success.
330  */
331 static int
332 fm_smb_check(smbios_hdl_t *shp)
333 {
334 	int i, j;
335 	int bb_cnt = 0;
336 	int pr_cnt = 0;
337 	int expr_cnt = 0;
338 	int ma_cnt = 0;
339 	int exma_cnt = 0;
340 	int mdev_cnt = 0;
341 	int exmdev_cnt = 0;
342 	uint16_t bb_id;
343 	uint16_t pr_id, expr_id;
344 	uint16_t ma_id, exma_id;
345 	uint16_t mdev_id, exmdev_id;
346 	uint16_t *sys_ma;
347 	smbios_bboard_t bb;
348 	smbios_processor_ext_t exproc;
349 	smbios_memarray_t ma;
350 	smbios_memarray_ext_t exma;
351 	smbios_memdevice_t mdev;
352 	smbios_memdevice_ext_t exmdev;
353 	smbs_cnt_t *bb_stype;
354 	smbs_cnt_t *pr_stype, *expr_stype;
355 	smbs_cnt_t *ma_stype, *exma_stype;
356 	smbs_cnt_t *mdev_stype, *exmdev_stype;
357 
358 	/*
359 	 * Verify the existance of the requuired extended OEM-Specific
360 	 * structures and they coincide with the structures they extend
361 	 * (e.g. the number of extended processor structures equal the
362 	 * number of processor structures).
363 	 */
364 	pr_cnt = smb_cnttypes(shp, SMB_TYPE_PROCESSOR);
365 	expr_cnt = smb_cnttypes(shp, SUN_OEM_EXT_PROCESSOR);
366 	ma_cnt = smb_cnttypes(shp, SMB_TYPE_MEMARRAY);
367 	exma_cnt = smb_cnttypes(shp, SUN_OEM_EXT_MEMARRAY);
368 	mdev_cnt = smb_cnttypes(shp, SMB_TYPE_MEMDEVICE);
369 	exmdev_cnt = smb_cnttypes(shp, SUN_OEM_EXT_MEMDEVICE);
370 	if (expr_cnt == 0 || exma_cnt == 0 || exmdev_cnt == 0 ||
371 	    expr_cnt != pr_cnt || exma_cnt > ma_cnt ||
372 	    exmdev_cnt > mdev_cnt) {
373 #ifdef	DEBUG
374 		cmn_err(CE_NOTE, "!Structure mismatch: ext_proc (%d) "
375 		    "proc (%d) ext_ma (%d) ma (%d) ext_mdev (%d) mdev (%d)\n",
376 		    expr_cnt, pr_cnt, exma_cnt, ma_cnt, exmdev_cnt,
377 		    mdev_cnt);
378 #endif	/* DEBUG */
379 		return (-1);
380 	}
381 
382 	/*
383 	 * Verify the OEM-Specific structrures are correctly
384 	 * linked to the SMBIOS structure types they extend.
385 	 */
386 
387 	/* allocate processor stypes */
388 	pr_stype = smb_create_strcnt(pr_cnt);
389 	expr_stype = smb_create_strcnt(expr_cnt);
390 
391 	/* fill in stypes */
392 	pr_stype->type = SMB_TYPE_PROCESSOR;
393 	smb_strcnt(shp, pr_stype);
394 	expr_stype->type = SUN_OEM_EXT_PROCESSOR;
395 	smb_strcnt(shp, expr_stype);
396 
397 	/* verify the ext proc struct belong to the proc struct */
398 	for (i = 0; i < pr_cnt; i++) {
399 		pr_id = pr_stype->ids[i]->id;
400 		expr_id = expr_stype->ids[i]->id;
401 		(void) smbios_info_extprocessor(shp, expr_id, &exproc);
402 		if (exproc.smbpe_processor != pr_id) {
403 #ifdef	DEBUG
404 			cmn_err(CE_NOTE, "!Processor struct linkage (%d)", i);
405 #endif	/* DEBUG */
406 			smb_free_strcnt(pr_stype, pr_cnt);
407 			smb_free_strcnt(expr_stype, expr_cnt);
408 			return (-1);
409 		}
410 	}
411 
412 	/* free stypes */
413 	smb_free_strcnt(pr_stype, pr_cnt);
414 	smb_free_strcnt(expr_stype, expr_cnt);
415 
416 	/* allocate memory array stypes */
417 	ma_stype = smb_create_strcnt(ma_cnt);
418 	exma_stype = smb_create_strcnt(exma_cnt);
419 	sys_ma = kmem_zalloc(sizeof (uint16_t) * ma_cnt, KM_SLEEP);
420 
421 	/* fill in stypes */
422 	ma_stype->type = SMB_TYPE_MEMARRAY;
423 	smb_strcnt(shp, ma_stype);
424 	exma_stype->type = SUN_OEM_EXT_MEMARRAY;
425 	smb_strcnt(shp, exma_stype);
426 
427 	/* verify linkage from ext memarray struct to memarray struct */
428 	for (i = 0; i < ma_cnt; i++) {
429 		sys_ma[i] = (uint16_t)-1;
430 		ma_id = ma_stype->ids[i]->id;
431 		(void) smbios_info_memarray(shp, ma_id, &ma);
432 		if (ma.smbma_use != SMB_MAU_SYSTEM)
433 			continue;
434 		/* this memarray is system memory */
435 		sys_ma[i] = ma_id;
436 		exma_id = exma_stype->ids[i]->id;
437 		(void) smbios_info_extmemarray(shp, exma_id, &exma);
438 		if (exma.smbmae_ma != ma_id) {
439 #ifdef	DEBUG
440 			cmn_err(CE_NOTE,
441 			    "!Memory Array struct linkage (%d)", i);
442 #endif	/* DEBUG */
443 			smb_free_strcnt(ma_stype, ma_cnt);
444 			smb_free_strcnt(exma_stype, exma_cnt);
445 			kmem_free(sys_ma, sizeof (uint16_t) * ma_cnt);
446 			return (-1);
447 		}
448 	}
449 
450 	/* free stypes */
451 	smb_free_strcnt(ma_stype, ma_cnt);
452 	smb_free_strcnt(exma_stype, exma_cnt);
453 
454 	/* allocate memory device stypes */
455 	mdev_stype = smb_create_strcnt(mdev_cnt);
456 	exmdev_stype = smb_create_strcnt(exmdev_cnt);
457 
458 	/* fill in stypes */
459 	mdev_stype->type = SMB_TYPE_MEMDEVICE;
460 	smb_strcnt(shp, mdev_stype);
461 	exmdev_stype->type = SUN_OEM_EXT_MEMDEVICE;
462 	smb_strcnt(shp, exmdev_stype);
463 
464 	/* verify linkage */
465 	for (i = 0; i < mdev_cnt; i++) {
466 		mdev_id = mdev_stype->ids[i]->id;
467 		(void) smbios_info_memdevice(shp, mdev_id, &mdev);
468 		/* only check system memory devices */
469 		for (j = 0; j < ma_cnt; j++) {
470 			if (sys_ma[j] == mdev.smbmd_array)
471 				break;
472 		}
473 		if (j == ma_cnt)
474 			continue;
475 		exmdev_id = exmdev_stype->ids[i]->id;
476 		(void) smbios_info_extmemdevice(shp, exmdev_id, &exmdev);
477 		if (exmdev.smbmdeve_md != mdev_id) {
478 #ifdef	DEBUG
479 			cmn_err(CE_NOTE, "!Memory Device struct linkage (%d)",
480 			    i);
481 #endif	/* DEBUG */
482 			smb_free_strcnt(mdev_stype, mdev_cnt);
483 			smb_free_strcnt(exmdev_stype, exmdev_cnt);
484 			kmem_free(sys_ma, sizeof (uint16_t) * ma_cnt);
485 			return (-1);
486 		}
487 	}
488 
489 	/* free stypes */
490 	smb_free_strcnt(mdev_stype, mdev_cnt);
491 	smb_free_strcnt(exmdev_stype, exmdev_cnt);
492 	kmem_free(sys_ma, sizeof (uint16_t) * ma_cnt);
493 
494 	/*
495 	 * Verify the presece of contained handles if there are more
496 	 * than one Type-2 (Base Board) structures.
497 	 */
498 	bb_cnt = smb_cnttypes(shp, SMB_TYPE_BASEBOARD);
499 	if (bb_cnt > 1) {
500 		/* allocate base board stypes */
501 		bb_stype = smb_create_strcnt(bb_cnt);
502 
503 		/* fill in stypes */
504 		bb_stype->type = SMB_TYPE_BASEBOARD;
505 		smb_strcnt(shp, bb_stype);
506 
507 		/* verify contained handles */
508 		for (i = 0; i < bb_cnt; i++) {
509 			bb_id = bb_stype->ids[i]->id;
510 			(void) smbios_info_bboard(shp, bb_id, &bb);
511 			if (bb.smbb_contn == 0) {
512 #ifdef	DEBUG
513 				cmn_err(CE_NOTE, "!No contained hanldes (%d)",
514 				    i);
515 #endif	/* DEBUG */
516 				smb_free_strcnt(bb_stype, bb_cnt);
517 				return (-1);
518 			}
519 		}
520 
521 		/* free stypes */
522 		smb_free_strcnt(bb_stype, bb_cnt);
523 	}
524 
525 	return (0);
526 }
527 
528 void
529 fm_smb_fmacompat()
530 {
531 	int i, j;
532 	int id;
533 	int cnt;
534 	const char **oem_strings = NULL;
535 	smbs_cnt_t *oemstypes;
536 	smbios_hdl_t *shp;
537 	int strcnt;
538 	int compat = 0;
539 
540 	/* check for BKS */
541 	if (x86gentopo_legacy == 1) {
542 		return;
543 	}
544 
545 	shp = ksmbios;
546 	if (shp == NULL) {
547 		goto bad;
548 	}
549 
550 	/* OEM strings (Type 11) */
551 	strcnt = smb_cnttypes(shp, SMB_TYPE_OEMSTR);
552 	if (strcnt == 0)
553 		goto bad;
554 
555 	oemstypes = smb_create_strcnt(strcnt);
556 	if (oemstypes == NULL)
557 		goto bad;
558 
559 	oemstypes->type = SMB_TYPE_OEMSTR;
560 	smb_strcnt(shp, oemstypes);
561 
562 	for (i = 0; i < oemstypes->count; i++) {
563 		id = oemstypes->ids[i]->id;
564 		cnt = smbios_info_strtab(shp, id, 0, NULL);
565 		if (cnt > 0) {
566 			oem_strings = kmem_zalloc(sizeof (char *) * cnt,
567 			    KM_SLEEP);
568 			(void) smbios_info_strtab(shp, id, cnt, oem_strings);
569 
570 			for (j = 0; j < cnt; j++) {
571 				if (strncmp(oem_strings[j], SMB_PRMS1,
572 				    strlen(SMB_PRMS1) + 1) == 0) {
573 					kmem_free(oem_strings,
574 					    sizeof (char *) * cnt);
575 					smb_free_strcnt(oemstypes, strcnt);
576 					compat = 1;
577 					break;
578 				}
579 			}
580 		}
581 	}
582 
583 	if (compat == 0) {
584 		/* didn't find x86pi magic cookie */
585 		if (oem_strings != NULL)
586 			kmem_free(oem_strings, sizeof (char *) * cnt);
587 		smb_free_strcnt(oemstypes, strcnt);
588 		goto bad;
589 	}
590 
591 	/* sanity check SMBIOS structures */
592 	if (fm_smb_check(shp) == 0)
593 		return;
594 
595 bad:
596 	/* not compatible with x86gentopo; revert to legacy enumeration */
597 #ifdef	DEBUG
598 	cmn_err(CE_NOTE,
599 	    "!SMBIOS is not compatible with x86 generic topology.");
600 	cmn_err(CE_NOTE, "!Invoking legacy x86 topology enumeration.");
601 #endif	/* DEBUG */
602 	x86gentopo_legacy = 1;
603 }
604 
605 static int
606 find_matching_apic(smbios_hdl_t *shp, uint16_t proc_id, uint_t strand_apicid)
607 {
608 	uint16_t ext_id;
609 	int i, j;
610 	smbios_processor_ext_t ep;
611 	smbs_cnt_t *pstypes;
612 	int strcnt;
613 
614 	strcnt = smb_cnttypes(shp, SUN_OEM_EXT_PROCESSOR);
615 	if (strcnt == 0)
616 		return (0);
617 
618 	pstypes = smb_create_strcnt(strcnt);
619 	if (pstypes == NULL)
620 		return (0);
621 
622 	pstypes->type = SUN_OEM_EXT_PROCESSOR;
623 	smb_strcnt(shp, pstypes);
624 	for (i = 0; i < pstypes->count; i++) {
625 		ext_id = pstypes->ids[i]->id;
626 		(void) smbios_info_extprocessor(shp, ext_id, &ep);
627 		if (ep.smbpe_processor == proc_id) {
628 			for (j = 0; j < ep.smbpe_n; j++) {
629 				if (ep.smbpe_apicid[j] == strand_apicid) {
630 					smb_free_strcnt(pstypes, strcnt);
631 					return (1);
632 				}
633 			}
634 		}
635 	}
636 	smb_free_strcnt(pstypes, strcnt);
637 	return (0);
638 }
639 
640 /*
641  * go throught the type 2 structure contained_ids looking for
642  * the type 4 which  has strand_apicid == this strand_apicid
643  */
644 static int
645 find_matching_proc(smbios_hdl_t *shp, uint_t strand_apicid,
646     uint16_t bb_id, uint16_t proc_hdl, int is_proc)
647 {
648 	int n;
649 	const smb_struct_t *sp;
650 	smbios_bboard_t bb;
651 	uint_t cont_count, cont_len;
652 	uint16_t cont_id;
653 	id_t *cont_hdl = NULL;
654 	int rc;
655 
656 
657 	(void) smbios_info_bboard(shp, bb_id, &bb);
658 	cont_count = (uint_t)bb.smbb_contn;
659 	if (cont_count == 0)
660 		return (0);
661 
662 	cont_len = sizeof (id_t);
663 	cont_hdl = kmem_zalloc(cont_count * cont_len, KM_SLEEP);
664 	if (cont_hdl == NULL)
665 		return (0);
666 
667 	rc = smbios_info_contains(shp, bb_id, cont_count, cont_hdl);
668 	if (rc > SMB_CONT_MAX) {
669 		kmem_free(cont_hdl, cont_count * cont_len);
670 		return (0);
671 	}
672 	cont_count = MIN(rc, cont_count);
673 
674 	for (n = 0; n < cont_count; n++) {
675 		cont_id = (uint16_t)cont_hdl[n];
676 		sp = smb_lookup_id(shp, cont_id);
677 		if (sp->smbst_hdr->smbh_type == SMB_TYPE_PROCESSOR) {
678 			if (is_proc) {
679 				if (find_matching_apic(shp, cont_id,
680 				    strand_apicid)) {
681 					kmem_free(cont_hdl,
682 					    cont_count * cont_len);
683 					return (1);
684 				}
685 			} else {
686 				if (cont_id == proc_hdl) {
687 					kmem_free(cont_hdl,
688 					    cont_count * cont_len);
689 					return (1);
690 				}
691 			}
692 		}
693 	}
694 	if (cont_hdl != NULL)
695 		kmem_free(cont_hdl, cont_count * cont_len);
696 
697 	return (0);
698 }
699 
700 void
701 get_bboard_index(smbs_cnt_t *bbstypes, uint_t bb_id, bbindex_t *bb_idx)
702 {
703 	int curr_id, tmp_id;
704 	int i, j, nb;
705 	bbindex_t tmp_idx;
706 
707 	for (i = 0; i < MAX_PAIRS; i++)
708 		tmp_idx.index[i] = 0;
709 
710 	tmp_idx.count = 0;
711 
712 	curr_id = bb_id;
713 	for (nb = bbstypes->count-1, i = 0; nb >= 0; nb--) {
714 		tmp_id = bbstypes->ids[nb]->id;
715 		if (tmp_id == curr_id) {
716 			tmp_idx.index[i] = nb;
717 			tmp_idx.count++;
718 			curr_id = bbstypes->ids[nb]->cont_by_id;
719 			if (curr_id == -1)
720 				break;
721 			i++;
722 		}
723 	}
724 
725 	for (i = tmp_idx.count - 1, j = 0; i >= 0; i--) {
726 		bb_idx->index[j] = tmp_idx.index[i];
727 		j++;
728 	}
729 
730 	bb_idx->count = tmp_idx.count;
731 }
732 
733 int
734 get_chassis_inst(smbios_hdl_t *shp, uint16_t *chassis_inst,
735     uint16_t bb_id, int *chcnt)
736 {
737 	int ch_strcnt;
738 	smbs_cnt_t *chstypes;
739 	uint16_t chassis_id, tmp_id;
740 	smbios_bboard_t bb;
741 	int rc = 0;
742 	int i;
743 
744 	rc = smbios_info_bboard(shp, bb_id, &bb);
745 	if (rc != 0) {
746 		return (-1);
747 	}
748 
749 	chassis_id = bb.smbb_chassis;
750 
751 	ch_strcnt = smb_cnttypes(shp, SMB_TYPE_CHASSIS);
752 
753 	if (ch_strcnt == 0)
754 		return (-1);
755 
756 	chstypes = smb_create_strcnt(ch_strcnt);
757 	if (chstypes == NULL)
758 		return (-1);
759 
760 	chstypes->type = SMB_TYPE_CHASSIS;
761 	smb_strcnt(shp, chstypes);
762 
763 	for (i = 0; i < chstypes->count; i++) {
764 		tmp_id = chstypes->ids[i]->id;
765 		if (tmp_id == chassis_id) {
766 			*chassis_inst = chstypes->ids[i]->inst;
767 			if (chstypes->ids[i]->inst != 0)
768 				*chcnt = 2;
769 			else
770 				*chcnt = 1;
771 			smb_free_strcnt(chstypes, ch_strcnt);
772 			return (0);
773 		}
774 	}
775 
776 	smb_free_strcnt(chstypes, ch_strcnt);
777 	return (-1);
778 }
779 
780 int
781 smb_get_bb_fmri(smbios_hdl_t *shp, nvlist_t *fmri,  uint_t parent,
782     smbs_cnt_t *bbstypes)
783 {
784 	int rc = 0;
785 	int i, j, n, cnt;
786 	int id, index;
787 	nvlist_t *pairs[MAX_PAIRS];
788 	smbios_bboard_t bb;
789 	uint16_t chassis_inst, mch_inst;
790 	char name[40];
791 	char idstr[11];
792 	bbindex_t bb_idx;
793 	uint16_t bbid;
794 	int chcnt = 0;
795 
796 	for (n = 0; n < MAX_PAIRS; n++) {
797 		bb_idx.index[n] = 0;
798 		pairs[n] = NULL;
799 	}
800 	bb_idx.count = 0;
801 
802 	get_bboard_index(bbstypes, parent, &bb_idx);
803 
804 	index = bb_idx.index[0];
805 	bbid = bbstypes->ids[index]->id;
806 
807 	rc = get_chassis_inst(shp, &chassis_inst, bbid, &chcnt);
808 
809 	if (rc != 0) {
810 		return (rc);
811 	}
812 
813 	if ((bb_idx.count + chcnt) > MAX_PAIRS) {
814 		return (-1);
815 	}
816 
817 	i = 0;
818 	if (chcnt > 1) {
819 		/*
820 		 * create main chassis pair
821 		 */
822 		pairs[i] = fm_nvlist_create(NULL);
823 		if (pairs[i] == NULL) {
824 			return (-1);
825 		}
826 		mch_inst = 0;
827 		(void) snprintf(idstr, sizeof (idstr), "%u", mch_inst);
828 		if ((nvlist_add_string(pairs[i], FM_FMRI_HC_NAME,
829 		    "chassis") != 0) ||
830 		    (nvlist_add_string(pairs[i], FM_FMRI_HC_ID, idstr)) != 0) {
831 			fm_nvlist_destroy(pairs[i], FM_NVA_FREE);
832 			return (-1);
833 		}
834 		i++;
835 	}
836 
837 	/*
838 	 * create chassis pair
839 	 */
840 	pairs[i] = fm_nvlist_create(NULL);
841 	if (pairs[i] == NULL) {
842 		for (n = 0; n < MAX_PAIRS; n++) {
843 			if (pairs[n] != NULL)
844 				fm_nvlist_destroy(pairs[n], FM_NVA_FREE);
845 		}
846 		return (-1);
847 	}
848 	(void) snprintf(idstr, sizeof (idstr), "%u", chassis_inst);
849 	if ((nvlist_add_string(pairs[i], FM_FMRI_HC_NAME, "chassis") != 0) ||
850 	    (nvlist_add_string(pairs[i], FM_FMRI_HC_ID, idstr) != 0)) {
851 		for (n = 0; n < MAX_PAIRS; n++) {
852 			if (pairs[n] != NULL)
853 				fm_nvlist_destroy(pairs[n], FM_NVA_FREE);
854 		}
855 		return (-1);
856 	}
857 
858 	for (j = 0, i = chcnt, cnt = chcnt; j < bb_idx.count; j++) {
859 		index = bb_idx.index[j];
860 		bbid = bbstypes->ids[index]->id;
861 		rc =  smbios_info_bboard(shp, bbid, &bb);
862 		if (rc != 0) {
863 			rc = -1;
864 			break;
865 		}
866 
867 		pairs[i] = fm_nvlist_create(NULL);
868 		if (pairs[i] == NULL) {
869 			rc = -1;
870 			break;
871 		}
872 
873 		id = bbstypes->ids[index]->inst;
874 		(void) snprintf(idstr, sizeof (idstr), "%u", id);
875 		(void) strncpy(name, bbd_type[bb.smbb_type].name,
876 		    sizeof (name));
877 		cnt++;
878 
879 		if (nvlist_add_string(pairs[i], FM_FMRI_HC_NAME, name) != 0 ||
880 		    nvlist_add_string(pairs[i], FM_FMRI_HC_ID, idstr)
881 		    != 0) {
882 			rc = -1;
883 			break;
884 		}
885 		i++;
886 	}
887 
888 	if (rc != -1) {
889 		if (nvlist_add_nvlist_array(fmri, FM_FMRI_HC_LIST,
890 		    pairs, cnt) != 0) {
891 			rc = -1;
892 		}
893 	}
894 
895 	for (n = 0; n < cnt; n++) {
896 		if (pairs[n] != NULL)
897 			fm_nvlist_destroy(pairs[n], FM_NVA_FREE);
898 	}
899 
900 	return (rc);
901 }
902 
903 /*
904  * pass in strand_apic id
905  * return chip's bboards list which has strand_apicid == passed
906  * in strand_apic id
907  */
908 static nvlist_t *
909 smb_bboard(uint_t strand_apicid, uint16_t proc_hdl, int is_proc)
910 {
911 	smbios_hdl_t *shp;
912 	smbs_cnt_t *bbstypes;
913 	int nb;
914 	int bb_smbid;
915 	nvlist_t *fmri = NULL;
916 	int rc = 0;
917 	int bb_strcnt;
918 
919 	if (x86gentopo_legacy)
920 		return (NULL);
921 
922 	shp = ksmbios;
923 	if (shp == NULL) {
924 		goto bad;
925 	}
926 
927 	/*
928 	 * Type 2 structs : "base board"
929 	 */
930 	bb_strcnt = smb_cnttypes(shp, SMB_TYPE_BASEBOARD);
931 	if (bb_strcnt == 0) {
932 		goto bad;
933 	}
934 
935 	bbstypes = smb_create_strcnt(bb_strcnt);
936 	if (bbstypes == NULL)  {
937 		goto bad;
938 	}
939 
940 	bbstypes->type = SMB_TYPE_BASEBOARD;
941 	smb_strcnt(shp, bbstypes);
942 	smb_bb_contains(shp, bbstypes);
943 
944 	for (nb = 0; nb < bbstypes->count; nb++) {
945 		if (bbstypes->ids[nb]->visited) {
946 			continue;
947 		}
948 
949 		bbstypes->ids[nb]->visited = 1;
950 		bb_smbid = bbstypes->ids[nb]->id;
951 
952 		/*
953 		 * check if there is a matching  processor under
954 		 * this board. If found, find base board(s) of this proc
955 		 * If proc is not in contained handle of a base board and
956 		 * there is only one base board in the system, treat that base
957 		 * board as the parent of the proc
958 		 */
959 		if (find_matching_proc(shp, strand_apicid,
960 		    bb_smbid, proc_hdl, is_proc) || (bbstypes->count == 1)) {
961 			fmri = fm_nvlist_create(NULL);
962 			if (fmri == NULL) {
963 				smb_free_strcnt(bbstypes, bb_strcnt);
964 				goto bad;
965 			}
966 			/*
967 			 * find parent by walking the cont_by_id
968 			 */
969 			rc = smb_get_bb_fmri(shp, fmri, bb_smbid, bbstypes);
970 			smb_free_strcnt(bbstypes, bb_strcnt);
971 			if (rc == 0) {
972 				return (fmri);
973 			} else
974 				goto bad;
975 		}
976 
977 	}
978 
979 	smb_free_strcnt(bbstypes, bb_strcnt);
980 bad:
981 	/* revert to legacy enumeration */
982 	x86gentopo_legacy = 1;
983 
984 	return (NULL);
985 }
986 
987 nvlist_t *
988 fm_smb_bboard(uint_t strand_apicid)
989 {
990 	return (smb_bboard(strand_apicid, 0, PROC));
991 }
992 
993 int
994 fm_smb_chipinst(uint_t strand_apicid, uint_t *chip_inst, uint16_t *smbiosid)
995 {
996 	int n;
997 	smbios_hdl_t *shp;
998 	uint16_t proc_id;
999 	smbs_cnt_t *pstypes;
1000 	int strcnt;
1001 
1002 	if (x86gentopo_legacy)
1003 		return (-1);
1004 
1005 	shp = ksmbios;
1006 	if (shp == NULL) {
1007 		goto bad;
1008 	}
1009 
1010 	strcnt = smb_cnttypes(shp, SMB_TYPE_PROCESSOR);
1011 	if (strcnt == 0)
1012 		goto bad;
1013 
1014 	pstypes = smb_create_strcnt(strcnt);
1015 	if (pstypes == NULL)
1016 		goto bad;
1017 
1018 	pstypes->type = SMB_TYPE_PROCESSOR;
1019 	smb_strcnt(shp, pstypes);
1020 	for (n = 0; n < pstypes->count; n++) {
1021 		proc_id = pstypes->ids[n]->id;
1022 		if (find_matching_apic(shp, proc_id, strand_apicid)) {
1023 			*chip_inst = pstypes->ids[n]->inst;
1024 			*smbiosid = pstypes->ids[n]->id;
1025 			smb_free_strcnt(pstypes, strcnt);
1026 			return (0);
1027 		}
1028 	}
1029 	smb_free_strcnt(pstypes, strcnt);
1030 bad:
1031 	/* revert to legacy enumerarion */
1032 	x86gentopo_legacy = 1;
1033 
1034 	return (-1);
1035 }
1036 
1037 nvlist_t *
1038 fm_smb_mc_bboards(uint_t bdf)
1039 {
1040 
1041 	int i;
1042 	smbios_hdl_t *shp;
1043 	uint16_t ext_id;
1044 	smbios_memarray_ext_t em;
1045 	nvlist_t *fmri = NULL;
1046 	smbs_cnt_t *mastypes;
1047 	int strcnt;
1048 
1049 	if (x86gentopo_legacy)
1050 		return (NULL);
1051 
1052 	shp = ksmbios;
1053 	if (shp == NULL) {
1054 		goto bad;
1055 	}
1056 
1057 	strcnt = smb_cnttypes(shp, SUN_OEM_EXT_MEMARRAY);
1058 	if (strcnt == 0)
1059 		goto bad;
1060 
1061 	mastypes = smb_create_strcnt(strcnt);
1062 	if (mastypes == NULL)
1063 		goto bad;
1064 
1065 	mastypes->type = SUN_OEM_EXT_MEMARRAY;
1066 	smb_strcnt(shp, mastypes);
1067 	for (i = 0; i < mastypes->count; i++) {
1068 		ext_id = mastypes->ids[i]->id;
1069 		(void) smbios_info_extmemarray(shp, ext_id, &em);
1070 		if (em.smbmae_bdf == bdf) {
1071 			fmri = smb_bboard(0, em.smbmae_comp, MC);
1072 			smb_free_strcnt(mastypes, strcnt);
1073 			return (fmri);
1074 		}
1075 	}
1076 	smb_free_strcnt(mastypes, strcnt);
1077 bad:
1078 	/* revert to legacy enumerarion */
1079 	x86gentopo_legacy = 1;
1080 
1081 	return (NULL);
1082 }
1083 
1084 int
1085 fm_smb_mc_chipinst(uint_t bdf, uint_t *chip_inst) {
1086 
1087 	int i, j;
1088 	smbios_hdl_t *shp;
1089 	smbios_memarray_ext_t em;
1090 	uint16_t ext_id, proc_id;
1091 	smbs_cnt_t *mastypes;
1092 	smbs_cnt_t *pstypes;
1093 	int ma_strcnt, p_strcnt;
1094 
1095 	if (x86gentopo_legacy)
1096 		return (-1);
1097 
1098 	shp = ksmbios;
1099 	if (shp == NULL) {
1100 		goto bad;
1101 	}
1102 
1103 	ma_strcnt = smb_cnttypes(shp, SUN_OEM_EXT_MEMARRAY);
1104 	if (ma_strcnt == 0)
1105 		goto bad;
1106 
1107 	mastypes = smb_create_strcnt(ma_strcnt);
1108 	if (mastypes == NULL)
1109 		goto bad;
1110 
1111 	mastypes->type = SUN_OEM_EXT_MEMARRAY;
1112 	smb_strcnt(shp, mastypes);
1113 	for (i = 0; i < mastypes->count; i++) {
1114 		ext_id = mastypes->ids[i]->id;
1115 		(void) smbios_info_extmemarray(shp, ext_id, &em);
1116 		    if (em.smbmae_bdf == bdf) {
1117 			p_strcnt = smb_cnttypes(shp, SMB_TYPE_PROCESSOR);
1118 			if (p_strcnt == 0) {
1119 				smb_free_strcnt(mastypes, ma_strcnt);
1120 				goto bad;
1121 			}
1122 
1123 			pstypes = smb_create_strcnt(p_strcnt);
1124 			if (pstypes == NULL) {
1125 				smb_free_strcnt(mastypes, ma_strcnt);
1126 				goto bad;
1127 			}
1128 
1129 			pstypes->type = SMB_TYPE_PROCESSOR;
1130 			smb_strcnt(shp, pstypes);
1131 			for (j = 0; j < pstypes->count; j++) {
1132 				proc_id = pstypes->ids[j]->id;
1133 				if (proc_id == em.smbmae_comp) {
1134 					*chip_inst = pstypes->ids[j]->inst;
1135 					smb_free_strcnt(mastypes, ma_strcnt);
1136 					smb_free_strcnt(pstypes, p_strcnt);
1137 					return (0);
1138 				}
1139 			}
1140 		}
1141 	}
1142 	smb_free_strcnt(mastypes, ma_strcnt);
1143 	smb_free_strcnt(pstypes, p_strcnt);
1144 bad:
1145 	/* revert to legacy enumeration */
1146 	x86gentopo_legacy = 1;
1147 
1148 	return (-1);
1149 }
1150