2 * Copyright 2003 Digi International (www.digi.com)
3 * Scott H Kilau <Scott_Kilau at digi dot com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
12 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13 * PURPOSE. See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 * $Id: downld.c,v 1.6 2009/01/14 14:10:54 markh Exp $
25 ** This is the daemon that sends the fep, bios, and concentrator images
26 ** from user space to the driver.
28 ** If the file changes in the middle of the download, you probably
29 ** will get what you deserve.
36 #include <sys/types.h>
38 #include <sys/errno.h>
40 #include "dgap_types.h"
42 #include "dgap_fep5.h"
44 #include "dgap_downld.h"
55 ** This structure is used to keep track of the different images available
56 ** to give to the driver. It is arranged so that the things that are
57 ** constants or that have defaults are first inthe strucutre to simplify
58 ** the table of initializers.
61 short type; /* bios, fep, conc */
62 short family; /* boards this applies to */
63 short subtype; /* subtype */
64 int len; /* size of image */
65 char *image; /* ioctl struct + image */
67 char *fname; /* filename of binary (i.e. "asfep.bin") */
68 char *pathname; /* pathname to this binary ("/etc/dgap/xrfep.bin"); */
69 time_t mtime; /* Last modification time */
78 #define DEFAULT_LOC "/lib/firmware/dgap/"
80 struct image_info *image_list;
83 struct image_info images[] = {
84 {IBIOS, T_EPC, SUBTYPE, 0, NULL, "EPC/X", "fxbios.bin", DEFAULT_LOC "fxbios.bin", 0 },
85 {IFEP, T_EPC, SUBTYPE, 0, NULL, "EPC/X", "fxfep.bin", DEFAULT_LOC "fxfep.bin", 0 },
86 {ICONC, T_EPC, SUBTYPE, 0, NULL, "EPC/X", "fxcon.bin", DEFAULT_LOC "fxcon.bin", 0 },
88 {IBIOS, T_CX, SUBTYPE, 0, NULL, "C/X", "cxbios.bin", DEFAULT_LOC "cxbios.bin", 0 },
89 {IFEP, T_CX, SUBTYPE, 0, NULL, "C/X", "cxhost.bin", DEFAULT_LOC "cxhost.bin", 0 },
91 {IBIOS, T_CX, T_PCIBUS, 0, NULL, "C/X PCI", "cxpbios.bin", DEFAULT_LOC "cxpbios.bin", 0 },
92 {IFEP, T_CX, T_PCIBUS, 0, NULL, "C/X PCI", "cxpfep.bin", DEFAULT_LOC "cxpfep.bin", 0 },
94 {ICONC, T_CX, SUBTYPE, 0, NULL, "C/X", "cxcon.bin", DEFAULT_LOC "cxcon.bin", 0 },
95 {ICONC, T_CX, SUBTYPE, 0, NULL, "C/X", "ibmcxcon.bin", DEFAULT_LOC "ibmcxcon.bin", 0 },
96 {ICONC, T_CX, SUBTYPE, 0, NULL, "C/X", "ibmencon.bin", DEFAULT_LOC "ibmencon.bin", 0 },
98 {IBIOS, FAMILY, T_PCXR, 0, NULL, "PCXR", "xrbios.bin", DEFAULT_LOC "xrbios.bin", 0 },
99 {IFEP, FAMILY, T_PCXR, 0, NULL, "PCXR", "xrfep.bin", DEFAULT_LOC "xrfep.bin", 0 },
101 {IBIOS, T_PCLITE, SUBTYPE, 0, NULL, "X/em", "sxbios.bin", DEFAULT_LOC "sxbios.bin", 0 },
102 {IFEP, T_PCLITE, SUBTYPE, 0, NULL, "X/em", "sxfep.bin", DEFAULT_LOC "sxfep.bin", 0 },
104 {IBIOS, T_EPC, T_PCIBUS, 0, NULL, "PCI", "pcibios.bin", DEFAULT_LOC "pcibios.bin", 0 },
105 {IFEP, T_EPC, T_PCIBUS, 0, NULL, "PCI", "pcifep.bin", DEFAULT_LOC "pcifep.bin", 0 },
106 {ICONFIG, 0, 0, 0, NULL, NULL, "dgap.conf", "/etc/dgap.conf", 0 },
108 /* IBAD/NULL entry indicating end-of-table */
110 {IBAD, 0, 0, 0, NULL, NULL, NULL, NULL, 0 }
119 struct downld_t *ip; /* Image pointer in current image */
120 struct downld_t *dp; /* conc. download */
124 * The same for either the FEP or the BIOS.
125 * Append the downldio header, issue the ioctl, then free
126 * the buffer. Not horribly CPU efficient, but quite RAM efficient.
129 void squirt(int req_type, int bdid, struct image_info *ii)
131 struct downldio *dliop;
137 * If this binary comes from a file, stat it to see how
138 * large it is. Yes, we intentionally do this each
139 * time for the binary may change between loads.
143 sfd = open(ii->pathname, O_RDONLY);
146 myperror(ii->pathname);
150 if (fstat(sfd, &sb) == -1 ) {
151 myperror(ii->pathname);
155 ii->len = sb.st_size ;
158 size_buf = ii->len + sizeof(struct downldio);
161 * This buffer will be freed at the end of this function. It is
162 * not resilient and should be around only long enough for the d/l
165 dliop = (struct downldio *) malloc(size_buf);
168 fprintf(stderr,"%s: can't get %d bytes of memory; aborting\n",
173 /* Now, stick the image in fepimage. This can come from either
174 * the compiled-in image or from the filesystem.
177 read(sfd, dliop->image.fi.fepimage, ii->len);
179 memcpy(dliop ->image.fi.fepimage, ii->image, ii->len);
181 dliop->req_type = req_type;
184 dliop->image.fi.len = ii->len;
187 printf("sending %d bytes of %s %s from %s\n",
189 (ii->type == IFEP) ? "FEP" : (ii->type == IBIOS) ? "BIOS" : "CONFIG",
190 ii->name ? ii->name : "",
191 (ii->pathname) ? ii->pathname : "internal image" );
193 if (ioctl(fd, DIGI_DLREQ_SET, (char *) dliop) == -1) {
196 "%s: warning - download ioctl failed\n",pgm);
212 * See if we need to reload the download image in core
215 void consider_file_rescan(struct image_info *ii)
221 /* This operation only makes sense when we're working from a file */
225 sfd = open (ii->pathname, O_RDONLY) ;
227 myperror(ii->pathname);
231 if( fstat(sfd,&sb) == -1 ) {
232 myperror(ii->pathname);
236 /* If the file hasn't changed since we last did this,
237 * and we have not done a free() on the image, bail
239 if (ii->image && (sb.st_mtime == ii->mtime))
242 ii->len = len = sb.st_size ;
244 /* Record the timestamp of the file */
245 ii->mtime = sb.st_mtime;
247 /* image should be NULL unless there is an image malloced
248 * in already. Before we malloc again, make sure we don't
249 * have a memory leak.
253 /* ii->image = NULL; */ /* not necessary */
256 /* This image will be kept only long enough for the
257 * download to happen. After sending the last block,
260 ii->image = malloc(len) ;
262 if (ii->image == NULL) {
264 "%s: can't get %d bytes of memory; aborting\n",
269 if (read(sfd, ii->image, len) < len) {
270 fprintf(stderr,"%s: read error on %s; aborting\n",
282 * Scan for images to match the driver requests
285 struct image_info * find_conc_image()
288 struct image_info *i = NULL ;
290 for ( x = 0; x < nimages; x++ ) {
296 consider_file_rescan(i) ;
298 ip = (struct downld_t *) image_list[x].image;
299 if (ip == NULL) continue;
302 * When I removed Clusterport, I kept only the code that I
303 * was SURE wasn't ClusterPort. We may not need the next two
306 if ((dp->dl_type != 'P' ) && ( ip->dl_srev == dp->dl_srev ))
313 int main(int argc, char **argv)
315 struct downldio dlio;
318 char *down, *image, *fname;
319 struct image_info *ii;
322 dp = &dlio.image.dl; /* conc. download */
324 while((argc > 2) && !strcmp(argv[1],"-d")) {
332 "usage: %s download-device [image-file] ...\n",
340 * Daemonize, unless debugging is turned on.
342 if (debugflag == 0) {
358 * The child no longer needs "stdin", "stdout", or "stderr",
359 * and should not block processes waiting for them to close.
368 if( (fd = open(argv[1], O_RDWR)) == -1 ) {
376 ** create a list of images to search through when trying to match
377 ** requests from the driver. Put images from the command line in
378 ** the list before built in images so that the command line images
379 ** can override the built in ones.
382 /* allocate space for the list */
386 /* count the number of default list entries */
388 for (count = 0; images[count].type != IBAD; ++count) ;
392 /* Really should just remove the variable "image_list".... robertl */
393 image_list = images ;
395 /* get the images from the command line */
396 for(x = 2; x < argc; x++) {
400 * strip off any leading path information for
401 * determining file type
403 if( (fname = strrchr(argv[x],'/')) == NULL)
406 fname++; /* skip the slash */
408 for (xx = 0; xx < count; xx++) {
409 if (strcmp(fname, images[xx].fname) == 0 ) {
410 images[xx].pathname = argv[x];
412 /* image should be NULL until */
413 /* space is malloced */
414 images[xx].image = NULL ;
422 ** Endless loop: get a request from the fep, and service that request.
425 /* get the request */
427 printf("b4 get ioctl...");
429 if (ioctl(fd,DIGI_DLREQ_GET, &dlio) == -1 ) {
432 "%s: warning - download ioctl failed\n",
439 printf("dlio.req_type is %d bd %d\n",
440 dlio.req_type,dlio.bdid);
442 switch(dlio.req_type) {
445 ** find the bios image for this type
447 for ( x = 0; x < nimages; x++ ) {
448 if(image_list[x].type != IBIOS)
451 if ((dlio.image.fi.type & FAMILY) ==
452 image_list[x].family) {
454 if ( image_list[x].family == T_CX ) {
455 if ((dlio.image.fi.type & BUSTYPE)
457 if ( image_list[x].subtype
465 else if ( image_list[x].family == T_EPC ) {
466 /* If subtype of image is T_PCIBUS, it is */
467 /* a PCI EPC image, so the board must */
468 /* have bus type T_PCIBUS to match */
469 if ((dlio.image.fi.type & BUSTYPE)
471 if ( image_list[x].subtype
476 /* NON PCI EPC doesn't use PCI image */
477 if ( image_list[x].subtype
485 else if ((dlio.image.fi.type & SUBTYPE) == image_list[x].subtype) {
486 /* PCXR board will break out of the loop here */
487 if ( image_list[x].subtype == T_PCXR ) {
495 ** no valid images exist
499 "%s: cannot find correct BIOS image\n",
503 dlio.image.fi.type = -1;
504 if (ioctl(fd, DIGI_DLREQ_SET, &dlio) == -1) {
507 "%s: warning - download ioctl failed\n",
515 squirt(dlio.req_type, dlio.bdid, &image_list[x]);
520 ** find the fep image for this type
522 for ( x = 0; x < nimages; x++ ) {
523 if(image_list[x].type != IFEP)
525 if( (dlio.image.fi.type & FAMILY) ==
526 image_list[x].family ) {
527 if ( image_list[x].family == T_CX ) {
529 if ((dlio.image.fi.type & BUSTYPE)
531 if ( image_list[x].subtype
540 else if ( image_list[x].family == T_EPC ) {
541 /* If subtype of image is T_PCIBUS, it is */
542 /* a PCI EPC image, so the board must */
543 /* have bus type T_PCIBUS to match */
544 if ((dlio.image.fi.type & BUSTYPE)
546 if ( image_list[x].subtype
551 /* NON PCI EPC doesn't use PCI image */
552 if ( image_list[x].subtype
560 else if ((dlio.image.fi.type & SUBTYPE) == image_list[x].subtype) {
561 /* PCXR board will break out of the loop here */
562 if ( image_list[x].subtype == T_PCXR ) {
570 ** no valid images exist
574 "%s: cannot find correct FEP image\n",
578 dlio.image.fi.type=-1;
579 if( ioctl(fd,DIGI_DLREQ_SET,&dlio) == -1 ) {
582 "%s: warning - download ioctl failed\n",
590 squirt(dlio.req_type, dlio.bdid, &image_list[x]);
593 case DLREQ_DEVCREATE:
597 sprintf(string, "%s /proc/dgap/%d/mknod", DEFSHELL, dlio.bdid);
599 sprintf(string, "%s /usr/sbin/dgap_updatedevs %d", DEFSHELL, dlio.bdid);
603 printf("Created Devices.\n");
604 if (ioctl(fd, DIGI_DLREQ_SET, &dlio) == -1 ) {
606 fprintf(stderr, "%s: warning - DEVCREATE ioctl failed\n",pgm);
612 printf("After ioctl set - Created Device.\n");
618 for ( x = 0; x < nimages; x++ ) {
619 if(image_list[x].type != ICONFIG)
627 ** no valid images exist
631 "%s: cannot find correct CONFIG image\n",
635 dlio.image.fi.type=-1;
636 if (ioctl(fd, DIGI_DLREQ_SET, &dlio) == -1 ) {
639 "%s: warning - download ioctl failed\n",
648 squirt(dlio.req_type, dlio.bdid, &image_list[x]);
653 ** find the image needed for this download
655 if ( dp->dl_seq == 0 ) {
657 ** find image for hardware rev range
659 for ( x = 0; x < nimages; x++ ) {
662 if(image_list[x].type != ICONC)
665 consider_file_rescan(ii) ;
667 ip = (struct downld_t *) image_list[x].image;
668 if (ip == NULL) continue;
671 * When I removed Clusterport, I kept only the
672 * code that I was SURE wasn't ClusterPort.
673 * We may not need the next four lines of code.
676 if ((dp->dl_type != 'P' ) &&
677 (ip->dl_lrev <= dp->dl_lrev ) &&
678 ( dp->dl_lrev <= ip->dl_hrev))
682 if ( x >= nimages ) {
684 ** No valid images exist
688 "%s: cannot find correct download image %d\n",
697 ** find image version required
699 if ((ii = find_conc_image()) == NULL ) {
701 ** No valid images exist
704 "%s: can't find rest of download image??\n",
711 ** download block of image
714 offset = 1024 * dp->dl_seq;
717 ** test if block requested within image
719 if ( offset < ii->len ) {
722 ** if it is, determine block size, set segment,
723 ** set size, set pointers, and copy block
725 if (( bsize = ii->len - offset ) > 1024 )
729 ** copy image version info to download area
731 dp->dl_srev = ip->dl_srev;
732 dp->dl_lrev = ip->dl_lrev;
733 dp->dl_hrev = ip->dl_hrev;
735 dp->dl_seg = (64 * dp->dl_seq) + ip->dl_seg;
738 down = (char *)&dp->dl_data[0];
739 image = (char *)((char *)ip + offset);
741 memcpy(down, image, bsize);
745 ** Image has been downloaded, set segment and
746 ** size to indicate no more blocks
748 dp->dl_seg = ip->dl_seg;
751 /* Now, we can release the concentrator */
752 /* image from memory if we're running */
753 /* from filesystem images */
764 "sending conc dl section %d to %s from %s\n",
765 dp->dl_seq, ii->name,
766 ii->pathname ? ii->pathname : "Internal Image");
768 if (ioctl(fd, DIGI_DLREQ_SET, &dlio) == -1 ) {
771 "%s: warning - download ioctl failed\n",
781 printf("pausing: "); fflush(stdout);
783 while(getchar() != '\n');
784 printf("continuing\n");
792 ** Same as normal perror(), but places the program name at the beginning
795 void myperror(char *s)
797 fprintf(stderr,"%s: %s: %s.\n",pgm, s, strerror(errno));