freebsd-nq/sys/dev/hea/eni_vcm.c
2000-10-27 21:32:10 +00:00

293 lines
6.5 KiB
C

/*
*
* ===================================
* 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.
*
* @(#) $FreeBSD$
*
*/
/*
* Efficient ENI Adapter Support
* -----------------------------
*
* Virtual Channel Managment
*
*/
#include <sys/param.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netatm/port.h>
#include <netatm/queue.h>
#include <netatm/atm.h>
#include <netatm/atm_sys.h>
#include <netatm/atm_cm.h>
#include <netatm/atm_if.h>
#include <netatm/atm_vc.h>
#include <dev/hea/eni_stats.h>
#include <dev/hea/eni.h>
#include <dev/hea/eni_var.h>
#ifndef lint
__RCSID("@(#) $FreeBSD$");
#endif
/*
* 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 );
}