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