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 2008 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_module.h> 48 #include <topo_subr.h> 49 #include <topo_prop.h> 50 #include <topo_tree.h> 51 #include <hc.h> 52 53 static int hc_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, 54 topo_instance_t, void *, void *); 55 static void hc_release(topo_mod_t *, tnode_t *); 56 static int hc_fmri_nvl2str(topo_mod_t *, tnode_t *, topo_version_t, 57 nvlist_t *, nvlist_t **); 58 static int hc_fmri_str2nvl(topo_mod_t *, tnode_t *, topo_version_t, 59 nvlist_t *, nvlist_t **); 60 static int hc_compare(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, 61 nvlist_t **); 62 static int hc_fmri_present(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, 63 nvlist_t **); 64 static int hc_fmri_unusable(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, 65 nvlist_t **); 66 static int hc_fmri_create_meth(topo_mod_t *, tnode_t *, topo_version_t, 67 nvlist_t *, nvlist_t **); 68 static int hc_fmri_prop_get(topo_mod_t *, tnode_t *, topo_version_t, 69 nvlist_t *, nvlist_t **); 70 static int hc_fmri_prop_set(topo_mod_t *, tnode_t *, topo_version_t, 71 nvlist_t *, nvlist_t **); 72 static int hc_fmri_pgrp_get(topo_mod_t *, tnode_t *, topo_version_t, 73 nvlist_t *, nvlist_t **); 74 static int hc_fmri_facility(topo_mod_t *, tnode_t *, topo_version_t, 75 nvlist_t *, nvlist_t **); 76 77 static nvlist_t *hc_fmri_create(topo_mod_t *, nvlist_t *, int, const char *, 78 topo_instance_t inst, const nvlist_t *, const char *, const char *, 79 const char *); 80 81 const topo_method_t hc_methods[] = { 82 { TOPO_METH_NVL2STR, TOPO_METH_NVL2STR_DESC, TOPO_METH_NVL2STR_VERSION, 83 TOPO_STABILITY_INTERNAL, hc_fmri_nvl2str }, 84 { TOPO_METH_STR2NVL, TOPO_METH_STR2NVL_DESC, TOPO_METH_STR2NVL_VERSION, 85 TOPO_STABILITY_INTERNAL, hc_fmri_str2nvl }, 86 { TOPO_METH_COMPARE, TOPO_METH_COMPARE_DESC, TOPO_METH_COMPARE_VERSION, 87 TOPO_STABILITY_INTERNAL, hc_compare }, 88 { TOPO_METH_PRESENT, TOPO_METH_PRESENT_DESC, TOPO_METH_PRESENT_VERSION, 89 TOPO_STABILITY_INTERNAL, hc_fmri_present }, 90 { TOPO_METH_UNUSABLE, TOPO_METH_UNUSABLE_DESC, 91 TOPO_METH_UNUSABLE_VERSION, TOPO_STABILITY_INTERNAL, 92 hc_fmri_unusable }, 93 { TOPO_METH_FMRI, TOPO_METH_FMRI_DESC, TOPO_METH_FMRI_VERSION, 94 TOPO_STABILITY_INTERNAL, hc_fmri_create_meth }, 95 { TOPO_METH_PROP_GET, TOPO_METH_PROP_GET_DESC, 96 TOPO_METH_PROP_GET_VERSION, TOPO_STABILITY_INTERNAL, 97 hc_fmri_prop_get }, 98 { TOPO_METH_PROP_SET, TOPO_METH_PROP_SET_DESC, 99 TOPO_METH_PROP_SET_VERSION, TOPO_STABILITY_INTERNAL, 100 hc_fmri_prop_set }, 101 { TOPO_METH_PGRP_GET, TOPO_METH_PGRP_GET_DESC, 102 TOPO_METH_PGRP_GET_VERSION, TOPO_STABILITY_INTERNAL, 103 hc_fmri_pgrp_get }, 104 { TOPO_METH_FACILITY, TOPO_METH_FACILITY_DESC, 105 TOPO_METH_FACILITY_VERSION, TOPO_STABILITY_INTERNAL, 106 hc_fmri_facility }, 107 { NULL } 108 }; 109 110 static const topo_modops_t hc_ops = 111 { hc_enum, hc_release }; 112 static const topo_modinfo_t hc_info = 113 { HC, FM_FMRI_SCHEME_HC, HC_VERSION, &hc_ops }; 114 115 static const hcc_t hc_canon[] = { 116 { BANK, TOPO_STABILITY_PRIVATE }, 117 { BAY, TOPO_STABILITY_PRIVATE }, 118 { BLADE, TOPO_STABILITY_PRIVATE }, 119 { BRANCH, TOPO_STABILITY_PRIVATE }, 120 { CMP, TOPO_STABILITY_PRIVATE }, 121 { CENTERPLANE, TOPO_STABILITY_PRIVATE }, 122 { CHASSIS, TOPO_STABILITY_PRIVATE }, 123 { CHIP, TOPO_STABILITY_PRIVATE }, 124 { CHIP_SELECT, TOPO_STABILITY_PRIVATE }, 125 { CORE, TOPO_STABILITY_PRIVATE }, 126 { CONTROLLER, TOPO_STABILITY_PRIVATE }, 127 { CPU, TOPO_STABILITY_PRIVATE }, 128 { CPUBOARD, TOPO_STABILITY_PRIVATE }, 129 { DIMM, TOPO_STABILITY_PRIVATE }, 130 { DISK, TOPO_STABILITY_PRIVATE }, 131 { DRAM, TOPO_STABILITY_PRIVATE }, 132 { DRAMCHANNEL, TOPO_STABILITY_PRIVATE }, 133 { FAN, TOPO_STABILITY_PRIVATE }, 134 { FANMODULE, TOPO_STABILITY_PRIVATE }, 135 { HOSTBRIDGE, TOPO_STABILITY_PRIVATE }, 136 { INTERCONNECT, TOPO_STABILITY_PRIVATE }, 137 { IOBOARD, TOPO_STABILITY_PRIVATE }, 138 { MEMBOARD, TOPO_STABILITY_PRIVATE }, 139 { MEMORYBUFFER, TOPO_STABILITY_PRIVATE }, 140 { MEMORYCONTROL, TOPO_STABILITY_PRIVATE }, 141 { MICROCORE, TOPO_STABILITY_PRIVATE }, 142 { MOTHERBOARD, TOPO_STABILITY_PRIVATE }, 143 { NIU, TOPO_STABILITY_PRIVATE }, 144 { NIUFN, TOPO_STABILITY_PRIVATE }, 145 { PCI_BUS, TOPO_STABILITY_PRIVATE }, 146 { PCI_DEVICE, TOPO_STABILITY_PRIVATE }, 147 { PCI_FUNCTION, TOPO_STABILITY_PRIVATE }, 148 { PCIEX_BUS, TOPO_STABILITY_PRIVATE }, 149 { PCIEX_DEVICE, TOPO_STABILITY_PRIVATE }, 150 { PCIEX_FUNCTION, TOPO_STABILITY_PRIVATE }, 151 { PCIEX_ROOT, TOPO_STABILITY_PRIVATE }, 152 { PCIEX_SWUP, TOPO_STABILITY_PRIVATE }, 153 { PCIEX_SWDWN, TOPO_STABILITY_PRIVATE }, 154 { POWERMODULE, TOPO_STABILITY_PRIVATE }, 155 { PSU, TOPO_STABILITY_PRIVATE }, 156 { RANK, TOPO_STABILITY_PRIVATE }, 157 { RISER, TOPO_STABILITY_PRIVATE }, 158 { SHELF, TOPO_STABILITY_PRIVATE }, 159 { SES_ENCLOSURE, TOPO_STABILITY_PRIVATE }, 160 { SYSTEMBOARD, TOPO_STABILITY_PRIVATE }, 161 { XAUI, TOPO_STABILITY_PRIVATE }, 162 { XFP, TOPO_STABILITY_PRIVATE } 163 }; 164 165 static int hc_ncanon = sizeof (hc_canon) / sizeof (hcc_t); 166 167 int 168 hc_init(topo_mod_t *mod, topo_version_t version) 169 { 170 /* 171 * Turn on module debugging output 172 */ 173 if (getenv("TOPOHCDEBUG")) 174 topo_mod_setdebug(mod); 175 176 topo_mod_dprintf(mod, "initializing hc builtin\n"); 177 178 if (version != HC_VERSION) 179 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 180 181 if (topo_mod_register(mod, &hc_info, TOPO_VERSION) != 0) { 182 topo_mod_dprintf(mod, "failed to register hc: " 183 "%s\n", topo_mod_errmsg(mod)); 184 return (-1); /* mod errno already set */ 185 } 186 187 return (0); 188 } 189 190 void 191 hc_fini(topo_mod_t *mod) 192 { 193 topo_mod_unregister(mod); 194 } 195 196 197 static const topo_pgroup_info_t sys_pgroup = { 198 TOPO_PGROUP_SYSTEM, 199 TOPO_STABILITY_PRIVATE, 200 TOPO_STABILITY_PRIVATE, 201 1 202 }; 203 204 static const topo_pgroup_info_t auth_pgroup = { 205 FM_FMRI_AUTHORITY, 206 TOPO_STABILITY_PRIVATE, 207 TOPO_STABILITY_PRIVATE, 208 1 209 }; 210 211 static void 212 hc_prop_set(tnode_t *node, nvlist_t *auth) 213 { 214 int err; 215 char isa[MAXNAMELEN]; 216 struct utsname uts; 217 char *prod, *csn, *server; 218 219 if (auth == NULL) 220 return; 221 222 if (topo_pgroup_create(node, &auth_pgroup, &err) != 0) { 223 if (err != ETOPO_PROP_DEFD) 224 return; 225 } 226 227 /* 228 * Inherit if we can, it saves memory 229 */ 230 if ((topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_PRODUCT, 231 &err) != 0) && (err != ETOPO_PROP_DEFD)) { 232 if (nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT, &prod) 233 == 0) 234 (void) topo_prop_set_string(node, FM_FMRI_AUTHORITY, 235 FM_FMRI_AUTH_PRODUCT, TOPO_PROP_IMMUTABLE, prod, 236 &err); 237 } 238 if ((topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_CHASSIS, 239 &err) != 0) && (err != ETOPO_PROP_DEFD)) { 240 if (nvlist_lookup_string(auth, FM_FMRI_AUTH_CHASSIS, &csn) == 0) 241 (void) topo_prop_set_string(node, FM_FMRI_AUTHORITY, 242 FM_FMRI_AUTH_CHASSIS, TOPO_PROP_IMMUTABLE, csn, 243 &err); 244 } 245 if ((topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_SERVER, 246 &err) != 0) && (err != ETOPO_PROP_DEFD)) { 247 if (nvlist_lookup_string(auth, FM_FMRI_AUTH_SERVER, &server) 248 == 0) 249 (void) topo_prop_set_string(node, FM_FMRI_AUTHORITY, 250 FM_FMRI_AUTH_SERVER, TOPO_PROP_IMMUTABLE, server, 251 &err); 252 } 253 254 if (topo_pgroup_create(node, &sys_pgroup, &err) != 0) 255 return; 256 257 isa[0] = '\0'; 258 (void) sysinfo(SI_ARCHITECTURE, isa, sizeof (isa)); 259 (void) uname(&uts); 260 (void) topo_prop_set_string(node, TOPO_PGROUP_SYSTEM, TOPO_PROP_ISA, 261 TOPO_PROP_IMMUTABLE, isa, &err); 262 (void) topo_prop_set_string(node, TOPO_PGROUP_SYSTEM, TOPO_PROP_MACHINE, 263 TOPO_PROP_IMMUTABLE, uts.machine, &err); 264 } 265 266 /*ARGSUSED*/ 267 int 268 hc_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, topo_instance_t min, 269 topo_instance_t max, void *notused1, void *notused2) 270 { 271 nvlist_t *pfmri = NULL; 272 nvlist_t *nvl; 273 nvlist_t *auth; 274 tnode_t *node; 275 int err; 276 /* 277 * Register root node methods 278 */ 279 if (strcmp(name, HC) == 0) { 280 (void) topo_method_register(mod, pnode, hc_methods); 281 return (0); 282 } 283 if (min != max) { 284 topo_mod_dprintf(mod, 285 "Request to enumerate %s component with an " 286 "ambiguous instance number, min (%d) != max (%d).\n", 287 HC, min, max); 288 return (topo_mod_seterrno(mod, EINVAL)); 289 } 290 291 (void) topo_node_resource(pnode, &pfmri, &err); 292 auth = topo_mod_auth(mod, pnode); 293 nvl = hc_fmri_create(mod, pfmri, FM_HC_SCHEME_VERSION, name, min, 294 auth, NULL, NULL, NULL); 295 nvlist_free(pfmri); /* callee ignores NULLs */ 296 if (nvl == NULL) { 297 nvlist_free(auth); 298 return (-1); 299 } 300 301 if ((node = topo_node_bind(mod, pnode, name, min, nvl)) == NULL) { 302 topo_mod_dprintf(mod, "topo_node_bind failed: %s\n", 303 topo_strerror(topo_mod_errno(mod))); 304 nvlist_free(auth); 305 nvlist_free(nvl); 306 return (-1); 307 } 308 309 /* 310 * Set FRU for the motherboard node 311 */ 312 if (strcmp(name, MOTHERBOARD) == 0) 313 (void) topo_node_fru_set(node, nvl, 0, &err); 314 315 hc_prop_set(node, auth); 316 nvlist_free(nvl); 317 nvlist_free(auth); 318 319 return (0); 320 } 321 322 /*ARGSUSED*/ 323 static void 324 hc_release(topo_mod_t *mp, tnode_t *node) 325 { 326 topo_method_unregister_all(mp, node); 327 } 328 329 static int 330 fmri_compare(topo_mod_t *mod, nvlist_t *nv1, nvlist_t *nv2) 331 { 332 uint8_t v1, v2; 333 nvlist_t **hcp1, **hcp2; 334 nvlist_t *f1 = NULL, *f2 = NULL; 335 int err, i; 336 uint_t nhcp1, nhcp2; 337 char *f1str, *f2str; 338 339 if (nvlist_lookup_uint8(nv1, FM_VERSION, &v1) != 0 || 340 nvlist_lookup_uint8(nv2, FM_VERSION, &v2) != 0 || 341 v1 > FM_HC_SCHEME_VERSION || v2 > FM_HC_SCHEME_VERSION) 342 return (topo_mod_seterrno(mod, EMOD_FMRI_VERSION)); 343 344 err = nvlist_lookup_nvlist_array(nv1, FM_FMRI_HC_LIST, &hcp1, &nhcp1); 345 err |= nvlist_lookup_nvlist_array(nv2, FM_FMRI_HC_LIST, &hcp2, &nhcp2); 346 if (err != 0) 347 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 348 349 if (nhcp1 != nhcp2) 350 return (0); 351 352 for (i = 0; i < nhcp1; i++) { 353 char *nm1 = NULL; 354 char *nm2 = NULL; 355 char *id1 = NULL; 356 char *id2 = NULL; 357 358 (void) nvlist_lookup_string(hcp1[i], FM_FMRI_HC_NAME, &nm1); 359 (void) nvlist_lookup_string(hcp2[i], FM_FMRI_HC_NAME, &nm2); 360 (void) nvlist_lookup_string(hcp1[i], FM_FMRI_HC_ID, &id1); 361 (void) nvlist_lookup_string(hcp2[i], FM_FMRI_HC_ID, &id2); 362 if (nm1 == NULL || nm2 == NULL || id1 == NULL || id2 == NULL) 363 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 364 365 if (strcmp(nm1, nm2) == 0 && strcmp(id1, id2) == 0) 366 continue; 367 368 return (0); 369 } 370 371 /* 372 * Finally, check if the FMRI's represent a facility node. If so, then 373 * verify that the facilty type ("sensor"|"indicator") and facility 374 * name match. 375 */ 376 (void) nvlist_lookup_nvlist(nv1, FM_FMRI_FACILITY, &f1); 377 (void) nvlist_lookup_nvlist(nv2, FM_FMRI_FACILITY, &f2); 378 379 if (f1 == NULL && f2 == NULL) 380 return (1); 381 else if (f1 == NULL || f2 == NULL) 382 return (0); 383 384 if (nvlist_lookup_string(f1, FM_FMRI_FACILITY_NAME, &f1str) == 0 && 385 nvlist_lookup_string(f2, FM_FMRI_FACILITY_NAME, &f2str) == 0 && 386 strcmp(f1str, f2str) == 0 && 387 nvlist_lookup_string(f1, FM_FMRI_FACILITY_TYPE, &f1str) == 0 && 388 nvlist_lookup_string(f2, FM_FMRI_FACILITY_TYPE, &f2str) == 0 && 389 strcmp(f1str, f2str) == 0) { 390 return (1); 391 } 392 return (0); 393 } 394 395 /*ARGSUSED*/ 396 static int 397 hc_compare(topo_mod_t *mod, tnode_t *node, topo_version_t version, 398 nvlist_t *in, nvlist_t **out) 399 { 400 int ret; 401 uint32_t compare; 402 nvlist_t *nv1, *nv2; 403 404 if (version > TOPO_METH_COMPARE_VERSION) 405 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 406 407 if (nvlist_lookup_nvlist(in, TOPO_METH_FMRI_ARG_NV1, &nv1) != 0 || 408 nvlist_lookup_nvlist(in, TOPO_METH_FMRI_ARG_NV2, &nv2) != 0) 409 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 410 411 ret = fmri_compare(mod, nv1, nv2); 412 if (ret < 0) 413 return (-1); 414 415 compare = ret; 416 if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) == 0) { 417 if (nvlist_add_uint32(*out, TOPO_METH_COMPARE_RET, 418 compare) == 0) 419 return (0); 420 else 421 nvlist_free(*out); 422 } 423 424 return (-1); 425 } 426 427 static ssize_t 428 fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen) 429 { 430 nvlist_t **hcprs = NULL; 431 nvlist_t *anvl = NULL; 432 nvlist_t *fnvl; 433 uint8_t version; 434 ssize_t size = 0; 435 uint_t hcnprs; 436 char *achas = NULL; 437 char *adom = NULL; 438 char *aprod = NULL; 439 char *asrvr = NULL; 440 char *ahost = NULL; 441 char *serial = NULL; 442 char *part = NULL; 443 char *root = NULL; 444 char *rev = NULL; 445 char *fname = NULL, *ftype = NULL; 446 int more_auth = 0; 447 int err, i; 448 449 if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 || 450 version > FM_HC_SCHEME_VERSION) 451 return (-1); 452 453 /* Get authority, if present */ 454 err = nvlist_lookup_nvlist(nvl, FM_FMRI_AUTHORITY, &anvl); 455 if (err != 0 && err != ENOENT) 456 return (-1); 457 458 if ((err = nvlist_lookup_string(nvl, FM_FMRI_HC_ROOT, &root)) != 0) 459 return (-1); 460 461 err = nvlist_lookup_nvlist_array(nvl, FM_FMRI_HC_LIST, &hcprs, &hcnprs); 462 if (err != 0 || hcprs == NULL) 463 return (-1); 464 465 if (anvl != NULL) { 466 (void) nvlist_lookup_string(anvl, 467 FM_FMRI_AUTH_PRODUCT, &aprod); 468 (void) nvlist_lookup_string(anvl, 469 FM_FMRI_AUTH_CHASSIS, &achas); 470 (void) nvlist_lookup_string(anvl, 471 FM_FMRI_AUTH_DOMAIN, &adom); 472 (void) nvlist_lookup_string(anvl, 473 FM_FMRI_AUTH_SERVER, &asrvr); 474 (void) nvlist_lookup_string(anvl, 475 FM_FMRI_AUTH_HOST, &ahost); 476 if (aprod != NULL) 477 more_auth++; 478 if (achas != NULL) 479 more_auth++; 480 if (adom != NULL) 481 more_auth++; 482 if (asrvr != NULL) 483 more_auth++; 484 if (ahost != NULL) 485 more_auth++; 486 } 487 488 (void) nvlist_lookup_string(nvl, FM_FMRI_HC_SERIAL_ID, &serial); 489 (void) nvlist_lookup_string(nvl, FM_FMRI_HC_PART, &part); 490 (void) nvlist_lookup_string(nvl, FM_FMRI_HC_REVISION, &rev); 491 492 /* hc:// */ 493 topo_fmristr_build(&size, buf, buflen, FM_FMRI_SCHEME_HC, NULL, "://"); 494 495 /* authority, if any */ 496 if (aprod != NULL) 497 topo_fmristr_build(&size, 498 buf, buflen, aprod, ":" FM_FMRI_AUTH_PRODUCT "=", NULL); 499 if (achas != NULL) 500 topo_fmristr_build(&size, 501 buf, buflen, achas, ":" FM_FMRI_AUTH_CHASSIS "=", NULL); 502 if (adom != NULL) 503 topo_fmristr_build(&size, 504 buf, buflen, adom, ":" FM_FMRI_AUTH_DOMAIN "=", NULL); 505 if (asrvr != NULL) 506 topo_fmristr_build(&size, 507 buf, buflen, asrvr, ":" FM_FMRI_AUTH_SERVER "=", NULL); 508 if (ahost != NULL) 509 topo_fmristr_build(&size, 510 buf, buflen, ahost, ":" FM_FMRI_AUTH_HOST "=", NULL); 511 512 /* hardware-id part */ 513 topo_fmristr_build(&size, 514 buf, buflen, serial, ":" FM_FMRI_HC_SERIAL_ID "=", NULL); 515 topo_fmristr_build(&size, 516 buf, buflen, part, ":" FM_FMRI_HC_PART "=", NULL); 517 topo_fmristr_build(&size, 518 buf, buflen, rev, ":" FM_FMRI_HC_REVISION "=", NULL); 519 520 /* separating slash */ 521 topo_fmristr_build(&size, buf, buflen, "/", NULL, NULL); 522 523 /* hc-root */ 524 topo_fmristr_build(&size, buf, buflen, root, NULL, NULL); 525 526 /* all the pairs */ 527 for (i = 0; i < hcnprs; i++) { 528 char *nm = NULL; 529 char *id = NULL; 530 531 if (i > 0) 532 topo_fmristr_build(&size, 533 buf, buflen, "/", NULL, NULL); 534 (void) nvlist_lookup_string(hcprs[i], FM_FMRI_HC_NAME, &nm); 535 (void) nvlist_lookup_string(hcprs[i], FM_FMRI_HC_ID, &id); 536 if (nm == NULL || id == NULL) 537 return (0); 538 topo_fmristr_build(&size, buf, buflen, nm, NULL, "="); 539 topo_fmristr_build(&size, buf, buflen, id, NULL, NULL); 540 } 541 542 /* 543 * If the nvlist represents a facility node, then we append the 544 * facility type and name to the end of the string representation using 545 * the format below: 546 * 547 * ?<ftype>=<fname> 548 */ 549 if (nvlist_lookup_nvlist(nvl, FM_FMRI_FACILITY, &fnvl) == 0) { 550 if (nvlist_lookup_string(fnvl, FM_FMRI_FACILITY_NAME, 551 &fname) != 0 || nvlist_lookup_string(fnvl, 552 FM_FMRI_FACILITY_TYPE, &ftype) != 0) 553 return (0); 554 topo_fmristr_build(&size, buf, buflen, "?", NULL, NULL); 555 topo_fmristr_build(&size, buf, buflen, "=", ftype, fname); 556 } 557 558 return (size); 559 } 560 561 /*ARGSUSED*/ 562 static int 563 hc_fmri_nvl2str(topo_mod_t *mod, tnode_t *node, topo_version_t version, 564 nvlist_t *nvl, nvlist_t **out) 565 { 566 ssize_t len; 567 char *name = NULL; 568 nvlist_t *fmristr; 569 570 if (version > TOPO_METH_NVL2STR_VERSION) 571 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 572 573 if ((len = fmri_nvl2str(nvl, NULL, 0)) == 0 || 574 (name = topo_mod_alloc(mod, len + 1)) == NULL || 575 fmri_nvl2str(nvl, name, len + 1) == 0) { 576 if (name != NULL) 577 topo_mod_free(mod, name, len + 1); 578 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 579 } 580 581 if (topo_mod_nvalloc(mod, &fmristr, NV_UNIQUE_NAME) != 0) { 582 topo_mod_free(mod, name, len + 1); 583 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 584 } 585 if (nvlist_add_string(fmristr, "fmri-string", name) != 0) { 586 topo_mod_free(mod, name, len + 1); 587 nvlist_free(fmristr); 588 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 589 } 590 topo_mod_free(mod, name, len + 1); 591 *out = fmristr; 592 593 return (0); 594 } 595 596 static nvlist_t * 597 hc_base_fmri_create(topo_mod_t *mod, const nvlist_t *auth, const char *part, 598 const char *rev, const char *serial) 599 { 600 nvlist_t *fmri; 601 int err = 0; 602 603 /* 604 * Create base HC nvlist 605 */ 606 if (topo_mod_nvalloc(mod, &fmri, NV_UNIQUE_NAME) != 0) 607 return (NULL); 608 609 err = nvlist_add_uint8(fmri, FM_VERSION, FM_HC_SCHEME_VERSION); 610 err |= nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC); 611 err |= nvlist_add_string(fmri, FM_FMRI_HC_ROOT, ""); 612 if (err != 0) { 613 nvlist_free(fmri); 614 return (NULL); 615 } 616 617 /* 618 * Add optional payload members 619 */ 620 if (serial != NULL) 621 (void) nvlist_add_string(fmri, FM_FMRI_HC_SERIAL_ID, serial); 622 if (part != NULL) 623 (void) nvlist_add_string(fmri, FM_FMRI_HC_PART, part); 624 if (rev != NULL) 625 (void) nvlist_add_string(fmri, FM_FMRI_HC_REVISION, rev); 626 if (auth != NULL) 627 (void) nvlist_add_nvlist(fmri, FM_FMRI_AUTHORITY, 628 (nvlist_t *)auth); 629 630 return (fmri); 631 } 632 633 static nvlist_t ** 634 make_hc_pairs(topo_mod_t *mod, char *fmri, int *num) 635 { 636 nvlist_t **pa; 637 char *hc, *fromstr; 638 char *starti, *startn, *endi, *endi2; 639 char *ne, *ns; 640 char *cname = NULL; 641 char *find; 642 char *cid = NULL; 643 int nslashes = 0; 644 int npairs = 0; 645 int i, hclen; 646 647 if ((hc = topo_mod_strdup(mod, fmri + 5)) == NULL) 648 return (NULL); 649 650 hclen = strlen(hc) + 1; 651 652 /* 653 * Count equal signs and slashes to determine how many 654 * hc-pairs will be present in the final FMRI. There should 655 * be at least as many slashes as equal signs. There can be 656 * more, though if the string after an = includes them. 657 */ 658 if ((fromstr = strchr(hc, '/')) == NULL) 659 return (NULL); 660 661 find = fromstr; 662 while ((ne = strchr(find, '=')) != NULL) { 663 find = ne + 1; 664 npairs++; 665 } 666 667 find = fromstr; 668 while ((ns = strchr(find, '/')) != NULL) { 669 find = ns + 1; 670 nslashes++; 671 } 672 673 /* 674 * Do we appear to have a well-formed string version of the FMRI? 675 */ 676 if (nslashes < npairs || npairs == 0) { 677 topo_mod_free(mod, hc, hclen); 678 return (NULL); 679 } 680 681 *num = npairs; 682 683 find = fromstr; 684 685 if ((pa = topo_mod_zalloc(mod, npairs * sizeof (nvlist_t *))) == NULL) { 686 topo_mod_free(mod, hc, hclen); 687 return (NULL); 688 } 689 690 /* 691 * We go through a pretty complicated procedure to find the 692 * name and id for each pair. That's because, unfortunately, 693 * we have some ids that can have slashes within them. So 694 * we can't just search for the next slash after the equal sign 695 * and decide that starts a new pair. Instead we have to find 696 * an equal sign for the next pair and work our way back to the 697 * slash from there. 698 */ 699 for (i = 0; i < npairs; i++) { 700 startn = strchr(find, '/'); 701 if (startn == NULL) 702 break; 703 startn++; 704 starti = strchr(find, '='); 705 if (starti == NULL) 706 break; 707 *starti = '\0'; 708 if ((cname = topo_mod_strdup(mod, startn)) == NULL) 709 break; 710 *starti++ = '='; 711 endi = strchr(starti, '='); 712 if (endi != NULL) { 713 *endi = '\0'; 714 endi2 = strrchr(starti, '/'); 715 if (endi2 == NULL) 716 break; 717 *endi = '='; 718 *endi2 = '\0'; 719 if ((cid = topo_mod_strdup(mod, starti)) == NULL) 720 break; 721 *endi2 = '/'; 722 find = endi2; 723 } else { 724 if ((cid = topo_mod_strdup(mod, starti)) == NULL) 725 break; 726 find = starti + strlen(starti); 727 } 728 if (topo_mod_nvalloc(mod, &pa[i], NV_UNIQUE_NAME) < 0) 729 break; 730 731 if (nvlist_add_string(pa[i], FM_FMRI_HC_NAME, cname) || 732 nvlist_add_string(pa[i], FM_FMRI_HC_ID, cid)) 733 break; 734 735 topo_mod_strfree(mod, cname); 736 topo_mod_strfree(mod, cid); 737 cname = NULL; 738 cid = NULL; 739 } 740 741 topo_mod_strfree(mod, cname); 742 topo_mod_strfree(mod, cid); 743 744 if (i < npairs) { 745 for (i = 0; i < npairs; i++) 746 nvlist_free(pa[i]); 747 topo_mod_free(mod, pa, npairs * sizeof (nvlist_t *)); 748 topo_mod_free(mod, hc, hclen); 749 return (NULL); 750 } 751 752 topo_mod_free(mod, hc, hclen); 753 754 return (pa); 755 } 756 757 int 758 make_hc_auth(topo_mod_t *mod, char *fmri, char **serial, char **part, 759 char **rev, nvlist_t **auth) 760 { 761 char *starti, *startn, *endi, *copy; 762 char *aname = NULL, *aid = NULL, *fs; 763 nvlist_t *na = NULL; 764 size_t len; 765 766 if ((copy = topo_mod_strdup(mod, fmri + 5)) == NULL) 767 return (-1); 768 769 len = strlen(copy); 770 771 /* 772 * Make sure there are a valid authority members 773 */ 774 startn = strchr(copy, ':'); 775 fs = strchr(copy, '/'); 776 777 if (startn == NULL || fs == NULL) { 778 topo_mod_strfree(mod, copy); 779 return (0); 780 } 781 782 /* 783 * The first colon we encounter must occur before the 784 * first slash 785 */ 786 if (startn > fs) 787 goto hcabail; 788 789 do { 790 if (++startn >= copy + len) 791 break; 792 793 if ((starti = strchr(startn, '=')) == NULL) 794 goto hcabail; 795 796 *starti = '\0'; 797 if (++starti > copy + len) 798 goto hcabail; 799 800 if ((aname = topo_mod_strdup(mod, startn)) == NULL) 801 goto hcabail; 802 803 startn = endi = strchr(starti, ':'); 804 if (endi == NULL) 805 if ((endi = strchr(starti, '/')) == NULL) 806 break; 807 808 *endi = '\0'; 809 if ((aid = topo_mod_strdup(mod, starti)) == NULL) 810 goto hcabail; 811 812 /* 813 * Return possible serial, part and revision 814 */ 815 if (strcmp(aname, FM_FMRI_HC_SERIAL_ID) == 0) { 816 *serial = topo_mod_strdup(mod, aid); 817 } else if (strcmp(aname, FM_FMRI_HC_PART) == 0) { 818 *part = topo_mod_strdup(mod, aid); 819 } else if (strcmp(aname, FM_FMRI_HC_REVISION) == 0) { 820 *rev = topo_mod_strdup(mod, aid); 821 } else { 822 if (na == NULL) { 823 if (topo_mod_nvalloc(mod, &na, 824 NV_UNIQUE_NAME) == 0) { 825 (void) nvlist_add_string(na, aname, 826 aid); 827 } 828 } else { 829 (void) nvlist_add_string(na, aname, aid); 830 } 831 } 832 topo_mod_strfree(mod, aname); 833 topo_mod_strfree(mod, aid); 834 aname = aid = NULL; 835 836 } while (startn != NULL); 837 838 *auth = na; 839 840 topo_mod_free(mod, copy, len + 1); 841 return (0); 842 843 hcabail: 844 topo_mod_free(mod, copy, len + 1); 845 topo_mod_strfree(mod, aname); 846 topo_mod_strfree(mod, aid); 847 nvlist_free(na); 848 return (-1); 849 } 850 851 852 /* 853 * This function creates an nvlist to represent the facility portion of an 854 * hc-scheme node, given a string representation of the fmri. This is called by 855 * hc_fmri_str2nvl. If the string does not contain a facility component 856 * (e.g. ?<ftype>=<fname>) then it bails early and returns 0. 857 * 858 * On failure it returns -1 and sets the topo mod errno 859 */ 860 int 861 make_facility(topo_mod_t *mod, char *str, nvlist_t **nvl) 862 { 863 char *fac, *copy, *fname, *ftype; 864 nvlist_t *nf = NULL; 865 size_t len; 866 867 if ((fac = strchr(str, '?')) == NULL) 868 return (0); 869 870 ++fac; 871 if ((copy = topo_mod_strdup(mod, fac)) == NULL) 872 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 873 874 fac = copy; 875 len = strlen(fac); 876 877 if ((fname = strchr(fac, '=')) == NULL) { 878 topo_mod_free(mod, copy, len + 1); 879 return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 880 } 881 882 fname[0] = '\0'; 883 ++fname; 884 ftype = fac; 885 886 if (topo_mod_nvalloc(mod, &nf, NV_UNIQUE_NAME) != 0) { 887 topo_mod_free(mod, copy, len + 1); 888 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 889 } 890 891 if (nvlist_add_string(nf, FM_FMRI_FACILITY_NAME, fname) != 0 || 892 nvlist_add_string(nf, FM_FMRI_FACILITY_TYPE, ftype) != 0) { 893 topo_mod_free(mod, copy, len + 1); 894 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 895 } 896 897 topo_mod_free(mod, copy, len + 1); 898 899 *nvl = nf; 900 901 return (0); 902 } 903 904 /*ARGSUSED*/ 905 static int 906 hc_fmri_str2nvl(topo_mod_t *mod, tnode_t *node, topo_version_t version, 907 nvlist_t *in, nvlist_t **out) 908 { 909 nvlist_t **pa = NULL; 910 nvlist_t *nf = NULL; 911 nvlist_t *auth = NULL; 912 nvlist_t *fac = NULL; 913 char *str; 914 char *serial = NULL, *part = NULL, *rev = NULL; 915 int npairs; 916 int i, e; 917 918 if (version > TOPO_METH_STR2NVL_VERSION) 919 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 920 921 if (nvlist_lookup_string(in, "fmri-string", &str) != 0) 922 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 923 924 /* We're expecting a string version of an hc scheme FMRI */ 925 if (strncmp(str, "hc://", 5) != 0) 926 return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 927 928 if ((pa = make_hc_pairs(mod, str, &npairs)) == NULL) 929 return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 930 931 if (make_hc_auth(mod, str, &serial, &part, &rev, &auth) < 0) 932 goto hcfmbail; 933 934 if ((nf = hc_base_fmri_create(mod, auth, part, rev, serial)) == NULL) 935 goto hcfmbail; 936 if ((e = nvlist_add_uint32(nf, FM_FMRI_HC_LIST_SZ, npairs)) == 0) 937 e = nvlist_add_nvlist_array(nf, FM_FMRI_HC_LIST, pa, npairs); 938 if (e != 0) { 939 topo_mod_dprintf(mod, "construction of new hc nvl failed"); 940 goto hcfmbail; 941 } 942 943 /* 944 * Clean-up 945 */ 946 for (i = 0; i < npairs; i++) 947 nvlist_free(pa[i]); 948 topo_mod_free(mod, pa, npairs * sizeof (nvlist_t *)); 949 topo_mod_strfree(mod, serial); 950 topo_mod_strfree(mod, part); 951 topo_mod_strfree(mod, rev); 952 nvlist_free(auth); 953 954 if (make_facility(mod, str, &fac) == -1) 955 goto hcfmbail; 956 957 if (fac != NULL) { 958 if (nvlist_add_nvlist(nf, FM_FMRI_FACILITY, fac) != 0) 959 goto hcfmbail; 960 } 961 962 *out = nf; 963 964 return (0); 965 966 hcfmbail: 967 if (nf != NULL) 968 nvlist_free(nf); 969 for (i = 0; i < npairs; i++) 970 nvlist_free(pa[i]); 971 topo_mod_free(mod, pa, npairs * sizeof (nvlist_t *)); 972 973 topo_mod_strfree(mod, serial); 974 topo_mod_strfree(mod, part); 975 topo_mod_strfree(mod, rev); 976 nvlist_free(auth); 977 nvlist_free(nf); 978 return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); 979 } 980 981 static nvlist_t * 982 hc_list_create(topo_mod_t *mod, const char *name, char *inst) 983 { 984 int err; 985 nvlist_t *hc; 986 987 if (topo_mod_nvalloc(mod, &hc, NV_UNIQUE_NAME) != 0) 988 return (NULL); 989 990 err = nvlist_add_string(hc, FM_FMRI_HC_NAME, name); 991 err |= nvlist_add_string(hc, FM_FMRI_HC_ID, inst); 992 if (err != 0) { 993 nvlist_free(hc); 994 return (NULL); 995 } 996 997 return (hc); 998 } 999 1000 static nvlist_t * 1001 hc_create_seterror(topo_mod_t *mod, nvlist_t **hcl, int n, nvlist_t *fmri, 1002 int err) 1003 { 1004 int i; 1005 1006 if (hcl != NULL) { 1007 for (i = 0; i < n + 1; ++i) 1008 nvlist_free(hcl[i]); 1009 1010 topo_mod_free(mod, hcl, sizeof (nvlist_t *) * (n + 1)); 1011 } 1012 1013 nvlist_free(fmri); 1014 1015 (void) topo_mod_seterrno(mod, err); 1016 1017 topo_mod_dprintf(mod, "unable to create hc FMRI: %s\n", 1018 topo_mod_errmsg(mod)); 1019 1020 return (NULL); 1021 } 1022 1023 static int 1024 hc_name_canonical(topo_mod_t *mod, const char *name) 1025 { 1026 int i; 1027 1028 if (getenv("NOHCCHECK") != NULL) 1029 return (1); 1030 1031 /* 1032 * Only enumerate elements with correct canonical names 1033 */ 1034 for (i = 0; i < hc_ncanon; i++) { 1035 if (strcmp(name, hc_canon[i].hcc_name) == 0) 1036 break; 1037 } 1038 if (i >= hc_ncanon) { 1039 topo_mod_dprintf(mod, "non-canonical name %s\n", 1040 name); 1041 return (0); 1042 } else { 1043 return (1); 1044 } 1045 } 1046 1047 static nvlist_t * 1048 hc_fmri_create(topo_mod_t *mod, nvlist_t *pfmri, int version, const char *name, 1049 topo_instance_t inst, const nvlist_t *auth, const char *part, 1050 const char *rev, const char *serial) 1051 { 1052 int i; 1053 char str[21]; /* sizeof (UINT64_MAX) + '\0' */ 1054 uint_t pelems = 0; 1055 nvlist_t **phcl = NULL; 1056 nvlist_t **hcl = NULL; 1057 nvlist_t *fmri = NULL; 1058 1059 if (version > FM_HC_SCHEME_VERSION) 1060 return (hc_create_seterror(mod, 1061 hcl, pelems, fmri, EMOD_VER_OLD)); 1062 else if (version < FM_HC_SCHEME_VERSION) 1063 return (hc_create_seterror(mod, 1064 hcl, pelems, fmri, EMOD_VER_NEW)); 1065 1066 /* 1067 * Check that the requested name is in our canonical list 1068 */ 1069 if (hc_name_canonical(mod, name) == 0) 1070 return (hc_create_seterror(mod, 1071 hcl, pelems, fmri, EMOD_NONCANON)); 1072 /* 1073 * Copy the parent's HC_LIST 1074 */ 1075 if (pfmri != NULL) { 1076 if (nvlist_lookup_nvlist_array(pfmri, FM_FMRI_HC_LIST, 1077 &phcl, &pelems) != 0) 1078 return (hc_create_seterror(mod, 1079 hcl, pelems, fmri, EMOD_FMRI_MALFORM)); 1080 } 1081 1082 hcl = topo_mod_zalloc(mod, sizeof (nvlist_t *) * (pelems + 1)); 1083 if (hcl == NULL) 1084 return (hc_create_seterror(mod, hcl, pelems, fmri, 1085 EMOD_NOMEM)); 1086 1087 for (i = 0; i < pelems; ++i) 1088 if (topo_mod_nvdup(mod, phcl[i], &hcl[i]) != 0) 1089 return (hc_create_seterror(mod, 1090 hcl, pelems, fmri, EMOD_FMRI_NVL)); 1091 1092 (void) snprintf(str, sizeof (str), "%d", inst); 1093 if ((hcl[i] = hc_list_create(mod, name, str)) == NULL) 1094 return (hc_create_seterror(mod, 1095 hcl, pelems, fmri, EMOD_FMRI_NVL)); 1096 1097 if ((fmri = hc_base_fmri_create(mod, auth, part, rev, serial)) == NULL) 1098 return (hc_create_seterror(mod, 1099 hcl, pelems, fmri, EMOD_FMRI_NVL)); 1100 1101 if (nvlist_add_nvlist_array(fmri, FM_FMRI_HC_LIST, hcl, pelems + 1) 1102 != 0) 1103 return (hc_create_seterror(mod, 1104 hcl, pelems, fmri, EMOD_FMRI_NVL)); 1105 1106 if (hcl != NULL) { 1107 for (i = 0; i < pelems + 1; ++i) { 1108 if (hcl[i] != NULL) 1109 nvlist_free(hcl[i]); 1110 } 1111 topo_mod_free(mod, hcl, sizeof (nvlist_t *) * (pelems + 1)); 1112 } 1113 1114 return (fmri); 1115 } 1116 1117 /*ARGSUSED*/ 1118 static int 1119 hc_fmri_create_meth(topo_mod_t *mod, tnode_t *node, topo_version_t version, 1120 nvlist_t *in, nvlist_t **out) 1121 { 1122 int ret; 1123 nvlist_t *args, *pfmri = NULL; 1124 nvlist_t *auth; 1125 uint32_t inst; 1126 char *name, *serial, *rev, *part; 1127 1128 if (version > TOPO_METH_FMRI_VERSION) 1129 return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 1130 1131 /* First the must-have fields */ 1132 if (nvlist_lookup_string(in, TOPO_METH_FMRI_ARG_NAME, &name) != 0) 1133 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 1134 if (nvlist_lookup_uint32(in, TOPO_METH_FMRI_ARG_INST, &inst) != 0) 1135 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 1136 1137 /* 1138 * args is optional 1139 */ 1140 pfmri = NULL; 1141 auth = NULL; 1142 serial = rev = part = NULL; 1143 if ((ret = nvlist_lookup_nvlist(in, TOPO_METH_FMRI_ARG_NVL, &args)) 1144 != 0) { 1145 if (ret != ENOENT) 1146 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 1147 } else { 1148 1149 /* And then optional arguments */ 1150 (void) nvlist_lookup_nvlist(args, TOPO_METH_FMRI_ARG_PARENT, 1151 &pfmri); 1152 (void) nvlist_lookup_nvlist(args, TOPO_METH_FMRI_ARG_AUTH, 1153 &auth); 1154 (void) nvlist_lookup_string(args, TOPO_METH_FMRI_ARG_PART, 1155 &part); 1156 (void) nvlist_lookup_string(args, TOPO_METH_FMRI_ARG_REV, &rev); 1157 (void) nvlist_lookup_string(args, TOPO_METH_FMRI_ARG_SER, 1158 &serial); 1159 } 1160 1161 *out = hc_fmri_create(mod, pfmri, version, name, inst, auth, part, 1162 rev, serial); 1163 if (*out == NULL) 1164 return (-1); 1165 return (0); 1166 } 1167 1168 struct hc_walk { 1169 topo_mod_walk_cb_t hcw_cb; 1170 void *hcw_priv; 1171 topo_walk_t *hcw_wp; 1172 nvlist_t **hcw_list; 1173 nvlist_t *hcw_fmri; 1174 nvlist_t *hcw_fac; 1175 uint_t hcw_index; 1176 uint_t hcw_end; 1177 }; 1178 1179 /* 1180 * Returns true if the given node is beneath the specified FMRI. This uses 1181 * the TOPO_METH_CONTAINS method, because some enumerators (such as external 1182 * enclosures) may want to do a comparison based on chassis WWN instead of the 1183 * instance ID. If this comparison function fails or is not supported, then we 1184 * fall back to a direct name/instance comparison. 1185 */ 1186 static int 1187 hc_match(topo_mod_t *mod, tnode_t *node, nvlist_t *fmri, const char *name, 1188 topo_instance_t inst, boolean_t *result) 1189 { 1190 nvlist_t *rsrc; 1191 nvlist_t *arg, *nvl; 1192 uint32_t match = 0; 1193 int err; 1194 1195 if (topo_node_resource(node, &rsrc, &err) != 0) 1196 return (-1); 1197 1198 if (topo_mod_nvalloc(mod, &arg, NV_UNIQUE_NAME) != 0 || 1199 nvlist_add_nvlist(arg, TOPO_METH_FMRI_ARG_FMRI, 1200 rsrc) != 0 || 1201 nvlist_add_nvlist(arg, TOPO_METH_FMRI_ARG_SUBFMRI, 1202 fmri) != 0) { 1203 nvlist_free(rsrc); 1204 (void) topo_mod_seterrno(mod, EMOD_NOMEM); 1205 return (-1); 1206 } 1207 1208 nvlist_free(rsrc); 1209 1210 if (topo_method_invoke(node, TOPO_METH_CONTAINS, 1211 TOPO_METH_CONTAINS_VERSION, arg, &nvl, &err) != 0) { 1212 nvlist_free(arg); 1213 if (err == ETOPO_METHOD_NOTSUP) { 1214 match = (strcmp(name, 1215 topo_node_name(node)) == 0 && 1216 inst == topo_node_instance(node)); 1217 } else { 1218 return (-1); 1219 } 1220 } else { 1221 nvlist_free(arg); 1222 if (nvlist_lookup_uint32(nvl, TOPO_METH_CONTAINS_RET, 1223 &match) != 0) { 1224 nvlist_free(nvl); 1225 (void) topo_mod_seterrno(mod, EMOD_NVL_INVAL); 1226 return (-1); 1227 } 1228 nvlist_free(nvl); 1229 } 1230 1231 *result = (match != 0); 1232 return (0); 1233 } 1234 1235 /* 1236 * Ideally, we should just be able to call topo_walk_bysibling(). But that 1237 * code assumes that the name/instance pair will match, so we need to 1238 * explicitly iterate over children of the parent looking for a matching value. 1239 */ 1240 static int 1241 hc_walk_sibling(topo_mod_t *mod, tnode_t *node, struct hc_walk *hwp, 1242 const char *name, topo_instance_t inst) 1243 { 1244 tnode_t *pnp = topo_node_parent(node); 1245 topo_walk_t *wp = hwp->hcw_wp; 1246 tnode_t *np; 1247 boolean_t matched; 1248 int status; 1249 1250 for (np = topo_child_first(pnp); np != NULL; 1251 np = topo_child_next(pnp, np)) { 1252 topo_node_hold(np); 1253 if (hc_match(mod, np, hwp->hcw_fmri, name, inst, 1254 &matched) == 0 && matched) { 1255 wp->tw_node = np; 1256 if (wp->tw_mod != NULL) 1257 status = wp->tw_cb(mod, np, hwp); 1258 else 1259 status = wp->tw_cb(wp->tw_thp, np, hwp); 1260 topo_node_rele(np); 1261 wp->tw_node = node; 1262 return (status); 1263 } 1264 1265 topo_node_rele(np); 1266 } 1267 1268 return (TOPO_WALK_TERMINATE); 1269 } 1270 1271 /* 1272 * Generic walker for the hc-scheme topo tree. This function uses the 1273 * hierachical nature of the hc-scheme to efficiently step through 1274 * the topo hc tree. Node lookups are done by topo_walk_byid() and 1275 * topo_walk_bysibling() at each component level to avoid unnecessary 1276 * traversal of the tree. hc_walker() never returns TOPO_WALK_NEXT, so 1277 * whether TOPO_WALK_CHILD or TOPO_WALK_SIBLING is specified by 1278 * topo_walk_step() doesn't affect the traversal. 1279 */ 1280 static int 1281 hc_walker(topo_mod_t *mod, tnode_t *node, void *pdata) 1282 { 1283 int i, err; 1284 struct hc_walk *hwp = (struct hc_walk *)pdata; 1285 char *name, *id; 1286 char *fname, *ftype; 1287 topo_instance_t inst; 1288 boolean_t match; 1289 1290 i = hwp->hcw_index; 1291 if (i > hwp->hcw_end) { 1292 if (hwp->hcw_fac != NULL) { 1293 if ((err = hwp->hcw_cb(mod, node, hwp->hcw_priv)) 1294 != 0) { 1295 (void) topo_mod_seterrno(mod, err); 1296 topo_mod_dprintf(mod, "hc_walker: callback " 1297 "failed: %s\n ", topo_mod_errmsg(mod)); 1298 return (TOPO_WALK_ERR); 1299 } 1300 topo_mod_dprintf(mod, "hc_walker: callback " 1301 "complete: terminate walk\n"); 1302 return (TOPO_WALK_TERMINATE); 1303 } else { 1304 topo_mod_dprintf(mod, "hc_walker: node not found\n"); 1305 return (TOPO_WALK_TERMINATE); 1306 } 1307 } 1308 1309 err = nvlist_lookup_string(hwp->hcw_list[i], FM_FMRI_HC_NAME, &name); 1310 err |= nvlist_lookup_string(hwp->hcw_list[i], FM_FMRI_HC_ID, &id); 1311 1312 if (err != 0) { 1313 (void) topo_mod_seterrno(mod, EMOD_NVL_INVAL); 1314 return (TOPO_WALK_ERR); 1315 } 1316 1317 inst = atoi(id); 1318 1319 /* 1320 * Check to see if our node matches the requested FMRI. If it doesn't 1321 * (because the enumerator determines matching based on something other 1322 * than name/instance, or because we're at the first level below the 1323 * root), then iterate over siblings to find the matching node. 1324 */ 1325 if (hc_match(mod, node, hwp->hcw_fmri, name, inst, &match) != 0) 1326 return (TOPO_WALK_ERR); 1327 1328 if (!match) 1329 return (hc_walk_sibling(mod, node, hwp, name, inst)); 1330 1331 topo_mod_dprintf(mod, "hc_walker: walking node:%s=%d for hc:" 1332 "%s=%d at %d, end at %d \n", topo_node_name(node), 1333 topo_node_instance(node), name, inst, i, hwp->hcw_end); 1334 1335 if (i == hwp->hcw_end) { 1336 1337 /* 1338 * We are at the end of the hc-list. Now, check for 1339 * a facility leaf and walk one more time. 1340 */ 1341 if (hwp->hcw_fac != NULL) { 1342 err = nvlist_lookup_string(hwp->hcw_fac, 1343 FM_FMRI_FACILITY_NAME, &fname); 1344 err |= nvlist_lookup_string(hwp->hcw_fac, 1345 FM_FMRI_FACILITY_TYPE, &ftype); 1346 if (err != 0) { 1347 (void) topo_mod_seterrno(mod, EMOD_NVL_INVAL); 1348 return (TOPO_WALK_ERR); 1349 } 1350 hwp->hcw_index++; 1351 topo_mod_dprintf(mod, "hc_walker: walk to facility " 1352 "node:%s=%s\n", fname, ftype); 1353 return (topo_walk_byid(hwp->hcw_wp, fname, 0)); 1354 } 1355 1356 /* 1357 * Otherwise, this is the node we're looking for. 1358 */ 1359 if ((err = hwp->hcw_cb(mod, node, hwp->hcw_priv)) != 0) { 1360 (void) topo_mod_seterrno(mod, err); 1361 topo_mod_dprintf(mod, "hc_walker: callback " 1362 "failed: %s\n ", topo_mod_errmsg(mod)); 1363 return (TOPO_WALK_ERR); 1364 } else { 1365 topo_mod_dprintf(mod, "hc_walker: callback " 1366 "complete: terminate walk\n"); 1367 return (TOPO_WALK_TERMINATE); 1368 } 1369 } 1370 1371 /* 1372 * Move on to the next component in the hc-list 1373 */ 1374 hwp->hcw_index = ++i; 1375 err = nvlist_lookup_string(hwp->hcw_list[i], FM_FMRI_HC_NAME, &name); 1376 err |= nvlist_lookup_string(hwp->hcw_list[i], FM_FMRI_HC_ID, &id); 1377 if (err != 0) { 1378 (void) topo_mod_seterrno(mod, err); 1379 return (TOPO_WALK_ERR); 1380 } 1381 inst = atoi(id); 1382 1383 return (topo_walk_byid(hwp->hcw_wp, name, inst)); 1384 1385 } 1386 1387 static struct hc_walk * 1388 hc_walk_init(topo_mod_t *mod, tnode_t *node, nvlist_t *rsrc, 1389 topo_mod_walk_cb_t cb, void *pdata) 1390 { 1391 int err, ret; 1392 uint_t sz; 1393 struct hc_walk *hwp; 1394 topo_walk_t *wp; 1395 1396 if ((hwp = topo_mod_alloc(mod, sizeof (struct hc_walk))) == NULL) { 1397 (void) topo_mod_seterrno(mod, EMOD_NOMEM); 1398 return (NULL); 1399 } 1400 1401 if (nvlist_lookup_nvlist_array(rsrc, FM_FMRI_HC_LIST, &hwp->hcw_list, 1402 &sz) != 0) { 1403 topo_mod_dprintf(mod, "hc_walk_init: failed to lookup %s " 1404 "nvlist\n", FM_FMRI_HC_LIST); 1405 topo_mod_free(mod, hwp, sizeof (struct hc_walk)); 1406 (void) topo_mod_seterrno(mod, EMOD_METHOD_INVAL); 1407 return (NULL); 1408 } 1409 if ((ret = nvlist_lookup_nvlist(rsrc, FM_FMRI_FACILITY, &hwp->hcw_fac)) 1410 != 0) { 1411 if (ret != ENOENT) { 1412 topo_mod_dprintf(mod, "hc_walk_init: unexpected error " 1413 "looking up %s nvlist", FM_FMRI_FACILITY); 1414 topo_mod_free(mod, hwp, sizeof (struct hc_walk)); 1415 (void) topo_mod_seterrno(mod, EMOD_METHOD_INVAL); 1416 return (NULL); 1417 } else { 1418 hwp->hcw_fac = NULL; 1419 } 1420 } 1421 1422 hwp->hcw_fmri = rsrc; 1423 hwp->hcw_end = sz - 1; 1424 hwp->hcw_index = 0; 1425 hwp->hcw_priv = pdata; 1426 hwp->hcw_cb = cb; 1427 if ((wp = topo_mod_walk_init(mod, node, hc_walker, (void *)hwp, &err)) 1428 == NULL) { 1429 topo_mod_dprintf(mod, "hc_walk_init: topo_mod_walk_init failed " 1430 "(%s)\n", topo_strerror(err)); 1431 topo_mod_free(mod, hwp, sizeof (struct hc_walk)); 1432 (void) topo_mod_seterrno(mod, err); 1433 return (NULL); 1434 } 1435 1436 hwp->hcw_wp = wp; 1437 1438 return (hwp); 1439 } 1440 1441 struct prop_lookup { 1442 const char *pl_pgroup; 1443 const char *pl_pname; 1444 int pl_flag; 1445 nvlist_t *pl_args; 1446 nvlist_t *pl_rsrc; 1447 nvlist_t *pl_prop; 1448 }; 1449 1450 /*ARGSUSED*/ 1451 static int 1452 hc_prop_get(topo_mod_t *mod, tnode_t *node, void *pdata) 1453 { 1454 int err = 0; 1455 1456 struct prop_lookup *plp = (struct prop_lookup *)pdata; 1457 1458 (void) topo_prop_getprop(node, plp->pl_pgroup, plp->pl_pname, 1459 plp->pl_args, &plp->pl_prop, &err); 1460 1461 return (err); 1462 } 1463 1464 static int 1465 hc_fmri_prop_get(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 prop_lookup *plp; 1471 1472 if (version > TOPO_METH_PROP_GET_VERSION) 1473 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW)); 1474 1475 if ((plp = topo_mod_alloc(mod, sizeof (struct prop_lookup))) == NULL) 1476 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 1477 1478 err = nvlist_lookup_string(in, TOPO_PROP_GROUP, 1479 (char **)&plp->pl_pgroup); 1480 err |= nvlist_lookup_string(in, TOPO_PROP_VAL_NAME, 1481 (char **)&plp->pl_pname); 1482 err |= nvlist_lookup_nvlist(in, TOPO_PROP_RESOURCE, &plp->pl_rsrc); 1483 if (err != 0) { 1484 topo_mod_free(mod, plp, sizeof (struct prop_lookup)); 1485 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 1486 } 1487 1488 /* 1489 * Private args to prop method are optional 1490 */ 1491 if ((err = nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &plp->pl_args)) 1492 != 0) { 1493 if (err != ENOENT) { 1494 topo_mod_free(mod, plp, sizeof (struct prop_lookup)); 1495 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 1496 } else { 1497 plp->pl_args = NULL; 1498 } 1499 } 1500 1501 plp->pl_prop = NULL; 1502 if ((hwp = hc_walk_init(mod, node, plp->pl_rsrc, hc_prop_get, 1503 (void *)plp)) != NULL) { 1504 if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) == 1505 TOPO_WALK_ERR) 1506 err = -1; 1507 else 1508 err = 0; 1509 topo_walk_fini(hwp->hcw_wp); 1510 topo_mod_free(mod, hwp, sizeof (struct hc_walk)); 1511 } else { 1512 err = -1; 1513 } 1514 1515 if (plp->pl_prop != NULL) 1516 *out = plp->pl_prop; 1517 1518 topo_mod_free(mod, plp, sizeof (struct prop_lookup)); 1519 1520 return (err); 1521 } 1522 1523 /*ARGSUSED*/ 1524 static int 1525 hc_pgrp_get(topo_mod_t *mod, tnode_t *node, void *pdata) 1526 { 1527 int err = 0; 1528 1529 struct prop_lookup *plp = (struct prop_lookup *)pdata; 1530 1531 (void) topo_prop_getpgrp(node, plp->pl_pgroup, &plp->pl_prop, &err); 1532 1533 return (err); 1534 } 1535 1536 static int 1537 hc_fmri_pgrp_get(topo_mod_t *mod, tnode_t *node, topo_version_t version, 1538 nvlist_t *in, nvlist_t **out) 1539 { 1540 int err; 1541 struct hc_walk *hwp; 1542 struct prop_lookup *plp; 1543 1544 if (version > TOPO_METH_PGRP_GET_VERSION) 1545 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW)); 1546 1547 if ((plp = topo_mod_alloc(mod, sizeof (struct prop_lookup))) == NULL) 1548 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 1549 1550 err = nvlist_lookup_string(in, TOPO_PROP_GROUP, 1551 (char **)&plp->pl_pgroup); 1552 err |= nvlist_lookup_nvlist(in, TOPO_PROP_RESOURCE, &plp->pl_rsrc); 1553 if (err != 0) { 1554 topo_mod_free(mod, plp, sizeof (struct prop_lookup)); 1555 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 1556 } 1557 1558 plp->pl_prop = NULL; 1559 if ((hwp = hc_walk_init(mod, node, plp->pl_rsrc, hc_pgrp_get, 1560 (void *)plp)) != NULL) { 1561 if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) == 1562 TOPO_WALK_ERR) 1563 err = -1; 1564 else 1565 err = 0; 1566 topo_walk_fini(hwp->hcw_wp); 1567 topo_mod_free(mod, hwp, sizeof (struct hc_walk)); 1568 } else { 1569 err = -1; 1570 } 1571 1572 if (plp->pl_prop != NULL) 1573 *out = plp->pl_prop; 1574 1575 topo_mod_free(mod, plp, sizeof (struct prop_lookup)); 1576 1577 return (err); 1578 } 1579 1580 /*ARGSUSED*/ 1581 static int 1582 hc_prop_setprop(topo_mod_t *mod, tnode_t *node, void *pdata) 1583 { 1584 int err = 0; 1585 1586 struct prop_lookup *plp = (struct prop_lookup *)pdata; 1587 1588 (void) topo_prop_setprop(node, plp->pl_pgroup, plp->pl_prop, 1589 plp->pl_flag, plp->pl_args, &err); 1590 1591 return (err); 1592 } 1593 1594 /*ARGSUSED*/ 1595 static int 1596 hc_fmri_prop_set(topo_mod_t *mod, tnode_t *node, topo_version_t version, 1597 nvlist_t *in, nvlist_t **out) 1598 { 1599 int err; 1600 struct hc_walk *hwp; 1601 struct prop_lookup *plp; 1602 1603 if (version > TOPO_METH_PROP_SET_VERSION) 1604 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW)); 1605 1606 if ((plp = topo_mod_alloc(mod, sizeof (struct prop_lookup))) == NULL) 1607 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 1608 1609 err = nvlist_lookup_string(in, TOPO_PROP_GROUP, 1610 (char **)&plp->pl_pgroup); 1611 err |= nvlist_lookup_nvlist(in, TOPO_PROP_RESOURCE, &plp->pl_rsrc); 1612 err |= nvlist_lookup_nvlist(in, TOPO_PROP_VAL, &plp->pl_prop); 1613 err |= nvlist_lookup_int32(in, TOPO_PROP_FLAG, &plp->pl_flag); 1614 if (err != 0) { 1615 topo_mod_free(mod, plp, sizeof (struct prop_lookup)); 1616 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 1617 } 1618 1619 /* 1620 * Private args to prop method are optional 1621 */ 1622 if ((err = nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &plp->pl_args)) 1623 != 0) { 1624 if (err != ENOENT) 1625 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 1626 else 1627 plp->pl_args = NULL; 1628 } 1629 1630 if ((hwp = hc_walk_init(mod, node, plp->pl_rsrc, hc_prop_setprop, 1631 (void *)plp)) != NULL) { 1632 if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) == 1633 TOPO_WALK_ERR) 1634 err = -1; 1635 else 1636 err = 0; 1637 topo_walk_fini(hwp->hcw_wp); 1638 topo_mod_free(mod, hwp, sizeof (struct hc_walk)); 1639 } else { 1640 err = -1; 1641 } 1642 1643 topo_mod_free(mod, plp, sizeof (struct prop_lookup)); 1644 1645 return (err); 1646 } 1647 1648 struct hc_args { 1649 nvlist_t *ha_fmri; 1650 nvlist_t *ha_nvl; 1651 }; 1652 1653 static int 1654 hc_is_present(topo_mod_t *mod, tnode_t *node, void *pdata) 1655 { 1656 int err; 1657 struct hc_args *hap = (struct hc_args *)pdata; 1658 1659 /* 1660 * check with the enumerator that created this FMRI 1661 * (topo node) 1662 */ 1663 if (topo_method_invoke(node, TOPO_METH_PRESENT, 1664 TOPO_METH_PRESENT_VERSION, hap->ha_fmri, &hap->ha_nvl, 1665 &err) < 0) { 1666 1667 /* 1668 * Err on the side of caution and return present 1669 */ 1670 if (topo_mod_nvalloc(mod, &hap->ha_nvl, NV_UNIQUE_NAME) == 0) 1671 if (nvlist_add_uint32(hap->ha_nvl, 1672 TOPO_METH_PRESENT_RET, 1) == 0) 1673 return (0); 1674 1675 return (ETOPO_PROP_NVL); 1676 } 1677 1678 return (0); 1679 } 1680 1681 static int 1682 hc_fmri_present(topo_mod_t *mod, tnode_t *node, topo_version_t version, 1683 nvlist_t *in, nvlist_t **out) 1684 { 1685 int err; 1686 struct hc_walk *hwp; 1687 struct hc_args *hap; 1688 1689 if (version > TOPO_METH_PRESENT_VERSION) 1690 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW)); 1691 1692 if ((hap = topo_mod_alloc(mod, sizeof (struct hc_args))) == NULL) 1693 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 1694 1695 hap->ha_fmri = in; 1696 hap->ha_nvl = NULL; 1697 if ((hwp = hc_walk_init(mod, node, hap->ha_fmri, hc_is_present, 1698 (void *)hap)) != NULL) { 1699 if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) == 1700 TOPO_WALK_ERR) 1701 err = -1; 1702 else 1703 err = 0; 1704 topo_walk_fini(hwp->hcw_wp); 1705 topo_mod_free(mod, hwp, sizeof (struct hc_walk)); 1706 } else { 1707 err = -1; 1708 } 1709 1710 if (hap->ha_nvl != NULL) 1711 *out = hap->ha_nvl; 1712 1713 topo_mod_free(mod, hap, sizeof (struct hc_args)); 1714 1715 return (err); 1716 } 1717 1718 static int 1719 hc_unusable(topo_mod_t *mod, tnode_t *node, void *pdata) 1720 { 1721 int err; 1722 struct hc_args *hap = (struct hc_args *)pdata; 1723 1724 /* 1725 * check with the enumerator that created this FMRI 1726 * (topo node) 1727 */ 1728 if (topo_method_invoke(node, TOPO_METH_UNUSABLE, 1729 TOPO_METH_UNUSABLE_VERSION, hap->ha_fmri, &hap->ha_nvl, 1730 &err) < 0) { 1731 1732 /* 1733 * Err on the side of caution and return usable 1734 */ 1735 if (topo_mod_nvalloc(mod, &hap->ha_nvl, NV_UNIQUE_NAME) == 0) 1736 if (nvlist_add_uint32(hap->ha_nvl, 1737 TOPO_METH_UNUSABLE_RET, 0) == 0) 1738 return (0); 1739 1740 return (ETOPO_PROP_NVL); 1741 } 1742 1743 return (err); 1744 } 1745 1746 static int 1747 hc_fmri_unusable(topo_mod_t *mod, tnode_t *node, topo_version_t version, 1748 nvlist_t *in, nvlist_t **out) 1749 { 1750 int err; 1751 struct hc_walk *hwp; 1752 struct hc_args *hap; 1753 1754 if (version > TOPO_METH_UNUSABLE_VERSION) 1755 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW)); 1756 1757 if ((hap = topo_mod_alloc(mod, sizeof (struct hc_args))) == NULL) 1758 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 1759 1760 hap->ha_fmri = in; 1761 hap->ha_nvl = NULL; 1762 if ((hwp = hc_walk_init(mod, node, hap->ha_fmri, hc_unusable, 1763 (void *)hap)) != NULL) { 1764 if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) == 1765 TOPO_WALK_ERR) 1766 err = -1; 1767 else 1768 err = 0; 1769 topo_walk_fini(hwp->hcw_wp); 1770 topo_mod_free(mod, hwp, sizeof (struct hc_walk)); 1771 } else { 1772 err = -1; 1773 } 1774 1775 if (hap->ha_nvl != NULL) 1776 *out = hap->ha_nvl; 1777 1778 topo_mod_free(mod, hap, sizeof (struct hc_args)); 1779 1780 return (err); 1781 } 1782 1783 struct fac_lookup { 1784 const char *fl_fac_type; 1785 uint32_t fl_fac_subtype; 1786 #ifdef _LP64 1787 uint64_t fl_callback; 1788 uint64_t fl_callback_args; 1789 #else 1790 uint32_t fl_callback; 1791 uint32_t fl_callback_args; 1792 #endif 1793 nvlist_t *fl_rsrc; 1794 nvlist_t *fl_fac_rsrc; 1795 }; 1796 1797 static int 1798 hc_fac_get(topo_mod_t *mod, tnode_t *node, void *pdata) 1799 { 1800 struct fac_lookup *flp = (struct fac_lookup *)pdata; 1801 topo_walk_cb_t cb = (topo_walk_cb_t)flp->fl_callback; 1802 topo_faclist_t faclist, *tmp; 1803 int err, ret = 0; 1804 1805 /* 1806 * Lookup the specified facility node. Return with an error if we can't 1807 * find it. 1808 */ 1809 if (topo_node_facility(mod->tm_hdl, node, flp->fl_fac_type, 1810 flp->fl_fac_subtype, &faclist, &err) != 0) { 1811 topo_mod_dprintf(mod, "hc_fac_get: topo_node_facility " 1812 "failed\n"); 1813 return (TOPO_WALK_ERR); 1814 } 1815 1816 /* 1817 * Invoke user's callback for each facility node in the topo list, 1818 * passing in a pointer to the facility node 1819 */ 1820 for (tmp = topo_list_next(&faclist.tf_list); tmp != NULL; 1821 tmp = topo_list_next(tmp)) { 1822 1823 if ((err = cb(mod->tm_hdl, tmp->tf_node, 1824 (void *)flp->fl_callback_args)) != 0) { 1825 (void) topo_mod_seterrno(mod, err); 1826 topo_mod_dprintf(mod, "hc_fac_get: callback failed: " 1827 "%s\n ", topo_mod_errmsg(mod)); 1828 ret = TOPO_WALK_ERR; 1829 break; 1830 } 1831 } 1832 1833 while ((tmp = topo_list_next(&faclist.tf_list)) != NULL) { 1834 topo_list_delete(&faclist.tf_list, tmp); 1835 topo_mod_free(mod, tmp, sizeof (topo_faclist_t)); 1836 } 1837 return (ret); 1838 } 1839 1840 static int 1841 hc_fmri_facility(topo_mod_t *mod, tnode_t *node, topo_version_t version, 1842 nvlist_t *in, nvlist_t **out) 1843 { 1844 int err = 0; 1845 struct hc_walk *hwp; 1846 struct fac_lookup *flp; 1847 1848 if (version > TOPO_METH_FACILITY_VERSION) 1849 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW)); 1850 1851 if ((flp = topo_mod_alloc(mod, sizeof (struct fac_lookup))) == NULL) 1852 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 1853 1854 /* 1855 * lookup arguments: hw resource, facility type, facility subtype, 1856 * callback and callback args 1857 */ 1858 err = nvlist_lookup_nvlist(in, TOPO_PROP_RESOURCE, &flp->fl_rsrc); 1859 err |= nvlist_lookup_string(in, FM_FMRI_FACILITY_TYPE, 1860 (char **)&flp->fl_fac_type); 1861 err |= nvlist_lookup_uint32(in, "type", &flp->fl_fac_subtype); 1862 #ifdef _LP64 1863 err |= nvlist_lookup_uint64(in, "callback", &flp->fl_callback); 1864 err |= nvlist_lookup_uint64(in, "callback-args", 1865 &flp->fl_callback_args); 1866 #else 1867 err |= nvlist_lookup_uint32(in, "callback", &flp->fl_callback); 1868 err |= nvlist_lookup_uint32(in, "callback-args", 1869 &flp->fl_callback_args); 1870 #endif 1871 if (err != 0) { 1872 topo_mod_dprintf(mod, "hc_fmri_facility: failed to construct " 1873 "walker arg nvlist\n"); 1874 topo_mod_free(mod, flp, sizeof (struct fac_lookup)); 1875 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); 1876 } 1877 1878 flp->fl_fac_rsrc = NULL; 1879 if ((hwp = hc_walk_init(mod, node, flp->fl_rsrc, hc_fac_get, 1880 (void *)flp)) != NULL) { 1881 if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) == 1882 TOPO_WALK_ERR) 1883 err = -1; 1884 else 1885 err = 0; 1886 topo_walk_fini(hwp->hcw_wp); 1887 topo_mod_free(mod, hwp, sizeof (struct hc_walk)); 1888 } else { 1889 topo_mod_dprintf(mod, "hc_fmri_facility: failed to initialize " 1890 "hc walker\n"); 1891 err = -1; 1892 } 1893 1894 if (flp->fl_fac_rsrc != NULL) 1895 *out = flp->fl_fac_rsrc; 1896 1897 topo_mod_free(mod, flp, sizeof (struct fac_lookup)); 1898 1899 return (err); 1900 } 1901