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                         nvlist_free(hc_list[i]);
 204                 }
 205                 fmd_hdl_free(hdl, hc_list, sizeof (nvlist_t *)*n);
 206                 fmd_hdl_free(hdl, nac, len);
 207                 return (NULL);
 208         }
 209 
 210         if (nvlist_alloc(&fru, NV_UNIQUE_NAME, 0) != 0) {
 211                 for (i = 0; i < n; i++) {
 212                         nvlist_free(hc_list[i]);
 213                 }
 214                 fmd_hdl_free(hdl, hc_list, sizeof (nvlist_t *)*n);
 215                 fmd_hdl_free(hdl, nac, len);
 216                 return (NULL);
 217         }
 218 
 219         if (nvlist_add_uint8(fru, FM_VERSION, FM_HC_SCHEME_VERSION) != 0 ||
 220             nvlist_add_string(fru, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC) != 0 ||
 221             nvlist_add_string(fru, FM_FMRI_HC_ROOT, "") != 0 ||
 222             nvlist_add_uint32(fru, FM_FMRI_HC_LIST_SZ, n) != 0 ||
 223             nvlist_add_nvlist_array(fru, FM_FMRI_HC_LIST, hc_list, n) != 0) {
 224                 for (i = 0; i < n; i++) {
 225                         nvlist_free(hc_list[i]);
 226                 }
 227                 fmd_hdl_free(hdl, hc_list, sizeof (nvlist_t *)*n);
 228                 fmd_hdl_free(hdl, nac, len);
 229                 nvlist_free(fru);
 230                 return (NULL);
 231         }
 232 
 233         for (i = 0; i < n; i++) {
 234                 nvlist_free(hc_list[i]);
 235         }
 236         fmd_hdl_free(hdl, hc_list, sizeof (nvlist_t *)*n);
 237         fmd_hdl_free(hdl, nac, len);
 238 
 239         if ((serialstr != NULL &&
 240             nvlist_add_string(fru, FM_FMRI_HC_SERIAL_ID, serialstr) != 0) ||
 241             (partstr != NULL &&
 242             nvlist_add_string(fru, FM_FMRI_HC_PART, partstr) != 0)) {
 243                 nvlist_free(fru);
 244                 return (NULL);
 245         }
 246 
 247         return (fru);
 248 }
 249 
 250 nvlist_t *
 251 cmd_boardfru_create_fault(fmd_hdl_t *hdl, nvlist_t *asru, const char *fltnm,
 252     uint_t cert, char *loc)
 253 {
 254         nvlist_t *flt, *nvlfru;
 255         char *serialstr, *partstr;
 256 
 257         if ((loc == NULL) || (strcmp(loc, EMPTY_STR) == 0))
 258                 return (NULL);
 259 
 260         if (nvlist_lookup_string(asru, FM_FMRI_HC_SERIAL_ID, &serialstr) != 0)
 261                 serialstr = NULL;
 262         if (nvlist_lookup_string(asru, FM_FMRI_HC_PART, &partstr) != 0)
 263                 partstr = NULL;
 264 
 265         nvlfru = cmd_mkboard_fru(hdl, loc, serialstr, partstr);
 266         if (nvlfru == NULL)
 267                 return (NULL);
 268 
 269         flt = cmd_nvl_create_fault(hdl, fltnm, cert, nvlfru, nvlfru, NULL);
 270         flt = cmd_fault_add_location(hdl, flt, loc);
 271         nvlist_free(nvlfru);
 272         return (flt);
 273 }
 274 
 275 /* find_mb -- find hardware platform motherboard within libtopo */
 276 
 277 /* ARGSUSED */
 278 static int
 279 find_mb(topo_hdl_t *thp, tnode_t *node, void *arg)
 280 {
 281         int err;
 282         nvlist_t *rsrc, **hcl;
 283         char *name;
 284         uint_t n;
 285 
 286         if (topo_node_resource(node, &rsrc, &err) < 0) {
 287                 return (TOPO_WALK_NEXT);        /* no resource, try next */
 288         }
 289 
 290         if (nvlist_lookup_nvlist_array(rsrc, FM_FMRI_HC_LIST, &hcl, &n) < 0) {
 291                 nvlist_free(rsrc);
 292                 return (TOPO_WALK_NEXT);
 293         }
 294 
 295         if (nvlist_lookup_string(hcl[0], FM_FMRI_HC_NAME, &name) != 0) {
 296                 nvlist_free(rsrc);
 297                 return (TOPO_WALK_NEXT);
 298         }
 299 
 300         if (strcmp(name, "motherboard") != 0) {
 301                 nvlist_free(rsrc);
 302                 return (TOPO_WALK_NEXT); /* not MB hc list, try next */
 303         }
 304 
 305         (void) nvlist_dup(rsrc, &mb_nvl, NV_UNIQUE_NAME);
 306 
 307         nvlist_free(rsrc);
 308         return (TOPO_WALK_TERMINATE);   /* if no space, give up */
 309 }
 310 
 311 /* init_mb -- read hardware platform motherboard from libtopo */
 312 
 313 nvlist_t *
 314 init_mb(fmd_hdl_t *hdl)
 315 {
 316         topo_hdl_t *thp;
 317         topo_walk_t *twp;
 318         int err;
 319 
 320         if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL)
 321                 return (NULL);
 322         if ((twp = topo_walk_init(thp,
 323             FM_FMRI_SCHEME_HC, find_mb, NULL, &err))
 324             == NULL) {
 325                 fmd_hdl_topo_rele(hdl, thp);
 326                 return (NULL);
 327         }
 328         (void) topo_walk_step(twp, TOPO_WALK_CHILD);
 329         topo_walk_fini(twp);
 330         fmd_hdl_topo_rele(hdl, thp);
 331         return (mb_nvl);
 332 }
 333 
 334 /*ARGSUSED*/
 335 static int
 336 find_dimm_sn_mem(topo_hdl_t *thp, tnode_t *node, void *arg)
 337 {
 338         int err;
 339         uint_t n;
 340         nvlist_t *rsrc;
 341         char **sn;
 342 
 343         if (topo_node_resource(node, &rsrc, &err) < 0) {
 344                 return (TOPO_WALK_NEXT);        /* no resource, try next */
 345         }
 346         if (nvlist_lookup_string_array(rsrc,
 347             FM_FMRI_HC_SERIAL_ID, &sn, &n) != 0) {
 348                 nvlist_free(rsrc);
 349                 return (TOPO_WALK_NEXT);
 350         }
 351         if (strcmp(*sn, (char *)arg) != 0) {
 352                 nvlist_free(rsrc);
 353                 return (TOPO_WALK_NEXT);
 354         }
 355         (void) nvlist_dup(rsrc, &dimm_nvl, NV_UNIQUE_NAME);
 356         nvlist_free(rsrc);
 357         return (TOPO_WALK_TERMINATE);   /* if no space, give up */
 358 }
 359 
 360 /*ARGSUSED*/
 361 static int
 362 find_dimm_sn_hc(topo_hdl_t *thp, tnode_t *node, void *arg)
 363 {
 364         int err;
 365         nvlist_t *fru;
 366         char *sn;
 367 
 368         if (topo_node_fru(node, &fru, 0,  &err) < 0) {
 369                 return (TOPO_WALK_NEXT);        /* no fru, try next */
 370         }
 371         if (nvlist_lookup_string(fru, FM_FMRI_HC_SERIAL_ID, &sn) != 0) {
 372                 nvlist_free(fru);
 373                 return (TOPO_WALK_NEXT);
 374         }
 375         if (strcmp(sn, (char *)arg) != 0) {
 376                 nvlist_free(fru);
 377                 return (TOPO_WALK_NEXT);
 378         }
 379         (void) nvlist_dup(fru, &dimm_nvl, NV_UNIQUE_NAME);
 380         nvlist_free(fru);
 381         return (TOPO_WALK_TERMINATE);   /* if no space, give up */
 382 }
 383 
 384 /* cmd_find_dimm_by_sn -- find fmri by sn from libtopo */
 385 
 386 nvlist_t *
 387 cmd_find_dimm_by_sn(fmd_hdl_t *hdl, char *schemename, char *sn)
 388 {
 389         topo_hdl_t *thp;
 390         topo_walk_t *twp;
 391         int err;
 392 
 393         dimm_nvl = NULL;
 394 
 395         if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL)
 396                 return (NULL);
 397         if (strcmp(schemename, FM_FMRI_SCHEME_MEM) == 0) {
 398                 if ((twp = topo_walk_init(thp,
 399                     schemename, find_dimm_sn_mem, sn, &err)) == NULL) {
 400                         fmd_hdl_topo_rele(hdl, thp);
 401                         return (NULL);
 402                 }
 403         } else {
 404                 if ((twp = topo_walk_init(thp,
 405                     schemename, find_dimm_sn_hc, sn, &err)) == NULL) {
 406                         fmd_hdl_topo_rele(hdl, thp);
 407                         return (NULL);
 408                 }
 409         }
 410         (void) topo_walk_step(twp, TOPO_WALK_CHILD);
 411         topo_walk_fini(twp);
 412         fmd_hdl_topo_rele(hdl, thp);
 413         return (dimm_nvl);
 414 }
 415 
 416 typedef struct cpuid {
 417         char serial[100];
 418         char id[10];
 419 } cpuid_t;
 420 
 421 /*ARGSUSED*/
 422 static int
 423 find_cpu_rsc_by_sn(topo_hdl_t *thp, tnode_t *node, void *arg)
 424 {
 425         int err;
 426         nvlist_t *rsc;
 427         cpuid_t *rscid = (cpuid_t *)arg;
 428         char *sn, *name, *id;
 429         nvlist_t **hcl;
 430         uint_t n;
 431 
 432         if (topo_node_resource(node, &rsc, &err) < 0) {
 433                 return (TOPO_WALK_NEXT);        /* no rsc, try next */
 434         }
 435 
 436         if (nvlist_lookup_string(rsc, FM_FMRI_HC_SERIAL_ID, &sn) != 0) {
 437                 nvlist_free(rsc);
 438                 return (TOPO_WALK_NEXT);
 439         }
 440         if (strcmp(rscid->serial, sn) != 0) {
 441                 nvlist_free(rsc);
 442                 return (TOPO_WALK_NEXT);
 443         }
 444 
 445         if (nvlist_lookup_nvlist_array(rsc, FM_FMRI_HC_LIST, &hcl, &n) != 0) {
 446                 nvlist_free(rsc);
 447                 return (TOPO_WALK_NEXT);
 448         }
 449 
 450         if ((nvlist_lookup_string(hcl[n - 1], FM_FMRI_HC_NAME, &name) != 0) ||
 451             (nvlist_lookup_string(hcl[n - 1], FM_FMRI_HC_ID, &id) != 0)) {
 452                 nvlist_free(rsc);
 453                 return (TOPO_WALK_NEXT);
 454         }
 455 
 456         if ((strcmp(name, "cpu") != 0) || (strcmp(rscid->id, id) != 0)) {
 457                 nvlist_free(rsc);
 458                 return (TOPO_WALK_NEXT);
 459         }
 460 
 461         (void) nvlist_dup(rsc, &rsc_nvl, NV_UNIQUE_NAME);
 462 
 463         nvlist_free(rsc);
 464         return (TOPO_WALK_TERMINATE);   /* if no space, give up */
 465 }
 466 
 467 nvlist_t *
 468 cmd_find_cpu_rsc_by_sn(fmd_hdl_t *hdl, cpuid_t *cpuid)
 469 {
 470         topo_hdl_t *thp;
 471         topo_walk_t *twp;
 472         int err;
 473 
 474         rsc_nvl = NULL;
 475         if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL)
 476                 return (NULL);
 477         if ((twp = topo_walk_init(thp, FM_FMRI_SCHEME_HC,
 478             find_cpu_rsc_by_sn, cpuid, &err)) == NULL) {
 479                 fmd_hdl_topo_rele(hdl, thp);
 480                 return (NULL);
 481         }
 482         (void) topo_walk_step(twp, TOPO_WALK_CHILD);
 483         topo_walk_fini(twp);
 484         fmd_hdl_topo_rele(hdl, thp);
 485         return (rsc_nvl);
 486 }
 487 
 488 nvlist_t *
 489 get_cpu_fault_resource(fmd_hdl_t *hdl, nvlist_t *asru)
 490 {
 491         uint32_t cpu;
 492         uint64_t serint;
 493         char serial[64];
 494         nvlist_t *rsc = NULL;
 495         cpuid_t cpuid;
 496         char strid[10];
 497 
 498         if (nvlist_lookup_uint64(asru, FM_FMRI_CPU_SERIAL_ID, &serint) != 0 ||
 499             nvlist_lookup_uint32(asru, FM_FMRI_CPU_ID, &cpu) != 0)
 500                 return (rsc);
 501 
 502         (void) snprintf(serial, sizeof (serial), "%llx", serint);
 503         (void) snprintf(strid, sizeof (strid), "%d", cpu);
 504 
 505         (void) strcpy(cpuid.serial, serial);
 506         (void) strcpy(cpuid.id, strid);
 507 
 508         rsc = cmd_find_cpu_rsc_by_sn(hdl, &cpuid);
 509         return (rsc);
 510 }
 511 
 512 /*ARGSUSED*/
 513 static int
 514 find_mem_rsc_hc(topo_hdl_t *thp, tnode_t *node, void *arg)
 515 {
 516         int err;
 517         nvlist_t *rsc;
 518         char *sn;
 519 
 520         if (topo_node_resource(node, &rsc, &err) < 0) {
 521                 return (TOPO_WALK_NEXT);        /* no rsc, try next */
 522         }
 523         if (nvlist_lookup_string(rsc, FM_FMRI_HC_SERIAL_ID, &sn) != 0) {
 524                 nvlist_free(rsc);
 525                 return (TOPO_WALK_NEXT);
 526         }
 527         if (strcmp(sn, (char *)arg) != 0) {
 528                 nvlist_free(rsc);
 529                 return (TOPO_WALK_NEXT);
 530         }
 531         (void) nvlist_dup(rsc, &rsc_nvl, NV_UNIQUE_NAME);
 532         nvlist_free(rsc);
 533         return (TOPO_WALK_TERMINATE);   /* if no space, give up */
 534 }
 535 
 536 nvlist_t *
 537 cmd_find_mem_rsc_by_sn(fmd_hdl_t *hdl, char *sn)
 538 {
 539         topo_hdl_t *thp;
 540         topo_walk_t *twp;
 541         int err;
 542 
 543         rsc_nvl = NULL;
 544 
 545         if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL)
 546                 return (NULL);
 547         if ((twp = topo_walk_init(thp, FM_FMRI_SCHEME_HC,
 548             find_mem_rsc_hc, sn, &err)) == NULL) {
 549                 fmd_hdl_topo_rele(hdl, thp);
 550                 return (NULL);
 551         }
 552         (void) topo_walk_step(twp, TOPO_WALK_CHILD);
 553         topo_walk_fini(twp);
 554         fmd_hdl_topo_rele(hdl, thp);
 555         return (rsc_nvl);
 556 }
 557 
 558 nvlist_t *
 559 get_mem_fault_resource(fmd_hdl_t *hdl, nvlist_t *fru)
 560 {
 561         char *sn;
 562         uint_t n;
 563         char **snarray;
 564 
 565         if (nvlist_lookup_string(fru, FM_FMRI_HC_SERIAL_ID, &sn) == 0)
 566                 return (cmd_find_mem_rsc_by_sn(hdl, sn));
 567 
 568         /*
 569          * T1 platform fru is in mem scheme
 570          */
 571         if (nvlist_lookup_string_array(fru, FM_FMRI_MEM_SERIAL_ID,
 572             &snarray, &n) == 0)
 573                 return (cmd_find_mem_rsc_by_sn(hdl, snarray[0]));
 574 
 575         return (NULL);
 576 }
 577 
 578 int
 579 is_T1_platform(nvlist_t *asru)
 580 {
 581         char *unum;
 582         if (nvlist_lookup_string(asru, FM_FMRI_MEM_UNUM, &unum) == 0) {
 583                 if (strstr(unum, "BR") == NULL)
 584                         return (1);
 585         }
 586         return (0);
 587 }
 588 
 589 nvlist_t *
 590 cmd_nvl_create_fault(fmd_hdl_t *hdl, const char *class, uint8_t cert,
 591     nvlist_t *asru, nvlist_t *fru, nvlist_t *rsrc)
 592 {
 593         nvlist_t *fllist;
 594         uint64_t offset, phyaddr;
 595         nvlist_t *hsp = NULL;
 596 
 597         rsrc = NULL;
 598         (void) nvlist_add_nvlist(fru, FM_FMRI_AUTHORITY,
 599             cmd.cmd_auth); /* not an error if this fails */
 600 
 601         if (strstr(class, "fault.memory.") != NULL) {
 602                 /*
 603                  * For T1 platform fault.memory.bank and fault.memory.dimm,
 604                  * do not issue the hc schmem for resource and fru
 605                  */
 606                 if (is_T1_platform(asru) && (strstr(class, ".page") == NULL)) {
 607                         fllist = fmd_nvl_create_fault(hdl, class, cert, asru,
 608                             fru, fru);
 609                         return (fllist);
 610                 }
 611 
 612                 rsrc = get_mem_fault_resource(hdl, fru);
 613                 /*
 614                  * Need to append the phyaddr & offset into the
 615                  * hc-specific of the fault.memory.page resource
 616                  */
 617                 if ((rsrc != NULL) && strstr(class, ".page") != NULL) {
 618                         if (nvlist_alloc(&hsp, NV_UNIQUE_NAME, 0) == 0) {
 619                                 if (nvlist_lookup_uint64(asru,
 620                                     FM_FMRI_MEM_PHYSADDR, &phyaddr) == 0)
 621                                         (void) (nvlist_add_uint64(hsp,
 622                                             FM_FMRI_MEM_PHYSADDR,
 623                                             phyaddr));
 624 
 625                                 if (nvlist_lookup_uint64(asru,
 626                                     FM_FMRI_MEM_OFFSET, &offset) == 0)
 627                                         (void) nvlist_add_uint64(hsp,
 628                                             FM_FMRI_HC_SPECIFIC_OFFSET, offset);
 629 
 630                                 (void) nvlist_add_nvlist(rsrc,
 631                                     FM_FMRI_HC_SPECIFIC, hsp);
 632                         }
 633                 }
 634                 fllist = fmd_nvl_create_fault(hdl, class, cert, asru,
 635                     fru, rsrc);
 636                 nvlist_free(hsp);
 637         } else {
 638                 rsrc = get_cpu_fault_resource(hdl, asru);
 639                 fllist = fmd_nvl_create_fault(hdl, class, cert, asru,
 640                     fru, rsrc);
 641         }
 642 
 643         nvlist_free(rsrc);
 644 
 645         return (fllist);
 646 }