h45067
s 00287/00000/00000
d D 3.1 84/11/13 16:30:46 dan 1 0
c date and time created 84/11/13 16:30:46 by dan
e
u
U
t
T
I 1
/*  vrdhandlr.c -- VIOS Read request handler
 *  copyright (c) American Information Systems Corporation
 *	Daniel Steinberg
 *	November, 1984
 *
 */

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


    PKT_STATE					/* throws: various errors */
vrd_handler (pkt)
    register PKT_PTR pkt;

/* vrd_handler (pkt) -- Process VIOS Read Requests
 *
 *	in:	pkt		I/O packet to process
 *	return:	(PKT_STATE)	next state of packet
 *	thrown:	V_ILL_FUNCTION	function not valid
 *		V_BAD_PARAMS	missing or zero length i/o buffer
 *				or non-null auxilliary buffer
 *		V_NO_DEVICE	no Primary Input device
 *
 *	Process Virtual I/O Read Requests in the following way:
 *		1) If the i/o function is not a simple READ_DATA,
 *			throw V_ILL_FUNCTION.
 *		2) If there is a non-null auxilliary buffer parameter, or if
 *		   there is a missing or zero length i/o buffer specification,
 *			throw V_BAD_PARAMS.
 *		3) If VIRTUAL OPERATING SYSTEM support, call buf_io_alloc()
 *		   (in hypersubs.c) to initiate buffered i/o, if possible.
 *		   If not possible, lock the input buffer.
 *		4) Duplicate the current packet, setting the child's target
 *		   device to the Primary Input unit, setting the parent
 *		   as the status return target, and incrementing State number
 *		   so that the child will restart at step (6).  Then requeue
 *		   the child packet.
 *		5) Set the current (parent) handler to vrdcomp_handler()
 *		   and return VIO_WAIT_STATE.
 *		   The child will then continue at step (6).  Upon the child's
 *		   completion, the parent will be reactivated to attempt error
 *		   recovery, input journaling, etc.
 *		6) The child processing restarts here.  Decrement the State
 *		   number and call the appropriate Class Handler.  If the
 *		   Class Handler finds that the primary input unit is another
 *		   Virtual Device, it will return VIO_RUN_STATE and the packet
 *		   will continue, with the new device set, at step (4).
 *		   Otherwise, the packet will be queued to the device handler.
 *
 *	The result of all of the above is to guarantee that, if there is
 *	buffered i/o or chained i/o (or both), all completion processing
 *	will be nested, to allow journaling and error recovery at each level.
 *	Also, if a request must be mapped from one device to another, the
 *	Class Handler will have a chance to remap the request for each device
 *	in a chained device list.
 *
 *	See also vrdcomp_handler() and rdbuf_handler() documentation below.
 */
{
    register IO_PACKET *pk;	/* dereferenced ptr */
    register PKT_PTR  npkt;	/* new i/o packet */
    register IO_PACKET *npk;
    register VDD_PTR dev;
    int err;

    pk = *pkt;		/* must renew after alloc() */

    switch (Stnum(pk))
	{
    case 0:
	if ( Fcode(pk) NE READ_DATA )
	    throw (V_ILL_FUNCTION);
	if ( (Auxparam(pk) NE NULL) OR (Ubufaddr(pk) EQ NULL) OR
		    (Ubufsize(pk) EQ 0) )
	    throw (V_BAD_PARAMS);

	/* chk_buffer() may throw V_BAD_BUFFER */
	if (NOT chk_buffer(pkt))	/* Check buffer address/size */
		throw(V_BAD_BUFFER);	/* buffer was read-only */

#ifdef V_OS /************ VIRTUAL OPERATING SYSTEM SUPPORT *************/
	/* determine if request should be buffered in local pool */
	if ( buf_io_alloc(pkt) )
	    {
	    Handler(pk = *pkt) = rdbuf_handler;	/* buffered i/o completion */
	    Stnum(pk) = 1;			/* reset state number */
	    return(VIO_WAIT_STATE);		/* let child complete */
	    }
					/* Unbuffered I/O */
	Stnum(pk = *pkt)++;		/* when read buffer is locked, */
	lock_buffer(pkt);		/* return to next state */

#endif /***************** VIRTUAL OPERATING SYSTEM SUPPORT *************/

#define VRD_ACTIVATE 1
#define VRD_CHILD 2

    case VRD_ACTIVATE:
	/* the current packet is either unbuffered i/o or a new pkt */

	npk = *(npkt = duppkt(pkt));	/* copy i/o packet */
	resetdev (npkt, VDevice(pk));	/* reset device */
	Parentstat(npk) = (int**) pkt;	/* copy status to parent */
	Stnum(npk) = VRD_CHILD;		/* continue child processing below */
	q_virtual(npkt);		/* queue the child packet */

	Stnum(pk) = 1;			/* input i/o is handled by child */
	Handler(pk) = vrdcomp_handler;	/* so wait for it */
	return(VIO_WAIT_STATE);

    case VRD_CHILD:
	/* if child is another Virtual Device,  reprocess above */

	Stnum(pk) = VRD_ACTIVATE;
	dev = VDevice(pk);
	return((*Classdispatcher(*dev))(VDREAD, pkt, dev));


#ifdef DEBUG4   /*************************************************************/
    default:
	error("vrd_handler: bad state in pkt @ %x", *pkt);
#endif /* DEBUG4 *************************************************************/

	} /*switch Stnum*/
}

    PKT_STATE
