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