1
0
Files
irix-657m-src/irix/cmd/flashio/flashio_everest.c
2022-09-29 17:59:04 +03:00

993 lines
25 KiB
C

/***********************************************************************\
* File: flashio.c *
* Author: jfk *
* *
* Reprograms the IO4 flash proms. The code in this file is *
* virtually identical to the code io arcs/IO4prom/flashprom.c. *
* The major difference is that this code uses the flash prom *
* device driver (which is memory maps into its address space). *
* *
\***********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <limits.h>
#include <string.h>
#include <strings.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/sbd.h>
#include <sys/mman.h>
#include <sys/file.h>
#include <sys/syssgi.h>
#include <sys/systeminfo.h>
#include <sys/times.h>
#include <sys/EVEREST/IP19.h>
#include <sys/EVEREST/everest.h>
#include <sys/EVEREST/evconfig.h>
#include <sys/EVEREST/promhdr.h>
#define DELAY newdelay
#define QUARTER (256 * 1024)
#define SPLIT (512 * 1024)
#define MEG (1024 * 1024)
#define READ_FLASH(_x) \
*((volatile unsigned short*) (FlashPromBase + (_x)))
#define WRITE_FLASH(_x, _y) \
READ_FLASH(_x) = (unsigned short) (_y)
#define qprintf if (!Quiet) printf
#define MAX_ERASE_RETRIES 3000
#define MAX_PROGRAM_RETRIES 50
#define EVCFGINFO_ADDR &(evcfginfo)
/*
* Intel programming commands. Since we have two of these chips ganged
* together, we have to write the commands in both the high and low bytes
* of the halfword.
*/
#define RESET 0xffff
#define SETUP_PROGRAM 0x4040
#define PROGRAM_VERIFY 0xc0c0
#define READ 0x0000
#define SETUP_ERASE 0x2020
#define ERASE 0x2020
#define ERASE_VERIFY 0xa0a0
#define DELAY_6_US 6
#define DELAY_10_US 10
#define DELAY_10_MS 10000
extern unsigned short load_lwin_half(unsigned int, unsigned int);
extern void store_lwin_half(unsigned int, unsigned int, unsigned short);
static void check_system(void);
static void print_version(void);
static void reset_flashprom(void);
static int read_flashprom(char*, evpromhdr_t*, seginfo_t*, char*);
static void program_all_flashproms(evpromhdr_t*, seginfo_t*, unsigned short*);
static int program_board(int, evpromhdr_t*, seginfo_t*, unsigned short*);
static int checkversions(evpromhdr_t *ph, int slot);
static int program_half(unsigned int, unsigned int);
static int erase_flashprom(void);
static int write_block(unsigned int, unsigned short*, unsigned int);
static void print_version(void);
static void newdelay(int);
static int compare_prom(int, evpromhdr_t *, seginfo_t *, char*);
static void compare_all_proms(evpromhdr_t *, seginfo_t *, char*);
static void read_prom(unsigned short *buffer);
static int init_evcfg(void);
static int map_flashprom(int slot);
/* A couple of random global definitions */
static unsigned int FlashPromSize;
static volatile char *FlashPromBase;
static evcfginfo_t evcfginfo;
static int Quiet = 0;
static int Force = 0;
static int TotalLength;
volatile unsigned int prevtime, currtime;
/*
* main reads the contents of the NVRAM from a binary file and
* writes the data directly into the flash prom. It is a little
* dangerous since if some kind of error occurs the flash prom
* can be corrupted.
*/
void
flashio_everest(int argc, char **argv)
{
evpromhdr_t promhdr;
seginfo_t seginfo;
unsigned board;
unsigned boardlist = 0;
unsigned short *buffer;
char filename[100];
int i;
int errflg = 0;
int do_print_version = 0;
int do_flash = 0;
int do_compare = 0;
/* Initialize the program */
check_system();
bzero(filename, 100);
FlashPromSize = MEG;
if (init_evcfg() == -1)
exit(1);
while ((i = getopt(argc, argv, "s:THqfcv")) != EOF) {
switch (i) {
case 's':
do_flash = 1;
board = atoi(optarg);
if (board < 1) {
fprintf(stderr, "flash: slot value must be a number > 0.\n");
exit(1);
}
if (board >= EV_MAX_SLOTS) {
fprintf(stderr, "slot must be between 0 and %d.\n",
EV_MAX_SLOTS);
exit(1);
}
boardlist |= (1 << board);
break;
case 'T':
do_flash = 1;
FlashPromSize = MEG;
break;
case 'H':
do_flash = 1;
FlashPromSize = SPLIT;
break;
case 'q':
Quiet = 1;
break;
case 'f':
do_flash = 1;
Force = 1;
break;
case 'v':
do_print_version = 1;
break;
case 'c':
do_compare = 1;
break;
case '?':
errflg++;
}
}
if (errflg) goto usage;
if (do_print_version && do_flash) {
fprintf(stderr, "flashio: cannot display version number and flash prom at same time\n");
goto usage;
}
if (do_print_version) {
print_version();
exit(0);
}
/* Parse out the filename with appropriate error checking */
if (optind == argc) {
fprintf(stderr, "flashio: must specify a prom image filename\n");
goto usage;
} else if (optind != (argc - 1)) {
fprintf(stderr, "flashio: only one prom image file may be specified\n");
goto usage;
} else {
strcpy(filename, argv[optind]);
}
if ((buffer = malloc(1024 * 1024)) == (unsigned short*) 0) {
fprintf(stderr, "cannot malloc flash buffer\n");
exit(1);
}
if (read_flashprom(filename, &promhdr, &seginfo, (char*) buffer) == -1)
exit(1);
if (do_compare) {
if (boardlist) {
for (i = 0; i < EV_MAX_SLOTS; i++) {
if (boardlist & (1 << i))
compare_prom(i, &promhdr, &seginfo, (char *) buffer);
}
} else {
compare_all_proms(&promhdr, &seginfo, (char *) buffer);
}
exit(0);
}
/* Now program the selected boards */
if (boardlist) {
for (i = 0; i < EV_MAX_SLOTS; i++) {
if (boardlist & (1 << i))
program_board(i, &promhdr, &seginfo, buffer);
}
} else {
(void) program_all_flashproms(&promhdr, &seginfo, buffer);
}
exit(0);
usage:
fprintf(stderr, "Usage: flashio [-s slotnum] [-q] [-f] [-T] [-v] file.bin\n"
"\t-s slot -- Only touch specified slot\n"
"\t-q -- Quiet. Don't print informational messages\n"
"\t-f -- Force the flash process\n"
"\t-T -- Total. Flash all 1 megabyte\n"
"\t-c -- Compare flash proms with prom image\n"
"\t-v -- Display flash prom versions\n");
exit(1);
}
/*
* compare_prom
* Compares the contents of the currently mapped flash prom with the
* prom image.
*/
static int
compare_prom( int slot, evpromhdr_t *promhdr, seginfo_t *seginfo, char *buffer)
{
char *prom_buffer;
char *prom_ptr;
int i, TotalLength;
int last_seg = 0;
int errors = 0;
evbrdinfo_t *brd = &(evcfginfo.ecfg_board[slot]);
/* Make sure this is a legitimate board. Complain if not */
if ((brd->eb_type & EVCLASS_MASK) != EVCLASS_IO) {
fprintf(stderr, "flashio: slot %d does not contain an IO board.\n",
slot);
return -1;
}
if (map_flashprom(slot) == -1)
return -1;
qprintf(" Comparing flashprom in slot %d to prom image...\n", slot);
prom_buffer = malloc(FlashPromSize);
read_prom((unsigned short *) prom_buffer);
prom_ptr = (char *) prom_buffer;
for (i = 0; i < sizeof(evpromhdr_t); i++) {
if (*(((char *)promhdr) + i) != *(prom_ptr + i)) {
errors++;
fprintf(stderr,
"flashio: Mismatch at location 0x%x (prom header)\n"
"between flashprom in slot %d and prom image\n",
prom_ptr + i, slot);
fprintf(stderr, " burned prom = %x file = %x\n",
*(((char *)promhdr) + i), *(prom_ptr + i));
}
}
prom_ptr = (char *) prom_buffer + SEGINFO_OFFSET;
for (i = 0; i < sizeof(seginfo_t); i++) {
if (*(((char *)seginfo) + i) != *(prom_ptr + i)) {
errors++;
fprintf(stderr,
"flashio: Mismatch at location 0x%x (seg info)\n"
"between flashprom in slot %d and prom image\n",
(prom_ptr + i) - prom_buffer, slot);
fprintf(stderr, " burned prom = %x file = %x\n",
*(((char *)seginfo) + i), *(prom_ptr + i));
}
}
for (i = 0; i < seginfo->si_numsegs; i++)
if (seginfo->si_segs[i].seg_offset > seginfo->si_segs[last_seg].seg_offset)
last_seg = i;
TotalLength = seginfo->si_segs[last_seg].seg_offset
+ seginfo->si_segs[last_seg].seg_length;
prom_ptr = (char *) prom_buffer + PROMDATA_OFFSET;
for (i = 0; i < TotalLength; i++) {
if (*(buffer + i) != *(prom_ptr + i)) {
errors++;
fprintf(stderr,
"flashio: Mismatch at location 0x%x (prom data)\n"
"between flashprom in slot %d and prom image\n",
(prom_ptr + i) - prom_buffer, slot);
fprintf(stderr, " burned prom = %x prom image = %x\n",
*(buffer + i), *(prom_ptr + i));
}
}
if (!errors)
qprintf(" Burned prom in slot %d matches prom image\n", slot);
return 0;
}
/*
* compare_all_proms
* Compares the contents of each flash prom on the system with the
* prom image.
*/
static void
compare_all_proms(evpromhdr_t *ph, seginfo_t *si, char *buffer)
{
int slot;
evbrdinfo_t *brd;
for (slot = EV_MAX_SLOTS - 1; slot >= 0; slot--) {
/* Check to see if this is a legitimate IO4 board */
brd = &(evcfginfo.ecfg_board[slot]);
if (EVCLASS(brd->eb_type) == EVCLASS_IO && brd->eb_enabled) {
if (map_flashprom(slot) == -1)
return;
compare_prom(slot, ph, si, buffer);
}
}
}
/*
* read_flashprom()
* Reads the flash prom binary data out of the specified
* file, checks its checksum, and then converts it into a
* form suitable for burning.
*/
static int
read_flashprom(char *file_name, evpromhdr_t *ph, seginfo_t *si, char *buffer)
{
int fd, cnt;
unsigned short *data;
char *curbufptr;
unsigned int numbytes;
unsigned int cksum = 0;
unsigned int i;
/* Open the file */
if ((fd = open(file_name, O_RDONLY)) < 0) {
fprintf(stderr, "flashio: cannot open flash prom source file: %s\n",
file_name);
perror(" Reason");
return -1;
}
/* Read in the header and make sure it looks kosher before we
* fry the flash prom.
*/
if ((cnt = read(fd, ph, sizeof(evpromhdr_t))) < 0) {
fprintf(stderr, "flashio: Could not read prom header structure\n");
close(fd);
return -1;
}
if (cnt != sizeof(evpromhdr_t)) {
fprintf(stderr, "flashio: Incorrect prom header structure size.\n");
close(fd);
return -1;
}
if (ph->prom_magic != PROM_MAGIC && ph->prom_magic != PROM_NEWMAGIC) {
fprintf(stderr, "flashio: Invalid PROM magic number: 0x%x\n",
ph->prom_magic);
close(fd);
return -1;
}
if (ph->prom_length > FlashPromSize) {
fprintf(stderr, "flashio: flash data won't fit in Flash PROM.\n");
close(fd);
return -1;
}
/* If this binary file is in the new prom format, we read in the
* segment table as well and alter the prom magic number so that
* the transfer from the IP19 PROM won't fail. If it isn't a
* new prom, we fake a segment table so that the low-level code
* won't be able to tell the difference.
*/
if (ph->prom_magic == PROM_NEWMAGIC) {
ph->prom_magic = PROM_MAGIC;
if ((cnt = read(fd, si, sizeof(seginfo_t))) < 0) {
fprintf(stderr, "flashio: Could not read segment info table.\n");
close(fd);
return -1;
}
if (cnt != sizeof(seginfo_t)) {
fprintf(stderr, "flashio: Incorrect seg info table size.\n");
close(fd);
return -1;
}
if (si->si_magic != SI_MAGIC) {
fprintf(stderr,
"SI_MAGIC == 0x%x, si->si_magic == 0x%x\n", SI_MAGIC, si->si_magic);
fprintf(stderr, "flashio: Incorrect seg info magic number.\n");
close(fd);
return -1;
}
} else {
/* Synthesize a small segment table for data reading */
si->si_magic = SI_MAGIC;
si->si_numsegs = 1;
si->si_segs[0].seg_type = SEGTYPE_MASTER;
si->si_segs[0].seg_cksum = ph->prom_cksum;
si->si_segs[0].seg_length = ph->prom_length;
si->si_segs[0].seg_offset = PROMDATA_OFFSET;
}
/* Read in the Flash EPROM contents */
curbufptr = (char *) buffer;
for (i = 0; i < si->si_numsegs; i++) {
promseg_t *seg = &(si->si_segs[i]);
char *start = curbufptr;
cksum = 0;
qprintf(" Reading segment %d...\n", i);
numbytes = seg->seg_length;
curbufptr = ((char *) buffer + seg->seg_offset - PROMDATA_OFFSET);
while (numbytes) {
unsigned int count = ((numbytes < 16000) ? numbytes : 16000);
if ((cnt = read(fd, curbufptr, count)) < 0) {
fprintf(stderr, "flashio: Error occurred while reading prom.\n");
close(fd);
return -1;
}
if (cnt == 0) {
fprintf(stderr, "flashio: Unexpected EOF\n");
close(fd);
return -1;
}
curbufptr += cnt;
numbytes -= cnt;
}
/* Checksum the buffer and make sure it seems okay */
numbytes = seg->seg_length;
data = (unsigned short *) start;
while (numbytes) {
cksum += *data++;
numbytes -= 2;
}
if (cksum != seg->seg_cksum) {
fprintf(stderr, "flashio: Checksum error (0x%x, 0x%x).\n",
cksum, seg->seg_cksum);
close(fd);
return -1;
}
} /* end for loop */
close(fd);
return 0;
}
/*
* program_all_flashproms
* Writes the contents of the promhdr and buffer data structures
* into all of the flash proms in the system.
*/
static void
program_all_flashproms(evpromhdr_t *ph, seginfo_t *si, unsigned short *buffer)
{
int slot;
evbrdinfo_t *brd;
for (slot = EV_MAX_SLOTS - 1; slot >= 0; slot--) {
/* Check to see if this is a legitimate IO4 board */
brd = &(evcfginfo.ecfg_board[slot]);
/* Skip over this board if it isn't an IO board or if
* the board is disabled.
*/
if ((brd->eb_type & EVCLASS_MASK) != EVCLASS_IO || !brd->eb_enabled)
continue;
program_board(slot, ph, si, buffer);
}
}
/*
* map_flashprom()
* Maps the IO4 flashprom for the given slot.
*/
static int
map_flashprom(int slot)
{
static int fd = -1;
char fpname[100];
/* Close old file */
if (fd != -1)
close(fd);
sprintf(fpname, "/dev/flash/flash%d", slot);
if ((fd = open(fpname, O_RDWR)) < 0) {
fprintf(stderr, "flashio: cannot open flash driver %s: ", fpname);
perror(" Reason");
return -1;
}
FlashPromBase = (volatile char*) mmap(0, 1024*1024, PROT_WRITE, MAP_SHARED,
fd, 0);
if (FlashPromBase == (volatile char*) -1) {
perror("flashio: mmap failed");
return -1;
}
return 0;
}
/*
* program_board()
* Programs a single IO4 board.
*/
static int
program_board(int slot, evpromhdr_t *ph, seginfo_t *si,
unsigned short *buffer)
{
evbrdinfo_t *brd = &(evcfginfo.ecfg_board[slot]);
int last_seg = 0;
int i;
/* Make sure this is a legitimate board. Complain if not */
if ((brd->eb_type & EVCLASS_MASK) != EVCLASS_IO) {
fprintf(stderr, "flashio: slot %d does not contain an IO board.\n",
slot);
return -1;
}
if (map_flashprom(slot) == -1)
return -1;
if (checkversions(ph, slot) == 1)
return 0;
for (i = 0; i < si->si_numsegs; i++)
if (si->si_segs[i].seg_offset > si->si_segs[last_seg].seg_offset)
last_seg = i;
TotalLength = si->si_segs[last_seg].seg_offset
+ si->si_segs[last_seg].seg_length;
/* Make sure we can map the RTC before trashing the flashprom. */
newdelay(-1);
fprintf(stderr, "Programming IO4 flashproms in slot %d; please wait...\n",
slot);
if (erase_flashprom() == -1) {
qprintf("Could not erase flash prom on IO4 in slot %d\n", slot);
return -1;
}
qprintf(" Writing PROM header to flash PROM...\n");
if (write_block(0, (unsigned short*) ph, sizeof(evpromhdr_t)) == -1)
printf(" Couldn't write header into flash prom\n");
qprintf(" Writing segment table to flash PROM...\n");
if (write_block(SEGINFO_OFFSET, (unsigned short*) si,
sizeof(seginfo_t)) == -1)
qprintf(" Couldn't write segment table into flash prom\n");
qprintf(" Writing PROM contents to flash PROM...\n");
if (write_block(PROMDATA_OFFSET, buffer, TotalLength) == -1)
qprintf(" Couldn't write data into flash prom\n");
reset_flashprom();
compare_prom(slot, ph, si, (char *) buffer);
return 0;
}
int
checkversions(evpromhdr_t *ph, int slot)
{
int oldvers;
/* Read in the version information */
oldvers = READ_FLASH(offsetof(evpromhdr_t, prom_version)) << 16;
oldvers |= READ_FLASH(offsetof(evpromhdr_t, prom_version) + 2);
/* Zero is a special case */
if (oldvers == 0)
return 0;
if ((oldvers == ph->prom_version) && !Force) {
qprintf("IO4 flashprom in slot %d is up-to-date\n", slot);
return 1;
}
if ((oldvers > ph->prom_version) && !Force) {
fprintf(stderr,
"WARNING: The file is older than the image which is currently\n"
" in the IO4 flash prom in slot %d. For this reason,\n"
" the flash proms have not been altered. If you\n"
" wish to revert to a previous version of the\n"
" proms you must use the flashio command's -f flag.\n",
slot
);
exit(1);
}
/* If the image in the file is newer than what is in the proms,
* return 0 to update.
*/
return 0;
}
/*
* program_half
* Program a single halfword using the quick-pulse algorithm
* described in the Intel documentation.
*/
static int
program_half(unsigned int prom_addr, unsigned int value)
{
uint retries = 0; /* Number of retries so far */
int program = 0x4040;
int verify = 0xc0c0;
unsigned int flashval;
for (retries = 0; retries < MAX_PROGRAM_RETRIES; retries++) {
WRITE_FLASH(prom_addr, program);
WRITE_FLASH(prom_addr, value);
DELAY(DELAY_10_US);
WRITE_FLASH(prom_addr, verify);
DELAY(DELAY_6_US);
flashval = READ_FLASH(prom_addr);
if (flashval == value) {
return 0;
}
program = 0xffff;
verify = 0xffff;
/* If the top byte didn't program set the value to redo it */
if ((flashval & 0xff00) != (value & 0xff00)) {
program &= 0x40ff;
verify &= 0xc0ff;
}
/* If the bottom byte didn't program set the value to redo it */
if ((flashval & 0x00ff) != (value & 0x00ff)) {
program &= 0xff40;
verify &= 0xffc0;
}
}
fprintf(stderr, "flashio: could not program 0x%x: wrote 0x%x, read 0x%x\n",
prom_addr, value, READ_FLASH(prom_addr));
return -1;
}
static unsigned short
erase_half(unsigned int offset, unsigned short mask)
{
unsigned int o;
unsigned short data;
WRITE_FLASH(offset, SETUP_ERASE & mask);
WRITE_FLASH(offset, ERASE & mask);
DELAY(DELAY_10_MS);
for (o = offset; o < offset + SPLIT; o+= 2) {
/* Check for all bits set to '1' */
WRITE_FLASH(o, ERASE_VERIFY & mask);
data = READ_FLASH(o);
if (data != 0xffff) {
return(((data & 0xff00) != 0xff00 ? 0xff00 : 0) |
((data & 0xff) != 0xff ? 0xff : 0));
}
}
return(0);
}
/*
* erase_flashprom
* Erases the entire flash EPROM.
*/
static int
erase_flashprom(void)
{
unsigned int i; /* Index variable */
unsigned int retries = 0; /* Number of erase retries */
unsigned short mask; /* mask for program commands */
reset_flashprom();
/* Check to see if the PROM has already been erased */
qprintf(" Checking for empty flash prom...\n");
for (i = 0; i < FlashPromSize; i += 2) {
if (READ_FLASH(i) != 0xffff)
break;
}
if (i == FlashPromSize)
return 0;
/* First we erase the Flash EPROM */
qprintf(" Zeroing out the flash eprom...\n");
for (i = 0; i < FlashPromSize; i += 2) {
if (program_half(i, 0) == -1) {
qprintf(" Couldn't zero halfword %d\n", i);
/*
* Some flashproms were damaged by defective software. This
* kludge allows those proms to work for one more release.
* Flashproms in IRIX 5.3 will likely be larger than 512M.
*/
if ((TotalLength < SPLIT) && (FlashPromSize == MEG)) {
printf("\007================================================="
"==========================\n");
printf(" WARNING: The flash PROM in this IO4 board may need"
" replacement.\n");
printf(" Please contact your service provider.\n");
printf("\007================================================="
"==========================\n");
printf(" Trying to program the lower half only...\n");
FlashPromSize = SPLIT;
return erase_flashprom();
} else {
return -1;
}
}
}
/* Now we repeatedly try to erase all of the data in the flash prom.
* If we find a word which hasn't been cleared, we start all over
* again
*/
qprintf(" Erasing flash eprom...\n");
/* Erase lower half */
mask = 0xffff;
retries = 0;
while (mask = erase_half(0, mask)) {
if (retries++ > MAX_ERASE_RETRIES) {
return(-1);
}
}
/* Erase upper half. */
mask = 0xffff;
retries = 0;
while (mask = erase_half(SPLIT, mask)) {
if (retries++ > MAX_ERASE_RETRIES) {
return(-1);
}
}
return 0;
}
static int
write_block(unsigned int offset, unsigned short *data, unsigned int length)
{
/* Check for alignment */
if (offset & 0x1) {
fprintf(stderr, "flashio (write_block): offset not halfword aligned\n");
return -1;
}
if ((unsigned long) data & 0x1) {
fprintf(stderr, "flashio (write_block): data not halfword aligned\n");
return -1;
}
if (length & 0x1) {
fprintf(stderr, "flashio (write_block): uneven length pass\n");
return -1;
}
while (length) {
if (program_half(offset, *data) == -1)
return -1;
length -= 2;
offset += 2;
data++;
}
return 0;
}
static void
read_prom(unsigned short *buffer)
{
int i;
for (i = 0; i < FlashPromSize; i+=2) {
*buffer = READ_FLASH(i);
buffer++;
}
}
/*
* init_evcfg initializes the local copy of the evcfginfo data
* structure. We play some games to insure that the macros
* in evconfig.h continue to work.
*/
static int
init_evcfg(void)
{
if (syssgi(SGI_GET_EVCONF, &evcfginfo, sizeof(evcfginfo)) == -1) {
perror("flashio: syssgi call for evconf failed");
return -1;
}
/* Make sure it didn't return garbage */
if (evcfginfo.ecfg_magic != EVCFGINFO_MAGIC) {
fprintf(stderr, "flashio: bad magic number in returned evcfg struct\n");
return -1;
}
return 0;
}
#define SEC 1000000
void newdelay(int time)
{
static volatile unsigned int *rtc;
static int inited = 0;
int waittime;
int fd;
__psint_t phys_addr;
int cycleval;
if ((time == -1) && !inited) {
if ((fd = open("/dev/mmem", O_RDONLY)) < 0) {
perror("flashio: Could not open /dev/mmem");
exit(1);
}
if ((phys_addr = syssgi(SGI_QUERY_CYCLECNTR, &cycleval)) == -1) {
perror("flashio: Could not get RTC address");
}
rtc = (volatile unsigned*) mmap(0, 0x1000, PROT_READ, MAP_SHARED, fd,
phys_addr);
if (rtc == (volatile unsigned*) -1) {
perror("flashio: mmap of RTC failed");
exit(1);
}
rtc++;
inited = 1;
return;
}
if (!inited) {
fprintf(stderr, "flashio: newdelay internal error.\n");
exit(1);
}
/* Calculate amount of time to wait */
waittime = time * 47;
prevtime = *rtc;
while (waittime > 0) {
currtime = *rtc;
if (currtime < prevtime)
waittime -= (UINT_MAX - prevtime) + currtime;
else
waittime -= currtime - prevtime;
prevtime = currtime;
}
}
/*
* reset the flashprom. We have to do this multiple times for
* each possible prom segment, because certain flash proms expect
* reset to be done twice in a row (Hitachi 128Kx8's, for example).
*/
static void
reset_flashprom(void)
{
WRITE_FLASH(0, RESET);
WRITE_FLASH(0, RESET);
WRITE_FLASH(QUARTER, RESET);
WRITE_FLASH(QUARTER, RESET);
WRITE_FLASH(SPLIT, RESET);
WRITE_FLASH(SPLIT, RESET);
WRITE_FLASH(3*QUARTER, RESET);
WRITE_FLASH(3*QUARTER, RESET);
}
/*
* check_system()
* Reads the system information and prints an error message
* if this system isn't an everest.
*/
static void
check_system(void)
{
char machine[5];
if (sysinfo(SI_MACHINE, machine, 5) == -1) {
perror("flashio: cannot read system information structure");
exit(1);
}
if (strcmp(machine, "IP19")
&& strcmp(machine, "IP21")
&& strcmp(machine, "IP25")) {
fprintf(stderr, "Flashio is used to reprogram the IO4 flash prom on\n"
"Challenge and Onyx machines. It can only be run on\n"
"those systems.\n\n");
exit(1);
}
}
/*
* print_version()
* Display flash prom version information for master flashprom.
*/
static void
print_version(void)
{
int slot;
unsigned vers;
evbrdinfo_t *brd;
for (slot = EV_MAX_SLOTS - 1; slot >= 0; slot--) {
/* Check to see if this is a legitimate IO4 board */
brd = &(evcfginfo.ecfg_board[slot]);
if (EVCLASS(brd->eb_type) == EVCLASS_IO && brd->eb_enabled) {
if (map_flashprom(slot) == -1)
return;
vers = READ_FLASH(offsetof(evpromhdr_t, prom_version)) << 16;
vers |= READ_FLASH(offsetof(evpromhdr_t, prom_version) + 2);
printf("Slot %2d: Flashprom version is %d\n", slot, vers);
}
}
}