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