443c8c13754d0996433b2038111815e9869de9d3
[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.6 2006/12/20 18:14:38 dillon 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 ( eup )
77         Eni_unit *eup;
78 {
79         int     val;
80
81         /*
82          * Write the SUNI master control register which
83          * will cause all the statistics counters to be
84          * loaded.
85          */
86         eup->eu_suni[SUNI_MASTER_REG] = eup->eu_suni[SUNI_MASTER_REG];
87
88         /*
89          * Delay to allow for counter load time...
90          */
91         DELAY ( SUNI_DELAY );
92
93         /*
94          * Statistics counters contain the number of events
95          * since the last time the counter was read.
96          */
97         val = READ_TWO ( SUNI_SECT_BIP_REG );           /* oc3_sect_bip8 */
98         val = READ_TWO ( SUNI_PATH_BIP_REG );           /* oc3_path_bip8 */
99         val = READ_THREE ( SUNI_LINE_BIP_REG );         /* oc3_line_bip24 */
100         val = READ_THREE ( SUNI_LINE_FEBE_REG );        /* oc3_line_febe */
101         val = READ_TWO ( SUNI_PATH_FEBE_REG );          /* oc3_path_febe */
102         val = READ_ONE ( SUNI_HECS_REG );               /* oc3_hec_corr */
103         val = READ_ONE ( SUNI_UHECS_REG );              /* oc3_hec_uncorr */
104 }
105
106 /*
107  * Retrieve SUNI stats
108  *
109  * Arguments:
110  *      eup             pointer to per unit structure
111  *
112  * Returns:
113  *      none
114  *
115  */
116 static void
117 eni_get_stats ( eup )
118         Eni_unit        *eup;
119 {
120         /*
121          * Write the SUNI master control register which
122          * will cause all the statistics counters to be
123          * loaded.
124          */
125         eup->eu_suni[SUNI_MASTER_REG] = eup->eu_suni[SUNI_MASTER_REG];
126
127         /*
128          * Delay to allow for counter load time...
129          */
130         DELAY ( 10 );
131
132         /*
133          * Statistics counters contain the number of events
134          * since the last time the counter was read.
135          */
136         eup->eu_stats.eni_st_oc3.oc3_sect_bip8 +=
137                         READ_TWO ( SUNI_SECT_BIP_REG );
138         eup->eu_stats.eni_st_oc3.oc3_path_bip8 +=
139                         READ_TWO ( SUNI_PATH_BIP_REG );
140         eup->eu_stats.eni_st_oc3.oc3_line_bip24 +=
141                         READ_THREE ( SUNI_LINE_BIP_REG );
142         eup->eu_stats.eni_st_oc3.oc3_line_febe +=
143                         READ_THREE ( SUNI_LINE_FEBE_REG );
144         eup->eu_stats.eni_st_oc3.oc3_path_febe +=
145                         READ_TWO ( SUNI_PATH_FEBE_REG );
146         eup->eu_stats.eni_st_oc3.oc3_hec_corr +=
147                         READ_ONE ( SUNI_HECS_REG );
148         eup->eu_stats.eni_st_oc3.oc3_hec_uncorr +=
149                         READ_ONE ( SUNI_UHECS_REG );
150 }
151
152 /*
153  * Handle netatm core service interface ioctl requests
154  *
155  * Called at splnet.
156  *
157  * Arguments:
158  *      code            ioctl function (sub)code
159  *      data            data to/from ioctl
160  *      arg             optional code-specific argument
161  *
162  * Returns:
163  *      0               request processed successfully
164  *      error           request failed - reason code
165  *
166  */
167 int
168 eni_atm_ioctl ( code, data, arg )
169         int code;
170         caddr_t data;
171         caddr_t arg;
172 {
173         struct atminfreq        *aip = (struct atminfreq *)data;
174         struct atm_pif          *pip = (struct atm_pif *)arg;
175         Eni_unit                *eup = (Eni_unit *)pip;
176         caddr_t                 buf = aip->air_buf_addr;
177         struct air_vinfo_rsp    *avr;
178         int                     count, len, buf_len = aip->air_buf_len;
179         int                     err = 0;
180         char                    ifname[2*IFNAMSIZ];
181
182         ATM_DEBUG2("eni_atm_ioctl: code=%d, opcode=%d\n",
183                 code, aip->air_opcode );
184
185         switch ( aip->air_opcode ) {
186
187         case AIOCS_INF_VST:
188                 /*
189                  * Get vendor statistics
190                  */
191                 if ( eup == NULL )
192                         return ( ENXIO );
193                 ksnprintf ( ifname, sizeof(ifname),
194                     "%s%d", pip->pif_name, pip->pif_unit );
195
196                 /*
197                  * Cast response structure onto user's buffer
198                  */
199                 avr = (struct air_vinfo_rsp *)buf;
200
201                 /*
202                  * How large is the response structure
203                  */
204                 len = sizeof(struct air_vinfo_rsp);
205
206                 /*
207                  * Sanity check - enough room for response structure?
208                  */
209                 if ( buf_len < len )
210                         return ( ENOSPC );
211
212                 /*
213                  * Copy interface name into response structure
214                  */
215                 if ((err = copyout(ifname, avr->avsp_intf, IFNAMSIZ)) != 0)
216                         break;
217
218                 /*
219                  * Advance the buffer address and decrement the size
220                  */
221                 buf += len;
222                 buf_len -= len;
223
224                 /*
225                  * Get the vendor stats (SUNI) from the hardware
226                  */
227                 eni_get_stats ( eup );
228                 /*
229                  * Stick as much of it as we have room for
230                  * into the response
231                  */
232                 count = MIN ( sizeof(Eni_stats), buf_len );
233
234                 /*
235                  * Copy stats into user's buffer. Return value is
236                  * amount of data copied.
237                  */
238                 if ((err = copyout((void *)&eup->eu_stats, buf, count)) != 0)
239                                 break;
240                 buf += count;
241                 buf_len -= count;
242                 if ( count < sizeof(Eni_stats) )
243                         err = ENOSPC;
244
245                 /*
246                  * Record amount we're returning as vendor info...
247                  */
248                 if ((err = copyout(&count, &avr->avsp_len, sizeof(int))) != 0)
249                         break;
250
251                 /*
252                  * Update the reply pointers and length
253                  */
254                 aip->air_buf_addr = buf;
255                 aip->air_buf_len = buf_len;
256                 break;
257
258         default:
259                 err = ENOSYS;           /* Operation not supported */
260                 break;
261         }
262
263         return ( err );
264
265 }
266