1 /* 2 * 3 * CDDL HEADER START 4 * 5 * The contents of this file are subject to the terms of the 6 * Common Development and Distribution License (the "License"). 7 * You may not use this file except in compliance with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 #pragma ident "%Z%%M% %I% %E% SMI" 29 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <errno.h> 34 #include <ctype.h> 35 #include <alloca.h> 36 #include <limits.h> 37 #include <fm/topo_mod.h> 38 #include <fm/topo_hc.h> 39 #include <sys/param.h> 40 #include <sys/systeminfo.h> 41 #include <sys/fm/protocol.h> 42 #include <sys/stat.h> 43 #include <sys/systeminfo.h> 44 #include <sys/utsname.h> 45 46 #include <topo_method.h> 47 #include <topo_subr.h> 48 #include <topo_prop.h> 49 #include <hc.h> 50 51 static int hc_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, 52 topo_instance_t, void *, void *); 53 static void hc_release(topo_mod_t *, tnode_t *); 54 static int hc_fmri_nvl2str(topo_mod_t *, tnode_t *, topo_version_t, 55 nvlist_t *, nvlist_t **); 56 static int hc_fmri_str2nvl(topo_mod_t *, tnode_t *, topo_version_t, 57 nvlist_t *, nvlist_t **); 58 static int hc_compare(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, 59 nvlist_t **); 60 static int hc_fmri_present(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, 61 nvlist_t **); 62 static int hc_fmri_unusable(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, 63 nvlist_t **); 64 static int hc_fmri_create_meth(topo_mod_t *, tnode_t *, topo_version_t, 65 nvlist_t *, nvlist_t **); 66 static int hc_fmri_prop_get(topo_mod_t *, tnode_t *, topo_version_t, 67 nvlist_t *, nvlist_t **); 68 static int hc_fmri_prop_set(topo_mod_t *, tnode_t *, topo_version_t, 69 nvlist_t *, nvlist_t **); 70 static int hc_fmri_pgrp_get(topo_mod_t *, tnode_t *, topo_version_t, 71 nvlist_t *, nvlist_t **); 72 73 static nvlist_t *hc_fmri_create(topo_mod_t *, nvlist_t *, int, const char *, 74 topo_instance_t inst, const nvlist_t *, const char *, const char *, 75 const char *); 76 77 const topo_method_t hc_methods[] = { 78 { TOPO_METH_NVL2STR, TOPO_METH_NVL2STR_DESC, TOPO_METH_NVL2STR_VERSION, 79 TOPO_STABILITY_INTERNAL, hc_fmri_nvl2str }, 80 { TOPO_METH_STR2NVL, TOPO_METH_STR2NVL_DESC, TOPO_METH_STR2NVL_VERSION, 81 TOPO_STABILITY_INTERNAL, hc_fmri_str2nvl }, 82 { TOPO_METH_COMPARE, TOPO_METH_COMPARE_DESC, TOPO_METH_COMPARE_VERSION, 83 TOPO_STABILITY_INTERNAL, hc_compare }, 84 { TOPO_METH_PRESENT, TOPO_METH_PRESENT_DESC, TOPO_METH_PRESENT_VERSION, 85 TOPO_STABILITY_INTERNAL, hc_fmri_present }, 86 { TOPO_METH_UNUSABLE, TOPO_METH_UNUSABLE_DESC, 87 TOPO_METH_UNUSABLE_VERSION, TOPO_STABILITY_INTERNAL, 88 hc_fmri_unusable }, 89 { TOPO_METH_FMRI, TOPO_METH_FMRI_DESC, TOPO_METH_FMRI_VERSION, 90 TOPO_STABILITY_INTERNAL, hc_fmri_create_meth }, 91 { TOPO_METH_PROP_GET, TOPO_METH_PROP_GET_DESC, 92 TOPO_METH_PROP_GET_VERSION, TOPO_STABILITY_INTERNAL, 93 hc_fmri_prop_get }, 94 { TOPO_METH_PROP_SET, TOPO_METH_PROP_SET_DESC, 95 TOPO_METH_PROP_SET_VERSION, TOPO_STABILITY_INTERNAL, 96 hc_fmri_prop_set }, 97 { TOPO_METH_PGRP_GET, TOPO_METH_PGRP_GET_DESC, 98 TOPO_METH_PGRP_GET_VERSION, TOPO_STABILITY_INTERNAL, 99 hc_fmri_pgrp_get }, 100 { NULL } 101 }; 102 103 static const topo_modops_t hc_ops = 104 { hc_enum, hc_release }; 105 static const topo_modinfo_t hc_info = 106 { HC, FM_FMRI_SCHEME_HC, HC_VERSION, &hc_ops }; 107 108 static const hcc_t hc_canon[] = { 109 { BAY, TOPO_STABILITY_PRIVATE }, 110 { BRANCH, TOPO_STABILITY_PRIVATE }, 111 { CMP, TOPO_STABILITY_PRIVATE }, 112 { CENTERPLANE, TOPO_STABILITY_PRIVATE }, 113 { CHASSIS, TOPO_STABILITY_PRIVATE }, 114 { CHIP, TOPO_STABILITY_PRIVATE }, 115 { CHIP_SELECT, TOPO_STABILITY_PRIVATE }, 116 { CPU, TOPO_STABILITY_PRIVATE }, 117 { CPUBOARD, TOPO_STABILITY_PRIVATE }, 118 { DIMM, TOPO_STABILITY_PRIVATE }, 119 { DISK, TOPO_STABILITY_PRIVATE }, 120 { DRAMCHANNEL, TOPO_STABILITY_PRIVATE }, 121 { HOSTBRIDGE, TOPO_STABILITY_PRIVATE }, 122 { INTERCONNECT, TOPO_STABILITY_PRIVATE }, 123 { IOBOARD, TOPO_STABILITY_PRIVATE }, 124 { MEMBOARD, TOPO_STABILITY_PRIVATE }, 125 { MEMORYCONTROL, TOPO_STABILITY_PRIVATE }, 126 { MOTHERBOARD, TOPO_STABILITY_PRIVATE }, 127 { NIU, TOPO_STABILITY_PRIVATE }, 128 { NIUFN, TOPO_STABILITY_PRIVATE }, 129 { PCI_BUS, TOPO_STABILITY_PRIVATE }, 130 { PCI_DEVICE, TOPO_STABILITY_PRIVATE }, 131 { PCI_FUNCTION, TOPO_STABILITY_PRIVATE }, 132 { PCIEX_BUS, TOPO_STABILITY_PRIVATE }, 133 { PCIEX_DEVICE, TOPO_STABILITY_PRIVATE }, 134 { PCIEX_FUNCTION, TOPO_STABILITY_PRIVATE }, 135 { PCIEX_ROOT, TOPO_STABILITY_PRIVATE }, 136 { PCIEX_SWUP, TOPO_STABILITY_PRIVATE }, 137 { PCIEX_SWDWN, TOPO_STABILITY_PRIVATE }, 138 { RANK, TOPO_STABILITY_PRIVATE }, 139 { SYSTEMBOARD, TOPO_STABILITY_PRIVATE }, 140 { XAUI, TOPO_STABILITY_PRIVATE }, 141 { XFP, TOPO_STABILITY_PRIVATE } 142 }; 143 144 static int hc_ncanon = sizeof (hc_canon) / sizeof (hcc_t); 145 146 int 147 hc_init(topo_mod_t *mod, topo_version_t version) 148 { 149 /* 150 * Turn on module debugging output 151 */ 152 if (getenv("TOPOHCDEBUG")) 153 topo_mod_setdebug(mod); 154 155 topo_mod_dprintf(mod, "initializing hc builtin\n"); 156 157 if (version != HC_VERSION) 158 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 159 160 if (topo_mod_register(mod, &hc_info, TOPO_VERSION) != 0) { 161 topo_mod_dprintf(mod, "failed to register hc: " 162 "%s\n", topo_mod_errmsg(mod)); 163 return (-1); /* mod errno already set */ 164 } 165 166 return (0); 167 } 168 169 void 170 hc_fini(topo_mod_t *mod) 171 { 172 topo_mod_unregister(mod); 173 } 174 175 176 static const topo_pgroup_info_t sys_pgroup = { 177 TOPO_PGROUP_SYSTEM, 178 TOPO_STABILITY_PRIVATE, 179 TOPO_STABILITY_PRIVATE, 180 1 181 }; 182 183 static const topo_pgroup_info_t auth_pgroup = { 184 FM_FMRI_AUTHORITY, 185 TOPO_STABILITY_PRIVATE, 186 TOPO_STABILITY_PRIVATE, 187 1 188 }; 189 190 static void 191 hc_prop_set(tnode_t *node, nvlist_t *auth) 192 { 193 int err; 194 char isa[MAXNAMELEN]; 195 struct utsname uts; 196 char *prod, *csn, *server; 197 198 if (auth == NULL) 199 return; 200 201 if (topo_pgroup_create(node, &auth_pgroup, &err) != 0) { 202 if (err != ETOPO_PROP_DEFD) 203 return; 204 } 205 206 /* 207 * Inherit if we can, it saves memory 208 */ 209 if (topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_PRODUCT, 210 &err) != 0) { 211 if (nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT, &prod) 212 == 0) 213 (void) topo_prop_set_string(node, FM_FMRI_AUTHORITY, 214 FM_FMRI_AUTH_PRODUCT, TOPO_PROP_IMMUTABLE, prod, 215 &err); 216 } 217 if (topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_CHASSIS, 218 &err) != 0) { 219 if (nvlist_lookup_string(auth, FM_FMRI_AUTH_CHASSIS, &csn) == 0) 220 (void) topo_prop_set_string(node, FM_FMRI_AUTHORITY, 221 FM_FMRI_AUTH_CHASSIS, TOPO_PROP_IMMUTABLE, csn, 222 &err); 223 } 224 if (topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_SERVER, 225 &err) != 0) { 226 if (nvlist_lookup_string(auth, FM_FMRI_AUTH_SERVER, &server) 227 == 0) 228 (void) topo_prop_set_string(node, FM_FMRI_AUTHORITY, 229 FM_FMRI_AUTH_SERVER, TOPO_PROP_IMMUTABLE, server, 230 &err); 231 } 232 233 if (topo_pgroup_create(node, &sys_pgroup, &err) != 0) 234 return; 235 236 isa[0] = '\0'; 237 (void) sysinfo(SI_ARCHITECTURE, isa, sizeof (isa)); 238 (void) uname(&uts); 239 (void) topo_prop_set_string(node, TOPO_PGROUP_SYSTEM, TOPO_PROP_ISA, 240 TOPO_PROP_IMMUTABLE, isa, &err); 241 (void) topo_prop_set_string(node, TOPO_PGROUP_SYSTEM, TOPO_PROP_MACHINE, 242 TOPO_PROP_IMMUTABLE, uts.machine, &err); 243 } 244 245 /*ARGSUSED*/ 246 int 247 hc_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, topo_instance_t min, 248 topo_instance_t max, void *notused1, void *notused2) 249 { 250 nvlist_t *pfmri = NULL; 251 nvlist_t *nvl; 252 nvlist_t *auth; 253 tnode_t *node; 254 int err; 255 /* 256 * Register root node methods 257 */ 258 if (strcmp(name, HC) == 0) { 259 (void) topo_method_register(mod, pnode, hc_methods); 260 return (0); 261 } 262 if (min != max) { 263 topo_mod_dprintf(mod, 264 "Request to enumerate %s component with an " 265 "ambiguous instance number, min (%d) != max (%d).\n", 266 HC, min, max); 267 return (topo_mod_seterrno(mod, EINVAL)); 268 } 269 270 (void) topo_node_resource(pnode, &pfmri, &err); 271 auth = topo_mod_auth(mod, pnode); 272 nvl = hc_fmri_create(mod, pfmri, FM_HC_SCHEME_VERSION, name, min, 273 auth, NULL, NULL, NULL); 274 nvlist_free(pfmri); /* callee ignores NULLs */ 275 if (nvl == NULL) { 276 nvlist_free(auth); 277 return (-1); 278 } 279 280 if ((node = topo_node_bind(mod, pnode, name, min, nvl)) == NULL) { 281 topo_mod_dprintf(mod, "topo_node_bind failed: %s\n", 282 topo_strerror(topo_mod_errno(mod))); 283 nvlist_free(auth); 284 nvlist_free(nvl); 285 return (-1); 286 } 287 288 hc_prop_set(node, auth); 289 nvlist_free(nvl); 290 nvlist_free(auth); 291 292 return (0); 293 } 294 295 /*ARGSUSED*/ 296 static void 297 hc_release(topo_mod_t *mp, tnode_t *node) 298 { 299 topo_method_unregister_all(mp, node); 300 } 301 302 static int 303 fmri_compare(topo_mod_t *mod, nvlist_t *nv1, nvlist_t *nv2) 304 { 305 uint8_t v1, v2; 306 nvlist_t **hcp1, **hcp2; 307 int err, i; 308 uint_t nhcp1, nhcp2; 309 310 if (nvlist_lookup_uint8(nv1, FM_VERSION, &v1) != 0 || 311 nvlist_lookup_uint8(nv2, FM_VERSION, &v2) != 0 || 312 v1 > FM_HC_SCHEME_VERSION || v2 > FM_HC_SCHEME_VERSION) 313 return (topo_mod_seterrno(mod, EMOD_FMRI_VERSION)); 314 315 err = nvlist_lookup_nvlist_array(nv1, FM_FMRI_HC_LIST, &hcp1, &nhcp1); 316 err |= nvlist_lookup_nvlist_array(nv2, FM_FMRI_HC_LIST, &hcp2, &nhcp2); 317 if (err != 0) 318 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 319 320 if (nhcp1 != nhcp2) 321 return (0); 322 323 for (i = 0; i < nhcp1; i++) { 324 char *nm1 = NULL; 325 char *nm2 = NULL; 326 char *id1 = NULL; 327 char *id2 = NULL; 328 329 (void) nvlist_lookup_string(hcp1[i], FM_FMRI_HC_NAME, &nm1); 330 (void) nvlist_lookup_string(hcp2[i], FM_FMRI_HC_NAME, &nm2); 331 (void) nvlist_lookup_string(hcp1[i], FM_FMRI_HC_ID, &id1); 332 (void) nvlist_lookup_string(hcp2[i], FM_FMRI_HC_ID, &id2); 333 if (nm1 == NULL || nm2 == NULL || id1 == NULL || id2 == NULL) 334 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 335 336 if (strcmp(nm1, nm2) == 0 && strcmp(id1, id2) == 0) 337 continue; 338 339 return (0); 340 } 341 342 return (1); 343 } 344 345 /*ARGSUSED*/ 346 static int 347 hc_compare(topo_mod_t *mod, tnode_t *node, topo_version_t version, 348 nvlist_t *in, nvlist_t **out) 349 { 350 int ret; 351 uint32_t compare; 352 nvlist_t *nv1, *nv2; 353 354 if (version > TOPO_METH_COMPARE_VERSION) 355 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 356 357 if (nvlist_lookup_nvlist(in, TOPO_METH_FMRI_ARG_NV1, &nv1) != 0 || 358 nvlist_lookup_nvlist(in, TOPO_METH_FMRI_ARG_NV2, &nv2) != 0) 359 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 360 361 ret = fmri_compare(mod, nv1, nv2); 362 if (ret < 0) 363 return (-1); 364 365 compare = ret; 366 if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) == 0) { 367 if (nvlist_add_uint32(*out, TOPO_METH_COMPARE_RET, 368 compare) == 0) 369 return (0); 370 else 371 nvlist_free(*out); 372 } 373 374 return (-1); 375 } 376 377 static ssize_t 378 fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen) 379 { 380 nvlist_t **hcprs = NULL; 381 nvlist_t *anvl = NULL; 382 uint8_t version; 383 ssize_t size = 0; 384 uint_t hcnprs; 385 char *achas = NULL; 386 char *adom = NULL; 387 char *aprod = NULL; 388 char *asrvr = NULL; 389 char *ahost = NULL; 390 char *serial = NULL; 391 char *part = NULL; 392 char *root = NULL; 393 char *rev = NULL; 394 int more_auth = 0; 395 int err, i; 396 397 if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || 398 version > FM_HC_SCHEME_VERSION) 399 return (-1); 400 401 /* Get authority, if present */ 402 err = nvlist_lookup_nvlist(nvl, FM_FMRI_AUTHORITY, &anvl); 403 if (err != 0 && err != ENOENT) 404 return (-1); 405 406 if ((err = nvlist_lookup_string(nvl, FM_FMRI_HC_ROOT, &root)) != 0) 407 return (-1); 408 409 err = nvlist_lookup_nvlist_array(nvl, FM_FMRI_HC_LIST, &hcprs, &hcnprs); 410 if (err != 0 || hcprs == NULL) 411 return (-1); 412 413 if (anvl != NULL) { 414 (void) nvlist_lookup_string(anvl, 415 FM_FMRI_AUTH_PRODUCT, &aprod); 416 (void) nvlist_lookup_string(anvl, 417 FM_FMRI_AUTH_CHASSIS, &achas); 418 (void) nvlist_lookup_string(anvl, 419 FM_FMRI_AUTH_DOMAIN, &adom); 420 (void) nvlist_lookup_string(anvl, 421 FM_FMRI_AUTH_SERVER, &asrvr); 422 (void) nvlist_lookup_string(anvl, 423 FM_FMRI_AUTH_HOST, &ahost); 424 if (aprod != NULL) 425 more_auth++; 426 if (achas != NULL) 427 more_auth++; 428 if (adom != NULL) 429 more_auth++; 430 if (asrvr != NULL) 431 more_auth++; 432 if (ahost != NULL) 433 more_auth++; 434 } 435 436 (void) nvlist_lookup_string(nvl, FM_FMRI_HC_SERIAL_ID, &serial); 437 (void) nvlist_lookup_string(nvl, FM_FMRI_HC_PART, &part); 438 (void) nvlist_lookup_string(nvl, FM_FMRI_HC_REVISION, &rev); 439 440 /* hc:// */ 441 topo_fmristr_build(&size, buf, buflen, FM_FMRI_SCHEME_HC, NULL, "://"); 442 443 /* authority, if any */ 444 if (aprod != NULL) 445 topo_fmristr_build(&size, 446 buf, buflen, aprod, ":" FM_FMRI_AUTH_PRODUCT "=", NULL); 447 if (achas != NULL) 448 topo_fmristr_build(&size, 449 buf, buflen, achas, ":" FM_FMRI_AUTH_CHASSIS "=", NULL); 450 if (adom != NULL) 451 topo_fmristr_build(&size, 452 buf, buflen, adom, ":" FM_FMRI_AUTH_DOMAIN "=", NULL); 453 if (asrvr != NULL) 454 topo_fmristr_build(&size, 455 buf, buflen, asrvr, ":" FM_FMRI_AUTH_SERVER "=", NULL); 456 if (ahost != NULL) 457 topo_fmristr_build(&size, 458 buf, buflen, ahost, ":" FM_FMRI_AUTH_HOST "=", NULL); 459 460 /* hardware-id part */ 461 topo_fmristr_build(&size, 462 buf, buflen, serial, ":" FM_FMRI_HC_SERIAL_ID "=", NULL); 463 topo_fmristr_build(&size, 464 buf, buflen, part, ":" FM_FMRI_HC_PART "=", NULL); 465 topo_fmristr_build(&size, 466 buf, buflen, rev, ":" FM_FMRI_HC_REVISION "=", NULL); 467 468 /* separating slash */ 469 topo_fmristr_build(&size, buf, buflen, "/", NULL, NULL); 470 471 /* hc-root */ 472 topo_fmristr_build(&size, buf, buflen, root, NULL, NULL); 473 474 /* all the pairs */ 475 for (i = 0; i < hcnprs; i++) { 476 char *nm = NULL; 477 char *id = NULL; 478 479 if (i > 0) 480 topo_fmristr_build(&size, 481 buf, buflen, "/", NULL, NULL); 482 (void) nvlist_lookup_string(hcprs[i], FM_FMRI_HC_NAME, &nm); 483 (void) nvlist_lookup_string(hcprs[i], FM_FMRI_HC_ID, &id); 484 if (nm == NULL || id == NULL) 485 return (0); 486 topo_fmristr_build(&size, buf, buflen, nm, NULL, "="); 487 topo_fmristr_build(&size, buf, buflen, id, NULL, NULL); 488 } 489 490 return (size); 491 } 492 493 /*ARGSUSED*/ 494 static int 495 hc_fmri_nvl2str(topo_mod_t *mod, tnode_t *node, topo_version_t version, 496 nvlist_t *nvl, nvlist_t **out) 497 { 498 ssize_t len; 499 char *name = NULL; 500 nvlist_t *fmristr; 501 502 if (version > TOPO_METH_NVL2STR_VERSION) 503 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 504 505 if ((len = fmri_nvl2str(nvl, NULL, 0)) == 0 || 506 (name = topo_mod_alloc(mod, len + 1)) == NULL || 507 fmri_nvl2str(nvl, name, len + 1) == 0) { 508 if (name != NULL) 509 topo_mod_free(mod, name, len + 1); 510 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 511 } 512 513 if (topo_mod_nvalloc(mod, &fmristr, NV_UNIQUE_NAME) != 0) { 514 topo_mod_free(mod, name, len + 1); 515 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 516 } 517 if (nvlist_add_string(fmristr, "fmri-string", name) != 0) { 518 topo_mod_free(mod, name, len + 1); 519 nvlist_free(fmristr); 520 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 521 } 522 topo_mod_free(mod, name, len + 1); 523 *out = fmristr; 524 525 return (0); 526 } 527 528 static nvlist_t * 529 hc_base_fmri_create(topo_mod_t *mod, const nvlist_t *auth, const char *part, 530 const char *rev, const char *serial) 531 { 532 nvlist_t *fmri; 533 int err = 0; 534 535 /* 536 * Create base HC nvlist 537 */ 538 if (topo_mod_nvalloc(mod, &fmri, NV_UNIQUE_NAME) != 0) 539 return (NULL); 540 541 err = nvlist_add_uint8(fmri, FM_VERSION, FM_HC_SCHEME_VERSION); 542 err |= nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC); 543 err |= nvlist_add_string(fmri, FM_FMRI_HC_ROOT, ""); 544 if (err != 0) { 545 nvlist_free(fmri); 546 return (NULL); 547 } 548 549 /* 550 * Add optional payload members 551 */ 552 if (serial != NULL) 553 (void) nvlist_add_string(fmri, FM_FMRI_HC_SERIAL_ID, serial); 554 if (part != NULL) 555 (void) nvlist_add_string(fmri, FM_FMRI_HC_PART, part); 556 if (rev != NULL) 557 (void) nvlist_add_string(fmri, FM_FMRI_HC_REVISION, rev); 558 if (auth != NULL) 559 (void) nvlist_add_nvlist(fmri, FM_FMRI_AUTHORITY, 560 (nvlist_t *)auth); 561 562 return (fmri); 563 } 564 565 static nvlist_t ** 566 make_hc_pairs(topo_mod_t *mod, char *fmri, int *num) 567 { 568 nvlist_t **pa; 569 char *hc, *fromstr; 570 char *starti, *startn, *endi, *endi2; 571 char *ne, *ns; 572 char *cname = NULL; 573 char *find; 574 char *cid = NULL; 575 int nslashes = 0; 576 int npairs = 0; 577 int i, hclen; 578 579 if ((hc = topo_mod_strdup(mod, fmri + 5)) == NULL) 580 return (NULL); 581 582 hclen = strlen(hc) + 1; 583 584 /* 585 * Count equal signs and slashes to determine how many 586 * hc-pairs will be present in the final FMRI. There should 587 * be at least as many slashes as equal signs. There can be 588 * more, though if the string after an = includes them. 589 */ 590 if ((fromstr = strchr(hc, '/')) == NULL) 591 return (NULL); 592 593 find = fromstr; 594 while ((ne = strchr(find, '=')) != NULL) { 595 find = ne + 1; 596 npairs++; 597 } 598 599 find = fromstr; 600 while ((ns = strchr(find, '/')) != NULL) { 601 find = ns + 1; 602 nslashes++; 603 } 604 605 /* 606 * Do we appear to have a well-formed string version of the FMRI? 607 */ 608 if (nslashes < npairs || npairs == 0) { 609 topo_mod_free(mod, hc, hclen); 610 return (NULL); 611 } 612 613 *num = npairs; 614 615 find = fromstr; 616 617 if ((pa = topo_mod_zalloc(mod, npairs * sizeof (nvlist_t *))) == NULL) { 618 topo_mod_free(mod, hc, hclen); 619 return (NULL); 620 } 621 622 /* 623 * We go through a pretty complicated procedure to find the 624 * name and id for each pair. That's because, unfortunately, 625 * we have some ids that can have slashes within them. So 626 * we can't just search for the next slash after the equal sign 627 * and decide that starts a new pair. Instead we have to find 628 * an equal sign for the next pair and work our way back to the 629 * slash from there. 630 */ 631 for (i = 0; i < npairs; i++) { 632 startn = strchr(find, '/'); 633 if (startn == NULL) 634 break; 635 startn++; 636 starti = strchr(find, '='); 637 if (starti == NULL) 638 break; 639 *starti = '\0'; 640 if ((cname = topo_mod_strdup(mod, startn)) == NULL) 641 break; 642 *starti++ = '='; 643 endi = strchr(starti, '='); 644 if (endi != NULL) { 645 *endi = '\0'; 646 endi2 = strrchr(starti, '/'); 647 if (endi2 == NULL) 648 break; 649 *endi = '='; 650 *endi2 = '\0'; 651 if ((cid = topo_mod_strdup(mod, starti)) == NULL) 652 break; 653 *endi2 = '/'; 654 find = endi2; 655 } else { 656 if ((cid = topo_mod_strdup(mod, starti)) == NULL) 657 break; 658 find = starti + strlen(starti); 659 } 660 if (topo_mod_nvalloc(mod, &pa[i], NV_UNIQUE_NAME) < 0) 661 break; 662 663 if (nvlist_add_string(pa[i], FM_FMRI_HC_NAME, cname) || 664 nvlist_add_string(pa[i], FM_FMRI_HC_ID, cid)) 665 break; 666 667 topo_mod_strfree(mod, cname); 668 topo_mod_strfree(mod, cid); 669 cname = NULL; 670 cid = NULL; 671 } 672 673 topo_mod_strfree(mod, cname); 674 topo_mod_strfree(mod, cid); 675 676 if (i < npairs) { 677 for (i = 0; i < npairs; i++) 678 nvlist_free(pa[i]); 679 topo_mod_free(mod, pa, npairs * sizeof (nvlist_t *)); 680 topo_mod_free(mod, hc, hclen); 681 return (NULL); 682 } 683 684 topo_mod_free(mod, hc, hclen); 685 686 return (pa); 687 } 688 689 void 690 make_hc_auth(topo_mod_t *mod, char *fmri, char **serial, char **part, 691 char **rev, nvlist_t **auth) 692 { 693 char *starti, *startn, *endi, *copy; 694 char *aname, *aid, *fs; 695 nvlist_t *na = NULL; 696 size_t len; 697 698 if ((copy = topo_mod_strdup(mod, fmri + 5)) == NULL) 699 return; 700 701 len = strlen(copy); 702 703 /* 704 * Make sure there are a valid authority members 705 */ 706 startn = strchr(copy, ':'); 707 fs = strchr(copy, '/'); 708 709 if (startn == NULL || fs == NULL) { 710 topo_mod_strfree(mod, copy); 711 return; 712 } 713 714 /* 715 * The first colon we encounter must occur before the 716 * first slash 717 */ 718 if (startn > fs) 719 return; 720 721 do { 722 if (++startn >= copy + len) 723 break; 724 725 if ((starti = strchr(startn, '=')) == NULL) 726 break; 727 728 *starti = '\0'; 729 if (++starti > copy + len) 730 break; 731 732 if ((aname = topo_mod_strdup(mod, startn)) == NULL) 733 break; 734 735 startn = endi = strchr(starti, ':'); 736 if (endi == NULL) 737 if ((endi = strchr(starti, '/')) == NULL) 738 break; 739 740 *endi = '\0'; 741 if ((aid = topo_mod_strdup(mod, starti)) == NULL) { 742 topo_mod_strfree(mod, aname); 743 break; 744 } 745 746 /* 747 * Return possible serial, part and revision 748 */ 749 if (strcmp(aname, FM_FMRI_HC_SERIAL_ID) == 0) { 750 *serial = topo_mod_strdup(mod, aid); 751 } else if (strcmp(aname, FM_FMRI_HC_PART) == 0) { 752 *part = topo_mod_strdup(mod, aid); 753 } else if (strcmp(aname, FM_FMRI_HC_REVISION) == 0) { 754 *rev = topo_mod_strdup(mod, aid); 755 } else { 756 if (na == NULL) { 757 if (topo_mod_nvalloc(mod, &na, 758 NV_UNIQUE_NAME) == 0) { 759 (void) nvlist_add_string(na, aname, 760 aid); 761 } 762 } else { 763 (void) nvlist_add_string(na, aname, aid); 764 } 765 } 766 topo_mod_strfree(mod, aname); 767 topo_mod_strfree(mod, aid); 768 769 } while (startn != NULL); 770 771 *auth = na; 772 773 topo_mod_free(mod, copy, len + 1); 774 } 775 776 /*ARGSUSED*/ 777 static int 778 hc_fmri_str2nvl(topo_mod_t *mod, tnode_t *node, topo_version_t version, 779 nvlist_t *in, nvlist_t **out) 780 { 781 nvlist_t **pa = NULL; 782 nvlist_t *nf = NULL; 783 nvlist_t *auth = NULL; 784 char *str; 785 char *serial = NULL, *part = NULL, *rev = NULL; 786 int npairs; 787 int i, e; 788 789 if (version > TOPO_METH_STR2NVL_VERSION) 790 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 791 792 if (nvlist_lookup_string(in, "fmri-string", &str) != 0) 793 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 794 795 /* We're expecting a string version of an hc scheme FMRI */ 796 if (strncmp(str, "hc://", 5) != 0) 797 return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 798 799 if ((pa = make_hc_pairs(mod, str, &npairs)) == NULL) 800 return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 801 802 make_hc_auth(mod, str, &serial, &part, &rev, &auth); 803 if ((nf = hc_base_fmri_create(mod, auth, part, rev, serial)) == NULL) 804 goto hcfmbail; 805 if ((e = nvlist_add_uint32(nf, FM_FMRI_HC_LIST_SZ, npairs)) == 0) 806 e = nvlist_add_nvlist_array(nf, FM_FMRI_HC_LIST, pa, npairs); 807 if (e != 0) { 808 topo_mod_dprintf(mod, "construction of new hc nvl failed"); 809 goto hcfmbail; 810 } 811 for (i = 0; i < npairs; i++) 812 nvlist_free(pa[i]); 813 topo_mod_free(mod, pa, npairs * sizeof (nvlist_t *)); 814 if (serial != NULL) 815 topo_mod_strfree(mod, serial); 816 if (part != NULL) 817 topo_mod_strfree(mod, part); 818 if (rev != NULL) 819 topo_mod_strfree(mod, rev); 820 nvlist_free(auth); 821 822 *out = nf; 823 824 return (0); 825 826 hcfmbail: 827 if (nf != NULL) 828 nvlist_free(nf); 829 for (i = 0; i < npairs; i++) 830 nvlist_free(pa[i]); 831 topo_mod_free(mod, pa, npairs * sizeof (nvlist_t *)); 832 if (serial != NULL) 833 topo_mod_strfree(mod, serial); 834 if (part != NULL) 835 topo_mod_strfree(mod, part); 836 if (rev != NULL) 837 topo_mod_strfree(mod, rev); 838 nvlist_free(auth); 839 return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 840 } 841 842 static nvlist_t * 843 hc_list_create(topo_mod_t *mod, const char *name, char *inst) 844 { 845 int err; 846 nvlist_t *hc; 847 848 if (topo_mod_nvalloc(mod, &hc, NV_UNIQUE_NAME) != 0) 849 return (NULL); 850 851 err = nvlist_add_string(hc, FM_FMRI_HC_NAME, name); 852 err |= nvlist_add_string(hc, FM_FMRI_HC_ID, inst); 853 if (err != 0) { 854 nvlist_free(hc); 855 return (NULL); 856 } 857 858 return (hc); 859 } 860 861 static nvlist_t * 862 hc_create_seterror(topo_mod_t *mod, nvlist_t **hcl, int n, nvlist_t *fmri, 863 int err) 864 { 865 int i; 866 867 if (hcl != NULL) { 868 for (i = 0; i < n + 1; ++i) 869 nvlist_free(hcl[i]); 870 871 topo_mod_free(mod, hcl, sizeof (nvlist_t *) * (n + 1)); 872 } 873 874 nvlist_free(fmri); 875 876 (void) topo_mod_seterrno(mod, err); 877 878 topo_mod_dprintf(mod, "unable to create hc FMRI: %s\n", 879 topo_mod_errmsg(mod)); 880 881 return (NULL); 882 } 883 884 static int 885 hc_name_canonical(topo_mod_t *mod, const char *name) 886 { 887 int i; 888 889 if (getenv("NOHCCHECK") != NULL) 890 return (1); 891 892 /* 893 * Only enumerate elements with correct canonical names 894 */ 895 for (i = 0; i < hc_ncanon; i++) { 896 if (strcmp(name, hc_canon[i].hcc_name) == 0) 897 break; 898 } 899 if (i >= hc_ncanon) { 900 topo_mod_dprintf(mod, "non-canonical name %s\n", 901 name); 902 return (0); 903 } else { 904 return (1); 905 } 906 } 907 908 static nvlist_t * 909 hc_fmri_create(topo_mod_t *mod, nvlist_t *pfmri, int version, const char *name, 910 topo_instance_t inst, const nvlist_t *auth, const char *part, 911 const char *rev, const char *serial) 912 { 913 int i; 914 char str[21]; /* sizeof (UINT64_MAX) + '\0' */ 915 uint_t pelems = 0; 916 nvlist_t **phcl = NULL; 917 nvlist_t **hcl = NULL; 918 nvlist_t *fmri = NULL; 919 920 if (version > FM_HC_SCHEME_VERSION) 921 return (hc_create_seterror(mod, 922 hcl, pelems, fmri, EMOD_VER_OLD)); 923 else if (version < FM_HC_SCHEME_VERSION) 924 return (hc_create_seterror(mod, 925 hcl, pelems, fmri, EMOD_VER_NEW)); 926 927 /* 928 * Check that the requested name is in our canonical list 929 */ 930 if (hc_name_canonical(mod, name) == 0) 931 return (hc_create_seterror(mod, 932 hcl, pelems, fmri, EMOD_NONCANON)); 933 /* 934 * Copy the parent's HC_LIST 935 */ 936 if (pfmri != NULL) { 937 if (nvlist_lookup_nvlist_array(pfmri, FM_FMRI_HC_LIST, 938 &phcl, &pelems) != 0) 939 return (hc_create_seterror(mod, 940 hcl, pelems, fmri, EMOD_FMRI_MALFORM)); 941 } 942 943 hcl = topo_mod_zalloc(mod, sizeof (nvlist_t *) * (pelems + 1)); 944 if (hcl == NULL) 945 return (hc_create_seterror(mod, hcl, pelems, fmri, 946 EMOD_NOMEM)); 947 948 for (i = 0; i < pelems; ++i) 949 if (topo_mod_nvdup(mod, phcl[i], &hcl[i]) != 0) 950 return (hc_create_seterror(mod, 951 hcl, pelems, fmri, EMOD_FMRI_NVL)); 952 953 (void) snprintf(str, sizeof (str), "%d", inst); 954 if ((hcl[i] = hc_list_create(mod, name, str)) == NULL) 955 return (hc_create_seterror(mod, 956 hcl, pelems, fmri, EMOD_FMRI_NVL)); 957 958 if ((fmri = hc_base_fmri_create(mod, auth, part, rev, serial)) == NULL) 959 return (hc_create_seterror(mod, 960 hcl, pelems, fmri, EMOD_FMRI_NVL)); 961 962 if (nvlist_add_nvlist_array(fmri, FM_FMRI_HC_LIST, hcl, pelems + 1) 963 != 0) 964 return (hc_create_seterror(mod, 965 hcl, pelems, fmri, EMOD_FMRI_NVL)); 966 967 if (hcl != NULL) { 968 for (i = 0; i < pelems + 1; ++i) { 969 if (hcl[i] != NULL) 970 nvlist_free(hcl[i]); 971 } 972 topo_mod_free(mod, hcl, sizeof (nvlist_t *) * (pelems + 1)); 973 } 974 975 return (fmri); 976 } 977 978 /*ARGSUSED*/ 979 static int 980 hc_fmri_create_meth(topo_mod_t *mod, tnode_t *node, topo_version_t version, 981 nvlist_t *in, nvlist_t **out) 982 { 983 int ret; 984 nvlist_t *args, *pfmri = NULL; 985 nvlist_t *auth; 986 uint32_t inst; 987 char *name, *serial, *rev, *part; 988 989 if (version > TOPO_METH_FMRI_VERSION) 990 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 991 992 /* First the must-have fields */ 993 if (nvlist_lookup_string(in, TOPO_METH_FMRI_ARG_NAME, &name) != 0) 994 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 995 if (nvlist_lookup_uint32(in, TOPO_METH_FMRI_ARG_INST, &inst) != 0) 996 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 997 998 /* 999 * args is optional 1000 */ 1001 pfmri = NULL; 1002 auth = NULL; 1003 serial = rev = part = NULL; 1004 if ((ret = nvlist_lookup_nvlist(in, TOPO_METH_FMRI_ARG_NVL, &args)) 1005 != 0) { 1006 if (ret != ENOENT) 1007 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 1008 } else { 1009 1010 /* And then optional arguments */ 1011 (void) nvlist_lookup_nvlist(args, TOPO_METH_FMRI_ARG_PARENT, 1012 &pfmri); 1013 (void) nvlist_lookup_nvlist(args, TOPO_METH_FMRI_ARG_AUTH, 1014 &auth); 1015 (void) nvlist_lookup_string(args, TOPO_METH_FMRI_ARG_PART, 1016 &part); 1017 (void) nvlist_lookup_string(args, TOPO_METH_FMRI_ARG_REV, &rev); 1018 (void) nvlist_lookup_string(args, TOPO_METH_FMRI_ARG_SER, 1019 &serial); 1020 } 1021 1022 *out = hc_fmri_create(mod, pfmri, version, name, inst, auth, part, 1023 rev, serial); 1024 if (*out == NULL) 1025 return (-1); 1026 return (0); 1027 } 1028 1029 struct hc_walk { 1030 topo_mod_walk_cb_t hcw_cb; 1031 void *hcw_priv; 1032 topo_walk_t *hcw_wp; 1033 nvlist_t **hcw_list; 1034 uint_t hcw_index; 1035 uint_t hcw_end; 1036 }; 1037 1038 /* 1039 * Generic walker for the hc-scheme topo tree. This function uses the 1040 * hierachical nature of the hc-scheme to step through efficiently through 1041 * the topo hc tree. Node lookups are done by topo_walk_byid() at each 1042 * component level to avoid unnecessary traversal of the tree. 1043 * 1044 */ 1045 static int 1046 hc_walker(topo_mod_t *mod, tnode_t *node, void *pdata) 1047 { 1048 int i, err; 1049 struct hc_walk *hwp = (struct hc_walk *)pdata; 1050 char *name, *id; 1051 topo_instance_t inst; 1052 1053 i = hwp->hcw_index; 1054 if (i > hwp->hcw_end) { 1055 (void) topo_mod_seterrno(mod, ETOPO_PROP_NOENT); 1056 return (TOPO_WALK_TERMINATE); 1057 } 1058 1059 err = nvlist_lookup_string(hwp->hcw_list[i], FM_FMRI_HC_NAME, &name); 1060 err |= nvlist_lookup_string(hwp->hcw_list[i], FM_FMRI_HC_ID, &id); 1061 1062 if (err != 0) { 1063 (void) topo_mod_seterrno(mod, EMOD_NVL_INVAL); 1064 return (TOPO_WALK_ERR); 1065 } 1066 1067 inst = atoi(id); 1068 1069 /* 1070 * Special case for the root node. We need to walk by siblings 1071 * until we find a matching node for cases where there may be multiple 1072 * nodes just below the hc root. 1073 */ 1074 if (i == 0) { 1075 if (strcmp(name, topo_node_name(node)) != 0 || 1076 inst != topo_node_instance(node)) { 1077 return (TOPO_WALK_NEXT); 1078 } 1079 } 1080 1081 topo_mod_dprintf(mod, "hc_walker: walking node:%s=%d for hc:" 1082 "%s=%d at %d, end at %d \n", topo_node_name(node), 1083 topo_node_instance(node), name, inst, i, hwp->hcw_end); 1084 if (i == hwp->hcw_end) { 1085 /* 1086 * We are at the end of the hc-list. Verify that 1087 * the last node contains the name/instance we are looking for. 1088 */ 1089 if (strcmp(topo_node_name(node), name) == 0 && 1090 inst == topo_node_instance(node)) { 1091 if ((err = hwp->hcw_cb(mod, node, hwp->hcw_priv)) 1092 != 0) { 1093 (void) topo_mod_seterrno(mod, err); 1094 topo_mod_dprintf(mod, "hc_walker: callback " 1095 "failed: %s\n ", topo_mod_errmsg(mod)); 1096 return (TOPO_WALK_ERR); 1097 } 1098 topo_mod_dprintf(mod, "hc_walker: callback " 1099 "complete: terminate walk\n"); 1100 return (TOPO_WALK_TERMINATE); 1101 } else { 1102 topo_mod_dprintf(mod, "hc_walker: %s=%d\n " 1103 "not found\n", name, inst); 1104 return (TOPO_WALK_TERMINATE); 1105 } 1106 } 1107 1108 hwp->hcw_index = ++i; 1109 err = nvlist_lookup_string(hwp->hcw_list[i], FM_FMRI_HC_NAME, &name); 1110 err |= nvlist_lookup_string(hwp->hcw_list[i], FM_FMRI_HC_ID, &id); 1111 if (err != 0) { 1112 (void) topo_mod_seterrno(mod, err); 1113 return (TOPO_WALK_ERR); 1114 } 1115 inst = atoi(id); 1116 1117 topo_mod_dprintf(mod, "hc_walker: walk byid of %s=%d \n", name, 1118 inst); 1119 return (topo_walk_byid(hwp->hcw_wp, name, inst)); 1120 1121 } 1122 1123 static struct hc_walk * 1124 hc_walk_init(topo_mod_t *mod, tnode_t *node, nvlist_t *rsrc, 1125 topo_mod_walk_cb_t cb, void *pdata) 1126 { 1127 int err; 1128 uint_t sz; 1129 struct hc_walk *hwp; 1130 topo_walk_t *wp; 1131 1132 if ((hwp = topo_mod_alloc(mod, sizeof (struct hc_walk))) == NULL) 1133 (void) topo_mod_seterrno(mod, EMOD_NOMEM); 1134 1135 if (nvlist_lookup_nvlist_array(rsrc, FM_FMRI_HC_LIST, &hwp->hcw_list, 1136 &sz) != 0) { 1137 topo_mod_free(mod, hwp, sizeof (struct hc_walk)); 1138 (void) topo_mod_seterrno(mod, EMOD_METHOD_INVAL); 1139 return (NULL); 1140 } 1141 1142 hwp->hcw_end = sz - 1; 1143 hwp->hcw_index = 0; 1144 hwp->hcw_priv = pdata; 1145 hwp->hcw_cb = cb; 1146 if ((wp = topo_mod_walk_init(mod, node, hc_walker, (void *)hwp, &err)) 1147 == NULL) { 1148 topo_mod_free(mod, hwp, sizeof (struct hc_walk)); 1149 (void) topo_mod_seterrno(mod, err); 1150 return (NULL); 1151 } 1152 1153 hwp->hcw_wp = wp; 1154 1155 return (hwp); 1156 } 1157 1158 struct prop_lookup { 1159 const char *pl_pgroup; 1160 const char *pl_pname; 1161 int pl_flag; 1162 nvlist_t *pl_args; 1163 nvlist_t *pl_rsrc; 1164 nvlist_t *pl_prop; 1165 }; 1166 1167 /*ARGSUSED*/ 1168 static int 1169 hc_prop_get(topo_mod_t *mod, tnode_t *node, void *pdata) 1170 { 1171 int err = 0; 1172 1173 struct prop_lookup *plp = (struct prop_lookup *)pdata; 1174 1175 (void) topo_prop_getprop(node, plp->pl_pgroup, plp->pl_pname, 1176 plp->pl_args, &plp->pl_prop, &err); 1177 1178 return (err); 1179 } 1180 1181 static int 1182 hc_fmri_prop_get(topo_mod_t *mod, tnode_t *node, topo_version_t version, 1183 nvlist_t *in, nvlist_t **out) 1184 { 1185 int err; 1186 struct hc_walk *hwp; 1187 struct prop_lookup *plp; 1188 1189 if (version > TOPO_METH_PROP_GET_VERSION) 1190 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW)); 1191 1192 if ((plp = topo_mod_alloc(mod, sizeof (struct prop_lookup))) == NULL) 1193 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 1194 1195 err = nvlist_lookup_string(in, TOPO_PROP_GROUP, 1196 (char **)&plp->pl_pgroup); 1197 err |= nvlist_lookup_string(in, TOPO_PROP_VAL_NAME, 1198 (char **)&plp->pl_pname); 1199 err |= nvlist_lookup_nvlist(in, TOPO_PROP_RESOURCE, &plp->pl_rsrc); 1200 if (err != 0) { 1201 topo_mod_free(mod, plp, sizeof (struct prop_lookup)); 1202 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 1203 } 1204 1205 /* 1206 * Private args to prop method are optional 1207 */ 1208 if ((err = nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &plp->pl_args)) 1209 != 0) { 1210 if (err != ENOENT) { 1211 topo_mod_free(mod, plp, sizeof (struct prop_lookup)); 1212 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 1213 } else { 1214 plp->pl_args = NULL; 1215 } 1216 } 1217 1218 plp->pl_prop = NULL; 1219 if ((hwp = hc_walk_init(mod, node, plp->pl_rsrc, hc_prop_get, 1220 (void *)plp)) != NULL) { 1221 if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_SIBLING) == 1222 TOPO_WALK_ERR) 1223 err = -1; 1224 else 1225 err = 0; 1226 topo_walk_fini(hwp->hcw_wp); 1227 } else { 1228 err = -1; 1229 } 1230 1231 topo_mod_free(mod, hwp, sizeof (struct hc_walk)); 1232 1233 if (plp->pl_prop != NULL) 1234 *out = plp->pl_prop; 1235 1236 topo_mod_free(mod, plp, sizeof (struct prop_lookup)); 1237 1238 return (err); 1239 } 1240 1241 /*ARGSUSED*/ 1242 static int 1243 hc_pgrp_get(topo_mod_t *mod, tnode_t *node, void *pdata) 1244 { 1245 int err = 0; 1246 1247 struct prop_lookup *plp = (struct prop_lookup *)pdata; 1248 1249 (void) topo_prop_getpgrp(node, plp->pl_pgroup, &plp->pl_prop, &err); 1250 1251 return (err); 1252 } 1253 1254 static int 1255 hc_fmri_pgrp_get(topo_mod_t *mod, tnode_t *node, topo_version_t version, 1256 nvlist_t *in, nvlist_t **out) 1257 { 1258 int err; 1259 struct hc_walk *hwp; 1260 struct prop_lookup *plp; 1261 1262 if (version > TOPO_METH_PGRP_GET_VERSION) 1263 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW)); 1264 1265 if ((plp = topo_mod_alloc(mod, sizeof (struct prop_lookup))) == NULL) 1266 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 1267 1268 err = nvlist_lookup_string(in, TOPO_PROP_GROUP, 1269 (char **)&plp->pl_pgroup); 1270 err |= nvlist_lookup_nvlist(in, TOPO_PROP_RESOURCE, &plp->pl_rsrc); 1271 if (err != 0) { 1272 topo_mod_free(mod, plp, sizeof (struct prop_lookup)); 1273 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 1274 } 1275 1276 plp->pl_prop = NULL; 1277 if ((hwp = hc_walk_init(mod, node, plp->pl_rsrc, hc_pgrp_get, 1278 (void *)plp)) != NULL) { 1279 if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_SIBLING) == 1280 TOPO_WALK_ERR) 1281 err = -1; 1282 else 1283 err = 0; 1284 topo_walk_fini(hwp->hcw_wp); 1285 } else { 1286 err = -1; 1287 } 1288 1289 topo_mod_free(mod, hwp, sizeof (struct hc_walk)); 1290 1291 if (plp->pl_prop != NULL) 1292 *out = plp->pl_prop; 1293 1294 topo_mod_free(mod, plp, sizeof (struct prop_lookup)); 1295 1296 return (err); 1297 } 1298 1299 /*ARGSUSED*/ 1300 static int 1301 hc_prop_setprop(topo_mod_t *mod, tnode_t *node, void *pdata) 1302 { 1303 int err = 0; 1304 1305 struct prop_lookup *plp = (struct prop_lookup *)pdata; 1306 1307 (void) topo_prop_setprop(node, plp->pl_pgroup, plp->pl_prop, 1308 plp->pl_flag, plp->pl_args, &err); 1309 1310 return (err); 1311 } 1312 1313 /*ARGSUSED*/ 1314 static int 1315 hc_fmri_prop_set(topo_mod_t *mod, tnode_t *node, topo_version_t version, 1316 nvlist_t *in, nvlist_t **out) 1317 { 1318 int err; 1319 struct hc_walk *hwp; 1320 struct prop_lookup *plp; 1321 1322 if (version > TOPO_METH_PROP_SET_VERSION) 1323 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW)); 1324 1325 if ((plp = topo_mod_alloc(mod, sizeof (struct prop_lookup))) == NULL) 1326 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 1327 1328 err = nvlist_lookup_string(in, TOPO_PROP_GROUP, 1329 (char **)&plp->pl_pgroup); 1330 err |= nvlist_lookup_nvlist(in, TOPO_PROP_RESOURCE, &plp->pl_rsrc); 1331 err |= nvlist_lookup_nvlist(in, TOPO_PROP_VAL, &plp->pl_prop); 1332 err |= nvlist_lookup_int32(in, TOPO_PROP_FLAG, &plp->pl_flag); 1333 if (err != 0) { 1334 topo_mod_free(mod, plp, sizeof (struct prop_lookup)); 1335 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 1336 } 1337 1338 /* 1339 * Private args to prop method are optional 1340 */ 1341 if ((err = nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &plp->pl_args)) 1342 != 0) { 1343 if (err != ENOENT) 1344 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 1345 else 1346 plp->pl_args = NULL; 1347 } 1348 1349 if ((hwp = hc_walk_init(mod, node, plp->pl_rsrc, hc_prop_setprop, 1350 (void *)plp)) != NULL) { 1351 if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_SIBLING) == 1352 TOPO_WALK_ERR) 1353 err = -1; 1354 else 1355 err = 0; 1356 topo_walk_fini(hwp->hcw_wp); 1357 } else { 1358 err = -1; 1359 } 1360 1361 topo_mod_free(mod, hwp, sizeof (struct hc_walk)); 1362 topo_mod_free(mod, plp, sizeof (struct prop_lookup)); 1363 1364 return (err); 1365 } 1366 1367 struct hc_args { 1368 nvlist_t *ha_fmri; 1369 nvlist_t *ha_nvl; 1370 }; 1371 1372 static int 1373 hc_is_present(topo_mod_t *mod, tnode_t *node, void *pdata) 1374 { 1375 int err; 1376 struct hc_args *hap = (struct hc_args *)pdata; 1377 1378 /* 1379 * check with the enumerator that created this FMRI 1380 * (topo node) 1381 */ 1382 if (topo_method_invoke(node, TOPO_METH_PRESENT, 1383 TOPO_METH_PRESENT_VERSION, hap->ha_fmri, &hap->ha_nvl, 1384 &err) < 0) { 1385 1386 /* 1387 * Err on the side of caution and return present 1388 */ 1389 if (topo_mod_nvalloc(mod, &hap->ha_nvl, NV_UNIQUE_NAME) == 0) 1390 if (nvlist_add_uint32(hap->ha_nvl, 1391 TOPO_METH_PRESENT_RET, 1) == 0) 1392 return (0); 1393 1394 return (ETOPO_PROP_NVL); 1395 } 1396 1397 return (0); 1398 } 1399 1400 static int 1401 hc_fmri_present(topo_mod_t *mod, tnode_t *node, topo_version_t version, 1402 nvlist_t *in, nvlist_t **out) 1403 { 1404 int err; 1405 struct hc_walk *hwp; 1406 struct hc_args *hap; 1407 1408 if (version > TOPO_METH_PRESENT_VERSION) 1409 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW)); 1410 1411 if ((hap = topo_mod_alloc(mod, sizeof (struct hc_args))) == NULL) 1412 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 1413 1414 hap->ha_fmri = in; 1415 hap->ha_nvl = NULL; 1416 if ((hwp = hc_walk_init(mod, node, hap->ha_fmri, hc_is_present, 1417 (void *)hap)) != NULL) { 1418 if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_SIBLING) == 1419 TOPO_WALK_ERR) 1420 err = -1; 1421 else 1422 err = 0; 1423 topo_walk_fini(hwp->hcw_wp); 1424 } else { 1425 err = -1; 1426 } 1427 1428 topo_mod_free(mod, hwp, sizeof (struct hc_walk)); 1429 1430 if (hap->ha_nvl != NULL) 1431 *out = hap->ha_nvl; 1432 1433 topo_mod_free(mod, hap, sizeof (struct hc_args)); 1434 1435 return (err); 1436 } 1437 1438 static int 1439 hc_unusable(topo_mod_t *mod, tnode_t *node, void *pdata) 1440 { 1441 int err; 1442 struct hc_args *hap = (struct hc_args *)pdata; 1443 1444 /* 1445 * check with the enumerator that created this FMRI 1446 * (topo node) 1447 */ 1448 if (topo_method_invoke(node, TOPO_METH_UNUSABLE, 1449 TOPO_METH_UNUSABLE_VERSION, hap->ha_fmri, &hap->ha_nvl, 1450 &err) < 0) { 1451 1452 /* 1453 * Err on the side of caution and return usable 1454 */ 1455 if (topo_mod_nvalloc(mod, &hap->ha_nvl, NV_UNIQUE_NAME) == 0) 1456 if (nvlist_add_uint32(hap->ha_nvl, 1457 TOPO_METH_UNUSABLE_RET, 0) == 0) 1458 return (0); 1459 1460 return (ETOPO_PROP_NVL); 1461 } 1462 1463 return (err); 1464 } 1465 1466 static int 1467 hc_fmri_unusable(topo_mod_t *mod, tnode_t *node, topo_version_t version, 1468 nvlist_t *in, nvlist_t **out) 1469 { 1470 int err; 1471 struct hc_walk *hwp; 1472 struct hc_args *hap; 1473 1474 if (version > TOPO_METH_UNUSABLE_VERSION) 1475 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW)); 1476 1477 if ((hap = topo_mod_alloc(mod, sizeof (struct hc_args))) == NULL) 1478 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 1479 1480 hap->ha_fmri = in; 1481 hap->ha_nvl = NULL; 1482 if ((hwp = hc_walk_init(mod, node, hap->ha_fmri, hc_unusable, 1483 (void *)hap)) != NULL) { 1484 if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_SIBLING) == 1485 TOPO_WALK_ERR) 1486 err = -1; 1487 else 1488 err = 0; 1489 topo_walk_fini(hwp->hcw_wp); 1490 } else { 1491 err = -1; 1492 } 1493 1494 topo_mod_free(mod, hwp, sizeof (struct hc_walk)); 1495 1496 if (hap->ha_nvl != NULL) 1497 *out = hap->ha_nvl; 1498 1499 topo_mod_free(mod, hap, sizeof (struct hc_args)); 1500 1501 return (err); 1502 } 1503