#pragma module pppd$asnfdt "X-4" /* ***************************************************************************** * * 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 FDT routines used by the Driver. They are: asn$read - FDT routine for read function asn$sense - FDT routine for sense function asn$set - FDT routine for set function asn$write - FDT routine for write function AUTHOR: Forrest A. Kenney 07-February-1996 REVISION HISTORY: X-4 BWK002 Barry W. Kierstein 17-DEC-1996 Replaced the standard Digital copyright with one compatible with the CMU copyright. X-3 BWK001 Barry W. Kierstein 24-JUL-1996 Corrected copyright notice. X-2 FAK001 Forrest A. Kenney 24-April-1996 Always return SS$_FDT_COMPL instead of status of last call. In the set code make sure we complete the I/O after we queue the AST. */ /* Define system data structure types and constants */ #include /* AST control block definitions */ #include /* Channel Control Block definitons */ #include /* Controller Request Block definitons */ #include /* Device data block definitions */ #include /* Driver Dispatch table definitions */ #include /* DEscriptor definitions */ #include /* Data structure type definitions */ #include /* Fork block definitions */ #include /* Interrupt Dispatch Block Definitions */ #include /* I/O function code and modifiers */ #include /* interger 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 /* 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" */ /* **++ ** asn$read - FDT routine for read function ** ** Functional description: ** ** This routine is called by the FDT dispatcher in the $QIO system service ** to process read functions. This FDT routine validates the request, ** allocates a buffered I/O packet and queues the IRP to this driver's ** start I/O routine. ** ** When the IRP is successfully queued to the driver's start I/O routine, ** IRP$L_SVAPTE points to the buffered I/O packet, IRP$L_BOFF is the number of ** bytes that have been charged against the process, and IRP$L_BCNT is the ** actual count of data bytes available for data in the buffered I/O packet. ** Note that the contents of the IRP$L_SVAPTE and IRP$L_BOFF cells must not be ** changed since I/O post processing will use these to deallocate the buffer ** packet and to credit the process. ** ** Since this is an upper-level FDT routine, this routine always returns ** the SS$_FDT_COMPL status. The $QIO status that is to be returned to the ** caller of the $QIO system service is returned indirectly by the FDT ** completion routine exe_std$qiodrvpkt via the FDT context structure. ** ** Calling convention: ** ** int asn$read (IRP *irp, PCB *pcb, ASNUCB *asnucb, CCB *ccb) ** ** Input parameters: ** ** IRP pointer to I/O request packet ** PCB pointer process control block ** ASNUCB pointer to unit control block ** CCB pointer to channel control block ** ** Output parameters: ** ** None ** ** Return value: ** ** SS$_FDT_COMPL ** ** Environment: ** ** Kernel mode, user process context, IPL 2. ** **-- */ int asn$read(IRP *irp, PCB *pcb, ASNUCB *asnucb, CCB *ccb) { char *data_ptr; char *user_buffer; int buffer_length; int32 return_length; int status; SYSBUF_HDR *system_buffer; user_buffer = (char *) irp->irp$l_qio_p1; buffer_length = irp->irp$l_qio_p2; if (((void *)asnucb->ASNLOG.ucb$l_tl_phyucb != (void *) 0) && (!asnucb->ucb$v_asn_delpend)) { if ((buffer_length > MINIMUM_MRU) && (buffer_length <= asnucb->ucb$l_asn_mru)) { status = exe_std$readchk(irp, pcb, (UCB *) asnucb, user_buffer, buffer_length); if (status & SS$_NORMAL) { buffer_length = buffer_length + sizeof(SYSBUF_HDR); status = exe_std$debit_bytcnt_alo(buffer_length, pcb, &return_length, (void **) &system_buffer); if (status & SS$_NORMAL) { irp->irp$l_svapte = (void *) system_buffer; irp->irp$l_boff = return_length; irp->irp$l_bcnt = irp->irp$l_qio_p2; data_ptr = (char *) system_buffer + sizeof(SYSBUF_HDR); system_buffer->pkt_datap = data_ptr; system_buffer->usr_bufp = user_buffer; system_buffer->pkt_size = return_length; status = call_qiodrvpkt(irp, (UCB *) asnucb); } else { status = call_abortio(irp, pcb, (UCB *) asnucb, status); } } else { status = call_abortio(irp, pcb, (UCB *) asnucb, status); } } else { status = call_abortio(irp, pcb, (UCB *) asnucb, SS$_IVBUFLEN); } } else { status = call_abortio(irp, pcb, (UCB *) asnucb, SS$_DEVINACT); } return SS$_FDT_COMPL; } /* **++ ** asn$sense - FDT routine for sense function ** ** Functional description: ** ** This routine is called by the FDT dispatcher in the $QIO system ** service to process sense mode and sense characteristics functions. The item ** list is checked for read access, and that the list is the correct length. ** If all is ok, the list is gone through one item at a time and the routine ** asn$do_sense_item is called. It an error occurs the walk is stopped and the ** error is returned. ** ** Since this is an upper-level FDT routine, this routine always returns ** the SS$_FDT_COMPL status. The $QIO status that is to be returned to the ** caller of the $QIO system service is returned indirectly by the FDT ** completion routines (e. g. EXE_STD$ABORTIO, EXE_STD$FINISHIO) viathe FDT ** context structure. ** ** Calling convention: ** ** int asn$sense (IRP *irp, PCB *pcb, ASNUCB *asnucb, CCB *ccb) ** ** Input parameters: ** ** IRP pointer to I/O request packet ** PCB pointer process control block ** ASNUCB pointer to unit control block ** CCB pointer to channel control block ** ** Output parameters: ** ** None ** ** Return value: ** ** SS$_FDT_COMPL ** ** Environment: ** ** Kernel mode, user process context, IPL 2. ** **-- */ int asn$sense(IRP *irp, PCB *pcb, ASNUCB *asnucb, CCB *ccb) { char *buffer; char *buffer_end; int acmode = 0; int buffer_len; int status; if (!asnucb->ucb$v_asn_delpend) { buffer = (char *) irp->irp$l_qio_p1; buffer_len = irp->irp$l_qio_p2; if ((buffer_len%sizeof(LSTITM)) == 0) { status = exe_std$prober((void *) buffer, buffer_len, acmode); if (status & SS$_NORMAL) { buffer_end = buffer + buffer_len; while ((buffer < buffer_end) && (status & SS$_NORMAL)) { status = asn$do_sense_item(asnucb, (LSTITM *) buffer, PROBE); if (status & SS$_NORMAL) { buffer += sizeof(LSTITM); } } if (buffer >= buffer_end) { status = call_finishio(irp, (UCB *) asnucb, buffer_len << 16 | status, 0); } else { status = call_abortio(irp, pcb, (UCB *) asnucb, status); } } else { status = call_abortio(irp, pcb, (UCB *) asnucb, status); } } else { status = call_abortio(irp, pcb, (UCB *) asnucb, SS$_BADPARAM); } } else { status = call_abortio(irp, pcb, (UCB *) asnucb, SS$_DEVINACT); } return SS$_FDT_COMPL; } /* **++ ** asn$set - FDT routine for set function ** ** Functional description: ** ** This routine is called by the FDT dispatcher in the $QIO system ** service to process set mode and set characteristics functions. The item ** list is checked for read access, and that the list is the correct length. ** If all is ok, the list is gone through one item at a time and the rotuine ** asn$do_set_item is called. If the hang-up AST is being enabled or disabled ** the item list validation steps are skipped. Instead the AST will be enabled ** or disabled by calling COM_STD$SETATTNAST. This FDT routine completes the ** I/O request without sending it to the driver start I/O routine. ** ** Since this is an upper-level FDT routine, this routine always returns ** the SS$_FDT_COMPL status. The $QIO status that is to be returned to the ** caller of the $QIO system service is returned indirectly by the FDT ** completion routines (e. g. exe_std$abortio, exe_std$finishio) via the FDT ** context structure. ** ** Calling convention: ** ** int asn$set (IRP *irp, PCB *pcb, ASNUCB *asnucb, CCB *ccb) ** ** Input parameters: ** ** IRP pointer to I/O request packet ** PCB pointer process control block ** ASNUCB pointer to unit control block ** CCB pointer to channel control block ** ** Output parameters: ** ** None ** ** Return value: ** ** SS$_FDT_COMPL ** ** Environment: ** ** Kernel mode, user process context, IPL 2. ** **-- */ int asn$set(IRP *irp, PCB *pcb, ASNUCB *asnucb, CCB *ccb) { char *buffer; char *buffer_end; int acmode = 0; int buffer_len; int status; LSTITM *item; if (!asnucb->ucb$v_asn_delpend) { if (irp->irp$l_func & IO$M_HANGUP) { status = com_std$setattnast(irp, pcb, (UCB *) asnucb, ccb, (ACB **) &asnucb->ASNLOG.ucb$l_tl_ctrly); status = call_finishio(irp, (UCB *) asnucb, status, 0); } else { buffer = (char *) irp->irp$l_qio_p1; buffer_len = irp->irp$l_qio_p2; if ((buffer_len%sizeof(LSTITM)) == 0) { status = exe_std$prober((void *) buffer, buffer_len, acmode); if (status & SS$_NORMAL) { buffer_end = buffer + buffer_len; while ((buffer < buffer_end) && (status & SS$_NORMAL)) { item = (LSTITM *) buffer; if (item->itm$w_type == ASN$_ACCM_XMIT) { status = exe_std$prober(item->itm$l_buffaddr, item->itm$w_length, acmode); } if (status & SS$_NORMAL) { status = asn$do_set_item(asnucb, (LSTITM *) buffer); if (status & SS$_NORMAL) { buffer += sizeof(LSTITM); } } } if (buffer >= buffer_end) { status = call_finishio(irp, (UCB *) asnucb, buffer_len << 16 | status, 0); } else { status = call_abortio(irp, pcb, (UCB *) asnucb, status); } } else { status = call_abortio(irp, pcb, (UCB *) asnucb, status); } } else { status = call_abortio(irp, pcb, (UCB *) asnucb, SS$_BADPARAM); } } } else { status = call_abortio(irp, pcb, (UCB *) asnucb, SS$_DEVINACT); } return SS$_FDT_COMPL; } /* **++ ** asn$write - FDT routine for write function ** ** Functional description: ** ** This routine is called by the FDT dispatcher in the $QIO system service ** to process write functions. This FDT routine validates the request, ** allocates a buffered I/O packet and copies the contents of the user buffer ** into the buffered I/O packet, and queues the IRP to this driver's alternate ** start I/O routine. ** ** When the IRP is successfully queued to the driver's start I/O routine, ** IRP$L_SVAPTE points to the buffered I/O packet, IRP$L_BOFF is the number ** of bytes that have been charged against the process, and IRP$L_BCNT is the ** actual count of data bytes in the buffered I/O packet that are to be sent ** to be sent . Note that the contents of the IRP$L_SVAPTE and IRP$L_BOFF ** cells must not be changed since I/O post processing will use these to ** deallocate the buffer packet and to credit the process. ** ** Since this is an upper-level FDT routine, this routine always returns ** the SS$_FDT_COMPL status. The $QIO status that is to be returned to the ** caller of the $QIO system service is returned indirectly by the FDT ** completion routines (e. g. exe_std$abortio, exe_std$altquepkt) via the ** FDT context structure. ** ** Calling convention: ** ** int asn$write (IRP *irp, PCB *pcb, ASNUCB *asnucb, CCB *ccb) ** ** Input parameters: ** ** IRP pointer to I/O request packet ** PCB pointer process control block ** ASNUCB pointer to unit control block ** CCB pointer to channel control block ** ** Output parameters: ** ** None ** ** Return value: ** ** SS$_FDT_COMPL ** ** Environment: ** ** Kernel mode, user process context, IPL 2. ** **-- */ int asn$write(IRP *irp, PCB *pcb, ASNUCB *asnucb, CCB *ccb) { char *data_ptr; char *user_buffer; int buffer_length; int32 return_length; int status; SYSBUF_HDR *system_buffer; if (((void *) asnucb->ASNLOG.ucb$l_tl_phyucb != (void *) 0) && (!asnucb->ucb$v_asn_delpend)) { user_buffer = (char *) irp->irp$l_qio_p1; buffer_length = irp->irp$l_qio_p2; if (((buffer_length + 4) >= MINIMUM_MTU ) && (buffer_length <= asnucb->ucb$l_asn_mtu)) { status = exe_std$writechk(irp, pcb, (UCB *) asnucb, user_buffer, buffer_length); if (status & SS$_NORMAL) { buffer_length = buffer_length + sizeof(SYSBUF_HDR); status = exe_std$debit_bytcnt_alo(buffer_length, pcb, &return_length, (void **) &system_buffer); if (status & SS$_NORMAL) { irp->irp$l_svapte = (void *) system_buffer; irp->irp$l_boff = return_length; irp->irp$l_bcnt = irp->irp$l_qio_p2; data_ptr = (char *) system_buffer + sizeof(SYSBUF_HDR); system_buffer->pkt_datap = data_ptr; system_buffer->usr_bufp = user_buffer; system_buffer->pkt_size = return_length; memcpy(data_ptr, user_buffer, irp->irp$l_qio_p2); exe_std$altquepkt(irp, (UCB *) asnucb); } else { status = call_abortio(irp, pcb, (UCB *) asnucb, status); } } else { status = call_abortio(irp, pcb, (UCB *) asnucb, status); } } else { status = call_abortio(irp, pcb, (UCB *) asnucb, SS$_IVBUFLEN); } } else { status = call_abortio(irp, pcb, (UCB *) asnucb, SS$_DEVINACT); } return SS$_FDT_COMPL; }