
/*
 * blkaddr.c: version 3.3 of 6/4/85
 *
 *  blkaddr.c -- Class-dependent routines for Block-Addressible Devices
 *  copyright (c) American Information Systems Corporation
 *	Daniel Steinberg	November, 1984
 */
#ifdef SCCS
static char *sccsid = "@(#)blkaddr.c	3.3";
#endif

#include "vinc/viosconf.h"
#include "vinc/iopacket.h"
#include "vinc/viocmds.h"
#include "vinc/viostatus.h"
#include "vinc/handlers.h"
#include "vinc/pktfuncs.h"
#include "vinc/poolfuncs.h"

    PKT_STATE					/* throws: various errors */
blka_dispatcher (cmd, pkt, dev)
    int cmd;
    PKT_PTR pkt;
    VDD_PTR dev;

/* blka_dispatcher (cmd, pkt, dev) -- Class-dependent i/o mapping dispatcher
 *
 *	in:	cmd		Type of VIOS request to handle
 *	in:	pkt		Current i/o packet ptr, if any
 *	in:	dev		Current device, if VDCREATE or VDREMOVE
 *	return:	(PKT_STATE)	Current state of i/o packet
 *	thrown:	V_ILL_MODIFIER	bad i/o request modifier
 *
 *	Perform i/o request handling for Block-Addressible Devices.
 *
 *	This routine is called during the processing of an i/o packet to perform
 *	any class-dependent operations or mapping of requests.  It must either
 *	verify that the request is valid for the given device class and initiate
 *	any class-dependent actions, or dispatch to a routine that will do so.
 *	(See DOCS/classdispatcher for more info on calling conditions.)
 *
 *	The processing is as follows:
 *		cmd == VDCREATE
 *		cmd == VDREMOVE
 *		cmd == PDCREATE	Copy bytes-per-block / size, in blocks
 *				from status of physical i/o to PDD.
 *		cmd == PDREMOVE
 *		cmd == VDREAD	If there is no primary input unit,
 *					throw V_NO_DEVICE.
 *				Re-map the block numbers from the current device
 *				to the primary input unit.  If the block number
 *				is out of range,
 *					throw V_BAD_PARAMS.
 *				Reset the packet to point to the primary input
 *				unit.  If the new unit is a Virtual Device,
 *					return VIO_RUN_STATE.
 *				If the new unit is a Physical Device, call
 *				q2device() (rdwrtsubs.c) and return its value.
 *		cmd == VDWRITE	If there is no primary output unit,
 *					throw V_NO_DEVICE.
 *				Re-map the block numbers from the current device
 *				to the primary output unit.  If the block number
 *				is out of range,
 *					throw V_BAD_PARAMS.
 *				Reset the packet to point to the primary output
 *				unit.  If the new unit is a Virtual Device,
 *					return VIO_RUN_STATE.
 *				If the new unit is a Physical Device, call
 *				q2device() (rdwrtsubs.c) and return its value.
 *		cmd == VDIOCTRL
 *		cmd == PDIOCTRL
 *
 *		cmd == VDINFO	Copy four parameters into user buffer of 'pkt':
 *					1) Blka_size
 *					2) Blka_max
 *					3) 0
 *					4) 0
 *
 *	Throws V_ILL_MODIFIER if the i/o request modifier is not valid for this
 *	class of devices.
 */
{
    register VDD *dv;
    register IO_PACKET *pk;
    register PDD_PTR pdev;
    register unsigned bsz;
    unsigned long tmp;		/* Make double precision float!!! */

    pk = *pkt;			/* dereference everything */
    dv = *dev;

    switch (cmd)
	{
    case VDCREATE:
	if ((Blka_size(dv) = Param2(pk)) EQ 0)
		throw(V_BAD_PARAMS);	/* set number of bytes per block */
	break;

    case VDREMOVE:
	break;

    case PDCREATE:
	Blka_size(dv) = Stataux2(pk);	/* set bytes/block from host */
	Blka_max(dv) = Stataux3(pk);	/* set max #blocks from host */
	break;

    case PDREMOVE:
	break;

    case VDREAD:
	pdev = (PDD_PTR) Primaryinput(dv);
	goto Chkblk;

    case VDWRITE:
	pdev = (PDD_PTR) Primaryoutput(dv);
Chkblk:
    
	if (pdev EQ NULL) throw(V_NO_DEVICE);	/* must r/w a device */
	tmp = Param1(pk) * Blka_size(dv);	/* ** Small numbers! ** */

				    /* bsz = block size of new device */
	Param2(pk) = tmp % (bsz = Blka_size(*pdev));

#ifdef DEBUG3   /*************************************************************/
	if ( (Param2(pk) NE 0) OR (tmp/Blka_size(dv) NE Param1(pk)) )
	    error("Unimplemented virtual/physical block mapping!!", NULL);
#endif /* DEBUG3 *************************************************************/

	if ( ( (Param1(pk) = tmp / bsz) +
	    ((Ubufsize(pk) + bsz - 1) / bsz))
		    GT Blka_max(*pdev) )
			    throw(V_BAD_PARAMS);	/* block # too large */

	if (Fmod(pk) NE 0)  throw(V_ILL_MODIFIER);

	resetdev(pkt,pdev);	/* point this packet to new unit */
	if (Devtype(*pdev) EQ VDTYPE)
	    break;		/* requeue packet if still Virtual device */

	return(q2device(pkt));	/* if Physical device, queue the packet to it */

    case VDIOCTRL:
    case PDIOCTRL:
	throw(V_ILL_FUNCTION);

#ifdef DEBUG_MAP   /***********************************************************/
    case VDMAPPOOL:
#endif /* DEBUG_MAP ***********************************************************/

	break;

    case VDINFO:			/* copy device info to user buffer */
	put_val(Blka_size(dv), pkt);	/* 1st word to copy */
	put_val(Blka_max(dv), pkt);	/* 2nd word to copy */
	put_val(0, pkt);		/* 3rd word to copy */
	put_val(0, pkt);		/* 4th word to copy */
	break;


#ifdef DEBUG3   /*************************************************************/
    default:
	error ("Bad command to blka_dispatcher: %d", cmd);
#endif /* DEBUG3 *************************************************************/

	} /*switch-cmd*/

    return(VIO_RUN_STATE);		/* continue processing */
}
