+++ /dev/null
-/*
- * Copyright 2003 Digi International (www.digi.com)
- * Scott H Kilau <Scott_Kilau at digi dot com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
- * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-/*
-** downld.c
-**
-** This is the daemon that sends the fep, bios, and concentrator images
-** from user space to the driver.
-** BUGS:
-** If the file changes in the middle of the download, you probably
-** will get what you deserve.
-**
-*/
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/errno.h>
-
-#include "dgap_types.h"
-#include "digi.h"
-#include "dgap_fep5.h"
-
-#include "dgap_downld.h"
-
-#include <string.h>
-#include <malloc.h>
-#include <stddef.h>
-#include <unistd.h>
-
-char *pgm;
-void myperror();
-
-/*
-** This structure is used to keep track of the different images available
-** to give to the driver. It is arranged so that the things that are
-** constants or that have defaults are first inthe strucutre to simplify
-** the table of initializers.
-*/
-struct image_info {
- short type; /* bios, fep, conc */
- short family; /* boards this applies to */
- short subtype; /* subtype */
- int len; /* size of image */
- char *image; /* ioctl struct + image */
- char *name;
- char *fname; /* filename of binary (i.e. "asfep.bin") */
- char *pathname; /* pathname to this binary ("/etc/dgap/xrfep.bin"); */
- time_t mtime; /* Last modification time */
-};
-
-#define IBIOS 0
-#define IFEP 1
-#define ICONC 2
-#define ICONFIG 3
-#define IBAD 4
-
-#define DEFAULT_LOC "/lib/firmware/dgap/"
-
-struct image_info *image_list;
-int nimages, count;
-
-struct image_info images[] = {
-{IBIOS, T_EPC, SUBTYPE, 0, NULL, "EPC/X", "fxbios.bin", DEFAULT_LOC "fxbios.bin", 0 },
-{IFEP, T_EPC, SUBTYPE, 0, NULL, "EPC/X", "fxfep.bin", DEFAULT_LOC "fxfep.bin", 0 },
-{ICONC, T_EPC, SUBTYPE, 0, NULL, "EPC/X", "fxcon.bin", DEFAULT_LOC "fxcon.bin", 0 },
-
-{IBIOS, T_CX, SUBTYPE, 0, NULL, "C/X", "cxbios.bin", DEFAULT_LOC "cxbios.bin", 0 },
-{IFEP, T_CX, SUBTYPE, 0, NULL, "C/X", "cxhost.bin", DEFAULT_LOC "cxhost.bin", 0 },
-
-{IBIOS, T_CX, T_PCIBUS, 0, NULL, "C/X PCI", "cxpbios.bin", DEFAULT_LOC "cxpbios.bin", 0 },
-{IFEP, T_CX, T_PCIBUS, 0, NULL, "C/X PCI", "cxpfep.bin", DEFAULT_LOC "cxpfep.bin", 0 },
-
-{ICONC, T_CX, SUBTYPE, 0, NULL, "C/X", "cxcon.bin", DEFAULT_LOC "cxcon.bin", 0 },
-{ICONC, T_CX, SUBTYPE, 0, NULL, "C/X", "ibmcxcon.bin", DEFAULT_LOC "ibmcxcon.bin", 0 },
-{ICONC, T_CX, SUBTYPE, 0, NULL, "C/X", "ibmencon.bin", DEFAULT_LOC "ibmencon.bin", 0 },
-
-{IBIOS, FAMILY, T_PCXR, 0, NULL, "PCXR", "xrbios.bin", DEFAULT_LOC "xrbios.bin", 0 },
-{IFEP, FAMILY, T_PCXR, 0, NULL, "PCXR", "xrfep.bin", DEFAULT_LOC "xrfep.bin", 0 },
-
-{IBIOS, T_PCLITE, SUBTYPE, 0, NULL, "X/em", "sxbios.bin", DEFAULT_LOC "sxbios.bin", 0 },
-{IFEP, T_PCLITE, SUBTYPE, 0, NULL, "X/em", "sxfep.bin", DEFAULT_LOC "sxfep.bin", 0 },
-
-{IBIOS, T_EPC, T_PCIBUS, 0, NULL, "PCI", "pcibios.bin", DEFAULT_LOC "pcibios.bin", 0 },
-{IFEP, T_EPC, T_PCIBUS, 0, NULL, "PCI", "pcifep.bin", DEFAULT_LOC "pcifep.bin", 0 },
-{ICONFIG, 0, 0, 0, NULL, NULL, "dgap.conf", "/etc/dgap.conf", 0 },
-
-/* IBAD/NULL entry indicating end-of-table */
-
-{IBAD, 0, 0, 0, NULL, NULL, NULL, NULL, 0 }
-
-} ;
-
-int errorprint = 1;
-int nodldprint = 1;
-int debugflag;
-int fd;
-
-struct downld_t *ip; /* Image pointer in current image */
-struct downld_t *dp; /* conc. download */
-
-
-/*
- * The same for either the FEP or the BIOS.
- * Append the downldio header, issue the ioctl, then free
- * the buffer. Not horribly CPU efficient, but quite RAM efficient.
- */
-
-void squirt(int req_type, int bdid, struct image_info *ii)
-{
- struct downldio *dliop;
- int size_buf;
- int sfd;
- struct stat sb;
-
- /*
- * If this binary comes from a file, stat it to see how
- * large it is. Yes, we intentionally do this each
- * time for the binary may change between loads.
- */
-
- if (ii->pathname) {
- sfd = open(ii->pathname, O_RDONLY);
-
- if (sfd < 0 ) {
- myperror(ii->pathname);
- goto squirt_end;
- }
-
- if (fstat(sfd, &sb) == -1 ) {
- myperror(ii->pathname);
- goto squirt_end;
- }
-
- ii->len = sb.st_size;
- }
-
- size_buf = ii->len + sizeof(struct downldio);
-
- /*
- * This buffer will be freed at the end of this function. It is
- * not resilient and should be around only long enough for the d/l
- * to happen.
- */
- dliop = (struct downldio *) malloc(size_buf);
-
- if (dliop == NULL) {
- fprintf(stderr,"%s: can't get %d bytes of memory; aborting\n",
- pgm, size_buf);
- exit (1);
- }
-
- /* Now, stick the image in fepimage. This can come from either
- * the compiled-in image or from the filesystem.
- */
- if (ii->pathname)
- read(sfd, dliop->image.fi.fepimage, ii->len);
- else
- memcpy(dliop ->image.fi.fepimage, ii->image, ii->len);
-
- dliop->req_type = req_type;
- dliop->bdid = bdid;
-
- dliop->image.fi.len = ii->len;
-
- if (debugflag)
- printf("sending %d bytes of %s %s from %s\n",
- ii->len,
- (ii->type == IFEP) ? "FEP" : (ii->type == IBIOS) ? "BIOS" : "CONFIG",
- ii->name ? ii->name : "",
- (ii->pathname) ? ii->pathname : "internal image" );
-
- if (ioctl(fd, DIGI_DLREQ_SET, (char *) dliop) == -1) {
- if(errorprint) {
- fprintf(stderr,
- "%s: warning - download ioctl failed\n",pgm);
- errorprint = 0;
- }
- sleep(2);
- }
-
-squirt_end:
-
- if (ii->pathname) {
- close(sfd);
- }
- free(dliop);
-}
-
-
-/*
- * See if we need to reload the download image in core
- *
- */
-void consider_file_rescan(struct image_info *ii)
-{
- int sfd;
- int len;
- struct stat sb;
-
- /* This operation only makes sense when we're working from a file */
-
- if (ii->pathname) {
-
- sfd = open (ii->pathname, O_RDONLY) ;
- if (sfd < 0 ) {
- myperror(ii->pathname);
- exit(1) ;
- }
-
- if( fstat(sfd,&sb) == -1 ) {
- myperror(ii->pathname);
- exit(1);
- }
-
- /* If the file hasn't changed since we last did this,
- * and we have not done a free() on the image, bail
- */
- if (ii->image && (sb.st_mtime == ii->mtime))
- goto end_rescan;
-
- ii->len = len = sb.st_size;
-
- /* Record the timestamp of the file */
- ii->mtime = sb.st_mtime;
-
- /* image should be NULL unless there is an image malloced
- * in already. Before we malloc again, make sure we don't
- * have a memory leak.
- */
- if ( ii->image ) {
- free( ii->image );
- /* ii->image = NULL; */ /* not necessary */
- }
-
- /* This image will be kept only long enough for the
- * download to happen. After sending the last block,
- * it will be freed
- */
- ii->image = malloc(len) ;
-
- if (ii->image == NULL) {
- fprintf(stderr,
- "%s: can't get %d bytes of memory; aborting\n",
- pgm, len);
- exit (1);
- }
-
- if (read(sfd, ii->image, len) < len) {
- fprintf(stderr,"%s: read error on %s; aborting\n",
- pgm, ii->pathname);
- exit (1);
- }
-
-end_rescan:
- close(sfd);
-
- }
-}
-
-/*
- * Scan for images to match the driver requests
- */
-
-struct image_info * find_conc_image()
-{
- int x;
- struct image_info *i = NULL;
-
- for ( x = 0; x < nimages; x++ ) {
- i=&image_list[x];
-
- if(i->type != ICONC)
- continue;
-
- consider_file_rescan(i) ;
-
- ip = (struct downld_t *) image_list[x].image;
- if (ip == NULL) continue;
-
- /*
- * When I removed Clusterport, I kept only the code that I
- * was SURE wasn't ClusterPort. We may not need the next two
- * lines of code.
- */
- if ((dp->dl_type != 'P' ) && ( ip->dl_srev == dp->dl_srev ))
- return i;
- }
- return NULL;
-}
-
-
-int main(int argc, char **argv)
-{
- struct downldio dlio;
- int offset, bsize;
- int x;
- char *down, *image, *fname;
- struct image_info *ii;
-
- pgm = argv[0];
- dp = &dlio.image.dl; /* conc. download */
-
- while((argc > 2) && !strcmp(argv[1],"-d")) {
- debugflag++ ;
- argc-- ;
- argv++ ;
- }
-
- if(argc < 2) {
- fprintf(stderr,
- "usage: %s download-device [image-file] ...\n",
- pgm);
- exit(1);
- }
-
-
-
- /*
- * Daemonize, unless debugging is turned on.
- */
- if (debugflag == 0) {
- switch (fork())
- {
- case 0:
- break;
-
- case -1:
- return 1;
-
- default:
- return 0;
- }
-
- setsid();
-
- /*
- * The child no longer needs "stdin", "stdout", or "stderr",
- * and should not block processes waiting for them to close.
- */
- fclose(stdin);
- fclose(stdout);
- fclose(stderr);
-
- }
-
- while (1) {
- if( (fd = open(argv[1], O_RDWR)) == -1 ) {
- sleep(1);
- }
- else
- break;
- }
-
- /*
- ** create a list of images to search through when trying to match
- ** requests from the driver. Put images from the command line in
- ** the list before built in images so that the command line images
- ** can override the built in ones.
- */
-
- /* allocate space for the list */
-
- nimages = argc - 2;
-
- /* count the number of default list entries */
-
- for (count = 0; images[count].type != IBAD; ++count) ;
-
- nimages += count;
-
- /* Really should just remove the variable "image_list".... robertl */
- image_list = images;
-
- /* get the images from the command line */
- for(x = 2; x < argc; x++) {
- int xx;
-
- /*
- * strip off any leading path information for
- * determining file type
- */
- if( (fname = strrchr(argv[x],'/')) == NULL)
- fname = argv[x];
- else
- fname++; /* skip the slash */
-
- for (xx = 0; xx < count; xx++) {
- if (strcmp(fname, images[xx].fname) == 0 ) {
- images[xx].pathname = argv[x];
-
- /* image should be NULL until */
- /* space is malloced */
- images[xx].image = NULL;
- }
- }
- }
-
- sleep(3);
-
- /*
- ** Endless loop: get a request from the fep, and service that request.
- */
- for(;;) {
- /* get the request */
- if (debugflag)
- printf("b4 get ioctl...");
-
- if (ioctl(fd,DIGI_DLREQ_GET, &dlio) == -1 ) {
- if (errorprint) {
- fprintf(stderr,
- "%s: warning - download ioctl failed\n",
- pgm);
- errorprint = 0;
- }
- sleep(2);
- } else {
- if (debugflag)
- printf("dlio.req_type is %d bd %d\n",
- dlio.req_type,dlio.bdid);
-
- switch(dlio.req_type) {
- case DLREQ_BIOS:
- /*
- ** find the bios image for this type
- */
- for ( x = 0; x < nimages; x++ ) {
- if(image_list[x].type != IBIOS)
- continue;
-
- if ((dlio.image.fi.type & FAMILY) ==
- image_list[x].family) {
-
- if ( image_list[x].family == T_CX ) {
- if ((dlio.image.fi.type & BUSTYPE)
- == T_PCIBUS ) {
- if ( image_list[x].subtype
- == T_PCIBUS )
- break;
- }
- else {
- break;
- }
- }
- else if ( image_list[x].family == T_EPC ) {
- /* If subtype of image is T_PCIBUS, it is */
- /* a PCI EPC image, so the board must */
- /* have bus type T_PCIBUS to match */
- if ((dlio.image.fi.type & BUSTYPE)
- == T_PCIBUS ) {
- if ( image_list[x].subtype
- == T_PCIBUS )
- break;
- }
- else {
- /* NON PCI EPC doesn't use PCI image */
- if ( image_list[x].subtype
- != T_PCIBUS )
- break;
- }
- }
- else
- break;
- }
- else if ((dlio.image.fi.type & SUBTYPE) == image_list[x].subtype) {
- /* PCXR board will break out of the loop here */
- if ( image_list[x].subtype == T_PCXR ) {
- break;
- }
- }
- }
-
- if ( x >= nimages) {
- /*
- ** no valid images exist
- */
- if(nodldprint) {
- fprintf(stderr,
- "%s: cannot find correct BIOS image\n",
- pgm);
- nodldprint = 0;
- }
- dlio.image.fi.type = -1;
- if (ioctl(fd, DIGI_DLREQ_SET, &dlio) == -1) {
- if (errorprint) {
- fprintf(stderr,
- "%s: warning - download ioctl failed\n",
- pgm);
- errorprint = 0;
- }
- sleep(2);
- }
- break;
- }
- squirt(dlio.req_type, dlio.bdid, &image_list[x]);
- break ;
-
- case DLREQ_FEP:
- /*
- ** find the fep image for this type
- */
- for ( x = 0; x < nimages; x++ ) {
- if(image_list[x].type != IFEP)
- continue;
- if( (dlio.image.fi.type & FAMILY) ==
- image_list[x].family ) {
- if ( image_list[x].family == T_CX ) {
- /* C/X PCI board */
- if ((dlio.image.fi.type & BUSTYPE)
- == T_PCIBUS ) {
- if ( image_list[x].subtype
- == T_PCIBUS )
- break;
- }
- else {
- /* Regular CX */
- break;
- }
- }
- else if ( image_list[x].family == T_EPC ) {
- /* If subtype of image is T_PCIBUS, it is */
- /* a PCI EPC image, so the board must */
- /* have bus type T_PCIBUS to match */
- if ((dlio.image.fi.type & BUSTYPE)
- == T_PCIBUS ) {
- if ( image_list[x].subtype
- == T_PCIBUS )
- break;
- }
- else {
- /* NON PCI EPC doesn't use PCI image */
- if ( image_list[x].subtype
- != T_PCIBUS )
- break;
- }
- }
- else
- break;
- }
- else if ((dlio.image.fi.type & SUBTYPE) == image_list[x].subtype) {
- /* PCXR board will break out of the loop here */
- if ( image_list[x].subtype == T_PCXR ) {
- break;
- }
- }
- }
-
- if ( x >= nimages) {
- /*
- ** no valid images exist
- */
- if(nodldprint) {
- fprintf(stderr,
- "%s: cannot find correct FEP image\n",
- pgm);
- nodldprint = 0;
- }
- dlio.image.fi.type=-1;
- if( ioctl(fd,DIGI_DLREQ_SET,&dlio) == -1 ) {
- if(errorprint) {
- fprintf(stderr,
- "%s: warning - download ioctl failed\n",
- pgm);
- errorprint=0;
- }
- sleep(2);
- }
- break;
- }
- squirt(dlio.req_type, dlio.bdid, &image_list[x]);
- break;
-
- case DLREQ_DEVCREATE:
- {
- char string[1024];
-#if 0
- sprintf(string, "%s /proc/dgap/%d/mknod", DEFSHELL, dlio.bdid);
-#endif
- sprintf(string, "%s /usr/sbin/dgap_updatedevs %d", DEFSHELL, dlio.bdid);
- system(string);
-
- if (debugflag)
- printf("Created Devices.\n");
- if (ioctl(fd, DIGI_DLREQ_SET, &dlio) == -1 ) {
- if(errorprint) {
- fprintf(stderr, "%s: warning - DEVCREATE ioctl failed\n",pgm);
- errorprint = 0;
- }
- sleep(2);
- }
- if (debugflag)
- printf("After ioctl set - Created Device.\n");
- }
-
- break;
-
- case DLREQ_CONFIG:
- for ( x = 0; x < nimages; x++ ) {
- if(image_list[x].type != ICONFIG)
- continue;
- else
- break;
- }
-
- if ( x >= nimages) {
- /*
- ** no valid images exist
- */
- if(nodldprint) {
- fprintf(stderr,
- "%s: cannot find correct CONFIG image\n",
- pgm);
- nodldprint = 0;
- }
- dlio.image.fi.type=-1;
- if (ioctl(fd, DIGI_DLREQ_SET, &dlio) == -1 ) {
- if(errorprint) {
- fprintf(stderr,
- "%s: warning - download ioctl failed\n",
- pgm);
- errorprint=0;
- }
- sleep(2);
- }
- break;
- }
-
- squirt(dlio.req_type, dlio.bdid, &image_list[x]);
- break;
-
- case DLREQ_CONC:
- /*
- ** find the image needed for this download
- */
- if ( dp->dl_seq == 0 ) {
- /*
- ** find image for hardware rev range
- */
- for ( x = 0; x < nimages; x++ ) {
- ii=&image_list[x];
-
- if(image_list[x].type != ICONC)
- continue;
-
- consider_file_rescan(ii) ;
-
- ip = (struct downld_t *) image_list[x].image;
- if (ip == NULL) continue;
-
- /*
- * When I removed Clusterport, I kept only the
- * code that I was SURE wasn't ClusterPort.
- * We may not need the next four lines of code.
- */
-
- if ((dp->dl_type != 'P' ) &&
- (ip->dl_lrev <= dp->dl_lrev ) &&
- ( dp->dl_lrev <= ip->dl_hrev))
- break;
- }
-
- if ( x >= nimages ) {
- /*
- ** No valid images exist
- */
- if(nodldprint) {
- fprintf(stderr,
- "%s: cannot find correct download image %d\n",
- pgm, dp->dl_lrev);
- nodldprint=0;
- }
- continue;
- }
-
- } else {
- /*
- ** find image version required
- */
- if ((ii = find_conc_image()) == NULL ) {
- /*
- ** No valid images exist
- */
- fprintf(stderr,
- "%s: can't find rest of download image??\n",
- pgm);
- continue;
- }
- }
-
- /*
- ** download block of image
- */
-
- offset = 1024 * dp->dl_seq;
-
- /*
- ** test if block requested within image
- */
- if ( offset < ii->len ) {
-
- /*
- ** if it is, determine block size, set segment,
- ** set size, set pointers, and copy block
- */
- if (( bsize = ii->len - offset ) > 1024 )
- bsize = 1024;
-
- /*
- ** copy image version info to download area
- */
- dp->dl_srev = ip->dl_srev;
- dp->dl_lrev = ip->dl_lrev;
- dp->dl_hrev = ip->dl_hrev;
-
- dp->dl_seg = (64 * dp->dl_seq) + ip->dl_seg;
- dp->dl_size = bsize;
-
- down = (char *)&dp->dl_data[0];
- image = (char *)((char *)ip + offset);
-
- memcpy(down, image, bsize);
- }
- else {
- /*
- ** Image has been downloaded, set segment and
- ** size to indicate no more blocks
- */
- dp->dl_seg = ip->dl_seg;
- dp->dl_size = 0;
-
- /* Now, we can release the concentrator */
- /* image from memory if we're running */
- /* from filesystem images */
-
- if (ii->pathname)
- if (ii->image) {
- free(ii->image);
- ii->image = NULL;
- }
- }
-
- if (debugflag)
- printf(
- "sending conc dl section %d to %s from %s\n",
- dp->dl_seq, ii->name,
- ii->pathname ? ii->pathname : "Internal Image");
-
- if (ioctl(fd, DIGI_DLREQ_SET, &dlio) == -1 ) {
- if (errorprint) {
- fprintf(stderr,
- "%s: warning - download ioctl failed\n",
- pgm);
- errorprint=0;
- }
- sleep(2);
- }
- break;
- } /* switch */
- }
- if (debugflag > 1) {
- printf("pausing: "); fflush(stdout);
- fflush(stdin);
- while(getchar() != '\n');
- printf("continuing\n");
- }
- }
-}
-
-/*
-** myperror()
-**
-** Same as normal perror(), but places the program name at the beginning
-** of the message.
-*/
-void myperror(char *s)
-{
- fprintf(stderr,"%s: %s: %s.\n",pgm, s, strerror(errno));
-}