#pragma module pppd$asnvci "X-6" /* ***************************************************************************** * * Copyright © 1996 Digital Equipment Corporation. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by Digital Equipment Corporation. The name of the * Corporation may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * ***************************************************************************** FACILITY: ASNDRIVER ABSTRACT: This module contains a the VCI rotuines. They are: VCI$ASN_Create_Port - Create port VCI$ASN_Delete_Port - Delete the port VCI$ASN_Transmit_Initiate - Set up and start a transmit VCI$ASN_PortMgmt_Synch - Perform set and sense functions AUTHOR: Forrest A. Kenney 23-February-1996 REVISION HISTORY: X-6 FAK004 Forrest A. Kenney 07-March-1997 Remove the acquisition of the device lock before seeing if we have an outstanding write. Just check the write state and if we have a write queued. If not then start the write if so queue the request. Also remove the check for state MULTI we can start a write as nothing will go out until we are clear of state multi. X-5 BWK001 Barry W. Kierstein 17-December-1996 Replaced the standard Digital copyright with one compatible with the CMU copyright. X-4 FAK003 Forrest A. Kenney 28-September-1996 In VCI$ASN_PortMgmt_Synch make sure we fill in the VCRP status on a get if it is success. X-3 FAK002 Forrest A. Kenney 27-June-1996 Clean up module headers. Beef up the logic in VCI$ASN_Delete_Port so that we know the device is truly idle before we diassociate ourselves from the upper VCM. X-2 FAK001 Forrest A. Kenney 20-June-1996 In VCI$ASN_PortMgmt_Synch set assume success when starting on first item in the item list. Also clean up some status tests. */ /* Define system data structure types and constants */ #include /* AST control block definitions */ #include /* Channel Control Block definitons */ #include /* Controller Request Block definitons */ #include /* VMS descriptor definitions */ #include /* Device data block definitions */ #include /* Driver Dispatch table definitions */ #include /* Data structure type definitions */ #include /* Fork block definitions */ #include /* I/O routines constants */ #include /* Interrupt Dispatch Block Definitions */ #include /* interger definitions */ #include /* I/O Request Packet definitions */ #include /* Object rights Block definitions */ #include /* Process Control Block definitions */ #include /* System data block definitions */ #include /* Spinlock definitions */ #include /* Status return valuse */ #include /* Terminal definitions TT$xxx */ #include /* TTY symbols private to class driver */ #include /* TTY UCB offsets */ #include /* UCB offsets */ #include /* VCRP defnitions */ #define VCIBDEF vcibdef /* This is needed to work around an incorrect definition for VCIB in LIB *. /* Define ASN specific data structures types and constants */ #include "asndef.h" /* ASN public definitions */ #include "asnmiscdef.h" /* ASN miscellanous items */ #include "asnvcibdef.h" /* ASN VCIB */ #include "pppd$asn_hide_ptrs.h" /* Hide long paths to items */ #include "pppd$asn_linkages.h" /* JSR register linkages */ #include "pppd$asn_prototypes.h" /* Prototypes for ASN routines */ /* Define function prototypes for system routines */ #include /* Prototypes for com$ and com_sdt$ routines */ #include /* Prototypes for exe$ and exe_std$ routines */ #include /* Prototypes for ioc$ and ioc_std$ routines */ #include /* Prototypes for sch$ and sch_std$ routines */ /* Define various device driver macros */ #include /* Device driver support macros, including */ /* table initialization macros and prototypes*/ /* Define the DEC C functions used by this driver */ #include /* OpenVMS AXP specific C builtin functions */ #include /* String routines provided by "kernel CRTL" */ /* **++ ** VCI$ASN_Create_Port - Create port ** ** Functional description: ** ** The upper VCM calls this routine to create a new port. The ** code performs the following steps: ** ** Fills in the routine addresses in the VCIB ** ** Calling convention: ** ** int VCI$ASN_Create_Port (ASNVCIB *asnvcib) ** ** Input parameters: ** ** VCIB pointer to the VCIB to be completed ** ** Output parameters: ** ** VCIB various fields filled in ** ** Return value: ** ** SS$_NORMAL Everything went just fine ** SS$_DEVINACT Device is scheduled for deletion or is not bound to a ** physical device ** ** Environment: ** ** Kernel mode IPL 8 with the fork lock held ** **-- */ int VCI$ASN_Create_Port(ASNVCIB *asnvcib) { int saved_fipl; int status = SS$_NORMAL; ASNUCB *asnucb; TTY_UCB *phyucb; asnucb = (ASNUCB *) asnvcib->vcib$ps_asn_ucb; if ((void *) asnucb != (void *) 0) { if ((!asnucb->ucb$v_asn_delpend) && ((void *)asnucb->ASNLOG.ucb$l_tl_phyucb != (void *) 0)) { asnvcib->vcib$r_vcibdef.vcib$a_portmgmt_synch = (int *) VCI$ASN_PortMgmt_Synch; asnvcib->vcib$r_vcibdef.vcib$a_transmit_initiate = (int *) VCI$ASN_Transmit_Initiate; asnvcib->vcib$r_vcibdef.vcib$a_portmgmt_initiate = 0; asnvcib->vcib$r_vcibdef.vcib$a_portmgmt_complete = 0; asnvcib->vcib$r_vcibdef.vcib$a_control_synch = 0; asnvcib->vcib$r_vcibdef.vcib$a_control_initiate = 0; asnvcib->vcib$r_vcibdef.vcib$a_control_complete = 0; asnucb->ucb$l_asn_vcib = (void *) asnvcib; } else { status = SS$_DEVINACT; } } else { status = SS$_DEVINACT; } return status; } /* **++ ** VCI$ASN_Delete_Port - Delete the port ** ** Functional description: ** ** The delete port routine is called by an upper VCM to delete a port. It ** does the following operations: ** ** 1) Makes sure delete port has not already been called if ** alread called return SS$_DEVINACT ** 2) Zeros the entry points to this driver ** 3) Zeros the UCB field and the name field ** 4) Calls the rotuine that gets the ASN UCB ready for deletion ** ** N.B. ** The assumtion here is that once this routine has been called that the ** UCB will never be used again. All that is waiting is to make sure the ** device is truly unused and then it will vanish. ** ** Calling convention: ** ** int VCI$ASN_Delete_Port (ASNVCIB *asnvcib) ** ** Input parameters: ** ** asnvcib Pointer to ASNVCIB ** ** Output parameters: ** ** None ** ** Return value: ** ** SS$_NORMAL Everything went just fine ** SS$_DEVINACT Already been here ** SS$_OPINCOIMPL Cannot set device up for deletion is I/O outstanding ** ** Environment: ** ** Kernel mode IPL 8 with the fork lock held ** **-- */ int VCI$ASN_Delete_Port(ASNVCIB *asnvcib) { int saved_fipl; int status = SS$_NORMAL; ASNUCB *asnucb; TTY_UCB *phyucb; asnucb = (ASNUCB *) asnvcib->vcib$ps_asn_ucb; if ((void *) asnucb != (void *) 0) { device_lock(asnucb->ASNBASE.ucb$l_dlck, RAISE_IPL, &saved_fipl); /* * We need to check the write flag under device IPL as it could * change while we are looking at it. We also need to make sure there * are no completion threads queued, or any I/O on the write queue. If * we return an SS$_OPINCOMPL the upper VCM should call us again later to * be deleted. * Note: That if it is safe after this test dropping the device * lock is OK. The fork lock is sufficient to prevent any new * activity from getting started. * */ phyucb = (TTY_UCB *) asnucb->ASNLOG.ucb$l_tl_phyucb; if ((void *) phyucb != (void *) 0) { if (phyucb->tty$v_st_write) { return SS$_OPINCOMPL; } } device_unlock(asnucb->ASNBASE.ucb$l_dlck, saved_fipl, SMP_RESTORE); if ((asnucb->ucb$l_asn_fork_cnt == 0) && (asnucb->ucb$l_asn_writeq_bl == &asnucb->ucb$l_asn_writeq_fl)) { asnucb->ucb$l_asn_vcib = 0; asnvcib->vcib$r_vcibdef.vcib$a_portmgmt_synch = 0; asnvcib->vcib$r_vcibdef.vcib$a_transmit_initiate = 0; asnvcib->vcib$ps_asn_ucb = 0; asn$prepare_for_delete(asnucb); } else { status = SS$_OPINCOMPL; } } else { status = SS$_DEVINACT; } return status; } /* **++ ** VCI$ASN_Transmit_Initiate - Set up and start a transmit ** ** Functional description: ** ** This routine is responsible for starting a packet transmission. It ** performs the following steps. ** ** 1) If needed computes a FCS and addes it to the end of the ** buffer ** 2) If the device is still bound to a port it checks to see if ** the packet can be sent now ** 3) If it cannot be sent now it queues the packet to the write ** queue ** ** Calling convention: ** ** int VCI$ASN_Transmit_Initiate (VCRP *vcrp, ASNVCIB *asnvcib) ** ** Input parameters: ** ** vcrp pointer to the VCRP ** vcib pointer to the VCIB ** ** Output parameters: ** ** None ** ** Return value: ** ** SS$_NORMAL Packet queued ** SS$_BADPARAM Buffer was to small or to large ** SS$_BUFFEROVF Buffer larger than transmit MTU ** SS$_DEVINACT Device is not bound to a terminal ** ** Environment: ** ** Kernel mode IPL 8 with the ASN devices fork lock held ** **-- */ int VCI$ASN_Transmit_Initiate(VCRP *vcrp, ASNVCIB *asnvcib) { char *buffer; unsigned int fcs; int saved_fipl; int status; ASNUCB *asnucb; TTY_UCB *phyucb; asnucb = (ASNUCB *) asnvcib->vcib$ps_asn_ucb; if ((void *) asnucb != (void *) 0) { phyucb = (TTY_UCB *) asnucb->ASNLOG.ucb$l_tl_phyucb; if ((!(asnucb->ucb$v_asn_delpend)) && ((void *) phyucb != (void *) 0)) { buffer = (char *) vcrp->vcrp$l_buffer_address; if ((vcrp->vcrp$l_bcnt <= asnucb->ucb$l_asn_mtu) && (vcrp->vcrp$l_bcnt + 4 >= MINIMUM_MTU)) { vcrp->vcrp$l_bcnt = asn$fcs_compute(asnucb, (unsigned char *) buffer, vcrp->vcrp$l_bcnt); vcrp->vcrp$l_total_pdu_size = vcrp->vcrp$l_bcnt; if ((!phyucb->tty$v_st_write) && ((void *) asnucb->ucb$l_asn_writeq_bl == (void *) asnucb->ucb$l_asn_writeq_fl)) { status = asn$write_start(asnucb, phyucb, (IRP *) vcrp); if (!(status & SS$_NORMAL)) { vcrp->vcrp$q_request_status = status; VCI$XXX_Transmit_Complete(vcrp, asnvcib); } } else { __PAL_INSQUEL((void *) asnucb->ucb$l_asn_writeq_bl, (void *) vcrp); } } else { status = SS$_BADPARAM; vcrp->vcrp$q_request_status = status; VCI$XXX_Transmit_Complete(vcrp, asnvcib); } } else { status = SS$_DEVINACT; vcrp->vcrp$q_request_status = status; VCI$XXX_Transmit_Complete(vcrp, asnvcib); } } else { status = SS$_DEVINACT; vcrp->vcrp$q_request_status = status; VCI$XXX_Transmit_Complete(vcrp, asnvcib); } return status; } /* **++ ** VCI$ASN_PortMgmt_Synch - Perform set and sense functions ** ** Functional description: ** ** This routine is called by the upper VCM to perform set and sense ** operations on the ASN device and it's associated physical terminal. The ** routine always completes syncronously is simply determines if the item list ** length is a multiple of 12. If the list length is incorrect it will return ** SS$_BADPARAM. The it will loop through the list one item at a time calling ** the correct routine. If any item fails the first longword of the status ** will be the failure reason, and the second longword of the status will have ** the failing item. Once any item fails processing will terminate. ** ** Calling convention: ** ** int VCI$ASN_PortMgmt_Synch (VCRP *vcrp, ASNVCIB *asnvcib) ** ** Input parameters: ** ** vcib pointer to the vcib ** vcrp pointer tot he vcrp ** ** Output parameters: ** ** On a sense the various items of data will be returned to the user. On ** set various fields in the UCB will be filled in. ** ** VCRP$Q_REQUEST_STATIS filled in with several possible completion ** status values. SS$_NORMAL, SS$_BADPARAM, ** SS$_DEVINACT. etc. ** ** Return value: ** ** SS$_NORMAL always ** ** Environment: ** ** Kernel mode IPL 8 with the ASN devices fork lock held ** **-- */ int VCI$ASN_PortMgmt_Synch(VCRP *vcrp, ASNVCIB *asnvcib) { char *buffer; char *buffer_end; int saved_fipl; int status= SS$_NORMAL; ASNRD *asnrd; ASNUCB *asnucb; TTY_UCB *phyucb; asnucb = (ASNUCB *) asnvcib->vcib$ps_asn_ucb; if ((void *) asnucb != (void *) 0) { phyucb = (TTY_UCB *) asnucb->ASNLOG.ucb$l_tl_phyucb; if ((!(asnucb->ucb$v_asn_delpend)) && ((void *) phyucb != (void *) 0)) { if (vcrp->vcrp$l_function == VCRP$K_FC_DISABLE_PORT) { device_lock(asnucb->ASNBASE.ucb$l_dlck, RAISE_IPL, &saved_fipl); asn$input_stop(asnucb); device_unlock(asnucb->ASNBASE.ucb$l_dlck, saved_fipl, SMP_RESTORE); vcrp->vcrp$q_request_status = SS$_NORMAL; } else if (vcrp->vcrp$l_function == VCRP$K_FC_ENABLE_PORT) { vcrp->vcrp$q_request_status = asn$enable_receive(asnucb, phyucb); } else if (vcrp->vcrp$l_function == VCRP$K_FC_GET) { buffer = (char *) vcrp->vcrp$a_input_list; buffer_end = (char *) vcrp->vcrp$a_input_list + vcrp->vcrp$t_mgmt_information[0]; if ((vcrp->vcrp$t_mgmt_information[0]%sizeof(LSTITM)) == 0) { while ((buffer < buffer_end) && (status & SS$_NORMAL)) { status = asn$do_sense_item(asnucb, (LSTITM *) buffer, NO_PROBE); if (status & SS$_NORMAL) { buffer += sizeof(LSTITM); vcrp->vcrp$q_request_status = status; } else { vcrp->vcrp$q_request_status = (((uint64)buffer << 32) | status); } } } else { vcrp->vcrp$q_request_status = SS$_BADPARAM; } } else if (vcrp->vcrp$l_function == VCRP$K_FC_SET) { buffer = (char *) vcrp->vcrp$a_input_list; buffer_end = (char *) vcrp->vcrp$a_input_list + vcrp->vcrp$t_mgmt_information[0]; if ((vcrp->vcrp$t_mgmt_information[0]%sizeof(LSTITM)) == 0) { while ((buffer < buffer_end) && (status & SS$_NORMAL)) { status = asn$do_set_item(asnucb, (LSTITM *) buffer); if (status & SS$_NORMAL) { buffer += sizeof(LSTITM); vcrp->vcrp$q_request_status = status; } else { vcrp->vcrp$q_request_status = (((uint64)buffer << 32) | status); } } } else { vcrp->vcrp$q_request_status = SS$_BADPARAM; } } else { vcrp->vcrp$q_request_status = SS$_BADPARAM; } } else { vcrp->vcrp$q_request_status = SS$_DEVINACT; } } else { vcrp->vcrp$q_request_status = SS$_DEVINACT; } return SS$_NORMAL; }