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