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