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