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 static ulong_t 750 topo_fmri_strhash_one(const char *fmri, size_t len) 751 { 752 ulong_t g, h = 0; 753 size_t i; 754 755 for (i = 0; i < len; i++) { 756 h = (h << 4) + fmri[i]; 757 758 if ((g = (h & 0xf0000000)) != 0) { 759 h ^= (g >> 24); 760 h ^= g; 761 } 762 } 763 764 return (h); 765 } 766 767 /*ARGSUSED*/ 768 ulong_t 769 topo_fmri_strhash(topo_hdl_t *thp, const char *fmri) 770 { 771 char *e; 772 ulong_t h; 773 774 if (strncmp(fmri, "hc://", 5) != 0 || 775 (e = strstr(fmri, SES_ENCLOSURE)) == NULL) 776 return (topo_fmri_strhash_one(fmri, strlen(fmri))); 777 778 h = topo_fmri_strhash_one(fmri, e - fmri); 779 e += sizeof (SES_ENCLOSURE); 780 781 while (isdigit(*e)) 782 e++; 783 784 h += topo_fmri_strhash_one(e, strlen(e)); 785 786 return (h); 787 } 788 789 /*ARGSUSED*/ 790 boolean_t 791 topo_fmri_strcmp(topo_hdl_t *thp, const char *a, const char *b) 792 { 793 char *ea, *eb; 794 795 if (strncmp(a, "hc://", 5) != 0 || 796 strncmp(b, "hc://", 5) != 0 || 797 (ea = strstr(a, SES_ENCLOSURE)) == NULL || 798 (eb = strstr(b, SES_ENCLOSURE)) == NULL) 799 return (strcmp(a, b) == 0); 800 801 if ((ea - a) != (eb - b)) 802 return (B_FALSE); 803 804 if (strncmp(a, b, ea - a) != 0) 805 return (B_FALSE); 806 807 ea += sizeof (SES_ENCLOSURE); 808 eb += sizeof (SES_ENCLOSURE); 809 810 while (isdigit(*ea)) 811 ea++; 812 while (isdigit(*eb)) 813 eb++; 814 815 return (strcmp(ea, eb) == 0); 816 } 817 818 int 819 topo_fmri_facility(topo_hdl_t *thp, nvlist_t *rsrc, const char *fac_type, 820 uint32_t fac_subtype, topo_walk_cb_t cb, void *cb_args, int *err) 821 { 822 int rv; 823 nvlist_t *in = NULL, *out; 824 tnode_t *rnode; 825 char *scheme; 826 827 if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0) 828 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 829 TOPO_METH_PROP_GET, in)); 830 831 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 832 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 833 TOPO_METH_PROP_GET, in)); 834 835 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 836 return (set_error(thp, ETOPO_FMRI_NVL, err, 837 TOPO_METH_PROP_GET, in)); 838 839 rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc); 840 rv |= nvlist_add_string(in, FM_FMRI_FACILITY_TYPE, fac_type); 841 rv |= nvlist_add_uint32(in, "type", fac_subtype); 842 #ifdef _LP64 843 rv |= nvlist_add_uint64(in, "callback", (uint64_t)cb); 844 rv |= nvlist_add_uint64(in, "callback-args", (uint64_t)cb_args); 845 #else 846 rv |= nvlist_add_uint32(in, "callback", (uint32_t)cb); 847 rv |= nvlist_add_uint32(in, "callback-args", (uint32_t)cb_args); 848 #endif 849 if (rv != 0) 850 return (set_error(thp, ETOPO_FMRI_NVL, err, 851 TOPO_METH_PROP_GET, in)); 852 853 rv = topo_method_invoke(rnode, TOPO_METH_FACILITY, 854 TOPO_METH_FACILITY_VERSION, in, &out, err); 855 856 nvlist_free(in); 857 858 if (rv != 0) 859 return (-1); /* *err is set for us */ 860 861 return (0); 862 } 863