freebsd-nq/sys/dev/hea/eni_vcm.c
Poul-Henning Kamp 1820df7a2d Add new files for HARP3
Host ATM Research Platform (HARP), Network Computing Services, Inc.
This software was developed with the support of the Defense Advanced
Research Projects Agency (DARPA).
1998-09-15 08:23:17 +00:00

284 lines
6.4 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.
*
* @(#) $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 );
}