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