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 #include <cmd_mem.h> 27 #include <cmd_branch.h> 28 #include <cmd_dimm.h> 29 #include <cmd.h> 30 #include <cmd_hc_sun4v.h> 31 32 #include <errno.h> 33 #include <string.h> 34 #include <strings.h> 35 #include <fcntl.h> 36 #include <unistd.h> 37 #include <fm/fmd_api.h> 38 #include <fm/libtopo.h> 39 #include <sys/fm/protocol.h> 40 #include <sys/mem.h> 41 #include <sys/nvpair.h> 42 43 #define BUF_SIZE 120 44 #define LEN_CMP 6 45 46 /* 47 * mbd_label: If a DIMM associated with this branch is located on a memory 48 * expansion board or riser board, return (pointer to) the label of that board; 49 * otherwise return NULL. 50 * We assume that there will be at most one such board for any branch. 51 */ 52 53 char * 54 mbd_label(fmd_hdl_t *hdl, cmd_branch_t *branch, const char *nacname) 55 { 56 cmd_dimm_t *dimm; 57 cmd_branch_memb_t *bm; 58 char *p; 59 size_t s; 60 61 for (bm = cmd_list_next(&branch->branch_dimms); bm != NULL; 62 bm = cmd_list_next(bm)) { 63 dimm = bm->dimm; 64 if ((p = strstr(dimm->dimm_unum, nacname)) != NULL) { 65 p = strchr(p, '/'); /* include instance number */ 66 s = p - dimm->dimm_unum; 67 p = fmd_hdl_zalloc(hdl, s+1, FMD_SLEEP); 68 (void) strncpy(p, dimm->dimm_unum, s); 69 *(p + s) = '\0'; 70 return (p); 71 } 72 } 73 return (NULL); 74 } 75 76 void 77 cmd_branch_add_dimm(fmd_hdl_t *hdl, cmd_branch_t *branch, cmd_dimm_t *dimm) 78 { 79 cmd_branch_memb_t *bm; 80 81 if (dimm == NULL) 82 return; 83 84 fmd_hdl_debug(hdl, "Attaching dimm %s to branch %s\n", 85 dimm->dimm_unum, branch->branch_unum); 86 bm = fmd_hdl_zalloc(hdl, sizeof (cmd_branch_memb_t), FMD_SLEEP); 87 bm->dimm = dimm; 88 cmd_list_append(&branch->branch_dimms, bm); 89 } 90 91 void 92 cmd_branch_remove_dimm(fmd_hdl_t *hdl, cmd_branch_t *branch, cmd_dimm_t *dimm) 93 { 94 cmd_branch_memb_t *bm; 95 96 fmd_hdl_debug(hdl, "Detaching dimm %s from branch %s\n", 97 dimm->dimm_unum, branch->branch_unum); 98 99 for (bm = cmd_list_next(&branch->branch_dimms); bm != NULL; 100 bm = cmd_list_next(bm)) { 101 if (bm->dimm == dimm) { 102 cmd_list_delete(&branch->branch_dimms, bm); 103 fmd_hdl_free(hdl, bm, sizeof (cmd_branch_memb_t)); 104 return; 105 } 106 } 107 108 fmd_hdl_abort(hdl, 109 "Attempt to disconnect dimm from non-parent branch\n"); 110 } 111 112 static cmd_dimm_t * 113 branch_dimm_create(fmd_hdl_t *hdl, char *dimm_unum, char **serids, 114 size_t nserids) 115 { 116 nvlist_t *fmri; 117 cmd_dimm_t *dimm; 118 119 fmri = cmd_mem_fmri_create(dimm_unum, serids, nserids); 120 121 if (fmri != NULL && (fmd_nvl_fmri_expand(hdl, fmri) == 0)) { 122 dimm = cmd_dimm_create(hdl, fmri); 123 if (dimm != NULL) { 124 nvlist_free(fmri); 125 return (dimm); 126 } 127 } 128 129 nvlist_free(fmri); 130 return (NULL); 131 } 132 133 static fmd_hdl_t *br_hdl; /* for use by callbacks */ 134 static int br_dimmcount; 135 static nvlist_t *br_memb_nvl; 136 137 /*ARGSUSED*/ 138 static int 139 branch_dimm_cb(topo_hdl_t *thp, tnode_t *node, void *arg) 140 { 141 char *lbl, *p, *q; 142 char cx[BUF_SIZE], cy[BUF_SIZE]; 143 nvlist_t *rsrc; 144 int err; 145 cmd_branch_t *branch = (cmd_branch_t *)arg; 146 cmd_dimm_t *dimm; 147 size_t nserids; 148 char **serids; 149 150 if (topo_node_resource(node, &rsrc, &err) < 0) 151 return (TOPO_WALK_NEXT); /* no label, try next */ 152 153 if ((nvlist_lookup_string(rsrc, FM_FMRI_MEM_UNUM, &lbl) != 0) || 154 (nvlist_lookup_string_array(rsrc, FM_FMRI_MEM_SERIAL_ID, 155 &serids, &nserids) != 0)) { 156 nvlist_free(rsrc); 157 return (TOPO_WALK_NEXT); 158 } 159 160 /* 161 * Massage the unum of the candidate DIMM as follows: 162 * a) remove any trailing J number. Use result for cmd_dimm_t. 163 * b) for branch membership purposes only, remove reference to 164 * a riser card (MR%d) if one exists. 165 */ 166 if ((p = strstr(lbl, "/J")) != NULL) { 167 (void) strncpy(cx, lbl, p - lbl); 168 cx[p - lbl] = '\0'; 169 } else { 170 (void) strcpy(cx, lbl); 171 } 172 (void) strcpy(cy, cx); 173 if ((p = strstr(cy, "/MR")) != NULL) { 174 if ((q = strchr(p + 1, '/')) != NULL) 175 (void) strcpy(p, q); 176 else 177 *p = '\0'; 178 } 179 180 /* 181 * For benefit of Batoka-like platforms, start comparison with 182 * "CMP", so that any leading "MEM" or "CPU" makes no difference. 183 */ 184 185 p = strstr(branch->branch_unum, "CMP"); 186 q = strstr(cy, "CMP"); 187 188 if ((p != NULL) && (q != NULL) && strncmp(p, q, strlen(p)) == 0) { 189 dimm = branch_dimm_create(br_hdl, cx, serids, nserids); 190 if (dimm != NULL) 191 cmd_branch_add_dimm(br_hdl, branch, dimm); 192 } 193 nvlist_free(rsrc); 194 return (TOPO_WALK_NEXT); 195 } 196 197 198 /* 199 * The cmd_dimm_t structure created for a DIMM in a branch never has a 200 * Jxxx in its unum; the cmd_dimm_t structure created for a DIMM containing 201 * a page, or in a bank (i.e. for ECC errors)-always-has a Jxxx in its 202 * unum. Therefore the set of cmd_dimm_t's created for a branch is always 203 * disjoint from the set of cmd_dimm_t's created for pages and/or banks, so 204 * the cmd_dimm_create will never link a 'branch' cmd_dimm_t into bank. 205 * Faulting a DIMM for ECC will not prevent subsequent faulting of "same" 206 * dimm for FBR/FBU and vice versa 207 */ 208 static int 209 branch_dimmlist_create(fmd_hdl_t *hdl, cmd_branch_t *branch) 210 { 211 topo_hdl_t *thp; 212 topo_walk_t *twp; 213 int err, dimm_count; 214 cmd_list_t *bp; 215 216 if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL) 217 return (0); 218 if ((twp = topo_walk_init(thp, 219 FM_FMRI_SCHEME_MEM, branch_dimm_cb, branch, &err)) 220 == NULL) { 221 fmd_hdl_topo_rele(hdl, thp); 222 return (0); 223 } 224 br_hdl = hdl; 225 (void) topo_walk_step(twp, TOPO_WALK_CHILD); 226 topo_walk_fini(twp); 227 fmd_hdl_topo_rele(hdl, thp); 228 229 for (dimm_count = 0, bp = cmd_list_next(&branch->branch_dimms); 230 bp != NULL; bp = cmd_list_next(bp), dimm_count++) 231 ; 232 return (dimm_count); 233 } 234 235 /*ARGSUSED*/ 236 static int 237 fru_by_label_cb(topo_hdl_t *thp, tnode_t *node, void *arg) 238 { 239 char *lbl; 240 int err; 241 char *target = (char *)arg; 242 243 if (topo_node_label(node, &lbl, &err) < 0) 244 return (TOPO_WALK_NEXT); /* no label, try next */ 245 246 if ((strcmp(target, lbl) == 0) && 247 (topo_node_fru(node, &br_memb_nvl, NULL, &err) == 0)) { 248 topo_hdl_strfree(thp, lbl); 249 return (TOPO_WALK_TERMINATE); 250 } 251 topo_hdl_strfree(thp, lbl); 252 return (TOPO_WALK_NEXT); 253 } 254 255 static nvlist_t * 256 fru_by_label(fmd_hdl_t *hdl, const char *target) 257 { 258 topo_hdl_t *thp; 259 topo_walk_t *twp; 260 int err; 261 262 br_memb_nvl = NULL; 263 if (((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) != NULL) && 264 ((twp = topo_walk_init(thp, FM_FMRI_SCHEME_HC, 265 fru_by_label_cb, (void *)target, &err)) != NULL)) { 266 br_hdl = hdl; 267 (void) topo_walk_step(twp, TOPO_WALK_CHILD); 268 topo_walk_fini(twp); 269 } 270 fmd_hdl_topo_rele(hdl, thp); 271 return (br_memb_nvl); 272 } 273 274 static void 275 add_bdflt_to_case(fmd_hdl_t *hdl, char *label, const char *fltnm, 276 uint8_t board_cert, fmd_case_t *cp) 277 { 278 nvlist_t *memb_nvl, *flt; 279 280 memb_nvl = fru_by_label(hdl, label); 281 if (memb_nvl != NULL) { 282 flt = cmd_nvl_create_fault(hdl, fltnm, board_cert, 283 memb_nvl, memb_nvl, NULL); 284 flt = cmd_fault_add_location(hdl, flt, label); 285 if (flt != NULL) { 286 fmd_case_add_suspect(hdl, cp, flt); 287 } 288 nvlist_free(memb_nvl); 289 } 290 } 291 292 /* 293 * For t5440, the memory channel goes like this: 294 * VF -> cpuboard -> D0 -> motherboard -> memboard -> D[1..3] 295 * If there is a dimm on the memory board, the memory board, 296 * motherboard, cpuboard, and dimms are in the suspect list. 297 * If there is no dimm on the memory board, the cpu board and 298 * the dimms are in the suspect list 299 * The board certainty = total board certainty / number of 300 * the faulty boards in the suspect list. 301 */ 302 void 303 cmd_branch_create_fault(fmd_hdl_t *hdl, cmd_branch_t *branch, 304 const char *fltnm, nvlist_t *asru) 305 { 306 nvlist_t *flt; 307 cmd_branch_memb_t *bm; 308 cmd_dimm_t *dimm; 309 int dimm_count = 0; 310 uint_t cert = 0; 311 uint_t board_cert = 0; 312 char *fruloc = NULL, *membd_label; 313 314 /* attach the dimms to the branch */ 315 dimm_count = branch_dimmlist_create(hdl, branch); 316 317 if ((membd_label = mbd_label(hdl, branch, "MEM")) != NULL) { 318 board_cert = CMD_BOARDS_CERT / 3; /* CPU, MEM, MB */ 319 320 /* 321 * Batoka with memory expansion. CPU expansion board will 322 * be added below. Add memory expansion board and motherboard 323 * FRUs here. 324 */ 325 326 add_bdflt_to_case(hdl, membd_label, fltnm, board_cert, 327 branch->branch_case.cc_cp); 328 fmd_hdl_strfree(hdl, membd_label); 329 add_bdflt_to_case(hdl, "MB", fltnm, board_cert, 330 branch->branch_case.cc_cp); 331 332 } else if ((membd_label = mbd_label(hdl, branch, "MR")) != NULL) { 333 334 board_cert = CMD_BOARDS_CERT / 2; /* MB, MR */ 335 336 /* 337 * Maramba or similar platform with mezzanine board. 338 * Motherboard FRU will be added below. Add the mezzanine 339 * board here. 340 */ 341 342 add_bdflt_to_case(hdl, membd_label, fltnm, board_cert, 343 branch->branch_case.cc_cp); 344 fmd_hdl_strfree(hdl, membd_label); 345 } else { 346 board_cert = CMD_BOARDS_CERT; /* only MB or CPU */ 347 } 348 349 /* 350 * The code which follows adds to the suspect list the FRU which 351 * contains the ereport 'detector'. This can be either a CPU 352 * expansion board (Batoka), or motherboard (Huron, Maramba, or 353 * derivative). 354 */ 355 356 fruloc = cmd_getfru_loc(hdl, asru); 357 flt = cmd_boardfru_create_fault(hdl, asru, fltnm, board_cert, fruloc); 358 if (flt != NULL) 359 fmd_case_add_suspect(hdl, branch->branch_case.cc_cp, flt); 360 361 if (dimm_count != 0) 362 cert = (100 - CMD_BOARDS_CERT) / dimm_count; 363 364 /* create dimm faults */ 365 for (bm = cmd_list_next(&branch->branch_dimms); bm != NULL; 366 bm = cmd_list_next(bm)) { 367 dimm = bm->dimm; 368 if (dimm != NULL) { 369 dimm->dimm_flags |= CMD_MEM_F_FAULTING; 370 cmd_dimm_dirty(hdl, dimm); 371 flt = cmd_dimm_create_fault(hdl, dimm, fltnm, cert); 372 fmd_case_add_suspect(hdl, branch->branch_case.cc_cp, 373 flt); 374 } 375 } 376 if (fruloc != NULL) 377 fmd_hdl_strfree(hdl, fruloc); 378 } 379 380 cmd_branch_t * 381 cmd_branch_create(fmd_hdl_t *hdl, nvlist_t *asru) 382 { 383 cmd_branch_t *branch; 384 const char *b_unum; 385 386 if ((b_unum = cmd_fmri_get_unum(asru)) == NULL) { 387 CMD_STAT_BUMP(bad_mem_asru); 388 return (NULL); 389 } 390 391 fmd_hdl_debug(hdl, "branch_create: creating new branch %s\n", b_unum); 392 CMD_STAT_BUMP(branch_creat); 393 394 branch = fmd_hdl_zalloc(hdl, sizeof (cmd_branch_t), FMD_SLEEP); 395 branch->branch_nodetype = CMD_NT_BRANCH; 396 branch->branch_version = CMD_BRANCH_VERSION; 397 398 cmd_bufname(branch->branch_bufname, sizeof (branch->branch_bufname), 399 "branch_%s", b_unum); 400 cmd_fmri_init(hdl, &branch->branch_asru, asru, "branch_asru_%s", 401 b_unum); 402 403 (void) nvlist_lookup_string(branch->branch_asru_nvl, FM_FMRI_MEM_UNUM, 404 (char **)&branch->branch_unum); 405 406 cmd_list_append(&cmd.cmd_branches, branch); 407 cmd_branch_dirty(hdl, branch); 408 409 return (branch); 410 } 411 412 cmd_branch_t * 413 cmd_branch_lookup_by_unum(fmd_hdl_t *hdl, const char *unum) 414 { 415 cmd_branch_t *branch; 416 417 fmd_hdl_debug(hdl, "branch_lookup: dimm_unum %s", unum); 418 /* 419 * fbr/fbu unum dimm does not have a J number 420 */ 421 if (strstr(unum, "J") != NULL) 422 return (NULL); 423 424 for (branch = cmd_list_next(&cmd.cmd_branches); branch != NULL; 425 branch = cmd_list_next(branch)) { 426 if (strcmp(branch->branch_unum, unum) == 0) 427 return (branch); 428 } 429 430 fmd_hdl_debug(hdl, "branch_lookup_by_unum: no branch is found\n"); 431 return (NULL); 432 } 433 434 cmd_branch_t * 435 cmd_branch_lookup(fmd_hdl_t *hdl, nvlist_t *asru) 436 { 437 cmd_branch_t *branch; 438 const char *unum; 439 440 if ((unum = cmd_fmri_get_unum(asru)) == NULL) { 441 CMD_STAT_BUMP(bad_mem_asru); 442 return (NULL); 443 } 444 445 for (branch = cmd_list_next(&cmd.cmd_branches); branch != NULL; 446 branch = cmd_list_next(branch)) { 447 if (strcmp(branch->branch_unum, unum) == 0) 448 return (branch); 449 } 450 451 fmd_hdl_debug(hdl, "cmd_branch_lookup: discarding old \n"); 452 return (NULL); 453 } 454 455 static cmd_branch_t * 456 branch_wrapv0(fmd_hdl_t *hdl, cmd_branch_pers_t *pers, size_t psz) 457 { 458 cmd_branch_t *branch; 459 460 if (psz != sizeof (cmd_branch_pers_t)) { 461 fmd_hdl_abort(hdl, "size of state doesn't match size of " 462 "version 0 state (%u bytes).\n", 463 sizeof (cmd_branch_pers_t)); 464 } 465 466 branch = fmd_hdl_zalloc(hdl, sizeof (cmd_branch_t), FMD_SLEEP); 467 bcopy(pers, branch, sizeof (cmd_branch_pers_t)); 468 fmd_hdl_free(hdl, pers, psz); 469 return (branch); 470 } 471 472 void * 473 cmd_branch_restore(fmd_hdl_t *hdl, fmd_case_t *cp, cmd_case_ptr_t *ptr) 474 { 475 cmd_branch_t *branch; 476 size_t branchsz; 477 478 479 for (branch = cmd_list_next(&cmd.cmd_branches); branch != NULL; 480 branch = cmd_list_next(branch)) { 481 if (strcmp(branch->branch_bufname, ptr->ptr_name) == 0) 482 break; 483 } 484 485 if (branch == NULL) { 486 fmd_hdl_debug(hdl, "restoring branch from %s\n", ptr->ptr_name); 487 488 if ((branchsz = fmd_buf_size(hdl, NULL, ptr->ptr_name)) == 0) { 489 fmd_hdl_abort(hdl, "branch referenced by case %s does " 490 "not exist in saved state\n", 491 fmd_case_uuid(hdl, cp)); 492 } else if (branchsz > CMD_BRANCH_MAXSIZE || 493 branchsz < CMD_BRANCH_MINSIZE) { 494 fmd_hdl_abort(hdl, 495 "branch buffer referenced by case %s " 496 "is out of bounds (is %u bytes, max %u, min %u)\n", 497 fmd_case_uuid(hdl, cp), branchsz, 498 CMD_BRANCH_MAXSIZE, CMD_BRANCH_MINSIZE); 499 } 500 501 if ((branch = cmd_buf_read(hdl, NULL, ptr->ptr_name, 502 branchsz)) == NULL) { 503 fmd_hdl_abort(hdl, "failed to read branch buf %s", 504 ptr->ptr_name); 505 } 506 507 fmd_hdl_debug(hdl, "found %d in version field\n", 508 branch->branch_version); 509 510 switch (branch->branch_version) { 511 case CMD_BRANCH_VERSION_0: 512 branch = branch_wrapv0(hdl, 513 (cmd_branch_pers_t *)branch, branchsz); 514 break; 515 default: 516 fmd_hdl_abort(hdl, "unknown version (found %d) " 517 "for branch state referenced by case %s.\n", 518 branch->branch_version, fmd_case_uuid(hdl, 519 cp)); 520 break; 521 } 522 523 cmd_fmri_restore(hdl, &branch->branch_asru); 524 525 if ((errno = nvlist_lookup_string(branch->branch_asru_nvl, 526 FM_FMRI_MEM_UNUM, (char **)&branch->branch_unum)) != 0) 527 fmd_hdl_abort(hdl, "failed to retrieve unum from asru"); 528 529 530 cmd_list_append(&cmd.cmd_branches, branch); 531 } 532 533 switch (ptr->ptr_subtype) { 534 case CMD_PTR_BRANCH_CASE: 535 cmd_mem_case_restore(hdl, &branch->branch_case, cp, "branch", 536 branch->branch_unum); 537 break; 538 default: 539 fmd_hdl_abort(hdl, "invalid %s subtype %d\n", 540 ptr->ptr_name, ptr->ptr_subtype); 541 } 542 543 return (branch); 544 } 545 546 void 547 cmd_branch_dirty(fmd_hdl_t *hdl, cmd_branch_t *branch) 548 { 549 if (fmd_buf_size(hdl, NULL, branch->branch_bufname) != 550 sizeof (cmd_branch_pers_t)) 551 fmd_buf_destroy(hdl, NULL, branch->branch_bufname); 552 553 /* No need to rewrite the FMRIs in the branch - they don't change */ 554 fmd_buf_write(hdl, NULL, branch->branch_bufname, &branch->branch_pers, 555 sizeof (cmd_branch_pers_t)); 556 } 557 558 static void 559 branch_dimmlist_free(fmd_hdl_t *hdl, cmd_branch_t *branch) 560 { 561 cmd_branch_memb_t *bm; 562 563 while ((bm = cmd_list_next(&branch->branch_dimms)) != NULL) { 564 cmd_list_delete(&branch->branch_dimms, bm); 565 fmd_hdl_free(hdl, bm, sizeof (cmd_branch_memb_t)); 566 } 567 } 568 569 static void 570 branch_free(fmd_hdl_t *hdl, cmd_branch_t *branch, int destroy) 571 { 572 fmd_hdl_debug(hdl, "Free branch %s\n", branch->branch_unum); 573 if (branch->branch_case.cc_cp != NULL) { 574 if (destroy) { 575 if (branch->branch_case.cc_serdnm != NULL) { 576 fmd_serd_destroy(hdl, 577 branch->branch_case.cc_serdnm); 578 fmd_hdl_strfree(hdl, 579 branch->branch_case.cc_serdnm); 580 branch->branch_case.cc_serdnm = NULL; 581 } 582 } 583 cmd_case_fini(hdl, branch->branch_case.cc_cp, destroy); 584 } 585 586 branch_dimmlist_free(hdl, branch); 587 cmd_fmri_fini(hdl, &branch->branch_asru, destroy); 588 589 if (destroy) 590 fmd_buf_destroy(hdl, NULL, branch->branch_bufname); 591 cmd_list_delete(&cmd.cmd_branches, branch); 592 fmd_hdl_free(hdl, branch, sizeof (cmd_branch_t)); 593 } 594 595 void 596 cmd_branch_destroy(fmd_hdl_t *hdl, cmd_branch_t *branch) 597 { 598 branch_free(hdl, branch, FMD_B_TRUE); 599 } 600 601 /*ARGSUSED*/ 602 static int 603 branch_exist_cb(topo_hdl_t *thp, tnode_t *node, void *arg) 604 { 605 char *lbl, *p, *q; 606 char cy[BUF_SIZE]; 607 nvlist_t *rsrc; 608 int err; 609 610 cmd_branch_t *branch = (cmd_branch_t *)arg; 611 612 if (topo_node_resource(node, &rsrc, &err) < 0) 613 return (TOPO_WALK_NEXT); /* no label, try next */ 614 615 if (nvlist_lookup_string(rsrc, "unum", &lbl) != 0) { 616 nvlist_free(rsrc); 617 return (TOPO_WALK_NEXT); 618 } 619 /* 620 * for branch membership purposes only, remove reference to 621 * a riser card (MR%d) if one exists. 622 */ 623 (void) strcpy(cy, lbl); 624 if ((p = strstr(cy, "/MR")) != NULL) { 625 if ((q = strchr(p + 1, '/')) != NULL) 626 (void) strcpy(p, q); 627 else 628 *p = '\0'; 629 } 630 if (strncmp(branch->branch_unum, cy, 631 strlen(branch->branch_unum)) == 0) { 632 br_dimmcount++; 633 nvlist_free(rsrc); 634 return (TOPO_WALK_TERMINATE); 635 } 636 nvlist_free(rsrc); 637 return (TOPO_WALK_NEXT); 638 } 639 640 static int 641 branch_exist(fmd_hdl_t *hdl, cmd_branch_t *branch) 642 { 643 topo_hdl_t *thp; 644 topo_walk_t *twp; 645 int err; 646 647 if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL) 648 return (0); 649 if ((twp = topo_walk_init(thp, 650 FM_FMRI_SCHEME_MEM, branch_exist_cb, branch, &err)) 651 == NULL) { 652 fmd_hdl_topo_rele(hdl, thp); 653 return (0); 654 } 655 br_dimmcount = 0; 656 (void) topo_walk_step(twp, TOPO_WALK_CHILD); 657 topo_walk_fini(twp); 658 fmd_hdl_topo_rele(hdl, thp); 659 660 return (br_dimmcount); 661 } 662 663 /* 664 * If the case has been solved, don't need to check the dimmlist 665 * If the case has not been solved, the branch is valid if there is least one 666 * existing dimm in the branch 667 */ 668 void 669 cmd_branch_validate(fmd_hdl_t *hdl) 670 { 671 cmd_branch_t *branch, *next; 672 673 fmd_hdl_debug(hdl, "cmd_branch_validate\n"); 674 675 for (branch = cmd_list_next(&cmd.cmd_branches); branch != NULL; 676 branch = next) { 677 next = cmd_list_next(branch); 678 if (branch->branch_case.cc_cp != NULL && 679 fmd_case_solved(hdl, branch->branch_case.cc_cp)) 680 continue; 681 if (branch_exist(hdl, branch)) 682 continue; 683 cmd_branch_destroy(hdl, branch); 684 } 685 } 686 687 void 688 cmd_branch_gc(fmd_hdl_t *hdl) 689 { 690 fmd_hdl_debug(hdl, "cmd_branch_gc\n"); 691 cmd_branch_validate(hdl); 692 } 693 694 void 695 cmd_branch_fini(fmd_hdl_t *hdl) 696 { 697 cmd_branch_t *branch; 698 fmd_hdl_debug(hdl, "cmd_branch_fini\n"); 699 700 while ((branch = cmd_list_next(&cmd.cmd_branches)) != NULL) 701 branch_free(hdl, branch, FMD_B_FALSE); 702 } 703