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