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