57ae28e7e9045de70f9f4fd420caad1375382c8d
[dragonfly.git] / sys / dev / atm / hea / eni_vcm.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_vcm.c,v 1.3 1999/08/28 00:41:47 peter Exp $
27  *      @(#) $DragonFly: src/sys/dev/atm/hea/eni_vcm.c,v 1.6 2004/08/25 01:53:38 dillon Exp $
28  */
29
30 /*
31  * Efficient ENI Adapter Support
32  * -----------------------------
33  *
34  * Virtual Channel Managment
35  *
36  */
37
38
39 #include <netproto/atm/kern_include.h>
40
41 #include "eni_stats.h"
42 #include "eni.h"
43 #include "eni_var.h"
44
45 /*
46  * VCC Stack Instantiation
47  * 
48  * This function is called via the common driver code during a device VCC
49  * stack instantiation.  The common code has already validated some of
50  * the request so we just need to check a few more ENI-specific details.
51  *
52  * Called at splnet.
53  *
54  * Arguments:
55  *      cup     pointer to device common unit
56  *      cvp     pointer to common VCC entry
57  *
58  * Returns:
59  *      0       instantiation successful
60  *      err     instantiation failed - reason indicated
61  *
62  */
63 int
64 eni_instvcc(cup, cvp)
65         Cmn_unit        *cup;
66         Cmn_vcc         *cvp;
67 {
68         Eni_unit        *eup = (Eni_unit *)cup;
69         Eni_vcc         *evp = (Eni_vcc *)cvp;
70         Atm_attributes  *ap = &evp->ev_connvc->cvc_attr;
71
72         /*
73          * Validate requested AAL
74          */
75         switch (ap->aal.type) {
76
77         case ATM_AAL0:
78                 break;
79
80         case ATM_AAL5:
81                 if ((ap->aal.v.aal5.forward_max_SDU_size > ENI_IFF_MTU) ||
82                     (ap->aal.v.aal5.backward_max_SDU_size > ENI_IFF_MTU)) {
83                         eup->eu_stats.eni_st_drv.drv_vc_maxpdu++;
84                         return (EINVAL);
85                 }
86                 break;
87
88         default:
89                 return (EINVAL);
90         }
91
92         return (0);
93 }
94
95
96 /*
97  * Open a VCC
98  *
99  * This function is called via the common driver code after receiving a
100  * stack *_INIT* command. The common code has already validated most of
101  * the request so we just need to check a few more ENI-specific details.
102  *
103  * Called at splimp.
104  *
105  * Arguments:
106  *      cup     pointer to device common unit
107  *      cvp     pointer to common VCC entry
108  *
109  * Returns:
110  *      0       open successful
111  *      err     open failed
112  *
113  */
114 int
115 eni_openvcc ( cup, cvp )
116         Cmn_unit        *cup;
117         Cmn_vcc         *cvp;
118 {
119         Eni_unit        *eup = (Eni_unit *)cup;
120         Eni_vcc         *evp = (Eni_vcc *)cvp;
121         struct vccb     *vcp = evp->ev_connvc->cvc_vcc;
122         int             err = 0;
123
124         VCI_Table       *vct;
125         int             size;
126         int             mode;
127         int             nsize;
128
129         /*
130          * Validate the VPI and VCI values
131          */
132         if ( (vcp->vc_vpi > eup->eu_pif.pif_maxvpi) ||
133              (vcp->vc_vci > eup->eu_pif.pif_maxvci) ) {
134                 eup->eu_stats.eni_st_drv.drv_vc_badrng++;
135                 return ( EFAULT );
136         }
137
138         /*
139          * Check if this VCI is already active
140          */
141         vct = &eup->eu_vcitbl[ vcp->vc_vci ];
142         if ( vct->vci_control >> VCI_MODE_SHIFT != VCI_MODE_TRASH ) {
143                 return ( EEXIST );
144         }
145
146         /*
147          * Allocate some permanent adapter memory for the reassembly
148          * buffer. Special case the signalling channel(s) buffer size.
149          * Otherwise, the buffer size will be based on whether this is
150          * a server or client card.
151          */
152         if ( vcp->vc_vci == UNI_SIG_VCI )       /* HACK */
153                 size = RX_SIG_BSIZE;
154         else
155                 size = (eup->eu_ramsize > MAX_CLIENT_RAM * ENI_BUF_PGSZ) ?
156                         RX_SERVER_BSIZE * ENI_BUF_PGSZ :
157                         RX_CLIENT_BSIZE * ENI_BUF_PGSZ;
158
159         if ( ( evp->ev_rxbuf = eni_allocate_buffer ( eup, (u_long *)&size ) )
160             == (caddr_t)NULL ) {
161                 return ( ENOMEM );
162         }
163         evp->ev_rxpos = 0;
164
165         /*
166          * We only need to open incoming VCI's so outbound VCI's
167          * just get set to CVS_ACTIVE state.
168          */
169         if ( ( vcp->vc_type & VCC_IN ) == 0 ) {
170                 /*
171                  * Set the state and return - nothing else needs to be done.
172                  */
173                 evp->ev_state = CVS_ACTIVE;
174                 return ( 0 );
175         }
176
177         /*
178          * Set the VCI Table entry to start receiving
179          */
180         mode = ( evp->ev_connvc->cvc_attr.aal.type == ATM_AAL5
181                 ? VCI_MODE_AAL5 : VCI_MODE_AAL0 );
182         size >>= ENI_LOC_PREDIV;        /* Predivide by 256 WORDS */
183         for ( nsize = -1; size; nsize++ )
184                 size >>= 1;
185
186         vct->vci_control = mode << VCI_MODE_SHIFT |
187             PTI_MODE_TRASH << VCI_PTI_SHIFT |
188                 ( (u_int)(evp->ev_rxbuf) >> ENI_LOC_PREDIV ) << VCI_LOC_SHIFT |
189                 nsize << VCI_SIZE_SHIFT;
190         vct->vci_descr = 0;             /* Descr = Rdptr = 0 */
191         vct->vci_write = 0;             /* WritePtr = CellCount = 0 */
192
193         /*
194          * Indicate VC active
195          */
196         evp->ev_state = CVS_ACTIVE;
197
198         return ( err );
199 }
200
201 /*
202  * Close a VCC
203  *
204  * This function is called via the common driver code after receiving a
205  * stack *_TERM* command. The common code has already validated most of
206  * the request so we just need to check a few more ENI-specific details.
207  *
208  * Called at splimp.
209  *
210  * Arguments:
211  *      cup     pointer to device common unit
212  *      cvp     pointer to common VCC entry
213  *
214  * Returns:
215  *      0       close successful
216  *      err     close failed
217  *
218  */
219 int
220 eni_closevcc ( cup, cvp )
221         Cmn_unit        *cup;
222         Cmn_vcc         *cvp;
223 {
224         Eni_unit        *eup = (Eni_unit *)cup;
225         Eni_vcc         *evp = (Eni_vcc *)cvp;
226         struct vccb     *vcp = evp->ev_connvc->cvc_vcc;
227         int             err = 0;
228
229         VCI_Table       *vct;
230
231         /*
232          * Clear any references to this VCC in our transmit queue
233          */
234         /*
235          * We'll simply allow any existing TX requests to be
236          * sent as that's easier then pulling them out of
237          * everywhere. Besides, they should be ignored at the
238          * receiver whenever the other end shuts down.
239          */
240
241         /*
242          * Free the adapter receive buffer
243          */
244         (void) eni_free_buffer ( eup, (caddr_t)evp->ev_rxbuf );
245
246         /*
247          * If this is an outbound only VCI, then we can close
248          * immediately.
249          */
250         if ( ( vcp->vc_type & VCC_IN ) == 0 ) {
251                 /*
252                  * The state will be set to TERM when we return
253                  * to the *_TERM caller.
254                  */
255                 return ( 0 );
256         }
257
258         /*
259          * Find VCI entry in VCI Table
260          */
261         vct = &eup->eu_vcitbl[ vcp->vc_vci ];
262
263         /*
264          * Reset the VCI state
265          */
266         vct->vci_control = ( vct->vci_control & VCI_MODE_MASK )
267                 /* | VCI_MODE_TRASH */;
268         DELAY ( MIDWAY_DELAY );                 /* Give the adapter time to */
269                                         /* make the transition */
270
271         /*
272          * Reset everything
273          */
274         KM_ZERO ( vct, sizeof(VCI_Table) );
275
276         return ( err );
277 }
278