Home | History | Annotate | Line # | Download | only in eeprom
eehandlers.c revision 1.15
      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