
/*
 * infhandlr.c: version 3.2 of 6/4/85
 *
 *  infhandlr.c -- VIOS Information request handler
 *  copyright (c) American Information Systems Corporation
 *	Daniel Steinberg  November, 1984
 */
#ifdef SCCS
static char *sccsid = "@(#)infhandlr.c	3.2";
#endif

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


    PKT_STATE			/* Throws: V_NO_DEVICE / V_ILL_FUNCTION */
vinfo_handler (pkt)
    register PKT_PTR pkt;

/* vinfo_handler (pkt) -- Do initial processing of VIOS Information Requests
 *
 *	in:	pkt		I/O Packet to process
 *	return:	(PKT_STATE)	next I/O packet state
 *	thrown:	V_NO_DEVICE	if device spec required, make sure it is legal
 *		V_ILL_FUNCTION	illegal information request
 *
 *	Dispatch i/o packet to appropriate VIOS Information handler.
 *	Make sure that there is (or isn't) a target device if required (or not).
 */
{
    register IO_PACKET *pk;	/* dereferenced ptr */
    register char **name;

    switch (Stnum(pk = *pkt))
	{
    case 0:
	switch (Fcode(pk))
	    {
	case DEV_INFO:
	    if (VDevice(pk) EQ NULL)		/* if no VDD/PDD */
		{
		/* Since there is no VDD or PDD, there might be a name */
		/* in the aux parameter (init_request() checked string) */
		/* Auxilliary param must be Virtual or Physical Device Name */

		if ( ((name = Auxparam(pk)) NE NULL) AND
			(**name NE '\0') AND
			    ( ( (catch() EQ 0) AND
				(VDevice(pk) = vdname_search(*name, Osid(pk)),
					uncatch(), TRUE) ) OR
			    ((PDevice(pk) = pname_search(*name)) NE NULL) ) )
		    {
		    /* Device name checked out and was placed in packet. */
		    /* Device i/o count will be decremented at completion. */

		    Outstanding_IO(*VDevice(pk))++;
		    } /*if-Auxparam is valid*/
		
		/* if still no device, dev_information() will catch it */

		} /*if-no VDD supplied*/

	    Handler(pk) = dev_information;	/* set handler routine addr */
	    return(VIO_RUN_STATE);		/* continue with new handler */

	default:
	    throw(V_ILL_FUNCTION);

	    } /* switch function-code */

	if (VDevice(pk) EQ NULL)  throw(V_NO_DEVICE);	/* must be a VDD */
	return(VIO_RUN_STATE);		/* continue with new handler */

    default:

#ifdef DEBUG3   /*************************************************************/
	error ("Bad stnum in pkt @%x (vctrl_handler)", *pkt);
#endif /* DEBUG3 *************************************************************/

	} /* switch Stnum */
}

    PKT_STATE					/* Throws: various errors */
dev_information (pkt)
    PKT_PTR pkt;

