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