xref: /onnv-gate/usr/src/psm/promif/ieee1275/sun4/prom_vercheck.c (revision 11498:2fc576d74742)
1*11498SJerry.Gilliam@Sun.COM /*
2*11498SJerry.Gilliam@Sun.COM  * CDDL HEADER START
3*11498SJerry.Gilliam@Sun.COM  *
4*11498SJerry.Gilliam@Sun.COM  * The contents of this file are subject to the terms of the
5*11498SJerry.Gilliam@Sun.COM  * Common Development and Distribution License (the "License").
6*11498SJerry.Gilliam@Sun.COM  * You may not use this file except in compliance with the License.
7*11498SJerry.Gilliam@Sun.COM  *
8*11498SJerry.Gilliam@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*11498SJerry.Gilliam@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*11498SJerry.Gilliam@Sun.COM  * See the License for the specific language governing permissions
11*11498SJerry.Gilliam@Sun.COM  * and limitations under the License.
12*11498SJerry.Gilliam@Sun.COM  *
13*11498SJerry.Gilliam@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*11498SJerry.Gilliam@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*11498SJerry.Gilliam@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*11498SJerry.Gilliam@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*11498SJerry.Gilliam@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*11498SJerry.Gilliam@Sun.COM  *
19*11498SJerry.Gilliam@Sun.COM  * CDDL HEADER END
20*11498SJerry.Gilliam@Sun.COM  */
21*11498SJerry.Gilliam@Sun.COM /*
22*11498SJerry.Gilliam@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23*11498SJerry.Gilliam@Sun.COM  * Use is subject to license terms.
24*11498SJerry.Gilliam@Sun.COM  */
25*11498SJerry.Gilliam@Sun.COM 
26*11498SJerry.Gilliam@Sun.COM #include <sys/promif.h>
27*11498SJerry.Gilliam@Sun.COM #include <sys/promimpl.h>
28*11498SJerry.Gilliam@Sun.COM 
29*11498SJerry.Gilliam@Sun.COM #ifdef	DPRINTF
30*11498SJerry.Gilliam@Sun.COM #define	dprintf	prom_printf
31*11498SJerry.Gilliam@Sun.COM #endif
32*11498SJerry.Gilliam@Sun.COM 
33*11498SJerry.Gilliam@Sun.COM /*
34*11498SJerry.Gilliam@Sun.COM  * Check if the prom is 64-bit ready.
35*11498SJerry.Gilliam@Sun.COM  */
36*11498SJerry.Gilliam@Sun.COM 
37*11498SJerry.Gilliam@Sun.COM /*
38*11498SJerry.Gilliam@Sun.COM  * Table listing the minimum prom versions supported by this kernel.
39*11498SJerry.Gilliam@Sun.COM  * The model value is expected to match the model in the flashprom node.
40*11498SJerry.Gilliam@Sun.COM  */
41*11498SJerry.Gilliam@Sun.COM static struct obp_rev_table {
42*11498SJerry.Gilliam@Sun.COM 	char *model;
43*11498SJerry.Gilliam@Sun.COM 	char *version;
44*11498SJerry.Gilliam@Sun.COM } obp_min_revs[] = {
45*11498SJerry.Gilliam@Sun.COM 	{"SUNW,525-1414", "OBP 3.11.2 1997/12/05 10:25"},  /* pulsar */
46*11498SJerry.Gilliam@Sun.COM 	{"SUNW,525-1672", "OBP 3.7.107 1998/02/19 17:54"},  /* tazmo */
47*11498SJerry.Gilliam@Sun.COM 	{"SUNW,525-1431", "OBP 3.2.16 1998/06/08 16:58"},   /* sunfire */
48*11498SJerry.Gilliam@Sun.COM 	{ NULL, NULL}
49*11498SJerry.Gilliam@Sun.COM };
50*11498SJerry.Gilliam@Sun.COM 
51*11498SJerry.Gilliam@Sun.COM #define	NMINS	60
52*11498SJerry.Gilliam@Sun.COM #define	NHOURS	24
53*11498SJerry.Gilliam@Sun.COM #define	NDAYS	31
54*11498SJerry.Gilliam@Sun.COM #define	NMONTHS	12
55*11498SJerry.Gilliam@Sun.COM 
56*11498SJerry.Gilliam@Sun.COM #define	YEAR(y)	 ((y-1) * (NMONTHS * NDAYS * NHOURS * NMINS))
57*11498SJerry.Gilliam@Sun.COM #define	MONTH(m) ((m-1) * (NDAYS * NHOURS * NMINS))
58*11498SJerry.Gilliam@Sun.COM #define	DAY(d)   ((d-1) * (NHOURS * NMINS))
59*11498SJerry.Gilliam@Sun.COM #define	HOUR(h)  ((h)   * (NMINS))
60*11498SJerry.Gilliam@Sun.COM #define	MINUTE(m) (m)
61*11498SJerry.Gilliam@Sun.COM 
62*11498SJerry.Gilliam@Sun.COM static int
strtoi(char * str,char ** pos)63*11498SJerry.Gilliam@Sun.COM strtoi(char *str, char **pos)
64*11498SJerry.Gilliam@Sun.COM {
65*11498SJerry.Gilliam@Sun.COM 	int c;
66*11498SJerry.Gilliam@Sun.COM 	int val = 0;
67*11498SJerry.Gilliam@Sun.COM 
68*11498SJerry.Gilliam@Sun.COM 	for (c = *str++; c >= '0' && c <= '9'; c = *str++) {
69*11498SJerry.Gilliam@Sun.COM 		val *= 10;
70*11498SJerry.Gilliam@Sun.COM 		val += c - '0';
71*11498SJerry.Gilliam@Sun.COM 	}
72*11498SJerry.Gilliam@Sun.COM 	if (pos)
73*11498SJerry.Gilliam@Sun.COM 		*pos = str;
74*11498SJerry.Gilliam@Sun.COM 	return (val);
75*11498SJerry.Gilliam@Sun.COM }
76*11498SJerry.Gilliam@Sun.COM 
77*11498SJerry.Gilliam@Sun.COM /*
78*11498SJerry.Gilliam@Sun.COM  * obp_timestamp: based on the OBP flashprom version string of the
79*11498SJerry.Gilliam@Sun.COM  * format "OBP x.y.z YYYY/MM/DD HH:MM" calculate a timestamp based
80*11498SJerry.Gilliam@Sun.COM  * on the year, month, day, hour and minute by turning that into
81*11498SJerry.Gilliam@Sun.COM  * a number of minutes.
82*11498SJerry.Gilliam@Sun.COM  */
83*11498SJerry.Gilliam@Sun.COM static int
obp_timestamp(char * v)84*11498SJerry.Gilliam@Sun.COM obp_timestamp(char *v)
85*11498SJerry.Gilliam@Sun.COM {
86*11498SJerry.Gilliam@Sun.COM 	char *c;
87*11498SJerry.Gilliam@Sun.COM 	int maj, year, month, day, hour, min;
88*11498SJerry.Gilliam@Sun.COM 
89*11498SJerry.Gilliam@Sun.COM 	if (v[0] != 'O' || v[1] != 'B' || v[2] != 'P')
90*11498SJerry.Gilliam@Sun.COM 		return (-1);
91*11498SJerry.Gilliam@Sun.COM 
92*11498SJerry.Gilliam@Sun.COM 	c = v + 3;
93*11498SJerry.Gilliam@Sun.COM 
94*11498SJerry.Gilliam@Sun.COM 	/* Find first non-space character after OBP */
95*11498SJerry.Gilliam@Sun.COM 	while (*c != '\0' && (*c == ' ' || *c == '\t'))
96*11498SJerry.Gilliam@Sun.COM 		c++;
97*11498SJerry.Gilliam@Sun.COM 	if (prom_strlen(c) < 5)		/* need at least "x.y.z" */
98*11498SJerry.Gilliam@Sun.COM 		return (-1);
99*11498SJerry.Gilliam@Sun.COM 
100*11498SJerry.Gilliam@Sun.COM 	maj = strtoi(c, &c);
101*11498SJerry.Gilliam@Sun.COM 	if (maj < 3)
102*11498SJerry.Gilliam@Sun.COM 		return (-1);
103*11498SJerry.Gilliam@Sun.COM 
104*11498SJerry.Gilliam@Sun.COM #if 0 /* XXX - not used */
105*11498SJerry.Gilliam@Sun.COM 	dot = dotdot = 0;
106*11498SJerry.Gilliam@Sun.COM 	if (*c == '.') {
107*11498SJerry.Gilliam@Sun.COM 		dot = strtoi(c + 1, &c);
108*11498SJerry.Gilliam@Sun.COM 
109*11498SJerry.Gilliam@Sun.COM 		/* optional? dot-dot release */
110*11498SJerry.Gilliam@Sun.COM 		if (*c == '.')
111*11498SJerry.Gilliam@Sun.COM 			dotdot = strtoi(c + 1, &c);
112*11498SJerry.Gilliam@Sun.COM 	}
113*11498SJerry.Gilliam@Sun.COM #endif
114*11498SJerry.Gilliam@Sun.COM 
115*11498SJerry.Gilliam@Sun.COM 	/* Find space at the end of version number */
116*11498SJerry.Gilliam@Sun.COM 	while (*c != '\0' && *c != ' ')
117*11498SJerry.Gilliam@Sun.COM 		c++;
118*11498SJerry.Gilliam@Sun.COM 	if (prom_strlen(c) < 11)	/* need at least " xxxx/xx/xx" */
119*11498SJerry.Gilliam@Sun.COM 		return (-1);
120*11498SJerry.Gilliam@Sun.COM 
121*11498SJerry.Gilliam@Sun.COM 	/* Point to first character of date */
122*11498SJerry.Gilliam@Sun.COM 	c++;
123*11498SJerry.Gilliam@Sun.COM 
124*11498SJerry.Gilliam@Sun.COM 	/* Validate date format */
125*11498SJerry.Gilliam@Sun.COM 	if (c[4] != '/' || c[7] != '/')
126*11498SJerry.Gilliam@Sun.COM 		return (-1);
127*11498SJerry.Gilliam@Sun.COM 
128*11498SJerry.Gilliam@Sun.COM 	year = strtoi(c, NULL);
129*11498SJerry.Gilliam@Sun.COM 	month = strtoi(c + 5, NULL);
130*11498SJerry.Gilliam@Sun.COM 	day = strtoi(c + 8, NULL);
131*11498SJerry.Gilliam@Sun.COM 
132*11498SJerry.Gilliam@Sun.COM 	if (year < 1995 || month == 0 || day == 0)
133*11498SJerry.Gilliam@Sun.COM 		return (-1);
134*11498SJerry.Gilliam@Sun.COM 
135*11498SJerry.Gilliam@Sun.COM 	/*
136*11498SJerry.Gilliam@Sun.COM 	 * Find space at the end of date number
137*11498SJerry.Gilliam@Sun.COM 	 */
138*11498SJerry.Gilliam@Sun.COM 	c += 10;
139*11498SJerry.Gilliam@Sun.COM 	while (*c != '\0' && *c != ' ')
140*11498SJerry.Gilliam@Sun.COM 		c++;
141*11498SJerry.Gilliam@Sun.COM 	if (prom_strlen(c) < 6)		/* need at least " xx:xx" */
142*11498SJerry.Gilliam@Sun.COM 		return (-1);
143*11498SJerry.Gilliam@Sun.COM 
144*11498SJerry.Gilliam@Sun.COM 	/* Point to first character of time */
145*11498SJerry.Gilliam@Sun.COM 	c++;
146*11498SJerry.Gilliam@Sun.COM 
147*11498SJerry.Gilliam@Sun.COM 	if (c[2] != ':')
148*11498SJerry.Gilliam@Sun.COM 		return (-1);
149*11498SJerry.Gilliam@Sun.COM 
150*11498SJerry.Gilliam@Sun.COM 	hour = strtoi(c, NULL);
151*11498SJerry.Gilliam@Sun.COM 	min = strtoi(c + 3, NULL);
152*11498SJerry.Gilliam@Sun.COM 
153*11498SJerry.Gilliam@Sun.COM 	return (YEAR(year) + MONTH(month) +
154*11498SJerry.Gilliam@Sun.COM 	    DAY(day) + HOUR(hour) + MINUTE(min));
155*11498SJerry.Gilliam@Sun.COM }
156*11498SJerry.Gilliam@Sun.COM 
157*11498SJerry.Gilliam@Sun.COM /*
158*11498SJerry.Gilliam@Sun.COM  * Check the prom against the obp_min_revs table and complain if
159*11498SJerry.Gilliam@Sun.COM  * the system has an older prom installed.  The actual major/minor/
160*11498SJerry.Gilliam@Sun.COM  * dotdot numbers are not checked, only the date/time stamp.
161*11498SJerry.Gilliam@Sun.COM  */
162*11498SJerry.Gilliam@Sun.COM 
163*11498SJerry.Gilliam@Sun.COM static struct obp_rev_table *flashprom_ortp;
164*11498SJerry.Gilliam@Sun.COM static pnode_t flashprom_node;
165*11498SJerry.Gilliam@Sun.COM static int flashprom_checked;
166*11498SJerry.Gilliam@Sun.COM static int flashprom_return_code;
167*11498SJerry.Gilliam@Sun.COM 
168*11498SJerry.Gilliam@Sun.COM int
check_timestamp(char * model,int tstamp)169*11498SJerry.Gilliam@Sun.COM check_timestamp(char *model, int tstamp)
170*11498SJerry.Gilliam@Sun.COM {
171*11498SJerry.Gilliam@Sun.COM 	int min_tstamp;
172*11498SJerry.Gilliam@Sun.COM 	struct obp_rev_table *ortp;
173*11498SJerry.Gilliam@Sun.COM 
174*11498SJerry.Gilliam@Sun.COM 	for (ortp = obp_min_revs; ortp->model != NULL; ortp++) {
175*11498SJerry.Gilliam@Sun.COM 		if (prom_strcmp(model, ortp->model) == 0) {
176*11498SJerry.Gilliam@Sun.COM 			min_tstamp = obp_timestamp(ortp->version);
177*11498SJerry.Gilliam@Sun.COM 			if (min_tstamp == -1) {
178*11498SJerry.Gilliam@Sun.COM #ifdef	DEBUG
179*11498SJerry.Gilliam@Sun.COM 				prom_printf("prom_version_check: "
180*11498SJerry.Gilliam@Sun.COM 				    "invalid OBP version string in table "
181*11498SJerry.Gilliam@Sun.COM 				    " (entry %d)", (int)(ortp - obp_min_revs));
182*11498SJerry.Gilliam@Sun.COM #endif
183*11498SJerry.Gilliam@Sun.COM 				continue;
184*11498SJerry.Gilliam@Sun.COM 			}
185*11498SJerry.Gilliam@Sun.COM 			if (tstamp < min_tstamp) {
186*11498SJerry.Gilliam@Sun.COM #ifdef	DPRINTF
187*11498SJerry.Gilliam@Sun.COM 				dprintf("prom_version_check: "
188*11498SJerry.Gilliam@Sun.COM 				    "Down-rev OBP detected.  "
189*11498SJerry.Gilliam@Sun.COM 				    "Please update to at least:\n\t%s\n\n",
190*11498SJerry.Gilliam@Sun.COM 				    ortp->version);
191*11498SJerry.Gilliam@Sun.COM #endif
192*11498SJerry.Gilliam@Sun.COM 				flashprom_ortp = ortp;
193*11498SJerry.Gilliam@Sun.COM 				return (1);
194*11498SJerry.Gilliam@Sun.COM 			}
195*11498SJerry.Gilliam@Sun.COM 		}
196*11498SJerry.Gilliam@Sun.COM 	} /* for each obp_rev_table entry */
197*11498SJerry.Gilliam@Sun.COM 
198*11498SJerry.Gilliam@Sun.COM 	return (0);
199*11498SJerry.Gilliam@Sun.COM }
200*11498SJerry.Gilliam@Sun.COM 
201*11498SJerry.Gilliam@Sun.COM static pnode_t
visit(pnode_t node)202*11498SJerry.Gilliam@Sun.COM visit(pnode_t node)
203*11498SJerry.Gilliam@Sun.COM {
204*11498SJerry.Gilliam@Sun.COM 	int tstamp, plen, i;
205*11498SJerry.Gilliam@Sun.COM 	char vers[512], model[64];
206*11498SJerry.Gilliam@Sun.COM 	static pnode_t openprom_node;
207*11498SJerry.Gilliam@Sun.COM 	static char version[] = "version";
208*11498SJerry.Gilliam@Sun.COM 	static char model_name[] = "model";
209*11498SJerry.Gilliam@Sun.COM 	static char flashprom[] = "flashprom";
210*11498SJerry.Gilliam@Sun.COM 
211*11498SJerry.Gilliam@Sun.COM 	/*
212*11498SJerry.Gilliam@Sun.COM 	 * if name isn't 'flashprom', continue.
213*11498SJerry.Gilliam@Sun.COM 	 */
214*11498SJerry.Gilliam@Sun.COM 	if (prom_getproplen(node, OBP_NAME) != sizeof (flashprom))
215*11498SJerry.Gilliam@Sun.COM 		return ((pnode_t)0);
216*11498SJerry.Gilliam@Sun.COM 	(void) prom_getprop(node, OBP_NAME, model);
217*11498SJerry.Gilliam@Sun.COM 	if (prom_strncmp(model, flashprom, sizeof (flashprom)) != 0)
218*11498SJerry.Gilliam@Sun.COM 		return ((pnode_t)0);
219*11498SJerry.Gilliam@Sun.COM 
220*11498SJerry.Gilliam@Sun.COM 	plen = prom_getproplen(node, version);
221*11498SJerry.Gilliam@Sun.COM 	if (plen <= 0 || plen > sizeof (vers))
222*11498SJerry.Gilliam@Sun.COM 		return ((pnode_t)0);
223*11498SJerry.Gilliam@Sun.COM 	(void) prom_getprop(node, version, vers);
224*11498SJerry.Gilliam@Sun.COM 	vers[plen] = '\0';
225*11498SJerry.Gilliam@Sun.COM 
226*11498SJerry.Gilliam@Sun.COM 	/* Make sure it's an OBP flashprom */
227*11498SJerry.Gilliam@Sun.COM 	if (vers[0] != 'O' && vers[1] != 'B' && vers[2] != 'P')
228*11498SJerry.Gilliam@Sun.COM 		return ((pnode_t)0);
229*11498SJerry.Gilliam@Sun.COM 
230*11498SJerry.Gilliam@Sun.COM 	plen = prom_getproplen(node, model_name);
231*11498SJerry.Gilliam@Sun.COM 	if (plen <= 0 || plen > sizeof (model))
232*11498SJerry.Gilliam@Sun.COM 		return ((pnode_t)0);
233*11498SJerry.Gilliam@Sun.COM 	(void) prom_getprop(node, model_name, model);
234*11498SJerry.Gilliam@Sun.COM 	model[plen] = '\0';
235*11498SJerry.Gilliam@Sun.COM 
236*11498SJerry.Gilliam@Sun.COM 	tstamp = obp_timestamp(vers);
237*11498SJerry.Gilliam@Sun.COM 	if (tstamp == -1) {
238*11498SJerry.Gilliam@Sun.COM 		prom_printf("prom_version_check: node contains "
239*11498SJerry.Gilliam@Sun.COM 		    "improperly formatted version property,\n"
240*11498SJerry.Gilliam@Sun.COM 		    "\tnot checking prom version");
241*11498SJerry.Gilliam@Sun.COM 		return ((pnode_t)0);
242*11498SJerry.Gilliam@Sun.COM 	}
243*11498SJerry.Gilliam@Sun.COM 
244*11498SJerry.Gilliam@Sun.COM 	i = check_timestamp(model, tstamp);
245*11498SJerry.Gilliam@Sun.COM 
246*11498SJerry.Gilliam@Sun.COM 	if (i == 0)
247*11498SJerry.Gilliam@Sun.COM 		return ((pnode_t)0);
248*11498SJerry.Gilliam@Sun.COM 
249*11498SJerry.Gilliam@Sun.COM 	/*
250*11498SJerry.Gilliam@Sun.COM 	 * We know that "node"'s flashprom image contains downrev firmware,
251*11498SJerry.Gilliam@Sun.COM 	 * however, a multi-board server might be running correct firmware.
252*11498SJerry.Gilliam@Sun.COM 	 * Check for that case by looking at the "/openprom" node,
253*11498SJerry.Gilliam@Sun.COM 	 * which always contains the running version. (We needed the
254*11498SJerry.Gilliam@Sun.COM 	 * "model" value to be able to do this, so we can use it as
255*11498SJerry.Gilliam@Sun.COM 	 * an index value into the table.)
256*11498SJerry.Gilliam@Sun.COM 	 *
257*11498SJerry.Gilliam@Sun.COM 	 * If it turns out we're running 'current' firmware,
258*11498SJerry.Gilliam@Sun.COM 	 * but detect down-rev firmware, use a different return code.
259*11498SJerry.Gilliam@Sun.COM 	 */
260*11498SJerry.Gilliam@Sun.COM 
261*11498SJerry.Gilliam@Sun.COM 	flashprom_return_code = PROM_VER64_UPGRADE;
262*11498SJerry.Gilliam@Sun.COM 
263*11498SJerry.Gilliam@Sun.COM 	openprom_node = prom_finddevice("/openprom");
264*11498SJerry.Gilliam@Sun.COM 	if (openprom_node == OBP_BADNODE)
265*11498SJerry.Gilliam@Sun.COM 		return (node);
266*11498SJerry.Gilliam@Sun.COM 
267*11498SJerry.Gilliam@Sun.COM 	plen = prom_getproplen(node, version);
268*11498SJerry.Gilliam@Sun.COM 	if (plen <= 0 || plen > sizeof (vers))
269*11498SJerry.Gilliam@Sun.COM 		return (node);
270*11498SJerry.Gilliam@Sun.COM 	(void) prom_getprop(node, version, vers);
271*11498SJerry.Gilliam@Sun.COM 	vers[plen] = '\0';
272*11498SJerry.Gilliam@Sun.COM 
273*11498SJerry.Gilliam@Sun.COM 	if (vers[0] != 'O' && vers[1] != 'B' && vers[2] != 'P') {
274*11498SJerry.Gilliam@Sun.COM 		prom_printf("prom_version_check: "
275*11498SJerry.Gilliam@Sun.COM 		    "unknown <version> string in </openprom>\n");
276*11498SJerry.Gilliam@Sun.COM 		return (node);
277*11498SJerry.Gilliam@Sun.COM 	}
278*11498SJerry.Gilliam@Sun.COM 
279*11498SJerry.Gilliam@Sun.COM 	tstamp = obp_timestamp(vers);
280*11498SJerry.Gilliam@Sun.COM 	if (tstamp == -1) {
281*11498SJerry.Gilliam@Sun.COM 		prom_printf("prom_version_check: "
282*11498SJerry.Gilliam@Sun.COM 		    "</openprom> node <version> property: bad tstamp\n");
283*11498SJerry.Gilliam@Sun.COM 		return (node);
284*11498SJerry.Gilliam@Sun.COM 	}
285*11498SJerry.Gilliam@Sun.COM 
286*11498SJerry.Gilliam@Sun.COM 	i = check_timestamp(model, tstamp);
287*11498SJerry.Gilliam@Sun.COM 	/*
288*11498SJerry.Gilliam@Sun.COM 	 * If that returned zero, then the running version is
289*11498SJerry.Gilliam@Sun.COM 	 * adequate ... so we can 'suggest' instead of 'require'.
290*11498SJerry.Gilliam@Sun.COM 	 */
291*11498SJerry.Gilliam@Sun.COM 	if (i == 0)
292*11498SJerry.Gilliam@Sun.COM 		flashprom_return_code = PROM_VER64_SUGGEST;
293*11498SJerry.Gilliam@Sun.COM 
294*11498SJerry.Gilliam@Sun.COM 	return (node);
295*11498SJerry.Gilliam@Sun.COM }
296*11498SJerry.Gilliam@Sun.COM 
297*11498SJerry.Gilliam@Sun.COM /*
298*11498SJerry.Gilliam@Sun.COM  * visit each node in the device tree, until we get a non-null answer
299*11498SJerry.Gilliam@Sun.COM  */
300*11498SJerry.Gilliam@Sun.COM static pnode_t
walk(pnode_t node)301*11498SJerry.Gilliam@Sun.COM walk(pnode_t node)
302*11498SJerry.Gilliam@Sun.COM {
303*11498SJerry.Gilliam@Sun.COM 	pnode_t id;
304*11498SJerry.Gilliam@Sun.COM 
305*11498SJerry.Gilliam@Sun.COM 	if (visit(node))
306*11498SJerry.Gilliam@Sun.COM 		return (node);
307*11498SJerry.Gilliam@Sun.COM 
308*11498SJerry.Gilliam@Sun.COM 	for (node = prom_childnode(node); node; node = prom_nextnode(node))
309*11498SJerry.Gilliam@Sun.COM 		if ((id = walk(node)) != (pnode_t)0)
310*11498SJerry.Gilliam@Sun.COM 			return (id);
311*11498SJerry.Gilliam@Sun.COM 
312*11498SJerry.Gilliam@Sun.COM 	return ((pnode_t)0);
313*11498SJerry.Gilliam@Sun.COM }
314*11498SJerry.Gilliam@Sun.COM 
315*11498SJerry.Gilliam@Sun.COM /*
316*11498SJerry.Gilliam@Sun.COM  * Check if the prom is 64-bit ready.
317*11498SJerry.Gilliam@Sun.COM  *
318*11498SJerry.Gilliam@Sun.COM  * If it's ready (or the test doesn't apply), return PROM_VER64_OK.
319*11498SJerry.Gilliam@Sun.COM  * If downrev firmware is running, return PROM_VER64_UPGRADE.
320*11498SJerry.Gilliam@Sun.COM  * If downrev firmware is detected (but not running), return PROM_VER64_SUGGEST.
321*11498SJerry.Gilliam@Sun.COM  *
322*11498SJerry.Gilliam@Sun.COM  * For PROM_VER64_UPGRADE and PROM_VER64_SUGGEST return code values:
323*11498SJerry.Gilliam@Sun.COM  * Return the nodeid of the flashprom node in *nodeid.
324*11498SJerry.Gilliam@Sun.COM  * and a printable message in *buf, buflen.
325*11498SJerry.Gilliam@Sun.COM  */
326*11498SJerry.Gilliam@Sun.COM int
prom_version_check(char * buf,size_t buflen,pnode_t * nodeid)327*11498SJerry.Gilliam@Sun.COM prom_version_check(char *buf, size_t buflen, pnode_t *nodeid)
328*11498SJerry.Gilliam@Sun.COM {
329*11498SJerry.Gilliam@Sun.COM 	char *p;
330*11498SJerry.Gilliam@Sun.COM 	pnode_t node = flashprom_node;
331*11498SJerry.Gilliam@Sun.COM 	size_t i;
332*11498SJerry.Gilliam@Sun.COM 
333*11498SJerry.Gilliam@Sun.COM 	/*
334*11498SJerry.Gilliam@Sun.COM 	 * If we already checked, we already know the answer.
335*11498SJerry.Gilliam@Sun.COM 	 */
336*11498SJerry.Gilliam@Sun.COM 	if (flashprom_checked == 0) {
337*11498SJerry.Gilliam@Sun.COM 		flashprom_node = node = walk(prom_rootnode());
338*11498SJerry.Gilliam@Sun.COM 		flashprom_checked = 1;
339*11498SJerry.Gilliam@Sun.COM 	}
340*11498SJerry.Gilliam@Sun.COM 
341*11498SJerry.Gilliam@Sun.COM 	if (nodeid)
342*11498SJerry.Gilliam@Sun.COM 		*nodeid = node;
343*11498SJerry.Gilliam@Sun.COM 
344*11498SJerry.Gilliam@Sun.COM 	if (node == (pnode_t)0) {
345*11498SJerry.Gilliam@Sun.COM 		if (buf && buflen)
346*11498SJerry.Gilliam@Sun.COM 			*buf = '\0';
347*11498SJerry.Gilliam@Sun.COM 		return (PROM_VER64_OK);
348*11498SJerry.Gilliam@Sun.COM 	}
349*11498SJerry.Gilliam@Sun.COM 
350*11498SJerry.Gilliam@Sun.COM 	/* bzero the callers buffer */
351*11498SJerry.Gilliam@Sun.COM 	for (i = buflen, p = buf; i != 0; --i, ++p)
352*11498SJerry.Gilliam@Sun.COM 		*p = '\0';
353*11498SJerry.Gilliam@Sun.COM 
354*11498SJerry.Gilliam@Sun.COM 	/*
355*11498SJerry.Gilliam@Sun.COM 	 * Do a bounded copy of the output string into the callers buffer
356*11498SJerry.Gilliam@Sun.COM 	 */
357*11498SJerry.Gilliam@Sun.COM 	if (buflen <= 1)
358*11498SJerry.Gilliam@Sun.COM 		return (flashprom_return_code);
359*11498SJerry.Gilliam@Sun.COM 
360*11498SJerry.Gilliam@Sun.COM 	(void) prom_strncpy(buf, flashprom_ortp->version, buflen - 1);
361*11498SJerry.Gilliam@Sun.COM 	return (flashprom_return_code);
362*11498SJerry.Gilliam@Sun.COM }
363