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