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 && compat == 0; 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                                         compat = 1;
 574                                         break;
 575                                 }
 576                         }
 577                         kmem_free(oem_strings, sizeof (char *) * cnt);
 578                 }
 579         }
 580         smb_free_strcnt(oemstypes, strcnt);
 581 
 582         /* sanity check SMBIOS structures */
 583         if ((compat != 0) && (fm_smb_check(shp) == 0))
 584                 return;
 585 
 586 bad:
 587         /* not compatible with x86gentopo; revert to legacy enumeration */
 588 #ifdef  DEBUG
 589         cmn_err(CE_NOTE,
 590             "!SMBIOS is not compatible with x86 generic topology.");
 591         cmn_err(CE_NOTE, "!Invoking legacy x86 topology enumeration.");
 592 #endif  /* DEBUG */
 593         x86gentopo_legacy = 1;
 594 }
 595 
 596 static int
 597 find_matching_apic(smbios_hdl_t *shp, uint16_t proc_id, uint_t strand_apicid)
 598 {
 599         uint16_t ext_id;
 600         int i, j;
 601         smbios_processor_ext_t ep;
 602         smbs_cnt_t *pstypes;
 603         int strcnt;
 604 
 605         strcnt = smb_cnttypes(shp, SUN_OEM_EXT_PROCESSOR);
 606         if (strcnt == 0)
 607                 return (0);
 608 
 609         pstypes = smb_create_strcnt(strcnt);
 610         if (pstypes == NULL)
 611                 return (0);
 612 
 613         pstypes->type = SUN_OEM_EXT_PROCESSOR;
 614         smb_strcnt(shp, pstypes);
 615         for (i = 0; i < pstypes->count; i++) {
 616                 ext_id = pstypes->ids[i]->id;
 617                 (void) smbios_info_extprocessor(shp, ext_id, &ep);
 618                 if (ep.smbpe_processor == proc_id) {
 619                         for (j = 0; j < ep.smbpe_n; j++) {
 620                                 if (ep.smbpe_apicid[j] == strand_apicid) {
 621                                         smb_free_strcnt(pstypes, strcnt);
 622                                         return (1);
 623                                 }
 624                         }
 625                 }
 626         }
 627         smb_free_strcnt(pstypes, strcnt);
 628         return (0);
 629 }
 630 
 631 /*
 632  * go throught the type 2 structure contained_ids looking for
 633  * the type 4 which  has strand_apicid == this strand_apicid
 634  */
 635 static int
 636 find_matching_proc(smbios_hdl_t *shp, uint_t strand_apicid,
 637     uint16_t bb_id, uint16_t proc_hdl, int is_proc)
 638 {
 639         int n;
 640         const smb_struct_t *sp;
 641         smbios_bboard_t bb;
 642         uint_t cont_count, cont_len;
 643         uint16_t cont_id;
 644         id_t *cont_hdl = NULL;
 645         int rc;
 646 
 647 
 648         (void) smbios_info_bboard(shp, bb_id, &bb);
 649         cont_count = (uint_t)bb.smbb_contn;
 650         if (cont_count == 0)
 651                 return (0);
 652 
 653         cont_len = sizeof (id_t);
 654         cont_hdl = kmem_zalloc(cont_count * cont_len, KM_SLEEP);
 655         if (cont_hdl == NULL)
 656                 return (0);
 657 
 658         rc = smbios_info_contains(shp, bb_id, cont_count, cont_hdl);
 659         if (rc > SMB_CONT_MAX) {
 660                 kmem_free(cont_hdl, cont_count * cont_len);
 661                 return (0);
 662         }
 663         cont_count = MIN(rc, cont_count);
 664 
 665         for (n = 0; n < cont_count; n++) {
 666                 cont_id = (uint16_t)cont_hdl[n];
 667                 sp = smb_lookup_id(shp, cont_id);
 668                 if (sp->smbst_hdr->smbh_type == SMB_TYPE_PROCESSOR) {
 669                         if (is_proc) {
 670                                 if (find_matching_apic(shp, cont_id,
 671                                     strand_apicid)) {
 672                                         kmem_free(cont_hdl,
 673                                             cont_count * cont_len);
 674                                         return (1);
 675                                 }
 676                         } else {
 677                                 if (cont_id == proc_hdl) {
 678                                         kmem_free(cont_hdl,
 679                                             cont_count * cont_len);
 680                                         return (1);
 681                                 }
 682                         }
 683                 }
 684         }
 685         if (cont_hdl != NULL)
 686                 kmem_free(cont_hdl, cont_count * cont_len);
 687 
 688         return (0);
 689 }
 690 
 691 void
 692 get_bboard_index(smbs_cnt_t *bbstypes, uint_t bb_id, bbindex_t *bb_idx)
 693 {
 694         int curr_id, tmp_id;
 695         int i, j, nb;
 696         bbindex_t tmp_idx;
 697 
 698         for (i = 0; i < MAX_PAIRS; i++)
 699                 tmp_idx.index[i] = 0;
 700 
 701         tmp_idx.count = 0;
 702 
 703         curr_id = bb_id;
 704         for (nb = bbstypes->count-1, i = 0; nb >= 0; nb--) {
 705                 tmp_id = bbstypes->ids[nb]->id;
 706                 if (tmp_id == curr_id) {
 707                         tmp_idx.index[i] = nb;
 708                         tmp_idx.count++;
 709                         curr_id = bbstypes->ids[nb]->cont_by_id;
 710                         if (curr_id == -1)
 711                                 break;
 712                         i++;
 713                 }
 714         }
 715 
 716         for (i = tmp_idx.count - 1, j = 0; i >= 0; i--) {
 717                 bb_idx->index[j] = tmp_idx.index[i];
 718                 j++;
 719         }
 720 
 721         bb_idx->count = tmp_idx.count;
 722 }
 723 
 724 int
 725 get_chassis_inst(smbios_hdl_t *shp, uint16_t *chassis_inst,
 726     uint16_t bb_id, int *chcnt)
 727 {
 728         int ch_strcnt;
 729         smbs_cnt_t *chstypes;
 730         uint16_t chassis_id, tmp_id;
 731         smbios_bboard_t bb;
 732         int rc = 0;
 733         int i;
 734 
 735         rc = smbios_info_bboard(shp, bb_id, &bb);
 736         if (rc != 0) {
 737                 return (-1);
 738         }
 739 
 740         chassis_id = bb.smbb_chassis;
 741 
 742         ch_strcnt = smb_cnttypes(shp, SMB_TYPE_CHASSIS);
 743 
 744         if (ch_strcnt == 0)
 745                 return (-1);
 746 
 747         chstypes = smb_create_strcnt(ch_strcnt);
 748         if (chstypes == NULL)
 749                 return (-1);
 750 
 751         chstypes->type = SMB_TYPE_CHASSIS;
 752         smb_strcnt(shp, chstypes);
 753 
 754         for (i = 0; i < chstypes->count; i++) {
 755                 tmp_id = chstypes->ids[i]->id;
 756                 if (tmp_id == chassis_id) {
 757                         *chassis_inst = chstypes->ids[i]->inst;
 758                         if (chstypes->ids[i]->inst != 0)
 759                                 *chcnt = 2;
 760                         else
 761                                 *chcnt = 1;
 762                         smb_free_strcnt(chstypes, ch_strcnt);
 763                         return (0);
 764                 }
 765         }
 766 
 767         smb_free_strcnt(chstypes, ch_strcnt);
 768         return (-1);
 769 }
 770 
 771 int
 772 smb_get_bb_fmri(smbios_hdl_t *shp, nvlist_t *fmri,  uint_t parent,
 773     smbs_cnt_t *bbstypes)
 774 {
 775         int rc = 0;
 776         int i, j, n, cnt;
 777         int id, index;
 778         nvlist_t *pairs[MAX_PAIRS];
 779         smbios_bboard_t bb;
 780         uint16_t chassis_inst, mch_inst;
 781         char name[40];
 782         char idstr[11];
 783         bbindex_t bb_idx;
 784         uint16_t bbid;
 785         int chcnt = 0;
 786 
 787         for (n = 0; n < MAX_PAIRS; n++) {
 788                 bb_idx.index[n] = 0;
 789                 pairs[n] = NULL;
 790         }
 791         bb_idx.count = 0;
 792 
 793         get_bboard_index(bbstypes, parent, &bb_idx);
 794 
 795         index = bb_idx.index[0];
 796         bbid = bbstypes->ids[index]->id;
 797 
 798         rc = get_chassis_inst(shp, &chassis_inst, bbid, &chcnt);
 799 
 800         if (rc != 0) {
 801                 return (rc);
 802         }
 803 
 804         if ((bb_idx.count + chcnt) > MAX_PAIRS) {
 805                 return (-1);
 806         }
 807 
 808         i = 0;
 809         if (chcnt > 1) {
 810                 /*
 811                  * create main chassis pair
 812                  */
 813                 pairs[i] = fm_nvlist_create(NULL);
 814                 if (pairs[i] == NULL) {
 815                         return (-1);
 816                 }
 817                 mch_inst = 0;
 818                 (void) snprintf(idstr, sizeof (idstr), "%u", mch_inst);
 819                 if ((nvlist_add_string(pairs[i], FM_FMRI_HC_NAME,
 820                     "chassis") != 0) ||
 821                     (nvlist_add_string(pairs[i], FM_FMRI_HC_ID, idstr)) != 0) {
 822                         fm_nvlist_destroy(pairs[i], FM_NVA_FREE);
 823                         return (-1);
 824                 }
 825                 i++;
 826         }
 827 
 828         /*
 829          * create chassis pair
 830          */
 831         pairs[i] = fm_nvlist_create(NULL);
 832         if (pairs[i] == NULL) {
 833                 for (n = 0; n < MAX_PAIRS; n++) {
 834                         if (pairs[n] != NULL)
 835                                 fm_nvlist_destroy(pairs[n], FM_NVA_FREE);
 836                 }
 837                 return (-1);
 838         }
 839         (void) snprintf(idstr, sizeof (idstr), "%u", chassis_inst);
 840         if ((nvlist_add_string(pairs[i], FM_FMRI_HC_NAME, "chassis") != 0) ||
 841             (nvlist_add_string(pairs[i], FM_FMRI_HC_ID, idstr) != 0)) {
 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 
 849         for (j = 0, i = chcnt, cnt = chcnt; j < bb_idx.count; j++) {
 850                 index = bb_idx.index[j];
 851                 bbid = bbstypes->ids[index]->id;
 852                 rc =  smbios_info_bboard(shp, bbid, &bb);
 853                 if (rc != 0) {
 854                         rc = -1;
 855                         break;
 856                 }
 857 
 858                 pairs[i] = fm_nvlist_create(NULL);
 859                 if (pairs[i] == NULL) {
 860                         rc = -1;
 861                         break;
 862                 }
 863 
 864                 id = bbstypes->ids[index]->inst;
 865                 (void) snprintf(idstr, sizeof (idstr), "%u", id);
 866                 (void) strncpy(name, bbd_type[bb.smbb_type].name,
 867                     sizeof (name));
 868                 cnt++;
 869 
 870                 if (nvlist_add_string(pairs[i], FM_FMRI_HC_NAME, name) != 0 ||
 871                     nvlist_add_string(pairs[i], FM_FMRI_HC_ID, idstr)
 872                     != 0) {
 873                         rc = -1;
 874                         break;
 875                 }
 876                 i++;
 877         }
 878 
 879         if (rc != -1) {
 880                 if (nvlist_add_nvlist_array(fmri, FM_FMRI_HC_LIST,
 881                     pairs, cnt) != 0) {
 882                         rc = -1;
 883                 }
 884         }
 885 
 886         for (n = 0; n < cnt; n++) {
 887                 if (pairs[n] != NULL)
 888                         fm_nvlist_destroy(pairs[n], FM_NVA_FREE);
 889         }
 890 
 891         return (rc);
 892 }
 893 
 894 /*
 895  * pass in strand_apic id
 896  * return chip's bboards list which has strand_apicid == passed
 897  * in strand_apic id
 898  */
 899 static nvlist_t *
 900 smb_bboard(uint_t strand_apicid, uint16_t proc_hdl, int is_proc)
 901 {
 902         smbios_hdl_t *shp;
 903         smbs_cnt_t *bbstypes;
 904         int nb;
 905         int bb_smbid;
 906         nvlist_t *fmri = NULL;
 907         int rc = 0;
 908         int bb_strcnt;
 909 
 910         if (x86gentopo_legacy)
 911                 return (NULL);
 912 
 913         shp = ksmbios;
 914         if (shp == NULL) {
 915                 goto bad;
 916         }
 917 
 918         /*
 919          * Type 2 structs : "base board"
 920          */
 921         bb_strcnt = smb_cnttypes(shp, SMB_TYPE_BASEBOARD);
 922         if (bb_strcnt == 0) {
 923                 goto bad;
 924         }
 925 
 926         bbstypes = smb_create_strcnt(bb_strcnt);
 927         if (bbstypes == NULL)  {
 928                 goto bad;
 929         }
 930 
 931         bbstypes->type = SMB_TYPE_BASEBOARD;
 932         smb_strcnt(shp, bbstypes);
 933         smb_bb_contains(shp, bbstypes);
 934 
 935         for (nb = 0; nb < bbstypes->count; nb++) {
 936                 if (bbstypes->ids[nb]->visited) {
 937                         continue;
 938                 }
 939 
 940                 bbstypes->ids[nb]->visited = 1;
 941                 bb_smbid = bbstypes->ids[nb]->id;
 942 
 943                 /*
 944                  * check if there is a matching  processor under
 945                  * this board. If found, find base board(s) of this proc
 946                  * If proc is not in contained handle of a base board and
 947                  * there is only one base board in the system, treat that base
 948                  * board as the parent of the proc
 949                  */
 950                 if (find_matching_proc(shp, strand_apicid,
 951                     bb_smbid, proc_hdl, is_proc) || (bbstypes->count == 1)) {
 952                         fmri = fm_nvlist_create(NULL);
 953                         if (fmri == NULL) {
 954                                 smb_free_strcnt(bbstypes, bb_strcnt);
 955                                 goto bad;
 956                         }
 957                         /*
 958                          * find parent by walking the cont_by_id
 959                          */
 960                         rc = smb_get_bb_fmri(shp, fmri, bb_smbid, bbstypes);
 961                         smb_free_strcnt(bbstypes, bb_strcnt);
 962                         if (rc == 0) {
 963                                 return (fmri);
 964                         } else
 965                                 goto bad;
 966                 }
 967 
 968         }
 969 
 970         smb_free_strcnt(bbstypes, bb_strcnt);
 971 bad:
 972         /* revert to legacy enumeration */
 973         x86gentopo_legacy = 1;
 974 
 975         return (NULL);
 976 }
 977 
 978 nvlist_t *
 979 fm_smb_bboard(uint_t strand_apicid)
 980 {
 981         return (smb_bboard(strand_apicid, 0, PROC));
 982 }
 983 
 984 int
 985 fm_smb_chipinst(uint_t strand_apicid, uint_t *chip_inst, uint16_t *smbiosid)
 986 {
 987         int n;
 988         smbios_hdl_t *shp;
 989         uint16_t proc_id;
 990         smbs_cnt_t *pstypes;
 991         int strcnt;
 992 
 993         if (x86gentopo_legacy)
 994                 return (-1);
 995 
 996         shp = ksmbios;
 997         if (shp == NULL) {
 998                 goto bad;
 999         }
1000 
1001         strcnt = smb_cnttypes(shp, SMB_TYPE_PROCESSOR);
1002         if (strcnt == 0)
1003                 goto bad;
1004 
1005         pstypes = smb_create_strcnt(strcnt);
1006         if (pstypes == NULL)
1007                 goto bad;
1008 
1009         pstypes->type = SMB_TYPE_PROCESSOR;
1010         smb_strcnt(shp, pstypes);
1011         for (n = 0; n < pstypes->count; n++) {
1012                 proc_id = pstypes->ids[n]->id;
1013                 if (find_matching_apic(shp, proc_id, strand_apicid)) {
1014                         *chip_inst = pstypes->ids[n]->inst;
1015                         *smbiosid = pstypes->ids[n]->id;
1016                         smb_free_strcnt(pstypes, strcnt);
1017                         return (0);
1018                 }
1019         }
1020         smb_free_strcnt(pstypes, strcnt);
1021 bad:
1022         /* revert to legacy enumerarion */
1023         x86gentopo_legacy = 1;
1024 
1025         return (-1);
1026 }
1027 
1028 nvlist_t *
1029 fm_smb_mc_bboards(uint_t bdf)
1030 {
1031 
1032         int i;
1033         smbios_hdl_t *shp;
1034         uint16_t ext_id;
1035         smbios_memarray_ext_t em;
1036         nvlist_t *fmri = NULL;
1037         smbs_cnt_t *mastypes;
1038         int strcnt;
1039 
1040         if (x86gentopo_legacy)
1041                 return (NULL);
1042 
1043         shp = ksmbios;
1044         if (shp == NULL) {
1045                 goto bad;
1046         }
1047 
1048         strcnt = smb_cnttypes(shp, SUN_OEM_EXT_MEMARRAY);
1049         if (strcnt == 0)
1050                 goto bad;
1051 
1052         mastypes = smb_create_strcnt(strcnt);
1053         if (mastypes == NULL)
1054                 goto bad;
1055 
1056         mastypes->type = SUN_OEM_EXT_MEMARRAY;
1057         smb_strcnt(shp, mastypes);
1058         for (i = 0; i < mastypes->count; i++) {
1059                 ext_id = mastypes->ids[i]->id;
1060                 (void) smbios_info_extmemarray(shp, ext_id, &em);
1061                 if (em.smbmae_bdf == bdf) {
1062                         fmri = smb_bboard(0, em.smbmae_comp, MC);
1063                         smb_free_strcnt(mastypes, strcnt);
1064                         return (fmri);
1065                 }
1066         }
1067         smb_free_strcnt(mastypes, strcnt);
1068 bad:
1069         /* revert to legacy enumerarion */
1070         x86gentopo_legacy = 1;
1071 
1072         return (NULL);
1073 }
1074 
1075 int
1076 fm_smb_mc_chipinst(uint_t bdf, uint_t *chip_inst) {
1077 
1078         int i, j;
1079         smbios_hdl_t *shp;
1080         smbios_memarray_ext_t em;
1081         uint16_t ext_id, proc_id;
1082         smbs_cnt_t *mastypes;
1083         smbs_cnt_t *pstypes;
1084         int ma_strcnt, p_strcnt;
1085 
1086         if (x86gentopo_legacy)
1087                 return (-1);
1088 
1089         shp = ksmbios;
1090         if (shp == NULL) {
1091                 goto bad;
1092         }
1093 
1094         ma_strcnt = smb_cnttypes(shp, SUN_OEM_EXT_MEMARRAY);
1095         if (ma_strcnt == 0)
1096                 goto bad;
1097 
1098         mastypes = smb_create_strcnt(ma_strcnt);
1099         if (mastypes == NULL)
1100                 goto bad;
1101 
1102         mastypes->type = SUN_OEM_EXT_MEMARRAY;
1103         smb_strcnt(shp, mastypes);
1104         for (i = 0; i < mastypes->count; i++) {
1105                 ext_id = mastypes->ids[i]->id;
1106                 (void) smbios_info_extmemarray(shp, ext_id, &em);
1107                     if (em.smbmae_bdf == bdf) {
1108                         p_strcnt = smb_cnttypes(shp, SMB_TYPE_PROCESSOR);
1109                         if (p_strcnt == 0) {
1110                                 smb_free_strcnt(mastypes, ma_strcnt);
1111                                 goto bad;
1112                         }
1113 
1114                         pstypes = smb_create_strcnt(p_strcnt);
1115                         if (pstypes == NULL) {
1116                                 smb_free_strcnt(mastypes, ma_strcnt);
1117                                 goto bad;
1118                         }
1119 
1120                         pstypes->type = SMB_TYPE_PROCESSOR;
1121                         smb_strcnt(shp, pstypes);
1122                         for (j = 0; j < pstypes->count; j++) {
1123                                 proc_id = pstypes->ids[j]->id;
1124                                 if (proc_id == em.smbmae_comp) {
1125                                         *chip_inst = pstypes->ids[j]->inst;
1126                                         smb_free_strcnt(mastypes, ma_strcnt);
1127                                         smb_free_strcnt(pstypes, p_strcnt);
1128                                         return (0);
1129                                 }
1130                         }
1131                 }
1132         }
1133         smb_free_strcnt(mastypes, ma_strcnt);
1134         smb_free_strcnt(pstypes, p_strcnt);
1135 bad:
1136         /* revert to legacy enumeration */
1137         x86gentopo_legacy = 1;
1138 
1139         return (-1);
1140 }