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