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