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