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