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