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