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