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