/*  vioinit.c -- VIOS initialization
 *  copyright (c) American Information Systems Corporation
 *	Daniel Steinberg
 *	November, 1984
 *
 */

/* Enable global symbol definitions */

#define	DEFINITIONS
#include "viosconf.h"

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


    						/* Throw: V_ALL_FAILURE */
vios_data_init ()

/* vios_data_init () -- Initialize VIOS data structures for cold/warm start
 *
 *	return:	(NONE)
 *	thrown:	V_ALL_FAILURE	not enough pool for initialization
 *
 *	Allocate and initialize VIOS system pool, then
 *	initialize the rest of the VIOS internal structures:
 *		1) Initialize device lists and queues.
 *		2) Initialize global flags.
 *		3) Create the fixed device class descriptors.
 *		4) Create the fixed device implementation module descriptors.
 *
 *	Enter this routine with interrupts disabled.
 *
 *	*** This routine assumes that sizeof(char) == 1 ***
 *	*** [Thia assumption is enforced in ctrlsubs.c] ***
 */
{
    register VDD_PTR console;
    register PDD_PTR ttya;
    register PKT_PTR mpkt;
    register PKT_PTR spkt;
    register PKT_PTR tpkt;

#define ISIZE (sizeof(int))

    /* In the beginning, there was the great, vast pool... */
    vios_pool_end =
	(vios_pool_start = gettopmem(TRUE, poolsize = POOLSIZE)) + POOLSIZE;
    
    if (vios_pool_start EQ -1)
	error("Not enough valid memory for VIOS pool", NULL);

#ifdef DEBUG_MAP /************************************************************/
    poolsize = (poolsize * ISIZE)/(ISIZE + 1);	/* and then along came bitmap */
    poolmap = (char*) (vios_pool_end = vios_pool_start + poolsize);
    mapsize = (poolsize) / sizeof(int);	/* set addr & length */
#endif /* DEBUG_MAP **********************************************************/

    Intdepth = 1;		/* Interrupts are already disabled */

    _i_pool (vios_pool_start, vios_pool_end);	/* ...and it was good */

    /* And on the second day, queues were formed where once there were none */
    Imp_modules.next = NULL;
    Imp_modules.last = NULL;

    Class_modules.next = NULL;
    Class_modules.last = NULL;

    Operating_systems.next = NULL;
    Operating_systems.last = NULL;

    Vqueue.next = NULL;
    Vqueue.last = NULL;
    Pqueue.next = NULL;
    Pqueue.last = NULL;
    Wqueue.next = NULL;
    Wqueue.last = NULL;

    Vdevices.next = NULL;
    Vdevices.last = NULL;
    Pdevices.next = NULL;
    Pdevices.last = NULL;

    /* and the flags, also */
    All_failed = FALSE;
    OS_Completion = FALSE;
    Intstate = FALSE;
    Vioexecuting = TRUE;
    Vioscheduled = FALSE;

    ticks = 0;		/* no clock interrupts yet */

    /* Initialize pool data structures */

#ifdef DEBUG3   /*************************************************************/
    if (catch() NE 0)  error ("VIOS initialize failure", NULL);
#endif /* DEBUG3 *************************************************************/

    q_item ( i_cm (REC_SEQ, recs_dispatcher), &Class_modules);
    q_item ( i_cm (BLK_ADDR, blka_dispatcher), &Class_modules);
    q_item ( i_cm (BUF_ADDR, bufa_dispatcher), &Class_modules);

    q_item ( i_imp(AISSTR, ais_dispatcher), &Imp_modules);
    q_item ( i_imp(HOSTSTR, host_dispatcher), &Imp_modules);

    q_item ( (Current_os = i_os()), &Operating_systems);

    /* Allocate and initialize the timeout handling i/o requests */
    mpkt = allpkt();	/* Allocate the minute timeout request */
    Compos(*mpkt) = (OS_IDENT) VIOS_ID;
    Osid(*mpkt) = (OS_IDENT) VIOS_ID;	/* set owner OS */
    Ftype(*mpkt) = INTERNAL_FUNCTION;		/* set request function type */
    Priority(*mpkt) = (PKT_PRIORITY) -10;	/* set high priority */

    tpkt = duppkt(spkt = duppkt(mpkt));		/* allocate sec & tick packets */
    Handler(*mpkt) = min_handler;		/* set minute timeout handler */
    Handler(*spkt) = sec_handler;		/* set second timeout handler */
    Handler(*tpkt) = tick_handler;		/* set tick timeout handler */

    State(*mpkt) = TMO_WAIT_STATE;		/* wait for timeout */
    State(*spkt) = TMO_WAIT_STATE;		/* wait for timeout */
    State(*tpkt) = TICK_WAIT_STATE;		/* wait for next clock tick */

    Timescale(*mpkt) = SEC_TIMEOUT;		/* wait 60 seconds */
    Timecount(*mpkt) = 60;
    Timescale(*spkt) = MSEC_TIMEOUT;		/* wait 1000 milliseconds */
    Timecount(*spkt) = 1000;

    q_wait(mpkt);		/* stick 'em all on the wait queue */
    q_wait(spkt);
    q_wait(tpkt);

#ifdef DEBUG3   /*************************************************************/
    uncatch();
#endif /* DEBUG3 *************************************************************/

    host_init();		/* clear host connection */
    _i_interrupts();		/* initialize interrupt handling */

    Vioexecuting = FALSE;
    Intdepth = 0;
}

    CLASS_MODULE **				/* Throw: V_ALL_FAILURE */
