h30244
s 00191/00000/00000
d D 3.1 84/11/13 16:26:50 dan 1 0
c date and time created 84/11/13 16:26:50 by dan
e
u
U
t
T
I 1
/*  auxhandlr.c -- VIOS Auxilliary Function request handler
 *  copyright (c) American Information Systems Corporation
 *	Daniel Steinberg
 *	November, 1984
 *
 */

#include "viosconf.h"
#include "iopacket.h"
#include "pktfuncs.h"
#include "poolfuncs.h"
#include "handlers.h"
#include "viocmds.h"
#include "viostatus.h"


    PKT_STATE			/* Throws: V_ILL_FUNCTION */
aux_handler (pkt)
    PKT_PTR pkt;

/* aux_handler (pkt) -- Dispatcher for VIOS Auxilliary Function requests
 *
 *	in:	pkt		I/O Packet to process
 *	return:	(PKT_STATE)	next I/O packet state
 *	thrown:	V_ILL_FUNCTION	illegal auxilliary function
 *
 *	Dispatch i/o packet to appropriate Auxilliary Function handler.
 */
{
    register IO_PACKET *pk;	/* dereferenced ptr */
    register PDD_PTR dev;

    switch (Stnum(pk = *pkt))
	{
    case 0:
	switch (Fcode(pk))
	    {
	case SET_TIMER:
	    Handler(pk) = timer_handler;	/* set a timer */
	    break;

	default:
	    throw(V_ILL_FUNCTION);

	    } /* switch function-code */

	return(VIO_RUN_STATE);		/* continue with new handler */

#ifdef DEBUG4   /*************************************************************/
    default:
	error ("Bad stnum in pkt @%x (aux_handler)", *pkt);
#endif /* DEBUG4 *************************************************************/

	} /* switch Stnum */
}

    PKT_STATE			/* Throws: V_ILL_MODIFIER / V_BAD_PARAMS */
timer_handler (pkt)
    PKT_PTR pkt;

/* timer_handler (pkt) -- Set periodic and one-shot timers
 *
 *	in:	pkt		I/O packet to process
 *	return:	(PKT_STATE)	next I/O packet state
 *	thrown:	V_ILL_MODIFIER	illegal function modifier
 *		V_BAD_PARAMS	no completion routine for PERIODIC timer
 *
 *	Handles SET_TIMER requests for both ONE_SHOT and PERIODIC timers.
 *	ONE_SHOT timers are handled as follows:
 *		1) Set the packet status to V_SUCCESS, Stataux1 to 1,
 *			and the handler to done_handler().
 *		2) Return TMO_WAIT_STATE so that the VIO request completes
 *			normally when the request timeout is satisfied.
 *			Status and completion will be returned as for
 *			any other VIOS request.
 *
 *	PERIODIC timers are handled as follows:
 *		1) Save the timeout in Param1 and the completion routine
 *			in Param2 (possibly specifiable in the future).
 *		2) Return TMO_WAIT_STATE...processing continues after
 *			the timeout interval has passed.
 *		3) Reset the timeout (from Param1).
 *		4) If there is a queued, but uncompleted, O.S. completion
 *			packet for this request increment the argument field
 *			so that it will count an extra interval when the
 *			operating system can dequeue it.  Then loop thru
 *			Step 2.
 *		5) Increment Stataux1, saving the unresolved timeout count
 *			in case there is an allocation failure for the
 *			O.S. Completion packet.
 *		6) Attempt to allocate an O.S. Completion packet.  If this
 *			fails, simply loop thru Step 2.  This means that
 *			allocation failures will cause the Operating System
 *			to wait for the next timeout before the completion
 *			packet allocation is retried.
 *		7) If the completion packet was allocated, set this packet
 *			address in it for Step 4 to find, set the completion
 *			routine address, and copy the Stataux1 value into
 *			the argument field.  Then zero Stataux1 field to
 *			accumulate timeout counts for the next allocation
 *			failure and loop thru Step 2.
 *
 *	PERIODIC timers loop forever until they are cancelled, at which point
 *	they return status thru the standard i/o completion mechanisms.
 *
 *	*** NOTE THAT THE PERIODIC TIMER WAKEUP CURRENTLY USES THE SAME
 *		COMPLETION ROUTINE AS THE REQUEST COMPLETION **
 */
{
    register IO_PACKET *pk;
    register OS_COMP **c;

    switch (Stnum(pk = *pkt))		/* dereference packet ptr */
	{
    case 0:
	if (Fmod(pk) & ~(ONE_SHOT | PERIODIC))	/* if other modifiers */
	    throw (V_ILL_MODIFIER);
	
	if (Fmod(pk) EQ ONE_SHOT)	/* timeout once and that's it */
	    {
	    Handler(pk) = done_handler;	/* done after timeout */
	    Statcode(pk) = V_SUCCESS;	/* and it worked, too */
	    Stataux1(pk) = 1;		/* say it timed out once, just for fun */
	    goto tmoreturn;		/* merge below */
	    } /*if-ONE_SHOT*/
	
	/* PERIODIC timers must come from an OS with a completion routine */

	if ( ((Param2(pk) = (unsigned) Comproutine(pk)) EQ NULL) OR
					((int)Compos(pk) LE 0) )
	    throw(V_BAD_PARAMS);

	Param1(pk) = Timeout(pk);	/* copy for future refresh */
	Stnum(pk)++;			/* come back at next case statement */
	goto tmoreturn;			/* go timeout for now */

    case 1:
	Timeout(pk) = Param1(pk);	/* reset the timeout count */

	/* If Stataux1 is clear, there may already be a queued completion */
	/* If not, the last we checked, there wasn't...so don't check again */

	if (Stataux1(pk) EQ 0)
	    {
	    /* get ptr to first queued completion packet, if any */
	    c = (OS_COMP**) Next(&(O_cqueue(*((OSD_PTR) Compos(pk)))));

	    while (c NE NULL)
		{
		if (O_cpkt(*c) EQ (int**)pkt)	/* is this for current pkt? */
		    {
		    O_carg(*c)++;	/* yes...just increment the ctr */
		    goto tmoreturn;	/* and wait for next timeout */
		    } /*if*/
		
		c = Next(*c);		/* try next queued completion */
		} /*while*/
	    } /*if-Stataux1*/
	
	/* There was not a completion already queued, so try to allocate one */

	Stataux1(pk)++;		/* count this timeout, in case of all failure */

	if ((c = (OS_COMP**) alloc(sizeof(OS_COMP))) NE NULL)
	    {
	    O_crout(*c) = (int(*)()) Param2(pk);	/* set routine to call */
	    O_cpkt(*c) = (int**)pkt;	/* save this packet address */
	    O_carg(*c) = Stataux1(pk);	/* set count of timeouts gone by */
	    Stataux1(pk) = 0;		/* reset count of timeouts gone by */


	    /* queue this completion packet onto the O.S.'s queue */
	    q_item(c, &O_cqueue(*((OSD_PTR) Compos(pk))));
	    OSscheduled = TRUE;		/* reschedule OS (for now) */
	    } /*if-alloc*/
	else
	    {
	    } /*if-alloc failure*/

	goto tmoreturn;		/* wait for next timeout */
	
#ifdef DEBUG4   /*************************************************************/
    default:
	error("Bad stnum in pkt @%x (timer_handler)", pk);
#endif /* DEBUG4 *************************************************************/

	} /*switch-Stnum*/
    
tmoreturn:
    return(TMO_WAIT_STATE);	/* wait til the swallows return from Cappucino */
}
E 1
