4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/promif.h>
27 #include <sys/promimpl.h>
30 #define dprintf prom_printf
34 * Check if the prom is 64-bit ready.
38 * Table listing the minimum prom versions supported by this kernel.
39 * The model value is expected to match the model in the flashprom node.
41 static struct obp_rev_table
{
45 {"SUNW,525-1414", "OBP 3.11.2 1997/12/05 10:25"}, /* pulsar */
46 {"SUNW,525-1672", "OBP 3.7.107 1998/02/19 17:54"}, /* tazmo */
47 {"SUNW,525-1431", "OBP 3.2.16 1998/06/08 16:58"}, /* sunfire */
56 #define YEAR(y) ((y-1) * (NMONTHS * NDAYS * NHOURS * NMINS))
57 #define MONTH(m) ((m-1) * (NDAYS * NHOURS * NMINS))
58 #define DAY(d) ((d-1) * (NHOURS * NMINS))
59 #define HOUR(h) ((h) * (NMINS))
63 strtoi(char *str
, char **pos
)
68 for (c
= *str
++; c
>= '0' && c
<= '9'; c
= *str
++) {
78 * obp_timestamp: based on the OBP flashprom version string of the
79 * format "OBP x.y.z YYYY/MM/DD HH:MM" calculate a timestamp based
80 * on the year, month, day, hour and minute by turning that into
81 * a number of minutes.
84 obp_timestamp(char *v
)
87 int maj
, year
, month
, day
, hour
, min
;
89 if (v
[0] != 'O' || v
[1] != 'B' || v
[2] != 'P')
94 /* Find first non-space character after OBP */
95 while (*c
!= '\0' && (*c
== ' ' || *c
== '\t'))
97 if (prom_strlen(c
) < 5) /* need at least "x.y.z" */
104 #if 0 /* XXX - not used */
107 dot
= strtoi(c
+ 1, &c
);
109 /* optional? dot-dot release */
111 dotdot
= strtoi(c
+ 1, &c
);
115 /* Find space at the end of version number */
116 while (*c
!= '\0' && *c
!= ' ')
118 if (prom_strlen(c
) < 11) /* need at least " xxxx/xx/xx" */
121 /* Point to first character of date */
124 /* Validate date format */
125 if (c
[4] != '/' || c
[7] != '/')
128 year
= strtoi(c
, NULL
);
129 month
= strtoi(c
+ 5, NULL
);
130 day
= strtoi(c
+ 8, NULL
);
132 if (year
< 1995 || month
== 0 || day
== 0)
136 * Find space at the end of date number
139 while (*c
!= '\0' && *c
!= ' ')
141 if (prom_strlen(c
) < 6) /* need at least " xx:xx" */
144 /* Point to first character of time */
150 hour
= strtoi(c
, NULL
);
151 min
= strtoi(c
+ 3, NULL
);
153 return (YEAR(year
) + MONTH(month
) +
154 DAY(day
) + HOUR(hour
) + MINUTE(min
));
158 * Check the prom against the obp_min_revs table and complain if
159 * the system has an older prom installed. The actual major/minor/
160 * dotdot numbers are not checked, only the date/time stamp.
163 static struct obp_rev_table
*flashprom_ortp
;
164 static pnode_t flashprom_node
;
165 static int flashprom_checked
;
166 static int flashprom_return_code
;
169 check_timestamp(char *model
, int tstamp
)
172 struct obp_rev_table
*ortp
;
174 for (ortp
= obp_min_revs
; ortp
->model
!= NULL
; ortp
++) {
175 if (prom_strcmp(model
, ortp
->model
) == 0) {
176 min_tstamp
= obp_timestamp(ortp
->version
);
177 if (min_tstamp
== -1) {
179 prom_printf("prom_version_check: "
180 "invalid OBP version string in table "
181 " (entry %d)", (int)(ortp
- obp_min_revs
));
185 if (tstamp
< min_tstamp
) {
187 dprintf("prom_version_check: "
188 "Down-rev OBP detected. "
189 "Please update to at least:\n\t%s\n\n",
192 flashprom_ortp
= ortp
;
196 } /* for each obp_rev_table entry */
205 char vers
[512], model
[64];
206 static pnode_t openprom_node
;
207 static char version
[] = "version";
208 static char model_name
[] = "model";
209 static char flashprom
[] = "flashprom";
212 * if name isn't 'flashprom', continue.
214 if (prom_getproplen(node
, OBP_NAME
) != sizeof (flashprom
))
216 (void) prom_getprop(node
, OBP_NAME
, model
);
217 if (prom_strncmp(model
, flashprom
, sizeof (flashprom
)) != 0)
220 plen
= prom_getproplen(node
, version
);
221 if (plen
<= 0 || plen
> sizeof (vers
))
223 (void) prom_getprop(node
, version
, vers
);
226 /* Make sure it's an OBP flashprom */
227 if (vers
[0] != 'O' && vers
[1] != 'B' && vers
[2] != 'P')
230 plen
= prom_getproplen(node
, model_name
);
231 if (plen
<= 0 || plen
> sizeof (model
))
233 (void) prom_getprop(node
, model_name
, model
);
236 tstamp
= obp_timestamp(vers
);
238 prom_printf("prom_version_check: node contains "
239 "improperly formatted version property,\n"
240 "\tnot checking prom version");
244 i
= check_timestamp(model
, tstamp
);
250 * We know that "node"'s flashprom image contains downrev firmware,
251 * however, a multi-board server might be running correct firmware.
252 * Check for that case by looking at the "/openprom" node,
253 * which always contains the running version. (We needed the
254 * "model" value to be able to do this, so we can use it as
255 * an index value into the table.)
257 * If it turns out we're running 'current' firmware,
258 * but detect down-rev firmware, use a different return code.
261 flashprom_return_code
= PROM_VER64_UPGRADE
;
263 openprom_node
= prom_finddevice("/openprom");
264 if (openprom_node
== OBP_BADNODE
)
267 plen
= prom_getproplen(node
, version
);
268 if (plen
<= 0 || plen
> sizeof (vers
))
270 (void) prom_getprop(node
, version
, vers
);
273 if (vers
[0] != 'O' && vers
[1] != 'B' && vers
[2] != 'P') {
274 prom_printf("prom_version_check: "
275 "unknown <version> string in </openprom>\n");
279 tstamp
= obp_timestamp(vers
);
281 prom_printf("prom_version_check: "
282 "</openprom> node <version> property: bad tstamp\n");
286 i
= check_timestamp(model
, tstamp
);
288 * If that returned zero, then the running version is
289 * adequate ... so we can 'suggest' instead of 'require'.
292 flashprom_return_code
= PROM_VER64_SUGGEST
;
298 * visit each node in the device tree, until we get a non-null answer
308 for (node
= prom_childnode(node
); node
; node
= prom_nextnode(node
))
309 if ((id
= walk(node
)) != (pnode_t
)0)
316 * Check if the prom is 64-bit ready.
318 * If it's ready (or the test doesn't apply), return PROM_VER64_OK.
319 * If downrev firmware is running, return PROM_VER64_UPGRADE.
320 * If downrev firmware is detected (but not running), return PROM_VER64_SUGGEST.
322 * For PROM_VER64_UPGRADE and PROM_VER64_SUGGEST return code values:
323 * Return the nodeid of the flashprom node in *nodeid.
324 * and a printable message in *buf, buflen.
327 prom_version_check(char *buf
, size_t buflen
, pnode_t
*nodeid
)
330 pnode_t node
= flashprom_node
;
334 * If we already checked, we already know the answer.
336 if (flashprom_checked
== 0) {
337 flashprom_node
= node
= walk(prom_rootnode());
338 flashprom_checked
= 1;
344 if (node
== (pnode_t
)0) {
347 return (PROM_VER64_OK
);
350 /* bzero the callers buffer */
351 for (i
= buflen
, p
= buf
; i
!= 0; --i
, ++p
)
355 * Do a bounded copy of the output string into the callers buffer
358 return (flashprom_return_code
);
360 (void) prom_strncpy(buf
, flashprom_ortp
->version
, buflen
- 1);
361 return (flashprom_return_code
);