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