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