vrdcomp_handler (pkt)
    register PKT_PTR pkt;

/* vrdcomp_handler (pkt) -- Completion of VIOS Read requests
 *
 *	in:	pkt		I/O packet to process
 *	return:	(PKT_STATE)	next state of packet
 *	thrown:	(NONE)
 *
 *	Handle completion of Virtual Device Read Requests as follows:
 *		1) If a device hard error occurred and if the target virtual
 *		   device has an Error-input Unit assignment, duplicate
 *		   the packet, setting up the child to issue a virtual
 *		   device read to the Error-input device.  The parent
 *		   is set to wait for the child's status.  When the parent
 *		   is restarted, the error V_NO_DEVICE is converted into
 *		   V_HARD_ERROR so that a non-existent Error-input device
 *		   is not misconstrued.  Then processing continues at 3) below.
 *		2) If the device returned an End-Of-Transmission (V_EOT)
 *		   and the target virtual device is a Record-Sequential
 *		   device with an EOT-input Unit assignment, pop the
 *		   primary input until there is another one, or until
 *		   there are no more pushed devices.  Then, reissue the
 *		   current packet to the vrd_handler().
 *		3) Otherwise, if a non-zero length read did occur and there
 *		   is a Journal-input Unit assigned to the target virtual
 *		   device, duplicate this packet, setting up the child
 *		   to write the i/o buffer out to the Journal-Input device.
 *		   DONE_WAIT_STATE is returned to requeue the parent until
 *		   the journaling is complete.
 *		4) Otherwise, return DONE_STATE to complete the i/o processing.
 */
{
    register IO_PACKET *pk;	/* dereferenced ptr */
    register PKT_PTR  npkt;	/* new i/o packet */
    register IO_PACKET *npk;
    register VDD_PTR dev;
    VDD_PTR idev;

    dev = VDevice(pk = *pkt);

    switch (Stnum(pk))
	{
    case 1:
	switch (Statcode(pk))
	    {
	case V_HARD_ERROR:		/* add other cases, if necessary */
	    if ( (idev = Errorinput(*dev)) NE NULL )
		{
		npk = *(npkt = duppkt(pkt));	/* make a new packet */
		resetdev(npkt,idev);	/* convert to error recovery */
		Handler(npk) = vrd_handler;
		Stnum(npk) = VRD_ACTIVATE;	/* start where it counts */
		Parentstat(npk) = (int**) pkt;	/* status from child */
		q_virtual(npkt);	/* queue it to start soon */

		Stnum(*pkt) = 3;		/* land below when done */
		return(VIO_WAIT_STATE);
		} /*if--err_input device*/
	    break;

	case V_EOT:
	    if (Devclass(*dev) EQ REC_SEQ)
		{
		while (Recs_eot(*dev) NE NULL)
		    {
		    pop_unit(dev);	/* pop until primary assigned again */
		    if (Primaryinput(*dev) NE NULL)
			{
			Stnum(pk) = VRD_ACTIVATE;	/* re-issue this pkt */
			Handler(pk) = vrd_handler;
			return (VIO_RUN_STATE);
			}
		    } /*while*/
		} /*if--rec_seq*/

	    break;
	    } /*switch--statcode*/

	Stnum(pk)++;

    case 2:
	if ( (Statbcount(pk) NE 0) AND ((idev=Journalinput(*dev)) NE NULL) )
	    {
	    npk = *(npkt = duppkt(pkt));	/* duplicate for journaling */
	    pk = *pkt;			/* refresh this copy */
	    resetdev(npkt,idev);	/* set journal device */
	    Ubufsize(npk) = Statbcount(pk);	/* write as much as was read */
	    Function(npk) = FCODE(WRITE_FUNCTION, WRITE_DATA, 0);
	    Handler(npk) = vwrt_handler;
	    Stnum(npk) = 0;
	    q_virtual(npkt);		/* queue child and wait for it */
	    } /*if journal_output device*/

	return(DONE_STATE);	/* done, or wait for child to complete */

		/* DON'T FALL THRU TO STATE 3 */
    case 3:
	if (Statcode(pk) EQ V_NO_DEVICE)
	    Statcode(pk) = V_HARD_ERROR;	/* if errinput not assigned */
	Stnum(pk)--;				/* return to previous state */
	return(VIO_RUN_STATE);			/* check for journal dev */

#ifdef DEBUG4   /*************************************************************/
    default:
	error("vrdcomp_handler: bad state in pkt @ %x", pk);
#endif /* DEBUG4 *************************************************************/

	} /*switch--Stnum*/
}

