/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include /* * Variable used to determine if the x86 generic topology enumerator will * revert to legacy enumeration. I.E. Big Kill Switch... tunable via * /etc/system */ int x86gentopo_legacy = 0; #define MC 0 #define PROC 1 #define MAX_PAIRS 20 #define MAX_CONT 40 typedef struct bbindex { int count; uint16_t index[MAX_PAIRS]; } bbindex_t; /* * the enum values come from DMTF */ typedef enum baseb { BB_BAD = 0, /* There is no bb value 0 */ BB_UNKNOWN, /* Unknown */ BB_OTHER, /* Other */ BB_BLADE, /* Server Blade */ BB_CONNSW, /* Connectivity Switch */ BB_SMM, /* System Management Module */ BB_PROCMOD, /* Processor Module */ BB_IOMOD, /* I/O Module */ BB_MEMMOD, /* Memory Module */ BB_DBOARD, /* Daughter Board */ BB_MBOARD, /* Motherboard */ BB_PROCMMOD, /* Processor/Memory Module */ BB_PROCIOMOD, /* Processor/IO Module */ BB_ICONNBD /* Interconnect Board */ } bbd_t; static struct bboard_type { bbd_t baseb; const char *name; } bbd_type[] = { {BB_BAD, NULL}, {BB_UNKNOWN, "unknown"}, {BB_OTHER, "other"}, {BB_BLADE, "systemboard"}, {BB_CONNSW, "connswitch"}, {BB_SMM, "smmodule"}, {BB_PROCMOD, "cpuboard"}, {BB_IOMOD, "ioboard"}, {BB_MEMMOD, "memboard"}, {BB_DBOARD, "systemboard"}, {BB_MBOARD, "motherboard"}, {BB_PROCMMOD, "systemboard"}, {BB_PROCIOMOD, "systemboard"}, {BB_ICONNBD, "systemboard"} }; typedef struct smbs_con_ids { int id; int inst; int cont_count; uint16_t **cont_ids; int cont_by_id; int visited; } smbs_con_ids_t; typedef struct smbs_cnt { int type; /* SMBIOS stucture type */ int count; /* number of table entries */ smbs_con_ids_t **ids; /* SMBIOS table entry id(s) */ } smbs_cnt_t; /* * dynamically allocate the storage for the smbs_cnt_t */ static smbs_cnt_t * smb_create_strcnt(int count) { smbs_cnt_t *types = NULL; int i, j; types = kmem_zalloc(sizeof (smbs_cnt_t), KM_SLEEP); types->ids = (smbs_con_ids_t **)kmem_zalloc( count * sizeof (smbs_con_ids_t *), KM_SLEEP); for (i = 0; i < count; i++) { types->ids[i] = (smbs_con_ids_t *)kmem_zalloc( sizeof (smbs_con_ids_t), KM_SLEEP); } for (i = 0; i < count; i++) { types->ids[i]->cont_ids = (uint16_t **)kmem_zalloc( MAX_CONT * sizeof (uint16_t *), KM_SLEEP); } for (i = 0; i < count; i++) { for (j = 0; j < MAX_CONT; j++) { types->ids[i]->cont_ids[j] = (uint16_t *)kmem_zalloc( sizeof (uint16_t), KM_SLEEP); } } return (types); } /* * free the smbs_cnt_t memory */ static void smb_free_strcnt(smbs_cnt_t *types, int count) { int i, j; if (types == NULL) return; for (i = 0; i < count; i++) { for (j = 0; j < MAX_CONT; j++) { if (types->ids[i]->cont_ids[j] != NULL) kmem_free(types->ids[i]->cont_ids[j], sizeof (uint16_t)); } } for (i = 0; i < count; i++) { if (types->ids[i]->cont_ids != NULL) kmem_free(types->ids[i]->cont_ids, MAX_CONT * sizeof (uint16_t *)); } for (i = 0; i < count; i++) { if (types->ids[i] != NULL) kmem_free(types->ids[i], sizeof (smbs_con_ids_t)); } if (types->ids != NULL) kmem_free(types->ids, count * sizeof (smbs_con_ids_t *)); if (types != NULL) kmem_free(types, sizeof (smbs_cnt_t)); } /* * count number of the structure type in the ksmbios */ static int smb_cnttypes(smbios_hdl_t *shp, int type) { const smb_struct_t *sp = shp->sh_structs; int nstructs = shp->sh_nstructs; int i; int cnt = 0; for (i = 0, cnt = 0; i < nstructs; i++, sp++) { if (sp->smbst_hdr->smbh_type == type) cnt++; } return (cnt); } static void smb_strcnt(smbios_hdl_t *shp, smbs_cnt_t *stype) { const smb_struct_t *sp = shp->sh_structs; int nstructs = shp->sh_nstructs; smbios_bboard_t bb; int i, cnt; int mb_cnt = 0; int cpub_cnt = 0; int sysb_cnt = 0; int memb_cnt = 0; int iob_cnt = 0; int inst = 0; int rc = 0; for (i = 0, cnt = 0; i < nstructs; i++, sp++) { if (sp->smbst_hdr->smbh_type == stype->type) { stype->ids[cnt]->id = sp->smbst_hdr->smbh_hdl; stype->ids[cnt]->inst = cnt; stype->ids[cnt]->visited = 0; stype->ids[cnt]->cont_by_id = -1; if (stype->type == SMB_TYPE_BASEBOARD) { rc = smbios_info_bboard(shp, stype->ids[cnt]->id, &bb); if (rc == 0) { switch (bb.smbb_type) { case SMB_BBT_PROC : inst = cpub_cnt++; break; case SMB_BBT_IO : inst = iob_cnt++; break; case SMB_BBT_MEM : inst = memb_cnt++; break; case SMB_BBT_MOTHER : inst = mb_cnt++; break; default: /* * SMB_BBT_UNKNOWN * SMB_BBT_OTHER * SMB_BBT_SBLADE * SMB_BBT_CSWITCH * SMB_BBT_SMM * SMB_BBT_DAUGHTER * SMB_BBT_PROCMEM * SMB_BBT_PROCIO * SMB_BBT_INTER */ inst = sysb_cnt++; break; } stype->ids[cnt]->inst = inst; } } cnt++; } } stype->count = cnt; } /* * Go through the smbios structures looking for type 2. Fill in * the cont_id and cont_by_id for each type 2 * */ static void smb_bb_contains(smbios_hdl_t *shp, smbs_cnt_t *stype) { int i, j, cnt, c; uint_t cont_count; const smb_struct_t *spt; smbios_bboard_t smb_bb; uint16_t bb_id, cont_id; uint_t cont_len; id_t *cont_hdl = NULL; int rc; for (cnt = 0; cnt < stype->count; cnt++) { bb_id = stype->ids[cnt]->id; (void) smbios_info_bboard(shp, stype->ids[cnt]->id, &smb_bb); cont_count = (uint_t)smb_bb.smbb_contn; if (cont_count == 0) { continue; } cont_len = sizeof (id_t); cont_hdl = kmem_zalloc(cont_count * cont_len, KM_SLEEP); if (cont_hdl == NULL) continue; rc = smbios_info_contains(shp, stype->ids[cnt]->id, cont_count, cont_hdl); if (rc > SMB_CONT_MAX) { kmem_free(cont_hdl, cont_count * cont_len); continue; } cont_count = MIN(rc, cont_count); /* * fill in the type 2 and type 4 ids which are * contained in this type 2 */ c = 0; for (j = 0; j < cont_count; j++) { cont_id = (uint16_t)cont_hdl[j]; spt = smb_lookup_id(shp, cont_id); if (spt->smbst_hdr->smbh_type == SMB_TYPE_BASEBOARD || spt->smbst_hdr->smbh_type == SMB_TYPE_PROCESSOR) { *stype->ids[cnt]->cont_ids[c] = cont_id; c++; } if (spt->smbst_hdr->smbh_type == SMB_TYPE_BASEBOARD) { for (i = 0; i < stype->count; i++) { if (stype->ids[i]->id == cont_id) { stype->ids[i]->cont_by_id = bb_id; } } } } stype->ids[cnt]->cont_count = c; if (cont_hdl != NULL) kmem_free(cont_hdl, cont_count * cont_len); } } /* * Verify SMBIOS structures for x86 generic topology. * * Return (0) on success. */ static int fm_smb_check(smbios_hdl_t *shp) { int i, j; int bb_cnt = 0; int pr_cnt = 0; int expr_cnt = 0; int ma_cnt = 0; int exma_cnt = 0; int mdev_cnt = 0; int exmdev_cnt = 0; uint16_t bb_id; uint16_t pr_id, expr_id; uint16_t ma_id, exma_id; uint16_t mdev_id, exmdev_id; uint16_t *sys_ma; smbios_bboard_t bb; smbios_processor_ext_t exproc; smbios_memarray_t ma; smbios_memarray_ext_t exma; smbios_memdevice_t mdev; smbios_memdevice_ext_t exmdev; smbs_cnt_t *bb_stype; smbs_cnt_t *pr_stype, *expr_stype; smbs_cnt_t *ma_stype, *exma_stype; smbs_cnt_t *mdev_stype, *exmdev_stype; /* * Verify the existance of the requuired extended OEM-Specific * structures and they coincide with the structures they extend * (e.g. the number of extended processor structures equal the * number of processor structures). */ pr_cnt = smb_cnttypes(shp, SMB_TYPE_PROCESSOR); expr_cnt = smb_cnttypes(shp, SUN_OEM_EXT_PROCESSOR); ma_cnt = smb_cnttypes(shp, SMB_TYPE_MEMARRAY); exma_cnt = smb_cnttypes(shp, SUN_OEM_EXT_MEMARRAY); mdev_cnt = smb_cnttypes(shp, SMB_TYPE_MEMDEVICE); exmdev_cnt = smb_cnttypes(shp, SUN_OEM_EXT_MEMDEVICE); if (expr_cnt == 0 || exma_cnt == 0 || exmdev_cnt == 0 || expr_cnt != pr_cnt || exma_cnt > ma_cnt || exmdev_cnt > mdev_cnt) { #ifdef DEBUG cmn_err(CE_NOTE, "!Structure mismatch: ext_proc (%d) " "proc (%d) ext_ma (%d) ma (%d) ext_mdev (%d) mdev (%d)\n", expr_cnt, pr_cnt, exma_cnt, ma_cnt, exmdev_cnt, mdev_cnt); #endif /* DEBUG */ return (-1); } /* * Verify the OEM-Specific structrures are correctly * linked to the SMBIOS structure types they extend. */ /* allocate processor stypes */ pr_stype = smb_create_strcnt(pr_cnt); expr_stype = smb_create_strcnt(expr_cnt); /* fill in stypes */ pr_stype->type = SMB_TYPE_PROCESSOR; smb_strcnt(shp, pr_stype); expr_stype->type = SUN_OEM_EXT_PROCESSOR; smb_strcnt(shp, expr_stype); /* verify the ext proc struct belong to the proc struct */ for (i = 0; i < pr_cnt; i++) { pr_id = pr_stype->ids[i]->id; expr_id = expr_stype->ids[i]->id; (void) smbios_info_extprocessor(shp, expr_id, &exproc); if (exproc.smbpe_processor != pr_id) { #ifdef DEBUG cmn_err(CE_NOTE, "!Processor struct linkage (%d)", i); #endif /* DEBUG */ smb_free_strcnt(pr_stype, pr_cnt); smb_free_strcnt(expr_stype, expr_cnt); return (-1); } } /* free stypes */ smb_free_strcnt(pr_stype, pr_cnt); smb_free_strcnt(expr_stype, expr_cnt); /* allocate memory array stypes */ ma_stype = smb_create_strcnt(ma_cnt); exma_stype = smb_create_strcnt(exma_cnt); sys_ma = kmem_zalloc(sizeof (uint16_t) * ma_cnt, KM_SLEEP); /* fill in stypes */ ma_stype->type = SMB_TYPE_MEMARRAY; smb_strcnt(shp, ma_stype); exma_stype->type = SUN_OEM_EXT_MEMARRAY; smb_strcnt(shp, exma_stype); /* verify linkage from ext memarray struct to memarray struct */ for (i = 0; i < ma_cnt; i++) { sys_ma[i] = (uint16_t)-1; ma_id = ma_stype->ids[i]->id; (void) smbios_info_memarray(shp, ma_id, &ma); if (ma.smbma_use != SMB_MAU_SYSTEM) continue; /* this memarray is system memory */ sys_ma[i] = ma_id; exma_id = exma_stype->ids[i]->id; (void) smbios_info_extmemarray(shp, exma_id, &exma); if (exma.smbmae_ma != ma_id) { #ifdef DEBUG cmn_err(CE_NOTE, "!Memory Array struct linkage (%d)", i); #endif /* DEBUG */ smb_free_strcnt(ma_stype, ma_cnt); smb_free_strcnt(exma_stype, exma_cnt); kmem_free(sys_ma, sizeof (uint16_t) * ma_cnt); return (-1); } } /* free stypes */ smb_free_strcnt(ma_stype, ma_cnt); smb_free_strcnt(exma_stype, exma_cnt); /* allocate memory device stypes */ mdev_stype = smb_create_strcnt(mdev_cnt); exmdev_stype = smb_create_strcnt(exmdev_cnt); /* fill in stypes */ mdev_stype->type = SMB_TYPE_MEMDEVICE; smb_strcnt(shp, mdev_stype); exmdev_stype->type = SUN_OEM_EXT_MEMDEVICE; smb_strcnt(shp, exmdev_stype); /* verify linkage */ for (i = 0; i < mdev_cnt; i++) { mdev_id = mdev_stype->ids[i]->id; (void) smbios_info_memdevice(shp, mdev_id, &mdev); /* only check system memory devices */ for (j = 0; j < ma_cnt; j++) { if (sys_ma[j] == mdev.smbmd_array) break; } if (j == ma_cnt) continue; exmdev_id = exmdev_stype->ids[i]->id; (void) smbios_info_extmemdevice(shp, exmdev_id, &exmdev); if (exmdev.smbmdeve_md != mdev_id) { #ifdef DEBUG cmn_err(CE_NOTE, "!Memory Device struct linkage (%d)", i); #endif /* DEBUG */ smb_free_strcnt(mdev_stype, mdev_cnt); smb_free_strcnt(exmdev_stype, exmdev_cnt); kmem_free(sys_ma, sizeof (uint16_t) * ma_cnt); return (-1); } } /* free stypes */ smb_free_strcnt(mdev_stype, mdev_cnt); smb_free_strcnt(exmdev_stype, exmdev_cnt); kmem_free(sys_ma, sizeof (uint16_t) * ma_cnt); /* * Verify the presece of contained handles if there are more * than one Type-2 (Base Board) structures. */ bb_cnt = smb_cnttypes(shp, SMB_TYPE_BASEBOARD); if (bb_cnt > 1) { /* allocate base board stypes */ bb_stype = smb_create_strcnt(bb_cnt); /* fill in stypes */ bb_stype->type = SMB_TYPE_BASEBOARD; smb_strcnt(shp, bb_stype); /* verify contained handles */ for (i = 0; i < bb_cnt; i++) { bb_id = bb_stype->ids[i]->id; (void) smbios_info_bboard(shp, bb_id, &bb); if (bb.smbb_contn == 0) { #ifdef DEBUG cmn_err(CE_NOTE, "!No contained hanldes (%d)", i); #endif /* DEBUG */ smb_free_strcnt(bb_stype, bb_cnt); return (-1); } } /* free stypes */ smb_free_strcnt(bb_stype, bb_cnt); } return (0); } void fm_smb_fmacompat() { int i, j; int id; int cnt; const char **oem_strings = NULL; smbs_cnt_t *oemstypes; smbios_hdl_t *shp; int strcnt; int compat = 0; /* check for BKS */ if (x86gentopo_legacy == 1) { return; } shp = ksmbios; if (shp == NULL) { goto bad; } /* OEM strings (Type 11) */ strcnt = smb_cnttypes(shp, SMB_TYPE_OEMSTR); if (strcnt == 0) goto bad; oemstypes = smb_create_strcnt(strcnt); if (oemstypes == NULL) goto bad; oemstypes->type = SMB_TYPE_OEMSTR; smb_strcnt(shp, oemstypes); for (i = 0; i < oemstypes->count && compat == 0; i++) { id = oemstypes->ids[i]->id; cnt = smbios_info_strtab(shp, id, 0, NULL); if (cnt > 0) { oem_strings = kmem_zalloc(sizeof (char *) * cnt, KM_SLEEP); (void) smbios_info_strtab(shp, id, cnt, oem_strings); for (j = 0; j < cnt; j++) { if (strncmp(oem_strings[j], SMB_PRMS1, strlen(SMB_PRMS1) + 1) == 0) { compat = 1; break; } } kmem_free(oem_strings, sizeof (char *) * cnt); } } smb_free_strcnt(oemstypes, strcnt); /* sanity check SMBIOS structures */ if ((compat != 0) && (fm_smb_check(shp) == 0)) return; bad: /* not compatible with x86gentopo; revert to legacy enumeration */ #ifdef DEBUG cmn_err(CE_NOTE, "!SMBIOS is not compatible with x86 generic topology."); cmn_err(CE_NOTE, "!Invoking legacy x86 topology enumeration."); #endif /* DEBUG */ x86gentopo_legacy = 1; } static int find_matching_apic(smbios_hdl_t *shp, uint16_t proc_id, uint_t strand_apicid) { uint16_t ext_id; int i, j; smbios_processor_ext_t ep; smbs_cnt_t *pstypes; int strcnt; strcnt = smb_cnttypes(shp, SUN_OEM_EXT_PROCESSOR); if (strcnt == 0) return (0); pstypes = smb_create_strcnt(strcnt); if (pstypes == NULL) return (0); pstypes->type = SUN_OEM_EXT_PROCESSOR; smb_strcnt(shp, pstypes); for (i = 0; i < pstypes->count; i++) { ext_id = pstypes->ids[i]->id; (void) smbios_info_extprocessor(shp, ext_id, &ep); if (ep.smbpe_processor == proc_id) { for (j = 0; j < ep.smbpe_n; j++) { if (ep.smbpe_apicid[j] == strand_apicid) { smb_free_strcnt(pstypes, strcnt); return (1); } } } } smb_free_strcnt(pstypes, strcnt); return (0); } /* * go throught the type 2 structure contained_ids looking for * the type 4 which has strand_apicid == this strand_apicid */ static int find_matching_proc(smbios_hdl_t *shp, uint_t strand_apicid, uint16_t bb_id, uint16_t proc_hdl, int is_proc) { int n; const smb_struct_t *sp; smbios_bboard_t bb; uint_t cont_count, cont_len; uint16_t cont_id; id_t *cont_hdl = NULL; int rc; (void) smbios_info_bboard(shp, bb_id, &bb); cont_count = (uint_t)bb.smbb_contn; if (cont_count == 0) return (0); cont_len = sizeof (id_t); cont_hdl = kmem_zalloc(cont_count * cont_len, KM_SLEEP); if (cont_hdl == NULL) return (0); rc = smbios_info_contains(shp, bb_id, cont_count, cont_hdl); if (rc > SMB_CONT_MAX) { kmem_free(cont_hdl, cont_count * cont_len); return (0); } cont_count = MIN(rc, cont_count); for (n = 0; n < cont_count; n++) { cont_id = (uint16_t)cont_hdl[n]; sp = smb_lookup_id(shp, cont_id); if (sp->smbst_hdr->smbh_type == SMB_TYPE_PROCESSOR) { if (is_proc) { if (find_matching_apic(shp, cont_id, strand_apicid)) { kmem_free(cont_hdl, cont_count * cont_len); return (1); } } else { if (cont_id == proc_hdl) { kmem_free(cont_hdl, cont_count * cont_len); return (1); } } } } if (cont_hdl != NULL) kmem_free(cont_hdl, cont_count * cont_len); return (0); } void get_bboard_index(smbs_cnt_t *bbstypes, uint_t bb_id, bbindex_t *bb_idx) { int curr_id, tmp_id; int i, j, nb; bbindex_t tmp_idx; for (i = 0; i < MAX_PAIRS; i++) tmp_idx.index[i] = 0; tmp_idx.count = 0; curr_id = bb_id; for (nb = bbstypes->count-1, i = 0; nb >= 0; nb--) { tmp_id = bbstypes->ids[nb]->id; if (tmp_id == curr_id) { tmp_idx.index[i] = nb; tmp_idx.count++; curr_id = bbstypes->ids[nb]->cont_by_id; if (curr_id == -1) break; i++; } } for (i = tmp_idx.count - 1, j = 0; i >= 0; i--) { bb_idx->index[j] = tmp_idx.index[i]; j++; } bb_idx->count = tmp_idx.count; } int get_chassis_inst(smbios_hdl_t *shp, uint16_t *chassis_inst, uint16_t bb_id, int *chcnt) { int ch_strcnt; smbs_cnt_t *chstypes; uint16_t chassis_id, tmp_id; smbios_bboard_t bb; int rc = 0; int i; rc = smbios_info_bboard(shp, bb_id, &bb); if (rc != 0) { return (-1); } chassis_id = bb.smbb_chassis; ch_strcnt = smb_cnttypes(shp, SMB_TYPE_CHASSIS); if (ch_strcnt == 0) return (-1); chstypes = smb_create_strcnt(ch_strcnt); if (chstypes == NULL) return (-1); chstypes->type = SMB_TYPE_CHASSIS; smb_strcnt(shp, chstypes); for (i = 0; i < chstypes->count; i++) { tmp_id = chstypes->ids[i]->id; if (tmp_id == chassis_id) { *chassis_inst = chstypes->ids[i]->inst; if (chstypes->ids[i]->inst != 0) *chcnt = 2; else *chcnt = 1; smb_free_strcnt(chstypes, ch_strcnt); return (0); } } smb_free_strcnt(chstypes, ch_strcnt); return (-1); } int smb_get_bb_fmri(smbios_hdl_t *shp, nvlist_t *fmri, uint_t parent, smbs_cnt_t *bbstypes) { int rc = 0; int i, j, n, cnt; int id, index; nvlist_t *pairs[MAX_PAIRS]; smbios_bboard_t bb; uint16_t chassis_inst, mch_inst; char name[40]; char idstr[11]; bbindex_t bb_idx; uint16_t bbid; int chcnt = 0; for (n = 0; n < MAX_PAIRS; n++) { bb_idx.index[n] = 0; pairs[n] = NULL; } bb_idx.count = 0; get_bboard_index(bbstypes, parent, &bb_idx); index = bb_idx.index[0]; bbid = bbstypes->ids[index]->id; rc = get_chassis_inst(shp, &chassis_inst, bbid, &chcnt); if (rc != 0) { return (rc); } if ((bb_idx.count + chcnt) > MAX_PAIRS) { return (-1); } i = 0; if (chcnt > 1) { /* * create main chassis pair */ pairs[i] = fm_nvlist_create(NULL); if (pairs[i] == NULL) { return (-1); } mch_inst = 0; (void) snprintf(idstr, sizeof (idstr), "%u", mch_inst); if ((nvlist_add_string(pairs[i], FM_FMRI_HC_NAME, "chassis") != 0) || (nvlist_add_string(pairs[i], FM_FMRI_HC_ID, idstr)) != 0) { fm_nvlist_destroy(pairs[i], FM_NVA_FREE); return (-1); } i++; } /* * create chassis pair */ pairs[i] = fm_nvlist_create(NULL); if (pairs[i] == NULL) { for (n = 0; n < MAX_PAIRS; n++) { if (pairs[n] != NULL) fm_nvlist_destroy(pairs[n], FM_NVA_FREE); } return (-1); } (void) snprintf(idstr, sizeof (idstr), "%u", chassis_inst); if ((nvlist_add_string(pairs[i], FM_FMRI_HC_NAME, "chassis") != 0) || (nvlist_add_string(pairs[i], FM_FMRI_HC_ID, idstr) != 0)) { for (n = 0; n < MAX_PAIRS; n++) { if (pairs[n] != NULL) fm_nvlist_destroy(pairs[n], FM_NVA_FREE); } return (-1); } for (j = 0, i = chcnt, cnt = chcnt; j < bb_idx.count; j++) { index = bb_idx.index[j]; bbid = bbstypes->ids[index]->id; rc = smbios_info_bboard(shp, bbid, &bb); if (rc != 0) { rc = -1; break; } pairs[i] = fm_nvlist_create(NULL); if (pairs[i] == NULL) { rc = -1; break; } id = bbstypes->ids[index]->inst; (void) snprintf(idstr, sizeof (idstr), "%u", id); (void) strncpy(name, bbd_type[bb.smbb_type].name, sizeof (name)); cnt++; if (nvlist_add_string(pairs[i], FM_FMRI_HC_NAME, name) != 0 || nvlist_add_string(pairs[i], FM_FMRI_HC_ID, idstr) != 0) { rc = -1; break; } i++; } if (rc != -1) { if (nvlist_add_nvlist_array(fmri, FM_FMRI_HC_LIST, pairs, cnt) != 0) { rc = -1; } } for (n = 0; n < cnt; n++) { if (pairs[n] != NULL) fm_nvlist_destroy(pairs[n], FM_NVA_FREE); } return (rc); } /* * pass in strand_apic id * return chip's bboards list which has strand_apicid == passed * in strand_apic id */ static nvlist_t * smb_bboard(uint_t strand_apicid, uint16_t proc_hdl, int is_proc) { smbios_hdl_t *shp; smbs_cnt_t *bbstypes; int nb; int bb_smbid; nvlist_t *fmri = NULL; int rc = 0; int bb_strcnt; if (x86gentopo_legacy) return (NULL); shp = ksmbios; if (shp == NULL) { goto bad; } /* * Type 2 structs : "base board" */ bb_strcnt = smb_cnttypes(shp, SMB_TYPE_BASEBOARD); if (bb_strcnt == 0) { goto bad; } bbstypes = smb_create_strcnt(bb_strcnt); if (bbstypes == NULL) { goto bad; } bbstypes->type = SMB_TYPE_BASEBOARD; smb_strcnt(shp, bbstypes); smb_bb_contains(shp, bbstypes); for (nb = 0; nb < bbstypes->count; nb++) { if (bbstypes->ids[nb]->visited) { continue; } bbstypes->ids[nb]->visited = 1; bb_smbid = bbstypes->ids[nb]->id; /* * check if there is a matching processor under * this board. If found, find base board(s) of this proc * If proc is not in contained handle of a base board and * there is only one base board in the system, treat that base * board as the parent of the proc */ if (find_matching_proc(shp, strand_apicid, bb_smbid, proc_hdl, is_proc) || (bbstypes->count == 1)) { fmri = fm_nvlist_create(NULL); if (fmri == NULL) { smb_free_strcnt(bbstypes, bb_strcnt); goto bad; } /* * find parent by walking the cont_by_id */ rc = smb_get_bb_fmri(shp, fmri, bb_smbid, bbstypes); smb_free_strcnt(bbstypes, bb_strcnt); if (rc == 0) { return (fmri); } else goto bad; } } smb_free_strcnt(bbstypes, bb_strcnt); bad: /* revert to legacy enumeration */ x86gentopo_legacy = 1; return (NULL); } nvlist_t * fm_smb_bboard(uint_t strand_apicid) { return (smb_bboard(strand_apicid, 0, PROC)); } int fm_smb_chipinst(uint_t strand_apicid, uint_t *chip_inst, uint16_t *smbiosid) { int n; smbios_hdl_t *shp; uint16_t proc_id; smbs_cnt_t *pstypes; int strcnt; if (x86gentopo_legacy) return (-1); shp = ksmbios; if (shp == NULL) { goto bad; } strcnt = smb_cnttypes(shp, SMB_TYPE_PROCESSOR); if (strcnt == 0) goto bad; pstypes = smb_create_strcnt(strcnt); if (pstypes == NULL) goto bad; pstypes->type = SMB_TYPE_PROCESSOR; smb_strcnt(shp, pstypes); for (n = 0; n < pstypes->count; n++) { proc_id = pstypes->ids[n]->id; if (find_matching_apic(shp, proc_id, strand_apicid)) { *chip_inst = pstypes->ids[n]->inst; *smbiosid = pstypes->ids[n]->id; smb_free_strcnt(pstypes, strcnt); return (0); } } smb_free_strcnt(pstypes, strcnt); bad: /* revert to legacy enumerarion */ x86gentopo_legacy = 1; return (-1); } nvlist_t * fm_smb_mc_bboards(uint_t bdf) { int i; smbios_hdl_t *shp; uint16_t ext_id; smbios_memarray_ext_t em; nvlist_t *fmri = NULL; smbs_cnt_t *mastypes; int strcnt; if (x86gentopo_legacy) return (NULL); shp = ksmbios; if (shp == NULL) { goto bad; } strcnt = smb_cnttypes(shp, SUN_OEM_EXT_MEMARRAY); if (strcnt == 0) goto bad; mastypes = smb_create_strcnt(strcnt); if (mastypes == NULL) goto bad; mastypes->type = SUN_OEM_EXT_MEMARRAY; smb_strcnt(shp, mastypes); for (i = 0; i < mastypes->count; i++) { ext_id = mastypes->ids[i]->id; (void) smbios_info_extmemarray(shp, ext_id, &em); if (em.smbmae_bdf == bdf) { fmri = smb_bboard(0, em.smbmae_comp, MC); smb_free_strcnt(mastypes, strcnt); return (fmri); } } smb_free_strcnt(mastypes, strcnt); bad: /* revert to legacy enumerarion */ x86gentopo_legacy = 1; return (NULL); } int fm_smb_mc_chipinst(uint_t bdf, uint_t *chip_inst) { int i, j; smbios_hdl_t *shp; smbios_memarray_ext_t em; uint16_t ext_id, proc_id; smbs_cnt_t *mastypes; smbs_cnt_t *pstypes; int ma_strcnt, p_strcnt; if (x86gentopo_legacy) return (-1); shp = ksmbios; if (shp == NULL) { goto bad; } ma_strcnt = smb_cnttypes(shp, SUN_OEM_EXT_MEMARRAY); if (ma_strcnt == 0) goto bad; mastypes = smb_create_strcnt(ma_strcnt); if (mastypes == NULL) goto bad; mastypes->type = SUN_OEM_EXT_MEMARRAY; smb_strcnt(shp, mastypes); pstypes = NULL; p_strcnt = 0; for (i = 0; i < mastypes->count; i++) { ext_id = mastypes->ids[i]->id; (void) smbios_info_extmemarray(shp, ext_id, &em); if (em.smbmae_bdf == bdf) { p_strcnt = smb_cnttypes(shp, SMB_TYPE_PROCESSOR); if (p_strcnt == 0) { smb_free_strcnt(mastypes, ma_strcnt); goto bad; } pstypes = smb_create_strcnt(p_strcnt); if (pstypes == NULL) { smb_free_strcnt(mastypes, ma_strcnt); goto bad; } pstypes->type = SMB_TYPE_PROCESSOR; smb_strcnt(shp, pstypes); for (j = 0; j < pstypes->count; j++) { proc_id = pstypes->ids[j]->id; if (proc_id == em.smbmae_comp) { *chip_inst = pstypes->ids[j]->inst; smb_free_strcnt(mastypes, ma_strcnt); smb_free_strcnt(pstypes, p_strcnt); return (0); } } } } smb_free_strcnt(mastypes, ma_strcnt); smb_free_strcnt(pstypes, p_strcnt); bad: /* revert to legacy enumeration */ x86gentopo_legacy = 1; return (-1); }