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