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