#ifdef V_OS /************ VIRTUAL OPERATING SYSTEM SUPPORT *************/
    PKT_STATE
rdbuf_handler (pkt)
    PKT_PTR pkt;

/* rdbuf_handler (pkt) -- Complete buffered read requests
 *
 *	in:	pkt		I/O packet to process
 *	return:	(PKT_STATE)	next state of packet
 *	thrown:	(NONE)
 *
 *	Handle completion of Buffered Read Requests as follows:
 *		1) If the transfer byte count is non-zero,
 *		   call lock_buffer() (in hypersubs.c) to lock
 *		   the original i/o buffer in memory.  Once it
 *		   is locked, call copy_pool() (in hypersubs.c)
 *		   to copy the buffer from pool to the locked buffer.
 *		2) Return DONE_STATE to complete i/o processing.
 */
{
    register IO_PACKET *pk;

    pk = *pkt;
    switch (Stnum(pk))
	{
    case 1:
	if (Statbcount(pk) NE 0)	/* if there's something to copy */
	    {
	    lock_buffer(pkt);		/* resched when buf locked */
	    pk = *pkt;
	    copy_pool (Auxparam(pk), &Ubuffer(pk));	/* copy to OS */
	    unlock_buffer (pkt);
	    } /*if count#0*/
	return(DONE_STATE);

#ifdef DEBUG4   /*************************************************************/
    default:
	error("rdbuf_handler: bad state in pkt @ %x", *pkt);
#endif /* DEBUG4 *************************************************************/

	} /*switch Stnum*/
}
#endif /***************** VIRTUAL OPERATING SYSTEM SUPPORT *************/
E 1
