#pragma module pppd$asndriver "X-7" /* ***************************************************************************** * * 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 has the basic routines needed to define Asynch device. It contains the following routines: driver$inint_tables - Init DPT, DDT and FDT asn$struc_init - Init device data structures asn$struc_reinit - Re-Init device data structures asn$unit_init - Unit initialization routine asn$clone_ucb - Cloned UCB setup asn$cancel_io - Cancel I/O AUTHOR: Forrest A. Kenney 30-January-1996 REVISION HISTORY: X-7 BWK001 Barry W. Kierstein 17-December-1996 Replaced the standard Digital copyright with one compatible with the CMU copyright. X-6 FAK005 Forrest A. Kenney 04-November-1996 Do not allocate the write buffer in cloned_ucb code. We are now going to get a write buffer when we start a write and free it when a write is completed. This allows us to clear the write flag when we abort a write or when it is done. We loose a little performance in the worse case allocating and deallocating pool but we simplify the logic for writes. X-5 FAK004 Forrest A. Kenney 04-October-1996 Do not clear the writing state when aborting a write. It will cleared when the write completion fork actually runs. X-4 FAK003 Forrest A. Kenney 05-September-1996 In asn$clone_ucb routine fill in logical UCB address. X-3 FAK002 Forrest A. Kenney 06-June-1996 Fix incorrect code where it was supposed to and against SS$_NORMAL but it was coded as &SS$_NORMAL. X-2 FAK001 Forrest A. Kenney 19-April-1996 Add logic to the unit initialization routine to copy the terminal drivers DDT to a dummy DDT. Then modify the dummy DDT to have no cancel I/O routine or selective cancel I/O routine. This is done so that when we swtich the class driver to ASNDRIVER we can keep the terminal drivers cancel I/O routine from being called. */ /* Define system data structure types and constants */ #include /* AST control block definitions */ #include /* Cancel I/O defintions */ #include /* Channel Control Block definitons */ #include /* Controller Request Block definitons */ #include /* Device class defintions */ #include /* DEscriptor definitions */ #include /* Device characteristics definitions */ #include /* Device data block definitions */ #include /* Driver Dispatch table definitions */ #include /* Driver prologue table defintions */ #include /* Data structure type definitions */ #include /* Fork block definitions */ #include /* Function decision table definitions */ #include /* Interrupt Dispatch Block Definitions */ #include /* interger definitions */ #include /* I/O function code definitions */ #include /* IPL definitions */ #include /* I/O Request Packet definitions */ #include /* Object rights Block definitions */ #include /* Process Control 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 /* TTY vector layout */ #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_msgtbl.h" /* Abort packet message */ #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" */ /* Define global storage */ DDT asndummy_ddt; /* **++ ** driver$inint_tables - Init DPT, DDT and FDT ** ** Functional description: ** ** This routine completes the initialization of the DPT, DDT, and the FDT ** structures. This routine is called once by the $LOAD_DRIVER service ** immediately after the driver image is loaded or reloaded and before any ** validity checks are performed on the DPT, DDT, or FDT. A prototype version ** of these structures is built into the image at link time from the ** VMS$VOLATILE_PRIVATE_INTERFACES.OLB library. Note that the device related ** data structures (e.g. DDB, UCB, etc.) have not yet been created when this ** routine is called. The actions of this routine must be confined to the ** initialization of the DPT, DDT, and FDT structures which are contained in ** the driver image. ** ** Calling convention: ** ** int driver$init_tables (); ** ** Input parameters: ** ** None ** ** Output parameters: ** ** None ** ** Return value: ** ** status If the status is not successful, then the driver image will not ** be unloaded. Note that the ini_* macros used below will ** result in a return from this routine with an error status if ** an initialization error is detected. ** ** Environment: ** ** Called at IPL as high as 31 in kernel mode. ** **-- */ int driver$init_tables() { /* ** ** Prototype driver DPT, DDT, and FDT will be pulled in from the ** VMS$VOLATILE_PRIVATE_INTERFACES.OLB library at link time. ** */ extern DPT driver$dpt; extern DDT driver$ddt; extern FDT driver$fdt; extern TT_CLASS CLASS_VECTOR; /* Finish initialization of the Driver Prologue Table (DPT) */ ini_dpt_name (&driver$dpt, "ASNDRIVER"); ini_dpt_adapt (&driver$dpt, AT$_NULL); ini_dpt_defunits (&driver$dpt, 1); ini_dpt_ucbsize (&driver$dpt, sizeof(ASNUCB)); ini_dpt_struc_init (&driver$dpt, asn$struc_init); ini_dpt_struc_reinit(&driver$dpt, asn$struc_reinit); ini_dpt_end (&driver$dpt); /* Finish initialization of the Driver Dispatch Table (DDT) */ ini_ddt_unitinit (&driver$ddt, asn$unit_init); ini_ddt_cancel (&driver$ddt, asn$cancelio); ini_ddt_cloneducb (&driver$ddt, asn$clone_ucb); ini_ddt_end (&driver$ddt); /* Finish initialization of the Function Decision Table (FDT) */ ini_fdt_act (&driver$fdt, IO$_READLBLK, asn$read, BUFFERED); ini_fdt_act (&driver$fdt, IO$_READPBLK, asn$read, BUFFERED); ini_fdt_act (&driver$fdt, IO$_READVBLK, asn$read, BUFFERED); ini_fdt_act (&driver$fdt, IO$_WRITELBLK, asn$write, BUFFERED); ini_fdt_act (&driver$fdt, IO$_WRITEPBLK, asn$write, BUFFERED); ini_fdt_act (&driver$fdt, IO$_WRITEVBLK, asn$write, BUFFERED); ini_fdt_act (&driver$fdt, IO$_SETMODE, asn$set, BUFFERED); ini_fdt_act (&driver$fdt, IO$_SETCHAR, asn$set, BUFFERED); ini_fdt_act (&driver$fdt, IO$_SENSEMODE, asn$sense, BUFFERED); ini_fdt_act (&driver$fdt, IO$_SENSECHAR, asn$sense, BUFFERED); ini_fdt_end (&driver$fdt); /* If we got this far then everything worked, so return success. */ return SS$_NORMAL; } /* **++ ** asn$struc_init - Init device data structures ** ** Functional description: ** ** This routine is called once for each unit by the $LOAD_DRIVER ** service after the UCB is created. At this point the UCB has not yet been ** fully linked into the I/O database. This routine is responsible for ** filling in driver specific fields in the I/O database structures that are ** passed as parameters as parameters to this routine. ** ** Only those fields that are not affected by a driver reload are filled ** in. In contrast, the structure reinitialization routine is responsible for ** filling in the fields that need to be corrected when (and if) this driver ** image is reloaded. ** ** After this routine is called for a new unit, then the reinitilization ** is called as well. Then the $LOAD_DRIVER service completes the integration ** of these device specific structures into the I/O database. ** ** ** Calling convention: ** ** void asn$struc_init (CRB *crb, DDB *ddb, IDB *idb, ORB *orb, ** ASNUCB *asnucb); ** ** Input parameters: ** ** CRB pointer to the controller request block ** DDB pointer to device data block ** IDB pointer to the interrupt dispatch block ** ORB pointer to the object rights block ** UCB pointer to the unit control block ** ** Output parameters: ** ** None ** ** Return value: ** ** None ** ** Environment: ** ** Kernel mode, IPL may be as high as 31 ** **-- */ void asn$struc_init(CRB *crb, DDB *ddb, IDB *idb, ORB *orb, ASNUCB *asnucb) { extern short int TTY$GW_DEFBUF; extern TTY$GL_DEFCHAR; extern TTY$GL_DEFCHAR2; /* Initiliaze fields in the base UCB */ asnucb->ASNBASE.ucb$b_flck = SPL$C_IOLOCK8; asnucb->ASNBASE.ucb$b_dipl = IPL$_IOLOCK8; asnucb->ASNBASE.ucb$l_devchar = DEV$M_AVL | DEV$M_ODV | DEV$M_IDV | DEV$M_TRM | DEV$M_REC | DEV$M_CCL; asnucb->ASNBASE.ucb$l_devchar2 = DEV$M_NNM | DEV$M_NOCLU; asnucb->ASNBASE.ucb$b_devclass = DC$_TERM; asnucb->ASNBASE.ucb$b_devtype = TT$_UNKNOWN; asnucb->ASNBASE.ucb$w_devbufsiz = TTY$GW_DEFBUF; asnucb->ASNBASE.ucb$l_devdepend = TTY$GL_DEFCHAR; asnucb->ASNBASE.ucb$l_devdepnd2 = TTY$GL_DEFCHAR2; asnucb->ASNBASE.ucb$l_devdepnd3 = 0; asnucb->ASNBASE.ucb$l_devdepnd4 = 0; asnucb->ASNBASE.ucb$l_sts = UCB$M_TEMPLATE; /* Initiliaze fields in the logical UCB */ asnucb->ucb$l_tt_logucb = 0; /* Initialize fields in the ASN extension region */ asnucb->ucb$l_asn_rcv_accm = 0xffffffff; asnucb->ucb$l_asn_xmit_accm[0] = 0xffffffff; asnucb->ucb$l_asn_xmit_accm[1] = 0; asnucb->ucb$l_asn_xmit_accm[2] = 0; asnucb->ucb$l_asn_xmit_accm[3] = 0x60000000; asnucb->ucb$l_asn_xmit_accm[4] = 0; asnucb->ucb$l_asn_xmit_accm[5] = 0; asnucb->ucb$l_asn_xmit_accm[6] = 0; asnucb->ucb$l_asn_xmit_accm[7] = 0; asnucb->ucb$l_asn_fcs_rcv = 16; asnucb->ucb$l_asn_fcs_xmit = 16; asnucb->ucb$l_asn_flow = ASN$M_XON_XOFF; asnucb->ucb$l_asn_mru = MAXIMUM_MRU; asnucb->ucb$l_asn_mtu = MAXIMUM_MTU; asnucb->ucb$l_asn_readq_fl = &asnucb->ucb$l_asn_readq_fl; asnucb->ucb$l_asn_readq_bl = &asnucb->ucb$l_asn_readq_fl; asnucb->ucb$l_asn_packetq_fl = &asnucb->ucb$l_asn_packetq_fl; asnucb->ucb$l_asn_packetq_bl = &asnucb->ucb$l_asn_packetq_fl; asnucb->ucb$l_asn_writeq_fl = &asnucb->ucb$l_asn_writeq_fl; asnucb->ucb$l_asn_writeq_bl = &asnucb->ucb$l_asn_writeq_fl; asnucb->ucb$l_asn_write_buffer = 0; asnucb->ucb$q_asn_data_lost = 0; asnucb->ucb$q_asn_dropped_chars = 0; asnucb->ucb$q_asn_fe = 0; asnucb->ucb$q_asn_long_pkts = 0; asnucb->ucb$q_asn_pkts_rcv = 0; asnucb->ucb$q_asn_pkts_sent = 0; asnucb->ucb$q_asn_runt_pkts = 0; asnucb->ucb$q_asn_total_chars = 0; return; } /* **++ ** asn$struc_reinit - Re-Init device data structures ** ** Functional description: ** ** This routine is called once for each unit by the $LOAD_DRIVER service ** immediately after the structure initialization routine is called. ** ** Additionally, this routine is called once for each unit by the ** $LOAD_DRIVER service when a driver is reloaded. Thus, this routine is ** responsible for filling in the fields in the I/O database structures that ** point into this driver image. ** ** Calling convention: ** ** void asn$struc_reinit (CRB *crb, DDB *ddb, IDB *idb, ORB *orb, ** ASNUCB *asnucb) ** ** Input parameters: ** ** CRB pointer to the controller request block ** DDB pointer to device data block ** IDB pointer to the interrupt dispatch block ** ORB pointer to the object rights block ** UCB pointer to the unit control block ** ** Output parameters: ** ** None ** ** Return value: ** ** None ** ** Environment: ** ** Kernel mode, system context, IPL may be as high as 31 and may not be ** altered. ** **-- */ void asn$struc_reinit (CRB *crb, DDB *ddb, IDB *idb, ORB *orb, ASNUCB *asnucb) { extern DDT driver$ddt; ddb->ddb$ps_ddt = &driver$ddt; return; } /* **++ ** asn$unit_init - Unit initialization routine ** ** Functional description: ** ** This routine is called once for each unit by the $LOAD_DRIVER service ** after a new unit control block has been created, initialized, and fully ** integrated into the I/O database. This routine is also called for each ** unit during power fail recovery. ** ** Calling convention: ** ** int asn$unit_init (IDB *idb, ASNUCB *asnucb) ** ** Input parameters: ** ** IDB pointer to the interrupt dispatch block ** UCB pointer to the unit control block ** ** Output parameters: ** ** None ** ** Return value: ** ** SS$_NORMAL ** ** Environment: ** ** Called in kernel mode at IPL 31 ** **-- */ int asn$unit_init(IDB *idb, ASNUCB *asnucb) { extern DPT *TTY$GL_DPT; if (!asnucb->ASNBASE.ucb$v_power) { asnucb->ucb$l_asn_createport = VCI$ASN_Create_Port; asnucb->ucb$l_asn_deleteport = VCI$ASN_Delete_Port; /* ** ** Now copy the terminal driver DDT to our dummy DDT and remap the ** cancel I/O and selective cancel rotuines to ioc$return_success. ** */ memcpy((void *) &asndummy_ddt, (void *) TTY$GL_DPT->dpt$ps_ddt, sizeof(DDT)); asndummy_ddt.ddt$ps_cancel_2 = ioc$return; asndummy_ddt.ddt$ps_cancel_selective_2 = ioc$return_success; } asnucb->ASNBASE.ucb$v_online = 1; return SS$_NORMAL; } /* **++ ** asn$clone_ucb - Cloned UCB setup ** ** Functional description: ** ** This routine is called after the template UCB has been cloned by ** assigning channel to the template device. It is responsible for allocating ** and setting up the read buffers and the write buffer. If any errors occur ** at this point the buffers will be deleted and an appropriate error will ** be reported. The assign code will delete template device and report this ** error back to the caller. ** ** Note: ** The buffer will be sized to the maximum allowable value and will only ** be deleted when the device is going away. This simplifies the design at ** the expense of wasting some extra pool. If operational experience shows ** this to be a problem we can reopen this decision. ** ** Calling convention: ** ** int asn$clone_ucb (ASNUCB *asnucb, DDT *ddt, PCB *pcb, ** ASNUCB *parent_ucb); ** ** Input parameters: ** ** ASNUCB pointer to new UCB ** DDT pointer to driver dispatch table ** PCB pointer to Process Control Block of cloning process ** PARENT_UCB pointer to the template UCB ** ** Output parameters: ** ** UCB$L_ASN_READQ_FL pointer to first element in the read buffer queue ** UCB$L_ASN_READQ_BL pointer to last element in the read bufferqueue ** UCB$L_ASN_PACKETQ_FL pointer to first element in the read packet queue ** UCB$L_ASN_PACKETKQ_BL pointer to last element in the read packet queue ** UCB$L_ASN_WRITEQ_FL pointer to first element in the write queue ** UCB$L_ASN_WRITEQ_BL pointer to last elenet in the write queue ** UCB$L_ASN_WRITE_BUFF address of write buffer ** Others ** ** Return value: ** ** SS$_NORMAL ** SS$_INSFMEM ** ** Environment: ** ** Kernel mode IPL 2 with the I/O database mutex held for write. ** **-- */ int asn$clone_ucb(ASNUCB *asnucb, DDT *ddt, PCB *pcb, ASNUCB *parent_ucb) { int count = 0; int request_size; int32 return_size; int status; ASNRD *asnrd; ASNWRT *asnwrt; /* Initiliaze fields in the logical UCB */ asnucb->ucb$l_tt_logucb = (UCB *) asnucb; /* Initialize fields in the ASN extension region */ asnucb->ucb$l_asn_flags = 0; asnucb->ucb$l_asn_rcv_accm = 0xffffffff; asnucb->ucb$l_asn_xmit_accm[0] = 0xffffffff; asnucb->ucb$l_asn_xmit_accm[1] = 0; asnucb->ucb$l_asn_xmit_accm[2] = 0; asnucb->ucb$l_asn_xmit_accm[3] = 0x60000000; asnucb->ucb$l_asn_xmit_accm[4] = 0; asnucb->ucb$l_asn_xmit_accm[5] = 0; asnucb->ucb$l_asn_xmit_accm[6] = 0; asnucb->ucb$l_asn_xmit_accm[7] = 0; asnucb->ucb$l_asn_fcs_rcv = 16; asnucb->ucb$l_asn_fcs_xmit = 16; asnucb->ucb$l_asn_flow = ASN$M_XON_XOFF; asnucb->ucb$l_asn_mru = MAXIMUM_MRU; asnucb->ucb$l_asn_mtu = MAXIMUM_MTU; asnucb->ucb$l_asn_readq_fl = &asnucb->ucb$l_asn_readq_fl; asnucb->ucb$l_asn_readq_bl = &asnucb->ucb$l_asn_readq_fl; asnucb->ucb$l_asn_packetq_fl = &asnucb->ucb$l_asn_packetq_fl; asnucb->ucb$l_asn_packetq_bl = &asnucb->ucb$l_asn_packetq_fl; asnucb->ucb$l_asn_writeq_fl = &asnucb->ucb$l_asn_writeq_fl; asnucb->ucb$l_asn_writeq_bl = &asnucb->ucb$l_asn_writeq_fl; asnucb->ucb$l_asn_write_buffer = 0; asnucb->ucb$q_asn_fr3 = 0; asnucb->ucb$q_asn_fr4 = 0; asnucb->ucb$q_asn_data_lost = 0; asnucb->ucb$q_asn_dropped_chars = 0; asnucb->ucb$q_asn_fe = 0; asnucb->ucb$q_asn_long_pkts = 0; asnucb->ucb$q_asn_pkts_rcv = 0; asnucb->ucb$q_asn_pkts_sent = 0; asnucb->ucb$q_asn_runt_pkts = 0; asnucb->ucb$q_asn_total_chars = 0; /* ** ** Allocate read packets and place them on the read queue ** ** Request size = 2 * mru + (16 bytes for address, control, and protocol ** fields) + SIZE of read packet header ** ** */ request_size = 2 * asnucb->ucb$l_asn_mru + PACKET_OVERHEAD + sizeof(ASNRD); do { status = exe_std$allocbuf(request_size, &return_size, (void **) &asnrd); if (status & SS$_NORMAL) { asnrd->asnrd$w_size = return_size; asnrd->asnrd$b_type = DYN$C_FRK; asnrd->asnrd$b_flck = SPL$C_IOLOCK8; asnrd->asnrd$l_putptr = (void *) &asnrd->asnrd$t_frame; asnrd->asnrd$l_end_frame = (void *) ((char *) asnrd + request_size); asnrd->asnrd$a_ucb = (void *) asnucb; __PAL_INSQUEL((void *) asnucb->ucb$l_asn_readq_bl, (void *) asnrd); } } while ((++count < READ_BUFFERS) && (status & SS$_NORMAL)); if (status & SS$_NORMAL) { asnucb->ASNBASE.ucb$v_deleteucb = 0; asnucb->ASNBASE.ucb$v_online = 1; } return status; } /* **++ ** asn$cancel_io - Cancel I/O ** ** Functional description: ** ** When an application issues a cancel I/O operation the paths ** actions taken are different for read and write request. The following ** will occur: ** ** 1. The queue of current outstanding I/O requests will be cleaned all ** and all queued requests will be completed with a reason of ** SS$_CANCEL. ** 2. The current read the request will be terminated with a reason ** of SS$_ABORT. Note that no data will be returned. ** 3. The queue of pending writes will be cleaned all queued write will ** be completed with a reason of SS$_CANCEL. ** 4. The write that is in progress will be terminated with a rewason of ** SS$_ABORT. The system write buffer will be made available for ** the next write. ** 5. The port driver will be called and told about the transmit. This ** will typically result in us sending a malformed frame. Send a flag ** sequence 0x7e after the port driver does the abort. My reading of ** the specification leads me to believe that this is optional but ** doing it should not hurt. ** ** If the reason is CAN$C_DASSGN, the reference count is zero, and there ** is no VCIB the following additional steps will be performed. ** ** 1. Write buffer will be deleted ** 2. The read queue will be emptied and the buffers deleted ** 3. If the device is still linked dyn$revert will be called to break the link ** 4. A deletion fork will be started to delete the UCB if one is not already started ** ** Calling convention: ** ** void asn$cancelio (int chan, IRP *irp, PCB *pcb, ASNUCB *asnnucb, ** int reason) ** ** Input parameters: ** ** Reason reason for cancel CAN$C_CANCEL or CAN$C_DASSGN ** ASNUCB pointer to the ASN UCB ** PCB pointer to the PCB for process requesting the cancel ** IRP IRP in the UCB$L_IRP field ** Channel channel number the cancel is for ** ** Output parameters: ** ** Numerous fields in the terminal UCB will be modified ** ** Return value: ** ** None ** ** Environment: ** ** This routine is called with the fork lock held. It will acquire the ** device lock as well. ** **-- */ void asn$cancelio(int chan, IRP *irp, PCB *pcb, ASNUCB *asnucb, int reason) { unsigned char out_char; int saved_dipl; int status; ASNWRT *asnwrt; IRP *next_irp; IRP *read_irp; IRP *write_irp; TTY_UCB *phyucb; extern EXE$GL_ABSTIM; phyucb = (TTY_UCB *) asnucb->ASNLOG.ucb$l_tl_phyucb; com_std$flushattns(pcb, (UCB *) asnucb, chan, (ACB **) &asnucb->ASNLOG.ucb$l_tl_ctrly); /* ** ** Cancel current read IRP if it matches the PID and channel. The current ** frame is left alone ** */ read_irp = asnucb->ASNBASE.ucb$l_irp; if (asnucb->ASNBASE.ucb$v_bsy) { if ((read_irp->irp$l_pid == pcb->pcb$l_pid) && (read_irp->irp$l_chan == chan)) { asnucb->ASNBASE.ucb$l_irp = 0; read_irp->irp$l_bcnt = 0; read_irp->irp$l_iost1 = SS$_ABORT; com_std$post_nocnt(read_irp); } } /* ** ** Cancel any writes that match the PID and channel. ** */ if ( (void *) &asnucb->ucb$l_asn_writeq_fl != (void *) asnucb->ucb$l_asn_writeq_bl) { next_irp = (IRP *) asnucb->ucb$l_asn_writeq_fl; do { if ((next_irp->irp$l_pid == pcb->pcb$l_pid) && (next_irp->irp$l_chan == chan)) { next_irp = next_irp->irp$l_ioqfl; __PAL_REMQUEL((void *)next_irp->irp$l_ioqbl, (void *) &write_irp); write_irp->irp$l_svapte = (void *) 0; write_irp->irp$l_bcnt = 0; write_irp->irp$l_iost1 = SS$_CANCEL; com_std$post_nocnt(write_irp); } else { next_irp = next_irp->irp$l_ioqfl; } } while ((void *) &asnucb->ucb$l_asn_writeq_fl != (void *) next_irp); } /* ** ** Now kill current write if it matches the PID and channel ** */ if ((void *) phyucb != (void *) 0) { device_lock(asnucb->ASNBASE.ucb$l_dlck, RAISE_IPL, &saved_dipl); asnwrt = 0; if (phyucb->tty$v_st_write) { asnwrt = (ASNWRT *) asnucb->ucb$l_asn_write_buffer; write_irp = (IRP *) asnwrt->asnwrt$a_vcrp; if (write_irp->irp$b_type == DYN$C_IRP) { if ((write_irp->irp$l_pid == pcb->pcb$l_pid) && (write_irp->irp$l_chan == chan)) { asnwrt->asnwrt$l_status = SS$_ABORT; phyucb->tty$v_st_write = 0; __ADD_ATOMIC_LONG(&asnucb->ucb$l_asn_fork_cnt, 1); exe_std$queue_fork((FKB *) asnwrt); port$abort(phyucb); port$resume(phyucb); phyucb->ucb$w_tt_multilen = strlen(asn$abort_string); phyucb->ucb$l_tt_multi = asn$abort_string; phyucb->tty$v_st_multi = 1; out_char = class$getnext(phyucb); if (phyucb->ucb$b_tt_outype != 0) { port$startio(out_char, phyucb); } } } } device_unlock(asnucb->ASNBASE.ucb$l_dlck, saved_dipl, SMP_RESTORE); } /* ** ** If this is the last reference to the device, and there is no VCIB ** associated and the cancel reason is CAN$C_DASSGN then prepare to make it go ** away. The prepare for delete routine will flush all pending I/O so no need ** to do it here. ** */ if ((asnucb->ASNBASE.ucb$l_refc == 0) && (asnucb->ucb$l_asn_vcib == (void *) 0) && (reason == CAN$C_DASSGN)) { asn$prepare_for_delete(asnucb); } return; }