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 #include <ctype.h> 28 #include <string.h> 29 #include <limits.h> 30 #include <fm/topo_mod.h> 31 #include <fm/fmd_fmri.h> 32 #include <sys/fm/protocol.h> 33 #include <topo_alloc.h> 34 #include <topo_error.h> 35 #include <topo_hc.h> 36 #include <topo_method.h> 37 #include <topo_subr.h> 38 #include <topo_string.h> 39 40 /* 41 * Topology node properties and method operations may be accessed by FMRI. 42 * The FMRI used to perform property look-ups and method operations is 43 * the FMRI contained in the matching topology node's protocol property 44 * grouping for the resource property. The full range of fmd(1M) 45 * scheme plugin operations are supported as long as a backend method is 46 * supplied by a scheme-specific enumerator or the enumerator module that 47 * created the matching topology node. Support for fmd scheme operations 48 * include: 49 * 50 * - expand 51 * - present 52 * - replaced 53 * - contains 54 * - unusable 55 * - service_state 56 * - nvl2str 57 * - retire 58 * - unretire 59 * 60 * In addition, the following operations are supported per-FMRI: 61 * 62 * - str2nvl: convert string-based FMRI to nvlist 63 * - compare: compare two FMRIs 64 * - asru: lookup associated ASRU property by FMRI 65 * - fru: lookup associated FRU by FMRI 66 * - create: an FMRI nvlist by scheme type 67 * - propery lookup 68 * 69 * These routines may only be called by consumers of a topology snapshot. 70 * They may not be called by libtopo enumerator or method modules. 71 */ 72 73 /*ARGSUSED*/ 74 static int 75 set_error(topo_hdl_t *thp, int err, int *errp, char *method, nvlist_t *nvlp) 76 { 77 if (nvlp != NULL) 78 nvlist_free(nvlp); 79 80 topo_dprintf(thp, TOPO_DBG_ERR, "%s failed: %s\n", method, 81 topo_strerror(err)); 82 83 *errp = err; 84 return (-1); 85 } 86 87 /*ARGSUSED*/ 88 static nvlist_t * 89 set_nverror(topo_hdl_t *thp, int err, int *errp, char *method, nvlist_t *nvlp) 90 { 91 if (nvlp != NULL) 92 nvlist_free(nvlp); 93 94 topo_dprintf(thp, TOPO_DBG_ERR, "%s failed: %s\n", method, 95 topo_strerror(err)); 96 97 *errp = err; 98 return (NULL); 99 } 100 101 int 102 topo_fmri_nvl2str(topo_hdl_t *thp, nvlist_t *fmri, char **fmristr, int *err) 103 { 104 char *scheme, *str; 105 nvlist_t *out = NULL; 106 tnode_t *rnode; 107 108 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 109 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 110 TOPO_METH_NVL2STR, out)); 111 112 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 113 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 114 TOPO_METH_NVL2STR, out)); 115 116 if (topo_method_invoke(rnode, TOPO_METH_NVL2STR, 117 TOPO_METH_NVL2STR_VERSION, fmri, &out, err) != 0) 118 return (set_error(thp, *err, err, TOPO_METH_NVL2STR, out)); 119 120 if (out == NULL || nvlist_lookup_string(out, "fmri-string", &str) != 0) 121 return (set_error(thp, ETOPO_METHOD_INVAL, err, 122 TOPO_METH_NVL2STR, out)); 123 124 if ((*fmristr = topo_hdl_strdup(thp, str)) == NULL) 125 return (set_error(thp, ETOPO_NOMEM, err, 126 TOPO_METH_NVL2STR, out)); 127 128 nvlist_free(out); 129 130 return (0); 131 } 132 133 int 134 topo_fmri_str2nvl(topo_hdl_t *thp, const char *fmristr, nvlist_t **fmri, 135 int *err) 136 { 137 char *f, buf[PATH_MAX]; 138 nvlist_t *out = NULL, *in = NULL; 139 tnode_t *rnode; 140 141 (void) strlcpy(buf, fmristr, sizeof (buf)); 142 if ((f = strchr(buf, ':')) == NULL) 143 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 144 TOPO_METH_STR2NVL, in)); 145 146 *f = '\0'; /* strip trailing FMRI path */ 147 148 if ((rnode = topo_hdl_root(thp, buf)) == NULL) 149 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 150 TOPO_METH_STR2NVL, in)); 151 152 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 153 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_STR2NVL, 154 in)); 155 156 if (nvlist_add_string(in, "fmri-string", fmristr) != 0) 157 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_STR2NVL, 158 in)); 159 160 if (topo_method_invoke(rnode, TOPO_METH_STR2NVL, 161 TOPO_METH_STR2NVL_VERSION, in, &out, err) != 0) 162 return (set_error(thp, *err, err, TOPO_METH_STR2NVL, in)); 163 164 nvlist_free(in); 165 166 if (out == NULL || 167 topo_hdl_nvdup(thp, out, fmri) != 0) 168 return (set_error(thp, ETOPO_FMRI_NVL, err, 169 TOPO_METH_STR2NVL, out)); 170 171 nvlist_free(out); 172 173 return (0); 174 } 175 176 int 177 topo_fmri_present(topo_hdl_t *thp, nvlist_t *fmri, int *err) 178 { 179 uint32_t present = 0; 180 char *scheme; 181 nvlist_t *out = NULL; 182 tnode_t *rnode; 183 184 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 185 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 186 TOPO_METH_PRESENT, out)); 187 188 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 189 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 190 TOPO_METH_PRESENT, out)); 191 192 if (topo_method_invoke(rnode, TOPO_METH_PRESENT, 193 TOPO_METH_PRESENT_VERSION, fmri, &out, err) < 0) { 194 (void) set_error(thp, *err, err, TOPO_METH_PRESENT, out); 195 return (present); 196 } 197 198 (void) nvlist_lookup_uint32(out, TOPO_METH_PRESENT_RET, &present); 199 nvlist_free(out); 200 201 return (present); 202 } 203 204 int 205 topo_fmri_replaced(topo_hdl_t *thp, nvlist_t *fmri, int *err) 206 { 207 uint32_t replaced = FMD_OBJ_STATE_NOT_PRESENT; 208 char *scheme; 209 nvlist_t *out = NULL; 210 tnode_t *rnode; 211 212 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 213 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 214 TOPO_METH_REPLACED, out)); 215 216 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 217 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 218 TOPO_METH_REPLACED, out)); 219 220 if (topo_method_invoke(rnode, TOPO_METH_REPLACED, 221 TOPO_METH_REPLACED_VERSION, fmri, &out, err) < 0) { 222 (void) set_error(thp, *err, err, TOPO_METH_REPLACED, out); 223 return (FMD_OBJ_STATE_UNKNOWN); 224 } 225 226 (void) nvlist_lookup_uint32(out, TOPO_METH_REPLACED_RET, &replaced); 227 nvlist_free(out); 228 229 return (replaced); 230 } 231 232 int 233 topo_fmri_contains(topo_hdl_t *thp, nvlist_t *fmri, nvlist_t *subfmri, int *err) 234 { 235 uint32_t contains; 236 char *scheme; 237 nvlist_t *in = NULL, *out = NULL; 238 tnode_t *rnode; 239 240 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 241 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 242 TOPO_METH_CONTAINS, NULL)); 243 244 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 245 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 246 TOPO_METH_CONTAINS, NULL)); 247 248 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 249 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS, 250 NULL)); 251 252 if (nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_FMRI, fmri) != 0 || 253 nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_SUBFMRI, subfmri) != 0) 254 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS, 255 in)); 256 257 if (topo_method_invoke(rnode, TOPO_METH_CONTAINS, 258 TOPO_METH_CONTAINS_VERSION, in, &out, err) < 0) 259 return (set_error(thp, *err, err, TOPO_METH_CONTAINS, in)); 260 261 (void) nvlist_lookup_uint32(out, TOPO_METH_CONTAINS_RET, &contains); 262 nvlist_free(in); 263 nvlist_free(out); 264 265 return (contains); 266 } 267 268 int 269 topo_fmri_unusable(topo_hdl_t *thp, nvlist_t *fmri, int *err) 270 { 271 char *scheme; 272 uint32_t unusable = 0; 273 nvlist_t *out = NULL; 274 tnode_t *rnode; 275 276 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 277 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 278 TOPO_METH_UNUSABLE, out)); 279 280 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 281 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 282 TOPO_METH_UNUSABLE, out)); 283 284 if (topo_method_invoke(rnode, TOPO_METH_UNUSABLE, 285 TOPO_METH_UNUSABLE_VERSION, fmri, &out, err) < 0) 286 return (set_error(thp, *err, err, TOPO_METH_UNUSABLE, out)); 287 288 (void) nvlist_lookup_uint32(out, TOPO_METH_UNUSABLE_RET, &unusable); 289 nvlist_free(out); 290 291 return (unusable); 292 } 293 294 int 295 topo_fmri_retire(topo_hdl_t *thp, nvlist_t *fmri, int *err) 296 { 297 char *scheme; 298 uint32_t status; 299 nvlist_t *out = NULL; 300 tnode_t *rnode; 301 302 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 303 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 304 TOPO_METH_RETIRE, out)); 305 306 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 307 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 308 TOPO_METH_RETIRE, out)); 309 310 if (topo_method_invoke(rnode, TOPO_METH_RETIRE, 311 TOPO_METH_RETIRE_VERSION, fmri, &out, err) < 0) 312 return (set_error(thp, *err, err, TOPO_METH_RETIRE, out)); 313 314 if (nvlist_lookup_uint32(out, TOPO_METH_RETIRE_RET, &status) != 0) 315 return (set_error(thp, ETOPO_METHOD_FAIL, err, 316 TOPO_METH_RETIRE, out)); 317 nvlist_free(out); 318 319 return (status); 320 } 321 322 int 323 topo_fmri_unretire(topo_hdl_t *thp, nvlist_t *fmri, int *err) 324 { 325 char *scheme; 326 uint32_t status; 327 nvlist_t *out = NULL; 328 tnode_t *rnode; 329 330 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 331 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 332 TOPO_METH_UNRETIRE, out)); 333 334 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 335 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 336 TOPO_METH_UNRETIRE, out)); 337 338 if (topo_method_invoke(rnode, TOPO_METH_UNRETIRE, 339 TOPO_METH_UNRETIRE_VERSION, fmri, &out, err) < 0) 340 return (set_error(thp, *err, err, TOPO_METH_UNRETIRE, out)); 341 342 if (nvlist_lookup_uint32(out, TOPO_METH_UNRETIRE_RET, &status) != 0) { 343 nvlist_free(out); 344 return (set_error(thp, ETOPO_METHOD_FAIL, err, 345 TOPO_METH_UNRETIRE, out)); 346 } 347 nvlist_free(out); 348 349 return (status); 350 } 351 352 int 353 topo_fmri_service_state(topo_hdl_t *thp, nvlist_t *fmri, int *err) 354 { 355 char *scheme; 356 uint32_t service_state = FMD_SERVICE_STATE_UNKNOWN; 357 nvlist_t *out = NULL; 358 tnode_t *rnode; 359 360 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 361 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 362 TOPO_METH_SERVICE_STATE, out)); 363 364 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 365 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 366 TOPO_METH_SERVICE_STATE, out)); 367 368 if (topo_method_invoke(rnode, TOPO_METH_SERVICE_STATE, 369 TOPO_METH_SERVICE_STATE_VERSION, fmri, &out, err) < 0) 370 return (set_error(thp, *err, err, TOPO_METH_SERVICE_STATE, 371 out)); 372 373 (void) nvlist_lookup_uint32(out, TOPO_METH_SERVICE_STATE_RET, 374 &service_state); 375 nvlist_free(out); 376 377 return (service_state); 378 } 379 380 int 381 topo_fmri_expand(topo_hdl_t *thp, nvlist_t *fmri, int *err) 382 { 383 char *scheme; 384 nvlist_t *out = NULL; 385 tnode_t *rnode; 386 387 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 388 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 389 TOPO_METH_EXPAND, out)); 390 391 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 392 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 393 TOPO_METH_EXPAND, out)); 394 395 if (topo_method_invoke(rnode, TOPO_METH_EXPAND, 396 TOPO_METH_EXPAND_VERSION, fmri, &out, err) != 0) 397 return (set_error(thp, *err, err, TOPO_METH_EXPAND, out)); 398 399 return (0); 400 } 401 402 static int 403 fmri_prop(topo_hdl_t *thp, nvlist_t *rsrc, const char *pgname, 404 const char *pname, nvlist_t *args, nvlist_t **prop, 405 int *err) 406 { 407 int rv; 408 nvlist_t *in = NULL; 409 tnode_t *rnode; 410 char *scheme; 411 412 if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0) 413 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 414 TOPO_METH_PROP_GET, in)); 415 416 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 417 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 418 TOPO_METH_PROP_GET, in)); 419 420 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 421 return (set_error(thp, ETOPO_FMRI_NVL, err, 422 TOPO_METH_PROP_GET, in)); 423 424 rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc); 425 rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pgname); 426 rv |= nvlist_add_string(in, TOPO_PROP_VAL_NAME, pname); 427 if (args != NULL) 428 rv |= nvlist_add_nvlist(in, TOPO_PROP_PARGS, args); 429 if (rv != 0) 430 return (set_error(thp, ETOPO_FMRI_NVL, err, 431 TOPO_METH_PROP_GET, in)); 432 433 *prop = NULL; 434 rv = topo_method_invoke(rnode, TOPO_METH_PROP_GET, 435 TOPO_METH_PROP_GET_VERSION, in, prop, err); 436 437 nvlist_free(in); 438 439 if (rv != 0) 440 return (-1); /* *err is set for us */ 441 442 if (*prop == NULL) 443 return (set_error(thp, ETOPO_PROP_NOENT, err, 444 TOPO_METH_PROP_GET, NULL)); 445 return (0); 446 } 447 448 int 449 topo_fmri_asru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **asru, int *err) 450 { 451 nvlist_t *ap, *prop = NULL; 452 453 if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_ASRU, 454 nvl, &prop, err) < 0) 455 return (set_error(thp, *err, err, "topo_fmri_asru", NULL)); 456 457 if (nvlist_lookup_nvlist(prop, TOPO_PROP_VAL_VAL, &ap) != 0) 458 return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_asru", 459 prop)); 460 461 if (topo_hdl_nvdup(thp, ap, asru) < 0) 462 return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_asru", 463 prop)); 464 465 nvlist_free(prop); 466 467 return (0); 468 } 469 470 int 471 topo_fmri_fru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **fru, int *err) 472 { 473 nvlist_t *fp, *prop = NULL; 474 475 if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU, 476 nvl, &prop, err) < 0) 477 return (set_error(thp, *err, err, "topo_fmri_fru", NULL)); 478 479 if (nvlist_lookup_nvlist(prop, TOPO_PROP_VAL_VAL, &fp) != 0) 480 return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_fru", 481 prop)); 482 483 if (topo_hdl_nvdup(thp, fp, fru) < 0) 484 return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_fru", 485 prop)); 486 487 nvlist_free(prop); 488 489 return (0); 490 } 491 492 int 493 topo_fmri_label(topo_hdl_t *thp, nvlist_t *nvl, char **label, int *err) 494 { 495 nvlist_t *prop = NULL; 496 char *lp; 497 498 if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_LABEL, 499 NULL, &prop, err) < 0) 500 return (set_error(thp, *err, err, "topo_fmri_label", NULL)); 501 502 if (nvlist_lookup_string(prop, TOPO_PROP_VAL_VAL, &lp) != 0) 503 return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_label", 504 prop)); 505 506 if ((*label = topo_hdl_strdup(thp, lp)) == NULL) 507 return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_label", 508 prop)); 509 510 nvlist_free(prop); 511 512 return (0); 513 } 514 515 int 516 topo_fmri_serial(topo_hdl_t *thp, nvlist_t *nvl, char **serial, int *err) 517 { 518 nvlist_t *prop = NULL; 519 char *sp; 520 521 /* 522 * If there is a serial id in the resource fmri, then use that. 523 * Otherwise fall back to looking for a serial id property in the 524 * protocol group. 525 */ 526 if (nvlist_lookup_string(nvl, FM_FMRI_HC_SERIAL_ID, &sp) == 0) { 527 if ((*serial = topo_hdl_strdup(thp, sp)) == NULL) 528 return (set_error(thp, ETOPO_PROP_NOMEM, err, 529 "topo_fmri_serial", prop)); 530 else 531 return (0); 532 } 533 534 if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, FM_FMRI_HC_SERIAL_ID, 535 NULL, &prop, err) < 0) 536 return (set_error(thp, *err, err, "topo_fmri_serial", NULL)); 537 538 if (nvlist_lookup_string(prop, TOPO_PROP_VAL_VAL, &sp) != 0) 539 return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_serial", 540 prop)); 541 542 if ((*serial = topo_hdl_strdup(thp, sp)) == NULL) 543 return (set_error(thp, ETOPO_PROP_NOMEM, err, 544 "topo_fmri_serial", prop)); 545 546 nvlist_free(prop); 547 548 return (0); 549 } 550 551 int topo_fmri_getprop(topo_hdl_t *thp, nvlist_t *nvl, const char *pg, 552 const char *pname, nvlist_t *args, nvlist_t **prop, 553 int *err) 554 { 555 *prop = NULL; 556 557 return (fmri_prop(thp, nvl, pg, pname, args, prop, err)); 558 } 559 560 int topo_fmri_setprop(topo_hdl_t *thp, nvlist_t *nvl, const char *pg, 561 nvlist_t *prop, int flag, nvlist_t *args, int *err) 562 { 563 int rv; 564 nvlist_t *in = NULL, *out = NULL; 565 tnode_t *rnode; 566 char *scheme; 567 568 if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme) != 0) 569 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 570 TOPO_METH_PROP_SET, in)); 571 572 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 573 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 574 TOPO_METH_PROP_SET, in)); 575 576 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 577 return (set_error(thp, ETOPO_FMRI_NVL, err, 578 TOPO_METH_PROP_SET, in)); 579 580 rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, nvl); 581 rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pg); 582 rv |= nvlist_add_nvlist(in, TOPO_PROP_VAL, prop); 583 rv |= nvlist_add_int32(in, TOPO_PROP_FLAG, (int32_t)flag); 584 if (args != NULL) 585 rv |= nvlist_add_nvlist(in, TOPO_PROP_PARGS, args); 586 if (rv != 0) 587 return (set_error(thp, ETOPO_FMRI_NVL, err, 588 TOPO_METH_PROP_SET, in)); 589 590 rv = topo_method_invoke(rnode, TOPO_METH_PROP_SET, 591 TOPO_METH_PROP_SET_VERSION, in, &out, err); 592 593 nvlist_free(in); 594 595 /* no return values */ 596 if (out != NULL) 597 nvlist_free(out); 598 599 if (rv) 600 return (-1); 601 602 return (0); 603 604 } 605 606 int 607 topo_fmri_getpgrp(topo_hdl_t *thp, nvlist_t *rsrc, const char *pgname, 608 nvlist_t **pgroup, int *err) 609 { 610 int rv; 611 nvlist_t *in = NULL; 612 tnode_t *rnode; 613 char *scheme; 614 615 if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0) 616 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 617 TOPO_METH_PROP_GET, in)); 618 619 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 620 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 621 TOPO_METH_PROP_GET, in)); 622 623 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 624 return (set_error(thp, ETOPO_FMRI_NVL, err, 625 TOPO_METH_PROP_GET, in)); 626 627 rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc); 628 rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pgname); 629 if (rv != 0) 630 return (set_error(thp, ETOPO_FMRI_NVL, err, 631 TOPO_METH_PROP_GET, in)); 632 633 *pgroup = NULL; 634 rv = topo_method_invoke(rnode, TOPO_METH_PGRP_GET, 635 TOPO_METH_PGRP_GET_VERSION, in, pgroup, err); 636 637 nvlist_free(in); 638 639 if (rv != 0) 640 return (-1); /* *err is set for us */ 641 642 if (*pgroup == NULL) 643 return (set_error(thp, ETOPO_PROP_NOENT, err, 644 TOPO_METH_PROP_GET, NULL)); 645 return (0); 646 } 647 648 int 649 topo_fmri_compare(topo_hdl_t *thp, nvlist_t *f1, nvlist_t *f2, int *err) 650 { 651 uint32_t compare; 652 char *scheme1, *scheme2; 653 nvlist_t *in; 654 nvlist_t *out = NULL; 655 tnode_t *rnode; 656 657 if (nvlist_lookup_string(f1, FM_FMRI_SCHEME, &scheme1) != 0) 658 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 659 TOPO_METH_COMPARE, NULL)); 660 if (nvlist_lookup_string(f2, FM_FMRI_SCHEME, &scheme2) != 0) 661 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 662 TOPO_METH_COMPARE, NULL)); 663 664 if (strcmp(scheme1, scheme2) != 0) 665 return (0); 666 667 if ((rnode = topo_hdl_root(thp, scheme1)) == NULL) 668 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 669 TOPO_METH_COMPARE, NULL)); 670 671 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 672 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE, 673 NULL)); 674 675 if (nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_NV1, f1) != 0 || 676 nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_NV2, f2) != 0) 677 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE, 678 in)); 679 680 if (topo_method_invoke(rnode, TOPO_METH_COMPARE, 681 TOPO_METH_COMPARE_VERSION, in, &out, err) < 0) 682 return (set_error(thp, *err, err, TOPO_METH_COMPARE, in)); 683 684 (void) nvlist_lookup_uint32(out, TOPO_METH_COMPARE_RET, &compare); 685 nvlist_free(out); 686 nvlist_free(in); 687 688 return (compare); 689 } 690 691 /* 692 * topo_fmri_create 693 * 694 * If possible, creates an FMRI of the requested version in the 695 * requested scheme. Args are passed as part of the inputs to the 696 * fmri-create method of the scheme. 697 */ 698 nvlist_t * 699 topo_fmri_create(topo_hdl_t *thp, const char *scheme, const char *name, 700 topo_instance_t inst, nvlist_t *nvl, int *err) 701 { 702 nvlist_t *ins; 703 nvlist_t *out; 704 tnode_t *rnode; 705 706 ins = out = NULL; 707 708 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 709 return (set_nverror(thp, ETOPO_METHOD_NOTSUP, err, 710 TOPO_METH_FMRI, NULL)); 711 712 if ((*err = topo_hdl_nvalloc(thp, &ins, NV_UNIQUE_NAME)) != 0) 713 return (set_nverror(thp, ETOPO_FMRI_NVL, err, 714 TOPO_METH_FMRI, NULL)); 715 716 if (nvlist_add_string(ins, TOPO_METH_FMRI_ARG_NAME, name) != 0 || 717 nvlist_add_uint32(ins, TOPO_METH_FMRI_ARG_INST, inst) != 0) { 718 return (set_nverror(thp, ETOPO_FMRI_NVL, err, 719 TOPO_METH_FMRI, ins)); 720 } 721 722 if (nvl != NULL && 723 nvlist_add_nvlist(ins, TOPO_METH_FMRI_ARG_NVL, nvl) != 0) { 724 return (set_nverror(thp, ETOPO_FMRI_NVL, err, 725 TOPO_METH_FMRI, ins)); 726 } 727 if (topo_method_invoke(rnode, 728 TOPO_METH_FMRI, TOPO_METH_FMRI_VERSION, ins, &out, err) != 0) { 729 return (set_nverror(thp, *err, err, TOPO_METH_FMRI, ins)); 730 } 731 nvlist_free(ins); 732 return (out); 733 } 734 735 /* 736 * These private utility functions are used by fmd to maintain its resource 737 * cache. Because hc instance numbers are not guaranteed, it's possible to 738 * have two different FMRI strings represent the same logical entity. These 739 * functions hide this implementation detail from unknowing consumers such as 740 * fmd. 741 * 742 * Ideally, we'd like to do a str2nvl() and then a full FMRI hash and 743 * comparison, but these functions are designed to be fast and efficient. 744 * Given that there is only a single hc node that has this property 745 * (ses-enclosure), we hard-code this behavior here. If there are more 746 * instances of this behavior in the future, this function could be made more 747 * generic. 748 * 749 * This code also handles changes in the server-id or revision fields of the hc 750 * FMRI, as these fields have no bearing on equivalence of FRUs. 751 */ 752 static ulong_t 753 topo_fmri_strhash_one(const char *fmri, size_t len) 754 { 755 ulong_t g, h = 0; 756 size_t i; 757 758 for (i = 0; i < len; i++) { 759 h = (h << 4) + fmri[i]; 760 761 if ((g = (h & 0xf0000000)) != 0) { 762 h ^= (g >> 24); 763 h ^= g; 764 } 765 } 766 767 return (h); 768 } 769 770 static const char * 771 topo_fmri_next_auth(const char *auth) 772 { 773 const char *colon, *slash; 774 775 colon = strchr(auth + 1, ':'); 776 slash = strchr(auth, '/'); 777 778 if (colon == NULL && slash == NULL) 779 return (NULL); 780 781 if (colon == NULL) 782 return (slash); 783 else if (slash < colon) 784 return (slash); 785 else 786 return (colon); 787 } 788 789 /* 790 * List of authority information we care about. Note that we explicitly ignore 791 * things that are properties of the chassis and not the resource itself: 792 * 793 * FM_FMRI_AUTH_PRODUCT_SN "product-sn" 794 * FM_FMRI_AUTH_PRODUCT "product-id" 795 * FM_FMRI_AUTH_DOMAIN "domain-id" 796 * FM_FMRI_AUTH_SERVER "server-id" 797 * FM_FMRI_AUTH_HOST "host-id" 798 * 799 * We also ignore the "revision" authority member, as that typically indicates 800 * the firmware revision and is not a static property of the FRU. This leaves 801 * the following interesting members: 802 * 803 * FM_FMRI_AUTH_CHASSIS "chassis-id" 804 * FM_FMRI_HC_SERIAL_ID "serial" 805 * FM_FMRI_HC_PART "part" 806 */ 807 typedef enum { 808 HC_AUTH_CHASSIS, 809 HC_AUTH_SERIAL, 810 HC_AUTH_PART, 811 HC_AUTH_MAX 812 } hc_auth_type_t; 813 814 static char *hc_auth_table[] = { 815 FM_FMRI_AUTH_CHASSIS, 816 FM_FMRI_HC_SERIAL_ID, 817 FM_FMRI_HC_PART 818 }; 819 820 /* 821 * Takes an authority member, with leading ":" and trailing "=", and returns 822 * one of the above types if it's one of the things we care about. If 823 * 'authlen' is specified, it is filled in with the length of the authority 824 * member, including leading and trailing characters. 825 */ 826 static hc_auth_type_t 827 hc_auth_to_type(const char *auth, size_t *authlen) 828 { 829 int i; 830 size_t len; 831 832 if (auth[0] != ':') 833 return (HC_AUTH_MAX); 834 835 for (i = 0; i < HC_AUTH_MAX; i++) { 836 len = strlen(hc_auth_table[i]); 837 838 if (strncmp(auth + 1, hc_auth_table[i], len) == 0 && 839 auth[len + 1] == '=') { 840 if (authlen) 841 *authlen = len + 2; 842 break; 843 } 844 } 845 846 return (i); 847 } 848 849 /*ARGSUSED*/ 850 ulong_t 851 topo_fmri_strhash_internal(topo_hdl_t *thp, const char *fmri, boolean_t noauth) 852 { 853 const char *auth, *next; 854 const char *enclosure; 855 ulong_t h; 856 hc_auth_type_t type; 857 858 if (strncmp(fmri, "hc://", 5) != 0) 859 return (topo_fmri_strhash_one(fmri, strlen(fmri))); 860 861 enclosure = strstr(fmri, SES_ENCLOSURE); 862 863 h = 0; 864 865 auth = next = fmri + 5; 866 while (*next != '/') { 867 auth = next; 868 869 if ((next = topo_fmri_next_auth(auth)) == NULL) { 870 next = auth; 871 break; 872 } 873 874 if ((type = hc_auth_to_type(auth, NULL)) == HC_AUTH_MAX) 875 continue; 876 877 if (!noauth || type == HC_AUTH_CHASSIS) 878 h += topo_fmri_strhash_one(auth, next - auth); 879 } 880 881 if (enclosure) { 882 next = enclosure + sizeof (SES_ENCLOSURE); 883 while (isdigit(*next)) 884 next++; 885 } 886 887 h += topo_fmri_strhash_one(next, strlen(next)); 888 889 return (h); 890 } 891 892 /*ARGSUSED*/ 893 ulong_t 894 topo_fmri_strhash(topo_hdl_t *thp, const char *fmri) 895 { 896 return (topo_fmri_strhash_internal(thp, fmri, B_FALSE)); 897 } 898 899 /*ARGSUSED*/ 900 ulong_t 901 topo_fmri_strhash_noauth(topo_hdl_t *thp, const char *fmri) 902 { 903 return (topo_fmri_strhash_internal(thp, fmri, B_TRUE)); 904 } 905 906 907 static void 908 topo_fmri_strcmp_parse_auth(const char *auth, const char *authtype[], 909 size_t authlen[]) 910 { 911 int i; 912 const char *next; 913 hc_auth_type_t type; 914 size_t len; 915 916 for (i = 0; i < HC_AUTH_MAX; i++) 917 authlen[i] = 0; 918 919 while (*auth != '/' && 920 (next = topo_fmri_next_auth(auth)) != NULL) { 921 if ((type = hc_auth_to_type(auth, &len)) == HC_AUTH_MAX) { 922 auth = next; 923 continue; 924 } 925 926 authtype[type] = auth + len; 927 authlen[type] = next - (auth + len); 928 auth = next; 929 } 930 } 931 932 /*ARGSUSED*/ 933 static boolean_t 934 topo_fmri_strcmp_internal(topo_hdl_t *thp, const char *a, const char *b, 935 boolean_t noauth) 936 { 937 const char *fmria, *fmrib; 938 const char *autha[HC_AUTH_MAX], *authb[HC_AUTH_MAX]; 939 size_t authlena[HC_AUTH_MAX], authlenb[HC_AUTH_MAX]; 940 int i; 941 942 /* 943 * For non-hc FMRIs, we don't do anything. 944 */ 945 if (strncmp(a, "hc://", 5) != 0 || 946 strncmp(b, "hc://", 5) != 0) 947 return (strcmp(a, b) == 0); 948 949 /* 950 * Get the portion of the FMRI independent of the authority 951 * information. 952 */ 953 fmria = strchr(a + 5, '/'); 954 fmrib = strchr(b + 5, '/'); 955 if (fmria == NULL || fmrib == NULL) 956 return (strcmp(a, b)); 957 fmria++; 958 fmrib++; 959 960 /* 961 * Comparing fmri authority information is a bit of a pain, because 962 * there may be a different number of members, and they can (but 963 * shouldn't be) in a different order. We need to create a copy of the 964 * authority and parse it into pieces. Because this function is 965 * intended to be fast (and not necessarily extensible), we hard-code 966 * the list of possible authority members in an enum and parse it into 967 * an array. 968 */ 969 topo_fmri_strcmp_parse_auth(a + 5, autha, authlena); 970 topo_fmri_strcmp_parse_auth(b + 5, authb, authlenb); 971 972 for (i = 0; i < HC_AUTH_MAX; i++) { 973 if (noauth && i != HC_AUTH_CHASSIS) 974 continue; 975 976 if (authlena[i] == 0 && authlenb[i] == 0) 977 continue; 978 979 if (authlena[i] != authlenb[i]) 980 return (B_FALSE); 981 982 if (strncmp(autha[i], authb[i], authlena[i]) != 0) 983 return (B_FALSE); 984 } 985 986 /* 987 * If this is rooted at a ses-enclosure node, skip past the instance 988 * number, as it has no meaning. 989 */ 990 if (strncmp(fmria, SES_ENCLOSURE, sizeof (SES_ENCLOSURE) - 1) == 0 && 991 strncmp(fmrib, SES_ENCLOSURE, sizeof (SES_ENCLOSURE) - 1) == 0) { 992 fmria += sizeof (SES_ENCLOSURE); 993 fmrib += sizeof (SES_ENCLOSURE); 994 995 while (isdigit(*fmria)) 996 fmria++; 997 while (isdigit(*fmrib)) 998 fmrib++; 999 } 1000 1001 return (strcmp(fmria, fmrib) == 0); 1002 } 1003 1004 /*ARGSUSED*/ 1005 boolean_t 1006 topo_fmri_strcmp(topo_hdl_t *thp, const char *a, const char *b) 1007 { 1008 return (topo_fmri_strcmp_internal(thp, a, b, B_FALSE)); 1009 } 1010 1011 /*ARGSUSED*/ 1012 boolean_t 1013 topo_fmri_strcmp_noauth(topo_hdl_t *thp, const char *a, const char *b) 1014 { 1015 return (topo_fmri_strcmp_internal(thp, a, b, B_TRUE)); 1016 } 1017 1018 int 1019 topo_fmri_facility(topo_hdl_t *thp, nvlist_t *rsrc, const char *fac_type, 1020 uint32_t fac_subtype, topo_walk_cb_t cb, void *cb_args, int *err) 1021 { 1022 int rv; 1023 nvlist_t *in = NULL, *out; 1024 tnode_t *rnode; 1025 char *scheme; 1026 1027 if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0) 1028 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 1029 TOPO_METH_PROP_GET, in)); 1030 1031 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 1032 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 1033 TOPO_METH_PROP_GET, in)); 1034 1035 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 1036 return (set_error(thp, ETOPO_FMRI_NVL, err, 1037 TOPO_METH_PROP_GET, in)); 1038 1039 rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc); 1040 rv |= nvlist_add_string(in, FM_FMRI_FACILITY_TYPE, fac_type); 1041 rv |= nvlist_add_uint32(in, "type", fac_subtype); 1042 #ifdef _LP64 1043 rv |= nvlist_add_uint64(in, "callback", (uint64_t)cb); 1044 rv |= nvlist_add_uint64(in, "callback-args", (uint64_t)cb_args); 1045 #else 1046 rv |= nvlist_add_uint32(in, "callback", (uint32_t)cb); 1047 rv |= nvlist_add_uint32(in, "callback-args", (uint32_t)cb_args); 1048 #endif 1049 if (rv != 0) 1050 return (set_error(thp, ETOPO_FMRI_NVL, err, 1051 TOPO_METH_PROP_GET, in)); 1052 1053 rv = topo_method_invoke(rnode, TOPO_METH_FACILITY, 1054 TOPO_METH_FACILITY_VERSION, in, &out, err); 1055 1056 nvlist_free(in); 1057 1058 if (rv != 0) 1059 return (-1); /* *err is set for us */ 1060 1061 return (0); 1062 } 1063