Initial import of binutils 2.22 on the new vendor branch
[dragonfly.git] / sys / dev / atm / hea / eni_if.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/hea/eni_if.c,v 1.5 1999/08/28 00:41:44 peter Exp $
27  *      @(#) $DragonFly: src/sys/dev/atm/hea/eni_if.c,v 1.7 2008/03/01 22:03:13 swildner Exp $
28  */
29
30 /*
31  * Efficient ENI Adapter Support
32  * -----------------------------
33  *
34  * Network interface layer support
35  *
36  */
37
38 #include <netproto/atm/kern_include.h>
39
40 #include "eni_stats.h"
41 #include "eni.h"
42 #include "eni_suni.h"
43 #include "eni_var.h"
44
45 static void     eni_get_stats (Eni_unit *);
46
47 /*
48  * SUNI statistics counters take one of three forms:
49  *      single byte value       (0x0 - 0xff)
50  *      two byte value          (0x0 - 0xffff)
51  *      two + 1/2 (three) byte value
52  *                              (0x0 - 0x0fffff)
53  */
54 #define READ_ONE(x)     ( (eup->eu_suni[(x)] & 0xff) )
55
56 #define READ_TWO(x)     ( (eup->eu_suni[(x)+1] & 0xff) << 8 | \
57                           (eup->eu_suni[(x)] & 0xff) )
58
59 #define READ_THREE(x)   ( (eup->eu_suni[(x)+2] & 0xf) << 16 | \
60                           (eup->eu_suni[(x)+1] & 0xff) << 8 | \
61                           (eup->eu_suni[(x)] & 0xff) )
62
63 /*
64  * Do an initial read of the error counters without saving them.
65  * In effect, this will "zero" our idea of the number of errors
66  * which have occurred since the driver was loaded.
67  *
68  * Arguments:
69  *      eup             pointer to per unit structure
70  *
71  * Returns:
72  *      none
73  *
74  */
75 void
76 eni_zero_stats(Eni_unit *eup)
77 {
78         int     val;
79
80         /*
81          * Write the SUNI master control register which
82          * will cause all the statistics counters to be
83          * loaded.
84          */
85         eup->eu_suni[SUNI_MASTER_REG] = eup->eu_suni[SUNI_MASTER_REG];
86
87         /*
88          * Delay to allow for counter load time...
89          */
90         DELAY ( SUNI_DELAY );
91
92         /*
93          * Statistics counters contain the number of events
94          * since the last time the counter was read.
95          */
96         val = READ_TWO ( SUNI_SECT_BIP_REG );           /* oc3_sect_bip8 */
97         val = READ_TWO ( SUNI_PATH_BIP_REG );           /* oc3_path_bip8 */
98         val = READ_THREE ( SUNI_LINE_BIP_REG );         /* oc3_line_bip24 */
99         val = READ_THREE ( SUNI_LINE_FEBE_REG );        /* oc3_line_febe */
100         val = READ_TWO ( SUNI_PATH_FEBE_REG );          /* oc3_path_febe */
101         val = READ_ONE ( SUNI_HECS_REG );               /* oc3_hec_corr */
102         val = READ_ONE ( SUNI_UHECS_REG );              /* oc3_hec_uncorr */
103 }
104
105 /*
106  * Retrieve SUNI stats
107  *
108  * Arguments:
109  *      eup             pointer to per unit structure
110  *
111  * Returns:
112  *      none
113  *
114  */
115 static void
116 eni_get_stats (Eni_unit *eup)
117 {
118         /*
119          * Write the SUNI master control register which
120          * will cause all the statistics counters to be
121          * loaded.
122          */
123         eup->eu_suni[SUNI_MASTER_REG] = eup->eu_suni[SUNI_MASTER_REG];
124
125         /*
126          * Delay to allow for counter load time...
127          */
128         DELAY ( 10 );
129
130         /*
131          * Statistics counters contain the number of events
132          * since the last time the counter was read.
133          */
134         eup->eu_stats.eni_st_oc3.oc3_sect_bip8 +=
135                         READ_TWO ( SUNI_SECT_BIP_REG );
136         eup->eu_stats.eni_st_oc3.oc3_path_bip8 +=
137                         READ_TWO ( SUNI_PATH_BIP_REG );
138         eup->eu_stats.eni_st_oc3.oc3_line_bip24 +=
139                         READ_THREE ( SUNI_LINE_BIP_REG );
140         eup->eu_stats.eni_st_oc3.oc3_line_febe +=
141                         READ_THREE ( SUNI_LINE_FEBE_REG );
142         eup->eu_stats.eni_st_oc3.oc3_path_febe +=
143                         READ_TWO ( SUNI_PATH_FEBE_REG );
144         eup->eu_stats.eni_st_oc3.oc3_hec_corr +=
145                         READ_ONE ( SUNI_HECS_REG );
146         eup->eu_stats.eni_st_oc3.oc3_hec_uncorr +=
147                         READ_ONE ( SUNI_UHECS_REG );
148 }
149
150 /*
151  * Handle netatm core service interface ioctl requests
152  *
153  * Called at splnet.
154  *
155  * Arguments:
156  *      code            ioctl function (sub)code
157  *      data            data to/from ioctl
158  *      arg             optional code-specific argument
159  *
160  * Returns:
161  *      0               request processed successfully
162  *      error           request failed - reason code
163  *
164  */
165 int
166 eni_atm_ioctl(int code, caddr_t data, caddr_t arg)
167 {
168         struct atminfreq        *aip = (struct atminfreq *)data;
169         struct atm_pif          *pip = (struct atm_pif *)arg;
170         Eni_unit                *eup = (Eni_unit *)pip;
171         caddr_t                 buf = aip->air_buf_addr;
172         struct air_vinfo_rsp    *avr;
173         int                     count, len, buf_len = aip->air_buf_len;
174         int                     err = 0;
175         char                    ifname[2*IFNAMSIZ];
176
177         ATM_DEBUG2("eni_atm_ioctl: code=%d, opcode=%d\n",
178                 code, aip->air_opcode );
179
180         switch ( aip->air_opcode ) {
181
182         case AIOCS_INF_VST:
183                 /*
184                  * Get vendor statistics
185                  */
186                 if ( eup == NULL )
187                         return ( ENXIO );
188                 ksnprintf ( ifname, sizeof(ifname),
189                     "%s%d", pip->pif_name, pip->pif_unit );
190
191                 /*
192                  * Cast response structure onto user's buffer
193                  */
194                 avr = (struct air_vinfo_rsp *)buf;
195
196                 /*
197                  * How large is the response structure
198                  */
199                 len = sizeof(struct air_vinfo_rsp);
200
201                 /*
202                  * Sanity check - enough room for response structure?
203                  */
204                 if ( buf_len < len )
205                         return ( ENOSPC );
206
207                 /*
208                  * Copy interface name into response structure
209                  */
210                 if ((err = copyout(ifname, avr->avsp_intf, IFNAMSIZ)) != 0)
211                         break;
212
213                 /*
214                  * Advance the buffer address and decrement the size
215                  */
216                 buf += len;
217                 buf_len -= len;
218
219                 /*
220                  * Get the vendor stats (SUNI) from the hardware
221                  */
222                 eni_get_stats ( eup );
223                 /*
224                  * Stick as much of it as we have room for
225                  * into the response
226                  */
227                 count = MIN ( sizeof(Eni_stats), buf_len );
228
229                 /*
230                  * Copy stats into user's buffer. Return value is
231                  * amount of data copied.
232                  */
233                 if ((err = copyout((void *)&eup->eu_stats, buf, count)) != 0)
234                                 break;
235                 buf += count;
236                 buf_len -= count;
237                 if ( count < sizeof(Eni_stats) )
238                         err = ENOSPC;
239
240                 /*
241                  * Record amount we're returning as vendor info...
242                  */
243                 if ((err = copyout(&count, &avr->avsp_len, sizeof(int))) != 0)
244                         break;
245
246                 /*
247                  * Update the reply pointers and length
248                  */
249                 aip->air_buf_addr = buf;
250                 aip->air_buf_len = buf_len;
251                 break;
252
253         default:
254                 err = ENOSYS;           /* Operation not supported */
255                 break;
256         }
257
258         return ( err );
259
260 }
261