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  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * Topology Plugin Modules
30  *
31  * Topology plugin modules are shared libraries that are dlopen'd and
32  * used to enumerate resources in the system.
33  * They are loaded by our builtin scheme-specific plugins or other modules
34  * to enumerate and create nodes for resources that are present in the system.
35  * They may also export a set of resource (node) specific methods that can be
36  * called on node-by-node basis.
37  *
38  * Module Plugin API
39  *
40  * Enumerators must provide entry points for intialization and clean-up
41  * (_topo_init() and _topo_fini()).  In their _topo_init() function, an
42  * enumerator should register (topo_mod_register()) its enumeration callback
43  * and allocate resources required for a subsequent call to the callback.
44  * Optionally, methods may also be registered with topo_method_register().
45  *
46  * In its enumeration callback routine, the module should search for resources
47  * within its realm of resposibility and create any node ranges,
48  * topo_node_range_create() or nodes, topo_node_bind().  The Enumerator
49  * module is handed a node to which it may begin attaching additional
50  * topology nodes.
51  *
52  * If additional helper modules need to be loaded to complete the enumeration
53  * the module may do so by calling topo_mod_load().  Enumeration may then
54  * continue with the module handing off enumeration to its helper module
55  * by calling topo_mod_enumerate().
56  *
57  * If the module registers a release callback, it will be called on a node
58  * by node basis during topo_snap_rele().  Any private node data may be
59  * deallocated or methods unregistered at that time.  Global module data
60  * should be clean-up before or at the time that the module _topo_fini
61  * entry point is called.
62  */
63 
64 #include <pthread.h>
65 #include <assert.h>
66 #include <errno.h>
67 #include <dirent.h>
68 #include <limits.h>
69 #include <alloca.h>
70 #include <unistd.h>
71 #include <stdio.h>
72 #include <sys/param.h>
73 #include <sys/utsname.h>
74 #include <sys/smbios.h>
75 #include <sys/fm/protocol.h>
76 
77 #include <topo_alloc.h>
78 #include <topo_error.h>
79 #include <topo_file.h>
80 #include <topo_module.h>
81 #include <topo_method.h>
82 #include <topo_string.h>
83 #include <topo_subr.h>
84 #include <topo_tree.h>
85 
86 #define	PLUGIN_PATH	"plugins"
87 #define	PLUGIN_PATH_LEN	MAXNAMELEN + 5
88 
89 topo_mod_t *
90 topo_mod_load(topo_mod_t *pmod, const char *name,
91     topo_version_t version)
92 {
93 	char *path;
94 	char file[PLUGIN_PATH_LEN];
95 	topo_mod_t *mod = NULL;
96 	topo_hdl_t *thp;
97 
98 	thp = pmod->tm_hdl;
99 
100 	/*
101 	 * Already loaded, topo_mod_lookup will bump the ref count
102 	 */
103 	if ((mod = topo_mod_lookup(thp, name, 1)) != NULL) {
104 		if (mod->tm_info->tmi_version != version) {
105 			topo_mod_rele(mod);
106 			(void) topo_mod_seterrno(pmod, ETOPO_MOD_VER);
107 			return (NULL);
108 		}
109 		return (mod);
110 	}
111 
112 	(void) snprintf(file, PLUGIN_PATH_LEN, "%s/%s.so",
113 	    PLUGIN_PATH, name);
114 	path = topo_search_path(pmod, thp->th_rootdir, (const char *)file);
115 	if (path == NULL ||
116 	    (mod = topo_modhash_load(thp, name, path, &topo_rtld_ops, version))
117 	    == NULL) { /* returned with mod held */
118 			topo_mod_strfree(pmod, path);
119 			(void) topo_mod_seterrno(pmod, topo_hdl_errno(thp) ?
120 			    topo_hdl_errno(thp) : ETOPO_MOD_NOENT);
121 			return (NULL);
122 	}
123 
124 	topo_mod_strfree(pmod, path);
125 
126 	return (mod);
127 }
128 
129 void
130 topo_mod_unload(topo_mod_t *mod)
131 {
132 	topo_mod_rele(mod);
133 }
134 
135 static int
136 set_register_error(topo_mod_t *mod, int err)
137 {
138 	if (mod->tm_info != NULL)
139 		topo_mod_unregister(mod);
140 
141 	topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR,
142 	    "module registration failed for %s: %s\n",
143 	    mod->tm_name, topo_strerror(err));
144 
145 	return (topo_mod_seterrno(mod, err));
146 }
147 
148 int
149 topo_mod_register(topo_mod_t *mod, const topo_modinfo_t *mip,
150     topo_version_t version)
151 {
152 
153 	assert(!(mod->tm_flags & TOPO_MOD_FINI ||
154 	    mod->tm_flags & TOPO_MOD_REG));
155 
156 	if (version != TOPO_VERSION)
157 		return (set_register_error(mod, EMOD_VER_ABI));
158 
159 	if ((mod->tm_info = topo_mod_alloc(mod, sizeof (topo_imodinfo_t)))
160 	    == NULL)
161 		return (set_register_error(mod, EMOD_NOMEM));
162 	if ((mod->tm_info->tmi_ops = topo_mod_alloc(mod,
163 	    sizeof (topo_modops_t))) == NULL)
164 		return (set_register_error(mod, EMOD_NOMEM));
165 
166 	mod->tm_info->tmi_desc = topo_mod_strdup(mod, mip->tmi_desc);
167 	if (mod->tm_info->tmi_desc == NULL)
168 		return (set_register_error(mod, EMOD_NOMEM));
169 
170 	mod->tm_info->tmi_scheme = topo_mod_strdup(mod, mip->tmi_scheme);
171 	if (mod->tm_info->tmi_scheme == NULL)
172 		return (set_register_error(mod, EMOD_NOMEM));
173 
174 
175 	mod->tm_info->tmi_version = (topo_version_t)mip->tmi_version;
176 	mod->tm_info->tmi_ops->tmo_enum = mip->tmi_ops->tmo_enum;
177 	mod->tm_info->tmi_ops->tmo_release = mip->tmi_ops->tmo_release;
178 
179 	mod->tm_flags |= TOPO_MOD_REG;
180 
181 	topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC,
182 	    "registration succeeded for %s\n", mod->tm_name);
183 
184 	return (0);
185 }
186 
187 void
188 topo_mod_unregister(topo_mod_t *mod)
189 {
190 	if (mod->tm_info == NULL)
191 		return;
192 
193 	assert(!(mod->tm_flags & TOPO_MOD_FINI));
194 
195 	mod->tm_flags &= ~TOPO_MOD_REG;
196 
197 	if (mod->tm_info == NULL)
198 		return;
199 
200 	if (mod->tm_info->tmi_ops != NULL)
201 		topo_mod_free(mod, mod->tm_info->tmi_ops,
202 		    sizeof (topo_modops_t));
203 	if (mod->tm_info->tmi_desc != NULL)
204 		topo_mod_strfree(mod, mod->tm_info->tmi_desc);
205 	if (mod->tm_info->tmi_scheme != NULL)
206 		topo_mod_strfree(mod, mod->tm_info->tmi_scheme);
207 
208 	topo_mod_free(mod, mod->tm_info, sizeof (topo_imodinfo_t));
209 
210 	mod->tm_info = NULL;
211 }
212 
213 int
214 topo_mod_enumerate(topo_mod_t *mod, tnode_t *node, const char *enum_name,
215     const char *name, topo_instance_t min, topo_instance_t max, void *data)
216 {
217 	int err = 0;
218 	topo_mod_t *enum_mod;
219 
220 	assert(mod->tm_flags & TOPO_MOD_REG);
221 
222 	if ((enum_mod = topo_mod_lookup(mod->tm_hdl, enum_name, 0)) == NULL)
223 		return (topo_mod_seterrno(mod, EMOD_MOD_NOENT));
224 
225 	topo_node_hold(node);
226 
227 	topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC, "module %s enumerating "
228 	    "node %s=%d\n", (char *)mod->tm_name, (char *)node->tn_name,
229 	    node->tn_instance);
230 
231 	topo_mod_enter(enum_mod);
232 	err = enum_mod->tm_info->tmi_ops->tmo_enum(enum_mod, node, name, min,
233 	    max, enum_mod->tm_priv, data);
234 	topo_mod_exit(enum_mod);
235 
236 	if (err != 0) {
237 		(void) topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
238 
239 		topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR,
240 		    "module %s failed enumeration for "
241 		    " node %s=%d\n", (char *)mod->tm_name,
242 		    (char *)node->tn_name, node->tn_instance);
243 
244 		topo_node_rele(node);
245 		return (-1);
246 	}
247 
248 	topo_node_rele(node);
249 
250 	return (0);
251 }
252 
253 int
254 topo_mod_enummap(topo_mod_t *mod, tnode_t *node, const char *name,
255     const char *scheme)
256 {
257 	return (topo_file_load(mod, node, (char *)name, (char *)scheme));
258 }
259 
260 static nvlist_t *
261 set_fmri_err(topo_mod_t *mod, int err)
262 {
263 	(void) topo_mod_seterrno(mod, err);
264 	return (NULL);
265 }
266 
267 nvlist_t *
268 topo_mod_hcfmri(topo_mod_t *mod, tnode_t *pnode, int version, const char *name,
269     topo_instance_t inst, nvlist_t *hc_specific, nvlist_t *auth,
270     const char *part, const char *rev, const char *serial)
271 {
272 	int err;
273 	nvlist_t *pfmri = NULL, *fmri = NULL, *args = NULL;
274 	nvlist_t *nfp = NULL;
275 
276 	if (version != FM_HC_SCHEME_VERSION)
277 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
278 
279 	/*
280 	 * Do we have any args to pass?
281 	 */
282 	if (pnode != NULL || auth != NULL || part != NULL || rev != NULL ||
283 	    serial != NULL || hc_specific != NULL) {
284 		if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
285 		    return (set_fmri_err(mod, EMOD_FMRI_NVL));
286 	}
287 
288 	if (pnode != NULL) {
289 		if (topo_node_resource(pnode, &pfmri, &err) < 0)
290 			return (set_fmri_err(mod, EMOD_NVL_INVAL));
291 
292 		if (nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_PARENT,
293 		    pfmri) != 0) {
294 			nvlist_free(pfmri);
295 			nvlist_free(args);
296 			return (set_fmri_err(mod, EMOD_FMRI_NVL));
297 		}
298 		nvlist_free(pfmri);
299 	}
300 
301 	/*
302 	 * Add optional payload
303 	 */
304 	if (auth != NULL)
305 		(void) nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_AUTH, auth);
306 	if (part != NULL)
307 		(void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_PART, part);
308 	if (rev != NULL)
309 		(void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_REV, rev);
310 	if (serial != NULL)
311 		(void) nvlist_add_string(args, TOPO_METH_FMRI_ARG_SER,
312 		    serial);
313 	if (hc_specific != NULL)
314 		(void) nvlist_add_nvlist(args, TOPO_METH_FMRI_ARG_HCS,
315 		    hc_specific);
316 
317 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_HC, name, inst,
318 	    args, &err)) == NULL) {
319 		nvlist_free(args);
320 		return (set_fmri_err(mod, err));
321 	}
322 
323 	nvlist_free(args);
324 
325 	(void) topo_mod_nvdup(mod, fmri, &nfp);
326 	nvlist_free(fmri);
327 
328 	return (nfp);
329 }
330 
331 nvlist_t *
332 topo_mod_devfmri(topo_mod_t *mod, int version, const char *dev_path,
333     const char *devid)
334 {
335 	int err;
336 	nvlist_t *fmri, *args;
337 	nvlist_t *nfp = NULL;
338 
339 	if (version != FM_DEV_SCHEME_VERSION)
340 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
341 
342 	if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
343 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
344 
345 	if (nvlist_add_string(args, FM_FMRI_DEV_PATH, dev_path) != 0) {
346 		nvlist_free(args);
347 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
348 	}
349 
350 	(void) nvlist_add_string(args, FM_FMRI_DEV_ID, devid);
351 
352 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_DEV,
353 	    FM_FMRI_SCHEME_DEV, 0, args, &err)) == NULL) {
354 		nvlist_free(args);
355 		return (set_fmri_err(mod, err));
356 	}
357 
358 	nvlist_free(args);
359 
360 	(void) topo_mod_nvdup(mod, fmri, &nfp);
361 	nvlist_free(fmri);
362 
363 	return (nfp);
364 }
365 
366 nvlist_t *
367 topo_mod_cpufmri(topo_mod_t *mod, int version, uint32_t cpu_id, uint8_t cpumask,
368     const char *serial)
369 {
370 	int err;
371 	nvlist_t *fmri = NULL, *args = NULL;
372 	nvlist_t *nfp = NULL;
373 
374 	if (version != FM_CPU_SCHEME_VERSION)
375 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
376 
377 	if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
378 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
379 
380 	if (nvlist_add_uint32(args, FM_FMRI_CPU_ID, cpu_id) != 0) {
381 		nvlist_free(args);
382 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
383 	}
384 
385 	/*
386 	 * Add optional payload
387 	 */
388 	(void) nvlist_add_uint8(args, FM_FMRI_CPU_MASK, cpumask);
389 	(void) nvlist_add_string(args, FM_FMRI_CPU_SERIAL_ID, serial);
390 
391 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_CPU,
392 	    FM_FMRI_SCHEME_CPU, 0, args, &err)) == NULL) {
393 		nvlist_free(args);
394 		return (set_fmri_err(mod, err));
395 	}
396 
397 	nvlist_free(args);
398 
399 	(void) topo_mod_nvdup(mod, fmri, &nfp);
400 	nvlist_free(fmri);
401 
402 	return (nfp);
403 }
404 
405 nvlist_t *
406 topo_mod_memfmri(topo_mod_t *mod, int version, uint64_t pa, uint64_t offset,
407 	const char *unum, int flags)
408 {
409 	int err;
410 	nvlist_t *args = NULL, *fmri = NULL;
411 	nvlist_t *nfp = NULL;
412 
413 	if (version != FM_MEM_SCHEME_VERSION)
414 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
415 
416 	if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
417 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
418 
419 	err = nvlist_add_string(args, FM_FMRI_MEM_UNUM, unum);
420 		nvlist_free(args);
421 	if (flags & TOPO_MEMFMRI_PA)
422 		err |= nvlist_add_uint64(args, FM_FMRI_MEM_PHYSADDR, pa);
423 	if (flags & TOPO_MEMFMRI_OFFSET)
424 		err |= nvlist_add_uint64(args, FM_FMRI_MEM_OFFSET, offset);
425 
426 	if (err != 0) {
427 		nvlist_free(args);
428 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
429 	}
430 
431 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_MEM,
432 	    FM_FMRI_SCHEME_MEM, 0, args, &err)) == NULL) {
433 		nvlist_free(args);
434 		return (set_fmri_err(mod, err));
435 	}
436 
437 	nvlist_free(args);
438 
439 	(void) topo_mod_nvdup(mod, fmri, &nfp);
440 	nvlist_free(fmri);
441 
442 	return (nfp);
443 
444 }
445 
446 nvlist_t *
447 topo_mod_pkgfmri(topo_mod_t *mod, int version, const char *path)
448 {
449 	int err;
450 	nvlist_t *fmri = NULL, *args = NULL;
451 	nvlist_t *nfp = NULL;
452 
453 	if (version != FM_PKG_SCHEME_VERSION)
454 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
455 
456 	if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
457 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
458 
459 	if (nvlist_add_string(args, "path", path) != 0) {
460 		nvlist_free(args);
461 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
462 	}
463 
464 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_CPU,
465 	    FM_FMRI_SCHEME_CPU, 0, args, &err)) == NULL) {
466 		nvlist_free(args);
467 		return (set_fmri_err(mod, err));
468 	}
469 
470 	nvlist_free(args);
471 
472 	(void) topo_mod_nvdup(mod, fmri, &nfp);
473 	nvlist_free(fmri);
474 
475 	return (nfp);
476 }
477 
478 nvlist_t *
479 topo_mod_modfmri(topo_mod_t *mod, int version, const char *driver)
480 {
481 	int err;
482 	nvlist_t *fmri = NULL, *args = NULL;
483 	nvlist_t *nfp = NULL;
484 
485 	if (version != FM_MOD_SCHEME_VERSION)
486 		return (set_fmri_err(mod, EMOD_FMRI_VERSION));
487 
488 	if (topo_mod_nvalloc(mod, &args, NV_UNIQUE_NAME) != 0)
489 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
490 
491 	if (nvlist_add_string(args, "DRIVER", driver) != 0) {
492 		nvlist_free(args);
493 		return (set_fmri_err(mod, EMOD_FMRI_NVL));
494 	}
495 
496 	if ((fmri = topo_fmri_create(mod->tm_hdl, FM_FMRI_SCHEME_CPU,
497 	    FM_FMRI_SCHEME_CPU, 0, args, &err)) == NULL) {
498 		nvlist_free(args);
499 		return (set_fmri_err(mod, err));
500 	}
501 
502 	nvlist_free(args);
503 
504 	(void) topo_mod_nvdup(mod, fmri, &nfp);
505 	nvlist_free(fmri);
506 
507 	return (nfp);
508 }
509 
510 int
511 topo_mod_str2nvl(topo_mod_t *mod, const char *fmristr, nvlist_t **fmri)
512 {
513 	int err;
514 	nvlist_t *np = NULL;
515 
516 	if (topo_fmri_str2nvl(mod->tm_hdl, fmristr, &np, &err) < 0)
517 		return (topo_mod_seterrno(mod, err));
518 
519 	if (topo_mod_nvdup(mod, np, fmri) < 0) {
520 		nvlist_free(np);
521 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
522 	}
523 
524 	nvlist_free(np);
525 
526 	return (0);
527 }
528 
529 int
530 topo_mod_nvl2str(topo_mod_t *mod, nvlist_t *fmri, char **fmristr)
531 {
532 	int err;
533 	char *sp;
534 
535 	if (topo_fmri_nvl2str(mod->tm_hdl, fmri, &sp, &err) < 0)
536 		return (topo_mod_seterrno(mod, err));
537 
538 	if ((*fmristr = topo_mod_strdup(mod, sp)) == NULL) {
539 		topo_hdl_strfree(mod->tm_hdl, sp);
540 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
541 	}
542 
543 	topo_hdl_strfree(mod->tm_hdl, sp);
544 
545 	return (0);
546 }
547 
548 void *
549 topo_mod_getspecific(topo_mod_t *mod)
550 {
551 	return (mod->tm_priv);
552 }
553 
554 void
555 topo_mod_setspecific(topo_mod_t *mod, void *data)
556 {
557 	mod->tm_priv = data;
558 }
559 
560 void
561 topo_mod_setdebug(topo_mod_t *mod)
562 {
563 	mod->tm_debug = 1;
564 }
565 
566 di_node_t
567 topo_mod_devinfo(topo_mod_t *mod)
568 {
569 	topo_hdl_t *thp = mod->tm_hdl;
570 
571 	if (thp->th_di == DI_NODE_NIL)
572 		thp->th_di = di_init("/", DINFOCPYALL);
573 
574 	return (thp->th_di);
575 }
576 
577 di_prom_handle_t
578 topo_mod_prominfo(topo_mod_t *mod)
579 {
580 	topo_hdl_t *thp = mod->tm_hdl;
581 
582 	if (thp->th_pi == DI_PROM_HANDLE_NIL)
583 		thp->th_pi = di_prom_init();
584 
585 	return (thp->th_pi);
586 }
587 
588 void
589 topo_mod_clrdebug(topo_mod_t *mod)
590 {
591 	mod->tm_debug = 0;
592 }
593 
594 /*PRINTFLIKE2*/
595 void
596 topo_mod_dprintf(topo_mod_t *mod, const char *format, ...)
597 {
598 	va_list alist;
599 
600 	if (mod->tm_debug == 0)
601 		return;
602 
603 	va_start(alist, format);
604 	topo_vdprintf(mod->tm_hdl, TOPO_DBG_MOD, (const char *)mod->tm_name,
605 	    format, alist);
606 	va_end(alist);
607 }
608 
609 static char *
610 topo_mod_product(topo_mod_t *mod)
611 {
612 	return (topo_mod_strdup(mod, mod->tm_hdl->th_product));
613 }
614 
615 static char *
616 topo_mod_server(topo_mod_t *mod)
617 {
618 	static struct utsname uts;
619 
620 	(void) uname(&uts);
621 	return (topo_mod_strdup(mod, uts.nodename));
622 }
623 
624 static char *
625 topo_mod_csn(topo_mod_t *mod)
626 {
627 	char csn[MAXNAMELEN];
628 	di_prom_handle_t promh = DI_PROM_HANDLE_NIL;
629 	di_node_t rooth = DI_NODE_NIL;
630 	char *bufp, *str;
631 	smbios_hdl_t *shp;
632 	smbios_system_t s1;
633 	smbios_info_t s2;
634 	id_t id;
635 
636 	if ((shp = smbios_open(NULL, SMB_VERSION, 0, NULL)) != NULL) {
637 		if ((id = smbios_info_system(shp, &s1)) != SMB_ERR &&
638 		    smbios_info_common(shp, id, &s2) != SMB_ERR) {
639 			(void) strlcpy(csn, s2.smbi_serial, MAXNAMELEN);
640 		}
641 		smbios_close(shp);
642 
643 		if (strcmp(csn, SMB_DEFAULT1) == 0 ||
644 		    strcmp(csn, SMB_DEFAULT2) == 0)
645 			return (NULL);
646 
647 		/*
648 		 * Terminate CSN at the first white space
649 		 */
650 		if ((str = strchr(csn, ' ')) != NULL)
651 			*str = '\0';
652 
653 	} else if ((rooth = topo_mod_devinfo(mod)) != DI_NODE_NIL &&
654 	    (promh = topo_mod_prominfo(mod)) != DI_PROM_HANDLE_NIL) {
655 		if (di_prom_prop_lookup_bytes(promh, rooth, "chassis-sn",
656 		    (unsigned char **)&bufp) != -1) {
657 			(void) strlcpy(csn, bufp, MAXNAMELEN);
658 		} else {
659 			return (NULL);
660 		}
661 	} else {
662 		return (NULL);
663 	}
664 
665 	return (topo_mod_strdup(mod, csn));
666 }
667 
668 nvlist_t *
669 topo_mod_auth(topo_mod_t *mod, tnode_t *pnode)
670 {
671 	int err;
672 	char *prod = NULL;
673 	char *csn = NULL;
674 	char *server = NULL;
675 	nvlist_t *auth;
676 
677 	(void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
678 	    FM_FMRI_AUTH_PRODUCT, &prod, &err);
679 	(void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
680 	    FM_FMRI_AUTH_CHASSIS, &csn, &err);
681 	(void) topo_prop_get_string(pnode, FM_FMRI_AUTHORITY,
682 	    FM_FMRI_AUTH_SERVER, &server, &err);
683 
684 	/*
685 	 * Let's do this the hard way
686 	 */
687 	if (prod == NULL)
688 		prod = topo_mod_product(mod);
689 	if (csn == NULL)
690 		csn = topo_mod_csn(mod);
691 	if (server == NULL) {
692 		server = topo_mod_server(mod);
693 	}
694 
695 	/*
696 	 * No luck, return NULL
697 	 */
698 	if (!prod && !server && !csn)
699 		return (NULL);
700 
701 	if ((err = topo_mod_nvalloc(mod, &auth, NV_UNIQUE_NAME)) != 0) {
702 		(void) topo_mod_seterrno(mod, EMOD_FMRI_NVL);
703 		return (NULL);
704 	}
705 
706 	if (prod != NULL) {
707 		err |= nvlist_add_string(auth, FM_FMRI_AUTH_PRODUCT, prod);
708 		topo_mod_strfree(mod, prod);
709 	}
710 	if (server != NULL) {
711 		err |= nvlist_add_string(auth, FM_FMRI_AUTH_SERVER, server);
712 		topo_mod_strfree(mod, server);
713 	}
714 	if (csn != NULL) {
715 		err |= nvlist_add_string(auth, FM_FMRI_AUTH_CHASSIS, csn);
716 		topo_mod_strfree(mod, csn);
717 	}
718 
719 	if (err != 0) {
720 		nvlist_free(auth);
721 		(void) topo_mod_seterrno(mod, EMOD_NVL_INVAL);
722 		return (NULL);
723 	}
724 
725 	return (auth);
726 }
727