diff options
Diffstat (limited to 'sys/dev/hea/eni_vcm.c')
-rw-r--r-- | sys/dev/hea/eni_vcm.c | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/sys/dev/hea/eni_vcm.c b/sys/dev/hea/eni_vcm.c new file mode 100644 index 0000000..36c2a3d --- /dev/null +++ b/sys/dev/hea/eni_vcm.c @@ -0,0 +1,283 @@ +/* + * + * =================================== + * HARP | Host ATM Research Platform + * =================================== + * + * + * This Host ATM Research Platform ("HARP") file (the "Software") is + * made available by Network Computing Services, Inc. ("NetworkCS") + * "AS IS". NetworkCS does not provide maintenance, improvements or + * support of any kind. + * + * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED, + * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE + * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE. + * In no event shall NetworkCS be responsible for any damages, including + * but not limited to consequential damages, arising from or relating to + * any use of the Software or related support. + * + * Copyright 1994-1998 Network Computing Services, Inc. + * + * Copies of this Software may be made, however, the above copyright + * notice must be reproduced on all copies. + * + * @(#) $Id: eni_vcm.c,v 1.8 1998/06/29 23:03:18 mks Exp $ + * + */ + +/* + * Efficient ENI Adapter Support + * ----------------------------- + * + * Virtual Channel Managment + * + */ + + +#ifndef lint +static char *RCSid = "@(#) $Id: eni_vcm.c,v 1.8 1998/06/29 23:03:18 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <dev/hea/eni_stats.h> +#include <dev/hea/eni.h> +#include <dev/hea/eni_var.h> + + +/* + * VCC Stack Instantiation + * + * This function is called via the common driver code during a device VCC + * stack instantiation. The common code has already validated some of + * the request so we just need to check a few more ENI-specific details. + * + * Called at splnet. + * + * Arguments: + * cup pointer to device common unit + * cvp pointer to common VCC entry + * + * Returns: + * 0 instantiation successful + * err instantiation failed - reason indicated + * + */ +int +eni_instvcc(cup, cvp) + Cmn_unit *cup; + Cmn_vcc *cvp; +{ + Eni_unit *eup = (Eni_unit *)cup; + Eni_vcc *evp = (Eni_vcc *)cvp; + Atm_attributes *ap = &evp->ev_connvc->cvc_attr; + + /* + * Validate requested AAL + */ + switch (ap->aal.type) { + + case ATM_AAL0: + break; + + case ATM_AAL5: + if ((ap->aal.v.aal5.forward_max_SDU_size > ENI_IFF_MTU) || + (ap->aal.v.aal5.backward_max_SDU_size > ENI_IFF_MTU)) { + eup->eu_stats.eni_st_drv.drv_vc_maxpdu++; + return (EINVAL); + } + break; + + default: + return (EINVAL); + } + + return (0); +} + + +/* + * Open a VCC + * + * This function is called via the common driver code after receiving a + * stack *_INIT* command. The common code has already validated most of + * the request so we just need to check a few more ENI-specific details. + * + * Called at splimp. + * + * Arguments: + * cup pointer to device common unit + * cvp pointer to common VCC entry + * + * Returns: + * 0 open sucessful + * err open failed + * + */ +int +eni_openvcc ( cup, cvp ) + Cmn_unit *cup; + Cmn_vcc *cvp; +{ + Eni_unit *eup = (Eni_unit *)cup; + Eni_vcc *evp = (Eni_vcc *)cvp; + struct vccb *vcp = evp->ev_connvc->cvc_vcc; + int err = 0; + + VCI_Table *vct; + int size; + int mode; + int nsize; + + /* + * Validate the VPI and VCI values + */ + if ( (vcp->vc_vpi > eup->eu_pif.pif_maxvpi) || + (vcp->vc_vci > eup->eu_pif.pif_maxvci) ) { + eup->eu_stats.eni_st_drv.drv_vc_badrng++; + return ( EFAULT ); + } + + /* + * Check if this VCI is already active + */ + vct = &eup->eu_vcitbl[ vcp->vc_vci ]; + if ( vct->vci_control >> VCI_MODE_SHIFT != VCI_MODE_TRASH ) { + return ( EEXIST ); + } + + /* + * Allocate some permanent adapter memory for the reassembly + * buffer. Special case the signalling channel(s) buffer size. + * Otherwise, the buffer size will be based on whether this is + * a server or client card. + */ + if ( vcp->vc_vci == UNI_SIG_VCI ) /* HACK */ + size = RX_SIG_BSIZE; + else + size = (eup->eu_ramsize > MAX_CLIENT_RAM * ENI_BUF_PGSZ) ? + RX_SERVER_BSIZE * ENI_BUF_PGSZ : + RX_CLIENT_BSIZE * ENI_BUF_PGSZ; + + if ( ( evp->ev_rxbuf = eni_allocate_buffer ( eup, (u_long *)&size ) ) + == (caddr_t)NULL ) { + return ( ENOMEM ); + } + evp->ev_rxpos = 0; + + /* + * We only need to open incoming VCI's so outbound VCI's + * just get set to CVS_ACTIVE state. + */ + if ( ( vcp->vc_type & VCC_IN ) == 0 ) { + /* + * Set the state and return - nothing else needs to be done. + */ + evp->ev_state = CVS_ACTIVE; + return ( 0 ); + } + + /* + * Set the VCI Table entry to start receiving + */ + mode = ( evp->ev_connvc->cvc_attr.aal.type == ATM_AAL5 + ? VCI_MODE_AAL5 : VCI_MODE_AAL0 ); + size >>= ENI_LOC_PREDIV; /* Predivide by 256 WORDS */ + for ( nsize = -1; size; nsize++ ) + size >>= 1; + + vct->vci_control = mode << VCI_MODE_SHIFT | + PTI_MODE_TRASH << VCI_PTI_SHIFT | + ( (u_int)(evp->ev_rxbuf) >> ENI_LOC_PREDIV ) << VCI_LOC_SHIFT | + nsize << VCI_SIZE_SHIFT; + vct->vci_descr = 0; /* Descr = Rdptr = 0 */ + vct->vci_write = 0; /* WritePtr = CellCount = 0 */ + + /* + * Indicate VC active + */ + evp->ev_state = CVS_ACTIVE; + + return ( err ); +} + +/* + * Close a VCC + * + * This function is called via the common driver code after receiving a + * stack *_TERM* command. The common code has already validated most of + * the request so we just need to check a few more ENI-specific details. + * + * Called at splimp. + * + * Arguments: + * cup pointer to device common unit + * cvp pointer to common VCC entry + * + * Returns: + * 0 close sucessful + * err close failed + * + */ +int +eni_closevcc ( cup, cvp ) + Cmn_unit *cup; + Cmn_vcc *cvp; +{ + Eni_unit *eup = (Eni_unit *)cup; + Eni_vcc *evp = (Eni_vcc *)cvp; + struct vccb *vcp = evp->ev_connvc->cvc_vcc; + int err = 0; + + VCI_Table *vct; + + /* + * Clear any references to this VCC in our transmit queue + */ + /* + * We'll simply allow any existing TX requests to be + * sent as that's easier then pulling them out of + * everywhere. Besides, they should be ignored at the + * receiver whenever the other end shuts down. + */ + + /* + * Free the adapter receive buffer + */ + (void) eni_free_buffer ( eup, (caddr_t)evp->ev_rxbuf ); + + /* + * If this is an outbound only VCI, then we can close + * immediately. + */ + if ( ( vcp->vc_type & VCC_IN ) == 0 ) { + /* + * The state will be set to TERM when we return + * to the *_TERM caller. + */ + return ( 0 ); + } + + /* + * Find VCI entry in VCI Table + */ + vct = &eup->eu_vcitbl[ vcp->vc_vci ]; + + /* + * Reset the VCI state + */ + vct->vci_control = ( vct->vci_control & VCI_MODE_MASK ) + /* | VCI_MODE_TRASH */; + DELAY ( MIDWAY_DELAY ); /* Give the adapter time to */ + /* make the transition */ + + /* + * Reset everything + */ + KM_ZERO ( (caddr_t)vct, sizeof(VCI_Table) ); + + return ( err ); +} + |