/* * * =================================== * 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: src/sys/dev/hfa/fore_vcm.c,v 1.4 1999/08/28 00:41:53 peter Exp $ * @(#) $DragonFly: src/sys/dev/atm/hfa/fore_vcm.c,v 1.3 2003/08/07 21:16:49 dillon Exp $ */ /* * FORE Systems 200-Series Adapter Support * --------------------------------------- * * Virtual Channel Management * */ #include "fore_include.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 Fore-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 fore_instvcc(cup, cvp) Cmn_unit *cup; Cmn_vcc *cvp; { Fore_vcc *fvp = (Fore_vcc *)cvp; Atm_attributes *ap = &fvp->fv_connvc->cvc_attr; /* * Validate requested AAL */ switch (ap->aal.type) { case ATM_AAL0: fvp->fv_aal = FORE_AAL_0; break; case ATM_AAL3_4: fvp->fv_aal = FORE_AAL_4; if ((ap->aal.v.aal4.forward_max_SDU_size > FORE_IFF_MTU) || (ap->aal.v.aal4.backward_max_SDU_size > FORE_IFF_MTU)) return (EINVAL); break; case ATM_AAL5: fvp->fv_aal = FORE_AAL_5; if ((ap->aal.v.aal5.forward_max_SDU_size > FORE_IFF_MTU) || (ap->aal.v.aal5.backward_max_SDU_size > FORE_IFF_MTU)) 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 Fore-specific details. * Then we just issue the command to the CP. Note that we can't wait around * for the CP to process the command, so we return success for now and abort * the connection if the command later fails. * * Called at splimp. * * Arguments: * cup pointer to device common unit * cvp pointer to common VCC entry * * Returns: * 0 open successful * else open failed * */ int fore_openvcc(cup, cvp) Cmn_unit *cup; Cmn_vcc *cvp; { Fore_unit *fup = (Fore_unit *)cup; Fore_vcc *fvp = (Fore_vcc *)cvp; H_cmd_queue *hcp; Cmd_queue *cqp; struct vccb *vcp; vcp = fvp->fv_connvc->cvc_vcc; ATM_DEBUG4("fore_openvcc: fup=%p, fvp=%p, vcc=(%d,%d)\n", fup, fvp, vcp->vc_vpi, vcp->vc_vci); /* * Validate the VPI and VCI values */ if ((vcp->vc_vpi > fup->fu_pif.pif_maxvpi) || (vcp->vc_vci > fup->fu_pif.pif_maxvci)) { return (1); } /* * Only need to tell the CP about incoming VCCs */ if ((vcp->vc_type & VCC_IN) == 0) { DEVICE_LOCK((Cmn_unit *)fup); fup->fu_open_vcc++; fvp->fv_state = CVS_ACTIVE; DEVICE_UNLOCK((Cmn_unit *)fup); return (0); } /* * Queue command at end of command queue */ hcp = fup->fu_cmd_tail; if ((*hcp->hcq_status) & QSTAT_FREE) { /* * Queue entry available, so set our view of things up */ hcp->hcq_code = CMD_ACT_VCCIN; hcp->hcq_arg = fvp; fup->fu_cmd_tail = hcp->hcq_next; fvp->fv_flags |= FVF_ACTCMD; /* * Now set the CP-resident queue entry - the CP will grab * the command when the op-code is set. */ cqp = hcp->hcq_cpelem; (*hcp->hcq_status) = QSTAT_PENDING; cqp->cmdq_act.act_vccid = CP_WRITE(vcp->vc_vci); if (fvp->fv_aal == FORE_AAL_0) cqp->cmdq_act.act_batch = CP_WRITE(1); cqp->cmdq_act.act_spec = CP_WRITE( ACT_SET_SPEC(BUF_STRAT_1, fvp->fv_aal, CMD_ACT_VCCIN | CMD_INTR_REQ)); } else { /* * Command queue full */ fup->fu_stats->st_drv.drv_cm_full++; return (1); } return (0); } /* * 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 Fore-specific details. * Then we just issue the command to the CP. Note that we can't wait around * for the CP to process the command, so we return success for now and whine * if the command later fails. * * Called at splimp. * * Arguments: * cup pointer to device common unit * cvp pointer to common VCC entry * * Returns: * 0 close successful * else close failed * */ int fore_closevcc(cup, cvp) Cmn_unit *cup; Cmn_vcc *cvp; { Fore_unit *fup = (Fore_unit *)cup; Fore_vcc *fvp = (Fore_vcc *)cvp; H_xmit_queue *hxp; H_cmd_queue *hcp; Cmd_queue *cqp; struct vccb *vcp; int i, err = 0; vcp = fvp->fv_connvc->cvc_vcc; ATM_DEBUG4("fore_closevcc: fup=%p, fvp=%p, vcc=(%d,%d)\n", fup, fvp, vcp->vc_vpi, vcp->vc_vci); DEVICE_LOCK((Cmn_unit *)fup); /* * Clear any references to this VCC in our transmit queue */ for (hxp = fup->fu_xmit_head, i = 0; (*hxp->hxq_status != QSTAT_FREE) && (i < XMIT_QUELEN); hxp = hxp->hxq_next, i++) { if (hxp->hxq_vcc == fvp) { hxp->hxq_vcc = NULL; } } /* * Clear any references to this VCC in our command queue */ for (hcp = fup->fu_cmd_head, i = 0; (*hcp->hcq_status != QSTAT_FREE) && (i < CMD_QUELEN); hcp = hcp->hcq_next, i++) { switch (hcp->hcq_code) { case CMD_ACT_VCCIN: case CMD_ACT_VCCOUT: if (hcp->hcq_arg == fvp) { hcp->hcq_arg = NULL; } break; } } /* * If this VCC has been previously activated, then we need to tell * the CP to deactivate it. */ if (fvp->fv_flags & FVF_ACTCMD) { /* * Queue command at end of command queue */ hcp = fup->fu_cmd_tail; if ((*hcp->hcq_status) & QSTAT_FREE) { /* * Queue entry available, so set our view of things up */ hcp->hcq_code = CMD_DACT_VCCIN; hcp->hcq_arg = fvp; fup->fu_cmd_tail = hcp->hcq_next; /* * Now set the CP-resident queue entry - the CP will * grab the command when the op-code is set. */ cqp = hcp->hcq_cpelem; (*hcp->hcq_status) = QSTAT_PENDING; cqp->cmdq_dact.dact_vccid = CP_WRITE(vcp->vc_vci); cqp->cmdq_dact.dact_cmd = CP_WRITE(CMD_DACT_VCCIN|CMD_INTR_REQ); } else { /* * Command queue full * * If we get here, we'll be getting out-of-sync with * the CP because we can't (for now at least) do * anything about close errors in the common code. * This won't be too bad, since we'll just toss any * PDUs received from the VCC and the sigmgr's will * always get open failures when trying to use this * (vpi,vci)...oh, well...always gotta have that one * last bug to fix! XXX */ fup->fu_stats->st_drv.drv_cm_full++; err = 1; } } /* * Finish up... */ if (fvp->fv_state == CVS_ACTIVE) fup->fu_open_vcc--; DEVICE_UNLOCK((Cmn_unit *)fup); return (err); }