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