xref: /titanic_51/usr/src/uts/sparc/os/cpr_sparc.c (revision 2df1fe9ca32bb227b9158c67f5c00b54c20b10fd)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5ecb24f52Svb70745  * Common Development and Distribution License (the "License").
6ecb24f52Svb70745  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22ecb24f52Svb70745  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * cpr functions for supported sparc platforms
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate #include <sys/types.h>
327c478bd9Sstevel@tonic-gate #include <sys/systm.h>
337c478bd9Sstevel@tonic-gate #include <sys/cpr.h>
347c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
357c478bd9Sstevel@tonic-gate #include <sys/errno.h>
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate /*
387c478bd9Sstevel@tonic-gate  * new_def_info is used as tmp space to store new values and write them
397c478bd9Sstevel@tonic-gate  * to nvram.  orig_def_info gets filled with the original nvram values,
407c478bd9Sstevel@tonic-gate  * gets written to disk, and later used by cprboot to restore the
417c478bd9Sstevel@tonic-gate  * original nvram values.
427c478bd9Sstevel@tonic-gate  */
437c478bd9Sstevel@tonic-gate static cdef_t *new_def_info;
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate static cdef_t orig_def_info = {
467c478bd9Sstevel@tonic-gate 	0, 0,
477c478bd9Sstevel@tonic-gate 	0, "boot-file",    "",		/* props[0] */
487c478bd9Sstevel@tonic-gate 	0, "boot-device",  "",		/* props[1] */
497c478bd9Sstevel@tonic-gate 	0, "auto-boot?",   "",		/* props[2] */
507c478bd9Sstevel@tonic-gate 	0, "diag-file",    "",		/* props[3] */
517c478bd9Sstevel@tonic-gate 	0, "diag-device",  "",		/* props[4] */
527c478bd9Sstevel@tonic-gate };
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate /*
557c478bd9Sstevel@tonic-gate  * since the above array is the only place where cprop_t content
567c478bd9Sstevel@tonic-gate  * is specified, these defines are provided for quick/direct access.
577c478bd9Sstevel@tonic-gate  */
587c478bd9Sstevel@tonic-gate #define	CPR_BF_IDX	0		/* index for boot-file */
597c478bd9Sstevel@tonic-gate #define	CPR_BD_IDX	1		/* index for boot-device */
607c478bd9Sstevel@tonic-gate #define	CPR_AB_IDX	2		/* index for auto-boot? */
617c478bd9Sstevel@tonic-gate #define	CPR_DF_IDX	3		/* index for diag-file */
627c478bd9Sstevel@tonic-gate #define	CPR_DD_IDX	4		/* index for diag-device */
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate #define	CPR_PROP_PTR(dfp, idx)	&(dfp)->props[idx]
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate static char *cpr_next_component(char **);
687c478bd9Sstevel@tonic-gate static char *cpr_get_prefix(char *);
69fa9e4066Sahrens static char *cpr_build_nodename(pnode_t);
707c478bd9Sstevel@tonic-gate static void cpr_abbreviate_devpath(char *, char *);
717c478bd9Sstevel@tonic-gate static int cpr_show_props = 0;
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate static int
75fa9e4066Sahrens cpr_get_options_node(pnode_t *nodep)
767c478bd9Sstevel@tonic-gate {
777c478bd9Sstevel@tonic-gate 	*nodep = prom_optionsnode();
787c478bd9Sstevel@tonic-gate 	if (*nodep == OBP_NONODE || *nodep == OBP_BADNODE) {
797c478bd9Sstevel@tonic-gate 		cpr_err(CE_WARN, "cannot get \"options\" node");
807c478bd9Sstevel@tonic-gate 		return (ENOENT);
817c478bd9Sstevel@tonic-gate 	}
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate 	return (0);
847c478bd9Sstevel@tonic-gate }
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate /*
887c478bd9Sstevel@tonic-gate  * returns non-zero on error, otherwise returns 0 and
897c478bd9Sstevel@tonic-gate  * sets the result code based on (prop value == "true")
907c478bd9Sstevel@tonic-gate  */
917c478bd9Sstevel@tonic-gate static int
927c478bd9Sstevel@tonic-gate cpr_get_bool_prop(char *name, int *result)
937c478bd9Sstevel@tonic-gate {
947c478bd9Sstevel@tonic-gate 	char value[PROP_BOOL_LEN];
95fa9e4066Sahrens 	pnode_t node;
967c478bd9Sstevel@tonic-gate 	int len, err;
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 	if (err = cpr_get_options_node(&node))
997c478bd9Sstevel@tonic-gate 		return (err);
1007c478bd9Sstevel@tonic-gate 	len = prom_getproplen(node, name);
1017c478bd9Sstevel@tonic-gate 	if (len < 0 || len >= sizeof (value))
1027c478bd9Sstevel@tonic-gate 		return (ENXIO);
1037c478bd9Sstevel@tonic-gate 	bzero(value, sizeof (value));
1047c478bd9Sstevel@tonic-gate 	if (prom_getprop(node, name, value) != len)
1057c478bd9Sstevel@tonic-gate 		return (ENOENT);
1067c478bd9Sstevel@tonic-gate 	*result = (strcmp(value, "true") == 0);
1077c478bd9Sstevel@tonic-gate 	return (0);
1087c478bd9Sstevel@tonic-gate }
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate /*
1127c478bd9Sstevel@tonic-gate  * write new or original values to nvram
1137c478bd9Sstevel@tonic-gate  */
1147c478bd9Sstevel@tonic-gate int
1157c478bd9Sstevel@tonic-gate cpr_update_nvram(cprop_t *props)
1167c478bd9Sstevel@tonic-gate {
1177c478bd9Sstevel@tonic-gate 	cprop_t *tail;
118fa9e4066Sahrens 	pnode_t node;
1197c478bd9Sstevel@tonic-gate 	int len, rc;
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate 	if (rc = cpr_get_options_node(&node))
1227c478bd9Sstevel@tonic-gate 		return (rc);
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 	if (cpr_show_props)
1257c478bd9Sstevel@tonic-gate 		prom_printf("\ncpr_show_props:\n");
1267c478bd9Sstevel@tonic-gate 	for (tail = props + CPR_MAXPROP; props < tail; props++) {
1277c478bd9Sstevel@tonic-gate 		if (cpr_show_props) {
1287c478bd9Sstevel@tonic-gate 			prom_printf("mod=%c, name \"%s\",\tvalue \"%s\"\n",
1297c478bd9Sstevel@tonic-gate 			    props->mod, props->name, props->value);
1307c478bd9Sstevel@tonic-gate 		}
1317c478bd9Sstevel@tonic-gate 		if (props->mod == PROP_NOMOD)
1327c478bd9Sstevel@tonic-gate 			continue;
1337c478bd9Sstevel@tonic-gate 		/*
1347c478bd9Sstevel@tonic-gate 		 * Note: When doing a prom_setprop you must include the
1357c478bd9Sstevel@tonic-gate 		 * trailing NULL in the length argument, but when calling
1367c478bd9Sstevel@tonic-gate 		 * prom_getproplen() the NULL is excluded from the count!
1377c478bd9Sstevel@tonic-gate 		 */
1387c478bd9Sstevel@tonic-gate 		len = strlen(props->value);
1397c478bd9Sstevel@tonic-gate 		rc = prom_setprop(node, props->name, props->value, len + 1);
1407c478bd9Sstevel@tonic-gate 		if (rc < 0 || prom_getproplen(node, props->name) != len) {
1417c478bd9Sstevel@tonic-gate 			cpr_err(CE_WARN, "cannot set nvram \"%s\" to \"%s\"",
1427c478bd9Sstevel@tonic-gate 			    props->name, props->value);
1437c478bd9Sstevel@tonic-gate 			return (ENXIO);
1447c478bd9Sstevel@tonic-gate 		}
1457c478bd9Sstevel@tonic-gate 	}
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate 	return (0);
1487c478bd9Sstevel@tonic-gate }
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate /*
1527c478bd9Sstevel@tonic-gate  * update nvram with the new or original nvram values;
1537c478bd9Sstevel@tonic-gate  * this routine provides local access to both sets
1547c478bd9Sstevel@tonic-gate  */
1557c478bd9Sstevel@tonic-gate int
1567c478bd9Sstevel@tonic-gate cpr_set_properties(int new)
1577c478bd9Sstevel@tonic-gate {
1587c478bd9Sstevel@tonic-gate 	cprop_t *props;
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 	props = new ? new_def_info->props : orig_def_info.props;
1617c478bd9Sstevel@tonic-gate 	return (cpr_update_nvram(props));
1627c478bd9Sstevel@tonic-gate }
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate /*
1677c478bd9Sstevel@tonic-gate  * update the .mod field in both new_def_info and orig_def_info;
1687c478bd9Sstevel@tonic-gate  * this tells cpr and cprboot which properties to set/reset.
1697c478bd9Sstevel@tonic-gate  * then copy the arg str into a new property value at index
1707c478bd9Sstevel@tonic-gate  */
1717c478bd9Sstevel@tonic-gate static void
1727c478bd9Sstevel@tonic-gate cpr_prop_update(int index, char *str)
1737c478bd9Sstevel@tonic-gate {
1747c478bd9Sstevel@tonic-gate 	cprop_t *prop;
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	prop = CPR_PROP_PTR(&orig_def_info, index);
1777c478bd9Sstevel@tonic-gate 	prop->mod = PROP_MOD;
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 	prop = CPR_PROP_PTR(new_def_info, index);
1807c478bd9Sstevel@tonic-gate 	prop->mod = PROP_MOD;
1817c478bd9Sstevel@tonic-gate 	(void) strcpy(prop->value, str);
1827c478bd9Sstevel@tonic-gate }
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate /*
1867c478bd9Sstevel@tonic-gate  * setup new property values within new_def_info;
1877c478bd9Sstevel@tonic-gate  * these are used later to udpate nvram
1887c478bd9Sstevel@tonic-gate  */
1897c478bd9Sstevel@tonic-gate static int
1907c478bd9Sstevel@tonic-gate cpr_prop_setup(void)
1917c478bd9Sstevel@tonic-gate {
1927c478bd9Sstevel@tonic-gate 	int len, err, ds_ival, dev_idx, file_idx;
1937c478bd9Sstevel@tonic-gate 	char bootdev[OBP_MAXPATHLEN], bootfile[OBP_MAXPATHLEN];
1947c478bd9Sstevel@tonic-gate 	char *cp, *sp;
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 	/*
1977c478bd9Sstevel@tonic-gate 	 * create a new boot-device value.  for some older prom revs,
1987c478bd9Sstevel@tonic-gate 	 * a fully qualified device path can be truncated when stored
1997c478bd9Sstevel@tonic-gate 	 * to nvram.  this call generates the shortest equivalent.
2007c478bd9Sstevel@tonic-gate 	 * using devaliases could be simpler in most cases.
2017c478bd9Sstevel@tonic-gate 	 */
2027c478bd9Sstevel@tonic-gate 	cpr_abbreviate_devpath(prom_bootpath(), bootdev);
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	/*
2057c478bd9Sstevel@tonic-gate 	 * create a new boot-file value; flags get appended when
206ecb24f52Svb70745 	 * not reusable and when the statefile is a block device
2077c478bd9Sstevel@tonic-gate 	 */
2087c478bd9Sstevel@tonic-gate 	(void) strcpy(bootfile, CPRBOOT);
209ecb24f52Svb70745 	if (!cpr_reusable_mode && cpr_statefile_is_spec())
2107c478bd9Sstevel@tonic-gate 		sp = " -S ";
2117c478bd9Sstevel@tonic-gate 	else
2127c478bd9Sstevel@tonic-gate 		sp = NULL;
2137c478bd9Sstevel@tonic-gate 	if (sp) {
2147c478bd9Sstevel@tonic-gate 		(void) strcat(bootfile, sp);
2157c478bd9Sstevel@tonic-gate 		len = strlen(bootfile);
2167c478bd9Sstevel@tonic-gate 		sp = cpr_get_statefile_prom_path();
2177c478bd9Sstevel@tonic-gate 		cpr_abbreviate_devpath(sp, &bootfile[len]);
2187c478bd9Sstevel@tonic-gate 	}
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 	/*
2217c478bd9Sstevel@tonic-gate 	 * record property info for booting with cprboot based on
2227c478bd9Sstevel@tonic-gate 	 * the value of diag-switch?.  when "false", set boot-device
2237c478bd9Sstevel@tonic-gate 	 * and boot-file; when "true", set diag-device and diag-file
2247c478bd9Sstevel@tonic-gate 	 */
2257c478bd9Sstevel@tonic-gate 	if (err = cpr_get_bool_prop("diag-switch?", &ds_ival))
2267c478bd9Sstevel@tonic-gate 		return (err);
2277c478bd9Sstevel@tonic-gate 	else if (ds_ival == 0) {
2287c478bd9Sstevel@tonic-gate 		dev_idx  = CPR_BD_IDX;
2297c478bd9Sstevel@tonic-gate 		file_idx = CPR_BF_IDX;
2307c478bd9Sstevel@tonic-gate 	} else {
2317c478bd9Sstevel@tonic-gate 		dev_idx  = CPR_DD_IDX;
2327c478bd9Sstevel@tonic-gate 		file_idx = CPR_DF_IDX;
2337c478bd9Sstevel@tonic-gate 	}
2347c478bd9Sstevel@tonic-gate 	cpr_prop_update(dev_idx,  bootdev);
235ecb24f52Svb70745 
236ecb24f52Svb70745 	if (!cpr_reusable_mode)
2377c478bd9Sstevel@tonic-gate 		cpr_prop_update(file_idx, bootfile);
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 	/*
2407c478bd9Sstevel@tonic-gate 	 * check/set auto-boot?
2417c478bd9Sstevel@tonic-gate 	 */
2427c478bd9Sstevel@tonic-gate 	sp = orig_def_info.props[CPR_AB_IDX].value;
2437c478bd9Sstevel@tonic-gate 	cp = "true";
2447c478bd9Sstevel@tonic-gate 	if (strcmp(sp, cp))
2457c478bd9Sstevel@tonic-gate 		cpr_prop_update(CPR_AB_IDX, cp);
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 	return (0);
2487c478bd9Sstevel@tonic-gate }
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate /*
2527c478bd9Sstevel@tonic-gate  * setup the original and new sets of property names/values
2537c478bd9Sstevel@tonic-gate  */
2547c478bd9Sstevel@tonic-gate int
2557c478bd9Sstevel@tonic-gate cpr_default_setup(int alloc)
2567c478bd9Sstevel@tonic-gate {
2577c478bd9Sstevel@tonic-gate 	cprop_t *orig, *new, *tail;
2587c478bd9Sstevel@tonic-gate 	int len, err = 0;
259fa9e4066Sahrens 	pnode_t node;
2607c478bd9Sstevel@tonic-gate 	char *fmt;
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 	if (alloc == 0) {
2637c478bd9Sstevel@tonic-gate 		ASSERT(new_def_info);
2647c478bd9Sstevel@tonic-gate 		kmem_free(new_def_info, sizeof (*new_def_info));
2657c478bd9Sstevel@tonic-gate 		new_def_info = NULL;
2667c478bd9Sstevel@tonic-gate 		return (0);
2677c478bd9Sstevel@tonic-gate 	}
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 	if (err = cpr_get_options_node(&node))
2707c478bd9Sstevel@tonic-gate 		return (err);
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	/*
2737c478bd9Sstevel@tonic-gate 	 * allocate space for new properties, get the original nvram
2747c478bd9Sstevel@tonic-gate 	 * property values, mark both property sets with PROP_NOMOD,
2757c478bd9Sstevel@tonic-gate 	 * and copy the original prop names to the new set.
2767c478bd9Sstevel@tonic-gate 	 */
2777c478bd9Sstevel@tonic-gate 	ASSERT(new_def_info == NULL);
2787c478bd9Sstevel@tonic-gate 	new_def_info = kmem_zalloc(sizeof (*new_def_info), KM_SLEEP);
2797c478bd9Sstevel@tonic-gate 	new = new_def_info->props;
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	for (orig = orig_def_info.props, tail = orig + CPR_MAXPROP;
2827c478bd9Sstevel@tonic-gate 	    orig < tail; orig++, new++) {
2837c478bd9Sstevel@tonic-gate 		len = prom_getproplen(node, orig->name);
2847c478bd9Sstevel@tonic-gate 		if (len < 0 || len >= (int)sizeof (orig->value)) {
2857c478bd9Sstevel@tonic-gate 			fmt = "invalid property or length for \"%s\"";
2867c478bd9Sstevel@tonic-gate 			err = ENXIO;
2877c478bd9Sstevel@tonic-gate 			break;
2887c478bd9Sstevel@tonic-gate 		}
2897c478bd9Sstevel@tonic-gate 		bzero(orig->value, sizeof (orig->value));
2907c478bd9Sstevel@tonic-gate 		if (prom_getprop(node, orig->name, orig->value) < 0) {
2917c478bd9Sstevel@tonic-gate 			fmt = "cannot get \"%s\" value";
2927c478bd9Sstevel@tonic-gate 			err = ENXIO;
2937c478bd9Sstevel@tonic-gate 			break;
2947c478bd9Sstevel@tonic-gate 		}
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 		new->mod = orig->mod = PROP_NOMOD;
2977c478bd9Sstevel@tonic-gate 		(void) strcpy(new->name, orig->name);
2987c478bd9Sstevel@tonic-gate 	}
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 	if (err) {
3017c478bd9Sstevel@tonic-gate 		kmem_free(new_def_info, sizeof (*new_def_info));
3027c478bd9Sstevel@tonic-gate 		new_def_info = NULL;
3037c478bd9Sstevel@tonic-gate 		cpr_err(CE_WARN, fmt, orig->name);
3047c478bd9Sstevel@tonic-gate 	} else
3057c478bd9Sstevel@tonic-gate 		err = cpr_prop_setup();
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	return (err);
3087c478bd9Sstevel@tonic-gate }
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate int
3127c478bd9Sstevel@tonic-gate cpr_validate_definfo(int reusable)
3137c478bd9Sstevel@tonic-gate {
3147c478bd9Sstevel@tonic-gate 	orig_def_info.mini.magic = CPR->c_cprboot_magic = CPR_DEFAULT_MAGIC;
3157c478bd9Sstevel@tonic-gate 	orig_def_info.mini.reusable = reusable;
3167c478bd9Sstevel@tonic-gate 	return (cpr_write_deffile(&orig_def_info));
3177c478bd9Sstevel@tonic-gate }
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate void
3217c478bd9Sstevel@tonic-gate cpr_send_notice(void)
3227c478bd9Sstevel@tonic-gate {
3237c478bd9Sstevel@tonic-gate 	static char cstr[] = "\014" "\033[1P" "\033[18;21H";
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	prom_printf(cstr);
3267c478bd9Sstevel@tonic-gate 	prom_printf("Saving System State. Please Wait... ");
3277c478bd9Sstevel@tonic-gate }
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate void
3307c478bd9Sstevel@tonic-gate cpr_spinning_bar(void)
3317c478bd9Sstevel@tonic-gate {
3327c478bd9Sstevel@tonic-gate 	static char *spin_strings[] = { "|\b", "/\b", "-\b", "\\\b" };
3337c478bd9Sstevel@tonic-gate 	static int idx;
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	prom_printf(spin_strings[idx]);
3367c478bd9Sstevel@tonic-gate 	if (++idx == 4)
3377c478bd9Sstevel@tonic-gate 		idx = 0;
3387c478bd9Sstevel@tonic-gate }
3397c478bd9Sstevel@tonic-gate 
340*2df1fe9cSrandyf void
341*2df1fe9cSrandyf cpr_resume_notice(void)
342*2df1fe9cSrandyf {
343*2df1fe9cSrandyf 	static char cstr[] = "\014" "\033[1P" "\033[18;21H";
344*2df1fe9cSrandyf 
345*2df1fe9cSrandyf 	prom_printf(cstr);
346*2df1fe9cSrandyf 	prom_printf("Restoring System State. Please Wait... ");
347*2df1fe9cSrandyf }
348*2df1fe9cSrandyf 
3497c478bd9Sstevel@tonic-gate /*
3507c478bd9Sstevel@tonic-gate  * Convert a full device path to its shortest unambiguous equivalent.
3517c478bd9Sstevel@tonic-gate  * For example, a path which starts out /iommu@x,y/sbus@i,j/espdma . . .
3527c478bd9Sstevel@tonic-gate  * might be converted to /iommu/sbus/espdma . . .  If we encounter
3537c478bd9Sstevel@tonic-gate  * problems at any point, just output the unabbreviated path.
3547c478bd9Sstevel@tonic-gate  */
3557c478bd9Sstevel@tonic-gate static void
3567c478bd9Sstevel@tonic-gate cpr_abbreviate_devpath(char *in_path, char *out_path)
3577c478bd9Sstevel@tonic-gate {
358fa9e4066Sahrens 	static pnode_t cur_node;
3597c478bd9Sstevel@tonic-gate 	char *position = in_path + 1;	/* Skip the leading slash. */
3607c478bd9Sstevel@tonic-gate 	char *cmpt;
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	cur_node = prom_nextnode(0);
3637c478bd9Sstevel@tonic-gate 	*out_path = '\0';
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	while ((cmpt = cpr_next_component(&position)) != NULL) {
366fa9e4066Sahrens 		pnode_t long_match = NULL;
367fa9e4066Sahrens 		pnode_t short_match = NULL;
3687c478bd9Sstevel@tonic-gate 		int short_hits = 0;
3697c478bd9Sstevel@tonic-gate 		char *name;
3707c478bd9Sstevel@tonic-gate 		char *prefix = cpr_get_prefix(cmpt);
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 		/* Go to next tree level by getting first child. */
3737c478bd9Sstevel@tonic-gate 		if ((cur_node = prom_childnode(cur_node)) == 0) {
3747c478bd9Sstevel@tonic-gate 			(void) strcpy(out_path, in_path);
3757c478bd9Sstevel@tonic-gate 			return;
3767c478bd9Sstevel@tonic-gate 		}
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate 		/*
3797c478bd9Sstevel@tonic-gate 		 * Traverse the current level and remember the node (if any)
3807c478bd9Sstevel@tonic-gate 		 * where we match on the fully qualified component name.
3817c478bd9Sstevel@tonic-gate 		 * Also remember the node of the most recent prefix match
3827c478bd9Sstevel@tonic-gate 		 * and the number of such matches.
3837c478bd9Sstevel@tonic-gate 		 */
3847c478bd9Sstevel@tonic-gate 		do {
3857c478bd9Sstevel@tonic-gate 			name = cpr_build_nodename(cur_node);
3867c478bd9Sstevel@tonic-gate 			if (strcmp(name, cmpt) == 0)
3877c478bd9Sstevel@tonic-gate 				long_match = cur_node;
3887c478bd9Sstevel@tonic-gate 			if (strncmp(prefix, name, strlen(prefix)) == 0) {
3897c478bd9Sstevel@tonic-gate 				short_match = cur_node;
3907c478bd9Sstevel@tonic-gate 				short_hits++;
3917c478bd9Sstevel@tonic-gate 			}
3927c478bd9Sstevel@tonic-gate 		} while ((cur_node = prom_nextnode(cur_node)) != 0);
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 		/*
3957c478bd9Sstevel@tonic-gate 		 * We don't want to be too dependent on what we know
3967c478bd9Sstevel@tonic-gate 		 * about how the names are stored.  We just assume that
3977c478bd9Sstevel@tonic-gate 		 * if there is only one match on the prefix, we can
3987c478bd9Sstevel@tonic-gate 		 * use it, otherwise we need to use a fully qualified
3997c478bd9Sstevel@tonic-gate 		 * name.  In the "impossible" cases we just give up
4007c478bd9Sstevel@tonic-gate 		 * and use the complete input devpath.
4017c478bd9Sstevel@tonic-gate 		 */
4027c478bd9Sstevel@tonic-gate 		(void) strcat(out_path, "/");
4037c478bd9Sstevel@tonic-gate 		if (short_hits == 1) {
4047c478bd9Sstevel@tonic-gate 			(void) strcat(out_path, prefix);
4057c478bd9Sstevel@tonic-gate 			cur_node = short_match;
4067c478bd9Sstevel@tonic-gate 		}
4077c478bd9Sstevel@tonic-gate 		else
4087c478bd9Sstevel@tonic-gate 			if (long_match) {
4097c478bd9Sstevel@tonic-gate 				(void) strcat(out_path, cmpt);
4107c478bd9Sstevel@tonic-gate 				cur_node = long_match;
4117c478bd9Sstevel@tonic-gate 			} else {
4127c478bd9Sstevel@tonic-gate 				(void) strcpy(out_path, in_path);
4137c478bd9Sstevel@tonic-gate 				return;
4147c478bd9Sstevel@tonic-gate 			}
4157c478bd9Sstevel@tonic-gate 	}
4167c478bd9Sstevel@tonic-gate 	/* We need to copy the target and slice info manually. */
4177c478bd9Sstevel@tonic-gate 	(void) strcat(out_path, strrchr(in_path, '@'));
4187c478bd9Sstevel@tonic-gate }
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate /*
4217c478bd9Sstevel@tonic-gate  * Return a pointer to the next component of a device path or NULL if
4227c478bd9Sstevel@tonic-gate  * the entire path has been consumed.  Note that we update the caller's
4237c478bd9Sstevel@tonic-gate  * pointer to the current position in the full pathname buffer.
4247c478bd9Sstevel@tonic-gate  */
4257c478bd9Sstevel@tonic-gate static char *
4267c478bd9Sstevel@tonic-gate cpr_next_component(char **path)
4277c478bd9Sstevel@tonic-gate {
4287c478bd9Sstevel@tonic-gate 	static char obuf[64];
4297c478bd9Sstevel@tonic-gate 	char *slash;
4307c478bd9Sstevel@tonic-gate 	int len = strlen(*path);
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	if (len == 0)
4337c478bd9Sstevel@tonic-gate 		return (NULL);
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	if ((slash = strchr(*path, '/'))) {
4367c478bd9Sstevel@tonic-gate 		len = slash - *path;
4377c478bd9Sstevel@tonic-gate 		(void) strncpy(obuf, *path, len);
4387c478bd9Sstevel@tonic-gate 		obuf[len] = '\0';
4397c478bd9Sstevel@tonic-gate 		*path += len + 1;	/* Position beyond the slash. */
4407c478bd9Sstevel@tonic-gate 	} else {
4417c478bd9Sstevel@tonic-gate 		(void) strcpy(obuf, *path);
4427c478bd9Sstevel@tonic-gate 		*path += len;		/* Position at the terminal NULL. */
4437c478bd9Sstevel@tonic-gate 	}
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 	return (obuf);
4467c478bd9Sstevel@tonic-gate }
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate /*
4497c478bd9Sstevel@tonic-gate  * Return a pointer to the prefix (i.e., the basic unqualified node name)
4507c478bd9Sstevel@tonic-gate  * Basically, this is the part of the fully qualified name before the @.
4517c478bd9Sstevel@tonic-gate  */
4527c478bd9Sstevel@tonic-gate static char *
4537c478bd9Sstevel@tonic-gate cpr_get_prefix(char *cmpt)
4547c478bd9Sstevel@tonic-gate {
4557c478bd9Sstevel@tonic-gate 	static char	prefix[OBP_MAXDRVNAME];
4567c478bd9Sstevel@tonic-gate 	char		*at_sign = strchr(cmpt, '@');
4577c478bd9Sstevel@tonic-gate 	int		len = at_sign ? at_sign - cmpt : strlen(cmpt);
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	(void) strncpy(prefix, cmpt, len);
4607c478bd9Sstevel@tonic-gate 	prefix[len] = '\0';
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 	return (prefix);
4637c478bd9Sstevel@tonic-gate }
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate /*
4667c478bd9Sstevel@tonic-gate  * Build the unambiguous name for the current node, like iommu@f,e10000000.
4677c478bd9Sstevel@tonic-gate  * The prefix is just the "name" property, and the qualifier is constructed
4687c478bd9Sstevel@tonic-gate  * from the first two (binary) words of the "reg" property.
4697c478bd9Sstevel@tonic-gate  */
4707c478bd9Sstevel@tonic-gate static char *
471fa9e4066Sahrens cpr_build_nodename(pnode_t node)
4727c478bd9Sstevel@tonic-gate {
4737c478bd9Sstevel@tonic-gate 	static char	name[OBP_MAXPATHLEN];
4747c478bd9Sstevel@tonic-gate 	int		reg[512];
4757c478bd9Sstevel@tonic-gate 	char		buf[32]; /* must contain expansion of @%x,%x */
4767c478bd9Sstevel@tonic-gate 	int		prop_len = prom_getproplen(node, OBP_NAME);
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 	if (prop_len < 0 || prop_len >= sizeof (name) ||
4797c478bd9Sstevel@tonic-gate 	    prom_getprop(node, OBP_NAME, name) < 0)
4807c478bd9Sstevel@tonic-gate 		return ("");
4817c478bd9Sstevel@tonic-gate 	name[prop_len] = '\0';
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 	if ((prop_len = prom_getproplen(node, OBP_REG)) <
4847c478bd9Sstevel@tonic-gate 	    2 * sizeof (int) || prop_len >= sizeof (reg))
4857c478bd9Sstevel@tonic-gate 		return (name);
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	if (prom_getprop(node, OBP_REG, (caddr_t)reg) < 0)
4887c478bd9Sstevel@tonic-gate 		return (name);
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 	(void) sprintf(buf, "@%x,%x", reg[0], reg[1]);
4917c478bd9Sstevel@tonic-gate 	(void) strcat(name, buf);
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	return (name);
4947c478bd9Sstevel@tonic-gate }
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate /*
4977c478bd9Sstevel@tonic-gate  * Makes a printable list of prom_prop names for error messages
4987c478bd9Sstevel@tonic-gate  * Caller must free space.
4997c478bd9Sstevel@tonic-gate  */
5007c478bd9Sstevel@tonic-gate char *
5017c478bd9Sstevel@tonic-gate cpr_enumerate_promprops(char **bufp, size_t *len)
5027c478bd9Sstevel@tonic-gate {
5037c478bd9Sstevel@tonic-gate 	cprop_t *prop, *tail;
5047c478bd9Sstevel@tonic-gate 	size_t size = 2;	/* for "." */
5057c478bd9Sstevel@tonic-gate 	char *buf;
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	tail = &orig_def_info.props[CPR_MAXPROP];
5087c478bd9Sstevel@tonic-gate 	for (prop = orig_def_info.props; prop < tail; prop++)
5097c478bd9Sstevel@tonic-gate 		size += strlen(prop->name) + 2;	/* + ", " */
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 	buf = kmem_alloc(size, KM_SLEEP);
5127c478bd9Sstevel@tonic-gate 	*buf = '\0';
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 	for (prop = orig_def_info.props; prop < tail; prop++) {
5157c478bd9Sstevel@tonic-gate 		if (strlen(buf))
5167c478bd9Sstevel@tonic-gate 			(void) strcat(buf, ", ");
5177c478bd9Sstevel@tonic-gate 		(void) strcat(buf, prop->name);
5187c478bd9Sstevel@tonic-gate 	}
5197c478bd9Sstevel@tonic-gate 	(void) strcat(buf, ".");
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	*bufp = buf;
5227c478bd9Sstevel@tonic-gate 	*len = size;
5237c478bd9Sstevel@tonic-gate 	return (buf);
5247c478bd9Sstevel@tonic-gate }
525