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 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Support function for the i86pc chip enumerator 29 */ 30 31 #include <sys/types.h> 32 #include <stdarg.h> 33 #include <strings.h> 34 #include <fm/fmd_fmri.h> 35 #include <sys/systeminfo.h> 36 #include <sys/fm/protocol.h> 37 #include <fm/topo_mod.h> 38 #include <fm/fmd_agent.h> 39 40 #include "chip.h" 41 42 static void fmri_dprint(topo_mod_t *, const char *, uint32_t, nvlist_t *); 43 static boolean_t is_page_fmri(nvlist_t *); 44 45 /* 46 * Whinge a debug message via topo_mod_dprintf and increment the 47 * given error counter. 48 */ 49 void 50 whinge(topo_mod_t *mod, int *nerr, const char *fmt, ...) 51 { 52 va_list ap; 53 char buf[160]; 54 55 if (nerr != NULL) 56 ++*nerr; 57 58 va_start(ap, fmt); 59 (void) vsnprintf(buf, sizeof (buf), fmt, ap); 60 va_end(ap); 61 62 topo_mod_dprintf(mod, "%s", buf); 63 } 64 65 /* 66 * Given an nvpair of a limited number of data types, extract the property 67 * name and value and add that combination to the given node in the 68 * specified property group using the corresponding topo_prop_set_* function 69 * for the data type. Return 1 on success, otherwise 0. 70 */ 71 int 72 nvprop_add(topo_mod_t *mod, nvpair_t *nvp, const char *pgname, tnode_t *node) 73 { 74 int success = 0; 75 int err; 76 char *pname = nvpair_name(nvp); 77 78 switch (nvpair_type(nvp)) { 79 case DATA_TYPE_BOOLEAN_VALUE: { 80 boolean_t val; 81 82 if (nvpair_value_boolean_value(nvp, &val) == 0 && 83 topo_prop_set_string(node, pgname, pname, 84 TOPO_PROP_IMMUTABLE, val ? "true" : "false", &err) == 0) 85 success = 1; 86 break; 87 } 88 89 case DATA_TYPE_UINT32: { 90 uint32_t val; 91 92 if (nvpair_value_uint32(nvp, &val) == 0 && 93 topo_prop_set_uint32(node, pgname, pname, 94 TOPO_PROP_IMMUTABLE, val, &err) == 0) 95 success = 1; 96 break; 97 } 98 99 case DATA_TYPE_UINT64: { 100 uint64_t val; 101 102 if (nvpair_value_uint64(nvp, &val) == 0 && 103 topo_prop_set_uint64(node, pgname, pname, 104 TOPO_PROP_IMMUTABLE, val, &err) == 0) 105 success = 1; 106 break; 107 } 108 109 case DATA_TYPE_UINT32_ARRAY: { 110 uint32_t *arrp; 111 uint_t nelem; 112 113 if (nvpair_value_uint32_array(nvp, &arrp, &nelem) == 0 && 114 nelem > 0 && topo_prop_set_uint32_array(node, pgname, pname, 115 TOPO_PROP_IMMUTABLE, arrp, nelem, &err) == 0) 116 success = 1; 117 break; 118 } 119 120 case DATA_TYPE_STRING: { 121 char *str; 122 123 if (nvpair_value_string(nvp, &str) == 0 && 124 topo_prop_set_string(node, pgname, pname, 125 TOPO_PROP_IMMUTABLE, str, &err) == 0) 126 success = 1; 127 break; 128 } 129 130 default: 131 whinge(mod, &err, "nvprop_add: Can't handle type %d for " 132 "'%s' in property group %s of %s node\n", 133 nvpair_type(nvp), pname, pgname, topo_node_name(node)); 134 break; 135 } 136 137 return (success ? 0 : 1); 138 } 139 140 /* 141 * Lookup string data named pname in the given nvlist and add that 142 * as property named pname in the given property group pgname on the indicated 143 * topo node. Fill pvalp with a pointer to the string value, valid until 144 * nvlist_free is called. 145 */ 146 int 147 add_nvlist_strprop(topo_mod_t *mod, tnode_t *node, nvlist_t *nvl, 148 const char *pgname, const char *pname, const char **pvalp) 149 { 150 char *pval; 151 int err = 0; 152 153 if (nvlist_lookup_string(nvl, pname, &pval) != 0) 154 return (-1); 155 156 if (topo_prop_set_string(node, pgname, pname, 157 TOPO_PROP_IMMUTABLE, pval, &err) == 0) { 158 if (pvalp) 159 *pvalp = pval; 160 return (0); 161 } else { 162 whinge(mod, &err, "add_nvlist_strprop: failed to add '%s'\n", 163 pname); 164 return (-1); 165 } 166 } 167 168 /* 169 * Lookup an int32 item named pname in the given nvlist and add that 170 * as property named pname in the given property group pgname on the indicated 171 * topo node. Fill pvalp with the property value. 172 */ 173 int 174 add_nvlist_longprop(topo_mod_t *mod, tnode_t *node, nvlist_t *nvl, 175 const char *pgname, const char *pname, int32_t *pvalp) 176 { 177 int32_t pval; 178 int err; 179 180 if ((nvlist_lookup_int32(nvl, pname, &pval)) != 0) 181 return (-1); 182 183 if (topo_prop_set_int32(node, pgname, pname, 184 TOPO_PROP_IMMUTABLE, pval, &err) == 0) { 185 if (pvalp) 186 *pvalp = pval; 187 return (0); 188 } else { 189 whinge(mod, &err, "add_nvlist_longprop: failed to add '%s'\n", 190 pname); 191 return (-1); 192 } 193 } 194 195 /* 196 * In a given nvlist lookup a variable number of int32 properties named in 197 * const char * varargs and each each in the given property group on the 198 * node. Fill an array of the retrieved values. 199 */ 200 int 201 add_nvlist_longprops(topo_mod_t *mod, tnode_t *node, nvlist_t *nvl, 202 const char *pgname, int32_t *pvalap, ...) 203 { 204 const char *pname; 205 va_list ap; 206 int nerr = 0; 207 208 va_start(ap, pvalap); 209 while ((pname = va_arg(ap, const char *)) != NULL) { 210 if (add_nvlist_longprop(mod, node, nvl, pgname, pname, 211 pvalap) != 0) 212 nerr++; /* have whinged elsewhere */ 213 214 if (pvalap != NULL) 215 ++pvalap; 216 } 217 va_end(ap); 218 219 return (nerr == 0 ? 0 : -1); 220 } 221 222 /* 223 * Construct an hc scheme resource FMRI for a node named name with 224 * instance number inst, parented by the given parent node pnode. 225 */ 226 int 227 mkrsrc(topo_mod_t *mod, tnode_t *pnode, const char *name, int inst, 228 nvlist_t *auth, nvlist_t **nvl) 229 { 230 *nvl = topo_mod_hcfmri(mod, pnode, FM_HC_SCHEME_VERSION, name, 231 inst, NULL, auth, NULL, NULL, NULL); 232 return (nvl != NULL ? 0 : -1); /* caller must free nvlist */ 233 } 234 235 /* 236 * Construct a cpu scheme FMRI with the given data; the caller must free 237 * the allocated nvlist with nvlist_free(). 238 */ 239 nvlist_t * 240 cpu_fmri_create(topo_mod_t *mod, uint32_t cpuid, char *s, uint8_t cpumask) 241 { 242 int err; 243 nvlist_t *asru; 244 245 if (topo_mod_nvalloc(mod, &asru, NV_UNIQUE_NAME) != 0) 246 return (NULL); 247 248 err = nvlist_add_uint8(asru, FM_VERSION, FM_CPU_SCHEME_VERSION); 249 err |= nvlist_add_string(asru, FM_FMRI_SCHEME, FM_FMRI_SCHEME_CPU); 250 err |= nvlist_add_uint32(asru, FM_FMRI_CPU_ID, cpuid); 251 err |= nvlist_add_uint8(asru, FM_FMRI_CPU_MASK, cpumask); 252 if (s != NULL) 253 err |= nvlist_add_string(asru, FM_FMRI_CPU_SERIAL_ID, s); 254 if (err != 0) { 255 nvlist_free(asru); 256 (void) topo_mod_seterrno(mod, EMOD_FMRI_NVL); 257 return (NULL); 258 } 259 260 return (asru); 261 } 262 263 /*ARGSUSED*/ 264 int 265 mem_asru_compute(topo_mod_t *mod, tnode_t *node, topo_version_t version, 266 nvlist_t *in, nvlist_t **out) 267 { 268 nvlist_t *asru, *args, *pargs, *hcsp; 269 int err; 270 uint64_t pa, offset; 271 272 if (strcmp(topo_node_name(node), RANK_NODE_NAME) != 0 && 273 strcmp(topo_node_name(node), DIMM_NODE_NAME) != 0 && 274 strcmp(topo_node_name(node), CS_NODE_NAME) != 0) 275 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 276 277 if (nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args) != 0) 278 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 279 280 if ((err = nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs)) != 0) { 281 if (err == ENOENT) { 282 pargs = args; 283 } else { 284 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 285 } 286 } 287 288 if (topo_mod_nvdup(mod, pargs, &asru) != 0) 289 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 290 291 err = 0; 292 293 /* 294 * if 'in' includes an hc-specific member which specifies asru-physaddr 295 * or asru-offset then rename them to asru and physaddr respectively. 296 */ 297 if (nvlist_lookup_nvlist(asru, FM_FMRI_HC_SPECIFIC, &hcsp) == 0) { 298 if (nvlist_lookup_uint64(hcsp, 299 "asru-"FM_FMRI_HC_SPECIFIC_PHYSADDR, &pa) == 0) { 300 err += nvlist_remove(hcsp, 301 "asru-"FM_FMRI_HC_SPECIFIC_PHYSADDR, 302 DATA_TYPE_UINT64); 303 err += nvlist_add_uint64(hcsp, 304 FM_FMRI_HC_SPECIFIC_PHYSADDR, 305 pa); 306 } 307 308 if (nvlist_lookup_uint64(hcsp, 309 "asru-"FM_FMRI_HC_SPECIFIC_OFFSET, &offset) == 0) { 310 err += nvlist_remove(hcsp, 311 "asru-"FM_FMRI_HC_SPECIFIC_OFFSET, 312 DATA_TYPE_UINT64); 313 err += nvlist_add_uint64(hcsp, 314 FM_FMRI_HC_SPECIFIC_OFFSET, 315 offset); 316 } 317 } 318 319 if (err != 0 || topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) < 0) { 320 nvlist_free(asru); 321 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 322 } 323 324 err = nvlist_add_string(*out, TOPO_PROP_VAL_NAME, TOPO_PROP_ASRU); 325 err |= nvlist_add_uint32(*out, TOPO_PROP_VAL_TYPE, TOPO_TYPE_FMRI); 326 err |= nvlist_add_nvlist(*out, TOPO_PROP_VAL_VAL, asru); 327 if (err != 0) { 328 nvlist_free(asru); 329 nvlist_free(*out); 330 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 331 } 332 333 nvlist_free(asru); 334 335 return (0); 336 } 337 338 static int 339 set_retnvl(topo_mod_t *mod, nvlist_t **out, const char *retname, uint32_t ret) 340 { 341 nvlist_t *nvl; 342 343 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) < 0) 344 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 345 346 if (nvlist_add_uint32(nvl, retname, ret) != 0) { 347 nvlist_free(nvl); 348 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); 349 } 350 351 *out = nvl; 352 return (0); 353 } 354 355 /* 356 * If we're getting called then the question of whether this dimm is plugged 357 * in has already been answered. What we don't know for sure is whether it's 358 * the same dimm or a different one plugged in the same slot. To check, we 359 * try and compare the serial numbers on the dimm in the current topology with 360 * the serial num from the unum fmri that got passed into this function as the 361 * argument. 362 * 363 */ 364 static int 365 fmri_replaced(topo_mod_t *mod, tnode_t *node, nvlist_t *unum, int *errp) 366 { 367 tnode_t *dimmnode; 368 int rc, err; 369 char *old_serial, *curr_serial; 370 fmd_agent_hdl_t *hdl; 371 372 /* 373 * If input is a page, return "replaced" if the offset is invalid. 374 */ 375 if (is_page_fmri(unum) && 376 (hdl = fmd_agent_open(FMD_AGENT_VERSION)) != NULL) { 377 rc = fmd_agent_page_isretired(hdl, unum); 378 err = fmd_agent_errno(hdl); 379 fmd_agent_close(hdl); 380 381 if (rc == FMD_AGENT_RETIRE_DONE && 382 err == EINVAL) 383 return (FMD_OBJ_STATE_NOT_PRESENT); 384 } 385 386 /* 387 * If a serial number for the dimm was available at the time of the 388 * fault, it will have been added as a string to the unum nvlist 389 */ 390 if (nvlist_lookup_string(unum, FM_FMRI_HC_SERIAL_ID, &old_serial)) 391 return (FMD_OBJ_STATE_UNKNOWN); 392 393 /* 394 * If the current serial number is available for the DIMM that this rank 395 * belongs to, it will be accessible as a property on the parent (dimm) 396 * node. 397 */ 398 dimmnode = topo_node_parent(node); 399 if (topo_prop_get_string(dimmnode, TOPO_PGROUP_PROTOCOL, 400 FM_FMRI_HC_SERIAL_ID, &curr_serial, &err) != 0) { 401 if (err == ETOPO_PROP_NOENT) { 402 return (FMD_OBJ_STATE_UNKNOWN); 403 } else { 404 *errp = EMOD_NVL_INVAL; 405 whinge(mod, NULL, "rank_fmri_present: Unexpected " 406 "error retrieving serial from node"); 407 return (-1); 408 } 409 } 410 411 if (strcmp(old_serial, curr_serial) != 0) { 412 topo_mod_strfree(mod, curr_serial); 413 return (FMD_OBJ_STATE_REPLACED); 414 } 415 416 topo_mod_strfree(mod, curr_serial); 417 418 return (FMD_OBJ_STATE_STILL_PRESENT); 419 } 420 421 /* 422 * In the event we encounter problems comparing serials or if a comparison isn't 423 * possible, we err on the side of caution and set is_present to TRUE. 424 */ 425 int 426 rank_fmri_present(topo_mod_t *mod, tnode_t *node, topo_version_t version, 427 nvlist_t *in, nvlist_t **out) 428 { 429 int is_present, err; 430 431 if (version > TOPO_METH_PRESENT_VERSION) 432 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 433 434 switch (fmri_replaced(mod, node, in, &err)) { 435 case FMD_OBJ_STATE_REPLACED: 436 case FMD_OBJ_STATE_NOT_PRESENT: 437 is_present = 0; 438 break; 439 440 case FMD_OBJ_STATE_UNKNOWN: 441 case FMD_OBJ_STATE_STILL_PRESENT: 442 is_present = 1; 443 break; 444 445 default: 446 return (topo_mod_seterrno(mod, err)); 447 } 448 449 fmri_dprint(mod, "rank_fmri_present", is_present, in); 450 451 return (set_retnvl(mod, out, TOPO_METH_PRESENT_RET, is_present)); 452 } 453 454 int 455 rank_fmri_replaced(topo_mod_t *mod, tnode_t *node, topo_version_t version, 456 nvlist_t *in, nvlist_t **out) 457 { 458 int is_replaced, err; 459 460 if (version > TOPO_METH_REPLACED_VERSION) 461 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 462 463 is_replaced = fmri_replaced(mod, node, in, &err); 464 if (is_replaced == -1) 465 return (topo_mod_seterrno(mod, err)); 466 467 fmri_dprint(mod, "rank_fmri_replaced", is_replaced, in); 468 469 return (set_retnvl(mod, out, TOPO_METH_REPLACED_RET, is_replaced)); 470 } 471 472 static void 473 fmri_dprint(topo_mod_t *mod, const char *op, uint32_t rc, nvlist_t *fmri) 474 { 475 char *fmristr; 476 const char *status; 477 478 if (getenv("TOPOCHIPDBG") == NULL) 479 return; 480 481 switch (rc) { 482 case FMD_AGENT_RETIRE_DONE: 483 status = "sync success"; 484 break; 485 case FMD_AGENT_RETIRE_ASYNC: 486 status = "async retiring"; 487 break; 488 case FMD_AGENT_RETIRE_FAIL: 489 status = "not retired"; 490 break; 491 default: 492 status = "unknown status"; 493 } 494 if (fmri != NULL && topo_mod_nvl2str(mod, fmri, &fmristr) == 0) { 495 topo_mod_dprintf(mod, "[%s]: %s => %d (\"%s\")\n", fmristr, 496 op, rc, status); 497 topo_mod_strfree(mod, fmristr); 498 } 499 } 500 501 struct strand_walk_data { 502 tnode_t *parent; 503 fmd_agent_hdl_t *hdl; 504 int (*func)(fmd_agent_hdl_t *, int, int, int); 505 int err; 506 int done; 507 int fail; 508 int async; 509 }; 510 511 static int 512 strand_walker(topo_mod_t *mod, tnode_t *node, void *pdata) 513 { 514 struct strand_walk_data *swdp = pdata; 515 int32_t chipid, coreid, strandid; 516 int err, rc; 517 518 /* 519 * Terminate the walk if we reach start-node's sibling 520 */ 521 if (node != swdp->parent && 522 topo_node_parent(node) == topo_node_parent(swdp->parent)) 523 return (TOPO_WALK_TERMINATE); 524 525 if (strcmp(topo_node_name(node), STRAND) != 0) 526 return (TOPO_WALK_NEXT); 527 528 if (topo_prop_get_int32(node, PGNAME(STRAND), STRAND_CHIP_ID, 529 &chipid, &err) < 0 || 530 topo_prop_get_int32(node, PGNAME(STRAND), STRAND_CORE_ID, 531 &coreid, &err) < 0) { 532 swdp->err++; 533 return (TOPO_WALK_NEXT); 534 } 535 strandid = topo_node_instance(node); 536 rc = swdp->func(swdp->hdl, chipid, coreid, strandid); 537 538 if (rc == FMD_AGENT_RETIRE_DONE) 539 swdp->done++; 540 else if (rc == FMD_AGENT_RETIRE_FAIL) 541 swdp->fail++; 542 else if (rc == FMD_AGENT_RETIRE_ASYNC) 543 swdp->async++; 544 else 545 swdp->err++; 546 547 if (getenv("TOPOCHIPDBG") != NULL) { 548 const char *op; 549 550 if (swdp->func == fmd_agent_cpu_retire) 551 op = "retire"; 552 else if (swdp->func == fmd_agent_cpu_unretire) 553 op = "unretire"; 554 else if (swdp->func == fmd_agent_cpu_isretired) 555 op = "check status"; 556 else 557 op = "unknown op"; 558 559 topo_mod_dprintf(mod, "%s cpu (%d:%d:%d): rc = %d, err = %s\n", 560 op, (int)chipid, (int)coreid, (int)strandid, rc, 561 fmd_agent_errmsg(swdp->hdl)); 562 } 563 564 return (TOPO_WALK_NEXT); 565 } 566 567 static int 568 walk_strands(topo_mod_t *mod, struct strand_walk_data *swdp, tnode_t *parent, 569 int (*func)(fmd_agent_hdl_t *, int, int, int)) 570 { 571 topo_walk_t *twp; 572 int err; 573 574 swdp->parent = parent; 575 swdp->func = func; 576 swdp->err = swdp->done = swdp->fail = swdp->async = 0; 577 if ((swdp->hdl = fmd_agent_open(FMD_AGENT_VERSION)) == NULL) { 578 swdp->fail++; 579 return (0); 580 } 581 582 twp = topo_mod_walk_init(mod, parent, strand_walker, swdp, &err); 583 if (twp == NULL) { 584 fmd_agent_close(swdp->hdl); 585 return (-1); 586 } 587 588 err = topo_walk_step(twp, TOPO_WALK_CHILD); 589 topo_walk_fini(twp); 590 fmd_agent_close(swdp->hdl); 591 592 if (err == TOPO_WALK_ERR || swdp->err > 0) 593 return (-1); 594 595 return (0); 596 } 597 598 /* ARGSUSED */ 599 int 600 retire_strands(topo_mod_t *mod, tnode_t *node, topo_version_t version, 601 nvlist_t *in, nvlist_t **out) 602 { 603 struct strand_walk_data swd; 604 uint32_t rc; 605 606 if (version > TOPO_METH_RETIRE_VERSION) 607 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 608 609 if (walk_strands(mod, &swd, node, fmd_agent_cpu_retire) == -1) 610 return (-1); 611 612 if (swd.fail > 0) 613 rc = FMD_AGENT_RETIRE_FAIL; 614 else if (swd.async > 0) 615 rc = FMD_AGENT_RETIRE_ASYNC; 616 else 617 rc = FMD_AGENT_RETIRE_DONE; 618 619 return (set_retnvl(mod, out, TOPO_METH_RETIRE_RET, rc)); 620 } 621 622 /* ARGSUSED */ 623 int 624 unretire_strands(topo_mod_t *mod, tnode_t *node, topo_version_t version, 625 nvlist_t *in, nvlist_t **out) 626 { 627 struct strand_walk_data swd; 628 uint32_t rc; 629 630 if (version > TOPO_METH_UNRETIRE_VERSION) 631 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 632 633 if (walk_strands(mod, &swd, node, fmd_agent_cpu_unretire) == -1) 634 return (-1); 635 636 if (swd.fail > 0) 637 rc = FMD_AGENT_RETIRE_FAIL; 638 else if (swd.async > 0) 639 rc = FMD_AGENT_RETIRE_ASYNC; 640 else 641 rc = FMD_AGENT_RETIRE_DONE; 642 643 return (set_retnvl(mod, out, TOPO_METH_UNRETIRE_RET, rc)); 644 } 645 646 /* ARGSUSED */ 647 int 648 service_state_strands(topo_mod_t *mod, tnode_t *node, topo_version_t version, 649 nvlist_t *in, nvlist_t **out) 650 { 651 struct strand_walk_data swd; 652 uint32_t rc; 653 654 if (version > TOPO_METH_SERVICE_STATE_VERSION) 655 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 656 657 if (walk_strands(mod, &swd, node, fmd_agent_cpu_isretired) == -1) 658 return (-1); 659 660 if (swd.done > 0) 661 rc = (swd.fail + swd.async > 0) ? FMD_SERVICE_STATE_DEGRADED : 662 FMD_SERVICE_STATE_UNUSABLE; 663 else if (swd.async > 0) 664 rc = FMD_SERVICE_STATE_ISOLATE_PENDING; 665 else if (swd.fail > 0) 666 rc = FMD_SERVICE_STATE_OK; 667 else 668 rc = FMD_SERVICE_STATE_UNKNOWN; 669 670 return (set_retnvl(mod, out, TOPO_METH_SERVICE_STATE_RET, rc)); 671 } 672 673 /* ARGSUSED */ 674 int 675 unusable_strands(topo_mod_t *mod, tnode_t *node, topo_version_t version, 676 nvlist_t *in, nvlist_t **out) 677 { 678 struct strand_walk_data swd; 679 uint32_t rc; 680 681 if (version > TOPO_METH_UNUSABLE_VERSION) 682 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 683 684 if (walk_strands(mod, &swd, node, fmd_agent_cpu_isretired) == -1) 685 return (-1); 686 687 rc = (swd.fail + swd.async > 0 || swd.done == 0) ? 0 : 1; 688 689 return (set_retnvl(mod, out, TOPO_METH_UNUSABLE_RET, rc)); 690 } 691 692 static boolean_t 693 is_page_fmri(nvlist_t *nvl) 694 { 695 nvlist_t *hcsp; 696 uint64_t val; 697 698 if (nvlist_lookup_nvlist(nvl, FM_FMRI_HC_SPECIFIC, &hcsp) == 0 && 699 (nvlist_lookup_uint64(hcsp, FM_FMRI_HC_SPECIFIC_OFFSET, 700 &val) == 0 || 701 nvlist_lookup_uint64(hcsp, "asru-" FM_FMRI_HC_SPECIFIC_OFFSET, 702 &val) == 0 || 703 nvlist_lookup_uint64(hcsp, FM_FMRI_HC_SPECIFIC_PHYSADDR, 704 &val) == 0 || 705 nvlist_lookup_uint64(hcsp, "asru-" FM_FMRI_HC_SPECIFIC_PHYSADDR, 706 &val) == 0)) 707 return (B_TRUE); 708 709 return (B_FALSE); 710 } 711 712 /* ARGSUSED */ 713 int 714 ntv_page_retire(topo_mod_t *mod, tnode_t *node, topo_version_t version, 715 nvlist_t *in, nvlist_t **out) 716 { 717 fmd_agent_hdl_t *hdl; 718 uint32_t rc = FMD_AGENT_RETIRE_FAIL; 719 720 if (version > TOPO_METH_RETIRE_VERSION) 721 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 722 if (is_page_fmri(in)) { 723 if ((hdl = fmd_agent_open(FMD_AGENT_VERSION)) != NULL) { 724 rc = fmd_agent_page_retire(hdl, in); 725 fmd_agent_close(hdl); 726 } 727 } 728 fmri_dprint(mod, "ntv_page_retire", rc, in); 729 return (set_retnvl(mod, out, TOPO_METH_RETIRE_RET, rc)); 730 } 731 732 /* ARGSUSED */ 733 int 734 ntv_page_unretire(topo_mod_t *mod, tnode_t *node, topo_version_t version, 735 nvlist_t *in, nvlist_t **out) 736 { 737 fmd_agent_hdl_t *hdl; 738 uint32_t rc = FMD_AGENT_RETIRE_FAIL; 739 740 if (version > TOPO_METH_UNRETIRE_VERSION) 741 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 742 if (is_page_fmri(in)) { 743 if ((hdl = fmd_agent_open(FMD_AGENT_VERSION)) != NULL) { 744 rc = fmd_agent_page_unretire(hdl, in); 745 fmd_agent_close(hdl); 746 } 747 } 748 fmri_dprint(mod, "ntv_page_unretire", rc, in); 749 return (set_retnvl(mod, out, TOPO_METH_UNRETIRE_RET, rc)); 750 } 751 752 /* ARGSUSED */ 753 int 754 ntv_page_service_state(topo_mod_t *mod, tnode_t *node, topo_version_t version, 755 nvlist_t *in, nvlist_t **out) 756 { 757 fmd_agent_hdl_t *hdl; 758 uint32_t rc = FMD_SERVICE_STATE_UNKNOWN; 759 760 if (version > TOPO_METH_SERVICE_STATE_VERSION) 761 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 762 if (is_page_fmri(in)) { 763 if ((hdl = fmd_agent_open(FMD_AGENT_VERSION)) != NULL) { 764 rc = fmd_agent_page_isretired(hdl, in); 765 fmd_agent_close(hdl); 766 if (rc == FMD_AGENT_RETIRE_DONE) 767 rc = FMD_SERVICE_STATE_UNUSABLE; 768 else if (rc == FMD_AGENT_RETIRE_FAIL) 769 rc = FMD_SERVICE_STATE_OK; 770 else if (rc == FMD_AGENT_RETIRE_ASYNC) 771 rc = FMD_SERVICE_STATE_ISOLATE_PENDING; 772 } 773 } 774 775 topo_mod_dprintf(mod, "ntv_page_service_state: rc = %u\n", rc); 776 return (set_retnvl(mod, out, TOPO_METH_SERVICE_STATE_RET, rc)); 777 } 778 779 /* ARGSUSED */ 780 int 781 ntv_page_unusable(topo_mod_t *mod, tnode_t *node, topo_version_t version, 782 nvlist_t *in, nvlist_t **out) 783 { 784 fmd_agent_hdl_t *hdl; 785 uint32_t rc = FMD_AGENT_RETIRE_FAIL; 786 787 if (version > TOPO_METH_UNUSABLE_VERSION) 788 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 789 if (is_page_fmri(in)) { 790 if ((hdl = fmd_agent_open(FMD_AGENT_VERSION)) != NULL) { 791 rc = fmd_agent_page_isretired(hdl, in); 792 fmd_agent_close(hdl); 793 } 794 } 795 topo_mod_dprintf(mod, "ntv_page_unusable: rc = %u\n", rc); 796 return (set_retnvl(mod, out, TOPO_METH_UNUSABLE_RET, 797 rc == FMD_AGENT_RETIRE_DONE ? 1 : 0)); 798 } 799