1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <ctype.h>
28 #include <string.h>
29 #include <limits.h>
30 #include <fm/topo_mod.h>
31 #include <fm/fmd_fmri.h>
32 #include <sys/fm/protocol.h>
33 #include <topo_alloc.h>
34 #include <topo_error.h>
35 #include <topo_hc.h>
36 #include <topo_method.h>
37 #include <topo_subr.h>
38 #include <topo_string.h>
39
40 /*
41 * Topology node properties and method operations may be accessed by FMRI.
42 * The FMRI used to perform property look-ups and method operations is
43 * the FMRI contained in the matching topology node's protocol property
44 * grouping for the resource property. The full range of fmd(1M)
45 * scheme plugin operations are supported as long as a backend method is
46 * supplied by a scheme-specific enumerator or the enumerator module that
47 * created the matching topology node. Support for fmd scheme operations
48 * include:
49 *
50 * - expand
51 * - present
52 * - replaced
53 * - contains
54 * - unusable
55 * - service_state
56 * - nvl2str
57 * - retire
58 * - unretire
59 *
60 * In addition, the following operations are supported per-FMRI:
61 *
62 * - str2nvl: convert string-based FMRI to nvlist
63 * - compare: compare two FMRIs
64 * - asru: lookup associated ASRU property by FMRI
65 * - fru: lookup associated FRU by FMRI
66 * - create: an FMRI nvlist by scheme type
67 * - propery lookup
68 *
69 * These routines may only be called by consumers of a topology snapshot.
70 * They may not be called by libtopo enumerator or method modules.
71 */
72
73 /*ARGSUSED*/
74 static int
set_error(topo_hdl_t * thp,int err,int * errp,char * method,nvlist_t * nvlp)75 set_error(topo_hdl_t *thp, int err, int *errp, char *method, nvlist_t *nvlp)
76 {
77 nvlist_free(nvlp);
78
79 topo_dprintf(thp, TOPO_DBG_ERR, "%s failed: %s\n", method,
80 topo_strerror(err));
81
82 *errp = err;
83 return (-1);
84 }
85
86 /*ARGSUSED*/
87 static nvlist_t *
set_nverror(topo_hdl_t * thp,int err,int * errp,char * method,nvlist_t * nvlp)88 set_nverror(topo_hdl_t *thp, int err, int *errp, char *method, nvlist_t *nvlp)
89 {
90 nvlist_free(nvlp);
91
92 topo_dprintf(thp, TOPO_DBG_ERR, "%s failed: %s\n", method,
93 topo_strerror(err));
94
95 *errp = err;
96 return (NULL);
97 }
98
99 int
topo_fmri_nvl2str(topo_hdl_t * thp,nvlist_t * fmri,char ** fmristr,int * err)100 topo_fmri_nvl2str(topo_hdl_t *thp, nvlist_t *fmri, char **fmristr, int *err)
101 {
102 char *scheme, *str;
103 nvlist_t *out = NULL;
104 tnode_t *rnode;
105
106 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
107 return (set_error(thp, ETOPO_FMRI_MALFORM, err,
108 TOPO_METH_NVL2STR, out));
109
110 if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
111 return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
112 TOPO_METH_NVL2STR, out));
113
114 if (topo_method_invoke(rnode, TOPO_METH_NVL2STR,
115 TOPO_METH_NVL2STR_VERSION, fmri, &out, err) != 0)
116 return (set_error(thp, *err, err, TOPO_METH_NVL2STR, out));
117
118 if (out == NULL || nvlist_lookup_string(out, "fmri-string", &str) != 0)
119 return (set_error(thp, ETOPO_METHOD_INVAL, err,
120 TOPO_METH_NVL2STR, out));
121
122 if ((*fmristr = topo_hdl_strdup(thp, str)) == NULL)
123 return (set_error(thp, ETOPO_NOMEM, err,
124 TOPO_METH_NVL2STR, out));
125
126 nvlist_free(out);
127
128 return (0);
129 }
130
131 int
topo_fmri_str2nvl(topo_hdl_t * thp,const char * fmristr,nvlist_t ** fmri,int * err)132 topo_fmri_str2nvl(topo_hdl_t *thp, const char *fmristr, nvlist_t **fmri,
133 int *err)
134 {
135 char *f, buf[PATH_MAX];
136 nvlist_t *out = NULL, *in = NULL;
137 tnode_t *rnode;
138
139 (void) strlcpy(buf, fmristr, sizeof (buf));
140 if ((f = strchr(buf, ':')) == NULL)
141 return (set_error(thp, ETOPO_FMRI_MALFORM, err,
142 TOPO_METH_STR2NVL, in));
143
144 *f = '\0'; /* strip trailing FMRI path */
145
146 if ((rnode = topo_hdl_root(thp, buf)) == NULL)
147 return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
148 TOPO_METH_STR2NVL, in));
149
150 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
151 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_STR2NVL,
152 in));
153
154 if (nvlist_add_string(in, "fmri-string", fmristr) != 0)
155 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_STR2NVL,
156 in));
157
158 if (topo_method_invoke(rnode, TOPO_METH_STR2NVL,
159 TOPO_METH_STR2NVL_VERSION, in, &out, err) != 0)
160 return (set_error(thp, *err, err, TOPO_METH_STR2NVL, in));
161
162 nvlist_free(in);
163
164 if (out == NULL ||
165 topo_hdl_nvdup(thp, out, fmri) != 0)
166 return (set_error(thp, ETOPO_FMRI_NVL, err,
167 TOPO_METH_STR2NVL, out));
168
169 nvlist_free(out);
170
171 return (0);
172 }
173
174 int
topo_fmri_present(topo_hdl_t * thp,nvlist_t * fmri,int * err)175 topo_fmri_present(topo_hdl_t *thp, nvlist_t *fmri, int *err)
176 {
177 uint32_t present = 0;
178 char *scheme;
179 nvlist_t *out = NULL;
180 tnode_t *rnode;
181
182 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
183 return (set_error(thp, ETOPO_FMRI_MALFORM, err,
184 TOPO_METH_PRESENT, out));
185
186 if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
187 return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
188 TOPO_METH_PRESENT, out));
189
190 if (topo_method_invoke(rnode, TOPO_METH_PRESENT,
191 TOPO_METH_PRESENT_VERSION, fmri, &out, err) < 0) {
192 (void) set_error(thp, *err, err, TOPO_METH_PRESENT, out);
193 return (present);
194 }
195
196 (void) nvlist_lookup_uint32(out, TOPO_METH_PRESENT_RET, &present);
197 nvlist_free(out);
198
199 return (present);
200 }
201
202 int
topo_fmri_replaced(topo_hdl_t * thp,nvlist_t * fmri,int * err)203 topo_fmri_replaced(topo_hdl_t *thp, nvlist_t *fmri, int *err)
204 {
205 uint32_t replaced = FMD_OBJ_STATE_NOT_PRESENT;
206 char *scheme;
207 nvlist_t *out = NULL;
208 tnode_t *rnode;
209
210 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
211 return (set_error(thp, ETOPO_FMRI_MALFORM, err,
212 TOPO_METH_REPLACED, out));
213
214 if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
215 return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
216 TOPO_METH_REPLACED, out));
217
218 if (topo_method_invoke(rnode, TOPO_METH_REPLACED,
219 TOPO_METH_REPLACED_VERSION, fmri, &out, err) < 0) {
220 (void) set_error(thp, *err, err, TOPO_METH_REPLACED, out);
221 return (FMD_OBJ_STATE_UNKNOWN);
222 }
223
224 (void) nvlist_lookup_uint32(out, TOPO_METH_REPLACED_RET, &replaced);
225 nvlist_free(out);
226
227 return (replaced);
228 }
229
230 int
topo_fmri_contains(topo_hdl_t * thp,nvlist_t * fmri,nvlist_t * subfmri,int * err)231 topo_fmri_contains(topo_hdl_t *thp, nvlist_t *fmri, nvlist_t *subfmri, int *err)
232 {
233 uint32_t contains;
234 char *scheme;
235 nvlist_t *in = NULL, *out = NULL;
236 tnode_t *rnode;
237
238 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
239 return (set_error(thp, ETOPO_FMRI_MALFORM, err,
240 TOPO_METH_CONTAINS, NULL));
241
242 if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
243 return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
244 TOPO_METH_CONTAINS, NULL));
245
246 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
247 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS,
248 NULL));
249
250 if (nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_FMRI, fmri) != 0 ||
251 nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_SUBFMRI, subfmri) != 0)
252 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS,
253 in));
254
255 if (topo_method_invoke(rnode, TOPO_METH_CONTAINS,
256 TOPO_METH_CONTAINS_VERSION, in, &out, err) < 0)
257 return (set_error(thp, *err, err, TOPO_METH_CONTAINS, in));
258
259 (void) nvlist_lookup_uint32(out, TOPO_METH_CONTAINS_RET, &contains);
260 nvlist_free(in);
261 nvlist_free(out);
262
263 return (contains);
264 }
265
266 int
topo_fmri_unusable(topo_hdl_t * thp,nvlist_t * fmri,int * err)267 topo_fmri_unusable(topo_hdl_t *thp, nvlist_t *fmri, int *err)
268 {
269 char *scheme;
270 uint32_t unusable = 0;
271 nvlist_t *out = NULL;
272 tnode_t *rnode;
273
274 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
275 return (set_error(thp, ETOPO_FMRI_MALFORM, err,
276 TOPO_METH_UNUSABLE, out));
277
278 if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
279 return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
280 TOPO_METH_UNUSABLE, out));
281
282 if (topo_method_invoke(rnode, TOPO_METH_UNUSABLE,
283 TOPO_METH_UNUSABLE_VERSION, fmri, &out, err) < 0)
284 return (set_error(thp, *err, err, TOPO_METH_UNUSABLE, out));
285
286 (void) nvlist_lookup_uint32(out, TOPO_METH_UNUSABLE_RET, &unusable);
287 nvlist_free(out);
288
289 return (unusable);
290 }
291
292 int
topo_fmri_retire(topo_hdl_t * thp,nvlist_t * fmri,int * err)293 topo_fmri_retire(topo_hdl_t *thp, nvlist_t *fmri, int *err)
294 {
295 char *scheme;
296 uint32_t status;
297 nvlist_t *out = NULL;
298 tnode_t *rnode;
299
300 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
301 return (set_error(thp, ETOPO_FMRI_MALFORM, err,
302 TOPO_METH_RETIRE, out));
303
304 if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
305 return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
306 TOPO_METH_RETIRE, out));
307
308 if (topo_method_invoke(rnode, TOPO_METH_RETIRE,
309 TOPO_METH_RETIRE_VERSION, fmri, &out, err) < 0)
310 return (set_error(thp, *err, err, TOPO_METH_RETIRE, out));
311
312 if (nvlist_lookup_uint32(out, TOPO_METH_RETIRE_RET, &status) != 0)
313 return (set_error(thp, ETOPO_METHOD_FAIL, err,
314 TOPO_METH_RETIRE, out));
315 nvlist_free(out);
316
317 return (status);
318 }
319
320 int
topo_fmri_unretire(topo_hdl_t * thp,nvlist_t * fmri,int * err)321 topo_fmri_unretire(topo_hdl_t *thp, nvlist_t *fmri, int *err)
322 {
323 char *scheme;
324 uint32_t status;
325 nvlist_t *out = NULL;
326 tnode_t *rnode;
327
328 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
329 return (set_error(thp, ETOPO_FMRI_MALFORM, err,
330 TOPO_METH_UNRETIRE, out));
331
332 if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
333 return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
334 TOPO_METH_UNRETIRE, out));
335
336 if (topo_method_invoke(rnode, TOPO_METH_UNRETIRE,
337 TOPO_METH_UNRETIRE_VERSION, fmri, &out, err) < 0)
338 return (set_error(thp, *err, err, TOPO_METH_UNRETIRE, out));
339
340 if (nvlist_lookup_uint32(out, TOPO_METH_UNRETIRE_RET, &status) != 0) {
341 nvlist_free(out);
342 return (set_error(thp, ETOPO_METHOD_FAIL, err,
343 TOPO_METH_UNRETIRE, out));
344 }
345 nvlist_free(out);
346
347 return (status);
348 }
349
350 int
topo_fmri_service_state(topo_hdl_t * thp,nvlist_t * fmri,int * err)351 topo_fmri_service_state(topo_hdl_t *thp, nvlist_t *fmri, int *err)
352 {
353 char *scheme;
354 uint32_t service_state = FMD_SERVICE_STATE_UNKNOWN;
355 nvlist_t *out = NULL;
356 tnode_t *rnode;
357
358 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
359 return (set_error(thp, ETOPO_FMRI_MALFORM, err,
360 TOPO_METH_SERVICE_STATE, out));
361
362 if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
363 return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
364 TOPO_METH_SERVICE_STATE, out));
365
366 if (topo_method_invoke(rnode, TOPO_METH_SERVICE_STATE,
367 TOPO_METH_SERVICE_STATE_VERSION, fmri, &out, err) < 0)
368 return (set_error(thp, *err, err, TOPO_METH_SERVICE_STATE,
369 out));
370
371 (void) nvlist_lookup_uint32(out, TOPO_METH_SERVICE_STATE_RET,
372 &service_state);
373 nvlist_free(out);
374
375 return (service_state);
376 }
377
378 int
topo_fmri_expand(topo_hdl_t * thp,nvlist_t * fmri,int * err)379 topo_fmri_expand(topo_hdl_t *thp, nvlist_t *fmri, int *err)
380 {
381 char *scheme;
382 nvlist_t *out = NULL;
383 tnode_t *rnode;
384
385 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
386 return (set_error(thp, ETOPO_FMRI_MALFORM, err,
387 TOPO_METH_EXPAND, out));
388
389 if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
390 return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
391 TOPO_METH_EXPAND, out));
392
393 if (topo_method_invoke(rnode, TOPO_METH_EXPAND,
394 TOPO_METH_EXPAND_VERSION, fmri, &out, err) != 0)
395 return (set_error(thp, *err, err, TOPO_METH_EXPAND, out));
396
397 return (0);
398 }
399
400 static int
fmri_prop(topo_hdl_t * thp,nvlist_t * rsrc,const char * pgname,const char * pname,nvlist_t * args,nvlist_t ** prop,int * err)401 fmri_prop(topo_hdl_t *thp, nvlist_t *rsrc, const char *pgname,
402 const char *pname, nvlist_t *args, nvlist_t **prop,
403 int *err)
404 {
405 int rv;
406 nvlist_t *in = NULL;
407 tnode_t *rnode;
408 char *scheme;
409
410 if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0)
411 return (set_error(thp, ETOPO_FMRI_MALFORM, err,
412 TOPO_METH_PROP_GET, in));
413
414 if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
415 return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
416 TOPO_METH_PROP_GET, in));
417
418 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
419 return (set_error(thp, ETOPO_FMRI_NVL, err,
420 TOPO_METH_PROP_GET, in));
421
422 rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc);
423 rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pgname);
424 rv |= nvlist_add_string(in, TOPO_PROP_VAL_NAME, pname);
425 if (args != NULL)
426 rv |= nvlist_add_nvlist(in, TOPO_PROP_PARGS, args);
427 if (rv != 0)
428 return (set_error(thp, ETOPO_FMRI_NVL, err,
429 TOPO_METH_PROP_GET, in));
430
431 *prop = NULL;
432 rv = topo_method_invoke(rnode, TOPO_METH_PROP_GET,
433 TOPO_METH_PROP_GET_VERSION, in, prop, err);
434
435 nvlist_free(in);
436
437 if (rv != 0)
438 return (-1); /* *err is set for us */
439
440 if (*prop == NULL)
441 return (set_error(thp, ETOPO_PROP_NOENT, err,
442 TOPO_METH_PROP_GET, NULL));
443 return (0);
444 }
445
446 int
topo_fmri_asru(topo_hdl_t * thp,nvlist_t * nvl,nvlist_t ** asru,int * err)447 topo_fmri_asru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **asru, int *err)
448 {
449 nvlist_t *ap, *prop = NULL;
450
451 if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_ASRU,
452 nvl, &prop, err) < 0)
453 return (set_error(thp, *err, err, "topo_fmri_asru", NULL));
454
455 if (nvlist_lookup_nvlist(prop, TOPO_PROP_VAL_VAL, &ap) != 0)
456 return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_asru",
457 prop));
458
459 if (topo_hdl_nvdup(thp, ap, asru) < 0)
460 return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_asru",
461 prop));
462
463 nvlist_free(prop);
464
465 return (0);
466 }
467
468 int
topo_fmri_fru(topo_hdl_t * thp,nvlist_t * nvl,nvlist_t ** fru,int * err)469 topo_fmri_fru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **fru, int *err)
470 {
471 nvlist_t *fp, *prop = NULL;
472
473 if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU,
474 nvl, &prop, err) < 0)
475 return (set_error(thp, *err, err, "topo_fmri_fru", NULL));
476
477 if (nvlist_lookup_nvlist(prop, TOPO_PROP_VAL_VAL, &fp) != 0)
478 return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_fru",
479 prop));
480
481 if (topo_hdl_nvdup(thp, fp, fru) < 0)
482 return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_fru",
483 prop));
484
485 nvlist_free(prop);
486
487 return (0);
488 }
489
490 int
topo_fmri_label(topo_hdl_t * thp,nvlist_t * nvl,char ** label,int * err)491 topo_fmri_label(topo_hdl_t *thp, nvlist_t *nvl, char **label, int *err)
492 {
493 nvlist_t *prop = NULL;
494 char *lp;
495
496 if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_LABEL,
497 NULL, &prop, err) < 0)
498 return (set_error(thp, *err, err, "topo_fmri_label", NULL));
499
500 if (nvlist_lookup_string(prop, TOPO_PROP_VAL_VAL, &lp) != 0)
501 return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_label",
502 prop));
503
504 if ((*label = topo_hdl_strdup(thp, lp)) == NULL)
505 return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_label",
506 prop));
507
508 nvlist_free(prop);
509
510 return (0);
511 }
512
513 int
topo_fmri_serial(topo_hdl_t * thp,nvlist_t * nvl,char ** serial,int * err)514 topo_fmri_serial(topo_hdl_t *thp, nvlist_t *nvl, char **serial, int *err)
515 {
516 nvlist_t *prop = NULL;
517 char *sp;
518
519 /*
520 * If there is a serial id in the resource fmri, then use that.
521 * Otherwise fall back to looking for a serial id property in the
522 * protocol group.
523 */
524 if (nvlist_lookup_string(nvl, FM_FMRI_HC_SERIAL_ID, &sp) == 0) {
525 if ((*serial = topo_hdl_strdup(thp, sp)) == NULL)
526 return (set_error(thp, ETOPO_PROP_NOMEM, err,
527 "topo_fmri_serial", prop));
528 else
529 return (0);
530 }
531
532 if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, FM_FMRI_HC_SERIAL_ID,
533 NULL, &prop, err) < 0)
534 return (set_error(thp, *err, err, "topo_fmri_serial", NULL));
535
536 if (nvlist_lookup_string(prop, TOPO_PROP_VAL_VAL, &sp) != 0)
537 return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_serial",
538 prop));
539
540 if ((*serial = topo_hdl_strdup(thp, sp)) == NULL)
541 return (set_error(thp, ETOPO_PROP_NOMEM, err,
542 "topo_fmri_serial", prop));
543
544 nvlist_free(prop);
545
546 return (0);
547 }
548
topo_fmri_getprop(topo_hdl_t * thp,nvlist_t * nvl,const char * pg,const char * pname,nvlist_t * args,nvlist_t ** prop,int * err)549 int topo_fmri_getprop(topo_hdl_t *thp, nvlist_t *nvl, const char *pg,
550 const char *pname, nvlist_t *args, nvlist_t **prop,
551 int *err)
552 {
553 *prop = NULL;
554
555 return (fmri_prop(thp, nvl, pg, pname, args, prop, err));
556 }
557
topo_fmri_setprop(topo_hdl_t * thp,nvlist_t * nvl,const char * pg,nvlist_t * prop,int flag,nvlist_t * args,int * err)558 int topo_fmri_setprop(topo_hdl_t *thp, nvlist_t *nvl, const char *pg,
559 nvlist_t *prop, int flag, nvlist_t *args, int *err)
560 {
561 int rv;
562 nvlist_t *in = NULL, *out = NULL;
563 tnode_t *rnode;
564 char *scheme;
565
566 if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme) != 0)
567 return (set_error(thp, ETOPO_FMRI_MALFORM, err,
568 TOPO_METH_PROP_SET, in));
569
570 if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
571 return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
572 TOPO_METH_PROP_SET, in));
573
574 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
575 return (set_error(thp, ETOPO_FMRI_NVL, err,
576 TOPO_METH_PROP_SET, in));
577
578 rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, nvl);
579 rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pg);
580 rv |= nvlist_add_nvlist(in, TOPO_PROP_VAL, prop);
581 rv |= nvlist_add_int32(in, TOPO_PROP_FLAG, (int32_t)flag);
582 if (args != NULL)
583 rv |= nvlist_add_nvlist(in, TOPO_PROP_PARGS, args);
584 if (rv != 0)
585 return (set_error(thp, ETOPO_FMRI_NVL, err,
586 TOPO_METH_PROP_SET, in));
587
588 rv = topo_method_invoke(rnode, TOPO_METH_PROP_SET,
589 TOPO_METH_PROP_SET_VERSION, in, &out, err);
590
591 nvlist_free(in);
592
593 /* no return values */
594 nvlist_free(out);
595
596 if (rv)
597 return (-1);
598
599 return (0);
600
601 }
602
603 int
topo_fmri_getpgrp(topo_hdl_t * thp,nvlist_t * rsrc,const char * pgname,nvlist_t ** pgroup,int * err)604 topo_fmri_getpgrp(topo_hdl_t *thp, nvlist_t *rsrc, const char *pgname,
605 nvlist_t **pgroup, int *err)
606 {
607 int rv;
608 nvlist_t *in = NULL;
609 tnode_t *rnode;
610 char *scheme;
611
612 if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0)
613 return (set_error(thp, ETOPO_FMRI_MALFORM, err,
614 TOPO_METH_PROP_GET, in));
615
616 if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
617 return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
618 TOPO_METH_PROP_GET, in));
619
620 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
621 return (set_error(thp, ETOPO_FMRI_NVL, err,
622 TOPO_METH_PROP_GET, in));
623
624 rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc);
625 rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pgname);
626 if (rv != 0)
627 return (set_error(thp, ETOPO_FMRI_NVL, err,
628 TOPO_METH_PROP_GET, in));
629
630 *pgroup = NULL;
631 rv = topo_method_invoke(rnode, TOPO_METH_PGRP_GET,
632 TOPO_METH_PGRP_GET_VERSION, in, pgroup, err);
633
634 nvlist_free(in);
635
636 if (rv != 0)
637 return (-1); /* *err is set for us */
638
639 if (*pgroup == NULL)
640 return (set_error(thp, ETOPO_PROP_NOENT, err,
641 TOPO_METH_PROP_GET, NULL));
642 return (0);
643 }
644
645 int
topo_fmri_compare(topo_hdl_t * thp,nvlist_t * f1,nvlist_t * f2,int * err)646 topo_fmri_compare(topo_hdl_t *thp, nvlist_t *f1, nvlist_t *f2, int *err)
647 {
648 uint32_t compare;
649 char *scheme1, *scheme2;
650 nvlist_t *in;
651 nvlist_t *out = NULL;
652 tnode_t *rnode;
653
654 if (nvlist_lookup_string(f1, FM_FMRI_SCHEME, &scheme1) != 0)
655 return (set_error(thp, ETOPO_FMRI_MALFORM, err,
656 TOPO_METH_COMPARE, NULL));
657 if (nvlist_lookup_string(f2, FM_FMRI_SCHEME, &scheme2) != 0)
658 return (set_error(thp, ETOPO_FMRI_MALFORM, err,
659 TOPO_METH_COMPARE, NULL));
660
661 if (strcmp(scheme1, scheme2) != 0)
662 return (0);
663
664 if ((rnode = topo_hdl_root(thp, scheme1)) == NULL)
665 return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
666 TOPO_METH_COMPARE, NULL));
667
668 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
669 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE,
670 NULL));
671
672 if (nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_NV1, f1) != 0 ||
673 nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_NV2, f2) != 0)
674 return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE,
675 in));
676
677 if (topo_method_invoke(rnode, TOPO_METH_COMPARE,
678 TOPO_METH_COMPARE_VERSION, in, &out, err) < 0)
679 return (set_error(thp, *err, err, TOPO_METH_COMPARE, in));
680
681 (void) nvlist_lookup_uint32(out, TOPO_METH_COMPARE_RET, &compare);
682 nvlist_free(out);
683 nvlist_free(in);
684
685 return (compare);
686 }
687
688 /*
689 * topo_fmri_create
690 *
691 * If possible, creates an FMRI of the requested version in the
692 * requested scheme. Args are passed as part of the inputs to the
693 * fmri-create method of the scheme.
694 */
695 nvlist_t *
topo_fmri_create(topo_hdl_t * thp,const char * scheme,const char * name,topo_instance_t inst,nvlist_t * nvl,int * err)696 topo_fmri_create(topo_hdl_t *thp, const char *scheme, const char *name,
697 topo_instance_t inst, nvlist_t *nvl, int *err)
698 {
699 nvlist_t *ins;
700 nvlist_t *out;
701 tnode_t *rnode;
702
703 ins = out = NULL;
704
705 if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
706 return (set_nverror(thp, ETOPO_METHOD_NOTSUP, err,
707 TOPO_METH_FMRI, NULL));
708
709 if ((*err = topo_hdl_nvalloc(thp, &ins, NV_UNIQUE_NAME)) != 0)
710 return (set_nverror(thp, ETOPO_FMRI_NVL, err,
711 TOPO_METH_FMRI, NULL));
712
713 if (nvlist_add_string(ins, TOPO_METH_FMRI_ARG_NAME, name) != 0 ||
714 nvlist_add_uint32(ins, TOPO_METH_FMRI_ARG_INST, inst) != 0) {
715 return (set_nverror(thp, ETOPO_FMRI_NVL, err,
716 TOPO_METH_FMRI, ins));
717 }
718
719 if (nvl != NULL &&
720 nvlist_add_nvlist(ins, TOPO_METH_FMRI_ARG_NVL, nvl) != 0) {
721 return (set_nverror(thp, ETOPO_FMRI_NVL, err,
722 TOPO_METH_FMRI, ins));
723 }
724 if (topo_method_invoke(rnode,
725 TOPO_METH_FMRI, TOPO_METH_FMRI_VERSION, ins, &out, err) != 0) {
726 return (set_nverror(thp, *err, err, TOPO_METH_FMRI, ins));
727 }
728 nvlist_free(ins);
729 return (out);
730 }
731
732 /*
733 * These private utility functions are used by fmd to maintain its resource
734 * cache. Because hc instance numbers are not guaranteed, it's possible to
735 * have two different FMRI strings represent the same logical entity. These
736 * functions hide this implementation detail from unknowing consumers such as
737 * fmd.
738 *
739 * Ideally, we'd like to do a str2nvl() and then a full FMRI hash and
740 * comparison, but these functions are designed to be fast and efficient.
741 * Given that there is only a single hc node that has this property
742 * (ses-enclosure), we hard-code this behavior here. If there are more
743 * instances of this behavior in the future, this function could be made more
744 * generic.
745 *
746 * This code also handles changes in the server-id or revision fields of the hc
747 * FMRI, as these fields have no bearing on equivalence of FRUs.
748 */
749 static ulong_t
topo_fmri_strhash_one(const char * fmri,size_t len)750 topo_fmri_strhash_one(const char *fmri, size_t len)
751 {
752 ulong_t g, h = 0;
753 size_t i;
754
755 for (i = 0; i < len; i++) {
756 h = (h << 4) + fmri[i];
757
758 if ((g = (h & 0xf0000000)) != 0) {
759 h ^= (g >> 24);
760 h ^= g;
761 }
762 }
763
764 return (h);
765 }
766
767 static const char *
topo_fmri_next_auth(const char * auth)768 topo_fmri_next_auth(const char *auth)
769 {
770 const char *colon, *slash;
771
772 colon = strchr(auth + 1, ':');
773 slash = strchr(auth, '/');
774
775 if (colon == NULL && slash == NULL)
776 return (NULL);
777
778 if (colon == NULL)
779 return (slash);
780 else if (slash < colon)
781 return (slash);
782 else
783 return (colon);
784 }
785
786 /*
787 * List of authority information we care about. Note that we explicitly ignore
788 * things that are properties of the chassis and not the resource itself:
789 *
790 * FM_FMRI_AUTH_PRODUCT_SN "product-sn"
791 * FM_FMRI_AUTH_PRODUCT "product-id"
792 * FM_FMRI_AUTH_DOMAIN "domain-id"
793 * FM_FMRI_AUTH_SERVER "server-id"
794 * FM_FMRI_AUTH_HOST "host-id"
795 *
796 * We also ignore the "revision" authority member, as that typically indicates
797 * the firmware revision and is not a static property of the FRU. This leaves
798 * the following interesting members:
799 *
800 * FM_FMRI_AUTH_CHASSIS "chassis-id"
801 * FM_FMRI_HC_SERIAL_ID "serial"
802 * FM_FMRI_HC_PART "part"
803 */
804 typedef enum {
805 HC_AUTH_CHASSIS,
806 HC_AUTH_SERIAL,
807 HC_AUTH_PART,
808 HC_AUTH_MAX
809 } hc_auth_type_t;
810
811 static char *hc_auth_table[] = {
812 FM_FMRI_AUTH_CHASSIS,
813 FM_FMRI_HC_SERIAL_ID,
814 FM_FMRI_HC_PART
815 };
816
817 /*
818 * Takes an authority member, with leading ":" and trailing "=", and returns
819 * one of the above types if it's one of the things we care about. If
820 * 'authlen' is specified, it is filled in with the length of the authority
821 * member, including leading and trailing characters.
822 */
823 static hc_auth_type_t
hc_auth_to_type(const char * auth,size_t * authlen)824 hc_auth_to_type(const char *auth, size_t *authlen)
825 {
826 int i;
827 size_t len;
828
829 if (auth[0] != ':')
830 return (HC_AUTH_MAX);
831
832 for (i = 0; i < HC_AUTH_MAX; i++) {
833 len = strlen(hc_auth_table[i]);
834
835 if (strncmp(auth + 1, hc_auth_table[i], len) == 0 &&
836 auth[len + 1] == '=') {
837 if (authlen)
838 *authlen = len + 2;
839 break;
840 }
841 }
842
843 return (i);
844 }
845
846 /*ARGSUSED*/
847 ulong_t
topo_fmri_strhash_internal(topo_hdl_t * thp,const char * fmri,boolean_t noauth)848 topo_fmri_strhash_internal(topo_hdl_t *thp, const char *fmri, boolean_t noauth)
849 {
850 const char *auth, *next;
851 const char *enclosure;
852 ulong_t h;
853 hc_auth_type_t type;
854
855 if (strncmp(fmri, "hc://", 5) != 0)
856 return (topo_fmri_strhash_one(fmri, strlen(fmri)));
857
858 enclosure = strstr(fmri, SES_ENCLOSURE);
859
860 h = 0;
861
862 auth = next = fmri + 5;
863 while (*next != '/') {
864 auth = next;
865
866 if ((next = topo_fmri_next_auth(auth)) == NULL) {
867 next = auth;
868 break;
869 }
870
871 if ((type = hc_auth_to_type(auth, NULL)) == HC_AUTH_MAX)
872 continue;
873
874 if (!noauth || type == HC_AUTH_CHASSIS)
875 h += topo_fmri_strhash_one(auth, next - auth);
876 }
877
878 if (enclosure) {
879 next = enclosure + sizeof (SES_ENCLOSURE);
880 while (isdigit(*next))
881 next++;
882 }
883
884 h += topo_fmri_strhash_one(next, strlen(next));
885
886 return (h);
887 }
888
889 /*ARGSUSED*/
890 ulong_t
topo_fmri_strhash(topo_hdl_t * thp,const char * fmri)891 topo_fmri_strhash(topo_hdl_t *thp, const char *fmri)
892 {
893 return (topo_fmri_strhash_internal(thp, fmri, B_FALSE));
894 }
895
896 /*ARGSUSED*/
897 ulong_t
topo_fmri_strhash_noauth(topo_hdl_t * thp,const char * fmri)898 topo_fmri_strhash_noauth(topo_hdl_t *thp, const char *fmri)
899 {
900 return (topo_fmri_strhash_internal(thp, fmri, B_TRUE));
901 }
902
903
904 static void
topo_fmri_strcmp_parse_auth(const char * auth,const char * authtype[],size_t authlen[])905 topo_fmri_strcmp_parse_auth(const char *auth, const char *authtype[],
906 size_t authlen[])
907 {
908 int i;
909 const char *next;
910 hc_auth_type_t type;
911 size_t len;
912
913 for (i = 0; i < HC_AUTH_MAX; i++)
914 authlen[i] = 0;
915
916 while (*auth != '/' &&
917 (next = topo_fmri_next_auth(auth)) != NULL) {
918 if ((type = hc_auth_to_type(auth, &len)) == HC_AUTH_MAX) {
919 auth = next;
920 continue;
921 }
922
923 authtype[type] = auth + len;
924 authlen[type] = next - (auth + len);
925 auth = next;
926 }
927 }
928
929 /*ARGSUSED*/
930 static boolean_t
topo_fmri_strcmp_internal(topo_hdl_t * thp,const char * a,const char * b,boolean_t noauth)931 topo_fmri_strcmp_internal(topo_hdl_t *thp, const char *a, const char *b,
932 boolean_t noauth)
933 {
934 const char *fmria, *fmrib;
935 const char *autha[HC_AUTH_MAX], *authb[HC_AUTH_MAX];
936 size_t authlena[HC_AUTH_MAX], authlenb[HC_AUTH_MAX];
937 int i;
938
939 /*
940 * For non-hc FMRIs, we don't do anything.
941 */
942 if (strncmp(a, "hc://", 5) != 0 ||
943 strncmp(b, "hc://", 5) != 0)
944 return (strcmp(a, b) == 0);
945
946 /*
947 * Get the portion of the FMRI independent of the authority
948 * information.
949 */
950 fmria = strchr(a + 5, '/');
951 fmrib = strchr(b + 5, '/');
952 if (fmria == NULL || fmrib == NULL)
953 return (strcmp(a, b));
954 fmria++;
955 fmrib++;
956
957 /*
958 * Comparing fmri authority information is a bit of a pain, because
959 * there may be a different number of members, and they can (but
960 * shouldn't be) in a different order. We need to create a copy of the
961 * authority and parse it into pieces. Because this function is
962 * intended to be fast (and not necessarily extensible), we hard-code
963 * the list of possible authority members in an enum and parse it into
964 * an array.
965 */
966 topo_fmri_strcmp_parse_auth(a + 5, autha, authlena);
967 topo_fmri_strcmp_parse_auth(b + 5, authb, authlenb);
968
969 for (i = 0; i < HC_AUTH_MAX; i++) {
970 if (noauth && i != HC_AUTH_CHASSIS)
971 continue;
972
973 if (authlena[i] == 0 && authlenb[i] == 0)
974 continue;
975
976 if (authlena[i] != authlenb[i])
977 return (B_FALSE);
978
979 if (strncmp(autha[i], authb[i], authlena[i]) != 0)
980 return (B_FALSE);
981 }
982
983 /*
984 * If this is rooted at a ses-enclosure node, skip past the instance
985 * number, as it has no meaning.
986 */
987 if (strncmp(fmria, SES_ENCLOSURE, sizeof (SES_ENCLOSURE) - 1) == 0 &&
988 strncmp(fmrib, SES_ENCLOSURE, sizeof (SES_ENCLOSURE) - 1) == 0) {
989 fmria += sizeof (SES_ENCLOSURE);
990 fmrib += sizeof (SES_ENCLOSURE);
991
992 while (isdigit(*fmria))
993 fmria++;
994 while (isdigit(*fmrib))
995 fmrib++;
996 }
997
998 return (strcmp(fmria, fmrib) == 0);
999 }
1000
1001 /*ARGSUSED*/
1002 boolean_t
topo_fmri_strcmp(topo_hdl_t * thp,const char * a,const char * b)1003 topo_fmri_strcmp(topo_hdl_t *thp, const char *a, const char *b)
1004 {
1005 return (topo_fmri_strcmp_internal(thp, a, b, B_FALSE));
1006 }
1007
1008 /*ARGSUSED*/
1009 boolean_t
topo_fmri_strcmp_noauth(topo_hdl_t * thp,const char * a,const char * b)1010 topo_fmri_strcmp_noauth(topo_hdl_t *thp, const char *a, const char *b)
1011 {
1012 return (topo_fmri_strcmp_internal(thp, a, b, B_TRUE));
1013 }
1014
1015 int
topo_fmri_facility(topo_hdl_t * thp,nvlist_t * rsrc,const char * fac_type,uint32_t fac_subtype,topo_walk_cb_t cb,void * cb_args,int * err)1016 topo_fmri_facility(topo_hdl_t *thp, nvlist_t *rsrc, const char *fac_type,
1017 uint32_t fac_subtype, topo_walk_cb_t cb, void *cb_args, int *err)
1018 {
1019 int rv;
1020 nvlist_t *in = NULL, *out;
1021 tnode_t *rnode;
1022 char *scheme;
1023
1024 if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0)
1025 return (set_error(thp, ETOPO_FMRI_MALFORM, err,
1026 TOPO_METH_PROP_GET, in));
1027
1028 if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
1029 return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
1030 TOPO_METH_PROP_GET, in));
1031
1032 if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
1033 return (set_error(thp, ETOPO_FMRI_NVL, err,
1034 TOPO_METH_PROP_GET, in));
1035
1036 rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc);
1037 rv |= nvlist_add_string(in, FM_FMRI_FACILITY_TYPE, fac_type);
1038 rv |= nvlist_add_uint32(in, "type", fac_subtype);
1039 #ifdef _LP64
1040 rv |= nvlist_add_uint64(in, "callback", (uint64_t)cb);
1041 rv |= nvlist_add_uint64(in, "callback-args", (uint64_t)cb_args);
1042 #else
1043 rv |= nvlist_add_uint32(in, "callback", (uint32_t)cb);
1044 rv |= nvlist_add_uint32(in, "callback-args", (uint32_t)cb_args);
1045 #endif
1046 if (rv != 0)
1047 return (set_error(thp, ETOPO_FMRI_NVL, err,
1048 TOPO_METH_PROP_GET, in));
1049
1050 rv = topo_method_invoke(rnode, TOPO_METH_FACILITY,
1051 TOPO_METH_FACILITY_VERSION, in, &out, err);
1052
1053 nvlist_free(in);
1054
1055 if (rv != 0)
1056 return (-1); /* *err is set for us */
1057
1058 return (0);
1059 }
1060