3cf94cbcf7737cf417525de48fb6aad68bb85a59
[dragonfly.git] / sbin / atm / fore_dnld / fore_dnld.c
1 /*
2  *
3  * ===================================
4  * HARP  |  Host ATM Research Platform
5  * ===================================
6  *
7  *
8  * This Host ATM Research Platform ("HARP") file (the "Software") is
9  * made available by Network Computing Services, Inc. ("NetworkCS")
10  * "AS IS".  NetworkCS does not provide maintenance, improvements or
11  * support of any kind.
12  *
13  * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
14  * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
15  * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
16  * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
17  * In no event shall NetworkCS be responsible for any damages, including
18  * but not limited to consequential damages, arising from or relating to
19  * any use of the Software or related support.
20  *
21  * Copyright 1994-1998 Network Computing Services, Inc.
22  *
23  * Copies of this Software may be made, however, the above copyright
24  * notice must be reproduced on all copies.
25  *
26  *      @(#) $FreeBSD: src/sbin/atm/fore_dnld/fore_dnld.c,v 1.6.2.2 2000/12/11 01:03:24 obrien Exp $
27  *      @(#) $DragonFly: src/sbin/atm/fore_dnld/fore_dnld.c,v 1.5 2004/02/04 17:39:58 joerg Exp $
28  */
29
30 /*
31  * User utilities
32  * --------------
33  *
34  * Download (pre)processed microcode into Fore Series-200 host adapter
35  * Interact with i960 uart on Fore Series-200 host adapter
36  *
37  */
38
39 #include <sys/param.h>
40 #include <sys/mman.h>
41 #include <sys/socket.h>
42 #include <sys/stat.h>
43 #include <net/if.h>
44 #include <netatm/atm.h>
45 #include <netatm/atm_if.h>
46 #include <netatm/atm_sap.h>
47 #include <netatm/atm_sys.h>
48 #include <netatm/atm_ioctl.h>
49 #include <dev/atm/hfa/fore.h>
50 #include <dev/atm/hfa/fore_aali.h>
51 #include <dev/atm/hfa/fore_slave.h>
52
53 #include <ctype.h>
54 #include <fcntl.h>
55 #include <paths.h>
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #if (defined(BSD) && (BSD >= 199103))
60 #include <termios.h>
61 #else
62 #include <termio.h>
63 #endif  /* !BSD */
64 #include <unistd.h>
65
66 extern u_char pca200e_microcode[];
67 extern int pca200e_microcode_size;
68
69 #ifdef sun
70 #define DEV_NAME "/dev/sbus%d"
71 #endif  /* sun */
72 #if (defined(BSD) && (BSD >= 199103))
73 #define DEV_NAME _PATH_KMEM
74 #endif  /* BSD */
75
76 #define MAX_CHECK       60
77
78 int     comm_mode = 0;
79 char    *progname;
80
81 int     tty;
82 cc_t    vmin, vtime;
83 #if (defined(BSD) && (BSD >= 199103))
84 struct termios sgtty;
85 #define TCSETA  TIOCSETA
86 #define TCGETA  TIOCGETA
87 #else
88 struct termio sgtty;
89 #endif  /* !BSD */
90
91 int     endian = 0;
92 int     verbose = 0;
93 int     reset = 0;
94
95 char    line[132];
96 int     lineptr = 0;
97
98 Mon960 *Uart;
99
100 int     sendbinfile(char *, u_char *);
101
102 void
103 delay(cnt)
104         int     cnt;
105 {
106         usleep(cnt);
107 }
108
109 unsigned long
110 CP_READ ( unsigned long val )
111 {
112         if ( endian )
113                 return ( ntohl ( val ) );
114         else
115                 return ( val );
116 }
117
118 unsigned long
119 CP_WRITE ( unsigned long val )
120 {
121         if ( endian )
122                 return ( htonl ( val ) );
123         else
124                 return ( val );
125 }
126
127 /*
128  * Print an error message and exit.
129  *
130  * Arguments:
131  *      none
132  *
133  * Returns:
134  *      none
135  */
136 void
137 error ( char *msg )
138 {
139         printf ( "%s\n", msg );
140         exit (1);
141 }
142
143 /*
144  * Get a byte for the uart and if printing, display it.
145  *
146  * Arguments:
147  *      prn                             Are we displaying characters
148  *
149  * Returns:
150  *      c                               Character from uart
151  */
152 char
153 getbyte ( int prn )
154 {
155         int     c;
156
157         while ( ! ( CP_READ(Uart->mon_xmithost) & UART_VALID ) )
158                 delay(10);
159
160         c = ( CP_READ(Uart->mon_xmithost) & UART_DATAMASK );
161         Uart->mon_xmithost = CP_WRITE(UART_READY);
162
163         /*
164          * We need to introduce a delay in here or things tend to hang...
165          */
166         delay(10000);
167
168         if ( lineptr >= sizeof(line) )
169                 lineptr = 0;
170
171         /*
172          * Save character into line
173          */
174         line[lineptr++] = c;
175
176         if (verbose) {
177                 if (isprint(c) || (c == '\n') || (c == '\r'))
178                         putc(c, stdout);
179         }
180         return ( c & 0xff );
181 }
182
183 /*
184  * Loop getting characters from uart into static string until eol. If printing,
185  * display the line retrieved.
186  *
187  * Arguments:
188  *      prn                             Are we displaying characters
189  *
190  * Returns:
191  *      none                            Line in global string 'line[]'
192  */
193 void
194 getline ( int prn )
195 {
196         char    c = '\0';
197         int     i = 0;
198
199         while ( c != '>' && c != '\n' && c != '\r' )
200         {
201                 c = getbyte(0);
202                 if ( ++i >= sizeof(line) )
203                 {
204                         if ( prn )
205                                 printf ( "%s", line );
206                         i = 0;
207                 }
208         }
209
210         /*
211          * Terminate line
212          */
213         line[lineptr] = 0;
214         lineptr = 0;
215
216 }
217
218 /*
219  * Send a byte to the i960
220  *
221  * Arguments:
222  *      c                               Character to send
223  *
224  * Returns:
225  *      none
226  */
227 void
228 xmit_byte ( unsigned char c, int dn )
229 {
230         int     val;
231
232         while ( CP_READ(Uart->mon_xmitmon) != UART_READY )
233         {
234                 if ( CP_READ(Uart->mon_xmithost) & UART_VALID )
235                         getbyte ( 0 );
236                 if ( !dn ) delay ( 10000 );
237         }
238         val = ( c | UART_VALID );
239         Uart->mon_xmitmon = CP_WRITE( val );
240         if ( !dn ) delay ( 10000 );
241         if ( CP_READ(Uart->mon_xmithost) & UART_VALID )
242                 getbyte ( 0 );
243
244 }
245
246 /*
247  * Transmit a line to the i960. Eol must be included as part of text to transmit.
248  *
249  * Arguments:
250  *      line                    Character string to transmit
251  *      len                     len of string. This allows us to include NULL's
252  *                                      in the string/block to be transmitted.
253  *
254  * Returns:
255  *      none
256  */
257 void
258 xmit_to_i960 ( char *line, int len, int dn )
259 {
260         int     i;
261
262         for ( i = 0; i < len; i++ )
263                 xmit_byte ( line[i], dn );
264 }
265
266 /*
267  * Send autobaud sequence to i960 monitor
268  *
269  * Arguments:
270  *      none
271  *
272  * Returns:
273  *      none
274  */
275 void
276 autobaud(void)
277 {
278         if ( strncmp ( line, "Mon960", 6 ) == 0 )
279                 xmit_to_i960 ( "\r\n\r\n\r\n\r\n", 8, 0 );
280 }
281
282 /*
283  * Reset tty to initial state
284  *
285  * Arguments:
286  *      ret             error code for exit()
287  *
288  * Returns:
289  *      none
290  *
291  */
292 void
293 finish ( int ret )
294 {
295         sgtty.c_lflag |= ( ICANON | ECHO );
296         sgtty.c_cc[VMIN] = vmin;
297         sgtty.c_cc[VTIME] = vtime;
298         ioctl ( tty, TCSETA, &sgtty );
299         exit ( ret );
300 }
301
302 /*
303  * Utility to strip off any leading path information from a filename
304  *
305  * Arguments:
306  *      path            pathname to strip
307  *
308  * Returns:
309  *      fname           striped filename
310  *
311  */
312 char *
313 basename ( char *path )
314 {
315         char *fname;
316
317         if ( ( fname = strrchr ( path, '/' ) ) != NULL )
318                 fname++;
319         else
320                 fname = path;
321
322         return ( fname );
323 }
324
325 /*
326  * ASCII constants
327  */
328 #define         SOH             001
329 #define         STX             002
330 #define         ETX             003
331 #define         EOT             004
332 #define         ENQ             005
333 #define         ACK             006
334 #define         LF              012
335 #define         CR              015
336 #define         NAK             025
337 #define         SYN             026
338 #define         CAN             030
339 #define         ESC             033
340
341 #define         NAKMAX          2
342 #define         ERRORMAX        10
343 #define         RETRYMAX        5
344
345 #define         CRCCHR          'C'
346 #define         CTRLZ           032
347
348 #define         BUFSIZE         128
349
350 #define         W               16
351 #define         B               8
352
353 /*
354  * crctab - CRC-16 constant array...
355  *     from Usenet contribution by Mark G. Mendel, Network Systems Corp.
356  *     (ihnp4!umn-cs!hyper!mark)
357  */
358 unsigned short crctab[1<<B] = {
359     0x0000,  0x1021,  0x2042,  0x3063,  0x4084,  0x50a5,  0x60c6,  0x70e7,
360     0x8108,  0x9129,  0xa14a,  0xb16b,  0xc18c,  0xd1ad,  0xe1ce,  0xf1ef,
361     0x1231,  0x0210,  0x3273,  0x2252,  0x52b5,  0x4294,  0x72f7,  0x62d6,
362     0x9339,  0x8318,  0xb37b,  0xa35a,  0xd3bd,  0xc39c,  0xf3ff,  0xe3de,
363     0x2462,  0x3443,  0x0420,  0x1401,  0x64e6,  0x74c7,  0x44a4,  0x5485,
364     0xa56a,  0xb54b,  0x8528,  0x9509,  0xe5ee,  0xf5cf,  0xc5ac,  0xd58d,
365     0x3653,  0x2672,  0x1611,  0x0630,  0x76d7,  0x66f6,  0x5695,  0x46b4,
366     0xb75b,  0xa77a,  0x9719,  0x8738,  0xf7df,  0xe7fe,  0xd79d,  0xc7bc,
367     0x48c4,  0x58e5,  0x6886,  0x78a7,  0x0840,  0x1861,  0x2802,  0x3823,
368     0xc9cc,  0xd9ed,  0xe98e,  0xf9af,  0x8948,  0x9969,  0xa90a,  0xb92b,
369     0x5af5,  0x4ad4,  0x7ab7,  0x6a96,  0x1a71,  0x0a50,  0x3a33,  0x2a12,
370     0xdbfd,  0xcbdc,  0xfbbf,  0xeb9e,  0x9b79,  0x8b58,  0xbb3b,  0xab1a,
371     0x6ca6,  0x7c87,  0x4ce4,  0x5cc5,  0x2c22,  0x3c03,  0x0c60,  0x1c41,
372     0xedae,  0xfd8f,  0xcdec,  0xddcd,  0xad2a,  0xbd0b,  0x8d68,  0x9d49,
373     0x7e97,  0x6eb6,  0x5ed5,  0x4ef4,  0x3e13,  0x2e32,  0x1e51,  0x0e70,
374     0xff9f,  0xefbe,  0xdfdd,  0xcffc,  0xbf1b,  0xaf3a,  0x9f59,  0x8f78,
375     0x9188,  0x81a9,  0xb1ca,  0xa1eb,  0xd10c,  0xc12d,  0xf14e,  0xe16f,
376     0x1080,  0x00a1,  0x30c2,  0x20e3,  0x5004,  0x4025,  0x7046,  0x6067,
377     0x83b9,  0x9398,  0xa3fb,  0xb3da,  0xc33d,  0xd31c,  0xe37f,  0xf35e,
378     0x02b1,  0x1290,  0x22f3,  0x32d2,  0x4235,  0x5214,  0x6277,  0x7256,
379     0xb5ea,  0xa5cb,  0x95a8,  0x8589,  0xf56e,  0xe54f,  0xd52c,  0xc50d,
380     0x34e2,  0x24c3,  0x14a0,  0x0481,  0x7466,  0x6447,  0x5424,  0x4405,
381     0xa7db,  0xb7fa,  0x8799,  0x97b8,  0xe75f,  0xf77e,  0xc71d,  0xd73c,
382     0x26d3,  0x36f2,  0x0691,  0x16b0,  0x6657,  0x7676,  0x4615,  0x5634,
383     0xd94c,  0xc96d,  0xf90e,  0xe92f,  0x99c8,  0x89e9,  0xb98a,  0xa9ab,
384     0x5844,  0x4865,  0x7806,  0x6827,  0x18c0,  0x08e1,  0x3882,  0x28a3,
385     0xcb7d,  0xdb5c,  0xeb3f,  0xfb1e,  0x8bf9,  0x9bd8,  0xabbb,  0xbb9a,
386     0x4a75,  0x5a54,  0x6a37,  0x7a16,  0x0af1,  0x1ad0,  0x2ab3,  0x3a92,
387     0xfd2e,  0xed0f,  0xdd6c,  0xcd4d,  0xbdaa,  0xad8b,  0x9de8,  0x8dc9,
388     0x7c26,  0x6c07,  0x5c64,  0x4c45,  0x3ca2,  0x2c83,  0x1ce0,  0x0cc1,
389     0xef1f,  0xff3e,  0xcf5d,  0xdf7c,  0xaf9b,  0xbfba,  0x8fd9,  0x9ff8,
390     0x6e17,  0x7e36,  0x4e55,  0x5e74,  0x2e93,  0x3eb2,  0x0ed1,  0x1ef0
391     };
392
393 /*
394  * Hacked up xmodem protocol. Transmits the file 'filename' down to the i960
395  * using the xmodem protocol.
396  *
397  * Arguments:
398  *      filename                        name of file to transmit
399  *
400  * Returns:
401  *      0                               file transmitted
402  *      -1                              unable to send file
403  */
404 int
405 xmitfile ( char *filename )
406 {
407         int     fd;
408         int     numsect;
409         int     sectnum;
410         struct stat stb;
411         char    c;
412         char    sendresp;
413         int     crcmode = 0;
414         int     attempts = 0;
415         int     errors;
416         int     sendfin;
417         int     extrachr;
418         char    buf[BUFSIZE + 6];
419         char    blockbuf[BUFSIZE + 6];
420         int     bufcntr;
421         int     bbufcntr;
422         int     bufsize = BUFSIZE;
423         int     checksum;
424
425         /*
426          * Try opening file
427          */
428         if ( ( fd = open ( filename, O_RDONLY ) ) < 0 )
429         {
430                 return -1;
431         }
432         stat ( filename, &stb );
433
434         /*
435          * Determine number of 128 bytes sectors to transmit
436          */
437         numsect = ( stb.st_size / 128 ) + 1;
438
439         if ( verbose )
440                 fprintf ( stderr, "Downloading %d sectors from %s\n",
441                         numsect, filename );
442
443         /*
444          * Send DO'wnload' command to i960
445          */
446         xmit_to_i960 ( "do\r\n", 4, 0 );
447         /*
448          * Wait for response from i960 indicating download in progress
449          */
450         while ( strncmp ( line, "Downloading", 11 ) != 0 )
451                 getline ( verbose );
452         
453
454         /*
455          * Get startup character from i960
456          */
457         do {
458                 while ( ( c = getbyte(0) ) != NAK && c != CRCCHR )
459                         if ( ++attempts > NAKMAX )
460                                 error ( "Remote system not responding" );
461
462                 if ( c == CRCCHR )
463                         crcmode = 1;
464
465         } while ( c != NAK && c != CRCCHR );
466
467         sectnum = 1;
468         attempts = errors = sendfin = extrachr = 0;
469
470         /*
471          * Loop over each sector to be sent
472          */
473         do {
474                 if ( extrachr >= 128 )
475                 {
476                         extrachr = 0;
477                         numsect++;
478                 }
479
480                 if ( sectnum > 0 )
481                 {
482                         /*
483                          * Read a sectors worth of data from the file into
484                          * an internal buffer.
485                          */
486                         for ( bufcntr = 0; bufcntr < bufsize; )
487                         {
488                                 int n;
489                                 /*
490                                  * Check for EOF
491                                  */
492                                 if ( ( n = read ( fd, &c, 1 ) ) == 0 )
493                                 {
494                                         sendfin = 1;
495                                         if ( !bufcntr )
496                                                 break;
497                                         buf[bufcntr++] = CTRLZ;
498                                         continue;
499                                 }
500                                 buf[bufcntr++] = c;
501                         }
502                         if ( !bufcntr )
503                                 break;
504                 }
505
506                 /*
507                  * Fill in xmodem protocol values. Block size and sector number
508                  */
509                 bbufcntr = 0;
510                 blockbuf[bbufcntr++] = (bufsize == 1024) ? STX : SOH;
511                 blockbuf[bbufcntr++] = sectnum;
512                 blockbuf[bbufcntr++] = ~sectnum;
513
514                 checksum = 0;
515
516                 /*
517                  * Loop over the internal buffer computing the checksum of the
518                  * sector
519                  */
520                 for ( bufcntr = 0; bufcntr < bufsize; bufcntr++ )
521                 {
522                         blockbuf[bbufcntr++] = buf[bufcntr];
523
524                         if ( crcmode )
525                                 checksum = (checksum<<B) ^ crctab[(checksum>>(W-B)) ^ buf[bufcntr]];
526                         else
527                                 checksum = ((checksum + buf[bufcntr]) & 0xff);
528
529                 }
530
531                 /*
532                  * Place the checksum at the end of the transmit buffer
533                  */
534                 if ( crcmode )
535                 {
536                         checksum &= 0xffff;
537                         blockbuf[bbufcntr++] = ((checksum >> 8) & 0xff);
538                         blockbuf[bbufcntr++] = (checksum & 0xff);
539                 } else
540                         blockbuf[bbufcntr++] = checksum;
541
542                 attempts = 0;
543
544                 /*
545                  * Make several attempts to send the data to the i960
546                  */
547                 do
548                 {
549                         /*
550                          * Transmit the sector + protocol to the i960
551                          */
552                         xmit_to_i960 ( blockbuf, bbufcntr, 1 );
553
554                         /*
555                          * Inform user where we're at
556                          */
557                         if ( verbose )
558                                 printf ( "Sector %3d %3dk\r",
559                                     sectnum, (sectnum * bufsize) / 1024 );
560
561                         attempts++;
562                         /*
563                          * Get response from i960
564                          */
565                         sendresp = getbyte(0);
566
567                         /*
568                          * If i960 didn't like the sector
569                          */
570                         if ( sendresp != ACK )
571                         {
572                                 errors++;
573
574                                 /*
575                                  * Are we supposed to cancel the transfer?
576                                  */
577                                 if ( ( sendresp & 0x7f ) == CAN )
578                                         if ( getbyte(0) == CAN )
579                                                 error ( "Send canceled at user's request" );
580                         }
581
582                 } while ( ( sendresp != ACK ) && ( attempts < RETRYMAX ) && ( errors < ERRORMAX ) );
583
584                 /*
585                  * Next sector
586                  */
587                 sectnum++;
588
589         } while ( !sendfin && ( attempts < RETRYMAX ) && ( errors < ERRORMAX ) );
590
591         /*
592          * Did we expire all our allows attempts?
593          */
594         if ( attempts >= RETRYMAX )
595         {
596                 xmit_byte ( CAN, 1 ), xmit_byte ( CAN, 1 ), xmit_byte ( CAN, 1 );
597                 error ( "Remote system not responding" );
598         }
599
600         /*
601          * Check for too many transmission errors
602          */
603         if ( errors >= ERRORMAX )
604         {
605                 xmit_byte ( CAN, 1 ), xmit_byte ( CAN, 1 ), xmit_byte ( CAN, 1 );
606                 error ( "Too many errors in transmission" );
607         }
608
609         attempts = 0;
610
611         /*
612          * Indicate the transfer is complete
613          */
614         xmit_byte ( EOT, 1 );
615
616         /*
617          * Wait until i960 acknowledges us
618          */
619         while ( ( c = getbyte(0) ) != ACK && ( ++attempts < RETRYMAX ) )
620                 xmit_byte ( EOT, 1 );
621
622         if ( attempts >= RETRYMAX )
623                 error ( "Remote system not responding on completion" );
624
625         /*
626          * After download, we'll see a few more command 
627          * prompts as the CP does its stuff. Ignore them.
628          */
629         while ( strncmp ( line, "=>", 2 ) != 0 )
630                 getline ( verbose );
631
632         while ( strncmp ( line, "=>", 2 ) != 0 )
633                 getline ( verbose );
634
635         while ( strncmp ( line, "=>", 2 ) != 0 )
636                 getline ( verbose );
637
638         /*
639          * Tell the i960 to start executing the downloaded code
640          */
641         xmit_to_i960 ( "go\r\n", 4, 0 );
642
643         /*
644          * Get the messages the CP will spit out
645          * after the GO command.
646          */
647         getline ( verbose );
648         getline ( verbose );
649
650         close ( fd );
651
652         return ( 0 );
653 }
654
655
656 int
657 loadmicrocode ( u_char *ucode, int size, u_char *ram )
658 {
659         struct {
660                 u_long  Id;
661                 u_long  fver;
662                 u_long  start;
663                 u_long  entry;
664         } binhdr;
665 #ifdef sun
666         union {
667                 u_long  w;
668                 char    c[4];
669         } w1, w2;
670 #endif
671         u_char  *bufp;
672         u_long  *lp;
673
674
675         /*
676          * Check that we understand this header
677          */
678         memcpy(&binhdr, ucode, sizeof(binhdr));
679         if ( strncmp ( (caddr_t)&binhdr.Id, "fore", 4 ) != 0 ) {
680                 fprintf ( stderr, "Unrecognized format in micorcode file." );
681                 return ( -1 );
682         }
683
684 #ifdef  sun
685         /*
686          * We always swap the SunOS microcode file...
687          */
688         endian = 1;
689
690         /*
691          * We need to swap the header start/entry words...
692          */
693         w1.w = binhdr.start;
694         for ( n = 0; n < sizeof(u_long); n++ )
695                 w2.c[3-n] = w1.c[n];
696         binhdr.start = w2.w;
697         w1.w = binhdr.entry;
698         for ( n = 0; n < sizeof(u_long); n++ )
699                 w2.c[3-n] = w1.c[n];
700         binhdr.entry = w2.w;
701 #endif  /* sun */
702
703         /*
704          * Set pointer to RAM load location
705          */
706         bufp = (ram + binhdr.start);
707
708         /*
709          * Load file
710          */
711         if ( endian ) {
712                 int     i;
713
714                 lp = (u_long *) ucode;
715                 /* Swap buffer */
716                 for ( i = 0; i < size / sizeof(long); i++ )
717 #ifndef sun
718                         lp[i] = CP_WRITE(lp[i]);
719 #else
720                 {
721                         int     j;
722
723                         w1.w = lp[i];
724                         for ( j = 0; j < 4; j++ )
725                                 w2.c[3-j] = w1.c[j];
726                         lp[i] = w2.w;
727                 }
728 #endif
729         }
730         bcopy ( (caddr_t)ucode, bufp, size );
731
732         /*
733          * With .bin extension, we need to specify start address on 'go'
734          * command.
735          */
736         {
737                 char    cmd[80];
738
739                 sprintf ( cmd, "go %lx\r\n", binhdr.entry );
740
741                 xmit_to_i960 ( cmd, strlen ( cmd ), 0 );
742
743                 while ( strncmp ( line, cmd, strlen(cmd) - 3 ) != 0 ) 
744                         getline ( verbose );
745
746                 if ( verbose )
747                         printf("\n");
748         }
749         return ( 0 );
750 }
751
752 int
753 sendbinfile ( char *fname, u_char *ram )
754 {
755         struct {
756                 u_long  Id;
757                 u_long  fver;
758                 u_long  start;
759                 u_long  entry;
760         } binhdr;
761 #ifdef sun
762         union {
763                 u_long  w;
764                 char    c[4];
765         } w1, w2;
766 #endif
767         int     fd;
768         int     n;
769         int     cnt = 0;
770         u_char  *bufp;
771         long    buffer[1024];
772
773         /*
774          * Try opening file
775          */
776         if ( ( fd = open ( fname, O_RDONLY ) ) < 0 )
777                 return ( -1 );
778
779         /*
780          * Read the .bin header from the file
781          */
782         if ( ( read ( fd, &binhdr, sizeof(binhdr) ) ) != sizeof(binhdr) )
783         {
784                 close ( fd );
785                 return ( -1 );
786         }
787
788         /*
789          * Check that we understand this header
790          */
791         if ( strncmp ( (caddr_t)&binhdr.Id, "fore", 4 ) != 0 ) {
792                 fprintf ( stderr, "Unrecognized format in micorcode file." );
793                 close ( fd );
794                 return ( -1 );
795         }
796
797 #ifdef  sun
798         /*
799          * We always swap the SunOS microcode file...
800          */
801         endian = 1;
802
803         /*
804          * We need to swap the header start/entry words...
805          */
806         w1.w = binhdr.start;
807         for ( n = 0; n < sizeof(u_long); n++ )
808                 w2.c[3-n] = w1.c[n];
809         binhdr.start = w2.w;
810         w1.w = binhdr.entry;
811         for ( n = 0; n < sizeof(u_long); n++ )
812                 w2.c[3-n] = w1.c[n];
813         binhdr.entry = w2.w;
814 #endif  /* sun */
815
816         /*
817          * Rewind the file
818          */
819         lseek ( fd, 0, 0 );
820
821         /*
822          * Set pointer to RAM load location
823          */
824         bufp = (ram + binhdr.start);
825
826         /*
827          * Load file
828          */
829         if ( endian ) {
830                 /*
831                  * Need to swap longs - copy file into temp buffer
832                  */
833                 while ( ( n = read ( fd, (char *)buffer, sizeof(buffer))) > 0 )
834                 {
835                         int     i;
836
837                         /* Swap buffer */
838                         for ( i = 0; i < sizeof(buffer) / sizeof(long); i++ )
839 #ifndef sun
840                                 buffer[i] = CP_WRITE(buffer[i]);
841 #else
842                         {
843                                 int     j;
844
845                                 w1.w = buffer[i];
846                                 for ( j = 0; j < 4; j++ )
847                                         w2.c[3-j] = w1.c[j];
848                                 buffer[i] = w2.w;
849                         }
850 #endif
851
852                         /*
853                          * Copy swapped buffer into CP RAM
854                          */
855                         cnt++;
856                         bcopy ( (caddr_t)buffer, bufp, n );
857                         if ( verbose )
858                                 printf ( "%d\r", cnt );
859                         bufp += n;
860                 }
861         } else {
862             while ( ( n = read ( fd, bufp, 128 ) ) > 0 )
863             {
864                 cnt++;
865                 if ( verbose )
866                         printf ( "%d\r", cnt );
867                 bufp += n;
868             }
869         }
870
871         /*
872          * With .bin extension, we need to specify start address on 'go'
873          * command.
874          */
875         {
876                 char    cmd[80];
877
878                 sprintf ( cmd, "go %lx\r\n", binhdr.entry );
879
880                 xmit_to_i960 ( cmd, strlen ( cmd ), 0 );
881
882                 while ( strncmp ( line, cmd, strlen(cmd) - 3 ) != 0 )
883                         getline ( verbose );
884
885                 if ( verbose )
886                         printf("\n");
887         }
888
889         close ( fd );
890         return ( 0 );
891 }
892
893
894 /*
895  * Program to download previously processed microcode to series-200 host adapter
896  */
897 int
898 main( int argc, char **argv )
899 {
900         int     fd;                     /* mmap for Uart */
901         u_char  *ram;                   /* pointer to RAM */
902         Mon960  *Mon;                   /* Uart */
903         Aali    *aap;
904         char    c;
905         int     i, err;
906         int     binary = 0;             /* Send binary file */
907         caddr_t buf;                    /* Ioctl buffer */
908         char    bus_dev[80];            /* Bus device to mmap on */
909         struct atminfreq req;
910         struct air_cfg_rsp *air;        /* Config info response structure */
911         int     buf_len;                /* Size of ioctl buffer */
912         char    *devname = "\0";        /* Device to download */
913         char    *dirname = NULL;        /* Directory path to objd files */
914         char    *objfile = NULL;        /* Command line object filename */
915         u_char  *ucode = NULL;          /* Pointer to microcode */
916         int     ucode_size = 0;         /* Length of microcode */
917         char    *sndfile = NULL;        /* Object filename to download */
918         char    filename[64];           /* Constructed object filename */
919         char    base[64];               /* sba200/sba200e/pca200e basename */
920         int     ext = 0;                /* 0 == bin 1 == objd */
921         struct stat sbuf;               /* Used to find if .bin or .objd */
922         extern char *optarg;
923
924         progname = (char *)basename(argv[0]);
925         comm_mode = strcmp ( progname, "fore_comm" ) == 0;
926
927         while ( ( c = getopt ( argc, argv, "i:d:f:berv" ) ) != -1 )
928             switch ( c ) {
929                 case 'b':
930                         binary++;
931                         break;
932                 case 'd':
933                         dirname = (char *)strdup ( optarg );
934                         break;
935                 case 'e':
936                         endian++;
937                         break;
938                 case 'i':
939                         devname = (char *)strdup ( optarg );
940                         break;
941                 case 'f':
942                         objfile = (char *)strdup ( optarg );
943                         break;
944                 case 'v':
945                         verbose++;
946                         break;
947                 case 'r':
948                         reset++;
949                         break;
950                 case '?':
951                         printf ( "usage: %s [-v] [-i intf] [-d dirname] [-f objfile]\n", argv[0] );
952                         exit ( 2 );
953             }
954         
955         /*
956          * Unbuffer stdout
957          */
958         setbuf ( stdout, NULL );
959                 
960         if ( ( fd = socket ( AF_ATM, SOCK_DGRAM, 0 ) ) < 0 )
961         {
962                 perror ( "Cannot create ATM socket" );
963                 exit ( 1 );
964         }
965         /*
966          * Over allocate memory for returned data. This allows
967          * space for IOCTL reply info as well as config info.
968          */
969         buf_len = 4 * sizeof(struct air_cfg_rsp);
970         if ( ( buf = (caddr_t)malloc(buf_len) ) == NULL )
971         {
972                 perror ( "Cannot allocate memory for reply" );
973                 exit ( 1 );
974         }
975         /*
976          * Fill in request paramaters
977          */
978         req.air_opcode = AIOCS_INF_CFG;
979         req.air_buf_addr = buf;
980         req.air_buf_len = buf_len;
981
982         /*
983          * Copy interface name into ioctl request
984          */
985         strcpy ( req.air_cfg_intf, devname );
986
987         /*
988          * Issue ioctl
989          */
990         if ( ( ioctl ( fd, AIOCINFO, (caddr_t)&req ) ) ) {
991                 perror ( "ioctl (AIOCSINFO)" );
992                 exit ( 1 );
993         }
994         /*
995          * Reset buffer pointer
996          */
997         req.air_buf_addr = buf;
998
999         /*
1000          * Close socket
1001          */
1002         close ( fd );
1003
1004         /*
1005          * Loop through all attached adapters
1006          */
1007         for (; req.air_buf_len >= sizeof(struct air_cfg_rsp); 
1008                         buf += sizeof(struct air_cfg_rsp),
1009                         req.air_buf_len -= sizeof(struct air_cfg_rsp)) {
1010
1011                 /*
1012                  * Point to vendor info
1013                  */
1014                 air = (struct air_cfg_rsp *)buf;
1015
1016                 if (air->acp_vendor == VENDOR_FORE )
1017                 {
1018                         /*
1019                          * Create /dev name
1020                          */
1021 #ifdef sun
1022                         sprintf ( bus_dev, DEV_NAME, air->acp_busslot );
1023 #else
1024                         sprintf ( bus_dev, DEV_NAME );
1025 #endif
1026
1027                         /*
1028                          * Setup signal handlers
1029                          */
1030                         signal ( SIGINT, SIG_IGN );
1031                         signal ( SIGQUIT, SIG_IGN );
1032                 
1033                         /*
1034                          * If comm_mode, setup terminal for single char I/O
1035                          */
1036                         if ( comm_mode ) {
1037                                 tty = open ( _PATH_TTY, O_RDWR );
1038                                 ioctl ( tty, TCGETA, &sgtty );
1039                                 sgtty.c_lflag &= ~( ICANON | ECHO );
1040                                 vmin = sgtty.c_cc[VMIN];
1041                                 vtime = sgtty.c_cc[VTIME];
1042                                 sgtty.c_cc[VMIN] = 0;
1043                                 sgtty.c_cc[VTIME] = 0;
1044                                 ioctl ( tty, TCSETA, &sgtty );
1045                         }
1046
1047                         /*
1048                          * Open bus for memory access
1049                          */
1050                         if ( ( fd = open ( bus_dev, O_RDWR ) ) < 0 )
1051                         {
1052                                 perror ( "open bus_dev" );
1053                                 fprintf(stderr, "%s download failed (%s)\n",
1054                                         air->acp_intf, bus_dev);
1055                                 continue;
1056                         }
1057
1058                         /*
1059                          * Map in the RAM memory to get access to the Uart
1060                          */
1061 #ifdef __FreeBSD__ /*XXX*/
1062                         ram = (u_char *) mmap(0, PCA200E_MMAP_SIZE,
1063 #else
1064                         ram = (u_char *) mmap(0, air->acp_ramsize,
1065 #endif
1066                                 PROT_READ | PROT_WRITE, MAP_SHARED | MAP_HASSEMAPHORE,
1067                                 fd, air->acp_ram);
1068                         if (ram == (u_char *)-1) {
1069                                 perror ( "mmap ram" );
1070                                 fprintf(stderr, "%s download failed\n",
1071                                         air->acp_intf);
1072                                 (void) close(fd);
1073                                 continue;
1074                         }
1075                         Mon = (Mon960 *)(ram + MON960_BASE);
1076                         Uart = (Mon960 *)&(Mon->mon_xmitmon);
1077
1078                         /*
1079                          * Determine endianess
1080                          */
1081                         switch ( Mon->mon_bstat ) {
1082                         case BOOT_COLDSTART:
1083                         case BOOT_MONREADY:
1084                         case BOOT_FAILTEST:
1085                         case BOOT_RUNNING:
1086                                 break;
1087
1088                         default:
1089                                 switch (ntohl(Mon->mon_bstat)) {
1090                                 case BOOT_COLDSTART:
1091                                 case BOOT_MONREADY:
1092                                 case BOOT_FAILTEST:
1093                                 case BOOT_RUNNING:
1094                                         endian++;
1095                                         break;
1096
1097                                 default:
1098                                         fprintf(stderr, "%s unknown status\n",
1099                                                 air->acp_intf);
1100                                         (void) close(fd);
1101                                         continue;
1102                                 }
1103                                 break;
1104                         }
1105
1106 #ifdef __FreeBSD__
1107                         if (reset) {
1108                                 u_int   *hcr = (u_int *)(ram + PCA200E_HCR_OFFSET);
1109                                 PCA200E_HCR_INIT(*hcr, PCA200E_RESET_BD);
1110                                 delay(10000);
1111                                 PCA200E_HCR_CLR(*hcr, PCA200E_RESET_BD);
1112                                 delay(10000);
1113                         }
1114 #endif
1115
1116                         if ( comm_mode ) {
1117                             static struct timeval timeout = { 0, 0 };
1118                             int esc_seen = 0;
1119
1120                             /*
1121                              * We want to talk with the i960 monitor
1122                              */
1123
1124                             /*
1125                              * Loop forever accepting characters
1126                              */
1127                             for ( ; ; ) {
1128                                 fd_set  fdr;
1129                                 int     ns;
1130
1131                                 /*
1132                                  * Check for data from the terminal
1133                                  */
1134                                 FD_ZERO ( &fdr );
1135                                 FD_SET ( fileno(stdin), &fdr );
1136
1137                                 if ( ( ns = select ( FD_SETSIZE, &fdr, NULL, NULL,
1138                                         &timeout ) ) < 0 ) {
1139                                                 perror ( "select" );
1140                                                 finish( -1 );
1141                                 }
1142
1143                                 if ( ns ) {
1144                                         int     c;
1145                                         int     nr;
1146
1147                                         nr = read ( fileno(stdin), &c, 1 );
1148                                         c &= 0xff;
1149                                         if ( !esc_seen ) {
1150                                             if ( c == 27 )
1151                                                 esc_seen++;
1152                                             else
1153                                                 xmit_byte ( c, 0 );
1154                                         } else {
1155                                             if ( c == 27 ) 
1156                                                 finish( -1 );
1157                                             else {
1158                                                 xmit_byte ( 27, 0 );
1159                                                 esc_seen = 0;
1160                                             }
1161                                             xmit_byte ( c, 0 );
1162                                         }
1163                                 }
1164
1165                                 /*
1166                                  * Check for data from the i960
1167                                  */
1168                                 if ( CP_READ(Uart->mon_xmithost) & UART_VALID ) {
1169                                         c = getbyte(0);
1170                                         putchar ( c );
1171                                 }
1172                                 if ( strcmp ( line, "Mon960" )  == 0 )
1173                                         autobaud();
1174
1175                             }
1176                         } else {
1177                             /*
1178                              * Make sure the driver is loaded and that the CP
1179                              * is ready for commands
1180                              */
1181                             if ( CP_READ(Mon->mon_bstat) == BOOT_RUNNING )
1182                             {
1183                                 fprintf ( stderr, 
1184                                 "%s is up and running - no download allowed.\n",
1185                                         air->acp_intf );
1186                                 (void) close(fd);
1187                                 continue;
1188                             }
1189                 
1190                             if ( CP_READ(Mon->mon_bstat) != BOOT_MONREADY )
1191                             {
1192                                 fprintf ( stderr, 
1193                                         "%s is not ready for downloading.\n", 
1194                                         air->acp_intf );
1195                                 (void) close(fd);
1196                                 continue;
1197                             }
1198                 
1199                             /*
1200                              * Indicate who we're downloading
1201                              */
1202                             if ( verbose )
1203                                 printf ( "Downloading code for %s\n",
1204                                         air->acp_intf );
1205
1206                             /*
1207                              * Look for the i960 monitor message. 
1208                              * We should see this after a board reset.
1209                              */
1210                             while ( strncmp ( line, "Mon960", 6 ) != 0 && 
1211                                 strncmp ( line, "=>", 2 ) != 0 )
1212                                 getline( verbose );     /* Verbose */
1213                 
1214                             /*
1215                              * Autobaud fakery
1216                              */
1217                             if ( strncmp ( line, "Mon960", 6 ) == 0 ) {
1218                                 xmit_to_i960 ( "\r\n\r\n\r\n\r\n", 8, 0 );
1219                                 delay ( 10000 );
1220                             }
1221
1222                             /*
1223                              * Keep reading until we get a command prompt
1224                              */
1225                             while ( strncmp ( line, "=>", 2 ) != 0 )
1226                                 getline( verbose );     /* Verbose */
1227
1228                             /*
1229                              * Choose the correct microcode file based on the
1230                              * adapter type the card claims to be.
1231                              */
1232                             switch ( air->acp_device )
1233                             {
1234                             case DEV_FORE_SBA200:
1235                                 sprintf ( base, "sba200" );
1236                                 break;
1237
1238                             case DEV_FORE_SBA200E:
1239                                 sprintf ( base, "sba200e" );
1240                                 break;
1241
1242                             case DEV_FORE_PCA200E:
1243                                 sprintf ( base, "pca200e" );
1244                                 break;
1245  
1246                             default:
1247                                 err = 1;
1248                                 fprintf(stderr, "Unknown adapter type: %d\n", 
1249                                         air->acp_device );
1250                             }
1251
1252                             sndfile = NULL;
1253
1254                             if ( objfile == NULL ) {
1255                                 switch ( air->acp_device ) {
1256                                 case DEV_FORE_SBA200:
1257                                 case DEV_FORE_SBA200E:
1258                                     sprintf ( filename, "%s.bin%d", base,
1259                                         air->acp_bustype );
1260                                     if ( stat ( filename, &sbuf ) == -1 ) {
1261                                         sprintf ( filename, "%s/%s.bin%d",
1262                                             dirname, base,
1263                                                 air->acp_bustype );
1264                                         if ( stat ( filename, &sbuf ) == -1 ) {
1265                                             ext = 1;
1266                                             sprintf ( filename, "%s.objd%d",
1267                                                 base, air->acp_bustype );
1268                                             if ( stat(filename, &sbuf) == -1 ) {
1269                                                 sprintf ( filename,
1270                                                     "%s/%s.objd%d", dirname,
1271                                                         base,
1272                                                             air->acp_bustype );
1273                                                 if ( stat ( filename, &sbuf ) != -1 )
1274                                                     sndfile = filename;
1275                                             } else
1276                                                 sndfile = filename;
1277                                         } else
1278                                             sndfile = filename;
1279                                     } else
1280                                         sndfile = filename;
1281                                     break;
1282                                 case DEV_FORE_PCA200E:
1283                                     /* Use compiled in microcode */
1284                                     ucode = pca200e_microcode;
1285                                     ucode_size = pca200e_microcode_size;
1286                                     break;
1287                                 default:
1288                                     break;
1289                                 }
1290                             } else
1291                                 sndfile = objfile;
1292
1293                             if ( ext && !binary )
1294                                 err = xmitfile ( sndfile );
1295                             else if (sndfile != NULL) 
1296                                 err = sendbinfile ( sndfile, ram );
1297                             else 
1298                                 err = loadmicrocode( ucode, ucode_size, ram );
1299
1300                             if ( err ) {
1301                                 fprintf(stderr, "%s download failed\n",
1302                                         air->acp_intf);
1303                                 (void) close(fd);
1304                                 continue;
1305                             }
1306
1307                             /*
1308                              * Download completed - wait around a while for
1309                              * the driver to initialize the adapter
1310                              */
1311                              aap = (Aali *)(ram + CP_READ(Mon->mon_appl));
1312                              for (i = 0; i < MAX_CHECK; i++, sleep(1)) {
1313                                 u_long  hb1, hb2, hb3;
1314
1315                                 hb3 = CP_READ(Mon->mon_bstat);
1316                                 if (hb3 != BOOT_RUNNING) {
1317                                         if (verbose)
1318                                                 printf("bstat %lx\n", hb3);
1319                                         continue;
1320                                 }
1321
1322                                 hb1 = CP_READ(aap->aali_heartbeat);
1323                                 delay(1);
1324                                 hb2 = CP_READ(aap->aali_heartbeat);
1325                                 if (verbose)
1326                                         printf("hb %lx %lx\n", hb1, hb2);
1327                                 if (hb1 < hb2)
1328                                         break;
1329                              }
1330                         }
1331
1332                         close ( fd );
1333                 }
1334         }
1335
1336         /*
1337          * Exit
1338          */
1339         exit (0);
1340
1341 }
1342