xref: /onnv-gate/usr/src/uts/sparc/os/cpr_sparc.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * cpr functions for supported sparc platforms
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate #include <sys/types.h>
33*0Sstevel@tonic-gate #include <sys/systm.h>
34*0Sstevel@tonic-gate #include <sys/cpr.h>
35*0Sstevel@tonic-gate #include <sys/kmem.h>
36*0Sstevel@tonic-gate #include <sys/errno.h>
37*0Sstevel@tonic-gate 
38*0Sstevel@tonic-gate /*
39*0Sstevel@tonic-gate  * new_def_info is used as tmp space to store new values and write them
40*0Sstevel@tonic-gate  * to nvram.  orig_def_info gets filled with the original nvram values,
41*0Sstevel@tonic-gate  * gets written to disk, and later used by cprboot to restore the
42*0Sstevel@tonic-gate  * original nvram values.
43*0Sstevel@tonic-gate  */
44*0Sstevel@tonic-gate static cdef_t *new_def_info;
45*0Sstevel@tonic-gate 
46*0Sstevel@tonic-gate static cdef_t orig_def_info = {
47*0Sstevel@tonic-gate 	0, 0,
48*0Sstevel@tonic-gate 	0, "boot-file",    "",		/* props[0] */
49*0Sstevel@tonic-gate 	0, "boot-device",  "",		/* props[1] */
50*0Sstevel@tonic-gate 	0, "auto-boot?",   "",		/* props[2] */
51*0Sstevel@tonic-gate 	0, "diag-file",    "",		/* props[3] */
52*0Sstevel@tonic-gate 	0, "diag-device",  "",		/* props[4] */
53*0Sstevel@tonic-gate };
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate /*
56*0Sstevel@tonic-gate  * since the above array is the only place where cprop_t content
57*0Sstevel@tonic-gate  * is specified, these defines are provided for quick/direct access.
58*0Sstevel@tonic-gate  */
59*0Sstevel@tonic-gate #define	CPR_BF_IDX	0		/* index for boot-file */
60*0Sstevel@tonic-gate #define	CPR_BD_IDX	1		/* index for boot-device */
61*0Sstevel@tonic-gate #define	CPR_AB_IDX	2		/* index for auto-boot? */
62*0Sstevel@tonic-gate #define	CPR_DF_IDX	3		/* index for diag-file */
63*0Sstevel@tonic-gate #define	CPR_DD_IDX	4		/* index for diag-device */
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate #define	CPR_PROP_PTR(dfp, idx)	&(dfp)->props[idx]
66*0Sstevel@tonic-gate 
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate static char *cpr_next_component(char **);
69*0Sstevel@tonic-gate static char *cpr_get_prefix(char *);
70*0Sstevel@tonic-gate static char *cpr_build_nodename(dnode_t);
71*0Sstevel@tonic-gate static void cpr_abbreviate_devpath(char *, char *);
72*0Sstevel@tonic-gate static int cpr_show_props = 0;
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate 
75*0Sstevel@tonic-gate static int
76*0Sstevel@tonic-gate cpr_get_options_node(dnode_t *nodep)
77*0Sstevel@tonic-gate {
78*0Sstevel@tonic-gate 	*nodep = prom_optionsnode();
79*0Sstevel@tonic-gate 	if (*nodep == OBP_NONODE || *nodep == OBP_BADNODE) {
80*0Sstevel@tonic-gate 		cpr_err(CE_WARN, "cannot get \"options\" node");
81*0Sstevel@tonic-gate 		return (ENOENT);
82*0Sstevel@tonic-gate 	}
83*0Sstevel@tonic-gate 
84*0Sstevel@tonic-gate 	return (0);
85*0Sstevel@tonic-gate }
86*0Sstevel@tonic-gate 
87*0Sstevel@tonic-gate 
88*0Sstevel@tonic-gate /*
89*0Sstevel@tonic-gate  * returns non-zero on error, otherwise returns 0 and
90*0Sstevel@tonic-gate  * sets the result code based on (prop value == "true")
91*0Sstevel@tonic-gate  */
92*0Sstevel@tonic-gate static int
93*0Sstevel@tonic-gate cpr_get_bool_prop(char *name, int *result)
94*0Sstevel@tonic-gate {
95*0Sstevel@tonic-gate 	char value[PROP_BOOL_LEN];
96*0Sstevel@tonic-gate 	dnode_t node;
97*0Sstevel@tonic-gate 	int len, err;
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate 	if (err = cpr_get_options_node(&node))
100*0Sstevel@tonic-gate 		return (err);
101*0Sstevel@tonic-gate 	len = prom_getproplen(node, name);
102*0Sstevel@tonic-gate 	if (len < 0 || len >= sizeof (value))
103*0Sstevel@tonic-gate 		return (ENXIO);
104*0Sstevel@tonic-gate 	bzero(value, sizeof (value));
105*0Sstevel@tonic-gate 	if (prom_getprop(node, name, value) != len)
106*0Sstevel@tonic-gate 		return (ENOENT);
107*0Sstevel@tonic-gate 	*result = (strcmp(value, "true") == 0);
108*0Sstevel@tonic-gate 	return (0);
109*0Sstevel@tonic-gate }
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate 
112*0Sstevel@tonic-gate /*
113*0Sstevel@tonic-gate  * write new or original values to nvram
114*0Sstevel@tonic-gate  */
115*0Sstevel@tonic-gate int
116*0Sstevel@tonic-gate cpr_update_nvram(cprop_t *props)
117*0Sstevel@tonic-gate {
118*0Sstevel@tonic-gate 	cprop_t *tail;
119*0Sstevel@tonic-gate 	dnode_t node;
120*0Sstevel@tonic-gate 	int len, rc;
121*0Sstevel@tonic-gate 
122*0Sstevel@tonic-gate 	if (rc = cpr_get_options_node(&node))
123*0Sstevel@tonic-gate 		return (rc);
124*0Sstevel@tonic-gate 
125*0Sstevel@tonic-gate 	if (cpr_show_props)
126*0Sstevel@tonic-gate 		prom_printf("\ncpr_show_props:\n");
127*0Sstevel@tonic-gate 	for (tail = props + CPR_MAXPROP; props < tail; props++) {
128*0Sstevel@tonic-gate 		if (cpr_show_props) {
129*0Sstevel@tonic-gate 			prom_printf("mod=%c, name \"%s\",\tvalue \"%s\"\n",
130*0Sstevel@tonic-gate 			    props->mod, props->name, props->value);
131*0Sstevel@tonic-gate 		}
132*0Sstevel@tonic-gate 		if (props->mod == PROP_NOMOD)
133*0Sstevel@tonic-gate 			continue;
134*0Sstevel@tonic-gate 		/*
135*0Sstevel@tonic-gate 		 * Note: When doing a prom_setprop you must include the
136*0Sstevel@tonic-gate 		 * trailing NULL in the length argument, but when calling
137*0Sstevel@tonic-gate 		 * prom_getproplen() the NULL is excluded from the count!
138*0Sstevel@tonic-gate 		 */
139*0Sstevel@tonic-gate 		len = strlen(props->value);
140*0Sstevel@tonic-gate 		rc = prom_setprop(node, props->name, props->value, len + 1);
141*0Sstevel@tonic-gate 		if (rc < 0 || prom_getproplen(node, props->name) != len) {
142*0Sstevel@tonic-gate 			cpr_err(CE_WARN, "cannot set nvram \"%s\" to \"%s\"",
143*0Sstevel@tonic-gate 			    props->name, props->value);
144*0Sstevel@tonic-gate 			return (ENXIO);
145*0Sstevel@tonic-gate 		}
146*0Sstevel@tonic-gate 	}
147*0Sstevel@tonic-gate 
148*0Sstevel@tonic-gate 	return (0);
149*0Sstevel@tonic-gate }
150*0Sstevel@tonic-gate 
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate /*
153*0Sstevel@tonic-gate  * update nvram with the new or original nvram values;
154*0Sstevel@tonic-gate  * this routine provides local access to both sets
155*0Sstevel@tonic-gate  */
156*0Sstevel@tonic-gate int
157*0Sstevel@tonic-gate cpr_set_properties(int new)
158*0Sstevel@tonic-gate {
159*0Sstevel@tonic-gate 	cprop_t *props;
160*0Sstevel@tonic-gate 
161*0Sstevel@tonic-gate 	props = new ? new_def_info->props : orig_def_info.props;
162*0Sstevel@tonic-gate 	return (cpr_update_nvram(props));
163*0Sstevel@tonic-gate }
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate 
167*0Sstevel@tonic-gate /*
168*0Sstevel@tonic-gate  * update the .mod field in both new_def_info and orig_def_info;
169*0Sstevel@tonic-gate  * this tells cpr and cprboot which properties to set/reset.
170*0Sstevel@tonic-gate  * then copy the arg str into a new property value at index
171*0Sstevel@tonic-gate  */
172*0Sstevel@tonic-gate static void
173*0Sstevel@tonic-gate cpr_prop_update(int index, char *str)
174*0Sstevel@tonic-gate {
175*0Sstevel@tonic-gate 	cprop_t *prop;
176*0Sstevel@tonic-gate 
177*0Sstevel@tonic-gate 	prop = CPR_PROP_PTR(&orig_def_info, index);
178*0Sstevel@tonic-gate 	prop->mod = PROP_MOD;
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate 	prop = CPR_PROP_PTR(new_def_info, index);
181*0Sstevel@tonic-gate 	prop->mod = PROP_MOD;
182*0Sstevel@tonic-gate 	(void) strcpy(prop->value, str);
183*0Sstevel@tonic-gate }
184*0Sstevel@tonic-gate 
185*0Sstevel@tonic-gate 
186*0Sstevel@tonic-gate /*
187*0Sstevel@tonic-gate  * setup new property values within new_def_info;
188*0Sstevel@tonic-gate  * these are used later to udpate nvram
189*0Sstevel@tonic-gate  */
190*0Sstevel@tonic-gate static int
191*0Sstevel@tonic-gate cpr_prop_setup(void)
192*0Sstevel@tonic-gate {
193*0Sstevel@tonic-gate 	int len, err, ds_ival, dev_idx, file_idx;
194*0Sstevel@tonic-gate 	char bootdev[OBP_MAXPATHLEN], bootfile[OBP_MAXPATHLEN];
195*0Sstevel@tonic-gate 	char *cp, *sp;
196*0Sstevel@tonic-gate 
197*0Sstevel@tonic-gate 	/*
198*0Sstevel@tonic-gate 	 * create a new boot-device value.  for some older prom revs,
199*0Sstevel@tonic-gate 	 * a fully qualified device path can be truncated when stored
200*0Sstevel@tonic-gate 	 * to nvram.  this call generates the shortest equivalent.
201*0Sstevel@tonic-gate 	 * using devaliases could be simpler in most cases.
202*0Sstevel@tonic-gate 	 */
203*0Sstevel@tonic-gate 	cpr_abbreviate_devpath(prom_bootpath(), bootdev);
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate 	/*
206*0Sstevel@tonic-gate 	 * create a new boot-file value; flags get appended when
207*0Sstevel@tonic-gate 	 * reusable is true or when the statefile is a block device
208*0Sstevel@tonic-gate 	 */
209*0Sstevel@tonic-gate 	(void) strcpy(bootfile, CPRBOOT);
210*0Sstevel@tonic-gate 	if (cpr_reusable_mode) {
211*0Sstevel@tonic-gate 		ASSERT(cpr_statefile_is_spec());
212*0Sstevel@tonic-gate 		sp = " -R -S ";
213*0Sstevel@tonic-gate 	} else if (cpr_statefile_is_spec())
214*0Sstevel@tonic-gate 		sp = " -S ";
215*0Sstevel@tonic-gate 	else
216*0Sstevel@tonic-gate 		sp = NULL;
217*0Sstevel@tonic-gate 	if (sp) {
218*0Sstevel@tonic-gate 		(void) strcat(bootfile, sp);
219*0Sstevel@tonic-gate 		len = strlen(bootfile);
220*0Sstevel@tonic-gate 		sp = cpr_get_statefile_prom_path();
221*0Sstevel@tonic-gate 		cpr_abbreviate_devpath(sp, &bootfile[len]);
222*0Sstevel@tonic-gate 	}
223*0Sstevel@tonic-gate 
224*0Sstevel@tonic-gate 	/*
225*0Sstevel@tonic-gate 	 * record property info for booting with cprboot based on
226*0Sstevel@tonic-gate 	 * the value of diag-switch?.  when "false", set boot-device
227*0Sstevel@tonic-gate 	 * and boot-file; when "true", set diag-device and diag-file
228*0Sstevel@tonic-gate 	 */
229*0Sstevel@tonic-gate 	if (err = cpr_get_bool_prop("diag-switch?", &ds_ival))
230*0Sstevel@tonic-gate 		return (err);
231*0Sstevel@tonic-gate 	else if (ds_ival == 0) {
232*0Sstevel@tonic-gate 		dev_idx  = CPR_BD_IDX;
233*0Sstevel@tonic-gate 		file_idx = CPR_BF_IDX;
234*0Sstevel@tonic-gate 	} else {
235*0Sstevel@tonic-gate 		dev_idx  = CPR_DD_IDX;
236*0Sstevel@tonic-gate 		file_idx = CPR_DF_IDX;
237*0Sstevel@tonic-gate 	}
238*0Sstevel@tonic-gate 	cpr_prop_update(dev_idx,  bootdev);
239*0Sstevel@tonic-gate 	cpr_prop_update(file_idx, bootfile);
240*0Sstevel@tonic-gate 
241*0Sstevel@tonic-gate 	/*
242*0Sstevel@tonic-gate 	 * check/set auto-boot?
243*0Sstevel@tonic-gate 	 */
244*0Sstevel@tonic-gate 	sp = orig_def_info.props[CPR_AB_IDX].value;
245*0Sstevel@tonic-gate 	cp = "true";
246*0Sstevel@tonic-gate 	if (strcmp(sp, cp))
247*0Sstevel@tonic-gate 		cpr_prop_update(CPR_AB_IDX, cp);
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate 	return (0);
250*0Sstevel@tonic-gate }
251*0Sstevel@tonic-gate 
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate /*
254*0Sstevel@tonic-gate  * setup the original and new sets of property names/values
255*0Sstevel@tonic-gate  */
256*0Sstevel@tonic-gate int
257*0Sstevel@tonic-gate cpr_default_setup(int alloc)
258*0Sstevel@tonic-gate {
259*0Sstevel@tonic-gate 	cprop_t *orig, *new, *tail;
260*0Sstevel@tonic-gate 	int len, err = 0;
261*0Sstevel@tonic-gate 	dnode_t node;
262*0Sstevel@tonic-gate 	char *fmt;
263*0Sstevel@tonic-gate 
264*0Sstevel@tonic-gate 	if (alloc == 0) {
265*0Sstevel@tonic-gate 		ASSERT(new_def_info);
266*0Sstevel@tonic-gate 		kmem_free(new_def_info, sizeof (*new_def_info));
267*0Sstevel@tonic-gate 		new_def_info = NULL;
268*0Sstevel@tonic-gate 		return (0);
269*0Sstevel@tonic-gate 	}
270*0Sstevel@tonic-gate 
271*0Sstevel@tonic-gate 	if (err = cpr_get_options_node(&node))
272*0Sstevel@tonic-gate 		return (err);
273*0Sstevel@tonic-gate 
274*0Sstevel@tonic-gate 	/*
275*0Sstevel@tonic-gate 	 * allocate space for new properties, get the original nvram
276*0Sstevel@tonic-gate 	 * property values, mark both property sets with PROP_NOMOD,
277*0Sstevel@tonic-gate 	 * and copy the original prop names to the new set.
278*0Sstevel@tonic-gate 	 */
279*0Sstevel@tonic-gate 	ASSERT(new_def_info == NULL);
280*0Sstevel@tonic-gate 	new_def_info = kmem_zalloc(sizeof (*new_def_info), KM_SLEEP);
281*0Sstevel@tonic-gate 	new = new_def_info->props;
282*0Sstevel@tonic-gate 
283*0Sstevel@tonic-gate 	for (orig = orig_def_info.props, tail = orig + CPR_MAXPROP;
284*0Sstevel@tonic-gate 	    orig < tail; orig++, new++) {
285*0Sstevel@tonic-gate 		len = prom_getproplen(node, orig->name);
286*0Sstevel@tonic-gate 		if (len < 0 || len >= (int)sizeof (orig->value)) {
287*0Sstevel@tonic-gate 			fmt = "invalid property or length for \"%s\"";
288*0Sstevel@tonic-gate 			err = ENXIO;
289*0Sstevel@tonic-gate 			break;
290*0Sstevel@tonic-gate 		}
291*0Sstevel@tonic-gate 		bzero(orig->value, sizeof (orig->value));
292*0Sstevel@tonic-gate 		if (prom_getprop(node, orig->name, orig->value) < 0) {
293*0Sstevel@tonic-gate 			fmt = "cannot get \"%s\" value";
294*0Sstevel@tonic-gate 			err = ENXIO;
295*0Sstevel@tonic-gate 			break;
296*0Sstevel@tonic-gate 		}
297*0Sstevel@tonic-gate 
298*0Sstevel@tonic-gate 		new->mod = orig->mod = PROP_NOMOD;
299*0Sstevel@tonic-gate 		(void) strcpy(new->name, orig->name);
300*0Sstevel@tonic-gate 	}
301*0Sstevel@tonic-gate 
302*0Sstevel@tonic-gate 	if (err) {
303*0Sstevel@tonic-gate 		kmem_free(new_def_info, sizeof (*new_def_info));
304*0Sstevel@tonic-gate 		new_def_info = NULL;
305*0Sstevel@tonic-gate 		cpr_err(CE_WARN, fmt, orig->name);
306*0Sstevel@tonic-gate 	} else
307*0Sstevel@tonic-gate 		err = cpr_prop_setup();
308*0Sstevel@tonic-gate 
309*0Sstevel@tonic-gate 	return (err);
310*0Sstevel@tonic-gate }
311*0Sstevel@tonic-gate 
312*0Sstevel@tonic-gate 
313*0Sstevel@tonic-gate int
314*0Sstevel@tonic-gate cpr_validate_definfo(int reusable)
315*0Sstevel@tonic-gate {
316*0Sstevel@tonic-gate 	orig_def_info.mini.magic = CPR->c_cprboot_magic = CPR_DEFAULT_MAGIC;
317*0Sstevel@tonic-gate 	orig_def_info.mini.reusable = reusable;
318*0Sstevel@tonic-gate 	return (cpr_write_deffile(&orig_def_info));
319*0Sstevel@tonic-gate }
320*0Sstevel@tonic-gate 
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate void
323*0Sstevel@tonic-gate cpr_send_notice(void)
324*0Sstevel@tonic-gate {
325*0Sstevel@tonic-gate 	static char cstr[] = "\014" "\033[1P" "\033[18;21H";
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate 	prom_printf(cstr);
328*0Sstevel@tonic-gate 	prom_printf("Saving System State. Please Wait... ");
329*0Sstevel@tonic-gate }
330*0Sstevel@tonic-gate 
331*0Sstevel@tonic-gate void
332*0Sstevel@tonic-gate cpr_spinning_bar(void)
333*0Sstevel@tonic-gate {
334*0Sstevel@tonic-gate 	static char *spin_strings[] = { "|\b", "/\b", "-\b", "\\\b" };
335*0Sstevel@tonic-gate 	static int idx;
336*0Sstevel@tonic-gate 
337*0Sstevel@tonic-gate 	prom_printf(spin_strings[idx]);
338*0Sstevel@tonic-gate 	if (++idx == 4)
339*0Sstevel@tonic-gate 		idx = 0;
340*0Sstevel@tonic-gate }
341*0Sstevel@tonic-gate 
342*0Sstevel@tonic-gate /*
343*0Sstevel@tonic-gate  * Convert a full device path to its shortest unambiguous equivalent.
344*0Sstevel@tonic-gate  * For example, a path which starts out /iommu@x,y/sbus@i,j/espdma . . .
345*0Sstevel@tonic-gate  * might be converted to /iommu/sbus/espdma . . .  If we encounter
346*0Sstevel@tonic-gate  * problems at any point, just output the unabbreviated path.
347*0Sstevel@tonic-gate  */
348*0Sstevel@tonic-gate static void
349*0Sstevel@tonic-gate cpr_abbreviate_devpath(char *in_path, char *out_path)
350*0Sstevel@tonic-gate {
351*0Sstevel@tonic-gate 	static dnode_t cur_node;
352*0Sstevel@tonic-gate 	char *position = in_path + 1;	/* Skip the leading slash. */
353*0Sstevel@tonic-gate 	char *cmpt;
354*0Sstevel@tonic-gate 
355*0Sstevel@tonic-gate 	cur_node = prom_nextnode(0);
356*0Sstevel@tonic-gate 	*out_path = '\0';
357*0Sstevel@tonic-gate 
358*0Sstevel@tonic-gate 	while ((cmpt = cpr_next_component(&position)) != NULL) {
359*0Sstevel@tonic-gate 		dnode_t long_match = NULL;
360*0Sstevel@tonic-gate 		dnode_t short_match = NULL;
361*0Sstevel@tonic-gate 		int short_hits = 0;
362*0Sstevel@tonic-gate 		char *name;
363*0Sstevel@tonic-gate 		char *prefix = cpr_get_prefix(cmpt);
364*0Sstevel@tonic-gate 
365*0Sstevel@tonic-gate 		/* Go to next tree level by getting first child. */
366*0Sstevel@tonic-gate 		if ((cur_node = prom_childnode(cur_node)) == 0) {
367*0Sstevel@tonic-gate 			(void) strcpy(out_path, in_path);
368*0Sstevel@tonic-gate 			return;
369*0Sstevel@tonic-gate 		}
370*0Sstevel@tonic-gate 
371*0Sstevel@tonic-gate 		/*
372*0Sstevel@tonic-gate 		 * Traverse the current level and remember the node (if any)
373*0Sstevel@tonic-gate 		 * where we match on the fully qualified component name.
374*0Sstevel@tonic-gate 		 * Also remember the node of the most recent prefix match
375*0Sstevel@tonic-gate 		 * and the number of such matches.
376*0Sstevel@tonic-gate 		 */
377*0Sstevel@tonic-gate 		do {
378*0Sstevel@tonic-gate 			name = cpr_build_nodename(cur_node);
379*0Sstevel@tonic-gate 			if (strcmp(name, cmpt) == 0)
380*0Sstevel@tonic-gate 				long_match = cur_node;
381*0Sstevel@tonic-gate 			if (strncmp(prefix, name, strlen(prefix)) == 0) {
382*0Sstevel@tonic-gate 				short_match = cur_node;
383*0Sstevel@tonic-gate 				short_hits++;
384*0Sstevel@tonic-gate 			}
385*0Sstevel@tonic-gate 		} while ((cur_node = prom_nextnode(cur_node)) != 0);
386*0Sstevel@tonic-gate 
387*0Sstevel@tonic-gate 		/*
388*0Sstevel@tonic-gate 		 * We don't want to be too dependent on what we know
389*0Sstevel@tonic-gate 		 * about how the names are stored.  We just assume that
390*0Sstevel@tonic-gate 		 * if there is only one match on the prefix, we can
391*0Sstevel@tonic-gate 		 * use it, otherwise we need to use a fully qualified
392*0Sstevel@tonic-gate 		 * name.  In the "impossible" cases we just give up
393*0Sstevel@tonic-gate 		 * and use the complete input devpath.
394*0Sstevel@tonic-gate 		 */
395*0Sstevel@tonic-gate 		(void) strcat(out_path, "/");
396*0Sstevel@tonic-gate 		if (short_hits == 1) {
397*0Sstevel@tonic-gate 			(void) strcat(out_path, prefix);
398*0Sstevel@tonic-gate 			cur_node = short_match;
399*0Sstevel@tonic-gate 		}
400*0Sstevel@tonic-gate 		else
401*0Sstevel@tonic-gate 			if (long_match) {
402*0Sstevel@tonic-gate 				(void) strcat(out_path, cmpt);
403*0Sstevel@tonic-gate 				cur_node = long_match;
404*0Sstevel@tonic-gate 			} else {
405*0Sstevel@tonic-gate 				(void) strcpy(out_path, in_path);
406*0Sstevel@tonic-gate 				return;
407*0Sstevel@tonic-gate 			}
408*0Sstevel@tonic-gate 	}
409*0Sstevel@tonic-gate 	/* We need to copy the target and slice info manually. */
410*0Sstevel@tonic-gate 	(void) strcat(out_path, strrchr(in_path, '@'));
411*0Sstevel@tonic-gate }
412*0Sstevel@tonic-gate 
413*0Sstevel@tonic-gate /*
414*0Sstevel@tonic-gate  * Return a pointer to the next component of a device path or NULL if
415*0Sstevel@tonic-gate  * the entire path has been consumed.  Note that we update the caller's
416*0Sstevel@tonic-gate  * pointer to the current position in the full pathname buffer.
417*0Sstevel@tonic-gate  */
418*0Sstevel@tonic-gate static char *
419*0Sstevel@tonic-gate cpr_next_component(char **path)
420*0Sstevel@tonic-gate {
421*0Sstevel@tonic-gate 	static char obuf[64];
422*0Sstevel@tonic-gate 	char *slash;
423*0Sstevel@tonic-gate 	int len = strlen(*path);
424*0Sstevel@tonic-gate 
425*0Sstevel@tonic-gate 	if (len == 0)
426*0Sstevel@tonic-gate 		return (NULL);
427*0Sstevel@tonic-gate 
428*0Sstevel@tonic-gate 	if ((slash = strchr(*path, '/'))) {
429*0Sstevel@tonic-gate 		len = slash - *path;
430*0Sstevel@tonic-gate 		(void) strncpy(obuf, *path, len);
431*0Sstevel@tonic-gate 		obuf[len] = '\0';
432*0Sstevel@tonic-gate 		*path += len + 1;	/* Position beyond the slash. */
433*0Sstevel@tonic-gate 	} else {
434*0Sstevel@tonic-gate 		(void) strcpy(obuf, *path);
435*0Sstevel@tonic-gate 		*path += len;		/* Position at the terminal NULL. */
436*0Sstevel@tonic-gate 	}
437*0Sstevel@tonic-gate 
438*0Sstevel@tonic-gate 	return (obuf);
439*0Sstevel@tonic-gate }
440*0Sstevel@tonic-gate 
441*0Sstevel@tonic-gate /*
442*0Sstevel@tonic-gate  * Return a pointer to the prefix (i.e., the basic unqualified node name)
443*0Sstevel@tonic-gate  * Basically, this is the part of the fully qualified name before the @.
444*0Sstevel@tonic-gate  */
445*0Sstevel@tonic-gate static char *
446*0Sstevel@tonic-gate cpr_get_prefix(char *cmpt)
447*0Sstevel@tonic-gate {
448*0Sstevel@tonic-gate 	static char	prefix[OBP_MAXDRVNAME];
449*0Sstevel@tonic-gate 	char		*at_sign = strchr(cmpt, '@');
450*0Sstevel@tonic-gate 	int		len = at_sign ? at_sign - cmpt : strlen(cmpt);
451*0Sstevel@tonic-gate 
452*0Sstevel@tonic-gate 	(void) strncpy(prefix, cmpt, len);
453*0Sstevel@tonic-gate 	prefix[len] = '\0';
454*0Sstevel@tonic-gate 
455*0Sstevel@tonic-gate 	return (prefix);
456*0Sstevel@tonic-gate }
457*0Sstevel@tonic-gate 
458*0Sstevel@tonic-gate /*
459*0Sstevel@tonic-gate  * Build the unambiguous name for the current node, like iommu@f,e10000000.
460*0Sstevel@tonic-gate  * The prefix is just the "name" property, and the qualifier is constructed
461*0Sstevel@tonic-gate  * from the first two (binary) words of the "reg" property.
462*0Sstevel@tonic-gate  */
463*0Sstevel@tonic-gate static char *
464*0Sstevel@tonic-gate cpr_build_nodename(dnode_t node)
465*0Sstevel@tonic-gate {
466*0Sstevel@tonic-gate 	static char	name[OBP_MAXPATHLEN];
467*0Sstevel@tonic-gate 	int		reg[512];
468*0Sstevel@tonic-gate 	char		buf[32]; /* must contain expansion of @%x,%x */
469*0Sstevel@tonic-gate 	int		prop_len = prom_getproplen(node, OBP_NAME);
470*0Sstevel@tonic-gate 
471*0Sstevel@tonic-gate 	if (prop_len < 0 || prop_len >= sizeof (name) ||
472*0Sstevel@tonic-gate 	    prom_getprop(node, OBP_NAME, name) < 0)
473*0Sstevel@tonic-gate 		return ("");
474*0Sstevel@tonic-gate 	name[prop_len] = '\0';
475*0Sstevel@tonic-gate 
476*0Sstevel@tonic-gate 	if ((prop_len = prom_getproplen(node, OBP_REG)) <
477*0Sstevel@tonic-gate 	    2 * sizeof (int) || prop_len >= sizeof (reg))
478*0Sstevel@tonic-gate 		return (name);
479*0Sstevel@tonic-gate 
480*0Sstevel@tonic-gate 	if (prom_getprop(node, OBP_REG, (caddr_t)reg) < 0)
481*0Sstevel@tonic-gate 		return (name);
482*0Sstevel@tonic-gate 
483*0Sstevel@tonic-gate 	(void) sprintf(buf, "@%x,%x", reg[0], reg[1]);
484*0Sstevel@tonic-gate 	(void) strcat(name, buf);
485*0Sstevel@tonic-gate 
486*0Sstevel@tonic-gate 	return (name);
487*0Sstevel@tonic-gate }
488*0Sstevel@tonic-gate 
489*0Sstevel@tonic-gate /*
490*0Sstevel@tonic-gate  * Makes a printable list of prom_prop names for error messages
491*0Sstevel@tonic-gate  * Caller must free space.
492*0Sstevel@tonic-gate  */
493*0Sstevel@tonic-gate char *
494*0Sstevel@tonic-gate cpr_enumerate_promprops(char **bufp, size_t *len)
495*0Sstevel@tonic-gate {
496*0Sstevel@tonic-gate 	cprop_t *prop, *tail;
497*0Sstevel@tonic-gate 	size_t size = 2;	/* for "." */
498*0Sstevel@tonic-gate 	char *buf;
499*0Sstevel@tonic-gate 
500*0Sstevel@tonic-gate 	tail = &orig_def_info.props[CPR_MAXPROP];
501*0Sstevel@tonic-gate 	for (prop = orig_def_info.props; prop < tail; prop++)
502*0Sstevel@tonic-gate 		size += strlen(prop->name) + 2;	/* + ", " */
503*0Sstevel@tonic-gate 
504*0Sstevel@tonic-gate 	buf = kmem_alloc(size, KM_SLEEP);
505*0Sstevel@tonic-gate 	*buf = '\0';
506*0Sstevel@tonic-gate 
507*0Sstevel@tonic-gate 	for (prop = orig_def_info.props; prop < tail; prop++) {
508*0Sstevel@tonic-gate 		if (strlen(buf))
509*0Sstevel@tonic-gate 			(void) strcat(buf, ", ");
510*0Sstevel@tonic-gate 		(void) strcat(buf, prop->name);
511*0Sstevel@tonic-gate 	}
512*0Sstevel@tonic-gate 	(void) strcat(buf, ".");
513*0Sstevel@tonic-gate 
514*0Sstevel@tonic-gate 	*bufp = buf;
515*0Sstevel@tonic-gate 	*len = size;
516*0Sstevel@tonic-gate 	return (buf);
517*0Sstevel@tonic-gate }
518