Initial import from FreeBSD RELENG_4:
[dragonfly.git] / usr.sbin / stallion / stlload / stlload.c
1 /*****************************************************************************/
2
3 /*
4  * stlload.c  -- stallion intelligent multiport down loader.
5  *
6  * Copyright (c) 1994-1998 Greg Ungerer (gerg@stallion.oz.au).
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed by Greg Ungerer.
20  * 4. Neither the name of the author nor the names of any co-contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36
37 /*****************************************************************************/
38
39 #ifndef lint
40 static const char rcsid[] =
41   "$FreeBSD: src/usr.sbin/stallion/stlload/stlload.c,v 1.10.2.2 2002/02/13 22:55:45 dbaker Exp $";
42 #endif /* not lint */
43
44 #include <err.h>
45 #include <fcntl.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <time.h>
49 #include <unistd.h>
50 #include <sys/stat.h>
51 #include <sys/ioctl.h>
52
53 #include <machine/cdk.h>
54
55 /*****************************************************************************/
56
57 char    *version = "2.0.0";
58 char    *defdevice = "/dev/staliomem%d";
59 char    *image = BOOTDIR "/cdk.sys";
60 char    *oldimage = BOOTDIR "/2681.sys";
61
62 char    *memdevice;
63 char    devstr[128];
64 int     brdnr = 0;
65 int     verbose = 0;
66 int     reset = 0;
67
68 /*
69  *      Define a local buffer for copying the image into the shared memory.
70  */
71 #define BUFSIZE         4096
72
73 char    buf[BUFSIZE];
74
75 /*
76  *      Define the timeout length when waiting for slave to start up.
77  *      The quantity is measured in seconds.
78  */
79 #define TIMEOUT         5
80
81 /*
82  *      Set up a default feature area structure.
83  */
84 cdkfeature_t    feature = { 0, 0, ETYP_CDK, 0, 0, 0, 0, 0 };
85
86 /*
87  *      Have local copies of the board signatures ready.
88  */
89 cdkecpsig_t     ecpsig;
90 cdkonbsig_t     onbsig;
91
92 /*****************************************************************************/
93
94 /*
95  *      Declare internal function prototypes here.
96  */
97 static void     usage(void);
98 int     ecpfindports(cdkecpsig_t *sigp);
99 int     onbfindports(cdkonbsig_t *sigp);
100 int     download(void);
101
102 /*****************************************************************************/
103
104 static void usage()
105 {
106         fprintf(stderr, "%s\n%s\n",
107 "usage: stlload [-vhVR] [-i image-file] [-c control-device] [-r rx-buf-size]",
108 "               [-t tx-buf-size] [-B boot-banner] [-b unit-number]");
109         exit(0);
110 }
111
112 /*****************************************************************************/
113
114 /*
115  *      Given a boards signature determine how many ports it has. We need to
116  *      know this to setup the slave feature arguments. This function is for
117  *      ECP boards only.
118  */
119
120 int ecpfindports(cdkecpsig_t *sigp)
121 {
122         unsigned int    id;
123         int             bank, nrports;
124
125         nrports = 0;
126         for (bank = 0; (bank < 8); bank++) {
127                 id = (unsigned int) sigp->panelid[bank];
128                 if (id == 0xff)
129                         break;
130                 if ((id & 0x07) != bank)
131                         break;
132                 if (id & 0x20) {
133                         nrports += 16;
134                         bank++;
135                 } else {
136                         nrports += 8;
137                 }
138         }
139
140         return(nrports);
141 }
142
143 /*****************************************************************************/
144
145 /*
146  *      Given a boards signature determine how many ports it has. We need to
147  *      know this to setup the slave feature arguments. This function is for
148  *      ONboards and Brumbys.
149  */
150
151 int onbfindports(cdkonbsig_t *sigp)
152 {
153         int     i, nrports;
154
155         if (sigp->amask1) {
156                 nrports = 32;
157         } else {
158                 for (i = 0; (i < 16); i++) {
159                         if (((sigp->amask0 << i) & 0x8000) == 0)
160                                 break;
161                 }
162                 nrports = i;
163         }
164
165         return(nrports);
166 }
167
168 /*****************************************************************************/
169
170 /*
171  *      Download an image to the slave board. There is a long sequence of
172  *      things to do to get the slave running, but it is basically a simple
173  *      process. Main things to do are: copy slave image into shared memory,
174  *      start slave running and then read shared memory map.
175  */
176
177 int download()
178 {
179         unsigned char   alivemarker;
180         time_t          strttime;
181         int             memfd, ifd;
182         int             nrdevs, sigok, n;
183
184         if (verbose)
185                 printf("Opening shared memory device %s\n", memdevice);
186         if ((memfd = open(memdevice, O_RDWR)) < 0) {
187                 warn("failed to open memory device %s", memdevice);
188                 return(-1);
189         }
190
191 /*
192  *      Before starting the download must tell driver that we are about to
193  *      stop its slave. This is only important if it is already running.
194  *      Once we have told the driver its stopped then do a hardware reset
195  *      on it, to get it into a known state.
196  */
197         if (verbose)
198                 printf("Stoping any current slave\n");
199         if (ioctl(memfd, STL_BSTOP, 0) < 0) {
200                 warn("ioctl(STL_BSTOP)");
201                 printf(" (Perhaps you're trying to download firmare to a PCI card that\n doesn't require this?)\n");
202                 return(-1);
203         }
204
205         if (verbose)
206                 printf("Reseting the board\n");
207         if (ioctl(memfd, STL_BRESET, 0) < 0) {
208                 warn("ioctl(STL_BRESET)");
209                 return(-1);
210         }
211         if (reset)
212                 return(0);
213
214 /*
215  *      After reseting the board we need to send an interrupt to the older
216  *      board types to get them to become active. Do that now.
217  */
218         if (verbose)
219                 printf("Interrupting board to activate shared memory\n");
220         if (ioctl(memfd, STL_BINTR, 0) < 0) {
221                 warn("ioctl(STL_BINTR)");
222                 return(-1);
223         }
224         /*sleep(1);*/
225
226         if (verbose)
227                 printf("Opening slave image file %s\n", image);
228         if ((ifd = open(image, O_RDONLY)) < 0) {
229                 warn("failed to open image file %s", image);
230                 return(-1);
231         }
232
233 /*
234  *      At this point get the signature of the board from the shared memory.
235  *      Do a double check that it is a board we know about. We will also need
236  *      to calculate the number of ports on this board (to use later).
237  */
238         sigok = 0;
239         if (verbose)
240                 printf("Reading ROM signature from board\n");
241
242         if (lseek(memfd, CDK_SIGADDR, SEEK_SET) != CDK_SIGADDR) {
243                 warn("lseek(%x) failed on memory file", CDK_FEATADDR);
244                 return(-1);
245         }
246         if (read(memfd, &ecpsig, sizeof(cdkecpsig_t)) < 0) {
247                 warn("read of ROM signature failed");
248                 return(-1);
249         }
250         if (ecpsig.magic == ECP_MAGIC) {
251                 nrdevs = ecpfindports(&ecpsig);
252                 if (nrdevs < 0)
253                         return(-1);
254                 sigok++;
255         }
256
257         if (lseek(memfd, CDK_SIGADDR, SEEK_SET) != CDK_SIGADDR) {
258                 warn("lseek(%x) failed on memory file", CDK_FEATADDR);
259                 return(-1);
260         }
261         if (read(memfd, &onbsig, sizeof(cdkonbsig_t)) < 0) {
262                 warn("read of ROM signature failed");
263                 return(-1);
264         }
265         if ((onbsig.magic0 == ONB_MAGIC0) && (onbsig.magic1 == ONB_MAGIC1) &&
266                         (onbsig.magic2 == ONB_MAGIC2) &&
267                         (onbsig.magic3 == ONB_MAGIC3)) {
268                 nrdevs = onbfindports(&onbsig);
269                 if (nrdevs < 0)
270                         return(-1);
271                 sigok++;
272         }
273
274         if (! sigok) {
275                 warnx("unknown signature from board");
276                 return(-1);
277         }
278
279         if (verbose)
280                 printf("Board signature reports %d ports\n", nrdevs);
281
282 /*
283  *      Start to copy the image file into shared memory. The first thing to
284  *      do is copy the vector region in from shared memory address 0. We will
285  *      then skip over the signature and feature area and start copying the
286  *      actual image data and code from 4k upwards.
287  */
288         if (verbose)
289                 printf("Copying vector table into shared memory\n");
290         if ((n = read(ifd, buf, CDK_SIGADDR)) < 0) {
291                 warn("read of image file failed");
292                 return(-1);
293         }
294         if (lseek(memfd, 0, SEEK_SET) != 0) {
295                 warn("lseek(%x) failed on memory file", CDK_FEATADDR);
296                 return(-1);
297         }
298         if (write(memfd, buf, n) < 0) {
299                 warn("write to memory device failed");
300                 return(-1);
301         }
302
303         if (lseek(ifd, 0x1000, SEEK_SET) != 0x1000) {
304                 warn("lseek(%x) failed on image file", CDK_FEATADDR);
305                 return(-1);
306         }
307         if (lseek(memfd, 0x1000, SEEK_SET) != 0x1000) {
308                 warn("lseek(%x) failed on memory device", CDK_FEATADDR);
309                 return(-1);
310         }
311
312 /*
313  *      Copy buffer size chunks of data from the image file into shared memory.
314  */
315         do {
316                 if ((n = read(ifd, buf, BUFSIZE)) < 0) {
317                         warn("read of image file failed");
318                         return(-1);
319                 }
320                 if (write(memfd, buf, n) < 0) {
321                         warn("write to memory device failed");
322                         return(-1);
323                 }
324         } while (n == BUFSIZE);
325
326         close(ifd);
327
328 /*
329  *      We need to down load the start up parameters for the slave. This is
330  *      done via the feature area of shared memory. Think of the feature area
331  *      as a way of passing "command line" arguments to the slave.
332  *      FIX: should do something here to load "brdspec" as well...
333  */
334         feature.nrdevs = nrdevs;
335         if (verbose)
336                 printf("Loading features into shared memory\n");
337         if (lseek(memfd, CDK_FEATADDR, SEEK_SET) != CDK_FEATADDR) {
338                 warn("lseek(%x) failed on memory device", CDK_FEATADDR);
339                 return(-1);
340         }
341         if (write(memfd, &feature, sizeof(cdkfeature_t)) < 0) {
342                 warn("write to memory device failed");
343                 return(-1);
344         }
345
346 /*
347  *      Wait for board alive marker to be set. The slave image will set the
348  *      byte at address CDK_RDYADDR to 0x13 after it has successfully started.
349  *      If this doesn't happen we timeout and fail.
350  */
351         if (verbose)
352                 printf("Setting alive marker to 0\n");
353         if (lseek(memfd, CDK_RDYADDR, SEEK_SET) != CDK_RDYADDR) {
354                 warn("lseek(%x) failed on memory device", CDK_RDYADDR);
355                 return(-1);
356         }
357         alivemarker = 0;
358         if (write(memfd, &alivemarker, 1) < 0) {
359                 warn("write to memory device failed");
360                 return(-1);
361         }
362
363 /*
364  *      At this point the entire image is loaded into shared memory. To start
365  *      it executiong we poke the board with an interrupt.
366  */
367         if (verbose)
368                 printf("Interrupting board to start slave image\n");
369         if (ioctl(memfd, STL_BINTR, 0) < 0) {
370                 warn("ioctl(STL_BINTR) failed");
371                 return(-1);
372         }
373
374         strttime = time((time_t *) NULL);
375         if (verbose)
376                 printf("Waiting for slave alive marker, time=%x timeout=%d\n",
377                         strttime, TIMEOUT);
378         while (time((time_t *) NULL) < (strttime + TIMEOUT)) {
379                 if (lseek(memfd, CDK_RDYADDR, SEEK_SET) != CDK_RDYADDR) {
380                         warn("lseek(%x) failed on memory device", CDK_RDYADDR);
381                         return(-1);
382                 }
383                 if (read(memfd, &alivemarker, 1) < 0){
384                         warn("read of image file failed");
385                         return(-1);
386                 }
387                 if (alivemarker == CDK_ALIVEMARKER)
388                         break;
389         }
390
391         if (alivemarker != CDK_ALIVEMARKER) {
392                 warnx("slave image failed to start");
393                 return(-1);
394         }
395
396         if (lseek(memfd, CDK_RDYADDR, SEEK_SET) != CDK_RDYADDR) {
397                 warn("lseek(%x) failed on memory device", CDK_RDYADDR);
398                 return(-1);
399         }
400         alivemarker = 0;
401         if (write(memfd, &alivemarker, 1) < 0) {
402                 warn("write to memory device failed");
403                 return(-1);
404         }
405
406         if (verbose)
407                 printf("Slave image started successfully\n");
408
409 /*
410  *      The last thing to do now is to get the driver started. Now that the
411  *      slave is operational it must read in the memory map and gets its
412  *      internal tables initialized.
413  */
414         if (verbose)
415                 printf("Driver initializing host shared memory interface\n");
416         if (ioctl(memfd, STL_BSTART, 0) < 0) {
417                 warn("ioctl(STL_BSTART) failed");
418                 return(-1);
419         }
420
421         close(memfd);
422         return(0);
423 }
424
425 /*****************************************************************************/
426
427 int main(int argc, char *argv[])
428 {
429         struct stat     statinfo;
430         int             c;
431
432         while ((c = getopt(argc, argv, "hvVRB:i:b:c:t:r:")) != -1) {
433                 switch (c) {
434                 case 'V':
435                         printf("stlload version %s\n", version);
436                         exit(0);
437                         break;
438                 case 'B':
439                         feature.banner = atol(optarg);
440                         break;
441                 case 'h':
442                         usage();
443                         break;
444                 case 'v':
445                         verbose++;
446                         break;
447                 case 'i':
448                         image = optarg;
449                         break;
450                 case 'R':
451                         reset++;
452                         break;
453                 case 'b':
454                         brdnr = atoi(optarg);
455                         break;
456                 case 'c':
457                         memdevice = optarg;
458                         break;
459                 case 't':
460                         feature.txrqsize = atol(optarg);
461                         break;
462                 case 'r':
463                         feature.rxrqsize = atol(optarg);
464                         break;
465                 case '?':
466                 default:
467                         usage();
468                         break;
469                 }
470         }
471
472         if (memdevice == (char *) NULL) {
473                 if ((brdnr < 0) || (brdnr >= 8))
474                         errx(1, "invalid board number %d specified", brdnr);
475                 sprintf(devstr, defdevice, brdnr);
476                 memdevice = &devstr[0];
477                 if (verbose)
478                         printf("Using shared memory device %s\n", memdevice);
479         }
480
481         if (verbose)
482                 printf("Downloading image %s to board %d\n", image, brdnr);
483
484 /*
485  *      Check that the shared memory device exits and is a character device.
486  */
487         if (stat(memdevice, &statinfo) < 0)
488                 errx(1, "memory device %s does not exist", memdevice);
489         if ((statinfo.st_mode & S_IFMT) != S_IFCHR)
490                 errx(1, "memory device %s is not a char device", memdevice);
491
492         if (stat(image, &statinfo) < 0)
493                 errx(1, "image file %s does not exist", image);
494
495 /*
496  *      All argument checking is now done. So lets get this show on the road.
497  */
498         if (download() < 0)
499                 exit(1);
500         exit(0);
501 }
502
503 /*****************************************************************************/