8699 Want NIC transceiver visibility
[unleashed.git] / usr / src / lib / fm / topo / libtopo / common / hc.c
blobdf718d6490ead6b71f9986f7fe91711aa3266fde
1 /*
3 * CDDL HEADER START
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.
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.
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]
20 * CDDL HEADER END
24 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
25 * Copyright (c) 2017, Joyent, Inc.
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>
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>
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 **);
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 *);
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 }
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 };
141 static const hcc_t hc_canon[] = {
142 { BANK, TOPO_STABILITY_PRIVATE },
143 { BAY, TOPO_STABILITY_PRIVATE },
144 { BLADE, TOPO_STABILITY_PRIVATE },
145 { BRANCH, TOPO_STABILITY_PRIVATE },
146 { CMP, TOPO_STABILITY_PRIVATE },
147 { CENTERPLANE, TOPO_STABILITY_PRIVATE },
148 { CHASSIS, TOPO_STABILITY_PRIVATE },
149 { CHIP, TOPO_STABILITY_PRIVATE },
150 { CHIP_SELECT, TOPO_STABILITY_PRIVATE },
151 { CORE, TOPO_STABILITY_PRIVATE },
152 { CONTROLLER, TOPO_STABILITY_PRIVATE },
153 { CPU, TOPO_STABILITY_PRIVATE },
154 { CPUBOARD, TOPO_STABILITY_PRIVATE },
155 { DIMM, TOPO_STABILITY_PRIVATE },
156 { DISK, TOPO_STABILITY_PRIVATE },
157 { DRAM, TOPO_STABILITY_PRIVATE },
158 { DRAMCHANNEL, TOPO_STABILITY_PRIVATE },
159 { FAN, TOPO_STABILITY_PRIVATE },
160 { FANBOARD, TOPO_STABILITY_PRIVATE },
161 { FANMODULE, TOPO_STABILITY_PRIVATE },
162 { HBA, TOPO_STABILITY_PRIVATE },
163 { HOSTBRIDGE, TOPO_STABILITY_PRIVATE },
164 { INTERCONNECT, TOPO_STABILITY_PRIVATE },
165 { IOBOARD, TOPO_STABILITY_PRIVATE },
166 { IPORT, TOPO_STABILITY_PRIVATE },
167 { MEMBOARD, TOPO_STABILITY_PRIVATE },
168 { MEMORYBUFFER, TOPO_STABILITY_PRIVATE },
169 { MEMORYCONTROL, TOPO_STABILITY_PRIVATE },
170 { MICROCORE, TOPO_STABILITY_PRIVATE },
171 { MOTHERBOARD, TOPO_STABILITY_PRIVATE },
172 { NIU, TOPO_STABILITY_PRIVATE },
173 { NIUFN, TOPO_STABILITY_PRIVATE },
174 { PCI_BUS, TOPO_STABILITY_PRIVATE },
175 { PCI_DEVICE, TOPO_STABILITY_PRIVATE },
176 { PCI_FUNCTION, TOPO_STABILITY_PRIVATE },
177 { PCIEX_BUS, TOPO_STABILITY_PRIVATE },
178 { PCIEX_DEVICE, TOPO_STABILITY_PRIVATE },
179 { PCIEX_FUNCTION, TOPO_STABILITY_PRIVATE },
180 { PCIEX_ROOT, TOPO_STABILITY_PRIVATE },
181 { PCIEX_SWUP, TOPO_STABILITY_PRIVATE },
182 { PCIEX_SWDWN, TOPO_STABILITY_PRIVATE },
183 { PORT, TOPO_STABILITY_PRIVATE },
184 { POWERBOARD, TOPO_STABILITY_PRIVATE },
185 { POWERMODULE, TOPO_STABILITY_PRIVATE },
186 { PSU, TOPO_STABILITY_PRIVATE },
187 { RANK, TOPO_STABILITY_PRIVATE },
188 { RECEPTACLE, TOPO_STABILITY_PRIVATE },
189 { RISER, TOPO_STABILITY_PRIVATE },
190 { SASEXPANDER, TOPO_STABILITY_PRIVATE },
191 { SCSI_DEVICE, TOPO_STABILITY_PRIVATE },
192 { SHELF, TOPO_STABILITY_PRIVATE },
193 { SES_ENCLOSURE, TOPO_STABILITY_PRIVATE },
194 { SMP_DEVICE, TOPO_STABILITY_PRIVATE },
195 { SP, TOPO_STABILITY_PRIVATE },
196 { STRAND, TOPO_STABILITY_PRIVATE },
197 { SUBCHASSIS, TOPO_STABILITY_PRIVATE },
198 { SYSTEMBOARD, TOPO_STABILITY_PRIVATE },
199 { TRANSCEIVER, TOPO_STABILITY_PRIVATE },
200 { XAUI, TOPO_STABILITY_PRIVATE },
201 { XFP, TOPO_STABILITY_PRIVATE }
204 static int hc_ncanon = sizeof (hc_canon) / sizeof (hcc_t);
207 hc_init(topo_mod_t *mod, topo_version_t version)
210 * Turn on module debugging output
212 if (getenv("TOPOHCDEBUG"))
213 topo_mod_setdebug(mod);
215 topo_mod_dprintf(mod, "initializing hc builtin\n");
217 if (version != HC_VERSION)
218 return (topo_mod_seterrno(mod, EMOD_VER_NEW));
220 if (topo_mod_register(mod, &hc_info, TOPO_VERSION) != 0) {
221 topo_mod_dprintf(mod, "failed to register hc: "
222 "%s\n", topo_mod_errmsg(mod));
223 return (-1); /* mod errno already set */
226 return (0);
229 void
230 hc_fini(topo_mod_t *mod)
232 topo_mod_unregister(mod);
236 static const topo_pgroup_info_t sys_pgroup = {
237 TOPO_PGROUP_SYSTEM,
238 TOPO_STABILITY_PRIVATE,
239 TOPO_STABILITY_PRIVATE,
243 static const topo_pgroup_info_t auth_pgroup = {
244 FM_FMRI_AUTHORITY,
245 TOPO_STABILITY_PRIVATE,
246 TOPO_STABILITY_PRIVATE,
250 static void
251 hc_prop_set(tnode_t *node, nvlist_t *auth)
253 int err;
254 char isa[MAXNAMELEN];
255 struct utsname uts;
256 char *prod, *psn, *csn, *server;
258 if (auth == NULL)
259 return;
261 if (topo_pgroup_create(node, &auth_pgroup, &err) != 0) {
262 if (err != ETOPO_PROP_DEFD)
263 return;
267 * Inherit if we can, it saves memory
269 if ((topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_PRODUCT,
270 &err) != 0) && (err != ETOPO_PROP_DEFD)) {
271 if (nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT, &prod)
272 == 0)
273 (void) topo_prop_set_string(node, FM_FMRI_AUTHORITY,
274 FM_FMRI_AUTH_PRODUCT, TOPO_PROP_IMMUTABLE, prod,
275 &err);
277 if ((topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_PRODUCT_SN,
278 &err) != 0) && (err != ETOPO_PROP_DEFD)) {
279 if (nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT_SN, &psn)
280 == 0)
281 (void) topo_prop_set_string(node, FM_FMRI_AUTHORITY,
282 FM_FMRI_AUTH_PRODUCT_SN, TOPO_PROP_IMMUTABLE, psn,
283 &err);
285 if ((topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_CHASSIS,
286 &err) != 0) && (err != ETOPO_PROP_DEFD)) {
287 if (nvlist_lookup_string(auth, FM_FMRI_AUTH_CHASSIS, &csn) == 0)
288 (void) topo_prop_set_string(node, FM_FMRI_AUTHORITY,
289 FM_FMRI_AUTH_CHASSIS, TOPO_PROP_IMMUTABLE, csn,
290 &err);
292 if ((topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_SERVER,
293 &err) != 0) && (err != ETOPO_PROP_DEFD)) {
294 if (nvlist_lookup_string(auth, FM_FMRI_AUTH_SERVER, &server)
295 == 0)
296 (void) topo_prop_set_string(node, FM_FMRI_AUTHORITY,
297 FM_FMRI_AUTH_SERVER, TOPO_PROP_IMMUTABLE, server,
298 &err);
301 if (topo_pgroup_create(node, &sys_pgroup, &err) != 0)
302 return;
304 isa[0] = '\0';
305 (void) sysinfo(SI_ARCHITECTURE, isa, sizeof (isa));
306 (void) uname(&uts);
307 (void) topo_prop_set_string(node, TOPO_PGROUP_SYSTEM, TOPO_PROP_ISA,
308 TOPO_PROP_IMMUTABLE, isa, &err);
309 (void) topo_prop_set_string(node, TOPO_PGROUP_SYSTEM, TOPO_PROP_MACHINE,
310 TOPO_PROP_IMMUTABLE, uts.machine, &err);
313 /*ARGSUSED*/
315 hc_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, topo_instance_t min,
316 topo_instance_t max, void *notused1, void *notused2)
318 int isglobal = (getzoneid() == GLOBAL_ZONEID);
319 nvlist_t *pfmri = NULL;
320 nvlist_t *nvl;
321 nvlist_t *auth;
322 tnode_t *node;
323 int err;
325 * Register root node methods
327 if (strcmp(name, HC) == 0) {
328 (void) topo_method_register(mod, pnode, hc_methods);
329 return (0);
331 if (min != max) {
332 topo_mod_dprintf(mod,
333 "Request to enumerate %s component with an "
334 "ambiguous instance number, min (%d) != max (%d).\n",
335 HC, min, max);
336 return (topo_mod_seterrno(mod, EINVAL));
339 if (!isglobal)
340 return (0);
342 (void) topo_node_resource(pnode, &pfmri, &err);
343 auth = topo_mod_auth(mod, pnode);
344 nvl = hc_fmri_create(mod, pfmri, FM_HC_SCHEME_VERSION, name, min,
345 auth, NULL, NULL, NULL);
346 nvlist_free(pfmri); /* callee ignores NULLs */
347 if (nvl == NULL) {
348 nvlist_free(auth);
349 return (-1);
352 if ((node = topo_node_bind(mod, pnode, name, min, nvl)) == NULL) {
353 topo_mod_dprintf(mod, "topo_node_bind failed: %s\n",
354 topo_strerror(topo_mod_errno(mod)));
355 nvlist_free(auth);
356 nvlist_free(nvl);
357 return (-1);
361 * Set FRU for the motherboard node
363 if (strcmp(name, MOTHERBOARD) == 0)
364 (void) topo_node_fru_set(node, nvl, 0, &err);
366 hc_prop_set(node, auth);
367 nvlist_free(nvl);
368 nvlist_free(auth);
370 return (0);
373 /*ARGSUSED*/
374 static void
375 hc_release(topo_mod_t *mp, tnode_t *node)
377 topo_method_unregister_all(mp, node);
380 static int
381 fmri_compare(topo_mod_t *mod, nvlist_t *nv1, nvlist_t *nv2)
383 uint8_t v1, v2;
384 nvlist_t **hcp1, **hcp2;
385 nvlist_t *f1 = NULL, *f2 = NULL;
386 int err, i;
387 uint_t nhcp1, nhcp2;
388 char *f1str, *f2str;
390 if (nvlist_lookup_uint8(nv1, FM_VERSION, &v1) != 0 ||
391 nvlist_lookup_uint8(nv2, FM_VERSION, &v2) != 0 ||
392 v1 > FM_HC_SCHEME_VERSION || v2 > FM_HC_SCHEME_VERSION)
393 return (topo_mod_seterrno(mod, EMOD_FMRI_VERSION));
395 err = nvlist_lookup_nvlist_array(nv1, FM_FMRI_HC_LIST, &hcp1, &nhcp1);
396 err |= nvlist_lookup_nvlist_array(nv2, FM_FMRI_HC_LIST, &hcp2, &nhcp2);
397 if (err != 0)
398 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
400 if (nhcp1 != nhcp2)
401 return (0);
403 for (i = 0; i < nhcp1; i++) {
404 char *nm1 = NULL;
405 char *nm2 = NULL;
406 char *id1 = NULL;
407 char *id2 = NULL;
409 (void) nvlist_lookup_string(hcp1[i], FM_FMRI_HC_NAME, &nm1);
410 (void) nvlist_lookup_string(hcp2[i], FM_FMRI_HC_NAME, &nm2);
411 (void) nvlist_lookup_string(hcp1[i], FM_FMRI_HC_ID, &id1);
412 (void) nvlist_lookup_string(hcp2[i], FM_FMRI_HC_ID, &id2);
413 if (nm1 == NULL || nm2 == NULL || id1 == NULL || id2 == NULL)
414 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
416 if (strcmp(nm1, nm2) == 0 && strcmp(id1, id2) == 0)
417 continue;
419 return (0);
423 * Finally, check if the FMRI's represent a facility node. If so, then
424 * verify that the facilty type ("sensor"|"indicator") and facility
425 * name match.
427 (void) nvlist_lookup_nvlist(nv1, FM_FMRI_FACILITY, &f1);
428 (void) nvlist_lookup_nvlist(nv2, FM_FMRI_FACILITY, &f2);
430 if (f1 == NULL && f2 == NULL)
431 return (1);
432 else if (f1 == NULL || f2 == NULL)
433 return (0);
435 if (nvlist_lookup_string(f1, FM_FMRI_FACILITY_NAME, &f1str) == 0 &&
436 nvlist_lookup_string(f2, FM_FMRI_FACILITY_NAME, &f2str) == 0 &&
437 strcmp(f1str, f2str) == 0 &&
438 nvlist_lookup_string(f1, FM_FMRI_FACILITY_TYPE, &f1str) == 0 &&
439 nvlist_lookup_string(f2, FM_FMRI_FACILITY_TYPE, &f2str) == 0 &&
440 strcmp(f1str, f2str) == 0) {
441 return (1);
443 return (0);
446 /*ARGSUSED*/
447 static int
448 hc_compare(topo_mod_t *mod, tnode_t *node, topo_version_t version,
449 nvlist_t *in, nvlist_t **out)
451 int ret;
452 uint32_t compare;
453 nvlist_t *nv1, *nv2;
455 if (version > TOPO_METH_COMPARE_VERSION)
456 return (topo_mod_seterrno(mod, EMOD_VER_NEW));
458 if (nvlist_lookup_nvlist(in, TOPO_METH_FMRI_ARG_NV1, &nv1) != 0 ||
459 nvlist_lookup_nvlist(in, TOPO_METH_FMRI_ARG_NV2, &nv2) != 0)
460 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
462 ret = fmri_compare(mod, nv1, nv2);
463 if (ret < 0)
464 return (-1);
466 compare = ret;
467 if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) == 0) {
468 if (nvlist_add_uint32(*out, TOPO_METH_COMPARE_RET,
469 compare) == 0)
470 return (0);
471 else
472 nvlist_free(*out);
475 return (-1);
478 static ssize_t
479 fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen)
481 nvlist_t **hcprs = NULL;
482 nvlist_t *hcsp = NULL;
483 nvlist_t *anvl = NULL;
484 nvpair_t *apair;
485 nvlist_t *fnvl;
486 uint8_t version;
487 ssize_t size = 0;
488 uint_t hcnprs;
489 char *serial = NULL;
490 char *part = NULL;
491 char *root = NULL;
492 char *rev = NULL;
493 char *aname, *aval;
494 char *fname = NULL, *ftype = NULL;
495 int err, i;
497 if (nvlist_lookup_uint8(nvl, FM_VERSION, &version) != 0 ||
498 version > FM_HC_SCHEME_VERSION)
499 return (0);
501 /* Get authority, if present */
502 err = nvlist_lookup_nvlist(nvl, FM_FMRI_AUTHORITY, &anvl);
503 if (err != 0 && err != ENOENT)
504 return (0);
506 (void) nvlist_lookup_string(nvl, FM_FMRI_HC_ROOT, &root);
508 err = nvlist_lookup_nvlist_array(nvl, FM_FMRI_HC_LIST, &hcprs, &hcnprs);
509 if (err != 0 || hcprs == NULL)
510 return (0);
512 (void) nvlist_lookup_string(nvl, FM_FMRI_HC_SERIAL_ID, &serial);
513 (void) nvlist_lookup_string(nvl, FM_FMRI_HC_PART, &part);
514 (void) nvlist_lookup_string(nvl, FM_FMRI_HC_REVISION, &rev);
516 /* hc:// */
517 topo_fmristr_build(&size, buf, buflen, FM_FMRI_SCHEME_HC, NULL, "://");
519 /* authority, if any */
520 if (anvl != NULL) {
521 for (apair = nvlist_next_nvpair(anvl, NULL);
522 apair != NULL; apair = nvlist_next_nvpair(anvl, apair)) {
523 if (nvpair_type(apair) != DATA_TYPE_STRING ||
524 nvpair_value_string(apair, &aval) != 0)
525 continue;
526 aname = nvpair_name(apair);
527 topo_fmristr_build(&size, buf, buflen, ":", NULL, NULL);
528 topo_fmristr_build(&size, buf, buflen, "=",
529 aname, aval);
533 /* hardware-id part */
534 topo_fmristr_build(&size,
535 buf, buflen, serial, ":" FM_FMRI_HC_SERIAL_ID "=", NULL);
536 topo_fmristr_build(&size,
537 buf, buflen, part, ":" FM_FMRI_HC_PART "=", NULL);
538 topo_fmristr_build(&size,
539 buf, buflen, rev, ":" FM_FMRI_HC_REVISION "=", NULL);
541 /* separating slash */
542 topo_fmristr_build(&size, buf, buflen, "/", NULL, NULL);
544 /* hc-root */
545 if (root)
546 topo_fmristr_build(&size, buf, buflen, root, NULL, NULL);
548 /* all the pairs */
549 for (i = 0; i < hcnprs; i++) {
550 char *nm = NULL;
551 char *id = NULL;
553 if (i > 0)
554 topo_fmristr_build(&size,
555 buf, buflen, "/", NULL, NULL);
556 (void) nvlist_lookup_string(hcprs[i], FM_FMRI_HC_NAME, &nm);
557 (void) nvlist_lookup_string(hcprs[i], FM_FMRI_HC_ID, &id);
558 if (nm == NULL || id == NULL)
559 return (0);
560 topo_fmristr_build(&size, buf, buflen, nm, NULL, "=");
561 topo_fmristr_build(&size, buf, buflen, id, NULL, NULL);
564 /* append offset/physaddr if it exists in hc-specific */
565 if (nvlist_lookup_nvlist(nvl, FM_FMRI_HC_SPECIFIC, &hcsp) == 0) {
566 char *hcsn = NULL;
567 char hexstr[17];
568 uint64_t val;
570 if (nvlist_lookup_uint64(hcsp, FM_FMRI_HC_SPECIFIC_OFFSET,
571 &val) == 0 || nvlist_lookup_uint64(hcsp,
572 "asru-" FM_FMRI_HC_SPECIFIC_OFFSET, &val) == 0)
573 hcsn = FM_FMRI_HC_SPECIFIC_OFFSET;
574 else if (nvlist_lookup_uint64(hcsp,
575 FM_FMRI_HC_SPECIFIC_PHYSADDR, &val) == 0 ||
576 nvlist_lookup_uint64(hcsp,
577 "asru-" FM_FMRI_HC_SPECIFIC_PHYSADDR, &val) == 0)
578 hcsn = FM_FMRI_HC_SPECIFIC_PHYSADDR;
580 if (hcsn != NULL) {
581 (void) snprintf(hexstr, sizeof (hexstr), "%llx", val);
582 topo_fmristr_build(&size, buf, buflen, "/", NULL, NULL);
583 topo_fmristr_build(&size, buf, buflen, "=", hcsn,
584 hexstr);
589 * If the nvlist represents a facility node, then we append the
590 * facility type and name to the end of the string representation using
591 * the format below:
593 * ?<ftype>=<fname>
595 if (nvlist_lookup_nvlist(nvl, FM_FMRI_FACILITY, &fnvl) == 0) {
596 if (nvlist_lookup_string(fnvl, FM_FMRI_FACILITY_NAME,
597 &fname) != 0 || nvlist_lookup_string(fnvl,
598 FM_FMRI_FACILITY_TYPE, &ftype) != 0)
599 return (0);
600 topo_fmristr_build(&size, buf, buflen, "?", NULL, NULL);
601 topo_fmristr_build(&size, buf, buflen, "=", ftype, fname);
604 return (size);
607 /*ARGSUSED*/
608 static int
609 hc_fmri_nvl2str(topo_mod_t *mod, tnode_t *node, topo_version_t version,
610 nvlist_t *nvl, nvlist_t **out)
612 ssize_t len;
613 char *name = NULL;
614 nvlist_t *fmristr;
616 if (version > TOPO_METH_NVL2STR_VERSION)
617 return (topo_mod_seterrno(mod, EMOD_VER_NEW));
619 if ((len = fmri_nvl2str(nvl, NULL, 0)) == 0 ||
620 (name = topo_mod_alloc(mod, len + 1)) == NULL ||
621 fmri_nvl2str(nvl, name, len + 1) == 0) {
622 if (name != NULL)
623 topo_mod_free(mod, name, len + 1);
624 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
627 if (topo_mod_nvalloc(mod, &fmristr, NV_UNIQUE_NAME) != 0) {
628 topo_mod_free(mod, name, len + 1);
629 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
631 if (nvlist_add_string(fmristr, "fmri-string", name) != 0) {
632 topo_mod_free(mod, name, len + 1);
633 nvlist_free(fmristr);
634 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
636 topo_mod_free(mod, name, len + 1);
637 *out = fmristr;
639 return (0);
642 static nvlist_t *
643 hc_base_fmri_create(topo_mod_t *mod, const nvlist_t *auth, const char *part,
644 const char *rev, const char *serial)
646 nvlist_t *fmri;
647 int err = 0;
650 * Create base HC nvlist
652 if (topo_mod_nvalloc(mod, &fmri, NV_UNIQUE_NAME) != 0)
653 return (NULL);
655 err = nvlist_add_uint8(fmri, FM_VERSION, FM_HC_SCHEME_VERSION);
656 err |= nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC);
657 err |= nvlist_add_string(fmri, FM_FMRI_HC_ROOT, "");
658 if (err != 0) {
659 nvlist_free(fmri);
660 return (NULL);
664 * Add optional payload members
666 if (serial != NULL)
667 (void) nvlist_add_string(fmri, FM_FMRI_HC_SERIAL_ID, serial);
668 if (part != NULL)
669 (void) nvlist_add_string(fmri, FM_FMRI_HC_PART, part);
670 if (rev != NULL)
671 (void) nvlist_add_string(fmri, FM_FMRI_HC_REVISION, rev);
672 if (auth != NULL)
673 (void) nvlist_add_nvlist(fmri, FM_FMRI_AUTHORITY,
674 (nvlist_t *)auth);
676 return (fmri);
679 static nvlist_t **
680 make_hc_pairs(topo_mod_t *mod, char *fmri, int *num)
682 nvlist_t **pa;
683 char *hc, *fromstr;
684 char *starti, *startn, *endi, *endi2;
685 char *ne, *ns;
686 char *cname = NULL;
687 char *find;
688 char *cid = NULL;
689 int nslashes = 0;
690 int npairs = 0;
691 int i, hclen;
693 if ((hc = topo_mod_strdup(mod, fmri + 5)) == NULL)
694 return (NULL);
696 hclen = strlen(hc) + 1;
699 * Count equal signs and slashes to determine how many
700 * hc-pairs will be present in the final FMRI. There should
701 * be at least as many slashes as equal signs. There can be
702 * more, though if the string after an = includes them.
704 if ((fromstr = strchr(hc, '/')) == NULL)
705 return (NULL);
707 find = fromstr;
708 while ((ne = strchr(find, '=')) != NULL) {
709 find = ne + 1;
710 npairs++;
713 find = fromstr;
714 while ((ns = strchr(find, '/')) != NULL) {
715 find = ns + 1;
716 nslashes++;
720 * Do we appear to have a well-formed string version of the FMRI?
722 if (nslashes < npairs || npairs == 0) {
723 topo_mod_free(mod, hc, hclen);
724 return (NULL);
727 *num = npairs;
729 find = fromstr;
731 if ((pa = topo_mod_zalloc(mod, npairs * sizeof (nvlist_t *))) == NULL) {
732 topo_mod_free(mod, hc, hclen);
733 return (NULL);
737 * We go through a pretty complicated procedure to find the
738 * name and id for each pair. That's because, unfortunately,
739 * we have some ids that can have slashes within them. So
740 * we can't just search for the next slash after the equal sign
741 * and decide that starts a new pair. Instead we have to find
742 * an equal sign for the next pair and work our way back to the
743 * slash from there.
745 for (i = 0; i < npairs; i++) {
746 startn = strchr(find, '/');
747 if (startn == NULL)
748 break;
749 startn++;
750 starti = strchr(find, '=');
751 if (starti == NULL)
752 break;
753 *starti = '\0';
754 if ((cname = topo_mod_strdup(mod, startn)) == NULL)
755 break;
756 *starti++ = '=';
757 endi = strchr(starti, '=');
758 if (endi != NULL) {
759 *endi = '\0';
760 endi2 = strrchr(starti, '/');
761 if (endi2 == NULL)
762 break;
763 *endi = '=';
764 *endi2 = '\0';
765 if ((cid = topo_mod_strdup(mod, starti)) == NULL)
766 break;
767 *endi2 = '/';
768 find = endi2;
769 } else {
770 if ((cid = topo_mod_strdup(mod, starti)) == NULL)
771 break;
772 find = starti + strlen(starti);
774 if (topo_mod_nvalloc(mod, &pa[i], NV_UNIQUE_NAME) < 0)
775 break;
777 if (nvlist_add_string(pa[i], FM_FMRI_HC_NAME, cname) ||
778 nvlist_add_string(pa[i], FM_FMRI_HC_ID, cid))
779 break;
781 topo_mod_strfree(mod, cname);
782 topo_mod_strfree(mod, cid);
783 cname = NULL;
784 cid = NULL;
787 topo_mod_strfree(mod, cname);
788 topo_mod_strfree(mod, cid);
790 if (i < npairs) {
791 for (i = 0; i < npairs; i++)
792 nvlist_free(pa[i]);
793 topo_mod_free(mod, pa, npairs * sizeof (nvlist_t *));
794 topo_mod_free(mod, hc, hclen);
795 return (NULL);
798 topo_mod_free(mod, hc, hclen);
800 return (pa);
804 make_hc_auth(topo_mod_t *mod, char *fmri, char **serial, char **part,
805 char **rev, nvlist_t **auth)
807 char *starti, *startn, *endi, *copy;
808 char *aname = NULL, *aid = NULL, *fs;
809 nvlist_t *na = NULL;
810 size_t len;
812 if ((copy = topo_mod_strdup(mod, fmri + 5)) == NULL)
813 return (-1);
815 len = strlen(copy);
818 * Make sure there are a valid authority members
820 startn = strchr(copy, ':');
821 fs = strchr(copy, '/');
823 if (startn == NULL || fs == NULL) {
824 topo_mod_strfree(mod, copy);
825 return (0);
829 * The first colon we encounter must occur before the
830 * first slash
832 if (startn > fs)
833 goto hcabail;
835 do {
836 if (++startn >= copy + len)
837 break;
839 if ((starti = strchr(startn, '=')) == NULL)
840 goto hcabail;
842 *starti = '\0';
843 if (++starti > copy + len)
844 goto hcabail;
846 if ((aname = topo_mod_strdup(mod, startn)) == NULL)
847 goto hcabail;
849 startn = endi = strchr(starti, ':');
850 if (endi == NULL)
851 if ((endi = strchr(starti, '/')) == NULL)
852 break;
854 *endi = '\0';
855 if ((aid = topo_mod_strdup(mod, starti)) == NULL)
856 goto hcabail;
859 * Return possible serial, part and revision
861 if (strcmp(aname, FM_FMRI_HC_SERIAL_ID) == 0) {
862 *serial = topo_mod_strdup(mod, aid);
863 } else if (strcmp(aname, FM_FMRI_HC_PART) == 0) {
864 *part = topo_mod_strdup(mod, aid);
865 } else if (strcmp(aname, FM_FMRI_HC_REVISION) == 0) {
866 *rev = topo_mod_strdup(mod, aid);
867 } else {
868 if (na == NULL) {
869 if (topo_mod_nvalloc(mod, &na,
870 NV_UNIQUE_NAME) == 0) {
871 (void) nvlist_add_string(na, aname,
872 aid);
874 } else {
875 (void) nvlist_add_string(na, aname, aid);
878 topo_mod_strfree(mod, aname);
879 topo_mod_strfree(mod, aid);
880 aname = aid = NULL;
882 } while (startn != NULL);
884 *auth = na;
886 topo_mod_free(mod, copy, len + 1);
887 return (0);
889 hcabail:
890 topo_mod_free(mod, copy, len + 1);
891 topo_mod_strfree(mod, aname);
892 topo_mod_strfree(mod, aid);
893 nvlist_free(na);
894 return (-1);
899 * This function creates an nvlist to represent the facility portion of an
900 * hc-scheme node, given a string representation of the fmri. This is called by
901 * hc_fmri_str2nvl. If the string does not contain a facility component
902 * (e.g. ?<ftype>=<fname>) then it bails early and returns 0.
904 * On failure it returns -1 and sets the topo mod errno
907 make_facility(topo_mod_t *mod, char *str, nvlist_t **nvl)
909 char *fac, *copy, *fname, *ftype;
910 nvlist_t *nf = NULL;
911 size_t len;
913 if ((fac = strchr(str, '?')) == NULL)
914 return (0);
916 ++fac;
917 if ((copy = topo_mod_strdup(mod, fac)) == NULL)
918 return (topo_mod_seterrno(mod, EMOD_NOMEM));
920 fac = copy;
921 len = strlen(fac);
923 if ((fname = strchr(fac, '=')) == NULL) {
924 topo_mod_free(mod, copy, len + 1);
925 return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM));
928 fname[0] = '\0';
929 ++fname;
930 ftype = fac;
932 if (topo_mod_nvalloc(mod, &nf, NV_UNIQUE_NAME) != 0) {
933 topo_mod_free(mod, copy, len + 1);
934 return (topo_mod_seterrno(mod, EMOD_NOMEM));
937 if (nvlist_add_string(nf, FM_FMRI_FACILITY_NAME, fname) != 0 ||
938 nvlist_add_string(nf, FM_FMRI_FACILITY_TYPE, ftype) != 0) {
939 topo_mod_free(mod, copy, len + 1);
940 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
943 topo_mod_free(mod, copy, len + 1);
945 *nvl = nf;
947 return (0);
950 /*ARGSUSED*/
951 static int
952 hc_fmri_str2nvl(topo_mod_t *mod, tnode_t *node, topo_version_t version,
953 nvlist_t *in, nvlist_t **out)
955 nvlist_t **pa = NULL;
956 nvlist_t *nf = NULL;
957 nvlist_t *auth = NULL;
958 nvlist_t *fac = NULL;
959 char *str;
960 char *serial = NULL, *part = NULL, *rev = NULL, *hcsn = NULL;
961 int npairs, n;
962 int i, e;
964 if (version > TOPO_METH_STR2NVL_VERSION)
965 return (topo_mod_seterrno(mod, EMOD_VER_NEW));
967 if (nvlist_lookup_string(in, "fmri-string", &str) != 0)
968 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
970 /* We're expecting a string version of an hc scheme FMRI */
971 if (strncmp(str, "hc://", 5) != 0)
972 return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM));
974 if ((pa = make_hc_pairs(mod, str, &npairs)) == NULL)
975 return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM));
977 if (make_hc_auth(mod, str, &serial, &part, &rev, &auth) < 0)
978 goto hcfmbail;
980 if ((nf = hc_base_fmri_create(mod, auth, part, rev, serial)) == NULL)
981 goto hcfmbail;
983 n = npairs;
986 * If the last pair in hc-list is offset or physaddr, we move
987 * it to hc-specific.
989 (void) nvlist_lookup_string(pa[npairs - 1], FM_FMRI_HC_NAME, &hcsn);
990 if (strcmp(hcsn, FM_FMRI_HC_SPECIFIC_OFFSET) == 0 ||
991 strcmp(hcsn, FM_FMRI_HC_SPECIFIC_PHYSADDR) == 0) {
992 char *hcid;
993 nvlist_t *hcsp;
994 uint64_t val;
996 (void) nvlist_lookup_string(pa[npairs - 1], FM_FMRI_HC_ID,
997 &hcid);
998 val = strtoull(hcid, NULL, 16);
999 if (topo_mod_nvalloc(mod, &hcsp, NV_UNIQUE_NAME) != 0)
1000 goto hcfmbail;
1001 if (nvlist_add_uint64(hcsp, hcsn, val) != 0 ||
1002 nvlist_add_nvlist(nf, FM_FMRI_HC_SPECIFIC, hcsp) != 0) {
1003 nvlist_free(hcsp);
1004 goto hcfmbail;
1007 nvlist_free(hcsp);
1008 n--;
1011 if ((e = nvlist_add_uint32(nf, FM_FMRI_HC_LIST_SZ, n)) == 0)
1012 e = nvlist_add_nvlist_array(nf, FM_FMRI_HC_LIST, pa, n);
1013 if (e != 0) {
1014 topo_mod_dprintf(mod, "construction of new hc nvl failed");
1015 goto hcfmbail;
1019 * Clean-up
1021 for (i = 0; i < npairs; i++)
1022 nvlist_free(pa[i]);
1023 topo_mod_free(mod, pa, npairs * sizeof (nvlist_t *));
1024 topo_mod_strfree(mod, serial);
1025 topo_mod_strfree(mod, part);
1026 topo_mod_strfree(mod, rev);
1027 nvlist_free(auth);
1029 if (make_facility(mod, str, &fac) == -1)
1030 goto hcfmbail;
1032 if (fac != NULL) {
1033 if (nvlist_add_nvlist(nf, FM_FMRI_FACILITY, fac) != 0)
1034 goto hcfmbail;
1037 *out = nf;
1039 return (0);
1041 hcfmbail:
1042 nvlist_free(nf);
1043 for (i = 0; i < npairs; i++)
1044 nvlist_free(pa[i]);
1045 topo_mod_free(mod, pa, npairs * sizeof (nvlist_t *));
1047 topo_mod_strfree(mod, serial);
1048 topo_mod_strfree(mod, part);
1049 topo_mod_strfree(mod, rev);
1050 nvlist_free(auth);
1051 nvlist_free(nf);
1052 return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM));
1055 static nvlist_t *
1056 hc_list_create(topo_mod_t *mod, const char *name, char *inst)
1058 int err;
1059 nvlist_t *hc;
1061 if (topo_mod_nvalloc(mod, &hc, NV_UNIQUE_NAME) != 0)
1062 return (NULL);
1064 err = nvlist_add_string(hc, FM_FMRI_HC_NAME, name);
1065 err |= nvlist_add_string(hc, FM_FMRI_HC_ID, inst);
1066 if (err != 0) {
1067 nvlist_free(hc);
1068 return (NULL);
1071 return (hc);
1074 static nvlist_t *
1075 hc_create_seterror(topo_mod_t *mod, nvlist_t **hcl, int n, nvlist_t *fmri,
1076 int err)
1078 int i;
1080 if (hcl != NULL) {
1081 for (i = 0; i < n + 1; ++i)
1082 nvlist_free(hcl[i]);
1084 topo_mod_free(mod, hcl, sizeof (nvlist_t *) * (n + 1));
1087 nvlist_free(fmri);
1089 (void) topo_mod_seterrno(mod, err);
1091 topo_mod_dprintf(mod, "unable to create hc FMRI: %s\n",
1092 topo_mod_errmsg(mod));
1094 return (NULL);
1097 static int
1098 hc_name_canonical(topo_mod_t *mod, const char *name)
1100 int i;
1102 if (getenv("NOHCCHECK") != NULL)
1103 return (1);
1106 * Only enumerate elements with correct canonical names
1108 for (i = 0; i < hc_ncanon; i++) {
1109 if (strcmp(name, hc_canon[i].hcc_name) == 0)
1110 break;
1112 if (i >= hc_ncanon) {
1113 topo_mod_dprintf(mod, "non-canonical name %s\n",
1114 name);
1115 return (0);
1116 } else {
1117 return (1);
1121 static nvlist_t *
1122 hc_fmri_create(topo_mod_t *mod, nvlist_t *pfmri, int version, const char *name,
1123 topo_instance_t inst, const nvlist_t *auth, const char *part,
1124 const char *rev, const char *serial)
1126 int i;
1127 char str[21]; /* sizeof (UINT64_MAX) + '\0' */
1128 uint_t pelems = 0;
1129 nvlist_t **phcl = NULL;
1130 nvlist_t **hcl = NULL;
1131 nvlist_t *fmri = NULL;
1133 if (version > FM_HC_SCHEME_VERSION)
1134 return (hc_create_seterror(mod,
1135 hcl, pelems, fmri, EMOD_VER_OLD));
1136 else if (version < FM_HC_SCHEME_VERSION)
1137 return (hc_create_seterror(mod,
1138 hcl, pelems, fmri, EMOD_VER_NEW));
1141 * Check that the requested name is in our canonical list
1143 if (hc_name_canonical(mod, name) == 0)
1144 return (hc_create_seterror(mod,
1145 hcl, pelems, fmri, EMOD_NONCANON));
1147 * Copy the parent's HC_LIST
1149 if (pfmri != NULL) {
1150 if (nvlist_lookup_nvlist_array(pfmri, FM_FMRI_HC_LIST,
1151 &phcl, &pelems) != 0)
1152 return (hc_create_seterror(mod,
1153 hcl, pelems, fmri, EMOD_FMRI_MALFORM));
1156 hcl = topo_mod_zalloc(mod, sizeof (nvlist_t *) * (pelems + 1));
1157 if (hcl == NULL)
1158 return (hc_create_seterror(mod, hcl, pelems, fmri,
1159 EMOD_NOMEM));
1161 for (i = 0; i < pelems; ++i)
1162 if (topo_mod_nvdup(mod, phcl[i], &hcl[i]) != 0)
1163 return (hc_create_seterror(mod,
1164 hcl, pelems, fmri, EMOD_FMRI_NVL));
1166 (void) snprintf(str, sizeof (str), "%d", inst);
1167 if ((hcl[i] = hc_list_create(mod, name, str)) == NULL)
1168 return (hc_create_seterror(mod,
1169 hcl, pelems, fmri, EMOD_FMRI_NVL));
1171 if ((fmri = hc_base_fmri_create(mod, auth, part, rev, serial)) == NULL)
1172 return (hc_create_seterror(mod,
1173 hcl, pelems, fmri, EMOD_FMRI_NVL));
1175 if (nvlist_add_nvlist_array(fmri, FM_FMRI_HC_LIST, hcl, pelems + 1)
1176 != 0)
1177 return (hc_create_seterror(mod,
1178 hcl, pelems, fmri, EMOD_FMRI_NVL));
1180 if (hcl != NULL) {
1181 for (i = 0; i < pelems + 1; ++i) {
1182 nvlist_free(hcl[i]);
1184 topo_mod_free(mod, hcl, sizeof (nvlist_t *) * (pelems + 1));
1187 return (fmri);
1190 /*ARGSUSED*/
1191 static int
1192 hc_fmri_create_meth(topo_mod_t *mod, tnode_t *node, topo_version_t version,
1193 nvlist_t *in, nvlist_t **out)
1195 int ret;
1196 nvlist_t *args, *pfmri = NULL;
1197 nvlist_t *auth;
1198 uint32_t inst;
1199 char *name, *serial, *rev, *part;
1201 if (version > TOPO_METH_FMRI_VERSION)
1202 return (topo_mod_seterrno(mod, EMOD_VER_NEW));
1204 /* First the must-have fields */
1205 if (nvlist_lookup_string(in, TOPO_METH_FMRI_ARG_NAME, &name) != 0)
1206 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
1207 if (nvlist_lookup_uint32(in, TOPO_METH_FMRI_ARG_INST, &inst) != 0)
1208 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
1211 * args is optional
1213 pfmri = NULL;
1214 auth = NULL;
1215 serial = rev = part = NULL;
1216 if ((ret = nvlist_lookup_nvlist(in, TOPO_METH_FMRI_ARG_NVL, &args))
1217 != 0) {
1218 if (ret != ENOENT)
1219 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
1220 } else {
1222 /* And then optional arguments */
1223 (void) nvlist_lookup_nvlist(args, TOPO_METH_FMRI_ARG_PARENT,
1224 &pfmri);
1225 (void) nvlist_lookup_nvlist(args, TOPO_METH_FMRI_ARG_AUTH,
1226 &auth);
1227 (void) nvlist_lookup_string(args, TOPO_METH_FMRI_ARG_PART,
1228 &part);
1229 (void) nvlist_lookup_string(args, TOPO_METH_FMRI_ARG_REV, &rev);
1230 (void) nvlist_lookup_string(args, TOPO_METH_FMRI_ARG_SER,
1231 &serial);
1234 *out = hc_fmri_create(mod, pfmri, version, name, inst, auth, part,
1235 rev, serial);
1236 if (*out == NULL)
1237 return (-1);
1238 return (0);
1241 struct hc_walk {
1242 topo_mod_walk_cb_t hcw_cb;
1243 void *hcw_priv;
1244 topo_walk_t *hcw_wp;
1245 nvlist_t **hcw_list;
1246 nvlist_t *hcw_fmri;
1247 nvlist_t *hcw_fac;
1248 uint_t hcw_index;
1249 uint_t hcw_end;
1253 * Returns true if the given node is beneath the specified FMRI. This uses
1254 * the TOPO_METH_CONTAINS method, because some enumerators (such as external
1255 * enclosures) may want to do a comparison based on chassis WWN instead of the
1256 * instance ID. If this comparison function fails or is not supported, then we
1257 * fall back to a direct name/instance comparison.
1259 static int
1260 hc_match(topo_mod_t *mod, tnode_t *node, nvlist_t *fmri, const char *name,
1261 topo_instance_t inst, boolean_t *result)
1263 nvlist_t *rsrc;
1264 nvlist_t *arg, *nvl;
1265 uint32_t match = 0;
1266 int err;
1268 if (topo_node_resource(node, &rsrc, &err) != 0)
1269 return (-1);
1271 if (topo_mod_nvalloc(mod, &arg, NV_UNIQUE_NAME) != 0 ||
1272 nvlist_add_nvlist(arg, TOPO_METH_FMRI_ARG_FMRI,
1273 rsrc) != 0 ||
1274 nvlist_add_nvlist(arg, TOPO_METH_FMRI_ARG_SUBFMRI,
1275 fmri) != 0) {
1276 nvlist_free(rsrc);
1277 (void) topo_mod_seterrno(mod, EMOD_NOMEM);
1278 return (-1);
1281 nvlist_free(rsrc);
1283 if (topo_method_invoke(node, TOPO_METH_CONTAINS,
1284 TOPO_METH_CONTAINS_VERSION, arg, &nvl, &err) != 0) {
1285 nvlist_free(arg);
1286 if (err == ETOPO_METHOD_NOTSUP) {
1287 match = (strcmp(name,
1288 topo_node_name(node)) == 0 &&
1289 inst == topo_node_instance(node));
1290 } else {
1291 return (-1);
1293 } else {
1294 nvlist_free(arg);
1295 if (nvlist_lookup_uint32(nvl, TOPO_METH_CONTAINS_RET,
1296 &match) != 0) {
1297 nvlist_free(nvl);
1298 (void) topo_mod_seterrno(mod, EMOD_NVL_INVAL);
1299 return (-1);
1301 nvlist_free(nvl);
1304 *result = (match != 0);
1305 return (0);
1309 * Ideally, we should just be able to call topo_walk_bysibling(). But that
1310 * code assumes that the name/instance pair will match, so we need to
1311 * explicitly iterate over children of the parent looking for a matching value.
1313 static int
1314 hc_walk_sibling(topo_mod_t *mod, tnode_t *node, struct hc_walk *hwp,
1315 const char *name, topo_instance_t inst)
1317 tnode_t *pnp = topo_node_parent(node);
1318 topo_walk_t *wp = hwp->hcw_wp;
1319 tnode_t *np;
1320 boolean_t matched;
1321 int status;
1323 for (np = topo_child_first(pnp); np != NULL;
1324 np = topo_child_next(pnp, np)) {
1325 topo_node_hold(np);
1326 if (hc_match(mod, np, hwp->hcw_fmri, name, inst,
1327 &matched) == 0 && matched) {
1328 wp->tw_node = np;
1329 if (wp->tw_mod != NULL)
1330 status = wp->tw_cb(mod, np, hwp);
1331 else
1332 status = wp->tw_cb(wp->tw_thp, np, hwp);
1333 topo_node_rele(np);
1334 wp->tw_node = node;
1335 return (status);
1338 topo_node_rele(np);
1341 return (TOPO_WALK_TERMINATE);
1345 * Generic walker for the hc-scheme topo tree. This function uses the
1346 * hierachical nature of the hc-scheme to efficiently step through
1347 * the topo hc tree. Node lookups are done by topo_walk_byid() and
1348 * topo_walk_bysibling() at each component level to avoid unnecessary
1349 * traversal of the tree. hc_walker() never returns TOPO_WALK_NEXT, so
1350 * whether TOPO_WALK_CHILD or TOPO_WALK_SIBLING is specified by
1351 * topo_walk_step() doesn't affect the traversal.
1353 static int
1354 hc_walker(topo_mod_t *mod, tnode_t *node, void *pdata)
1356 int i, err;
1357 struct hc_walk *hwp = (struct hc_walk *)pdata;
1358 char *name, *id;
1359 char *fname, *ftype;
1360 topo_instance_t inst;
1361 boolean_t match;
1363 i = hwp->hcw_index;
1364 if (i > hwp->hcw_end) {
1365 if (hwp->hcw_fac != NULL) {
1366 if ((err = hwp->hcw_cb(mod, node, hwp->hcw_priv))
1367 != 0) {
1368 (void) topo_mod_seterrno(mod, err);
1369 topo_mod_dprintf(mod, "hc_walker: callback "
1370 "failed: %s\n ", topo_mod_errmsg(mod));
1371 return (TOPO_WALK_ERR);
1373 topo_mod_dprintf(mod, "hc_walker: callback "
1374 "complete: terminate walk\n");
1375 return (TOPO_WALK_TERMINATE);
1376 } else {
1377 topo_mod_dprintf(mod, "hc_walker: node not found\n");
1378 return (TOPO_WALK_TERMINATE);
1382 err = nvlist_lookup_string(hwp->hcw_list[i], FM_FMRI_HC_NAME, &name);
1383 err |= nvlist_lookup_string(hwp->hcw_list[i], FM_FMRI_HC_ID, &id);
1385 if (err != 0) {
1386 (void) topo_mod_seterrno(mod, EMOD_NVL_INVAL);
1387 return (TOPO_WALK_ERR);
1390 inst = atoi(id);
1393 * Check to see if our node matches the requested FMRI. If it doesn't
1394 * (because the enumerator determines matching based on something other
1395 * than name/instance, or because we're at the first level below the
1396 * root), then iterate over siblings to find the matching node.
1398 if (hc_match(mod, node, hwp->hcw_fmri, name, inst, &match) != 0)
1399 return (TOPO_WALK_ERR);
1401 if (!match)
1402 return (hc_walk_sibling(mod, node, hwp, name, inst));
1404 topo_mod_dprintf(mod, "hc_walker: walking node:%s=%d for hc:"
1405 "%s=%d at %d, end at %d \n", topo_node_name(node),
1406 topo_node_instance(node), name, inst, i, hwp->hcw_end);
1408 if (i == hwp->hcw_end) {
1411 * We are at the end of the hc-list. Now, check for
1412 * a facility leaf and walk one more time.
1414 if (hwp->hcw_fac != NULL) {
1415 err = nvlist_lookup_string(hwp->hcw_fac,
1416 FM_FMRI_FACILITY_NAME, &fname);
1417 err |= nvlist_lookup_string(hwp->hcw_fac,
1418 FM_FMRI_FACILITY_TYPE, &ftype);
1419 if (err != 0) {
1420 (void) topo_mod_seterrno(mod, EMOD_NVL_INVAL);
1421 return (TOPO_WALK_ERR);
1423 hwp->hcw_index++;
1424 topo_mod_dprintf(mod, "hc_walker: walk to facility "
1425 "node:%s=%s\n", fname, ftype);
1426 return (topo_walk_byid(hwp->hcw_wp, fname, 0));
1430 * Otherwise, this is the node we're looking for.
1432 if ((err = hwp->hcw_cb(mod, node, hwp->hcw_priv)) != 0) {
1433 (void) topo_mod_seterrno(mod, err);
1434 topo_mod_dprintf(mod, "hc_walker: callback "
1435 "failed: %s\n ", topo_mod_errmsg(mod));
1436 return (TOPO_WALK_ERR);
1437 } else {
1438 topo_mod_dprintf(mod, "hc_walker: callback "
1439 "complete: terminate walk\n");
1440 return (TOPO_WALK_TERMINATE);
1445 * Move on to the next component in the hc-list
1447 hwp->hcw_index = ++i;
1448 err = nvlist_lookup_string(hwp->hcw_list[i], FM_FMRI_HC_NAME, &name);
1449 err |= nvlist_lookup_string(hwp->hcw_list[i], FM_FMRI_HC_ID, &id);
1450 if (err != 0) {
1451 (void) topo_mod_seterrno(mod, err);
1452 return (TOPO_WALK_ERR);
1454 inst = atoi(id);
1456 return (topo_walk_byid(hwp->hcw_wp, name, inst));
1460 static struct hc_walk *
1461 hc_walk_init(topo_mod_t *mod, tnode_t *node, nvlist_t *rsrc,
1462 topo_mod_walk_cb_t cb, void *pdata)
1464 int err, ret;
1465 uint_t sz;
1466 struct hc_walk *hwp;
1467 topo_walk_t *wp;
1469 if ((hwp = topo_mod_alloc(mod, sizeof (struct hc_walk))) == NULL) {
1470 (void) topo_mod_seterrno(mod, EMOD_NOMEM);
1471 return (NULL);
1474 if (nvlist_lookup_nvlist_array(rsrc, FM_FMRI_HC_LIST, &hwp->hcw_list,
1475 &sz) != 0) {
1476 topo_mod_dprintf(mod, "hc_walk_init: failed to lookup %s "
1477 "nvlist\n", FM_FMRI_HC_LIST);
1478 topo_mod_free(mod, hwp, sizeof (struct hc_walk));
1479 (void) topo_mod_seterrno(mod, EMOD_METHOD_INVAL);
1480 return (NULL);
1482 if ((ret = nvlist_lookup_nvlist(rsrc, FM_FMRI_FACILITY, &hwp->hcw_fac))
1483 != 0) {
1484 if (ret != ENOENT) {
1485 topo_mod_dprintf(mod, "hc_walk_init: unexpected error "
1486 "looking up %s nvlist", FM_FMRI_FACILITY);
1487 topo_mod_free(mod, hwp, sizeof (struct hc_walk));
1488 (void) topo_mod_seterrno(mod, EMOD_METHOD_INVAL);
1489 return (NULL);
1490 } else {
1491 hwp->hcw_fac = NULL;
1495 hwp->hcw_fmri = rsrc;
1496 hwp->hcw_end = sz - 1;
1497 hwp->hcw_index = 0;
1498 hwp->hcw_priv = pdata;
1499 hwp->hcw_cb = cb;
1500 if ((wp = topo_mod_walk_init(mod, node, hc_walker, (void *)hwp, &err))
1501 == NULL) {
1502 topo_mod_dprintf(mod, "hc_walk_init: topo_mod_walk_init failed "
1503 "(%s)\n", topo_strerror(err));
1504 topo_mod_free(mod, hwp, sizeof (struct hc_walk));
1505 (void) topo_mod_seterrno(mod, err);
1506 return (NULL);
1509 hwp->hcw_wp = wp;
1511 return (hwp);
1514 struct prop_lookup {
1515 const char *pl_pgroup;
1516 const char *pl_pname;
1517 int pl_flag;
1518 nvlist_t *pl_args;
1519 nvlist_t *pl_rsrc;
1520 nvlist_t *pl_prop;
1523 /*ARGSUSED*/
1524 static int
1525 hc_prop_get(topo_mod_t *mod, tnode_t *node, void *pdata)
1527 int err = 0;
1529 struct prop_lookup *plp = (struct prop_lookup *)pdata;
1531 (void) topo_prop_getprop(node, plp->pl_pgroup, plp->pl_pname,
1532 plp->pl_args, &plp->pl_prop, &err);
1534 return (err);
1537 static int
1538 hc_fmri_prop_get(topo_mod_t *mod, tnode_t *node, topo_version_t version,
1539 nvlist_t *in, nvlist_t **out)
1541 int err;
1542 struct hc_walk *hwp;
1543 struct prop_lookup *plp;
1545 if (version > TOPO_METH_PROP_GET_VERSION)
1546 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
1548 if ((plp = topo_mod_alloc(mod, sizeof (struct prop_lookup))) == NULL)
1549 return (topo_mod_seterrno(mod, EMOD_NOMEM));
1551 err = nvlist_lookup_string(in, TOPO_PROP_GROUP,
1552 (char **)&plp->pl_pgroup);
1553 err |= nvlist_lookup_string(in, TOPO_PROP_VAL_NAME,
1554 (char **)&plp->pl_pname);
1555 err |= nvlist_lookup_nvlist(in, TOPO_PROP_RESOURCE, &plp->pl_rsrc);
1556 if (err != 0) {
1557 topo_mod_free(mod, plp, sizeof (struct prop_lookup));
1558 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
1562 * Private args to prop method are optional
1564 if ((err = nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &plp->pl_args))
1565 != 0) {
1566 if (err != ENOENT) {
1567 topo_mod_free(mod, plp, sizeof (struct prop_lookup));
1568 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
1569 } else {
1570 plp->pl_args = NULL;
1574 plp->pl_prop = NULL;
1575 if ((hwp = hc_walk_init(mod, node, plp->pl_rsrc, hc_prop_get,
1576 (void *)plp)) != NULL) {
1577 if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
1578 TOPO_WALK_ERR)
1579 err = -1;
1580 else
1581 err = 0;
1582 topo_walk_fini(hwp->hcw_wp);
1583 topo_mod_free(mod, hwp, sizeof (struct hc_walk));
1584 } else {
1585 err = -1;
1588 if (plp->pl_prop != NULL)
1589 *out = plp->pl_prop;
1591 topo_mod_free(mod, plp, sizeof (struct prop_lookup));
1593 return (err);
1596 /*ARGSUSED*/
1597 static int
1598 hc_pgrp_get(topo_mod_t *mod, tnode_t *node, void *pdata)
1600 int err = 0;
1602 struct prop_lookup *plp = (struct prop_lookup *)pdata;
1604 (void) topo_prop_getpgrp(node, plp->pl_pgroup, &plp->pl_prop, &err);
1606 return (err);
1609 static int
1610 hc_fmri_pgrp_get(topo_mod_t *mod, tnode_t *node, topo_version_t version,
1611 nvlist_t *in, nvlist_t **out)
1613 int err;
1614 struct hc_walk *hwp;
1615 struct prop_lookup *plp;
1617 if (version > TOPO_METH_PGRP_GET_VERSION)
1618 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
1620 if ((plp = topo_mod_alloc(mod, sizeof (struct prop_lookup))) == NULL)
1621 return (topo_mod_seterrno(mod, EMOD_NOMEM));
1623 err = nvlist_lookup_string(in, TOPO_PROP_GROUP,
1624 (char **)&plp->pl_pgroup);
1625 err |= nvlist_lookup_nvlist(in, TOPO_PROP_RESOURCE, &plp->pl_rsrc);
1626 if (err != 0) {
1627 topo_mod_free(mod, plp, sizeof (struct prop_lookup));
1628 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
1631 plp->pl_prop = NULL;
1632 if ((hwp = hc_walk_init(mod, node, plp->pl_rsrc, hc_pgrp_get,
1633 (void *)plp)) != NULL) {
1634 if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
1635 TOPO_WALK_ERR)
1636 err = -1;
1637 else
1638 err = 0;
1639 topo_walk_fini(hwp->hcw_wp);
1640 topo_mod_free(mod, hwp, sizeof (struct hc_walk));
1641 } else {
1642 err = -1;
1645 if (plp->pl_prop != NULL)
1646 *out = plp->pl_prop;
1648 topo_mod_free(mod, plp, sizeof (struct prop_lookup));
1650 return (err);
1653 /*ARGSUSED*/
1654 static int
1655 hc_prop_setprop(topo_mod_t *mod, tnode_t *node, void *pdata)
1657 int err = 0;
1659 struct prop_lookup *plp = (struct prop_lookup *)pdata;
1661 (void) topo_prop_setprop(node, plp->pl_pgroup, plp->pl_prop,
1662 plp->pl_flag, plp->pl_args, &err);
1664 return (err);
1667 /*ARGSUSED*/
1668 static int
1669 hc_fmri_prop_set(topo_mod_t *mod, tnode_t *node, topo_version_t version,
1670 nvlist_t *in, nvlist_t **out)
1672 int err;
1673 struct hc_walk *hwp;
1674 struct prop_lookup *plp;
1676 if (version > TOPO_METH_PROP_SET_VERSION)
1677 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
1679 if ((plp = topo_mod_alloc(mod, sizeof (struct prop_lookup))) == NULL)
1680 return (topo_mod_seterrno(mod, EMOD_NOMEM));
1682 err = nvlist_lookup_string(in, TOPO_PROP_GROUP,
1683 (char **)&plp->pl_pgroup);
1684 err |= nvlist_lookup_nvlist(in, TOPO_PROP_RESOURCE, &plp->pl_rsrc);
1685 err |= nvlist_lookup_nvlist(in, TOPO_PROP_VAL, &plp->pl_prop);
1686 err |= nvlist_lookup_int32(in, TOPO_PROP_FLAG, &plp->pl_flag);
1687 if (err != 0) {
1688 topo_mod_free(mod, plp, sizeof (struct prop_lookup));
1689 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
1693 * Private args to prop method are optional
1695 if ((err = nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &plp->pl_args))
1696 != 0) {
1697 if (err != ENOENT)
1698 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
1699 else
1700 plp->pl_args = NULL;
1703 if ((hwp = hc_walk_init(mod, node, plp->pl_rsrc, hc_prop_setprop,
1704 (void *)plp)) != NULL) {
1705 if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
1706 TOPO_WALK_ERR)
1707 err = -1;
1708 else
1709 err = 0;
1710 topo_walk_fini(hwp->hcw_wp);
1711 topo_mod_free(mod, hwp, sizeof (struct hc_walk));
1712 } else {
1713 err = -1;
1716 topo_mod_free(mod, plp, sizeof (struct prop_lookup));
1718 return (err);
1721 struct hc_args {
1722 nvlist_t *ha_fmri;
1723 nvlist_t *ha_nvl;
1724 char *ha_method_name;
1725 topo_version_t ha_method_ver;
1728 static int
1729 hc_auth_changed(nvlist_t *nva, nvlist_t *nvb, const char *propname)
1731 char *stra, *strb;
1733 if (nvlist_lookup_string(nva, propname, &stra) != 0 ||
1734 nvlist_lookup_string(nvb, propname, &strb) != 0)
1735 return (FMD_OBJ_STATE_UNKNOWN);
1737 if (strcmp(stra, strb) != 0)
1738 return (FMD_OBJ_STATE_REPLACED);
1739 else
1740 return (FMD_OBJ_STATE_STILL_PRESENT);
1743 static int
1744 hc_is_present(topo_mod_t *mod, tnode_t *node, void *pdata)
1746 int err;
1747 struct hc_args *hap = (struct hc_args *)pdata;
1748 nvlist_t *rsrc;
1749 boolean_t present;
1752 * check with the enumerator that created this FMRI
1753 * (topo node)
1755 if (topo_method_invoke(node, TOPO_METH_PRESENT,
1756 TOPO_METH_PRESENT_VERSION, hap->ha_fmri, &hap->ha_nvl,
1757 &err) < 0) {
1760 * If the method exists but failed for some other reason,
1761 * propagate the error as making any decision over presence is
1762 * impossible.
1764 if (err != ETOPO_METHOD_NOTSUP)
1765 return (err);
1768 * Check the authority information. If the part id or serial
1769 * number doesn't match, then it isn't the same FMRI.
1770 * Otherwise, assume presence.
1772 if (topo_node_resource(node, &rsrc, &err) != 0)
1773 return (err);
1775 present = B_TRUE;
1776 if (hc_auth_changed(hap->ha_fmri, rsrc,
1777 FM_FMRI_HC_SERIAL_ID) == FMD_OBJ_STATE_REPLACED ||
1778 hc_auth_changed(hap->ha_fmri, rsrc,
1779 FM_FMRI_HC_PART) == FMD_OBJ_STATE_REPLACED) {
1780 present = B_FALSE;
1782 nvlist_free(rsrc);
1784 if (topo_mod_nvalloc(mod, &hap->ha_nvl, NV_UNIQUE_NAME) != 0)
1785 return (EMOD_NOMEM);
1787 if (nvlist_add_uint32(hap->ha_nvl,
1788 TOPO_METH_PRESENT_RET, present) != 0) {
1789 nvlist_free(hap->ha_nvl);
1790 hap->ha_nvl = NULL;
1791 return (EMOD_NOMEM);
1795 return (0);
1798 static int
1799 hc_fmri_present(topo_mod_t *mod, tnode_t *node, topo_version_t version,
1800 nvlist_t *in, nvlist_t **out)
1802 int err;
1803 struct hc_walk *hwp;
1804 struct hc_args *hap;
1806 if (version > TOPO_METH_PRESENT_VERSION)
1807 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
1809 if ((hap = topo_mod_alloc(mod, sizeof (struct hc_args))) == NULL)
1810 return (topo_mod_seterrno(mod, EMOD_NOMEM));
1812 hap->ha_fmri = in;
1813 hap->ha_nvl = NULL;
1814 if ((hwp = hc_walk_init(mod, node, hap->ha_fmri, hc_is_present,
1815 (void *)hap)) != NULL) {
1816 if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
1817 TOPO_WALK_ERR)
1818 err = -1;
1819 else
1820 err = 0;
1821 topo_walk_fini(hwp->hcw_wp);
1822 topo_mod_free(mod, hwp, sizeof (struct hc_walk));
1823 } else {
1824 err = -1;
1827 if (hap->ha_nvl != NULL)
1828 *out = hap->ha_nvl;
1830 topo_mod_free(mod, hap, sizeof (struct hc_args));
1832 return (err);
1835 static int
1836 hc_is_replaced(topo_mod_t *mod, tnode_t *node, void *pdata)
1838 int err;
1839 struct hc_args *hap = (struct hc_args *)pdata;
1840 uint32_t present = 0;
1841 nvlist_t *rsrc;
1842 uint32_t rval = FMD_OBJ_STATE_UNKNOWN;
1845 * check with the enumerator that created this FMRI
1846 * (topo node)
1848 if (topo_method_invoke(node, TOPO_METH_REPLACED,
1849 TOPO_METH_REPLACED_VERSION, hap->ha_fmri, &hap->ha_nvl,
1850 &err) < 0) {
1852 * If the method exists but failed for some other
1853 * reason, propagate the error as making any decision
1854 * over presence is impossible.
1856 if (err != ETOPO_METHOD_NOTSUP)
1857 return (err);
1860 * Enumerator didn't provide "replaced" method -
1861 * try "present" method
1863 if (topo_method_invoke(node, TOPO_METH_PRESENT,
1864 TOPO_METH_PRESENT_VERSION, hap->ha_fmri, &hap->ha_nvl,
1865 &err) < 0) {
1867 * If the method exists but failed for some other
1868 * reason, propagate the error as making any decision
1869 * over presence is impossible.
1871 if (err != ETOPO_METHOD_NOTSUP)
1872 return (err);
1875 * Enumerator didn't provide "present" method either -
1876 * so check the authority information. If the part id
1877 * or serial number doesn't match, then it isn't the
1878 * same FMRI. Otherwise, if we have a serial number and
1879 * it hasn't changed, then assume it is the same FMRI.
1881 if (topo_node_resource(node, &rsrc, &err) != 0)
1882 return (err);
1883 rval = hc_auth_changed(hap->ha_fmri, rsrc,
1884 FM_FMRI_HC_PART);
1885 if (rval != FMD_OBJ_STATE_REPLACED)
1886 rval = hc_auth_changed(hap->ha_fmri, rsrc,
1887 FM_FMRI_HC_SERIAL_ID);
1888 nvlist_free(rsrc);
1889 if (topo_mod_nvalloc(mod, &hap->ha_nvl,
1890 NV_UNIQUE_NAME) != 0)
1891 return (EMOD_NOMEM);
1892 if (nvlist_add_uint32(hap->ha_nvl,
1893 TOPO_METH_REPLACED_RET, rval) != 0) {
1894 nvlist_free(hap->ha_nvl);
1895 hap->ha_nvl = NULL;
1896 return (ETOPO_PROP_NVL);
1898 } else {
1899 (void) nvlist_lookup_uint32(hap->ha_nvl,
1900 TOPO_METH_PRESENT_RET, &present);
1901 (void) nvlist_remove(hap->ha_nvl,
1902 TOPO_METH_PRESENT_RET, DATA_TYPE_UINT32);
1903 if (nvlist_add_uint32(hap->ha_nvl,
1904 TOPO_METH_REPLACED_RET,
1905 present ? FMD_OBJ_STATE_UNKNOWN :
1906 FMD_OBJ_STATE_NOT_PRESENT) != 0) {
1907 nvlist_free(hap->ha_nvl);
1908 hap->ha_nvl = NULL;
1909 return (ETOPO_PROP_NVL);
1913 return (0);
1916 static int
1917 hc_fmri_replaced(topo_mod_t *mod, tnode_t *node, topo_version_t version,
1918 nvlist_t *in, nvlist_t **out)
1920 int err;
1921 struct hc_walk *hwp;
1922 struct hc_args *hap;
1924 if (version > TOPO_METH_REPLACED_VERSION)
1925 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
1927 if ((hap = topo_mod_alloc(mod, sizeof (struct hc_args))) == NULL)
1928 return (topo_mod_seterrno(mod, EMOD_NOMEM));
1930 hap->ha_fmri = in;
1931 hap->ha_nvl = NULL;
1932 if ((hwp = hc_walk_init(mod, node, hap->ha_fmri, hc_is_replaced,
1933 (void *)hap)) != NULL) {
1934 if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
1935 TOPO_WALK_ERR)
1936 err = -1;
1937 else
1938 err = 0;
1939 topo_walk_fini(hwp->hcw_wp);
1940 topo_mod_free(mod, hwp, sizeof (struct hc_walk));
1941 } else {
1942 err = -1;
1945 if (hap->ha_nvl != NULL)
1946 *out = hap->ha_nvl;
1948 topo_mod_free(mod, hap, sizeof (struct hc_args));
1950 return (err);
1953 static int
1954 hc_unusable(topo_mod_t *mod, tnode_t *node, void *pdata)
1956 int err;
1957 struct hc_args *hap = (struct hc_args *)pdata;
1960 * check with the enumerator that created this FMRI
1961 * (topo node)
1963 if (topo_method_invoke(node, TOPO_METH_UNUSABLE,
1964 TOPO_METH_UNUSABLE_VERSION, hap->ha_fmri, &hap->ha_nvl,
1965 &err) < 0) {
1968 * Err on the side of caution and return usable
1970 if (topo_mod_nvalloc(mod, &hap->ha_nvl, NV_UNIQUE_NAME) == 0)
1971 if (nvlist_add_uint32(hap->ha_nvl,
1972 TOPO_METH_UNUSABLE_RET, 0) == 0)
1973 return (0);
1975 return (ETOPO_PROP_NVL);
1978 return (0);
1981 static int
1982 hc_fmri_unusable(topo_mod_t *mod, tnode_t *node, topo_version_t version,
1983 nvlist_t *in, nvlist_t **out)
1985 int err;
1986 struct hc_walk *hwp;
1987 struct hc_args *hap;
1989 if (version > TOPO_METH_UNUSABLE_VERSION)
1990 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
1992 if ((hap = topo_mod_alloc(mod, sizeof (struct hc_args))) == NULL)
1993 return (topo_mod_seterrno(mod, EMOD_NOMEM));
1995 hap->ha_fmri = in;
1996 hap->ha_nvl = NULL;
1997 if ((hwp = hc_walk_init(mod, node, hap->ha_fmri, hc_unusable,
1998 (void *)hap)) != NULL) {
1999 if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
2000 TOPO_WALK_ERR)
2001 err = -1;
2002 else
2003 err = 0;
2004 topo_walk_fini(hwp->hcw_wp);
2005 topo_mod_free(mod, hwp, sizeof (struct hc_walk));
2006 } else {
2007 err = -1;
2010 if (hap->ha_nvl != NULL)
2011 *out = hap->ha_nvl;
2013 topo_mod_free(mod, hap, sizeof (struct hc_args));
2015 return (err);
2018 struct fac_lookup {
2019 const char *fl_fac_type;
2020 uint32_t fl_fac_subtype;
2021 #ifdef _LP64
2022 uint64_t fl_callback;
2023 uint64_t fl_callback_args;
2024 #else
2025 uint32_t fl_callback;
2026 uint32_t fl_callback_args;
2027 #endif
2028 nvlist_t *fl_rsrc;
2029 nvlist_t *fl_fac_rsrc;
2032 static int
2033 hc_fac_get(topo_mod_t *mod, tnode_t *node, void *pdata)
2035 struct fac_lookup *flp = (struct fac_lookup *)pdata;
2036 topo_walk_cb_t cb = (topo_walk_cb_t)flp->fl_callback;
2037 topo_faclist_t faclist, *tmp;
2038 int err, ret = 0;
2041 * Lookup the specified facility node. Return with an error if we can't
2042 * find it.
2044 if (topo_node_facility(mod->tm_hdl, node, flp->fl_fac_type,
2045 flp->fl_fac_subtype, &faclist, &err) != 0) {
2046 topo_mod_dprintf(mod, "hc_fac_get: topo_node_facility "
2047 "failed\n");
2048 return (TOPO_WALK_ERR);
2052 * Invoke user's callback for each facility node in the topo list,
2053 * passing in a pointer to the facility node
2055 for (tmp = topo_list_next(&faclist.tf_list); tmp != NULL;
2056 tmp = topo_list_next(tmp)) {
2058 if ((err = cb(mod->tm_hdl, tmp->tf_node,
2059 (void *)flp->fl_callback_args)) != 0) {
2060 (void) topo_mod_seterrno(mod, err);
2061 topo_mod_dprintf(mod, "hc_fac_get: callback failed: "
2062 "%s\n ", topo_mod_errmsg(mod));
2063 ret = TOPO_WALK_ERR;
2064 break;
2068 while ((tmp = topo_list_next(&faclist.tf_list)) != NULL) {
2069 topo_list_delete(&faclist.tf_list, tmp);
2070 topo_mod_free(mod, tmp, sizeof (topo_faclist_t));
2072 return (ret);
2075 static int
2076 hc_fmri_facility(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2077 nvlist_t *in, nvlist_t **out)
2079 int err = 0;
2080 struct hc_walk *hwp;
2081 struct fac_lookup *flp;
2083 if (version > TOPO_METH_FACILITY_VERSION)
2084 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
2086 if ((flp = topo_mod_alloc(mod, sizeof (struct fac_lookup))) == NULL)
2087 return (topo_mod_seterrno(mod, EMOD_NOMEM));
2090 * lookup arguments: hw resource, facility type, facility subtype,
2091 * callback and callback args
2093 err = nvlist_lookup_nvlist(in, TOPO_PROP_RESOURCE, &flp->fl_rsrc);
2094 err |= nvlist_lookup_string(in, FM_FMRI_FACILITY_TYPE,
2095 (char **)&flp->fl_fac_type);
2096 err |= nvlist_lookup_uint32(in, "type", &flp->fl_fac_subtype);
2097 #ifdef _LP64
2098 err |= nvlist_lookup_uint64(in, "callback", &flp->fl_callback);
2099 err |= nvlist_lookup_uint64(in, "callback-args",
2100 &flp->fl_callback_args);
2101 #else
2102 err |= nvlist_lookup_uint32(in, "callback", &flp->fl_callback);
2103 err |= nvlist_lookup_uint32(in, "callback-args",
2104 &flp->fl_callback_args);
2105 #endif
2106 if (err != 0) {
2107 topo_mod_dprintf(mod, "hc_fmri_facility: failed to construct "
2108 "walker arg nvlist\n");
2109 topo_mod_free(mod, flp, sizeof (struct fac_lookup));
2110 return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
2113 flp->fl_fac_rsrc = NULL;
2114 if ((hwp = hc_walk_init(mod, node, flp->fl_rsrc, hc_fac_get,
2115 (void *)flp)) != NULL) {
2116 if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
2117 TOPO_WALK_ERR)
2118 err = -1;
2119 else
2120 err = 0;
2121 topo_walk_fini(hwp->hcw_wp);
2122 topo_mod_free(mod, hwp, sizeof (struct hc_walk));
2123 } else {
2124 topo_mod_dprintf(mod, "hc_fmri_facility: failed to initialize "
2125 "hc walker\n");
2126 err = -1;
2129 if (flp->fl_fac_rsrc != NULL)
2130 *out = flp->fl_fac_rsrc;
2132 topo_mod_free(mod, flp, sizeof (struct fac_lookup));
2134 return (err);
2137 /* ARGSUSED */
2138 static int
2139 hc_expand(topo_mod_t *mod, tnode_t *node, void *pdata)
2141 int err;
2142 nvlist_t *nvl;
2143 const char **namep;
2144 struct hc_args *hap = (struct hc_args *)pdata;
2145 const char *names[] = {
2146 FM_FMRI_HC_SERIAL_ID,
2147 FM_FMRI_HC_PART,
2148 FM_FMRI_HC_REVISION,
2149 NULL
2152 if (topo_node_resource(node, &nvl, &err) != 0)
2153 return (ETOPO_METHOD_FAIL);
2155 for (namep = names; *namep != NULL; namep++) {
2156 char *in_val, *node_val;
2158 if (nvlist_lookup_string(nvl, *namep, &node_val) != 0)
2159 continue;
2161 if (nvlist_lookup_string(hap->ha_fmri, *namep, &in_val) == 0) {
2162 if (strcmp(in_val, node_val) == 0)
2163 continue;
2164 (void) nvlist_remove(hap->ha_fmri, *namep,
2165 DATA_TYPE_STRING);
2168 if (nvlist_add_string(hap->ha_fmri, *namep, node_val) != 0) {
2169 nvlist_free(nvl);
2170 return (ETOPO_PROP_NVL);
2173 nvlist_free(nvl);
2175 return (0);
2178 /* ARGSUSED */
2179 static int
2180 hc_fmri_expand(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2181 nvlist_t *in, nvlist_t **out)
2183 int err;
2184 struct hc_walk *hwp;
2185 struct hc_args *hap;
2187 if (version > TOPO_METH_EXPAND_VERSION)
2188 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
2190 if ((hap = topo_mod_alloc(mod, sizeof (struct hc_args))) == NULL)
2191 return (topo_mod_seterrno(mod, EMOD_NOMEM));
2193 hap->ha_fmri = in;
2194 hap->ha_nvl = NULL;
2195 if ((hwp = hc_walk_init(mod, node, hap->ha_fmri, hc_expand,
2196 (void *)hap)) != NULL) {
2197 if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
2198 TOPO_WALK_ERR)
2199 err = -1;
2200 else
2201 err = 0;
2202 topo_walk_fini(hwp->hcw_wp);
2203 } else {
2204 err = -1;
2207 topo_mod_free(mod, hwp, sizeof (struct hc_walk));
2209 /* expand method should not return out nvlist */
2210 assert(hap->ha_nvl == NULL);
2212 topo_mod_free(mod, hap, sizeof (struct hc_args));
2214 return (err);
2217 static int
2218 hc_retire_subr(topo_mod_t *mod, tnode_t *node, void *pdata)
2220 int err, rc;
2221 struct hc_args *hap = (struct hc_args *)pdata;
2223 topo_mod_dprintf(mod, "hc_retire_subr: invoking method %s\n",
2224 hap->ha_method_name);
2226 * check with the enumerator that created this FMRI
2227 * (topo node)
2229 rc = topo_method_invoke(node, hap->ha_method_name,
2230 hap->ha_method_ver, hap->ha_fmri, &hap->ha_nvl, &err);
2232 topo_mod_dprintf(mod, "hc_retire_subr: invoking method %s "
2233 "returned %d\n", hap->ha_method_name, rc);
2235 return (rc < 0 ? err : 0);
2238 static int
2239 hc_fmri_retire_subr(topo_mod_t *mod, tnode_t *node, char *method_name,
2240 topo_version_t builtin_version, topo_version_t version, nvlist_t *in,
2241 nvlist_t **out)
2243 int err;
2244 struct hc_walk *hwp;
2245 struct hc_args *hap;
2247 if (version > builtin_version)
2248 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
2250 if ((hap = topo_mod_alloc(mod, sizeof (struct hc_args))) == NULL)
2251 return (topo_mod_seterrno(mod, EMOD_NOMEM));
2253 hap->ha_fmri = in;
2254 hap->ha_nvl = NULL;
2255 hap->ha_method_name = method_name;
2256 hap->ha_method_ver = version;
2257 if ((hwp = hc_walk_init(mod, node, hap->ha_fmri, hc_retire_subr,
2258 (void *)hap)) != NULL) {
2259 if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
2260 TOPO_WALK_ERR)
2261 err = -1;
2262 else
2263 err = 0;
2264 topo_walk_fini(hwp->hcw_wp);
2265 } else {
2266 err = -1;
2269 topo_mod_free(mod, hwp, sizeof (struct hc_walk));
2271 if (hap->ha_nvl != NULL)
2272 *out = hap->ha_nvl;
2274 topo_mod_free(mod, hap, sizeof (struct hc_args));
2276 return (err);
2279 static int
2280 hc_fmri_retire(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2281 nvlist_t *in, nvlist_t **out)
2283 return (hc_fmri_retire_subr(mod, node, TOPO_METH_RETIRE,
2284 TOPO_METH_RETIRE_VERSION, version, in, out));
2287 static int
2288 hc_fmri_unretire(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2289 nvlist_t *in, nvlist_t **out)
2291 return (hc_fmri_retire_subr(mod, node, TOPO_METH_UNRETIRE,
2292 TOPO_METH_UNRETIRE_VERSION, version, in, out));
2295 static int
2296 hc_fmri_service_state(topo_mod_t *mod, tnode_t *node, topo_version_t version,
2297 nvlist_t *in, nvlist_t **out)
2299 return (hc_fmri_retire_subr(mod, node, TOPO_METH_SERVICE_STATE,
2300 TOPO_METH_SERVICE_STATE_VERSION, version, in, out));