/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1987,1988
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */
/* $Header:wconfig.c 12.0$ */
/* $ACIS:wconfig.c 12.0$ */
/* $Source: /ibm/acis/usr/sys/pc_code/RCS/wconfig.c,v $ */

#ifndef lint
static char    *rcsid = "$Header:wconfig.c 12.0$";
#endif



#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
#include <dos.h>
#include <fcntl.h>
#include <io.h>
#include <sys\types.h>
#include "pcparam.h"
#include "abios_st.h"
#include "dio.h"
#include "rb.h"
#include "bios.h"
#include "vars.h"


extern struct drvparm hdparm[], fdparam[];	/* In dio.c   */

/*
 * The rest are defined in rb.c
 */


extern struct bios_data far *bios_data;



struct rb_part  rb_part[NHD];

char	bbtbuf[2 * SECSIZE];
char    tmpbuf[2 * SECSIZE];


/*
 * This routine is used to write certain configuration paramaters to
 * a control block in the coprocessor memory that are required to
 * boot the system. Since the coprocessor addresses the PCIF
 * as the next 1MB after the end of it's own physical storage
 * we need to tell it how much memory it has. The other values
 * passed up are done so to make the boot process a little easier.
 */
void write_config()
{
	register int    i;
	u_short         seg, off, pstart, pend, lastdrive, drive, j, sysid, plen;
	u_long          addr;
	struct postconfig   config;
	struct hdinfo  *hdinfoptr;
	struct drvparm *hd;
#ifdef ABIOS
	u_long		badblock;
#endif /* ABIOS */
	struct ptable  *ptable = (struct ptable *) (tmpbuf + PTOFFSET);
	struct rb_part *hdpart;
	struct miscconfig {
		long	nvram;
		long	ipl_device;
		long	keyboard_id;
		long	machine_type;
		} miscconfig;
	extern long	boot_dev;		/* the boot device */
	extern u_short	dst_flag;		/* if dst in effect */
	extern u_short	pc_mem_size;		/* pc's memory */
	extern char     version[];		/* the version string */
	char *p;
	char *getenv();
	u_short physmem_reg = cur_cbcb->physmem_bytes >> 20;

#ifdef DEBUG
	u_short         ldebug = *dbugptr & INITDEBUG;
#endif /* DEBUG */


	/*
	 * Initialize the conf structure. 
	 */

	bzero((char *) &config, sizeof (struct postconfig));

	/*
	 * Now fill it in. 
	 */

	config.mem_size = exchw(physmem_reg);

	/*
	 * Note: Do NOT exchange these values. Unix expects to see them in
	 * INTEL byte order. 
	 */

	switch (physmem_reg)
	{
	case 2:
		config.memconfig = exchl((long) CONFIG2MB);
		break;

	case 4:
		config.memconfig = exchl((long) CONFIG4MB);
		break;

	case 8:
		config.memconfig = exchl((long) CONFIG8MB);
		break;

	default:
		printf("(%d) ", physmem_reg);
		pcpanic("Unknown Memory Size For ROMP Coprocessor");
		break;
	}

	config.pcif_base = exchw(cur_cbcb->port);/* Port address of PCIF	 */
	config.cpu = cur_cbcb->cpu;		/* this cpu number */
	config.maxcpu = ncpu;			/* total cpu's */

	addr = (u_long) (char far *) cur_cbcb;
	seg = HIWORD(addr);
	off = LOWORD(addr);
	config.cbcb_addr = exchl(MAKEPADDR(seg, off));	/* Address of cbcb */

	config.equip = exchw(bios_data->equip_flag);	/* Equip data */
	config.ega_info = bios_data->egasw1;	/* Ega switches */
	config.ega_switch = bios_data->egasw2;

	config.dst_flag = exchw(dst_flag);
	config.pc_mem_size = exchw(pc_mem_size);

	strncpy(config.version, version, (sizeof config.version) - 1);	/* copy version msg */

	/* allow passing of a string to UNIX in memory */
	if (p = getenv("UNIX_STRING"))
		strncpy(config.string, p, (sizeof config.string) - 1);

	/*
	 * Get all the Disk Info 
	 *
	 * For each drive that could be attached to the system: Call the routine
	 * getdiskgeometry() to find out if the disk is present. If the disk
	 * is attached then fill out the hdinfo data in the config record.
	 * Next we see if there is a bad block table present for this disk.
	 * If there is then we call bbtinit() for that drive. Finally we find
	 * out if there is a 4.2 partition defined on that drive, and if
	 * there is we place the starting cylinder and length into the hdinfo
	 * structure. 
	 *
	 *
	 * Note: Bios drive numbers for the fixed disks start at 0x80; 
	 *
	 */
#ifndef ABIOS
	config.os_type = DOS_TYPE;
	lastdrive = 0x80 + (NHD - 1);
	for (drive = 0x80; drive <= lastdrive; drive++)
#else /* ABIOS */
	config.os_type = ABIOS_TYPE;
	for (drive = 0 ; drive < NHD; drive++)
#endif /* ABIOS */
	{
#ifndef ABIOS
		getdiskgeometry(drive, (long) 0);
		j = drive - 0x80;
		hd = &hdparm[j];
		hdinfoptr = &config.hdinfo[j];
		hdpart = &rb_part[j];
#else /* ABIOS */
		hddiskgeometry(drive, (long) 0);
		hd = &hdparm[drive];
		hdinfoptr = &config.hdinfo[drive];
		hdpart = &rb_part[drive];
#endif /* ABIOS */
		if (hd->maxcyl)
		{
			hdinfoptr->ncpd = exchw(hd->maxcyl + 1);
			hdinfoptr->ntpc = exchw(hd->maxhd + 1);
			hdinfoptr->nspt = exchw(hd->maxsec);
			hdinfoptr->flag |= HDINFO_PRESENT;

			/*
			 * Check to see if there is a 4.2 Partition present.
			 * If there is then see if there is a bad block table 
			 */
#ifndef ABIOS
			if (io(DISKOP_READ, drive, 0, 0, 1, 1, (char far *) tmpbuf) >= 0)
#else /* ABIOS */
			if (hdio(DISKOP_READ, drive, (u_long)0, 1, 
						     (char far *) tmpbuf) >= 0)
#endif /* ABIOS */
			{
			  hdpart->dos_start = 0xfffffff;
			  hdpart->dos_end = 0;
			  if (ptable->signature == VALID_SIG)
			  {
			     for (i = 0; i < 4; i++)
			     {
				sysid = ptable->pt[i].sysid & 0x00ff;
				pstart = XTRACTCYL(ptable->pt[i].scyl, ptable->pt[i].ssec);
				pend = XTRACTCYL(ptable->pt[i].ecyl, ptable->pt[i].esec);
				plen = pend - pstart + 1;
				if ((sysid == DOS12) || (sysid == DOS16)) {
				   hdpart->dos_start = pstart;
				   hdpart->dos_end = pend;
				}
				if (sysid == ACIS42)
				{
				   /*
				    * Save it for rb to
				    * use 
				    */

				   hdpart->pstart = pstart;
				   hdpart->plen = plen;

				   /*
				    * Now put it into
				    * the config record 
				    */

				   hdinfoptr->pstart = exchw(pstart);
				   hdinfoptr->plen = exchw(plen);
				   hdinfoptr->flag |= HDINFO_42PART;
				   DEBUGF(ldebug, 
					printf("4.2 Partition For Drive %#x\n",
								 drive)
				   );
				   DEBUGF(ldebug, 
					printf("\tStart: %#x end %#x\n", 
								pstart, pend)
				   );
#ifdef ABIOS
				   badblock = ((u_long)pstart*(hd->maxhd + 1)
					* hd->maxsec) +8;
				   if (hdio(DISKOP_READ, drive, badblock, 1, 
						     (char far *)bbtbuf) >= 0) {
					if (bbtinit(drive,(char far *)bbtbuf)
								         >= 0) {
					   hdinfoptr->flag |= HDINFO_BADBLOCK;
					}
				   }
#else /* !ABIOS */
				   if (bbtinit(drive) >= 0)
					hdinfoptr->flag |= HDINFO_BADBLOCK;
#endif /* ABIOS */
				}
#ifdef DEBUG
				if (ldebug)
				   printf(
			      "Sys Id: %#x  Start %#x    End: %#x   Len: %#x\n",
				            sysid, pstart, pend, pend - pstart);
#endif /* DEBUG */
			     }
			   } else {
#ifdef DEBUG
				if (ldebug) {
				   printf("Invalid Signature %#x\n",
							ptable->signature);
				   printf("No Partition Table Present for drive %#x\n", drive);
				}
#endif /* DEBUG */
				hdinfoptr->flag |= HDINFO_NOBRPT;
			   }
	 		} else
				pcpanic("Can't Read Partition Record");

			hdinfoptr->flag = exchw(hdinfoptr->flag);
		}
	}

	addr = UNIXPOST;	/* This is where the stuff goes */

	if (moveout(addr, (caddr_t) & config, sizeof(config)) < 0)
		pcpanic("Can't write config data to coprocessor");

	addr = UNIXPOSTMISC;	/* where misc stuff goes */

	bzero((char *) &miscconfig, sizeof (struct miscconfig));

	miscconfig.ipl_device = exchl((long) boot_dev);

	if (moveout(addr, (caddr_t) & miscconfig, sizeof(miscconfig)) < 0)
		pcpanic("Can't write misc config data to coprocessor");

}

/*
 * zero a chunk of memory
 */
bzero(cp1,length)
	char	       *cp1;
	int		length;
{
	while (--length >= 0)
		*cp1++ = 0;
}

