Merge from vendor branch GCC:
[dragonfly.git] / sys / dev / atm / hfa / fore_load.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/sys/dev/hfa/fore_load.c,v 1.13 1999/09/25 18:23:49 phk Exp $
27  *      @(#) $DragonFly: src/sys/dev/atm/hfa/fore_load.c,v 1.9 2004/09/15 01:51:55 joerg Exp $
28  */
29
30 /*
31  * FORE Systems 200-Series Adapter Support
32  * ---------------------------------------
33  *
34  * Loadable kernel module and device identification support
35  *
36  */
37
38 #include "fore_include.h"
39
40 /*
41  * Local functions
42  */
43 static int      fore_start (void);
44 #ifdef sun
45 static int      fore_stop (void);
46 static int      fore_doload (void);
47 static int      fore_dounload (void);
48 static int      fore_identify (char *);
49 static int      fore_attach (struct devinfo *);
50 #endif
51 #if defined(__DragonFly__) || defined(__FreeBSD__)
52 static const char *     fore_pci_probe (pcici_t, pcidi_t);
53 static void     fore_pci_attach (pcici_t, int);
54 #if BSD < 199506
55 static int      fore_pci_shutdown (struct kern_devconf *, int);
56 #else
57 static void     fore_pci_shutdown (void *, int);
58 #endif
59 #endif
60 static void     fore_unattach (Fore_unit *);
61 static void     fore_reset (Fore_unit *);
62
63
64 /*
65  * Local variables
66  */
67 static int      fore_inited = 0;
68
69 /*
70  * Driver entry points
71  */
72 #ifdef sun
73 static struct dev_ops   fore_ops = {
74         1,              /* revision */
75         fore_identify,  /* identify */
76         fore_attach,    /* attach */
77         NULL,           /* open */
78         NULL,           /* close */
79         NULL,           /* read */
80         NULL,           /* write */
81         NULL,           /* strategy */
82         NULL,           /* dump */
83         NULL,           /* psize */
84         NULL,           /* ioctl */
85         NULL,           /* reset */
86         NULL            /* mmap */
87 };
88 #endif
89
90 #if defined(__DragonFly__) || defined(__FreeBSD__)
91 static  u_long  fore_pci_count = 0;
92
93 static struct pci_device fore_pci_device = {
94         FORE_DEV_NAME,
95         fore_pci_probe,
96         fore_pci_attach,
97         &fore_pci_count,
98 #if BSD < 199506
99         fore_pci_shutdown
100 #else
101         NULL
102 #endif
103 };
104
105 COMPAT_PCI_DRIVER(fore_pci, fore_pci_device);
106 #endif
107
108
109 /*
110  * Initialize driver processing
111  * 
112  * This will be called during module loading.  Not much to do here, as
113  * we must wait for our identify/attach routines to get called before
114  * we know what we're in for.
115  *
116  * Arguments:
117  *      none
118  *
119  * Returns:
120  *      0       startup was successful 
121  *      errno   startup failed - reason indicated
122  *
123  */
124 static int
125 fore_start()
126 {
127
128         /*
129          * Verify software version
130          */
131         if (atm_version != ATM_VERSION) {
132                 log(LOG_ERR, "version mismatch: fore=%d.%d kernel=%d.%d\n",
133                         ATM_VERS_MAJ(ATM_VERSION), ATM_VERS_MIN(ATM_VERSION),
134                         ATM_VERS_MAJ(atm_version), ATM_VERS_MIN(atm_version));
135                 return (EINVAL);
136         }
137
138         /*
139          * Initialize DMA mapping
140          */
141         DMA_INIT();
142
143         /*
144          * Start up watchdog timer
145          */
146         atm_timeout(&fore_timer, ATM_HZ * FORE_TIME_TICK, fore_timeout);
147
148         fore_inited = 1;
149
150         return (0);
151 }
152
153
154 #ifdef sun
155
156 /*
157  * Halt driver processing 
158  * 
159  * This will be called just prior to unloading the module from memory.
160  * Everything we've setup since we've been loaded must be undone here.
161  *
162  * Arguments:
163  *      none
164  *
165  * Returns:
166  *      0       shutdown was successful 
167  *      errno   shutdown failed - reason indicated
168  *
169  */
170 static int
171 fore_stop()
172 {
173         int     err = 0;
174         int     s = splimp();
175         int     i;
176
177         /*
178          * Stop the watchdog timer
179          */
180         (void) atm_untimeout(&fore_timer);
181
182         /*
183          * Clean up each device (if any)
184          */
185         for ( i = 0; i < fore_nunits; i++ ) {
186                 Fore_unit       *fup = fore_units[i];
187
188                 if (fup == NULL)
189                         continue;
190
191                 /*
192                  * Deregister device from kernel services
193                  */
194                 if (err = atm_physif_deregister((Cmn_unit *)fup)) {
195                         (void) splx(s);
196                         return (err);
197                 }
198
199                 /*
200                  * Unattach the device from the system
201                  */
202                 fore_unattach(fup);
203
204                 /*
205                  * Free any Fore-specific device resources
206                  */
207                 fore_interface_free(fup);
208
209                 /*
210                  * Free the unit structure
211                  */
212                 atm_dev_free(fup);
213                 fore_units[i] = NULL;
214         }
215
216         fore_nunits = 0;
217
218         /*
219          * Now free our global resources
220          */
221
222         /*
223          * Release our storage pools
224          */
225         atm_release_pool(&fore_vcc_pool);
226         atm_release_pool(&fore_nif_pool);
227
228         /*
229          * Release all DMA mappings
230          */
231         DMA_RELEASE();
232
233         fore_inited = 0;
234
235         (void) splx(s);
236
237         return (0);
238 }
239
240 /*
241  * Device identify routine
242  * 
243  * Determine if this driver will support the named device.  If we claim to
244  * support the device, our attach routine will (later) be called for the
245  * device.
246  *
247  * Arguments:
248  *      name    pointer to identifier string from device
249  *
250  * Returns:
251  *      1       driver claims support for this device
252  *      0       device not claimed by this driver
253  *
254  */
255 static int
256 fore_identify(name)
257         char    *name;
258 {
259         int     ret = 0;
260         int     i = 0;
261
262         /*
263          * Initialize driver stuff
264          */
265         if (fore_inited == 0) {
266                 if (fore_start())
267                         return (0);
268         }
269
270         while (fore_devices[i].fd_name) {
271                 if (strcmp(fore_devices[i].fd_name, name) == 0) {
272
273                         /*
274                          * We support this device!!
275                          */
276                         if (fore_nunits < FORE_MAX_UNITS) {
277                                 fore_nunits++;
278                                 ret = 1;
279                         } else {
280                                 log(LOG_ERR,
281                                         "fore_identify: Too many devices\n");
282                         }
283                         break;
284                 }
285                 i++;
286         }
287         return (ret);
288 }
289
290
291 /*
292  * Device attach routine
293  * 
294  * Attach a device we've previously claimed to support.  Walk through its
295  * register set and map, as required.  Determine what level the device will
296  * be interrupting at and then register an interrupt handler for it.  If we
297  * succeed, then reset the adapter and read useful info from its PROM.
298  * Last, register the interface with the kernel ATM services.
299  *
300  * Arguments:
301  *      devinfo_p       pointer to device information structure
302  *
303  * Returns:
304  *      0       attach was successful
305  *      -1      attach failed
306  *
307  */
308 static int
309 fore_attach(devinfo_p)
310         struct dev_info *devinfo_p;
311 {
312         struct dev_reg  *dev_reg_p;
313         struct dev_intr *dev_intr_p;
314         Fore_unit       *fup;
315         Atm_config      *fcp;
316         addr_t          valp;
317         int             val;
318         int             i;
319         int             err_count = BOOT_LOOPS;
320         static int      unit = 0;
321
322         /*
323          * Sanity check
324          */
325         if (devinfo_p == NULL)
326                 return (-1);
327
328         /*
329          * Make sure this isn't a duplicate unit
330          */
331         if (fore_units[unit] != NULL)
332                 return (-1);
333
334         /*
335          * Allocate a new unit structure
336          */
337         fup = (Fore_unit *) atm_dev_alloc(sizeof(Fore_unit), sizeof(int), 0);
338         if (fup == NULL)
339                 return (-1);
340
341         /*
342          * Start initializing it
343          */
344         fup->fu_unit = unit;
345         fup->fu_mtu = FORE_IFF_MTU;
346         fup->fu_devinfo = devinfo_p;
347         fup->fu_vcc_pool = &fore_vcc_pool;
348         fup->fu_nif_pool = &fore_nif_pool;
349         fup->fu_ioctl = fore_atm_ioctl;
350         fup->fu_instvcc = fore_instvcc;
351         fup->fu_openvcc = fore_openvcc;
352         fup->fu_closevcc = fore_closevcc;
353         fup->fu_output = fore_output;
354
355         /*
356          * Consider this unit assigned
357          */
358         fore_units[unit] = fup;
359         unit++;
360
361         ATM_DEBUG1("fore_attach: fup=%p\n", fup);
362         ATM_DEBUG2("\tfu_xmit_q=%p fu_xmit_head=%p\n",
363                 fup->fu_xmit_q, &fup->fu_xmit_head);
364         ATM_DEBUG2("\tfu_recv_q=%p fu_recv_head=%p\n",
365                 fup->fu_recv_q, &fup->fu_recv_head);
366         ATM_DEBUG2("\tfu_buf1s_q=%p fu_buf1s_head=%p\n",
367                 fup->fu_buf1s_q, &fup->fu_buf1s_head);
368         ATM_DEBUG2("\tfu_buf1l_q=%p fu_buf1l_head=%p\n",
369                 fup->fu_buf1l_q, &fup->fu_buf1l_head);
370         ATM_DEBUG2("\tfu_cmd_q=%p fu_cmd_head=%p\n",
371                 fup->fu_cmd_q, &fup->fu_cmd_head);
372         ATM_DEBUG1("\tfu_stats=%p\n",
373                 &fup->fu_stats);
374
375         /*
376          * Tell kernel our unit number
377          */
378         devinfo_p->devi_unit = fup->fu_unit;
379
380         /*
381          * Figure out what type of device we've got.  This should always
382          * work since we've already done this at identify time!
383          */
384         i = 0;
385         while (fore_devices[i].fd_name) {
386                 if (strcmp(fore_devices[i].fd_name, devinfo_p->devi_name) == 0)
387                         break;
388                 i++;
389         }
390         if (fore_devices[i].fd_name == NULL)
391                 return (-1);
392
393         fup->fu_config.ac_device = fore_devices[i].fd_devtyp;
394
395         /*
396          * Walk through the OPENPROM register information
397          * mapping register banks as they are found.
398          */
399         for ( dev_reg_p = devinfo_p->devi_reg, i = 1;
400                 i <= devinfo_p->devi_nreg; i++, ++dev_reg_p )
401         {
402                 if ( dev_reg_p == NULL )
403                 {
404                         /*
405                          * Can't happen...
406                          */
407                         return ( -1 );
408                 }
409
410                 /*
411                  * Each device type has different register sets
412                  */
413                 switch (fup->fu_config.ac_device) {
414
415 #ifdef FORE_SBUS
416                 case DEV_FORE_SBA200E:
417
418                         switch ( i )
419                         {
420                         /*
421                          * Host Control Register (HCR)
422                          */
423                         case 1:
424                                 if ( sizeof(Fore_reg) != dev_reg_p->reg_size )
425                                 {
426                                         return ( -1 );
427                                 }
428                                 fup->fu_ctlreg = (Fore_reg *)
429                                         map_regs ( dev_reg_p->reg_addr,
430                                                 sizeof(Fore_reg),
431                                                 dev_reg_p->reg_bustype );
432                                 if ( fup->fu_ctlreg == NULL )
433                                 {
434                                         return ( -1 );
435                                 }
436                                 break;
437
438                         /*
439                          * SBus Burst Transfer Configuration Register
440                          */
441                         case 2:
442                                 /*
443                                  * Not used
444                                  */
445                                 break;
446
447                         /*
448                          * SBus Interrupt Level Select Register
449                          */
450                         case 3:
451                                 if ( sizeof (Fore_reg) != dev_reg_p->reg_size )
452                                 {
453                                         return ( -1 );
454                                 }
455                                 fup->fu_intlvl = (Fore_reg *)
456                                         map_regs ( dev_reg_p->reg_addr,
457                                                 sizeof(Fore_reg),
458                                                 dev_reg_p->reg_bustype );
459                                 if ( fup->fu_intlvl == NULL )
460                                 {
461                                         return ( -1 );
462                                 }
463                                 break;
464
465                         /*
466                          * i960 RAM
467                          */
468                         case 4:
469                                 fup->fu_ram = (Fore_mem *)
470                                         map_regs ( dev_reg_p->reg_addr,
471                                                 dev_reg_p->reg_size,
472                                                 dev_reg_p->reg_bustype );
473                                 if ( fup->fu_ram == NULL )
474                                 {
475                                         return ( -1 );
476                                 }
477                                 fup->fu_ramsize = dev_reg_p->reg_size;
478
479                                 /*
480                                  * Various versions of the Sun PROM mess with 
481                                  * the reg_addr value in unpredictable (to me,
482                                  * at least) ways, so just use the "memoffset"
483                                  * property, which should give us the RAM 
484                                  * offset directly.
485                                  */
486                                 val = getprop(devinfo_p->devi_nodeid, 
487                                                         "memoffset", -1);
488                                 if (val == -1) {
489                                         return (-1);
490                                 }
491                                 fup->fu_config.ac_ram = val;
492                                 fup->fu_config.ac_ramsize = fup->fu_ramsize;
493
494                                 /*
495                                  * Set monitor interface for initializing
496                                  */
497                                 fup->fu_mon = (Mon960 *)
498                                         (fup->fu_ram + MON960_BASE);
499                                 break;
500
501                         default:
502                                 log(LOG_ERR, 
503                                         "fore_attach: Too many registers\n");
504                                 return ( -1 );
505                         }
506                         break;
507
508                 case DEV_FORE_SBA200:
509
510                         switch ( i )
511                         {
512                         /*
513                          * Board Control Register (BCR)
514                          */
515                         case 1:
516                                 if ( sizeof(Fore_reg) != dev_reg_p->reg_size )
517                                 {
518                                         return ( -1 );
519                                 }
520                                 fup->fu_ctlreg = (Fore_reg *)
521                                         map_regs ( dev_reg_p->reg_addr,
522                                                 sizeof(Fore_reg),
523                                                 dev_reg_p->reg_bustype );
524                                 if ( fup->fu_ctlreg == NULL )
525                                 {
526                                         return ( -1 );
527                                 }
528                                 break;
529
530                         /*
531                          * i960 RAM
532                          */
533                         case 2:
534                                 fup->fu_ram = (Fore_mem *)
535                                         map_regs ( dev_reg_p->reg_addr,
536                                                 dev_reg_p->reg_size,
537                                                 dev_reg_p->reg_bustype );
538                                 if ( fup->fu_ram == NULL )
539                                 {
540                                         return ( -1 );
541                                 }
542                                 fup->fu_ramsize = dev_reg_p->reg_size;
543
544                                 /*
545                                  * Various versions of the Sun PROM mess with 
546                                  * the reg_addr value in unpredictable (to me,
547                                  * at least) ways, so just use the "memoffset"
548                                  * property, which should give us the RAM 
549                                  * offset directly.
550                                  */
551                                 val = getprop(devinfo_p->devi_nodeid, 
552                                                         "memoffset", -1);
553                                 if (val == -1) {
554                                         return (-1);
555                                 }
556                                 fup->fu_config.ac_ram = val;
557                                 fup->fu_config.ac_ramsize = fup->fu_ramsize;
558
559                                 /*
560                                  * Set monitor interface for initializing
561                                  */
562                                 fup->fu_mon = (Mon960 *)
563                                         (fup->fu_ram + MON960_BASE);
564                                 break;
565
566                         default:
567                                 log(LOG_ERR, 
568                                         "fore_attach: Too many registers\n");
569                                 return ( -1 );
570                         }
571                         break;
572 #endif  /* FORE_SBUS */
573
574                 default:
575                         log(LOG_ERR, 
576                                 "fore_attach: Unsupported device type %d\n",
577                                 fup->fu_config.ac_device);
578                         return (-1);
579                 }
580         }
581
582         /*
583          * Install the device in the interrupt chain.
584          *
585          * dev_intr_p may be null IFF devi_nintr is zero.
586          */
587         dev_intr_p = devinfo_p->devi_intr;
588         for ( i = devinfo_p->devi_nintr; i > 0; --i, ++dev_intr_p )
589         {
590
591                 if ( dev_intr_p == NULL )
592                 {
593                         /*
594                          * Can't happen.
595                          */
596                         return ( -1 );
597                 }
598
599                 /*
600                  * Convert hardware ipl (0-15) into spl level.
601                  */
602                 if ( ipltospl ( dev_intr_p->int_pri ) > fup->fu_intrpri )
603                 {
604                         fup->fu_intrpri = ipltospl ( dev_intr_p->int_pri );
605
606                         /*
607                          * If SBA-200E card, set SBus interrupt level
608                          * into board register
609                          */
610                         if ( fup->fu_intlvl ) {
611 #if defined(sun4c)
612                                 *(fup->fu_intlvl) = dev_intr_p->int_pri;
613 #elif defined(sun4m)
614                                 extern int      svimap[];
615
616                                 *(fup->fu_intlvl) = 
617                                         svimap[dev_intr_p->int_pri & 0xf];
618 #else
619                                 #error PORT ME;
620 #endif
621                         }
622                 }
623
624                 DEVICE_LOCK((Cmn_unit *)fup);
625
626                 /*
627                  * Register our interrupt routine.
628                  */
629                 (void) addintr ( dev_intr_p->int_pri, fore_poll,
630                     devinfo_p->devi_name, devinfo_p->devi_unit );
631
632                 /*
633                  * If we can do DMA (we can), then DVMA routines need
634                  * to know the highest IPL level we will interrupt at.
635                  */
636                 adddma ( dev_intr_p->int_pri );
637
638                 DEVICE_UNLOCK((Cmn_unit *)fup);
639         }
640
641         /*
642          * Poke the hardware...boot the CP and prepare it for downloading
643          */
644         fore_reset(fup);
645
646         switch (fup->fu_config.ac_device) {
647
648 #ifdef FORE_SBUS
649         case DEV_FORE_SBA200E:
650                 /*
651                  * Enable interrupts
652                  */
653                 SBA200E_HCR_SET(*fup->fu_ctlreg, SBA200E_SBUS_ENA);
654                 break;
655 #endif  /* FORE_SBUS */
656         }
657
658         /*
659          * Wait for monitor to perform self-test
660          */
661         while (CP_READ(fup->fu_mon->mon_bstat) != BOOT_MONREADY) {
662                 if (CP_READ(fup->fu_mon->mon_bstat) == BOOT_FAILTEST) {
663                         log(LOG_ERR, "fore_attach: Unit %d failed self-test\n",
664                                 fup->fu_unit);
665                         return (-1);
666
667                 } else if ( --err_count == 0 ) {
668                         log(LOG_ERR, "fore_attach: Unit %d unable to boot\n",
669                                 fup->fu_unit);
670                         return (-1);
671                 }
672                 DELAY ( BOOT_DELAY );
673         }
674
675         /*
676          * Write a one line message to the console informing
677          * that we've attached the device.
678          */
679         report_dev ( devinfo_p );
680
681         /*
682          * Get the mac address from the card PROM
683          */
684         val = getprop ( devinfo_p->devi_nodeid, "macaddress1", -1 );
685         if ( val != -1 ) {
686                 fup->fu_pif.pif_macaddr.ma_data[0] = val & 0xff;
687                 val = getprop ( devinfo_p->devi_nodeid, "macaddress2", -1 );
688                 fup->fu_pif.pif_macaddr.ma_data[1] = val & 0xff;
689                 val = getprop ( devinfo_p->devi_nodeid, "macaddress3", -1 );
690                 fup->fu_pif.pif_macaddr.ma_data[2] = val & 0xff;
691                 val = getprop ( devinfo_p->devi_nodeid, "macaddress4", -1 );
692                 fup->fu_pif.pif_macaddr.ma_data[3] = val & 0xff;
693                 val = getprop ( devinfo_p->devi_nodeid, "macaddress5", -1 );
694                 fup->fu_pif.pif_macaddr.ma_data[4] = val & 0xff;
695                 val = getprop ( devinfo_p->devi_nodeid, "macaddress6", -1 );
696                 fup->fu_pif.pif_macaddr.ma_data[5] = val & 0xff;
697         } else {
698                 /*
699                  * Newer PROM - mac addresses have been combined. Also,
700                  * macaddrlo2 reflects the board serial number.
701                  */
702                 val = htonl(getprop(devinfo_p->devi_nodeid, "macaddrlo2", -1));
703                 KM_COPY ( (caddr_t)&val, 
704                         (caddr_t)&fup->fu_pif.pif_macaddr.ma_data[2],
705                         sizeof(val) );
706                 val = htonl(getprop(devinfo_p->devi_nodeid, "macaddrhi4", -1));
707                 KM_COPY ( (caddr_t)&val,
708                         (caddr_t)fup->fu_pif.pif_macaddr.ma_data,
709                         sizeof(val) );
710         }
711
712         /*
713          * Setup the adapter config info
714          */
715         fcp = &fup->fu_config;
716         fcp->ac_vendor = VENDOR_FORE;
717         fcp->ac_vendapi = VENDAPI_FORE_1;
718         fcp->ac_macaddr = fup->fu_pif.pif_macaddr;
719         val = getprop ( devinfo_p->devi_nodeid, "promversion", -1 );
720         if ( val == -1 ) {
721                 val = getprop ( devinfo_p->devi_nodeid, "hw-version", -1 );
722         }
723         if (val != -1) {
724                 snprintf(fcp->ac_hard_vers,
725                     sizeof(fcp->ac_hard_vers), "%d.%d.%d",
726                         (val >> 16) & 0xff, (val >> 8) & 0xff, val & 0xff);
727         } else
728                 snprintf(fcp->ac_hard_vers,
729                     sizeof(fcp->ac_hard_vers), "Unknown");
730
731         val = getprop ( devinfo_p->devi_nodeid, "serialnumber", -1 );
732         if ( val != -1 )
733                 fcp->ac_serial = val;
734
735         valp = (addr_t)getlongprop ( devinfo_p->devi_nodeid, "model" );
736         if ( valp )
737         {
738                 /*
739                  * Media Type
740                  */
741                 switch (fcp->ac_device) {
742
743 #ifdef FORE_SBUS
744                 case DEV_FORE_SBA200E:
745                         fcp->ac_media = MEDIA_OC3C;
746                         fup->fu_pif.pif_pcr = ATM_PCR_OC3C;
747                         break;
748
749                 case DEV_FORE_SBA200:
750                         /*
751                          * Look at the /SSS trailer to determine 4B5B speed
752                          *      TAXI-100 = 125; TAXI-140 = 175
753                          * Assume that OC3 has no /SSS speed identifier.
754                          */
755                         while (*valp && *valp != '/')
756                                 valp++;
757                         if (*valp == NULL) {
758                                 fcp->ac_media = MEDIA_OC3C;
759                                 fup->fu_pif.pif_pcr = ATM_PCR_OC3C;
760                         } else if (strcmp(valp, "/125") == 0) {
761                                 fcp->ac_media = MEDIA_TAXI_100;
762                                 fup->fu_pif.pif_pcr = ATM_PCR_TAXI100;
763                         } else {
764                                 fcp->ac_media = MEDIA_TAXI_140;
765                                 fup->fu_pif.pif_pcr = ATM_PCR_TAXI140;
766                         }
767                         break;
768 #endif  /* FORE_SBUS */
769                 }
770
771                 /*
772                  * Free property space
773                  */
774                 KM_FREE(valp, getproplen(devinfo_p->devi_nodeid, "model"), 0);
775         }
776
777         /*
778          * Bus information
779          */
780         fcp->ac_busslot = 
781 #ifdef SBUS_SIZE
782                 (long)(devinfo_p->devi_reg->reg_addr - SBUS_BASE) / SBUS_SIZE;
783 #else
784                 sbusslot((u_long)devinfo_p->devi_reg->reg_addr);
785 #endif
786
787         val = getprop(devinfo_p->devi_parent->devi_nodeid, "burst-sizes", 0);
788         if (val & SBUS_BURST32)
789                 fcp->ac_bustype = BUS_SBUS_B32;
790         else
791                 fcp->ac_bustype = BUS_SBUS_B16;
792
793         /*
794          * Set device capabilities
795          */
796         fup->fu_pif.pif_maxvpi = FORE_MAX_VPI;
797         fup->fu_pif.pif_maxvci = FORE_MAX_VCI;
798
799         /*
800          * Register this interface with ATM core services
801          */
802         if ( atm_physif_register
803                         ((Cmn_unit *)fup, FORE_DEV_NAME, fore_services) != 0 )
804         {
805                 /*
806                  * Registration failed - back everything out
807                  */
808                 /*
809                  * Modload calls UNLOAD if it get's a failure - don't
810                  * call fore_unload() here.
811                  */
812                 return ( -1 );
813         }
814
815         /*
816          * Initialize the CP microcode program.
817          */
818         fore_initialize(fup);
819
820         return (0);
821 }
822 #endif  /* sun */
823
824
825 #if defined(__DragonFly__) || defined(__FreeBSD__)
826 /*
827  * Device probe routine
828  * 
829  * Determine if this driver will support the identified device.  If we claim
830  * to support the device, our attach routine will (later) be called for the
831  * device.
832  *
833  * Arguments:
834  *      config_id       device's PCI configuration ID
835  *      device_id       device's PCI Vendor/Device ID
836  *
837  * Returns:
838  *      name    device identification string
839  *      NULL    device not claimed by this driver
840  *
841  */
842 static const char *
843 fore_pci_probe(config_id, device_id)
844         pcici_t config_id;
845         pcidi_t device_id;
846 {
847
848         /*
849          * Initialize driver stuff
850          */
851         if (fore_inited == 0) {
852                 if (fore_start())
853                         return (NULL);
854         }
855
856         if ((device_id & 0xffff) != FORE_VENDOR_ID)
857                 return (NULL);
858
859         if (((device_id >> 16) & 0xffff) == FORE_PCA200E_ID)
860                 return ("FORE Systems PCA-200E ATM");
861
862         return (NULL);
863 }
864
865
866 /*
867  * Device attach routine
868  * 
869  * Attach a device we've previously claimed to support.  Walk through its
870  * register set and map, as required.  Determine what level the device will
871  * be interrupting at and then register an interrupt handler for it.  If we
872  * succeed, then reset the adapter and initialize the microcode.
873  * Last, register the interface with the kernel ATM services.
874  *
875  * Arguments:
876  *      config_id       device's PCI configuration ID
877  *      unit            device unit number
878  *
879  * Returns:
880  *      none
881  *
882  */
883 static void
884 fore_pci_attach(config_id, unit)
885         pcici_t config_id;
886         int     unit;
887 {
888         Fore_unit       *fup;
889         vm_offset_t     va;
890         vm_offset_t     pa;
891         pcidi_t         device_id;
892         long            val;
893         int             err_count = BOOT_LOOPS;
894
895         /*
896          * Just checking...
897          */
898         if (unit >= FORE_MAX_UNITS) {
899                 log(LOG_ERR, "%s%d: too many devices\n", 
900                         FORE_DEV_NAME, unit);
901                 return;
902         }
903
904         /*
905          * Make sure this isn't a duplicate unit
906          */
907         if (fore_units[unit] != NULL)
908                 return;
909
910         /*
911          * Allocate a new unit structure
912          */
913         fup = (Fore_unit *) atm_dev_alloc(sizeof(Fore_unit), sizeof(int), 0);
914         if (fup == NULL)
915                 return;
916
917         /*
918          * Start initializing it
919          */
920         fup->fu_unit = unit;
921         fup->fu_mtu = FORE_IFF_MTU;
922         fup->fu_pcitag = config_id;
923         fup->fu_vcc_pool = &fore_vcc_pool;
924         fup->fu_nif_pool = &fore_nif_pool;
925         fup->fu_ioctl = fore_atm_ioctl;
926         fup->fu_instvcc = fore_instvcc;
927         fup->fu_openvcc = fore_openvcc;
928         fup->fu_closevcc = fore_closevcc;
929         fup->fu_output = fore_output;
930         callout_init(&fup->fu_init_timer);
931
932         /*
933          * Get our device type
934          */
935         device_id = pci_conf_read ( config_id, PCI_ID_REG );
936         switch ((device_id >> 16) & 0xffff) {
937
938         case FORE_PCA200E_ID:
939                 fup->fu_config.ac_device = DEV_FORE_PCA200E;
940                 break;
941
942         default:
943                 fup->fu_config.ac_device = DEV_UNKNOWN;
944         }
945
946         /*
947          * Enable Memory Mapping / Bus Mastering 
948          */
949         val = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG);
950         val |= (PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
951         pci_conf_write(config_id, PCI_COMMAND_STATUS_REG, val);
952
953         /*
954          * Map RAM
955          */
956         val = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG);
957         if ((val & PCIM_CMD_MEMEN) == 0) {
958                 log(LOG_ERR, "%s%d: memory mapping not enabled\n", 
959                         FORE_DEV_NAME, unit);
960                 goto failed;
961         }
962         if ((pci_map_mem(config_id, PCA200E_PCI_MEMBASE, &va, &pa)) == 0) {
963                 log(LOG_ERR, "%s%d: unable to map memory\n", 
964                         FORE_DEV_NAME, unit);
965                 goto failed;
966         }
967         fup->fu_ram = (Fore_mem *)va;
968         fup->fu_ramsize = PCA200E_RAM_SIZE;
969         fup->fu_mon = (Mon960 *)(fup->fu_ram + MON960_BASE);
970         fup->fu_ctlreg = (Fore_reg *)(va + PCA200E_HCR_OFFSET);
971         fup->fu_imask = (Fore_reg *)(va + PCA200E_IMASK_OFFSET);
972         fup->fu_psr = (Fore_reg *)(va + PCA200E_PSR_OFFSET);
973
974         /*
975          * Convert Endianess of Slave RAM accesses
976          */
977         val = pci_conf_read(config_id, PCA200E_PCI_MCTL);
978         val |= PCA200E_MCTL_SWAP;
979         pci_conf_write(config_id, PCA200E_PCI_MCTL, val);
980
981         /*
982          * Map interrupt in
983          */
984         if ( !pci_map_int( config_id, fore_intr, fup, &net_imask ) ) {
985                 log(LOG_ERR, "%s%d: unable to map interrupt\n", 
986                         FORE_DEV_NAME, unit);
987                 goto failed;
988         }
989
990         /*
991          * Poke the hardware - boot the CP and prepare it for downloading
992          */
993         fore_reset(fup);
994
995         /*
996          * Wait for the monitor to perform self-test
997          */
998         while (CP_READ(fup->fu_mon->mon_bstat) != BOOT_MONREADY) {
999                 if (CP_READ(fup->fu_mon->mon_bstat) == BOOT_FAILTEST) {
1000                         log(LOG_ERR, "%s%d: failed self-test\n", 
1001                                 FORE_DEV_NAME, unit);
1002                         goto failed;
1003                 } else if ( --err_count == 0 ) {
1004                         log(LOG_ERR, "%s%d: unable to boot - status=0x%lx\n", 
1005                                 FORE_DEV_NAME, unit,
1006                                 (u_long)CP_READ(fup->fu_mon->mon_bstat));
1007                         goto failed;
1008                 }
1009                 DELAY ( BOOT_DELAY );
1010         }
1011
1012         /*
1013          * Setup the adapter config info - at least as much as we can
1014          */
1015         fup->fu_config.ac_vendor = VENDOR_FORE;
1016         fup->fu_config.ac_vendapi = VENDAPI_FORE_1;
1017         fup->fu_config.ac_media = MEDIA_OC3C;
1018         fup->fu_pif.pif_pcr = ATM_PCR_OC3C;
1019         fup->fu_config.ac_bustype = BUS_PCI;
1020         fup->fu_config.ac_busslot = config_id->bus << 8 | config_id->slot;
1021
1022         /*
1023          * Save device ram info for user-level programs
1024          */
1025         fup->fu_config.ac_ram = (long)fup->fu_ram;
1026         fup->fu_config.ac_ramsize = fup->fu_ramsize;
1027
1028         /*
1029          * Set device capabilities
1030          */
1031         fup->fu_pif.pif_maxvpi = FORE_MAX_VPI;
1032         fup->fu_pif.pif_maxvci = FORE_MAX_VCI;
1033
1034         /*
1035          * Register this interface with ATM core services
1036          */
1037         if ( atm_physif_register
1038                         ((Cmn_unit *)fup, FORE_DEV_NAME, fore_services) != 0 )
1039         {
1040                 /*
1041                  * Registration failed - back everything out
1042                  */
1043                 goto failed;
1044         }
1045
1046         fore_units[unit] = fup;
1047         fore_nunits++;
1048
1049 #if BSD >= 199506
1050         /*
1051          * Add hook to our shutdown function
1052          */
1053         EVENTHANDLER_REGISTER(shutdown_post_sync, fore_pci_shutdown, fup,
1054                               SHUTDOWN_PRI_DEFAULT);
1055 #endif
1056
1057         /*
1058          * Initialize the CP microcode program.
1059          */
1060         fore_initialize(fup);
1061
1062         return;
1063
1064 failed:
1065         /*
1066          * Unattach the device from the system
1067          */
1068         fore_unattach(fup);
1069
1070         /*
1071          * Free any Fore-specific device resources
1072          */
1073         fore_interface_free(fup);
1074
1075         atm_dev_free(fup);
1076
1077         return;
1078 }
1079
1080
1081 #if BSD < 199506
1082 /*
1083  * Device shutdown routine
1084  * 
1085  * Arguments:
1086  *      kdc             pointer to device's configuration table
1087  *      force           forced shutdown flag
1088  *
1089  * Returns:
1090  *      none
1091  *
1092  */
1093 static int
1094 fore_pci_shutdown(kdc, force)
1095         struct kern_devconf     *kdc;
1096         int                     force;
1097 {
1098         Fore_unit       *fup;
1099
1100         if (kdc->kdc_unit < fore_nunits) {
1101
1102                 fup = fore_units[kdc->kdc_unit];
1103                 if (fup != NULL) {
1104                         fore_reset(fup);
1105                 }
1106         }
1107
1108         (void) dev_detach(kdc);
1109         return (0);
1110 }
1111 #else
1112 /*
1113  * Device shutdown routine
1114  * 
1115  * Arguments:
1116  *      howto           type of shutdown
1117  *      fup             pointer to device unit structure
1118  *
1119  * Returns:
1120  *      none
1121  *
1122  */
1123 static void
1124 fore_pci_shutdown(fup, howto)
1125         void            *fup;
1126         int             howto;
1127 {
1128
1129         fore_reset((Fore_unit *) fup);
1130
1131         return;
1132 }
1133 #endif  /* BSD < 199506 */
1134 #endif  /* __FreeBSD__ */
1135
1136
1137 /*
1138  * Device unattach routine
1139  * 
1140  * Reset the physical device, remove any pending timeouts, 
1141  * unmap any register sets, and unregister any interrupts.
1142  *
1143  * Arguments:
1144  *      fup             pointer to device unit structure
1145  *
1146  * Returns:
1147  *      none
1148  */ 
1149 static void
1150 fore_unattach(fup)
1151         Fore_unit       *fup;
1152 {
1153 #ifdef sun
1154         struct dev_info         *devinfo_p = fup->fu_devinfo;
1155         struct dev_reg          *dev_reg_p;
1156         struct dev_intr         *dev_intr_p;
1157         int                     i;
1158 #endif
1159
1160
1161         /*
1162          * Reset the board and return it to cold_start state.
1163          * Hopefully, this will prevent use of resources as
1164          * we're trying to free things up.
1165          */
1166         fore_reset(fup);
1167
1168         /*
1169          * Lock out all device interrupts
1170          */
1171         DEVICE_LOCK((Cmn_unit *)fup);
1172
1173         /*
1174          * Remove any pending timeout()'s
1175          */
1176         callout_stop(&fup->fu_init_timer);
1177
1178 #ifdef sun
1179         /*
1180          * Remove any mappings of the device
1181          */
1182         for ( dev_reg_p = devinfo_p->devi_reg, i = 1;
1183                 i <= devinfo_p->devi_nreg; i++, ++dev_reg_p )
1184         {
1185                 if ( dev_reg_p == NULL )
1186                 {
1187                         /*
1188                          * Can't happen...
1189                          */
1190                         break;
1191                 }
1192
1193                 /*
1194                  * Each device type has different register sets
1195                  */
1196                 switch (fup->fu_config.ac_device) {
1197
1198 #ifdef FORE_SBUS
1199                 case DEV_FORE_SBA200E:
1200
1201                         switch ( i )
1202                         {
1203                         /*
1204                          * Host Control Register (HCR)
1205                          */
1206                         case 1:
1207                                 unmap_regs((addr_t)fup->fu_ctlreg,
1208                                         sizeof(Fore_reg));
1209                                 break;
1210
1211                         /*
1212                          * SBus Burst Transfer Configuration Register
1213                          */
1214                         case 2:
1215                                 /*
1216                                  * Not used
1217                                  */
1218                                 break;
1219
1220                         /*
1221                          * SBus Interrupt Level Select Register
1222                          */
1223                         case 3:
1224                                 unmap_regs((addr_t)fup->fu_intlvl,
1225                                         sizeof(Fore_reg));
1226                                 break;
1227
1228                         /*
1229                          * i960 RAM
1230                          */
1231                         case 4:
1232                                 unmap_regs((addr_t)fup->fu_ram,
1233                                         fup->fu_ramsize);
1234                                 break;
1235                         }
1236                         break;
1237
1238                 case DEV_FORE_SBA200:
1239
1240                         switch ( i )
1241                         {
1242                         /*
1243                          * Board Control Register (BCR)
1244                          */
1245                         case 1:
1246                                 unmap_regs((addr_t)fup->fu_ctlreg,
1247                                         sizeof(Fore_reg));
1248                                 break;
1249
1250                         /*
1251                          * i960 RAM
1252                          */
1253                         case 2:
1254                                 unmap_regs((addr_t)fup->fu_ram,
1255                                         fup->fu_ramsize);
1256                                 break;
1257                         }
1258                         break;
1259 #endif  /* FORE_SBUS */
1260                 }
1261         }
1262
1263         /*
1264          * Remove the interrupt vector(s)
1265          */
1266         dev_intr_p = devinfo_p->devi_intr;
1267         for ( i = devinfo_p->devi_nintr; i > 0; --i, ++dev_intr_p )
1268         {
1269                 if ( dev_intr_p == NULL )
1270                 {
1271                         /*
1272                          * Can't happen...
1273                          */
1274                         break;
1275                 }
1276                 (void) remintr ( dev_intr_p->int_pri, fore_poll );
1277         }
1278 #endif  /* sun */
1279
1280 #if defined(__DragonFly__) || defined(__FreeBSD__)
1281         /*
1282          * Unmap the device interrupt
1283          */
1284         (void) pci_unmap_int(fup->fu_pcitag);
1285
1286         /*
1287          * Unmap memory
1288          */
1289 #ifdef notdef
1290         (void) pci_unmap_mem(fup->fu_pcitag, PCA200E_PCI_MEMBASE);
1291 #endif
1292 #endif  /* __FreeBSD__ */
1293
1294         DEVICE_UNLOCK((Cmn_unit *)fup);
1295 }
1296
1297
1298 /*
1299  * Device reset routine
1300  * 
1301  * Reset the physical device
1302  *
1303  * Arguments:
1304  *      fup             pointer to device unit structure
1305  *
1306  * Returns:
1307  *      none
1308  */ 
1309 static void
1310 fore_reset(fup)
1311         Fore_unit       *fup;
1312 {
1313         int     s = splimp();
1314
1315         /*
1316          * Reset the board and return it to cold_start state
1317          */
1318         if (fup->fu_mon)
1319                 fup->fu_mon->mon_bstat = CP_WRITE(BOOT_COLDSTART);
1320
1321         if (fup->fu_ctlreg) {
1322
1323                 switch (fup->fu_config.ac_device) {
1324
1325 #ifdef FORE_SBUS
1326                 case DEV_FORE_SBA200E:
1327                         /*
1328                          * Reset i960 by setting and clearing RESET
1329                          */
1330                         SBA200E_HCR_INIT(*fup->fu_ctlreg, SBA200E_RESET);
1331                         SBA200E_HCR_CLR(*fup->fu_ctlreg, SBA200E_RESET);
1332                         break;
1333
1334                 case DEV_FORE_SBA200:
1335                         /*
1336                          * Reset i960 by setting and clearing RESET
1337                          *
1338                          * SBA200 will NOT reset if bit is OR'd in!
1339                          */
1340                         *fup->fu_ctlreg = SBA200_RESET;
1341                         *fup->fu_ctlreg = SBA200_RESET_CLR;
1342                         break;
1343 #endif  /* FORE_SBUS */
1344 #ifdef FORE_PCI
1345                 case DEV_FORE_PCA200E:
1346                         /*
1347                          * Reset i960 by setting and clearing RESET
1348                          */
1349                         PCA200E_HCR_INIT(*fup->fu_ctlreg, PCA200E_RESET);
1350                         DELAY(10000);
1351                         PCA200E_HCR_CLR(*fup->fu_ctlreg, PCA200E_RESET);
1352                         break;
1353
1354 #endif
1355                 default:
1356                         panic("fore_reset: unknown device type");
1357                         break;
1358                 }
1359         }
1360
1361         (void) splx(s);
1362         return;
1363 }
1364
1365
1366 #ifndef ATM_LINKED
1367 /*
1368  *******************************************************************
1369  *
1370  * Loadable Module Support
1371  *
1372  *******************************************************************
1373  */
1374
1375 #ifdef sun
1376 /*
1377  * Generic module load processing
1378  * 
1379  * This function is called by an OS-specific function when this
1380  * module is being loaded.
1381  *
1382  * Arguments:
1383  *      none
1384  *
1385  * Returns:
1386  *      0       load was successful 
1387  *      errno   load failed - reason indicated
1388  *
1389  */
1390 static int
1391 fore_doload()
1392 {
1393         int     err = 0;
1394
1395         /*
1396          * Start us up
1397          */
1398         err = fore_start();
1399         if (err)
1400                 /* Problems, clean up */
1401                 (void)fore_stop();
1402
1403         return (err);
1404 }
1405
1406
1407 /*
1408  * Generic module unload processing
1409  * 
1410  * This function is called by an OS-specific function when this
1411  * module is being unloaded.
1412  *
1413  * Arguments:
1414  *      none
1415  *
1416  * Returns:
1417  *      0       unload was successful 
1418  *      errno   unload failed - reason indicated
1419  *
1420  */
1421 static int
1422 fore_dounload()
1423 {
1424         int     err = 0;
1425
1426         /*
1427          * OK, try to clean up our mess
1428          */
1429         err = fore_stop();
1430
1431         return (err);
1432 }
1433
1434
1435 /*
1436  * Loadable driver description
1437  */
1438 static struct vdldrv    fore_drv = {
1439         VDMAGIC_DRV,    /* Device Driver */
1440         "fore_mod",     /* name */
1441         &fore_ops,      /* dev_ops */
1442         NULL,           /* bdevsw */
1443         NULL,           /* cdevsw */
1444         0,              /* blockmajor */
1445         0               /* charmajor */
1446 };
1447
1448
1449 /*
1450  * Loadable module support entry point
1451  * 
1452  * This is the routine called by the vd driver for all loadable module
1453  * functions for this pseudo driver.  This routine name must be specified
1454  * on the modload(1) command.  This routine will be called whenever the
1455  * modload(1), modunload(1) or modstat(1) commands are issued for this
1456  * module.
1457  *
1458  * Arguments:
1459  *      cmd     vd command code
1460  *      vdp     pointer to vd driver's structure
1461  *      vdi     pointer to command-specific vdioctl_* structure
1462  *      vds     pointer to status structure (VDSTAT only)
1463  *
1464  * Returns:
1465  *      0       command was successful 
1466  *      errno   command failed - reason indicated
1467  *
1468  */
1469 int
1470 fore_mod(cmd, vdp, vdi, vds)
1471         int             cmd;
1472         struct vddrv    *vdp;
1473         caddr_t         vdi;
1474         struct vdstat   *vds;
1475 {
1476         int     err = 0;
1477
1478         switch (cmd) {
1479
1480         case VDLOAD:
1481                 /*
1482                  * Module Load
1483                  *
1484                  * We dont support any user configuration
1485                  */
1486                 err = fore_doload();
1487                 if (err == 0)
1488                         /* Let vd driver know about us */
1489                         vdp->vdd_vdtab = (struct vdlinkage *)&fore_drv;
1490                 break;
1491
1492         case VDUNLOAD:
1493                 /*
1494                  * Module Unload
1495                  */
1496                 err = fore_dounload();
1497                 break;
1498
1499         case VDSTAT:
1500                 /*
1501                  * Module Status
1502                  */
1503
1504                 /* Not much to say at the moment */
1505
1506                 break;
1507
1508         default:
1509                 log(LOG_ERR, "fore_mod: Unknown vd command 0x%x\n", cmd);
1510                 err = EINVAL;
1511         }
1512
1513         return (err);
1514 }
1515 #endif  /* sun */
1516
1517 #if defined(__DragonFly__) || defined(__FreeBSD__)
1518 #ifdef notdef
1519
1520 /*
1521  * Driver entry points
1522  */
1523 static struct cdevsw fore_cdev = {
1524         /* name */      noname,
1525         /* maj */       -1,
1526         /* flags */     0,
1527         /* port */      NULL,
1528         /* clone */     NULL,
1529
1530         /* open */      noopen,
1531         /* close */     noclose,
1532         /* read */      noread,
1533         /* write */     nowrite,
1534         /* ioctl */     noioctl,
1535         /* poll */      nopoll,
1536         /* mmap */      nommap,
1537         /* strategy */  nostrategy,
1538         /* dump */      nodump,
1539         /* psize */     nopsize
1540 };
1541
1542
1543 /*
1544  * Loadable device driver module description
1545  */
1546 #if BSD < 199506
1547 MOD_DEV("fore_mod", LM_DT_CHAR, -1, (void *)&fore_cdev);
1548 #else
1549 MOD_DEV(fore, LM_DT_CHAR, -1, (void *)&fore_cdev);
1550 #endif
1551
1552
1553 /*
1554  * Loadable module support "load" entry point
1555  * 
1556  * This is the routine called by the lkm driver whenever the
1557  * modload(1) command is issued for this module.
1558  *
1559  * Arguments:
1560  *      lkmtp   pointer to lkm drivers's structure
1561  *      cmd     lkm command code
1562  *
1563  * Returns:
1564  *      0       command was successful 
1565  *      errno   command failed - reason indicated
1566  *
1567  */
1568 static int
1569 fore_load(lkmtp, cmd)
1570         struct lkm_table        *lkmtp;
1571         int             cmd;
1572 {
1573         return(fore_doload());
1574 }
1575
1576
1577 /*
1578  * Loadable module support "unload" entry point
1579  * 
1580  * This is the routine called by the lkm driver whenever the
1581  * modunload(1) command is issued for this module.
1582  *
1583  * Arguments:
1584  *      lkmtp   pointer to lkm drivers's structure
1585  *      cmd     lkm command code
1586  *
1587  * Returns:
1588  *      0       command was successful 
1589  *      errno   command failed - reason indicated
1590  *
1591  */
1592 static int
1593 fore_unload(lkmtp, cmd)
1594         struct lkm_table        *lkmtp;
1595         int             cmd;
1596 {
1597         return(fore_dounload());
1598 }
1599
1600
1601 /*
1602  * Loadable module support entry point
1603  * 
1604  * This is the routine called by the lkm driver for all loadable module
1605  * functions for this driver.  This routine name must be specified
1606  * on the modload(1) command.  This routine will be called whenever the
1607  * modload(1), modunload(1) or modstat(1) commands are issued for this
1608  * module.
1609  *
1610  * Arguments:
1611  *      lkmtp   pointer to lkm drivers's structure
1612  *      cmd     lkm command code
1613  *      ver     lkm version
1614  *
1615  * Returns:
1616  *      0       command was successful 
1617  *      errno   command failed - reason indicated
1618  *
1619  */
1620 int
1621 fore_mod(lkmtp, cmd, ver)
1622         struct lkm_table        *lkmtp;
1623         int             cmd;
1624         int             ver;
1625 {
1626 #if BSD < 199506
1627         DISPATCH(lkmtp, cmd, ver, fore_load, fore_unload, nosys);
1628 #else
1629         DISPATCH(lkmtp, cmd, ver, fore_load, fore_unload, lkm_nullcmd);
1630 #endif
1631 }
1632 #endif  /* notdef */
1633 #endif  /* __FreeBSD__ */
1634
1635 #endif  /* ATM_LINKED */
1636