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