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 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 
  27 #include <fm/fmd_api.h>
  28 #include <fm/libtopo.h>
  29 #include <sys/fm/protocol.h>
  30 #include <cmd.h>
  31 #include <string.h>
  32 #include <cmd_hc_sun4v.h>
  33 
  34 /* Using a global variable is safe because the DE is single threaded */
  35 
  36 nvlist_t *dimm_nvl;
  37 nvlist_t *mb_nvl;
  38 nvlist_t *rsc_nvl;
  39 
  40 nvlist_t *
  41 cmd_fault_add_location(fmd_hdl_t *hdl, nvlist_t *flt, const char *locstr) {
  42 
  43         char *t, *s;
  44 
  45         if (nvlist_lookup_string(flt, FM_FAULT_LOCATION, &t) == 0)
  46                 return (flt); /* already has location value */
  47 
  48         /* Replace occurrence of ": " with "/" to avoid confusing ILOM. */
  49         t = fmd_hdl_zalloc(hdl, strlen(locstr) + 1, FMD_SLEEP);
  50         s = strstr(locstr, ": ");
  51         if (s != NULL) {
  52                 (void) strncpy(t, locstr, s - locstr);
  53                 (void) strcat(t, "/");
  54                 (void) strcat(t, s + 2);
  55         } else {
  56                 (void) strcpy(t, locstr);
  57         }
  58 
  59         /* Also, remove any J number from end of this string. */
  60         s = strstr(t, "/J");
  61         if (s != NULL)
  62                 *s = '\0';
  63 
  64         if (nvlist_add_string(flt, FM_FAULT_LOCATION, t) != 0)
  65                 fmd_hdl_error(hdl, "unable to alloc location for fault\n");
  66         fmd_hdl_free(hdl, t, strlen(locstr) + 1);
  67         return (flt);
  68 }
  69 
  70 typedef struct tr_ent {
  71         const char *nac_component;
  72         const char *hc_component;
  73 } tr_ent_t;
  74 
  75 static tr_ent_t tr_tbl[] = {
  76         { "MB",         "motherboard" },
  77         { "CPU",        "cpuboard" },
  78         { "MEM",        "memboard" },
  79         { "CMP",        "chip" },
  80         { "BR",         "branch" },
  81         { "CH",         "dram-channel" },
  82         { "R",          "rank" },
  83         { "D",          "dimm" }
  84 };
  85 
  86 #define tr_tbl_n        sizeof (tr_tbl) / sizeof (tr_ent_t)
  87 
  88 int
  89 map_name(const char *p) {
  90         int i;
  91 
  92         for (i = 0; i < tr_tbl_n; i++) {
  93                 if (strncmp(p, tr_tbl[i].nac_component,
  94                     strlen(tr_tbl[i].nac_component)) == 0)
  95                         return (i);
  96         }
  97         return (-1);
  98 }
  99 
 100 int
 101 cmd_count_components(const char *str, char sep)
 102 {
 103         int num = 0;
 104         const char *cptr = str;
 105 
 106         if (*cptr == sep) cptr++;               /* skip initial sep */
 107         if (strlen(cptr) > 0) num = 1;
 108         while ((cptr = strchr(cptr, sep)) != NULL) {
 109                 cptr++;
 110                 if (cptr == NULL || strcmp(cptr, "") == 0) break;
 111                 if (map_name(cptr) >= 0) num++;
 112         }
 113         return (num);
 114 }
 115 
 116 /*
 117  * This version of breakup_components assumes that all component names which
 118  * it sees are of the form:  <nonnumeric piece><numeric piece>
 119  * i.e. no embedded numerals in component name which have to be spelled out.
 120  */
 121 
 122 int
 123 cmd_breakup_components(char *str, char *sep, nvlist_t **hc_nvl)
 124 {
 125         char namebuf[64], instbuf[64];
 126         char *token, *tokbuf;
 127         int i, j, namelen, instlen;
 128 
 129         i = 0;
 130         for (token = strtok_r(str, sep, &tokbuf);
 131             token != NULL;
 132             token = strtok_r(NULL, sep, &tokbuf)) {
 133                 namelen = strcspn(token, "0123456789");
 134                 instlen = strspn(token+namelen, "0123456789");
 135                 (void) strncpy(namebuf, token, namelen);
 136                 namebuf[namelen] = '\0';
 137 
 138                 if ((j = map_name(namebuf)) < 0)
 139                         continue; /* skip names that don't map */
 140 
 141                 if (instlen == 0) {
 142                         (void) strncpy(instbuf, "0", 2);
 143                 } else {
 144                         (void) strncpy(instbuf, token+namelen, instlen);
 145                         instbuf[instlen] = '\0';
 146                 }
 147                 if (nvlist_add_string(hc_nvl[i], FM_FMRI_HC_NAME,
 148                     tr_tbl[j].hc_component) != 0 ||
 149                     nvlist_add_string(hc_nvl[i], FM_FMRI_HC_ID, instbuf) != 0)
 150                         return (-1);
 151                 i++;
 152         }
 153         return (1);
 154 }
 155 
 156 char *
 157 cmd_getfru_loc(fmd_hdl_t *hdl, nvlist_t *asru) {
 158 
 159         char *fru_loc, *cpufru;
 160         if (nvlist_lookup_string(asru, FM_FMRI_CPU_CPUFRU, &cpufru) == 0) {
 161                 fru_loc = strstr(cpufru, "MB");
 162                 if (fru_loc != NULL) {
 163                         fmd_hdl_debug(hdl, "cmd_getfru_loc: fruloc=%s\n",
 164                             fru_loc);
 165                         return (fmd_hdl_strdup(hdl, fru_loc, FMD_SLEEP));
 166                 }
 167         }
 168         fmd_hdl_debug(hdl, "cmd_getfru_loc: Default fruloc=empty string\n");
 169         return (fmd_hdl_strdup(hdl, EMPTY_STR, FMD_SLEEP));
 170 }
 171 
 172 nvlist_t *
 173 cmd_mkboard_fru(fmd_hdl_t *hdl, char *frustr, char *serialstr, char *partstr) {
 174 
 175         char *nac, *nac_name;
 176         int n, i, len;
 177         nvlist_t *fru, **hc_list;
 178 
 179         if (frustr == NULL)
 180                 return (NULL);
 181 
 182         if ((nac_name = strstr(frustr, "MB")) == NULL)
 183                 return (NULL);
 184 
 185         len = strlen(nac_name) + 1;
 186 
 187         nac = fmd_hdl_zalloc(hdl, len, FMD_SLEEP);
 188         (void) strcpy(nac, nac_name);
 189 
 190         n = cmd_count_components(nac, '/');
 191 
 192         fmd_hdl_debug(hdl, "cmd_mkboard_fru: nac=%s components=%d\n", nac, n);
 193 
 194         hc_list = fmd_hdl_zalloc(hdl, sizeof (nvlist_t *)*n, FMD_SLEEP);
 195 
 196         for (i = 0; i < n; i++) {
 197                 (void) nvlist_alloc(&hc_list[i],
 198                     NV_UNIQUE_NAME|NV_UNIQUE_NAME_TYPE, 0);
 199         }
 200 
 201         if (cmd_breakup_components(nac, "/", hc_list) < 0) {
 202                 for (i = 0; i < n; i++) {
 203                         if (hc_list[i] != NULL)
 204                             nvlist_free(hc_list[i]);
 205                 }
 206                 fmd_hdl_free(hdl, hc_list, sizeof (nvlist_t *)*n);
 207                 fmd_hdl_free(hdl, nac, len);
 208                 return (NULL);
 209         }
 210 
 211         if (nvlist_alloc(&fru, NV_UNIQUE_NAME, 0) != 0) {
 212                 for (i = 0; i < n; i++) {
 213                         if (hc_list[i] != NULL)
 214                             nvlist_free(hc_list[i]);
 215                 }
 216                 fmd_hdl_free(hdl, hc_list, sizeof (nvlist_t *)*n);
 217                 fmd_hdl_free(hdl, nac, len);
 218                 return (NULL);
 219         }
 220 
 221         if (nvlist_add_uint8(fru, FM_VERSION, FM_HC_SCHEME_VERSION) != 0 ||
 222             nvlist_add_string(fru, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC) != 0 ||
 223             nvlist_add_string(fru, FM_FMRI_HC_ROOT, "") != 0 ||
 224             nvlist_add_uint32(fru, FM_FMRI_HC_LIST_SZ, n) != 0 ||
 225             nvlist_add_nvlist_array(fru, FM_FMRI_HC_LIST, hc_list, n) != 0) {
 226                 for (i = 0; i < n; i++) {
 227                         if (hc_list[i] != NULL)
 228                             nvlist_free(hc_list[i]);
 229                 }
 230                 fmd_hdl_free(hdl, hc_list, sizeof (nvlist_t *)*n);
 231                 fmd_hdl_free(hdl, nac, len);
 232                 nvlist_free(fru);
 233                 return (NULL);
 234         }
 235 
 236         for (i = 0; i < n; i++) {
 237                 if (hc_list[i] != NULL)
 238                     nvlist_free(hc_list[i]);
 239         }
 240         fmd_hdl_free(hdl, hc_list, sizeof (nvlist_t *)*n);
 241         fmd_hdl_free(hdl, nac, len);
 242 
 243         if ((serialstr != NULL &&
 244             nvlist_add_string(fru, FM_FMRI_HC_SERIAL_ID, serialstr) != 0) ||
 245             (partstr != NULL &&
 246             nvlist_add_string(fru, FM_FMRI_HC_PART, partstr) != 0)) {
 247                 nvlist_free(fru);
 248                 return (NULL);
 249         }
 250 
 251         return (fru);
 252 }
 253 
 254 nvlist_t *
 255 cmd_boardfru_create_fault(fmd_hdl_t *hdl, nvlist_t *asru, const char *fltnm,
 256     uint_t cert, char *loc)
 257 {
 258         nvlist_t *flt, *nvlfru;
 259         char *serialstr, *partstr;
 260 
 261         if ((loc == NULL) || (strcmp(loc, EMPTY_STR) == 0))
 262                 return (NULL);
 263 
 264         if (nvlist_lookup_string(asru, FM_FMRI_HC_SERIAL_ID, &serialstr) != 0)
 265                 serialstr = NULL;
 266         if (nvlist_lookup_string(asru, FM_FMRI_HC_PART, &partstr) != 0)
 267                 partstr = NULL;
 268 
 269         nvlfru = cmd_mkboard_fru(hdl, loc, serialstr, partstr);
 270         if (nvlfru == NULL)
 271                 return (NULL);
 272 
 273         flt = cmd_nvl_create_fault(hdl, fltnm, cert, nvlfru, nvlfru, NULL);
 274         flt = cmd_fault_add_location(hdl, flt, loc);
 275         if (nvlfru != NULL)
 276                 nvlist_free(nvlfru);
 277         return (flt);
 278 }
 279 
 280 /* find_mb -- find hardware platform motherboard within libtopo */
 281 
 282 /* ARGSUSED */
 283 static int
 284 find_mb(topo_hdl_t *thp, tnode_t *node, void *arg)
 285 {
 286         int err;
 287         nvlist_t *rsrc, **hcl;
 288         char *name;
 289         uint_t n;
 290 
 291         if (topo_node_resource(node, &rsrc, &err) < 0) {
 292                 return (TOPO_WALK_NEXT);        /* no resource, try next */
 293         }
 294 
 295         if (nvlist_lookup_nvlist_array(rsrc, FM_FMRI_HC_LIST, &hcl, &n) < 0) {
 296                 nvlist_free(rsrc);
 297                 return (TOPO_WALK_NEXT);
 298         }
 299 
 300         if (nvlist_lookup_string(hcl[0], FM_FMRI_HC_NAME, &name) != 0) {
 301                 nvlist_free(rsrc);
 302                 return (TOPO_WALK_NEXT);
 303         }
 304 
 305         if (strcmp(name, "motherboard") != 0) {
 306                 nvlist_free(rsrc);
 307                 return (TOPO_WALK_NEXT); /* not MB hc list, try next */
 308         }
 309 
 310         (void) nvlist_dup(rsrc, &mb_nvl, NV_UNIQUE_NAME);
 311 
 312         nvlist_free(rsrc);
 313         return (TOPO_WALK_TERMINATE);   /* if no space, give up */
 314 }
 315 
 316 /* init_mb -- read hardware platform motherboard from libtopo */
 317 
 318 nvlist_t *
 319 init_mb(fmd_hdl_t *hdl)
 320 {
 321         topo_hdl_t *thp;
 322         topo_walk_t *twp;
 323         int err;
 324 
 325         if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL)
 326                 return (NULL);
 327         if ((twp = topo_walk_init(thp,
 328             FM_FMRI_SCHEME_HC, find_mb, NULL, &err))
 329             == NULL) {
 330                 fmd_hdl_topo_rele(hdl, thp);
 331                 return (NULL);
 332         }
 333         (void) topo_walk_step(twp, TOPO_WALK_CHILD);
 334         topo_walk_fini(twp);
 335         fmd_hdl_topo_rele(hdl, thp);
 336         return (mb_nvl);
 337 }
 338 
 339 /*ARGSUSED*/
 340 static int
 341 find_dimm_sn_mem(topo_hdl_t *thp, tnode_t *node, void *arg)
 342 {
 343         int err;
 344         uint_t n;
 345         nvlist_t *rsrc;
 346         char **sn;
 347 
 348         if (topo_node_resource(node, &rsrc, &err) < 0) {
 349                 return (TOPO_WALK_NEXT);        /* no resource, try next */
 350         }
 351         if (nvlist_lookup_string_array(rsrc,
 352             FM_FMRI_HC_SERIAL_ID, &sn, &n) != 0) {
 353                 nvlist_free(rsrc);
 354                 return (TOPO_WALK_NEXT);
 355         }
 356         if (strcmp(*sn, (char *)arg) != 0) {
 357                 nvlist_free(rsrc);
 358                 return (TOPO_WALK_NEXT);
 359         }
 360         (void) nvlist_dup(rsrc, &dimm_nvl, NV_UNIQUE_NAME);
 361         nvlist_free(rsrc);
 362         return (TOPO_WALK_TERMINATE);   /* if no space, give up */
 363 }
 364 
 365 /*ARGSUSED*/
 366 static int
 367 find_dimm_sn_hc(topo_hdl_t *thp, tnode_t *node, void *arg)
 368 {
 369         int err;
 370         nvlist_t *fru;
 371         char *sn;
 372 
 373         if (topo_node_fru(node, &fru, 0,  &err) < 0) {
 374                 return (TOPO_WALK_NEXT);        /* no fru, try next */
 375         }
 376         if (nvlist_lookup_string(fru, FM_FMRI_HC_SERIAL_ID, &sn) != 0) {
 377                 nvlist_free(fru);
 378                 return (TOPO_WALK_NEXT);
 379         }
 380         if (strcmp(sn, (char *)arg) != 0) {
 381                 nvlist_free(fru);
 382                 return (TOPO_WALK_NEXT);
 383         }
 384         (void) nvlist_dup(fru, &dimm_nvl, NV_UNIQUE_NAME);
 385         nvlist_free(fru);
 386         return (TOPO_WALK_TERMINATE);   /* if no space, give up */
 387 }
 388 
 389 /* cmd_find_dimm_by_sn -- find fmri by sn from libtopo */
 390 
 391 nvlist_t *
 392 cmd_find_dimm_by_sn(fmd_hdl_t *hdl, char *schemename, char *sn)
 393 {
 394         topo_hdl_t *thp;
 395         topo_walk_t *twp;
 396         int err;
 397 
 398         dimm_nvl = NULL;
 399 
 400         if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL)
 401                 return (NULL);
 402         if (strcmp(schemename, FM_FMRI_SCHEME_MEM) == 0) {
 403                 if ((twp = topo_walk_init(thp,
 404                     schemename, find_dimm_sn_mem, sn, &err)) == NULL) {
 405                         fmd_hdl_topo_rele(hdl, thp);
 406                         return (NULL);
 407                 }
 408         } else {
 409                 if ((twp = topo_walk_init(thp,
 410                     schemename, find_dimm_sn_hc, sn, &err)) == NULL) {
 411                         fmd_hdl_topo_rele(hdl, thp);
 412                         return (NULL);
 413                 }
 414         }
 415         (void) topo_walk_step(twp, TOPO_WALK_CHILD);
 416         topo_walk_fini(twp);
 417         fmd_hdl_topo_rele(hdl, thp);
 418         return (dimm_nvl);
 419 }
 420 
 421 typedef struct cpuid {
 422         char serial[100];
 423         char id[10];
 424 } cpuid_t;
 425 
 426 /*ARGSUSED*/
 427 static int
 428 find_cpu_rsc_by_sn(topo_hdl_t *thp, tnode_t *node, void *arg)
 429 {
 430         int err;
 431         nvlist_t *rsc;
 432         cpuid_t *rscid = (cpuid_t *)arg;
 433         char *sn, *name, *id;
 434         nvlist_t **hcl;
 435         uint_t n;
 436 
 437         if (topo_node_resource(node, &rsc, &err) < 0) {
 438                 return (TOPO_WALK_NEXT);        /* no rsc, try next */
 439         }
 440 
 441         if (nvlist_lookup_string(rsc, FM_FMRI_HC_SERIAL_ID, &sn) != 0) {
 442                 nvlist_free(rsc);
 443                 return (TOPO_WALK_NEXT);
 444         }
 445         if (strcmp(rscid->serial, sn) != 0) {
 446                 nvlist_free(rsc);
 447                 return (TOPO_WALK_NEXT);
 448         }
 449 
 450         if (nvlist_lookup_nvlist_array(rsc, FM_FMRI_HC_LIST, &hcl, &n) != 0) {
 451                 nvlist_free(rsc);
 452                 return (TOPO_WALK_NEXT);
 453         }
 454 
 455         if ((nvlist_lookup_string(hcl[n - 1], FM_FMRI_HC_NAME, &name) != 0) ||
 456             (nvlist_lookup_string(hcl[n - 1], FM_FMRI_HC_ID, &id) != 0)) {
 457                 nvlist_free(rsc);
 458                 return (TOPO_WALK_NEXT);
 459         }
 460 
 461         if ((strcmp(name, "cpu") != 0) || (strcmp(rscid->id, id) != 0)) {
 462                 nvlist_free(rsc);
 463                 return (TOPO_WALK_NEXT);
 464         }
 465 
 466         (void) nvlist_dup(rsc, &rsc_nvl, NV_UNIQUE_NAME);
 467 
 468         nvlist_free(rsc);
 469         return (TOPO_WALK_TERMINATE);   /* if no space, give up */
 470 }
 471 
 472 nvlist_t *
 473 cmd_find_cpu_rsc_by_sn(fmd_hdl_t *hdl, cpuid_t *cpuid)
 474 {
 475         topo_hdl_t *thp;
 476         topo_walk_t *twp;
 477         int err;
 478 
 479         rsc_nvl = NULL;
 480         if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL)
 481                 return (NULL);
 482         if ((twp = topo_walk_init(thp, FM_FMRI_SCHEME_HC,
 483             find_cpu_rsc_by_sn, cpuid, &err)) == NULL) {
 484                 fmd_hdl_topo_rele(hdl, thp);
 485                 return (NULL);
 486         }
 487         (void) topo_walk_step(twp, TOPO_WALK_CHILD);
 488         topo_walk_fini(twp);
 489         fmd_hdl_topo_rele(hdl, thp);
 490         return (rsc_nvl);
 491 }
 492 
 493 nvlist_t *
 494 get_cpu_fault_resource(fmd_hdl_t *hdl, nvlist_t *asru)
 495 {
 496         uint32_t cpu;
 497         uint64_t serint;
 498         char serial[64];
 499         nvlist_t *rsc = NULL;
 500         cpuid_t cpuid;
 501         char strid[10];
 502 
 503         if (nvlist_lookup_uint64(asru, FM_FMRI_CPU_SERIAL_ID, &serint) != 0 ||
 504             nvlist_lookup_uint32(asru, FM_FMRI_CPU_ID, &cpu) != 0)
 505                 return (rsc);
 506 
 507         (void) snprintf(serial, sizeof (serial), "%llx", serint);
 508         (void) snprintf(strid, sizeof (strid), "%d", cpu);
 509 
 510         (void) strcpy(cpuid.serial, serial);
 511         (void) strcpy(cpuid.id, strid);
 512 
 513         rsc = cmd_find_cpu_rsc_by_sn(hdl, &cpuid);
 514         return (rsc);
 515 }
 516 
 517 /*ARGSUSED*/
 518 static int
 519 find_mem_rsc_hc(topo_hdl_t *thp, tnode_t *node, void *arg)
 520 {
 521         int err;
 522         nvlist_t *rsc;
 523         char *sn;
 524 
 525         if (topo_node_resource(node, &rsc, &err) < 0) {
 526                 return (TOPO_WALK_NEXT);        /* no rsc, try next */
 527         }
 528         if (nvlist_lookup_string(rsc, FM_FMRI_HC_SERIAL_ID, &sn) != 0) {
 529                 nvlist_free(rsc);
 530                 return (TOPO_WALK_NEXT);
 531         }
 532         if (strcmp(sn, (char *)arg) != 0) {
 533                 nvlist_free(rsc);
 534                 return (TOPO_WALK_NEXT);
 535         }
 536         (void) nvlist_dup(rsc, &rsc_nvl, NV_UNIQUE_NAME);
 537         nvlist_free(rsc);
 538         return (TOPO_WALK_TERMINATE);   /* if no space, give up */
 539 }
 540 
 541 nvlist_t *
 542 cmd_find_mem_rsc_by_sn(fmd_hdl_t *hdl, char *sn)
 543 {
 544         topo_hdl_t *thp;
 545         topo_walk_t *twp;
 546         int err;
 547 
 548         rsc_nvl = NULL;
 549 
 550         if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL)
 551                 return (NULL);
 552         if ((twp = topo_walk_init(thp, FM_FMRI_SCHEME_HC,
 553             find_mem_rsc_hc, sn, &err)) == NULL) {
 554                 fmd_hdl_topo_rele(hdl, thp);
 555                 return (NULL);
 556         }
 557         (void) topo_walk_step(twp, TOPO_WALK_CHILD);
 558         topo_walk_fini(twp);
 559         fmd_hdl_topo_rele(hdl, thp);
 560         return (rsc_nvl);
 561 }
 562 
 563 nvlist_t *
 564 get_mem_fault_resource(fmd_hdl_t *hdl, nvlist_t *fru)
 565 {
 566         char *sn;
 567         uint_t n;
 568         char **snarray;
 569 
 570         if (nvlist_lookup_string(fru, FM_FMRI_HC_SERIAL_ID, &sn) == 0)
 571                 return (cmd_find_mem_rsc_by_sn(hdl, sn));
 572 
 573         /*
 574          * T1 platform fru is in mem scheme
 575          */
 576         if (nvlist_lookup_string_array(fru, FM_FMRI_MEM_SERIAL_ID,
 577             &snarray, &n) == 0)
 578                 return (cmd_find_mem_rsc_by_sn(hdl, snarray[0]));
 579 
 580         return (NULL);
 581 }
 582 
 583 int
 584 is_T1_platform(nvlist_t *asru)
 585 {
 586         char *unum;
 587         if (nvlist_lookup_string(asru, FM_FMRI_MEM_UNUM, &unum) == 0) {
 588                 if (strstr(unum, "BR") == NULL)
 589                         return (1);
 590         }
 591         return (0);
 592 }
 593 
 594 nvlist_t *
 595 cmd_nvl_create_fault(fmd_hdl_t *hdl, const char *class, uint8_t cert,
 596     nvlist_t *asru, nvlist_t *fru, nvlist_t *rsrc)
 597 {
 598         nvlist_t *fllist;
 599         uint64_t offset, phyaddr;
 600         nvlist_t *hsp = NULL;
 601 
 602         rsrc = NULL;
 603         (void) nvlist_add_nvlist(fru, FM_FMRI_AUTHORITY,
 604             cmd.cmd_auth); /* not an error if this fails */
 605 
 606         if (strstr(class, "fault.memory.") != NULL) {
 607                 /*
 608                  * For T1 platform fault.memory.bank and fault.memory.dimm,
 609                  * do not issue the hc schmem for resource and fru
 610                  */
 611                 if (is_T1_platform(asru) && (strstr(class, ".page") == NULL)) {
 612                         fllist = fmd_nvl_create_fault(hdl, class, cert, asru,
 613                             fru, fru);
 614                         return (fllist);
 615                 }
 616 
 617                 rsrc = get_mem_fault_resource(hdl, fru);
 618                 /*
 619                  * Need to append the phyaddr & offset into the
 620                  * hc-specific of the fault.memory.page resource
 621                  */
 622                 if ((rsrc != NULL) && strstr(class, ".page") != NULL) {
 623                         if (nvlist_alloc(&hsp, NV_UNIQUE_NAME, 0) == 0) {
 624                                 if (nvlist_lookup_uint64(asru,
 625                                     FM_FMRI_MEM_PHYSADDR, &phyaddr) == 0)
 626                                         (void) (nvlist_add_uint64(hsp,
 627                                             FM_FMRI_MEM_PHYSADDR,
 628                                             phyaddr));
 629 
 630                                 if (nvlist_lookup_uint64(asru,
 631                                     FM_FMRI_MEM_OFFSET, &offset) == 0)
 632                                         (void) nvlist_add_uint64(hsp,
 633                                             FM_FMRI_HC_SPECIFIC_OFFSET, offset);
 634 
 635                                 (void) nvlist_add_nvlist(rsrc,
 636                                     FM_FMRI_HC_SPECIFIC, hsp);
 637                         }
 638                 }
 639                 fllist = fmd_nvl_create_fault(hdl, class, cert, asru,
 640                     fru, rsrc);
 641                 if (hsp != NULL)
 642                         nvlist_free(hsp);
 643         } else {
 644                 rsrc = get_cpu_fault_resource(hdl, asru);
 645                 fllist = fmd_nvl_create_fault(hdl, class, cert, asru,
 646                     fru, rsrc);
 647         }
 648 
 649         if (rsrc != NULL)
 650                 nvlist_free(rsrc);
 651 
 652         return (fllist);
 653 }