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