/* dev_information (pkt) -- Process Device Information Requests
 *
 *	in:	pkt		I/O Packet to process
 *	return:	(PKT_STATE)	next I/O packet state
 *	thrown:	V_BAD_PARAMS	Bad parameter in request
 *		V_NO_DEVICE	Device does not exist (if VDD unit)
 *		V_ILL_MODIFIER	VDD unit request for Physical Device
 *		V_SUCCESS	Packet successfully processed
 *
 *	Process VIOS requests to report on a Physical or Virtual Device.
 *	Process as follows:
 *		1) If there is a user buffer supplied, make sure it is
 *		   big enough to hold the status block, plus at least
 *		   one character of the device name.  If not,
 *			throw V_BAD_BUFFER.
 *		2) If no device descriptor or name was supplied,
 *		   allow the function only if NXT_VDEV or NXT_PDEV
 *		   modifier; in this case, set the first virtual or
 *		   physical device in the queue.
 *		   If the modifier is not one of the above two,
 *			throw V_NO_DEVICE.
 *		3) If the modifier is one of the Virtual Device units,
 *		   make sure that the device is a Virtual Device.
 *		   If the modifier is NXT_PDEV, device must be Physical.
 *		   Otherwise,
 *			throw V_BAD_PARAMS.
 *		4) If invalid function modifier,
 *			throw V_ILL_MODIFIER.
 *		5) If the modifier specifies a unit or next device and
 *		   there is none, set the second status return to NULL and
 *			throw V_SUCCESS.
 *		6) Set the device class in the auxilliary status word.
 *		   Set the device type (VDTYPE or PDTYPE) in the third
 *		   return parameter.
 *		7) If there is a user buffer specified, copy device information
 *		   to it, followed by as much of the device name as will fit.
 *		   Always terminate the returned device name with an asciz zero.
 *		8) Throw V_SUCCESS.
 */
{
    register IO_PACKET *pk;	/* dereferenced i/o pointer */
    register VDD *dv;		/* ptr to VDD */
    register VDD_PTR dev;	/* bufptr to VDD */
    register char *name;	/* bufptr to device name */
    unsigned mod;		/* request modifier */
    int pdevflg;		/* TRUE if FND_PDEV flag set */

#define MINDEVINFO (1 + (4 * sizeof(unsigned)))

    dev = VDevice(pk = *pkt);
    mod = Fmod(pk);
    pdevflg = mod & FND_PDEV;

    if (Ubufsize(pk) NE 0)
	{
	if (Ubufsize(pk) LT MINDEVINFO)
	    throw(V_BAD_BUFFER);	/* if buffer, must be long enough */

	/* 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 *************/
	lock_buffer(pkt);		/* make sure buffer is resident */
#endif /***************** VIRTUAL OPERATING SYSTEM SUPPORT *************/

	} /*if-buffer*/

    if (dev EQ NULL)		/* allow only NXT_PDEV & NXT_VDEV if no dev */
	{
	if (mod EQ NXT_VDEV)	/* find first Virtual Device */
	    {
	    dev = (VDD_PTR) Next(&Vdevices);	/* get first VDD in list */
	    }
	else
	    {
	    if (mod EQ NXT_PDEV)	/* find first Physical Device */
		{
		dev = (VDD_PTR) Next(&Pdevices);	/* get 1st PDD */
		}
	    else
		throw(V_NO_DEVICE);		/* no device supplied */
	    }
	
	if (dev EQ NULL)	/* if no devices in list */
	    goto nodevice;

	mod = 0;		/* already got the next device in the list */

	} /*if-Null VDD*/

    dv = *dev;		/* dereference the device ptr */

    if (mod NE 0)		/* if looking for a particular unit */
	{
	/* throw V_BAD_PARAMS if the device isn't Virtual, except on NXT_PDEV */
	if (mod EQ NXT_PDEV)
	    {
	    if (Devtype(dv) NE PDTYPE) 
		goto badparams;			/* Not physical: bad news */
	    }
	else
	    {
	    if (Devtype(dv) NE VDTYPE) 
badparams:
		throw(V_BAD_PARAMS);		/* bad request parameters */
	    }
	} /*if-mod*/
    
    switch (mod & ~(FND_PDEV))	/* now perform any indicated redirection */
	{
    case 0:
	break;			/* leave device alone */

    case NXT_PDEV:
	dev = (VDD_PTR) Next(dv);	/* get next device in list */
	break;

    case NXT_VDEV:
	while ((dev = (VDD_PTR) Next(dv)) NE NULL)	/* get next dev */
	    {
	    if ( (Osid(pk) EQ HYPER_ID) OR
		    (Ownerid(dv = *dev) EQ Osid(pk)) )	/* if owner match */
		break;					/* got the next dev */
	    } /*while*/
	break;

    case PRI_INP:
	dev = (VDD_PTR) Primaryinput(dv);	/* get target dev */
	goto traceinput;

    case PRI_OUT:
	dev = (VDD_PTR) Primaryoutput(dv);	/* get target dev */
	goto traceoutput;

    case JOU_INP:
	dev = (VDD_PTR) Journalinput(dv);	/* get target dev */
	goto traceoutput;

    case JOU_OUT:
	dev = (VDD_PTR) Journaloutput(dv);	/* get target dev */
traceoutput:
	if (pdevflg)		/* if FND_PDEV (find only last Primary Unit) */
	    dev = (VDD_PTR) fnd_out_pdd(dev);	/* trace to physical device */
	break;

    case ERR_INP:
	dev = (VDD_PTR) Errorinput(dv);		/* get target dev */
traceinput:
	if (pdevflg)		/* if FND_PDEV (find only last Primary Unit) */
	    dev = (VDD_PTR) fnd_inp_pdd(dev);	/* trace to physical device */
	break;

    default:
	throw(V_ILL_MODIFIER);
	} /*switch-mod*/

nodevice:
    if ( (Stataux2(pk) = (int) dev) EQ NULL )	/* if redirected device NULL */
	throw(V_SUCCESS);

    Statauxcode(pk) = Devclass(dv = *dev);	/* return device class */
    Stataux3(pk) = (UB32) Devtype(dv);		/* and VDTYPE/PDTYPE */

    if (Ubufsize(pk) NE 0)			/* if user buffer supplied */
	{
	/* Call class-dependent routine to fill in data */
	(*Classdispatcher(dv)) (VDINFO, pkt, dev);
	Statbcount(pk) = MINDEVINFO - 1;	/* make sure count is right */

	/* Copy as much of the device name as will fit */
	mod = Ubufsize(pk) - MINDEVINFO;	/* set max length */

	if (Devname(dv) NE NULL)
	    {
	    name = *Devname(dv);	/* get name string ptr */

	    /* While there is room left and name left */
	    while ( (mod-- NE 0) AND (*name NE '\0') )
		put_chr(*name++, pkt);	/* copy next character to buffer */

	    put_chr(0, pkt);		/* put out asciz terminator */
	    } /*if-Devname*/
	} /*if-Buffer*/

    throw(V_SUCCESS);
}
