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 2009 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 nvlist_t *resource; 369 int rc, err; 370 char *old_serial, *curr_serial; 371 fmd_agent_hdl_t *hdl; 372 373 /* 374 * If input is a page, return "replaced" if the offset is invalid. 375 */ 376 if (is_page_fmri(unum) && 377 (hdl = fmd_agent_open(FMD_AGENT_VERSION)) != NULL) { 378 rc = fmd_agent_page_isretired(hdl, unum); 379 err = fmd_agent_errno(hdl); 380 fmd_agent_close(hdl); 381 382 if (rc == FMD_AGENT_RETIRE_DONE && 383 err == EINVAL) 384 return (FMD_OBJ_STATE_NOT_PRESENT); 385 } 386 387 /* 388 * If a serial number for the dimm was available at the time of the 389 * fault, it will have been added as a string to the unum nvlist 390 */ 391 if (nvlist_lookup_string(unum, FM_FMRI_HC_SERIAL_ID, &old_serial)) 392 return (FMD_OBJ_STATE_UNKNOWN); 393 394 /* 395 * If the current serial number is available for the DIMM that this rank 396 * belongs to, it will be accessible as a property on the parent (dimm) 397 * node. If there is a serial id in the resource fmri, then use that. 398 * Otherwise fall back to looking for a serial id property in the 399 * protocol group. 400 */ 401 dimmnode = topo_node_parent(node); 402 if (topo_node_resource(dimmnode, &resource, &err) != -1) { 403 if (nvlist_lookup_string(resource, FM_FMRI_HC_SERIAL_ID, 404 &curr_serial) == 0) { 405 if (strcmp(old_serial, curr_serial) != 0) { 406 nvlist_free(resource); 407 return (FMD_OBJ_STATE_REPLACED); 408 } else { 409 nvlist_free(resource); 410 return (FMD_OBJ_STATE_STILL_PRESENT); 411 } 412 } 413 nvlist_free(resource); 414 } 415 if (topo_prop_get_string(dimmnode, TOPO_PGROUP_PROTOCOL, 416 FM_FMRI_HC_SERIAL_ID, &curr_serial, &err) != 0) { 417 if (err == ETOPO_PROP_NOENT) { 418 return (FMD_OBJ_STATE_UNKNOWN); 419 } else { 420 *errp = EMOD_NVL_INVAL; 421 whinge(mod, NULL, "rank_fmri_present: Unexpected " 422 "error retrieving serial from node"); 423 return (-1); 424 } 425 } 426 427 if (strcmp(old_serial, curr_serial) != 0) { 428 topo_mod_strfree(mod, curr_serial); 429 return (FMD_OBJ_STATE_REPLACED); 430 } 431 432 topo_mod_strfree(mod, curr_serial); 433 434 return (FMD_OBJ_STATE_STILL_PRESENT); 435 } 436 437 /* 438 * In the event we encounter problems comparing serials or if a comparison isn't 439 * possible, we err on the side of caution and set is_present to TRUE. 440 */ 441 int 442 rank_fmri_present(topo_mod_t *mod, tnode_t *node, topo_version_t version, 443 nvlist_t *in, nvlist_t **out) 444 { 445 int is_present, err; 446 447 if (version > TOPO_METH_PRESENT_VERSION) 448 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 449 450 switch (fmri_replaced(mod, node, in, &err)) { 451 case FMD_OBJ_STATE_REPLACED: 452 case FMD_OBJ_STATE_NOT_PRESENT: 453 is_present = 0; 454 break; 455 456 case FMD_OBJ_STATE_UNKNOWN: 457 case FMD_OBJ_STATE_STILL_PRESENT: 458 is_present = 1; 459 break; 460 461 default: 462 return (topo_mod_seterrno(mod, err)); 463 } 464 465 fmri_dprint(mod, "rank_fmri_present", is_present, in); 466 467 return (set_retnvl(mod, out, TOPO_METH_PRESENT_RET, is_present)); 468 } 469 470 int 471 rank_fmri_replaced(topo_mod_t *mod, tnode_t *node, topo_version_t version, 472 nvlist_t *in, nvlist_t **out) 473 { 474 int is_replaced, err; 475 476 if (version > TOPO_METH_REPLACED_VERSION) 477 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 478 479 is_replaced = fmri_replaced(mod, node, in, &err); 480 if (is_replaced == -1) 481 return (topo_mod_seterrno(mod, err)); 482 483 fmri_dprint(mod, "rank_fmri_replaced", is_replaced, in); 484 485 return (set_retnvl(mod, out, TOPO_METH_REPLACED_RET, is_replaced)); 486 } 487 488 static void 489 fmri_dprint(topo_mod_t *mod, const char *op, uint32_t rc, nvlist_t *fmri) 490 { 491 char *fmristr; 492 const char *status; 493 494 if (getenv("TOPOCHIPDBG") == NULL) 495 return; 496 497 switch (rc) { 498 case FMD_AGENT_RETIRE_DONE: 499 status = "sync success"; 500 break; 501 case FMD_AGENT_RETIRE_ASYNC: 502 status = "async retiring"; 503 break; 504 case FMD_AGENT_RETIRE_FAIL: 505 status = "not retired"; 506 break; 507 default: 508 status = "unknown status"; 509 } 510 if (fmri != NULL && topo_mod_nvl2str(mod, fmri, &fmristr) == 0) { 511 topo_mod_dprintf(mod, "[%s]: %s => %d (\"%s\")\n", fmristr, 512 op, rc, status); 513 topo_mod_strfree(mod, fmristr); 514 } 515 } 516 517 struct strand_walk_data { 518 tnode_t *parent; 519 fmd_agent_hdl_t *hdl; 520 int (*func)(fmd_agent_hdl_t *, int, int, int); 521 int err; 522 int done; 523 int fail; 524 int async; 525 }; 526 527 static int 528 strand_walker(topo_mod_t *mod, tnode_t *node, void *pdata) 529 { 530 struct strand_walk_data *swdp = pdata; 531 int32_t chipid, coreid, strandid; 532 int err, rc; 533 534 /* 535 * Terminate the walk if we reach start-node's sibling 536 */ 537 if (node != swdp->parent && 538 topo_node_parent(node) == topo_node_parent(swdp->parent)) 539 return (TOPO_WALK_TERMINATE); 540 541 if (strcmp(topo_node_name(node), STRAND) != 0) 542 return (TOPO_WALK_NEXT); 543 544 if (topo_prop_get_int32(node, PGNAME(STRAND), STRAND_CHIP_ID, 545 &chipid, &err) < 0 || 546 topo_prop_get_int32(node, PGNAME(STRAND), STRAND_CORE_ID, 547 &coreid, &err) < 0) { 548 swdp->err++; 549 return (TOPO_WALK_NEXT); 550 } 551 strandid = topo_node_instance(node); 552 rc = swdp->func(swdp->hdl, chipid, coreid, strandid); 553 554 if (rc == FMD_AGENT_RETIRE_DONE) 555 swdp->done++; 556 else if (rc == FMD_AGENT_RETIRE_FAIL) 557 swdp->fail++; 558 else if (rc == FMD_AGENT_RETIRE_ASYNC) 559 swdp->async++; 560 else 561 swdp->err++; 562 563 if (getenv("TOPOCHIPDBG") != NULL) { 564 const char *op; 565 566 if (swdp->func == fmd_agent_cpu_retire) 567 op = "retire"; 568 else if (swdp->func == fmd_agent_cpu_unretire) 569 op = "unretire"; 570 else if (swdp->func == fmd_agent_cpu_isretired) 571 op = "check status"; 572 else 573 op = "unknown op"; 574 575 topo_mod_dprintf(mod, "%s cpu (%d:%d:%d): rc = %d, err = %s\n", 576 op, (int)chipid, (int)coreid, (int)strandid, rc, 577 fmd_agent_errmsg(swdp->hdl)); 578 } 579 580 return (TOPO_WALK_NEXT); 581 } 582 583 static int 584 walk_strands(topo_mod_t *mod, struct strand_walk_data *swdp, tnode_t *parent, 585 int (*func)(fmd_agent_hdl_t *, int, int, int)) 586 { 587 topo_walk_t *twp; 588 int err; 589 590 swdp->parent = parent; 591 swdp->func = func; 592 swdp->err = swdp->done = swdp->fail = swdp->async = 0; 593 if ((swdp->hdl = fmd_agent_open(FMD_AGENT_VERSION)) == NULL) { 594 swdp->fail++; 595 return (0); 596 } 597 598 twp = topo_mod_walk_init(mod, parent, strand_walker, swdp, &err); 599 if (twp == NULL) { 600 fmd_agent_close(swdp->hdl); 601 return (-1); 602 } 603 604 err = topo_walk_step(twp, TOPO_WALK_CHILD); 605 topo_walk_fini(twp); 606 fmd_agent_close(swdp->hdl); 607 608 if (err == TOPO_WALK_ERR || swdp->err > 0) 609 return (-1); 610 611 return (0); 612 } 613 614 /* ARGSUSED */ 615 int 616 retire_strands(topo_mod_t *mod, tnode_t *node, topo_version_t version, 617 nvlist_t *in, nvlist_t **out) 618 { 619 struct strand_walk_data swd; 620 uint32_t rc; 621 622 if (version > TOPO_METH_RETIRE_VERSION) 623 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 624 625 if (walk_strands(mod, &swd, node, fmd_agent_cpu_retire) == -1) 626 return (-1); 627 628 if (swd.fail > 0) 629 rc = FMD_AGENT_RETIRE_FAIL; 630 else if (swd.async > 0) 631 rc = FMD_AGENT_RETIRE_ASYNC; 632 else 633 rc = FMD_AGENT_RETIRE_DONE; 634 635 return (set_retnvl(mod, out, TOPO_METH_RETIRE_RET, rc)); 636 } 637 638 /* ARGSUSED */ 639 int 640 unretire_strands(topo_mod_t *mod, tnode_t *node, topo_version_t version, 641 nvlist_t *in, nvlist_t **out) 642 { 643 struct strand_walk_data swd; 644 uint32_t rc; 645 646 if (version > TOPO_METH_UNRETIRE_VERSION) 647 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 648 649 if (walk_strands(mod, &swd, node, fmd_agent_cpu_unretire) == -1) 650 return (-1); 651 652 if (swd.fail > 0) 653 rc = FMD_AGENT_RETIRE_FAIL; 654 else if (swd.async > 0) 655 rc = FMD_AGENT_RETIRE_ASYNC; 656 else 657 rc = FMD_AGENT_RETIRE_DONE; 658 659 return (set_retnvl(mod, out, TOPO_METH_UNRETIRE_RET, rc)); 660 } 661 662 /* ARGSUSED */ 663 int 664 service_state_strands(topo_mod_t *mod, tnode_t *node, topo_version_t version, 665 nvlist_t *in, nvlist_t **out) 666 { 667 struct strand_walk_data swd; 668 uint32_t rc; 669 670 if (version > TOPO_METH_SERVICE_STATE_VERSION) 671 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 672 673 if (walk_strands(mod, &swd, node, fmd_agent_cpu_isretired) == -1) 674 return (-1); 675 676 if (swd.done > 0) 677 rc = (swd.fail + swd.async > 0) ? FMD_SERVICE_STATE_DEGRADED : 678 FMD_SERVICE_STATE_UNUSABLE; 679 else if (swd.async > 0) 680 rc = FMD_SERVICE_STATE_ISOLATE_PENDING; 681 else if (swd.fail > 0) 682 rc = FMD_SERVICE_STATE_OK; 683 else 684 rc = FMD_SERVICE_STATE_UNKNOWN; 685 686 return (set_retnvl(mod, out, TOPO_METH_SERVICE_STATE_RET, rc)); 687 } 688 689 /* ARGSUSED */ 690 int 691 unusable_strands(topo_mod_t *mod, tnode_t *node, topo_version_t version, 692 nvlist_t *in, nvlist_t **out) 693 { 694 struct strand_walk_data swd; 695 uint32_t rc; 696 697 if (version > TOPO_METH_UNUSABLE_VERSION) 698 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 699 700 if (walk_strands(mod, &swd, node, fmd_agent_cpu_isretired) == -1) 701 return (-1); 702 703 rc = (swd.fail + swd.async > 0 || swd.done == 0) ? 0 : 1; 704 705 return (set_retnvl(mod, out, TOPO_METH_UNUSABLE_RET, rc)); 706 } 707 708 static boolean_t 709 is_page_fmri(nvlist_t *nvl) 710 { 711 nvlist_t *hcsp; 712 uint64_t val; 713 714 if (nvlist_lookup_nvlist(nvl, FM_FMRI_HC_SPECIFIC, &hcsp) == 0 && 715 (nvlist_lookup_uint64(hcsp, FM_FMRI_HC_SPECIFIC_OFFSET, 716 &val) == 0 || 717 nvlist_lookup_uint64(hcsp, "asru-" FM_FMRI_HC_SPECIFIC_OFFSET, 718 &val) == 0 || 719 nvlist_lookup_uint64(hcsp, FM_FMRI_HC_SPECIFIC_PHYSADDR, 720 &val) == 0 || 721 nvlist_lookup_uint64(hcsp, "asru-" FM_FMRI_HC_SPECIFIC_PHYSADDR, 722 &val) == 0)) 723 return (B_TRUE); 724 725 return (B_FALSE); 726 } 727 728 /* ARGSUSED */ 729 int 730 ntv_page_retire(topo_mod_t *mod, tnode_t *node, topo_version_t version, 731 nvlist_t *in, nvlist_t **out) 732 { 733 fmd_agent_hdl_t *hdl; 734 uint32_t rc = FMD_AGENT_RETIRE_FAIL; 735 736 if (version > TOPO_METH_RETIRE_VERSION) 737 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 738 if (is_page_fmri(in)) { 739 if ((hdl = fmd_agent_open(FMD_AGENT_VERSION)) != NULL) { 740 rc = fmd_agent_page_retire(hdl, in); 741 fmd_agent_close(hdl); 742 } 743 } 744 fmri_dprint(mod, "ntv_page_retire", rc, in); 745 return (set_retnvl(mod, out, TOPO_METH_RETIRE_RET, rc)); 746 } 747 748 /* ARGSUSED */ 749 int 750 ntv_page_unretire(topo_mod_t *mod, tnode_t *node, topo_version_t version, 751 nvlist_t *in, nvlist_t **out) 752 { 753 fmd_agent_hdl_t *hdl; 754 uint32_t rc = FMD_AGENT_RETIRE_FAIL; 755 756 if (version > TOPO_METH_UNRETIRE_VERSION) 757 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 758 if (is_page_fmri(in)) { 759 if ((hdl = fmd_agent_open(FMD_AGENT_VERSION)) != NULL) { 760 rc = fmd_agent_page_unretire(hdl, in); 761 fmd_agent_close(hdl); 762 } 763 } 764 fmri_dprint(mod, "ntv_page_unretire", rc, in); 765 return (set_retnvl(mod, out, TOPO_METH_UNRETIRE_RET, rc)); 766 } 767 768 /* ARGSUSED */ 769 int 770 ntv_page_service_state(topo_mod_t *mod, tnode_t *node, topo_version_t version, 771 nvlist_t *in, nvlist_t **out) 772 { 773 fmd_agent_hdl_t *hdl; 774 uint32_t rc = FMD_SERVICE_STATE_UNKNOWN; 775 776 if (version > TOPO_METH_SERVICE_STATE_VERSION) 777 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 778 if (is_page_fmri(in)) { 779 if ((hdl = fmd_agent_open(FMD_AGENT_VERSION)) != NULL) { 780 rc = fmd_agent_page_isretired(hdl, in); 781 fmd_agent_close(hdl); 782 if (rc == FMD_AGENT_RETIRE_DONE) 783 rc = FMD_SERVICE_STATE_UNUSABLE; 784 else if (rc == FMD_AGENT_RETIRE_FAIL) 785 rc = FMD_SERVICE_STATE_OK; 786 else if (rc == FMD_AGENT_RETIRE_ASYNC) 787 rc = FMD_SERVICE_STATE_ISOLATE_PENDING; 788 } 789 } 790 791 topo_mod_dprintf(mod, "ntv_page_service_state: rc = %u\n", rc); 792 return (set_retnvl(mod, out, TOPO_METH_SERVICE_STATE_RET, rc)); 793 } 794 795 /* ARGSUSED */ 796 int 797 ntv_page_unusable(topo_mod_t *mod, tnode_t *node, topo_version_t version, 798 nvlist_t *in, nvlist_t **out) 799 { 800 fmd_agent_hdl_t *hdl; 801 uint32_t rc = FMD_AGENT_RETIRE_FAIL; 802 803 if (version > TOPO_METH_UNUSABLE_VERSION) 804 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 805 if (is_page_fmri(in)) { 806 if ((hdl = fmd_agent_open(FMD_AGENT_VERSION)) != NULL) { 807 rc = fmd_agent_page_isretired(hdl, in); 808 fmd_agent_close(hdl); 809 } 810 } 811 topo_mod_dprintf(mod, "ntv_page_unusable: rc = %u\n", rc); 812 return (set_retnvl(mod, out, TOPO_METH_UNUSABLE_RET, 813 rc == FMD_AGENT_RETIRE_DONE ? 1 : 0)); 814 } 815