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