xref: /netbsd-src/usr.sbin/eeprom/eehandlers.c (revision c0179c282a5968435315a82f4128c61372c68fc3)
1 /*	$NetBSD: eehandlers.c,v 1.12 2006/11/20 20:36:12 christos Exp $	*/
2 
3 /*-
4  * Copyright (c) 1996 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 #include <sys/types.h>
40 #include <ctype.h>
41 #include <err.h>
42 #include <errno.h>
43 #include <fcntl.h>
44 #include <string.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <time.h>
49 #include <unistd.h>
50 #include <util.h>
51 
52 #include <machine/eeprom.h>
53 #ifdef __sparc__
54 #include <machine/openpromio.h>
55 #endif /* __sparc__ */
56 
57 #include "defs.h"
58 
59 extern	char *path_eeprom;
60 extern	int eval;
61 extern	int update_checksums;
62 extern	int ignore_checksum;
63 extern	int fix_checksum;
64 extern	int cksumfail;
65 extern	u_short writecount;
66 
67 static	char err_str[BUFSIZE];
68 
69 static	void badval (struct keytabent *, char *);
70 static	int doio (struct keytabent *, u_char *, ssize_t, int);
71 
72 struct	keytabent eekeytab[] = {
73 	{ "hwupdate",		0x10,	ee_hwupdate },
74 	{ "memsize",		0x14,	ee_num8 },
75 	{ "memtest",		0x15,	ee_num8 },
76 	{ "scrsize",		0x16,	ee_screensize },
77 	{ "watchdog_reboot",	0x17,	ee_truefalse },
78 	{ "default_boot",	0x18,	ee_truefalse },
79 	{ "bootdev",		0x19,	ee_bootdev },
80 	{ "kbdtype",		0x1e,	ee_kbdtype },
81 	{ "console",		0x1f,	ee_constype },
82 	{ "keyclick",		0x21,	ee_truefalse },
83 	{ "diagdev",		0x22,	ee_bootdev },
84 	{ "diagpath",		0x28,	ee_diagpath },
85 	{ "columns",		0x50,	ee_num8 },
86 	{ "rows",		0x51,	ee_num8 },
87 	{ "ttya_use_baud",	0x58,	ee_truefalse },
88 	{ "ttya_baud",		0x59,	ee_num16 },
89 	{ "ttya_no_rtsdtr",	0x5b,	ee_truefalse },
90 	{ "ttyb_use_baud",	0x60,	ee_truefalse },
91 	{ "ttyb_baud",		0x61,	ee_num16 },
92 	{ "ttyb_no_rtsdtr",	0x63,	ee_truefalse },
93 	{ "banner",		0x68,	ee_banner },
94 	{ "secure",		0,	ee_notsupp },
95 	{ "bad_login",		0,	ee_notsupp },
96 	{ "password",		0,	ee_notsupp },
97 	{ NULL,			0,	ee_notsupp },
98 };
99 
100 #define BARF(kt) {							\
101 	badval((kt), arg);						\
102 	++eval;								\
103 	return;								\
104 }
105 
106 #define FAILEDREAD(kt) {						\
107 	warnx("%s", err_str);						\
108 	warnx("failed to read field `%s'", (kt)->kt_keyword);		\
109 	++eval;								\
110 	return;								\
111 }
112 
113 #define FAILEDWRITE(kt) {						\
114 	warnx("%s", err_str);						\
115 	warnx("failed to update field `%s'", (kt)->kt_keyword);		\
116 	++eval;								\
117 	return;								\
118 }
119 
120 void
121 ee_action(keyword, arg)
122 	char *keyword, *arg;
123 {
124 	struct keytabent *ktent;
125 
126 	for (ktent = eekeytab; ktent->kt_keyword != NULL; ++ktent) {
127 		if (strcmp(ktent->kt_keyword, keyword) == 0) {
128 			(*ktent->kt_handler)(ktent, arg);
129 			return;
130 		}
131 	}
132 
133 	warnx("unknown keyword %s", keyword);
134 	++eval;
135 }
136 
137 void
138 ee_dump()
139 {
140 	struct keytabent *ktent;
141 
142 	for (ktent = eekeytab; ktent->kt_keyword != NULL; ++ktent)
143 		(*ktent->kt_handler)(ktent, NULL);
144 }
145 
146 void
147 ee_hwupdate(ktent, arg)
148 	struct keytabent *ktent;
149 	char *arg;
150 {
151 	time_t t;
152 	char *cp, *cp2;
153 
154 	if (arg) {
155 		if ((strcmp(arg, "now") == 0) ||
156 		    (strcmp(arg, "today") == 0)) {
157 			if ((t = time(NULL)) == (time_t)(-1)) {
158 				warnx("can't get current time");
159 				++eval;
160 				return;
161 			}
162 		} else
163 			if ((t = parsedate(arg, NULL, NULL)) == (time_t)(-1))
164 				BARF(ktent);
165 
166 		if (doio(ktent, (u_char *)&t, sizeof(t), IO_WRITE))
167 			FAILEDWRITE(ktent);
168 	} else
169 		if (doio(ktent, (u_char *)&t, sizeof(t), IO_READ))
170 			FAILEDREAD(ktent);
171 
172 	cp = ctime(&t);
173 	if ((cp2 = strrchr(cp, '\n')) != NULL)
174 		*cp2 = '\0';
175 
176 	printf("%s=%ld (%s)\n", ktent->kt_keyword, (long)t, cp);
177 }
178 
179 void
180 ee_num8(ktent, arg)
181 	struct keytabent *ktent;
182 	char *arg;
183 {
184 	u_char num8 = 0;
185 	u_int num32;
186 	int i;
187 
188 	if (arg) {
189 		for (i = 0; i < (strlen(arg) - 1); ++i)
190 			if (!isdigit((unsigned char)arg[i]))
191 				BARF(ktent);
192 		num32 = atoi(arg);
193 		if (num32 > 0xff)
194 			BARF(ktent);
195 		num8 += num32;
196 		if (doio(ktent, &num8, sizeof(num8), IO_WRITE))
197 			FAILEDWRITE(ktent);
198 	} else
199 		if (doio(ktent, &num8, sizeof(num8), IO_READ))
200 			FAILEDREAD(ktent);
201 
202 	printf("%s=%d\n", ktent->kt_keyword, num8);
203 }
204 
205 void
206 ee_num16(ktent, arg)
207 	struct keytabent *ktent;
208 	char *arg;
209 {
210 	u_int16_t num16 = 0;
211 	u_int num32;
212 	int i;
213 
214 	if (arg) {
215 		for (i = 0; i < (strlen(arg) - 1); ++i)
216 			if (!isdigit((unsigned char)arg[i]))
217 				BARF(ktent);
218 		num32 = atoi(arg);
219 		if (num32 > 0xffff)
220 			BARF(ktent);
221 		num16 += num32;
222 		if (doio(ktent, (u_char *)&num16, sizeof(num16), IO_WRITE))
223 			FAILEDWRITE(ktent);
224 	} else
225 		if (doio(ktent, (u_char *)&num16, sizeof(num16), IO_READ))
226 			FAILEDREAD(ktent);
227 
228 	printf("%s=%d\n", ktent->kt_keyword, num16);
229 }
230 
231 static	struct strvaltabent scrsizetab[] = {
232 	{ "1152x900",		EE_SCR_1152X900 },
233 	{ "1024x1024",		EE_SCR_1024X1024 },
234 	{ "1600x1280",		EE_SCR_1600X1280 },
235 	{ "1440x1440",		EE_SCR_1440X1440 },
236 	{ NULL,			0 },
237 };
238 
239 void
240 ee_screensize(ktent, arg)
241 	struct keytabent *ktent;
242 	char *arg;
243 {
244 	struct strvaltabent *svp;
245 	u_char scsize;
246 
247 	if (arg) {
248 		for (svp = scrsizetab; svp->sv_str != NULL; ++svp)
249 			if (strcmp(svp->sv_str, arg) == 0)
250 				break;
251 		if (svp->sv_str == NULL)
252 			BARF(ktent);
253 
254 		scsize = svp->sv_val;
255 		if (doio(ktent, &scsize, sizeof(scsize), IO_WRITE))
256 			FAILEDWRITE(ktent);
257 	} else {
258 		if (doio(ktent, &scsize, sizeof(scsize), IO_READ))
259 			FAILEDREAD(ktent);
260 
261 		for (svp = scrsizetab; svp->sv_str != NULL; ++svp)
262 			if (svp->sv_val == scsize)
263 				break;
264 		if (svp->sv_str == NULL) {
265 			warnx("unknown %s value %d", ktent->kt_keyword,
266 			    scsize);
267 			return;
268 		}
269 	}
270 	printf("%s=%s\n", ktent->kt_keyword, svp->sv_str);
271 }
272 
273 static	struct strvaltabent truthtab[] = {
274 	{ "true",		EE_TRUE },
275 	{ "false",		EE_FALSE },
276 	{ NULL,			0 },
277 };
278 
279 void
280 ee_truefalse(ktent, arg)
281 	struct keytabent *ktent;
282 	char *arg;
283 {
284 	struct strvaltabent *svp;
285 	u_char truth;
286 
287 	if (arg) {
288 		for (svp = truthtab; svp->sv_str != NULL; ++svp)
289 			if (strcmp(svp->sv_str, arg) == 0)
290 				break;
291 		if (svp->sv_str == NULL)
292 			BARF(ktent);
293 
294 		truth = svp->sv_val;
295 		if (doio(ktent, &truth, sizeof(truth), IO_WRITE))
296 			FAILEDWRITE(ktent);
297 	} else {
298 		if (doio(ktent, &truth, sizeof(truth), IO_READ))
299 			FAILEDREAD(ktent);
300 
301 		for (svp = truthtab; svp->sv_str != NULL; ++svp)
302 			if (svp->sv_val == truth)
303 				break;
304 		if (svp->sv_str == NULL) {
305 			warnx("unknown truth value 0x%x for %s", truth,
306 			    ktent->kt_keyword);
307 			return;
308 		}
309 	}
310 	printf("%s=%s\n", ktent->kt_keyword, svp->sv_str);
311 }
312 
313 void
314 ee_bootdev(ktent, arg)
315 	struct keytabent *ktent;
316 	char *arg;
317 {
318 	u_char dev[5];
319 	int i;
320 	size_t arglen;
321 	char *cp;
322 
323 	if (arg) {
324 		/*
325 		 * The format of the string we accept is the following:
326 		 *	cc(n,n,n)
327 		 * where:
328 		 *	c -- an alphabetical character [a-z]
329 		 *	n -- a number in hexadecimal, between 0 and ff,
330 		 *	     with no leading `0x'.
331 		 */
332 		arglen = strlen(arg);
333 		if (arglen < 9 || arglen > 12 || arg[2] != '(' ||
334 		     arg[arglen - 1] != ')')
335 			BARF(ktent);
336 
337 		/* Handle the first 2 letters. */
338 		for (i = 0; i < 2; ++i) {
339 			if (arg[i] < 'a' || arg[i] > 'z')
340 				BARF(ktent);
341 			dev[i] = (u_char)arg[i];
342 		}
343 
344 		/* Handle the 3 `0x'-less hex values. */
345 		cp = &arg[3];
346 		for (i = 2; i < 5; ++i) {
347 			if (*cp == '\0')
348 				BARF(ktent);
349 
350 			if (*cp >= '0' && *cp <= '9')
351 				dev[i] = *cp++ - '0';
352 			else if (*cp >= 'a' && *cp <= 'f')
353 				dev[i] = 10 + (*cp++ - 'a');
354 			else
355 				BARF(ktent);
356 
357 			/* Deal with a second digit. */
358 			if (*cp >= '0' && *cp <= '9') {
359 				dev[i] <<= 4;
360 				dev[i] &= 0xf0;
361 				dev[i] += *cp++ - '0';
362 			} else if (*cp >= 'a' && *cp <= 'f') {
363 				dev[i] <<= 4;
364 				dev[i] &= 0xf0;
365 				dev[i] += 10 + (*cp++ - 'a');
366 			}
367 
368 			/* Ensure we have the correct delimiter. */
369 			if ((*cp == ',' && i < 4) || (*cp == ')' && i == 4)) {
370 				++cp;
371 				continue;
372 			} else
373 				BARF(ktent);
374 		}
375 		if (doio(ktent, (u_char *)&dev[0], sizeof(dev), IO_WRITE))
376 			FAILEDWRITE(ktent);
377 	} else
378 		if (doio(ktent, (u_char *)&dev[0], sizeof(dev), IO_READ))
379 			FAILEDREAD(ktent);
380 
381 	printf("%s=%c%c(%x,%x,%x)\n", ktent->kt_keyword, dev[0],
382 	     dev[1], dev[2], dev[3], dev[4]);
383 }
384 
385 void
386 ee_kbdtype(ktent, arg)
387 	struct keytabent *ktent;
388 	char *arg;
389 {
390 	u_char kbd = 0;
391 	u_int kbd2;
392 	int i;
393 
394 	if (arg) {
395 		for (i = 0; i < (strlen(arg) - 1); ++i)
396 			if (!isdigit((unsigned char)arg[i]))
397 				BARF(ktent);
398 		kbd2 = atoi(arg);
399 		if (kbd2 > 0xff)
400 			BARF(ktent);
401 		kbd += kbd2;
402 		if (doio(ktent, &kbd, sizeof(kbd), IO_WRITE))
403 			FAILEDWRITE(ktent);
404 	} else
405 		if (doio(ktent, &kbd, sizeof(kbd), IO_READ))
406 			FAILEDREAD(ktent);
407 
408 	printf("%s=%d (%s)\n", ktent->kt_keyword, kbd, kbd ? "other" : "Sun");
409 }
410 
411 static	struct strvaltabent constab[] = {
412 	{ "b&w",		EE_CONS_BW },
413 	{ "ttya",		EE_CONS_TTYA },
414 	{ "ttyb",		EE_CONS_TTYB },
415 	{ "color",		EE_CONS_COLOR },
416 	{ "p4opt",		EE_CONS_P4OPT },
417 	{ NULL,			0 },
418 };
419 
420 void
421 ee_constype(ktent, arg)
422 	struct keytabent *ktent;
423 	char *arg;
424 {
425 	struct strvaltabent *svp;
426 	u_char cons;
427 
428 	if (arg) {
429 		for (svp = constab; svp->sv_str != NULL; ++svp)
430 			if (strcmp(svp->sv_str, arg) == 0)
431 				break;
432 		if (svp->sv_str == NULL)
433 			BARF(ktent);
434 
435 		cons = svp->sv_val;
436 		if (doio(ktent, &cons, sizeof(cons), IO_WRITE))
437 			FAILEDWRITE(ktent);
438 	} else {
439 		if (doio(ktent, &cons, sizeof(cons), IO_READ))
440 			FAILEDREAD(ktent);
441 
442 		for (svp = constab; svp->sv_str != NULL; ++svp)
443 			if (svp->sv_val == cons)
444 				break;
445 		if (svp->sv_str == NULL) {
446 			warnx("unknown type 0x%x for %s", cons,
447 			    ktent->kt_keyword);
448 			return;
449 		}
450 	}
451 	printf("%s=%s\n", ktent->kt_keyword, svp->sv_str);
452 
453 }
454 
455 void
456 ee_diagpath(ktent, arg)
457 	struct keytabent *ktent;
458 	char *arg;
459 {
460 	char path[40];
461 
462 	memset(path, 0, sizeof(path));
463 	if (arg) {
464 		if (strlen(arg) > sizeof(path))
465 			BARF(ktent);
466 		memcpy(path, arg, sizeof path);
467 		if (doio(ktent, (u_char *)&path[0], sizeof(path), IO_WRITE))
468 			FAILEDWRITE(ktent);
469 	} else
470 		if (doio(ktent, (u_char *)&path[0], sizeof(path), IO_READ))
471 			FAILEDREAD(ktent);
472 
473 	printf("%s=%s\n", ktent->kt_keyword, path);
474 }
475 
476 void
477 ee_banner(ktent, arg)
478 	struct keytabent *ktent;
479 	char *arg;
480 {
481 	char string[80];
482 	u_char enable;
483 	struct keytabent kt;
484 
485 	kt.kt_keyword = "enable_banner";
486 	kt.kt_offset = EE_BANNER_ENABLE_LOC;
487 	kt.kt_handler = ee_notsupp;
488 
489 	memset(string, '\0', sizeof(string));
490 	if (arg) {
491 		if (strlen(arg) > sizeof(string))
492 			BARF(ktent);
493 		if (*arg != '\0') {
494 			enable = EE_TRUE;
495 			memcpy(string, arg, sizeof string);
496 			if (doio(ktent, (u_char *)string,
497 			    sizeof(string), IO_WRITE))
498 				FAILEDWRITE(ktent);
499 		} else {
500 			enable = EE_FALSE;
501 			if (doio(ktent, (u_char *)string,
502 			    sizeof(string), IO_READ))
503 				FAILEDREAD(ktent);
504 		}
505 
506 		if (doio(&kt, &enable, sizeof(enable), IO_WRITE))
507 			FAILEDWRITE(&kt);
508 	} else {
509 		if (doio(ktent, (u_char *)string, sizeof(string), IO_READ))
510 			FAILEDREAD(ktent);
511 		if (doio(&kt, &enable, sizeof(enable), IO_READ))
512 			FAILEDREAD(&kt);
513 	}
514 	printf("%s=%s (%s)\n", ktent->kt_keyword, string,
515 	    enable == EE_TRUE ? "enabled" : "disabled");
516 }
517 
518 /* ARGSUSED */
519 void
520 ee_notsupp(ktent, arg)
521 	struct keytabent *ktent;
522 	char *arg;
523 {
524 
525 	warnx("field `%s' not yet supported", ktent->kt_keyword);
526 }
527 
528 static void
529 badval(ktent, arg)
530 	struct keytabent *ktent;
531 	char *arg;
532 {
533 
534 	warnx("inappropriate value `%s' for field `%s'", arg,
535 	    ktent->kt_keyword);
536 }
537 
538 static int
539 doio(ktent, buf, len, wr)
540 	struct keytabent *ktent;
541 	u_char *buf;
542 	ssize_t len;
543 	int wr;
544 {
545 	int fd, rval = 0;
546 	u_char *buf2;
547 
548 	buf2 = (u_char *)calloc(1, len);
549 	if (buf2 == NULL) {
550 		memcpy(err_str, "memory allocation failed", sizeof err_str);
551 		return (1);
552 	}
553 
554 	fd = open(path_eeprom, wr == IO_WRITE ? O_RDWR : O_RDONLY, 0640);
555 	if (fd < 0) {
556 		(void)snprintf(err_str, sizeof err_str, "open: %s: %s", path_eeprom,
557 		    strerror(errno));
558 		free(buf2);
559 		return (1);
560 	}
561 
562 	if (lseek(fd, (off_t)ktent->kt_offset, SEEK_SET) < (off_t)0) {
563 		(void)snprintf(err_str, sizeof err_str, "lseek: %s: %s",
564 		    path_eeprom, strerror(errno));
565 		rval = 1;
566 		goto done;
567 	}
568 
569 	if (read(fd, buf2, len) != len) {
570 		(void)snprintf(err_str, sizeof err_str, "read: %s: %s",
571 		    path_eeprom, strerror(errno));
572 		return (1);
573 	}
574 
575 	if (wr == IO_WRITE) {
576 		if (memcmp(buf, buf2, len) == 0)
577 			goto done;
578 
579 		if (lseek(fd, (off_t)ktent->kt_offset, SEEK_SET) < (off_t)0) {
580 			(void)snprintf(err_str, sizeof err_str, "lseek: %s: %s",
581 			    path_eeprom, strerror(errno));
582 			rval = 1;
583 			goto done;
584 		}
585 
586 		++update_checksums;
587 		if (write(fd, buf, len) < 0) {
588 			(void)snprintf(err_str, sizeof err_str, "write: %s: %s",
589 			    path_eeprom, strerror(errno));
590 			rval = 1;
591 			goto done;
592 		}
593 	} else
594 		memmove(buf, buf2, len);
595 
596  done:
597 	free(buf2);
598 	(void)close(fd);
599 	return (rval);
600 }
601 
602 /*
603  * Read from eeLastHwUpdate to just before eeReserved.  Calculate
604  * a checksum, and deposit 3 copies of it sequentially starting at
605  * eeChecksum[0].  Increment the write count, and deposit 3 copies
606  * of it sequentially starting at eeWriteCount[0].
607  */
608 void
609 ee_updatechecksums()
610 {
611 	struct keytabent kt;
612 	u_char checkme[EE_SIZE - EE_HWUPDATE_LOC];
613 	u_char checksum;
614 	int i;
615 
616 	kt.kt_keyword = "eeprom contents";
617 	kt.kt_offset = EE_HWUPDATE_LOC;
618 	kt.kt_handler = ee_notsupp;
619 
620 	if (doio(&kt, checkme, sizeof(checkme), IO_READ)) {
621 		cksumfail = 1;
622 		FAILEDREAD(&kt);
623 	}
624 
625 	checksum = ee_checksum(checkme, sizeof(checkme));
626 
627 	kt.kt_keyword = "eeprom checksum";
628 	for (i = 0; i < 4; ++i) {
629 		kt.kt_offset = EE_CKSUM_LOC + (i * sizeof(checksum));
630 		if (doio(&kt, &checksum, sizeof(checksum), IO_WRITE)) {
631 			cksumfail = 1;
632 			FAILEDWRITE(&kt);
633 		}
634 	}
635 
636 	kt.kt_keyword = "eeprom writecount";
637 	for (i = 0; i < 4; ++i) {
638 		kt.kt_offset = EE_WC_LOC + (i * sizeof(writecount));
639 		if (doio(&kt, (u_char *)&writecount, sizeof(writecount),
640 		    IO_WRITE)) {
641 			cksumfail = 1;
642 			FAILEDWRITE(&kt);
643 		}
644 	}
645 }
646 
647 void
648 ee_verifychecksums()
649 {
650 	struct keytabent kt;
651 	u_char checkme[EE_SIZE - EE_HWUPDATE_LOC];
652 	u_char checksum, ochecksum[3];
653 	u_short owritecount[3];
654 
655 	/*
656 	 * Verify that the EEPROM's write counts match, and update the
657 	 * global copy for use later.
658 	 */
659 	kt.kt_keyword = "eeprom writecount";
660 	kt.kt_offset = EE_WC_LOC;
661 	kt.kt_handler = ee_notsupp;
662 
663 	if (doio(&kt, (u_char *)&owritecount, sizeof(owritecount), IO_READ)) {
664 		cksumfail = 1;
665 		FAILEDREAD(&kt);
666 	}
667 
668 	if (owritecount[0] != owritecount[1] ||
669 	    owritecount[0] != owritecount[2]) {
670 		warnx("eeprom writecount mismatch %s",
671 		    ignore_checksum ? "(ignoring)" :
672 		    (fix_checksum ? "(fixing)" : ""));
673 
674 		if (!ignore_checksum && !fix_checksum) {
675 			cksumfail = 1;
676 			return;
677 		}
678 
679 		writecount = MAXIMUM(owritecount[0], owritecount[1]);
680 		writecount = MAXIMUM(writecount, owritecount[2]);
681 	} else
682 		writecount = owritecount[0];
683 
684 	/*
685 	 * Verify that the EEPROM's checksums match and are correct.
686 	 */
687 	kt.kt_keyword = "eeprom checksum";
688 	kt.kt_offset = EE_CKSUM_LOC;
689 
690 	if (doio(&kt, ochecksum, sizeof(ochecksum), IO_READ)) {
691 		cksumfail = 1;
692 		FAILEDREAD(&kt);
693 	}
694 
695 	if (ochecksum[0] != ochecksum[1] ||
696 	    ochecksum[0] != ochecksum[2]) {
697 		warnx("eeprom checksum mismatch %s",
698 		    ignore_checksum ? "(ignoring)" :
699 		    (fix_checksum ? "(fixing)" : ""));
700 
701 		if (!ignore_checksum && !fix_checksum) {
702 			cksumfail = 1;
703 			return;
704 		}
705 	}
706 
707 	kt.kt_keyword = "eeprom contents";
708 	kt.kt_offset = EE_HWUPDATE_LOC;
709 
710 	if (doio(&kt, checkme, sizeof(checkme), IO_READ)) {
711 		cksumfail = 1;
712 		FAILEDREAD(&kt);
713 	}
714 
715 	checksum = ee_checksum(checkme, sizeof(checkme));
716 
717 	if (ochecksum[0] != checksum) {
718 		warnx("eeprom checksum incorrect %s",
719 		    ignore_checksum ? "(ignoring)" :
720 		    (fix_checksum ? "(fixing)" : ""));
721 
722 		if (!ignore_checksum && !fix_checksum) {
723 			cksumfail = 1;
724 			return;
725 		}
726 	}
727 
728 	if (fix_checksum)
729 		ee_updatechecksums();
730 }
731 
732 u_char
733 ee_checksum(area, len)
734 	u_char *area;
735 	size_t len;
736 {
737 	u_char sum = 0;
738 
739 	while (len--)
740 		sum += *area++;
741 
742 	return (0x100 - sum);
743 }
744