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 <sys/fm/protocol.h> 34 #include <topo_alloc.h> 35 #include <topo_error.h> 36 #include <topo_hc.h> 37 #include <topo_method.h> 38 #include <topo_subr.h> 39 #include <topo_string.h> 40 41 /* 42 * Topology node properties and method operations may be accessed by FMRI. 43 * The FMRI used to perform property look-ups and method operations is 44 * the FMRI contained in the matching topology node's protocol property 45 * grouping for the resource property. The full range of fmd(1M) 46 * scheme plugin operations are supported as long as a backend method is 47 * supplied by a scheme-specific enumerator or the enumerator module that 48 * created the matching topology node. Support for fmd scheme operations 49 * include: 50 * 51 * - expand 52 * - present 53 * - contains 54 * - unusable 55 * - nvl2str 56 * 57 * In addition, the following operations are supported per-FMRI: 58 * 59 * - str2nvl: convert string-based FMRI to nvlist 60 * - compare: compare two FMRIs 61 * - asru: lookup associated ASRU property by FMRI 62 * - fru: lookup associated FRU by FMRI 63 * - create: an FMRI nvlist by scheme type 64 * - propery lookup 65 * 66 * These routines may only be called by consumers of a topology snapshot. 67 * They may not be called by libtopo enumerator or method modules. 68 */ 69 70 /*ARGSUSED*/ 71 static int 72 set_error(topo_hdl_t *thp, int err, int *errp, char *method, nvlist_t *nvlp) 73 { 74 if (nvlp != NULL) 75 nvlist_free(nvlp); 76 77 topo_dprintf(thp, TOPO_DBG_ERR, "%s failed: %s\n", method, 78 topo_strerror(err)); 79 80 *errp = err; 81 return (-1); 82 } 83 84 /*ARGSUSED*/ 85 static nvlist_t * 86 set_nverror(topo_hdl_t *thp, int err, int *errp, char *method, nvlist_t *nvlp) 87 { 88 if (nvlp != NULL) 89 nvlist_free(nvlp); 90 91 topo_dprintf(thp, TOPO_DBG_ERR, "%s failed: %s\n", method, 92 topo_strerror(err)); 93 94 *errp = err; 95 return (NULL); 96 } 97 98 int 99 topo_fmri_nvl2str(topo_hdl_t *thp, nvlist_t *fmri, char **fmristr, int *err) 100 { 101 char *scheme, *str; 102 nvlist_t *out = NULL; 103 tnode_t *rnode; 104 105 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 106 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 107 TOPO_METH_NVL2STR, out)); 108 109 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 110 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 111 TOPO_METH_NVL2STR, out)); 112 113 if (topo_method_invoke(rnode, TOPO_METH_NVL2STR, 114 TOPO_METH_NVL2STR_VERSION, fmri, &out, err) != 0) 115 return (set_error(thp, *err, err, TOPO_METH_NVL2STR, out)); 116 117 if (out == NULL || nvlist_lookup_string(out, "fmri-string", &str) != 0) 118 return (set_error(thp, ETOPO_METHOD_INVAL, err, 119 TOPO_METH_NVL2STR, out)); 120 121 if ((*fmristr = topo_hdl_strdup(thp, str)) == NULL) 122 return (set_error(thp, ETOPO_NOMEM, err, 123 TOPO_METH_NVL2STR, out)); 124 125 nvlist_free(out); 126 127 return (0); 128 } 129 130 int 131 topo_fmri_str2nvl(topo_hdl_t *thp, const char *fmristr, nvlist_t **fmri, 132 int *err) 133 { 134 char *f, buf[PATH_MAX]; 135 nvlist_t *out = NULL, *in = NULL; 136 tnode_t *rnode; 137 138 (void) strlcpy(buf, fmristr, sizeof (buf)); 139 if ((f = strchr(buf, ':')) == NULL) 140 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 141 TOPO_METH_STR2NVL, in)); 142 143 *f = '\0'; /* strip trailing FMRI path */ 144 145 if ((rnode = topo_hdl_root(thp, buf)) == NULL) 146 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 147 TOPO_METH_STR2NVL, in)); 148 149 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 150 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_STR2NVL, 151 in)); 152 153 if (nvlist_add_string(in, "fmri-string", fmristr) != 0) 154 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_STR2NVL, 155 in)); 156 157 if (topo_method_invoke(rnode, TOPO_METH_STR2NVL, 158 TOPO_METH_STR2NVL_VERSION, in, &out, err) != 0) 159 return (set_error(thp, *err, err, TOPO_METH_STR2NVL, in)); 160 161 nvlist_free(in); 162 163 if (out == NULL || 164 topo_hdl_nvdup(thp, out, fmri) != 0) 165 return (set_error(thp, ETOPO_FMRI_NVL, err, 166 TOPO_METH_STR2NVL, out)); 167 168 nvlist_free(out); 169 170 return (0); 171 } 172 173 int 174 topo_fmri_present(topo_hdl_t *thp, nvlist_t *fmri, int *err) 175 { 176 uint32_t present = 0; 177 char *scheme; 178 nvlist_t *out = NULL; 179 tnode_t *rnode; 180 181 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 182 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 183 TOPO_METH_PRESENT, out)); 184 185 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 186 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 187 TOPO_METH_PRESENT, out)); 188 189 if (topo_method_invoke(rnode, TOPO_METH_PRESENT, 190 TOPO_METH_PRESENT_VERSION, fmri, &out, err) < 0) { 191 (void) set_error(thp, *err, err, TOPO_METH_PRESENT, out); 192 return (present); 193 } 194 195 (void) nvlist_lookup_uint32(out, TOPO_METH_PRESENT_RET, &present); 196 nvlist_free(out); 197 198 return (present); 199 } 200 201 int 202 topo_fmri_contains(topo_hdl_t *thp, nvlist_t *fmri, nvlist_t *subfmri, int *err) 203 { 204 uint32_t contains; 205 char *scheme; 206 nvlist_t *in = NULL, *out = NULL; 207 tnode_t *rnode; 208 209 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 210 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 211 TOPO_METH_CONTAINS, NULL)); 212 213 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 214 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 215 TOPO_METH_CONTAINS, NULL)); 216 217 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 218 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS, 219 NULL)); 220 221 if (nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_FMRI, fmri) != 0 || 222 nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_SUBFMRI, subfmri) != 0) 223 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS, 224 in)); 225 226 if (topo_hdl_nvalloc(thp, &out, NV_UNIQUE_NAME) != 0) 227 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS, 228 out)); 229 230 if (topo_method_invoke(rnode, TOPO_METH_CONTAINS, 231 TOPO_METH_CONTAINS_VERSION, in, &out, err) < 0) { 232 nvlist_free(out); 233 return (set_error(thp, *err, err, TOPO_METH_CONTAINS, in)); 234 } 235 236 (void) nvlist_lookup_uint32(out, TOPO_METH_CONTAINS_RET, &contains); 237 nvlist_free(in); 238 nvlist_free(out); 239 240 return (contains); 241 } 242 243 int 244 topo_fmri_unusable(topo_hdl_t *thp, nvlist_t *fmri, int *err) 245 { 246 char *scheme; 247 uint32_t unusable = 0; 248 nvlist_t *out = NULL; 249 tnode_t *rnode; 250 251 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) 252 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 253 TOPO_METH_UNUSABLE, out)); 254 255 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 256 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 257 TOPO_METH_UNUSABLE, out)); 258 259 if (topo_method_invoke(rnode, TOPO_METH_UNUSABLE, 260 TOPO_METH_UNUSABLE_VERSION, fmri, &out, err) < 0) 261 return (set_error(thp, *err, err, TOPO_METH_UNUSABLE, out)); 262 263 (void) nvlist_lookup_uint32(out, TOPO_METH_UNUSABLE_RET, &unusable); 264 nvlist_free(out); 265 266 return (unusable); 267 } 268 269 int 270 topo_fmri_expand(topo_hdl_t *thp, nvlist_t *fmri, int *err) 271 { 272 char *scheme; 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_EXPAND, out)); 279 280 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 281 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 282 TOPO_METH_EXPAND, out)); 283 284 if (topo_method_invoke(rnode, TOPO_METH_EXPAND, 285 TOPO_METH_EXPAND_VERSION, fmri, &out, err) != 0) 286 return (set_error(thp, *err, err, TOPO_METH_EXPAND, out)); 287 288 return (0); 289 } 290 291 static int 292 fmri_prop(topo_hdl_t *thp, nvlist_t *rsrc, const char *pgname, 293 const char *pname, nvlist_t *args, nvlist_t **prop, 294 int *err) 295 { 296 int rv; 297 nvlist_t *in = NULL; 298 tnode_t *rnode; 299 char *scheme; 300 301 if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0) 302 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 303 TOPO_METH_PROP_GET, in)); 304 305 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 306 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 307 TOPO_METH_PROP_GET, in)); 308 309 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 310 return (set_error(thp, ETOPO_FMRI_NVL, err, 311 TOPO_METH_PROP_GET, in)); 312 313 rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc); 314 rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pgname); 315 rv |= nvlist_add_string(in, TOPO_PROP_VAL_NAME, pname); 316 if (args != NULL) 317 rv |= nvlist_add_nvlist(in, TOPO_PROP_PARGS, args); 318 if (rv != 0) 319 return (set_error(thp, ETOPO_FMRI_NVL, err, 320 TOPO_METH_PROP_GET, in)); 321 322 *prop = NULL; 323 rv = topo_method_invoke(rnode, TOPO_METH_PROP_GET, 324 TOPO_METH_PROP_GET_VERSION, in, prop, err); 325 326 nvlist_free(in); 327 328 if (rv != 0) 329 return (-1); /* *err is set for us */ 330 331 if (*prop == NULL) 332 return (set_error(thp, ETOPO_PROP_NOENT, err, 333 TOPO_METH_PROP_GET, NULL)); 334 return (0); 335 } 336 337 int 338 topo_fmri_asru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **asru, int *err) 339 { 340 nvlist_t *ap, *prop = NULL; 341 342 if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_ASRU, 343 nvl, &prop, err) < 0) 344 return (set_error(thp, *err, err, "topo_fmri_asru", NULL)); 345 346 if (nvlist_lookup_nvlist(prop, TOPO_PROP_VAL_VAL, &ap) != 0) 347 return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_asru", 348 prop)); 349 350 if (topo_hdl_nvdup(thp, ap, asru) < 0) 351 return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_asru", 352 prop)); 353 354 nvlist_free(prop); 355 356 return (0); 357 } 358 359 int 360 topo_fmri_fru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **fru, int *err) 361 { 362 nvlist_t *fp, *prop = NULL; 363 364 if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU, 365 nvl, &prop, err) < 0) 366 return (set_error(thp, *err, err, "topo_fmri_fru", NULL)); 367 368 if (nvlist_lookup_nvlist(prop, TOPO_PROP_VAL_VAL, &fp) != 0) 369 return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_fru", 370 prop)); 371 372 if (topo_hdl_nvdup(thp, fp, fru) < 0) 373 return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_fru", 374 prop)); 375 376 nvlist_free(prop); 377 378 return (0); 379 } 380 381 int 382 topo_fmri_label(topo_hdl_t *thp, nvlist_t *nvl, char **label, int *err) 383 { 384 nvlist_t *prop = NULL; 385 char *lp; 386 387 if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_LABEL, 388 NULL, &prop, err) < 0) 389 return (set_error(thp, *err, err, "topo_fmri_label", NULL)); 390 391 if (nvlist_lookup_string(prop, TOPO_PROP_VAL_VAL, &lp) != 0) 392 return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_label", 393 prop)); 394 395 if ((*label = topo_hdl_strdup(thp, lp)) == NULL) 396 return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_label", 397 prop)); 398 399 nvlist_free(prop); 400 401 return (0); 402 } 403 404 int 405 topo_fmri_serial(topo_hdl_t *thp, nvlist_t *nvl, char **serial, int *err) 406 { 407 nvlist_t *prop = NULL; 408 char *sp; 409 410 if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, FM_FMRI_HC_SERIAL_ID, 411 NULL, &prop, err) < 0) 412 return (set_error(thp, *err, err, "topo_fmri_serial", NULL)); 413 414 if (nvlist_lookup_string(prop, TOPO_PROP_VAL_VAL, &sp) != 0) 415 return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_serial", 416 prop)); 417 418 if ((*serial = topo_hdl_strdup(thp, sp)) == NULL) 419 return (set_error(thp, ETOPO_PROP_NOMEM, err, 420 "topo_fmri_serial", prop)); 421 422 nvlist_free(prop); 423 424 return (0); 425 } 426 427 int topo_fmri_getprop(topo_hdl_t *thp, nvlist_t *nvl, const char *pg, 428 const char *pname, nvlist_t *args, nvlist_t **prop, 429 int *err) 430 { 431 *prop = NULL; 432 433 return (fmri_prop(thp, nvl, pg, pname, args, prop, err)); 434 } 435 436 int topo_fmri_setprop(topo_hdl_t *thp, nvlist_t *nvl, const char *pg, 437 nvlist_t *prop, int flag, nvlist_t *args, int *err) 438 { 439 int rv; 440 nvlist_t *in = NULL, *out = NULL; 441 tnode_t *rnode; 442 char *scheme; 443 444 if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme) != 0) 445 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 446 TOPO_METH_PROP_SET, in)); 447 448 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 449 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 450 TOPO_METH_PROP_SET, in)); 451 452 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 453 return (set_error(thp, ETOPO_FMRI_NVL, err, 454 TOPO_METH_PROP_SET, in)); 455 456 rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, nvl); 457 rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pg); 458 rv |= nvlist_add_nvlist(in, TOPO_PROP_VAL, prop); 459 rv |= nvlist_add_int32(in, TOPO_PROP_FLAG, (int32_t)flag); 460 if (args != NULL) 461 rv |= nvlist_add_nvlist(in, TOPO_PROP_PARGS, args); 462 if (rv != 0) 463 return (set_error(thp, ETOPO_FMRI_NVL, err, 464 TOPO_METH_PROP_SET, in)); 465 466 rv = topo_method_invoke(rnode, TOPO_METH_PROP_SET, 467 TOPO_METH_PROP_SET_VERSION, in, &out, err); 468 469 nvlist_free(in); 470 471 /* no return values */ 472 if (out != NULL) 473 nvlist_free(out); 474 475 if (rv) 476 return (-1); 477 478 return (0); 479 480 } 481 482 int 483 topo_fmri_getpgrp(topo_hdl_t *thp, nvlist_t *rsrc, const char *pgname, 484 nvlist_t **pgroup, int *err) 485 { 486 int rv; 487 nvlist_t *in = NULL; 488 tnode_t *rnode; 489 char *scheme; 490 491 if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0) 492 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 493 TOPO_METH_PROP_GET, in)); 494 495 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 496 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 497 TOPO_METH_PROP_GET, in)); 498 499 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 500 return (set_error(thp, ETOPO_FMRI_NVL, err, 501 TOPO_METH_PROP_GET, in)); 502 503 rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc); 504 rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pgname); 505 if (rv != 0) 506 return (set_error(thp, ETOPO_FMRI_NVL, err, 507 TOPO_METH_PROP_GET, in)); 508 509 *pgroup = NULL; 510 rv = topo_method_invoke(rnode, TOPO_METH_PGRP_GET, 511 TOPO_METH_PGRP_GET_VERSION, in, pgroup, err); 512 513 nvlist_free(in); 514 515 if (rv != 0) 516 return (-1); /* *err is set for us */ 517 518 if (*pgroup == NULL) 519 return (set_error(thp, ETOPO_PROP_NOENT, err, 520 TOPO_METH_PROP_GET, NULL)); 521 return (0); 522 } 523 524 int 525 topo_fmri_compare(topo_hdl_t *thp, nvlist_t *f1, nvlist_t *f2, int *err) 526 { 527 uint32_t compare; 528 char *scheme1, *scheme2; 529 nvlist_t *in; 530 nvlist_t *out = NULL; 531 tnode_t *rnode; 532 533 if (nvlist_lookup_string(f1, FM_FMRI_SCHEME, &scheme1) != 0) 534 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 535 TOPO_METH_COMPARE, NULL)); 536 if (nvlist_lookup_string(f2, FM_FMRI_SCHEME, &scheme2) != 0) 537 return (set_error(thp, ETOPO_FMRI_MALFORM, err, 538 TOPO_METH_COMPARE, NULL)); 539 540 if (strcmp(scheme1, scheme2) != 0) 541 return (0); 542 543 if ((rnode = topo_hdl_root(thp, scheme1)) == NULL) 544 return (set_error(thp, ETOPO_METHOD_NOTSUP, err, 545 TOPO_METH_COMPARE, NULL)); 546 547 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0) 548 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE, 549 NULL)); 550 551 if (nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_NV1, f1) != 0 || 552 nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_NV2, f2) != 0) 553 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE, 554 in)); 555 556 if (topo_method_invoke(rnode, TOPO_METH_COMPARE, 557 TOPO_METH_COMPARE_VERSION, in, &out, err) < 0) 558 return (set_error(thp, *err, err, TOPO_METH_COMPARE, in)); 559 560 (void) nvlist_lookup_uint32(out, TOPO_METH_COMPARE_RET, &compare); 561 nvlist_free(out); 562 nvlist_free(in); 563 564 return (compare); 565 } 566 567 /* 568 * topo_fmri_create 569 * 570 * If possible, creates an FMRI of the requested version in the 571 * requested scheme. Args are passed as part of the inputs to the 572 * fmri-create method of the scheme. 573 */ 574 nvlist_t * 575 topo_fmri_create(topo_hdl_t *thp, const char *scheme, const char *name, 576 topo_instance_t inst, nvlist_t *nvl, int *err) 577 { 578 nvlist_t *ins; 579 nvlist_t *out; 580 tnode_t *rnode; 581 582 ins = out = NULL; 583 584 if ((rnode = topo_hdl_root(thp, scheme)) == NULL) 585 return (set_nverror(thp, ETOPO_METHOD_NOTSUP, err, 586 TOPO_METH_FMRI, NULL)); 587 588 if ((*err = topo_hdl_nvalloc(thp, &ins, NV_UNIQUE_NAME)) != 0) 589 return (set_nverror(thp, ETOPO_FMRI_NVL, err, 590 TOPO_METH_FMRI, NULL)); 591 592 if (nvlist_add_string(ins, TOPO_METH_FMRI_ARG_NAME, name) != 0 || 593 nvlist_add_uint32(ins, TOPO_METH_FMRI_ARG_INST, inst) != 0) { 594 return (set_nverror(thp, ETOPO_FMRI_NVL, err, 595 TOPO_METH_FMRI, ins)); 596 } 597 598 if (nvl != NULL && 599 nvlist_add_nvlist(ins, TOPO_METH_FMRI_ARG_NVL, nvl) != 0) { 600 return (set_nverror(thp, ETOPO_FMRI_NVL, err, 601 TOPO_METH_FMRI, ins)); 602 } 603 if (topo_method_invoke(rnode, 604 TOPO_METH_FMRI, TOPO_METH_FMRI_VERSION, ins, &out, err) != 0) { 605 return (set_nverror(thp, *err, err, TOPO_METH_FMRI, ins)); 606 } 607 nvlist_free(ins); 608 return (out); 609 } 610 611 /* 612 * These private utility functions are used by fmd to maintain its resource 613 * cache. Because hc instance numbers are not guaranteed, it's possible to 614 * have two different FMRI strings represent the same logical entity. These 615 * functions hide this implementation detail from unknowing consumers such as 616 * fmd. 617 * 618 * Ideally, we'd like to do a str2nvl() and then a full FMRI hash and 619 * comparison, but these functions are designed to be fast and efficient. 620 * Given that there is only a single hc node that has this property 621 * (ses-enclosure), we hard-code this behavior here. If there are more 622 * instances of this behavior in the future, this function could be made more 623 * generic. 624 */ 625 static ulong_t 626 topo_fmri_strhash_one(const char *fmri, size_t len) 627 { 628 ulong_t g, h = 0; 629 size_t i; 630 631 for (i = 0; i < len; i++) { 632 h = (h << 4) + fmri[i]; 633 634 if ((g = (h & 0xf0000000)) != 0) { 635 h ^= (g >> 24); 636 h ^= g; 637 } 638 } 639 640 return (h); 641 } 642 643 /*ARGSUSED*/ 644 ulong_t 645 topo_fmri_strhash(topo_hdl_t *thp, const char *fmri) 646 { 647 char *e; 648 ulong_t h; 649 650 if (strncmp(fmri, "hc://", 5) != 0 || 651 (e = strstr(fmri, SES_ENCLOSURE)) == NULL) 652 return (topo_fmri_strhash_one(fmri, strlen(fmri))); 653 654 h = topo_fmri_strhash_one(fmri, e - fmri); 655 e += sizeof (SES_ENCLOSURE); 656 657 while (isdigit(*e)) 658 e++; 659 660 h += topo_fmri_strhash_one(e, strlen(e)); 661 662 return (h); 663 } 664 665 /*ARGSUSED*/ 666 boolean_t 667 topo_fmri_strcmp(topo_hdl_t *thp, const char *a, const char *b) 668 { 669 char *ea, *eb; 670 671 if (strncmp(a, "hc://", 5) != 0 || 672 strncmp(b, "hc://", 5) != 0 || 673 (ea = strstr(a, SES_ENCLOSURE)) == NULL || 674 (eb = strstr(b, SES_ENCLOSURE)) == NULL) 675 return (strcmp(a, b) == 0); 676 677 if ((ea - a) != (eb - b)) 678 return (B_FALSE); 679 680 if (strncmp(a, b, ea - a) != 0) 681 return (B_FALSE); 682 683 ea += sizeof (SES_ENCLOSURE); 684 eb += sizeof (SES_ENCLOSURE); 685 686 while (isdigit(*ea)) 687 ea++; 688 while (isdigit(*eb)) 689 eb++; 690 691 return (strcmp(ea, eb) == 0); 692 } 693