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