i_cm (class, disp)
    UB8 class;
    PKT_STATE (*disp)();

/* i_cm (class, disp) -- Initialize a class handling module descriptor
 *
 *	in:	class		Device class of module
 *	in:	disp		Dispatch routine address
 *	return:	(CLASS_MODULE **)	Bufptr to allocated module
 *	thrown:	V_ALL_FAILURE	can't allocate class handling module descriptor
 *
 *	Allocate a Class Handling Module Descriptor.  This structure is
 *	used to locate the class dispatcher that is called to perform any
 *	class-dependent operations on an active i/o packet.
 */
{
    register CLASS_MODULE **cm;
    register char *t;
    register int i;

    cm = (CLASS_MODULE**) valloc(sizeof(CLASS_MODULE));	/* allocate module */
    t = (char*) *cm;
    for (i=0; i<sizeof(CLASS_MODULE); i++)
	*t++ = '\0';			/* init data space */
    C_dispatcher(*cm) = disp;		/* set dispatch routine address */
    C_class(*cm) = class;		/* set class number */
    return(cm);
}

    IMP_MODULE **				/* Throw: V_ALL_FAILURE */
i_imp (name, disp)
    char *name;
    PKT_STATE (*disp)();

/* i_imp (name, disp) -- Initialize an implementation module descriptor
 *
 *	in:	name		Implementation module name
 *	in:	disp		Dispatch routine address
 *	return:	(IMP_MODULE **)	Bufptr to allocated module
 *	thrown:	V_ALL_FAILURE	can't allocate implementation module descriptor
 *
 *	Allocate an Implementation Module Descriptor.  This structure is
 *	used to locate the device dispatcher when creating a new physical
 *	device on the fly.
 */
{
    register IMP_MODULE **imp;
    register char *t;
    register int i;
    char **im;

    imp = (IMP_MODULE**) valloc(sizeof(IMP_MODULE));	/* allocate module */
    t = (char*) *imp;
    for (i=0; i<sizeof(IMP_MODULE); i++)
	*t++ = '\0';			/* init data space */
    Imp_dispatcher(*imp) = disp;	/* set dispatch routine address */
    im = Imp_name(*imp) = valloc(1 + strlen(name));
    strcpy (*im, name);			/* copy name string */
    return(imp);
}

    OSD_PTR				/* Throw: V_ALL_FAILURE */
i_os ()

/* i_os () -- Initialize an operating system descriptor
 *
 *	return:	(OSD_PTR)	Bufptr to allocated Operating System Descriptor
 *	thrown:	V_ALL_FAILURE	can't allocate os descriptor
 *
 *	Allocate an Operating System Descriptor.  This structure is
 *	used to schedule a Target Operating System for execution.
 */
{
    register OSD_PTR osd;
    register char *t;
    register int i;

    osd = (OSD_PTR) valloc(sizeof(OSD));	/* allocate module */
    t = (char*) *osd;
    for (i=0; i<sizeof(OSD); i++)
	*t++ = '\0';			/* init data space */

    return(osd);
}
