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 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <ctype.h> 30 #include <string.h> 31 #include <limits.h> 32 #include <fm/topo_mod.h> 33 #include <fm/fmd_fmri.h> 34 #include <sys/fm/protocol.h> 35 #include <topo_alloc.h> 36 #include <topo_error.h> 37 #include <topo_hc.h> 38 #include <topo_method.h> 39 #include <topo_subr.h> 40 #include <topo_string.h> 41 42 /* 43 * Topology node properties and method operations may be accessed by FMRI. 44 * The FMRI used to perform property look-ups and method operations is 45 * the FMRI contained in the matching topology node's protocol property 46 * grouping for the resource property. The full range of fmd(1M) 47 * scheme plugin operations are supported as long as a backend method is 48 * supplied by a scheme-specific enumerator or the enumerator module that 49 * created the matching topology node. Support for fmd scheme operations 50 * include: 51 * 52 * - expand 53 * - present 54 * - replaced 55 * - contains 56 * - unusable 57 * - service_state 58 * - nvl2str 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_hdl_nvalloc(thp, &out, NV_UNIQUE_NAME) != 0) 258 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS, 259 out)); 260 261 if (topo_method_invoke(rnode, TOPO_METH_CONTAINS, 262 TOPO_METH_CONTAINS_VERSION, in, &out, err) < 0) { 263 nvlist_free(out); 264 return (set_error(thp, *err, err, TOPO_METH_CONTAINS, in)); 265 } 266 267 (void) nvlist_lookup_uint32(out, TOPO_METH_CONTAINS_RET, &contains); 268 nvlist_free(in); 269 nvlist_free(out); 270 271 return (contains); 272 } 273 274 int 275 topo_fmri_unusable(topo_hdl_t *thp, nvlist_t *fmri, int *err) 276 { 277 char *scheme; 278 uint32_t unusable = 0; 279 nvlist_t *out = NULL; 280 tnode_t *rnode; 281 282 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 283 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 284 TOPO_METH_UNUSABLE, out)); 285 286 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 287 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 288 TOPO_METH_UNUSABLE, out)); 289 290 if (topo_method_invoke(rnode, TOPO_METH_UNUSABLE, 291 TOPO_METH_UNUSABLE_VERSION, fmri, &out, err) < 0) 292 return (set_error(thp, *err, err, TOPO_METH_UNUSABLE, out)); 293 294 (void) nvlist_lookup_uint32(out, TOPO_METH_UNUSABLE_RET, &unusable); 295 nvlist_free(out); 296 297 return (unusable); 298 } 299 300 int 301 topo_fmri_service_state(topo_hdl_t *thp, nvlist_t *fmri, int *err) 302 { 303 char *scheme; 304 uint32_t service_state = FMD_SERVICE_STATE_UNKNOWN; 305 nvlist_t *out = NULL; 306 tnode_t *rnode; 307 308 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 309 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 310 TOPO_METH_SERVICE_STATE, out)); 311 312 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 313 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 314 TOPO_METH_SERVICE_STATE, out)); 315 316 if (topo_method_invoke(rnode, TOPO_METH_SERVICE_STATE, 317 TOPO_METH_SERVICE_STATE_VERSION, fmri, &out, err) < 0) 318 return (set_error(thp, *err, err, TOPO_METH_SERVICE_STATE, 319 out)); 320 321 (void) nvlist_lookup_uint32(out, TOPO_METH_SERVICE_STATE_RET, 322 &service_state); 323 nvlist_free(out); 324 325 return (service_state); 326 } 327 328 int 329 topo_fmri_expand(topo_hdl_t *thp, nvlist_t *fmri, int *err) 330 { 331 char *scheme; 332 nvlist_t *out = NULL; 333 tnode_t *rnode; 334 335 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 336 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 337 TOPO_METH_EXPAND, out)); 338 339 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 340 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 341 TOPO_METH_EXPAND, out)); 342 343 if (topo_method_invoke(rnode, TOPO_METH_EXPAND, 344 TOPO_METH_EXPAND_VERSION, fmri, &out, err) != 0) 345 return (set_error(thp, *err, err, TOPO_METH_EXPAND, out)); 346 347 return (0); 348 } 349 350 static int 351 fmri_prop(topo_hdl_t *thp, nvlist_t *rsrc, const char *pgname, 352 const char *pname, nvlist_t *args, nvlist_t **prop, 353 int *err) 354 { 355 int rv; 356 nvlist_t *in = NULL; 357 tnode_t *rnode; 358 char *scheme; 359 360 if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0) 361 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 362 TOPO_METH_PROP_GET, in)); 363 364 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 365 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 366 TOPO_METH_PROP_GET, in)); 367 368 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 369 return (set_error(thp, ETOPO_FMRI_NVL, err, 370 TOPO_METH_PROP_GET, in)); 371 372 rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc); 373 rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pgname); 374 rv |= nvlist_add_string(in, TOPO_PROP_VAL_NAME, pname); 375 if (args != NULL) 376 rv |= nvlist_add_nvlist(in, TOPO_PROP_PARGS, args); 377 if (rv != 0) 378 return (set_error(thp, ETOPO_FMRI_NVL, err, 379 TOPO_METH_PROP_GET, in)); 380 381 *prop = NULL; 382 rv = topo_method_invoke(rnode, TOPO_METH_PROP_GET, 383 TOPO_METH_PROP_GET_VERSION, in, prop, err); 384 385 nvlist_free(in); 386 387 if (rv != 0) 388 return (-1); /* *err is set for us */ 389 390 if (*prop == NULL) 391 return (set_error(thp, ETOPO_PROP_NOENT, err, 392 TOPO_METH_PROP_GET, NULL)); 393 return (0); 394 } 395 396 int 397 topo_fmri_asru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **asru, int *err) 398 { 399 nvlist_t *ap, *prop = NULL; 400 401 if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_ASRU, 402 nvl, &prop, err) < 0) 403 return (set_error(thp, *err, err, "topo_fmri_asru", NULL)); 404 405 if (nvlist_lookup_nvlist(prop, TOPO_PROP_VAL_VAL, &ap) != 0) 406 return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_asru", 407 prop)); 408 409 if (topo_hdl_nvdup(thp, ap, asru) < 0) 410 return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_asru", 411 prop)); 412 413 nvlist_free(prop); 414 415 return (0); 416 } 417 418 int 419 topo_fmri_fru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **fru, int *err) 420 { 421 nvlist_t *fp, *prop = NULL; 422 423 if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU, 424 nvl, &prop, err) < 0) 425 return (set_error(thp, *err, err, "topo_fmri_fru", NULL)); 426 427 if (nvlist_lookup_nvlist(prop, TOPO_PROP_VAL_VAL, &fp) != 0) 428 return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_fru", 429 prop)); 430 431 if (topo_hdl_nvdup(thp, fp, fru) < 0) 432 return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_fru", 433 prop)); 434 435 nvlist_free(prop); 436 437 return (0); 438 } 439 440 int 441 topo_fmri_label(topo_hdl_t *thp, nvlist_t *nvl, char **label, int *err) 442 { 443 nvlist_t *prop = NULL; 444 char *lp; 445 446 if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_LABEL, 447 NULL, &prop, err) < 0) 448 return (set_error(thp, *err, err, "topo_fmri_label", NULL)); 449 450 if (nvlist_lookup_string(prop, TOPO_PROP_VAL_VAL, &lp) != 0) 451 return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_label", 452 prop)); 453 454 if ((*label = topo_hdl_strdup(thp, lp)) == NULL) 455 return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_label", 456 prop)); 457 458 nvlist_free(prop); 459 460 return (0); 461 } 462 463 int 464 topo_fmri_serial(topo_hdl_t *thp, nvlist_t *nvl, char **serial, int *err) 465 { 466 nvlist_t *prop = NULL; 467 char *sp; 468 469 if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, FM_FMRI_HC_SERIAL_ID, 470 NULL, &prop, err) < 0) 471 return (set_error(thp, *err, err, "topo_fmri_serial", NULL)); 472 473 if (nvlist_lookup_string(prop, TOPO_PROP_VAL_VAL, &sp) != 0) 474 return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_serial", 475 prop)); 476 477 if ((*serial = topo_hdl_strdup(thp, sp)) == NULL) 478 return (set_error(thp, ETOPO_PROP_NOMEM, err, 479 "topo_fmri_serial", prop)); 480 481 nvlist_free(prop); 482 483 return (0); 484 } 485 486 int topo_fmri_getprop(topo_hdl_t *thp, nvlist_t *nvl, const char *pg, 487 const char *pname, nvlist_t *args, nvlist_t **prop, 488 int *err) 489 { 490 *prop = NULL; 491 492 return (fmri_prop(thp, nvl, pg, pname, args, prop, err)); 493 } 494 495 int topo_fmri_setprop(topo_hdl_t *thp, nvlist_t *nvl, const char *pg, 496 nvlist_t *prop, int flag, nvlist_t *args, int *err) 497 { 498 int rv; 499 nvlist_t *in = NULL, *out = NULL; 500 tnode_t *rnode; 501 char *scheme; 502 503 if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme) != 0) 504 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 505 TOPO_METH_PROP_SET, in)); 506 507 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 508 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 509 TOPO_METH_PROP_SET, in)); 510 511 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 512 return (set_error(thp, ETOPO_FMRI_NVL, err, 513 TOPO_METH_PROP_SET, in)); 514 515 rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, nvl); 516 rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pg); 517 rv |= nvlist_add_nvlist(in, TOPO_PROP_VAL, prop); 518 rv |= nvlist_add_int32(in, TOPO_PROP_FLAG, (int32_t)flag); 519 if (args != NULL) 520 rv |= nvlist_add_nvlist(in, TOPO_PROP_PARGS, args); 521 if (rv != 0) 522 return (set_error(thp, ETOPO_FMRI_NVL, err, 523 TOPO_METH_PROP_SET, in)); 524 525 rv = topo_method_invoke(rnode, TOPO_METH_PROP_SET, 526 TOPO_METH_PROP_SET_VERSION, in, &out, err); 527 528 nvlist_free(in); 529 530 /* no return values */ 531 if (out != NULL) 532 nvlist_free(out); 533 534 if (rv) 535 return (-1); 536 537 return (0); 538 539 } 540 541 int 542 topo_fmri_getpgrp(topo_hdl_t *thp, nvlist_t *rsrc, const char *pgname, 543 nvlist_t **pgroup, int *err) 544 { 545 int rv; 546 nvlist_t *in = NULL; 547 tnode_t *rnode; 548 char *scheme; 549 550 if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0) 551 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 552 TOPO_METH_PROP_GET, in)); 553 554 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 555 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 556 TOPO_METH_PROP_GET, in)); 557 558 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 559 return (set_error(thp, ETOPO_FMRI_NVL, err, 560 TOPO_METH_PROP_GET, in)); 561 562 rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc); 563 rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pgname); 564 if (rv != 0) 565 return (set_error(thp, ETOPO_FMRI_NVL, err, 566 TOPO_METH_PROP_GET, in)); 567 568 *pgroup = NULL; 569 rv = topo_method_invoke(rnode, TOPO_METH_PGRP_GET, 570 TOPO_METH_PGRP_GET_VERSION, in, pgroup, err); 571 572 nvlist_free(in); 573 574 if (rv != 0) 575 return (-1); /* *err is set for us */ 576 577 if (*pgroup == NULL) 578 return (set_error(thp, ETOPO_PROP_NOENT, err, 579 TOPO_METH_PROP_GET, NULL)); 580 return (0); 581 } 582 583 int 584 topo_fmri_compare(topo_hdl_t *thp, nvlist_t *f1, nvlist_t *f2, int *err) 585 { 586 uint32_t compare; 587 char *scheme1, *scheme2; 588 nvlist_t *in; 589 nvlist_t *out = NULL; 590 tnode_t *rnode; 591 592 if (nvlist_lookup_string(f1, FM_FMRI_SCHEME, &scheme1) != 0) 593 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 594 TOPO_METH_COMPARE, NULL)); 595 if (nvlist_lookup_string(f2, FM_FMRI_SCHEME, &scheme2) != 0) 596 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 597 TOPO_METH_COMPARE, NULL)); 598 599 if (strcmp(scheme1, scheme2) != 0) 600 return (0); 601 602 if ((rnode = topo_hdl_root(thp, scheme1)) == NULL) 603 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 604 TOPO_METH_COMPARE, NULL)); 605 606 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 607 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE, 608 NULL)); 609 610 if (nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_NV1, f1) != 0 || 611 nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_NV2, f2) != 0) 612 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE, 613 in)); 614 615 if (topo_method_invoke(rnode, TOPO_METH_COMPARE, 616 TOPO_METH_COMPARE_VERSION, in, &out, err) < 0) 617 return (set_error(thp, *err, err, TOPO_METH_COMPARE, in)); 618 619 (void) nvlist_lookup_uint32(out, TOPO_METH_COMPARE_RET, &compare); 620 nvlist_free(out); 621 nvlist_free(in); 622 623 return (compare); 624 } 625 626 /* 627 * topo_fmri_create 628 * 629 * If possible, creates an FMRI of the requested version in the 630 * requested scheme. Args are passed as part of the inputs to the 631 * fmri-create method of the scheme. 632 */ 633 nvlist_t * 634 topo_fmri_create(topo_hdl_t *thp, const char *scheme, const char *name, 635 topo_instance_t inst, nvlist_t *nvl, int *err) 636 { 637 nvlist_t *ins; 638 nvlist_t *out; 639 tnode_t *rnode; 640 641 ins = out = NULL; 642 643 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 644 return (set_nverror(thp, ETOPO_METHOD_NOTSUP, err, 645 TOPO_METH_FMRI, NULL)); 646 647 if ((*err = topo_hdl_nvalloc(thp, &ins, NV_UNIQUE_NAME)) != 0) 648 return (set_nverror(thp, ETOPO_FMRI_NVL, err, 649 TOPO_METH_FMRI, NULL)); 650 651 if (nvlist_add_string(ins, TOPO_METH_FMRI_ARG_NAME, name) != 0 || 652 nvlist_add_uint32(ins, TOPO_METH_FMRI_ARG_INST, inst) != 0) { 653 return (set_nverror(thp, ETOPO_FMRI_NVL, err, 654 TOPO_METH_FMRI, ins)); 655 } 656 657 if (nvl != NULL && 658 nvlist_add_nvlist(ins, TOPO_METH_FMRI_ARG_NVL, nvl) != 0) { 659 return (set_nverror(thp, ETOPO_FMRI_NVL, err, 660 TOPO_METH_FMRI, ins)); 661 } 662 if (topo_method_invoke(rnode, 663 TOPO_METH_FMRI, TOPO_METH_FMRI_VERSION, ins, &out, err) != 0) { 664 return (set_nverror(thp, *err, err, TOPO_METH_FMRI, ins)); 665 } 666 nvlist_free(ins); 667 return (out); 668 } 669 670 /* 671 * These private utility functions are used by fmd to maintain its resource 672 * cache. Because hc instance numbers are not guaranteed, it's possible to 673 * have two different FMRI strings represent the same logical entity. These 674 * functions hide this implementation detail from unknowing consumers such as 675 * fmd. 676 * 677 * Ideally, we'd like to do a str2nvl() and then a full FMRI hash and 678 * comparison, but these functions are designed to be fast and efficient. 679 * Given that there is only a single hc node that has this property 680 * (ses-enclosure), we hard-code this behavior here. If there are more 681 * instances of this behavior in the future, this function could be made more 682 * generic. 683 */ 684 static ulong_t 685 topo_fmri_strhash_one(const char *fmri, size_t len) 686 { 687 ulong_t g, h = 0; 688 size_t i; 689 690 for (i = 0; i < len; i++) { 691 h = (h << 4) + fmri[i]; 692 693 if ((g = (h & 0xf0000000)) != 0) { 694 h ^= (g >> 24); 695 h ^= g; 696 } 697 } 698 699 return (h); 700 } 701 702 /*ARGSUSED*/ 703 ulong_t 704 topo_fmri_strhash(topo_hdl_t *thp, const char *fmri) 705 { 706 char *e; 707 ulong_t h; 708 709 if (strncmp(fmri, "hc://", 5) != 0 || 710 (e = strstr(fmri, SES_ENCLOSURE)) == NULL) 711 return (topo_fmri_strhash_one(fmri, strlen(fmri))); 712 713 h = topo_fmri_strhash_one(fmri, e - fmri); 714 e += sizeof (SES_ENCLOSURE); 715 716 while (isdigit(*e)) 717 e++; 718 719 h += topo_fmri_strhash_one(e, strlen(e)); 720 721 return (h); 722 } 723 724 /*ARGSUSED*/ 725 boolean_t 726 topo_fmri_strcmp(topo_hdl_t *thp, const char *a, const char *b) 727 { 728 char *ea, *eb; 729 730 if (strncmp(a, "hc://", 5) != 0 || 731 strncmp(b, "hc://", 5) != 0 || 732 (ea = strstr(a, SES_ENCLOSURE)) == NULL || 733 (eb = strstr(b, SES_ENCLOSURE)) == NULL) 734 return (strcmp(a, b) == 0); 735 736 if ((ea - a) != (eb - b)) 737 return (B_FALSE); 738 739 if (strncmp(a, b, ea - a) != 0) 740 return (B_FALSE); 741 742 ea += sizeof (SES_ENCLOSURE); 743 eb += sizeof (SES_ENCLOSURE); 744 745 while (isdigit(*ea)) 746 ea++; 747 while (isdigit(*eb)) 748 eb++; 749 750 return (strcmp(ea, eb) == 0); 751 } 752 753 int 754 topo_fmri_facility(topo_hdl_t *thp, nvlist_t *rsrc, const char *fac_type, 755 uint32_t fac_subtype, topo_walk_cb_t cb, void *cb_args, int *err) 756 { 757 int rv; 758 nvlist_t *in = NULL, *out; 759 tnode_t *rnode; 760 char *scheme; 761 762 if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0) 763 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 764 TOPO_METH_PROP_GET, in)); 765 766 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 767 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 768 TOPO_METH_PROP_GET, in)); 769 770 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 771 return (set_error(thp, ETOPO_FMRI_NVL, err, 772 TOPO_METH_PROP_GET, in)); 773 774 rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc); 775 rv |= nvlist_add_string(in, FM_FMRI_FACILITY_TYPE, fac_type); 776 rv |= nvlist_add_uint32(in, "type", fac_subtype); 777 #ifdef _LP64 778 rv |= nvlist_add_uint64(in, "callback", (uint64_t)cb); 779 rv |= nvlist_add_uint64(in, "callback-args", (uint64_t)cb_args); 780 #else 781 rv |= nvlist_add_uint32(in, "callback", (uint32_t)cb); 782 rv |= nvlist_add_uint32(in, "callback-args", (uint32_t)cb_args); 783 #endif 784 if (rv != 0) 785 return (set_error(thp, ETOPO_FMRI_NVL, err, 786 TOPO_METH_PROP_GET, in)); 787 788 rv = topo_method_invoke(rnode, TOPO_METH_FACILITY, 789 TOPO_METH_FACILITY_VERSION, in, &out, err); 790 791 nvlist_free(in); 792 793 if (rv != 0) 794 return (-1); /* *err is set for us */ 795 796 return (0); 797 } 798