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