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