/*
 *	This routine gets an absolute block from the boot disk.
 */

#include "ktypes.h"

char *_getblockwht = "$Header: getblock.c,v 1.5 86/12/17 15:12:15 tom Exp $";

extern struct rm  *DISKADDR;		/* ptr to drive registers */
extern struct MBA *MBABASE;		/* ptr to MBA regs*/

get_abs_block(unit,block,buffer)
	int	unit;
	long	block;
	char	*buffer;		/* where to put the data */
	
{
	return(rmget_abs_block(unit,block,buffer));
}


/*
 *	MASSBUS registers
 */
struct MBA
{
  bits32	csr;		/* 0 */
  bits32	cr;		/* 4 */
  bits32	sr;		/* 8 */
  cardinal32	var;		/* 0x0c */
  integer32	bcr;		/* 0x10 */
  byte		fill[0x7ec];	/* 0x14-0x7FF */
  cardinal32	map_reg[256];	/* 0x800 - 0x8ff */
};

#define	SETVV	0x13
#define READ	0x39
#define DRIVECLEAR 0x09
#define PRESET	0x11
#define	FORMAT16B	0x1000
#define BUSY	0x80000000
#define ABORT	0x1000

#define MBAVALID	0x80000000
#define MBAINIT		0x1
  

/*
 * rm   DEVICE SPECIFIC CODE to access the rm05 disk.  This routine
 *      reads a block from the disk.
 */

struct rm
{
	int     rmcs;		/* 0x00 */
	int     rmsr;		/* 0x04 */
	int     rmfill0;	/* 0x08 */
	int     rmfill1;	/* 0x0c */
	int	rmfill2;	/* 0x10 */
	int	rmda;		/* 0x14 */
	int	rmfill3;	/* 0x18 */
	int	rmfill4;	/* 0x1c */
	int	rmfill5;	/* 0x20 */
	int	rmof;		/* 0x24 */
	int	rmdc;		/* 0x28 */
};



rmget_abs_block(unit, block,bufptr)
	int                     unit;
	long                    block;
	char			*bufptr;
{
	register int            sector, track, cyl;
	register int	temp;

#ifdef DEBUG
printf("rmget_abs_block(DEBUG): unit %d, block %d, bufptr %X\n",
       unit,block,bufptr);
#endif

	/* check for range */

	if (unit < 0 || unit >= 8)
	  {
	    printf("rmget_abs_block: UNIT OUT OF RANGE: %d\n",unit);
	    return -1;
	  }


#ifdef NOTYET
	/* theoretically, this should only need to be done, once, and
	 * was done in the level 0 bootloader, but just for suspenders AND
	 * belt, we will do it again for every transfer
	 */
	MBABASE->cr = MBAINIT;	/* init MASSBUS */

	DISKADDR->rmof = FORMAT16B;

	DISKADDR->rmcs = 0;
	DISKADDR->rmcs = DRIVECLEAR;
	/* wait for drive ready */
	while (MBABASE->sr < 0)
	  ;

	DISKADDR->rmcs = PRESET;
	/* wait for drive ready */
	while (MBABASE->sr < 0)
	  ;

	DISKADDR->rmcs = SETVV;
#endif

	/* wait for drive ready */
	while (MBABASE->sr < 0)
	  ;

#ifdef DEBUG
printf("getblock(DEBUG): drive ready\n");
#endif
	
	/* calculate the disk address */

	sector = block % 32;
	block /= 32;

	track = block % 19;
	cyl = block / 19;

#ifdef DEBUG
printf("getblock(DEBUG): cyl %d, track %d, sector %d\n",
      cyl,track,sector);
#endif

	/* set up MBA registers */
	/* need to find the page frame # and byte offset of the actual buffer,
	   since the chances of it being page aligned are practically 0
	 */
	MBABASE->map_reg[0] = ( (unsigned int) bufptr) / 512 | MBAVALID;
	MBABASE->map_reg[1] = MBABASE->map_reg[0] + 1;
	MBABASE->map_reg[2] = 0;	/* firewall */
	MBABASE->var	    = (unsigned int)bufptr % 512;
	MBABASE->bcr	    = -512;
	
#ifdef DEBUG
printf("getblock(DEBUG): finished setting up MBA regs:\n");
printf("getblock(DEBUG): reg0 %X  reg1 %X, reg2 %X, var %X\n",
       MBABASE->map_reg[0],MBABASE->map_reg[1],MBABASE->map_reg[2],MBABASE->var);
#endif /* DEBUG */

	/* set up disk registers */

	DISKADDR->rmda = (track << 8) | sector;
	DISKADDR->rmdc = cyl;

#ifdef DEBUG
printf("getblock(DEBUG): drive regs set up, GOing...   ");
#endif
	DISKADDR->rmcs = READ;

#ifdef DEBUG
printf("waiting...  ");
#endif

	/* wait for not busy */

	while (MBABASE->sr < 0)
		;
#ifdef DEBUG
printf("Done\n");
#endif

#ifdef DEBUG
	dumpblock(bufptr);
#endif DEBUG

	/* check for error */

#ifdef DEBUG
printf("getblock: MBABASE->sr %X\n",MBABASE->sr);
printf("getblock: & ABORT %X\n",MBABASE->sr&ABORT);
#endif /* DEBUG */

	/* must use a temp reg car to force the compiler to not use
	   	a bit field instruction to the IO page, which appears
		to cause a machine check. If you must change this code,
		be sure and check the assembly output and beware the fruminous
		MACHINE CHECK!! - tep 11/20/86
	*/
	temp = MBABASE->sr&ABORT;
	
#ifdef DEBUG
printf("getblock: retval  %X\n",( temp ? -1 : 0) );
#endif

	return ( temp ? -1 : 0);
}


#ifdef DEBUG
dumpblock(ptr)
     cardinal32 *ptr;
{
  register int i;

printf("dumpblock: block &%X\n",ptr);

  for (i=0;i<128;i++)
    {
      if (i%8 == 0)
	printf("\n%X: ",ptr+i);
      printf("    %X",*(ptr+i));
    }
  printf("\n");
}
#endif


