xref: /onnv-gate/usr/src/uts/sparc/os/cpr_sparc.c (revision 5295:a21f2449e5f9)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
53982Svb70745  * Common Development and Distribution License (the "License").
63982Svb70745  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
223982Svb70745  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * cpr functions for supported sparc platforms
300Sstevel@tonic-gate  */
310Sstevel@tonic-gate #include <sys/types.h>
320Sstevel@tonic-gate #include <sys/systm.h>
330Sstevel@tonic-gate #include <sys/cpr.h>
340Sstevel@tonic-gate #include <sys/kmem.h>
350Sstevel@tonic-gate #include <sys/errno.h>
360Sstevel@tonic-gate 
370Sstevel@tonic-gate /*
380Sstevel@tonic-gate  * new_def_info is used as tmp space to store new values and write them
390Sstevel@tonic-gate  * to nvram.  orig_def_info gets filled with the original nvram values,
400Sstevel@tonic-gate  * gets written to disk, and later used by cprboot to restore the
410Sstevel@tonic-gate  * original nvram values.
420Sstevel@tonic-gate  */
430Sstevel@tonic-gate static cdef_t *new_def_info;
440Sstevel@tonic-gate 
450Sstevel@tonic-gate static cdef_t orig_def_info = {
460Sstevel@tonic-gate 	0, 0,
470Sstevel@tonic-gate 	0, "boot-file",    "",		/* props[0] */
480Sstevel@tonic-gate 	0, "boot-device",  "",		/* props[1] */
490Sstevel@tonic-gate 	0, "auto-boot?",   "",		/* props[2] */
500Sstevel@tonic-gate 	0, "diag-file",    "",		/* props[3] */
510Sstevel@tonic-gate 	0, "diag-device",  "",		/* props[4] */
520Sstevel@tonic-gate };
530Sstevel@tonic-gate 
540Sstevel@tonic-gate /*
550Sstevel@tonic-gate  * since the above array is the only place where cprop_t content
560Sstevel@tonic-gate  * is specified, these defines are provided for quick/direct access.
570Sstevel@tonic-gate  */
580Sstevel@tonic-gate #define	CPR_BF_IDX	0		/* index for boot-file */
590Sstevel@tonic-gate #define	CPR_BD_IDX	1		/* index for boot-device */
600Sstevel@tonic-gate #define	CPR_AB_IDX	2		/* index for auto-boot? */
610Sstevel@tonic-gate #define	CPR_DF_IDX	3		/* index for diag-file */
620Sstevel@tonic-gate #define	CPR_DD_IDX	4		/* index for diag-device */
630Sstevel@tonic-gate 
640Sstevel@tonic-gate #define	CPR_PROP_PTR(dfp, idx)	&(dfp)->props[idx]
650Sstevel@tonic-gate 
660Sstevel@tonic-gate 
670Sstevel@tonic-gate static char *cpr_next_component(char **);
680Sstevel@tonic-gate static char *cpr_get_prefix(char *);
69789Sahrens static char *cpr_build_nodename(pnode_t);
700Sstevel@tonic-gate static void cpr_abbreviate_devpath(char *, char *);
710Sstevel@tonic-gate static int cpr_show_props = 0;
720Sstevel@tonic-gate 
730Sstevel@tonic-gate 
740Sstevel@tonic-gate static int
cpr_get_options_node(pnode_t * nodep)75789Sahrens cpr_get_options_node(pnode_t *nodep)
760Sstevel@tonic-gate {
770Sstevel@tonic-gate 	*nodep = prom_optionsnode();
780Sstevel@tonic-gate 	if (*nodep == OBP_NONODE || *nodep == OBP_BADNODE) {
790Sstevel@tonic-gate 		cpr_err(CE_WARN, "cannot get \"options\" node");
800Sstevel@tonic-gate 		return (ENOENT);
810Sstevel@tonic-gate 	}
820Sstevel@tonic-gate 
830Sstevel@tonic-gate 	return (0);
840Sstevel@tonic-gate }
850Sstevel@tonic-gate 
860Sstevel@tonic-gate 
870Sstevel@tonic-gate /*
880Sstevel@tonic-gate  * returns non-zero on error, otherwise returns 0 and
890Sstevel@tonic-gate  * sets the result code based on (prop value == "true")
900Sstevel@tonic-gate  */
910Sstevel@tonic-gate static int
cpr_get_bool_prop(char * name,int * result)920Sstevel@tonic-gate cpr_get_bool_prop(char *name, int *result)
930Sstevel@tonic-gate {
940Sstevel@tonic-gate 	char value[PROP_BOOL_LEN];
95789Sahrens 	pnode_t node;
960Sstevel@tonic-gate 	int len, err;
970Sstevel@tonic-gate 
980Sstevel@tonic-gate 	if (err = cpr_get_options_node(&node))
990Sstevel@tonic-gate 		return (err);
1000Sstevel@tonic-gate 	len = prom_getproplen(node, name);
1010Sstevel@tonic-gate 	if (len < 0 || len >= sizeof (value))
1020Sstevel@tonic-gate 		return (ENXIO);
1030Sstevel@tonic-gate 	bzero(value, sizeof (value));
1040Sstevel@tonic-gate 	if (prom_getprop(node, name, value) != len)
1050Sstevel@tonic-gate 		return (ENOENT);
1060Sstevel@tonic-gate 	*result = (strcmp(value, "true") == 0);
1070Sstevel@tonic-gate 	return (0);
1080Sstevel@tonic-gate }
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate /*
1120Sstevel@tonic-gate  * write new or original values to nvram
1130Sstevel@tonic-gate  */
1140Sstevel@tonic-gate int
cpr_update_nvram(cprop_t * props)1150Sstevel@tonic-gate cpr_update_nvram(cprop_t *props)
1160Sstevel@tonic-gate {
1170Sstevel@tonic-gate 	cprop_t *tail;
118789Sahrens 	pnode_t node;
1190Sstevel@tonic-gate 	int len, rc;
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 	if (rc = cpr_get_options_node(&node))
1220Sstevel@tonic-gate 		return (rc);
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate 	if (cpr_show_props)
1250Sstevel@tonic-gate 		prom_printf("\ncpr_show_props:\n");
1260Sstevel@tonic-gate 	for (tail = props + CPR_MAXPROP; props < tail; props++) {
1270Sstevel@tonic-gate 		if (cpr_show_props) {
1280Sstevel@tonic-gate 			prom_printf("mod=%c, name \"%s\",\tvalue \"%s\"\n",
1290Sstevel@tonic-gate 			    props->mod, props->name, props->value);
1300Sstevel@tonic-gate 		}
1310Sstevel@tonic-gate 		if (props->mod == PROP_NOMOD)
1320Sstevel@tonic-gate 			continue;
1330Sstevel@tonic-gate 		/*
1340Sstevel@tonic-gate 		 * Note: When doing a prom_setprop you must include the
1350Sstevel@tonic-gate 		 * trailing NULL in the length argument, but when calling
1360Sstevel@tonic-gate 		 * prom_getproplen() the NULL is excluded from the count!
1370Sstevel@tonic-gate 		 */
1380Sstevel@tonic-gate 		len = strlen(props->value);
1390Sstevel@tonic-gate 		rc = prom_setprop(node, props->name, props->value, len + 1);
1400Sstevel@tonic-gate 		if (rc < 0 || prom_getproplen(node, props->name) != len) {
1410Sstevel@tonic-gate 			cpr_err(CE_WARN, "cannot set nvram \"%s\" to \"%s\"",
1420Sstevel@tonic-gate 			    props->name, props->value);
1430Sstevel@tonic-gate 			return (ENXIO);
1440Sstevel@tonic-gate 		}
1450Sstevel@tonic-gate 	}
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 	return (0);
1480Sstevel@tonic-gate }
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate /*
1520Sstevel@tonic-gate  * update nvram with the new or original nvram values;
1530Sstevel@tonic-gate  * this routine provides local access to both sets
1540Sstevel@tonic-gate  */
1550Sstevel@tonic-gate int
cpr_set_properties(int new)1560Sstevel@tonic-gate cpr_set_properties(int new)
1570Sstevel@tonic-gate {
1580Sstevel@tonic-gate 	cprop_t *props;
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 	props = new ? new_def_info->props : orig_def_info.props;
1610Sstevel@tonic-gate 	return (cpr_update_nvram(props));
1620Sstevel@tonic-gate }
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate /*
1670Sstevel@tonic-gate  * update the .mod field in both new_def_info and orig_def_info;
1680Sstevel@tonic-gate  * this tells cpr and cprboot which properties to set/reset.
1690Sstevel@tonic-gate  * then copy the arg str into a new property value at index
1700Sstevel@tonic-gate  */
1710Sstevel@tonic-gate static void
cpr_prop_update(int index,char * str)1720Sstevel@tonic-gate cpr_prop_update(int index, char *str)
1730Sstevel@tonic-gate {
1740Sstevel@tonic-gate 	cprop_t *prop;
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	prop = CPR_PROP_PTR(&orig_def_info, index);
1770Sstevel@tonic-gate 	prop->mod = PROP_MOD;
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 	prop = CPR_PROP_PTR(new_def_info, index);
1800Sstevel@tonic-gate 	prop->mod = PROP_MOD;
1810Sstevel@tonic-gate 	(void) strcpy(prop->value, str);
1820Sstevel@tonic-gate }
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate /*
1860Sstevel@tonic-gate  * setup new property values within new_def_info;
1870Sstevel@tonic-gate  * these are used later to udpate nvram
1880Sstevel@tonic-gate  */
1890Sstevel@tonic-gate static int
cpr_prop_setup(void)1900Sstevel@tonic-gate cpr_prop_setup(void)
1910Sstevel@tonic-gate {
1920Sstevel@tonic-gate 	int len, err, ds_ival, dev_idx, file_idx;
1930Sstevel@tonic-gate 	char bootdev[OBP_MAXPATHLEN], bootfile[OBP_MAXPATHLEN];
1940Sstevel@tonic-gate 	char *cp, *sp;
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate 	/*
1970Sstevel@tonic-gate 	 * create a new boot-device value.  for some older prom revs,
1980Sstevel@tonic-gate 	 * a fully qualified device path can be truncated when stored
1990Sstevel@tonic-gate 	 * to nvram.  this call generates the shortest equivalent.
2000Sstevel@tonic-gate 	 * using devaliases could be simpler in most cases.
2010Sstevel@tonic-gate 	 */
2020Sstevel@tonic-gate 	cpr_abbreviate_devpath(prom_bootpath(), bootdev);
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 	/*
2050Sstevel@tonic-gate 	 * create a new boot-file value; flags get appended when
2063982Svb70745 	 * not reusable and when the statefile is a block device
2070Sstevel@tonic-gate 	 */
2080Sstevel@tonic-gate 	(void) strcpy(bootfile, CPRBOOT);
2093982Svb70745 	if (!cpr_reusable_mode && cpr_statefile_is_spec())
2100Sstevel@tonic-gate 		sp = " -S ";
2110Sstevel@tonic-gate 	else
2120Sstevel@tonic-gate 		sp = NULL;
2130Sstevel@tonic-gate 	if (sp) {
2140Sstevel@tonic-gate 		(void) strcat(bootfile, sp);
2150Sstevel@tonic-gate 		len = strlen(bootfile);
2160Sstevel@tonic-gate 		sp = cpr_get_statefile_prom_path();
2170Sstevel@tonic-gate 		cpr_abbreviate_devpath(sp, &bootfile[len]);
2180Sstevel@tonic-gate 	}
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 	/*
2210Sstevel@tonic-gate 	 * record property info for booting with cprboot based on
2220Sstevel@tonic-gate 	 * the value of diag-switch?.  when "false", set boot-device
2230Sstevel@tonic-gate 	 * and boot-file; when "true", set diag-device and diag-file
2240Sstevel@tonic-gate 	 */
2250Sstevel@tonic-gate 	if (err = cpr_get_bool_prop("diag-switch?", &ds_ival))
2260Sstevel@tonic-gate 		return (err);
2270Sstevel@tonic-gate 	else if (ds_ival == 0) {
2280Sstevel@tonic-gate 		dev_idx  = CPR_BD_IDX;
2290Sstevel@tonic-gate 		file_idx = CPR_BF_IDX;
2300Sstevel@tonic-gate 	} else {
2310Sstevel@tonic-gate 		dev_idx  = CPR_DD_IDX;
2320Sstevel@tonic-gate 		file_idx = CPR_DF_IDX;
2330Sstevel@tonic-gate 	}
2340Sstevel@tonic-gate 	cpr_prop_update(dev_idx,  bootdev);
2353982Svb70745 
2363982Svb70745 	if (!cpr_reusable_mode)
2373982Svb70745 		cpr_prop_update(file_idx, bootfile);
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 	/*
2400Sstevel@tonic-gate 	 * check/set auto-boot?
2410Sstevel@tonic-gate 	 */
2420Sstevel@tonic-gate 	sp = orig_def_info.props[CPR_AB_IDX].value;
2430Sstevel@tonic-gate 	cp = "true";
2440Sstevel@tonic-gate 	if (strcmp(sp, cp))
2450Sstevel@tonic-gate 		cpr_prop_update(CPR_AB_IDX, cp);
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate 	return (0);
2480Sstevel@tonic-gate }
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate /*
2520Sstevel@tonic-gate  * setup the original and new sets of property names/values
2530Sstevel@tonic-gate  */
2540Sstevel@tonic-gate int
cpr_default_setup(int alloc)2550Sstevel@tonic-gate cpr_default_setup(int alloc)
2560Sstevel@tonic-gate {
2570Sstevel@tonic-gate 	cprop_t *orig, *new, *tail;
2580Sstevel@tonic-gate 	int len, err = 0;
259789Sahrens 	pnode_t node;
2600Sstevel@tonic-gate 	char *fmt;
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 	if (alloc == 0) {
2630Sstevel@tonic-gate 		ASSERT(new_def_info);
2640Sstevel@tonic-gate 		kmem_free(new_def_info, sizeof (*new_def_info));
2650Sstevel@tonic-gate 		new_def_info = NULL;
2660Sstevel@tonic-gate 		return (0);
2670Sstevel@tonic-gate 	}
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 	if (err = cpr_get_options_node(&node))
2700Sstevel@tonic-gate 		return (err);
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 	/*
2730Sstevel@tonic-gate 	 * allocate space for new properties, get the original nvram
2740Sstevel@tonic-gate 	 * property values, mark both property sets with PROP_NOMOD,
2750Sstevel@tonic-gate 	 * and copy the original prop names to the new set.
2760Sstevel@tonic-gate 	 */
2770Sstevel@tonic-gate 	ASSERT(new_def_info == NULL);
2780Sstevel@tonic-gate 	new_def_info = kmem_zalloc(sizeof (*new_def_info), KM_SLEEP);
2790Sstevel@tonic-gate 	new = new_def_info->props;
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate 	for (orig = orig_def_info.props, tail = orig + CPR_MAXPROP;
2820Sstevel@tonic-gate 	    orig < tail; orig++, new++) {
2830Sstevel@tonic-gate 		len = prom_getproplen(node, orig->name);
2840Sstevel@tonic-gate 		if (len < 0 || len >= (int)sizeof (orig->value)) {
2850Sstevel@tonic-gate 			fmt = "invalid property or length for \"%s\"";
2860Sstevel@tonic-gate 			err = ENXIO;
2870Sstevel@tonic-gate 			break;
2880Sstevel@tonic-gate 		}
2890Sstevel@tonic-gate 		bzero(orig->value, sizeof (orig->value));
2900Sstevel@tonic-gate 		if (prom_getprop(node, orig->name, orig->value) < 0) {
2910Sstevel@tonic-gate 			fmt = "cannot get \"%s\" value";
2920Sstevel@tonic-gate 			err = ENXIO;
2930Sstevel@tonic-gate 			break;
2940Sstevel@tonic-gate 		}
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 		new->mod = orig->mod = PROP_NOMOD;
2970Sstevel@tonic-gate 		(void) strcpy(new->name, orig->name);
2980Sstevel@tonic-gate 	}
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate 	if (err) {
3010Sstevel@tonic-gate 		kmem_free(new_def_info, sizeof (*new_def_info));
3020Sstevel@tonic-gate 		new_def_info = NULL;
3030Sstevel@tonic-gate 		cpr_err(CE_WARN, fmt, orig->name);
3040Sstevel@tonic-gate 	} else
3050Sstevel@tonic-gate 		err = cpr_prop_setup();
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 	return (err);
3080Sstevel@tonic-gate }
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate int
cpr_validate_definfo(int reusable)3120Sstevel@tonic-gate cpr_validate_definfo(int reusable)
3130Sstevel@tonic-gate {
3140Sstevel@tonic-gate 	orig_def_info.mini.magic = CPR->c_cprboot_magic = CPR_DEFAULT_MAGIC;
3150Sstevel@tonic-gate 	orig_def_info.mini.reusable = reusable;
3160Sstevel@tonic-gate 	return (cpr_write_deffile(&orig_def_info));
3170Sstevel@tonic-gate }
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate void
cpr_send_notice(void)3210Sstevel@tonic-gate cpr_send_notice(void)
3220Sstevel@tonic-gate {
3230Sstevel@tonic-gate 	static char cstr[] = "\014" "\033[1P" "\033[18;21H";
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 	prom_printf(cstr);
3260Sstevel@tonic-gate 	prom_printf("Saving System State. Please Wait... ");
3270Sstevel@tonic-gate }
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate void
cpr_spinning_bar(void)3300Sstevel@tonic-gate cpr_spinning_bar(void)
3310Sstevel@tonic-gate {
3320Sstevel@tonic-gate 	static char *spin_strings[] = { "|\b", "/\b", "-\b", "\\\b" };
3330Sstevel@tonic-gate 	static int idx;
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 	prom_printf(spin_strings[idx]);
3360Sstevel@tonic-gate 	if (++idx == 4)
3370Sstevel@tonic-gate 		idx = 0;
3380Sstevel@tonic-gate }
3390Sstevel@tonic-gate 
340*5295Srandyf void
cpr_resume_notice(void)341*5295Srandyf cpr_resume_notice(void)
342*5295Srandyf {
343*5295Srandyf 	static char cstr[] = "\014" "\033[1P" "\033[18;21H";
344*5295Srandyf 
345*5295Srandyf 	prom_printf(cstr);
346*5295Srandyf 	prom_printf("Restoring System State. Please Wait... ");
347*5295Srandyf }
348*5295Srandyf 
3490Sstevel@tonic-gate /*
3500Sstevel@tonic-gate  * Convert a full device path to its shortest unambiguous equivalent.
3510Sstevel@tonic-gate  * For example, a path which starts out /iommu@x,y/sbus@i,j/espdma . . .
3520Sstevel@tonic-gate  * might be converted to /iommu/sbus/espdma . . .  If we encounter
3530Sstevel@tonic-gate  * problems at any point, just output the unabbreviated path.
3540Sstevel@tonic-gate  */
3550Sstevel@tonic-gate static void
cpr_abbreviate_devpath(char * in_path,char * out_path)3560Sstevel@tonic-gate cpr_abbreviate_devpath(char *in_path, char *out_path)
3570Sstevel@tonic-gate {
358789Sahrens 	static pnode_t cur_node;
3590Sstevel@tonic-gate 	char *position = in_path + 1;	/* Skip the leading slash. */
3600Sstevel@tonic-gate 	char *cmpt;
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	cur_node = prom_nextnode(0);
3630Sstevel@tonic-gate 	*out_path = '\0';
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 	while ((cmpt = cpr_next_component(&position)) != NULL) {
366789Sahrens 		pnode_t long_match = NULL;
367789Sahrens 		pnode_t short_match = NULL;
3680Sstevel@tonic-gate 		int short_hits = 0;
3690Sstevel@tonic-gate 		char *name;
3700Sstevel@tonic-gate 		char *prefix = cpr_get_prefix(cmpt);
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 		/* Go to next tree level by getting first child. */
3730Sstevel@tonic-gate 		if ((cur_node = prom_childnode(cur_node)) == 0) {
3740Sstevel@tonic-gate 			(void) strcpy(out_path, in_path);
3750Sstevel@tonic-gate 			return;
3760Sstevel@tonic-gate 		}
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 		/*
3790Sstevel@tonic-gate 		 * Traverse the current level and remember the node (if any)
3800Sstevel@tonic-gate 		 * where we match on the fully qualified component name.
3810Sstevel@tonic-gate 		 * Also remember the node of the most recent prefix match
3820Sstevel@tonic-gate 		 * and the number of such matches.
3830Sstevel@tonic-gate 		 */
3840Sstevel@tonic-gate 		do {
3850Sstevel@tonic-gate 			name = cpr_build_nodename(cur_node);
3860Sstevel@tonic-gate 			if (strcmp(name, cmpt) == 0)
3870Sstevel@tonic-gate 				long_match = cur_node;
3880Sstevel@tonic-gate 			if (strncmp(prefix, name, strlen(prefix)) == 0) {
3890Sstevel@tonic-gate 				short_match = cur_node;
3900Sstevel@tonic-gate 				short_hits++;
3910Sstevel@tonic-gate 			}
3920Sstevel@tonic-gate 		} while ((cur_node = prom_nextnode(cur_node)) != 0);
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 		/*
3950Sstevel@tonic-gate 		 * We don't want to be too dependent on what we know
3960Sstevel@tonic-gate 		 * about how the names are stored.  We just assume that
3970Sstevel@tonic-gate 		 * if there is only one match on the prefix, we can
3980Sstevel@tonic-gate 		 * use it, otherwise we need to use a fully qualified
3990Sstevel@tonic-gate 		 * name.  In the "impossible" cases we just give up
4000Sstevel@tonic-gate 		 * and use the complete input devpath.
4010Sstevel@tonic-gate 		 */
4020Sstevel@tonic-gate 		(void) strcat(out_path, "/");
4030Sstevel@tonic-gate 		if (short_hits == 1) {
4040Sstevel@tonic-gate 			(void) strcat(out_path, prefix);
4050Sstevel@tonic-gate 			cur_node = short_match;
4060Sstevel@tonic-gate 		}
4070Sstevel@tonic-gate 		else
4080Sstevel@tonic-gate 			if (long_match) {
4090Sstevel@tonic-gate 				(void) strcat(out_path, cmpt);
4100Sstevel@tonic-gate 				cur_node = long_match;
4110Sstevel@tonic-gate 			} else {
4120Sstevel@tonic-gate 				(void) strcpy(out_path, in_path);
4130Sstevel@tonic-gate 				return;
4140Sstevel@tonic-gate 			}
4150Sstevel@tonic-gate 	}
4160Sstevel@tonic-gate 	/* We need to copy the target and slice info manually. */
4170Sstevel@tonic-gate 	(void) strcat(out_path, strrchr(in_path, '@'));
4180Sstevel@tonic-gate }
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate /*
4210Sstevel@tonic-gate  * Return a pointer to the next component of a device path or NULL if
4220Sstevel@tonic-gate  * the entire path has been consumed.  Note that we update the caller's
4230Sstevel@tonic-gate  * pointer to the current position in the full pathname buffer.
4240Sstevel@tonic-gate  */
4250Sstevel@tonic-gate static char *
cpr_next_component(char ** path)4260Sstevel@tonic-gate cpr_next_component(char **path)
4270Sstevel@tonic-gate {
4280Sstevel@tonic-gate 	static char obuf[64];
4290Sstevel@tonic-gate 	char *slash;
4300Sstevel@tonic-gate 	int len = strlen(*path);
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 	if (len == 0)
4330Sstevel@tonic-gate 		return (NULL);
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	if ((slash = strchr(*path, '/'))) {
4360Sstevel@tonic-gate 		len = slash - *path;
4370Sstevel@tonic-gate 		(void) strncpy(obuf, *path, len);
4380Sstevel@tonic-gate 		obuf[len] = '\0';
4390Sstevel@tonic-gate 		*path += len + 1;	/* Position beyond the slash. */
4400Sstevel@tonic-gate 	} else {
4410Sstevel@tonic-gate 		(void) strcpy(obuf, *path);
4420Sstevel@tonic-gate 		*path += len;		/* Position at the terminal NULL. */
4430Sstevel@tonic-gate 	}
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 	return (obuf);
4460Sstevel@tonic-gate }
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate /*
4490Sstevel@tonic-gate  * Return a pointer to the prefix (i.e., the basic unqualified node name)
4500Sstevel@tonic-gate  * Basically, this is the part of the fully qualified name before the @.
4510Sstevel@tonic-gate  */
4520Sstevel@tonic-gate static char *
cpr_get_prefix(char * cmpt)4530Sstevel@tonic-gate cpr_get_prefix(char *cmpt)
4540Sstevel@tonic-gate {
4550Sstevel@tonic-gate 	static char	prefix[OBP_MAXDRVNAME];
4560Sstevel@tonic-gate 	char		*at_sign = strchr(cmpt, '@');
4570Sstevel@tonic-gate 	int		len = at_sign ? at_sign - cmpt : strlen(cmpt);
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 	(void) strncpy(prefix, cmpt, len);
4600Sstevel@tonic-gate 	prefix[len] = '\0';
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 	return (prefix);
4630Sstevel@tonic-gate }
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate /*
4660Sstevel@tonic-gate  * Build the unambiguous name for the current node, like iommu@f,e10000000.
4670Sstevel@tonic-gate  * The prefix is just the "name" property, and the qualifier is constructed
4680Sstevel@tonic-gate  * from the first two (binary) words of the "reg" property.
4690Sstevel@tonic-gate  */
4700Sstevel@tonic-gate static char *
cpr_build_nodename(pnode_t node)471789Sahrens cpr_build_nodename(pnode_t node)
4720Sstevel@tonic-gate {
4730Sstevel@tonic-gate 	static char	name[OBP_MAXPATHLEN];
4740Sstevel@tonic-gate 	int		reg[512];
4750Sstevel@tonic-gate 	char		buf[32]; /* must contain expansion of @%x,%x */
4760Sstevel@tonic-gate 	int		prop_len = prom_getproplen(node, OBP_NAME);
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 	if (prop_len < 0 || prop_len >= sizeof (name) ||
4790Sstevel@tonic-gate 	    prom_getprop(node, OBP_NAME, name) < 0)
4800Sstevel@tonic-gate 		return ("");
4810Sstevel@tonic-gate 	name[prop_len] = '\0';
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate 	if ((prop_len = prom_getproplen(node, OBP_REG)) <
4840Sstevel@tonic-gate 	    2 * sizeof (int) || prop_len >= sizeof (reg))
4850Sstevel@tonic-gate 		return (name);
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 	if (prom_getprop(node, OBP_REG, (caddr_t)reg) < 0)
4880Sstevel@tonic-gate 		return (name);
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 	(void) sprintf(buf, "@%x,%x", reg[0], reg[1]);
4910Sstevel@tonic-gate 	(void) strcat(name, buf);
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 	return (name);
4940Sstevel@tonic-gate }
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate /*
4970Sstevel@tonic-gate  * Makes a printable list of prom_prop names for error messages
4980Sstevel@tonic-gate  * Caller must free space.
4990Sstevel@tonic-gate  */
5000Sstevel@tonic-gate char *
cpr_enumerate_promprops(char ** bufp,size_t * len)5010Sstevel@tonic-gate cpr_enumerate_promprops(char **bufp, size_t *len)
5020Sstevel@tonic-gate {
5030Sstevel@tonic-gate 	cprop_t *prop, *tail;
5040Sstevel@tonic-gate 	size_t size = 2;	/* for "." */
5050Sstevel@tonic-gate 	char *buf;
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 	tail = &orig_def_info.props[CPR_MAXPROP];
5080Sstevel@tonic-gate 	for (prop = orig_def_info.props; prop < tail; prop++)
5090Sstevel@tonic-gate 		size += strlen(prop->name) + 2;	/* + ", " */
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate 	buf = kmem_alloc(size, KM_SLEEP);
5120Sstevel@tonic-gate 	*buf = '\0';
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate 	for (prop = orig_def_info.props; prop < tail; prop++) {
5150Sstevel@tonic-gate 		if (strlen(buf))
5160Sstevel@tonic-gate 			(void) strcat(buf, ", ");
5170Sstevel@tonic-gate 		(void) strcat(buf, prop->name);
5180Sstevel@tonic-gate 	}
5190Sstevel@tonic-gate 	(void) strcat(buf, ".");
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 	*bufp = buf;
5220Sstevel@tonic-gate 	*len = size;
5230Sstevel@tonic-gate 	return (buf);
5240Sstevel@tonic-gate }
525