V7M/sys/dev/hk.c_i

/*
*	RK06/07 disk driver
*/

#include "../h/param.h"
#include "../h/systm.h"
#include "../h/buf.h"
#include "../h/conf.h"
#include "../h/dir.h"
#include "../h/user.h"

/*
*
*	The following  structure defines the order of the Control
*	and Status registers for the RK06/07
*
*/
struct device
{
	int	hkcs1;		/* Control and Status register 1 */
	int	hkwc;		/* Word Count Register */
	caddr_t	hkba;		/* Memory Address Register */
	int	hkda;		/* Track Sector Address Register */
	int	hkcs2;		/* Control And Status Register 2 */
	int	hkds;		/* Drive Status Register */
	int	hkerr;		/* Error Register */
	int	hkas;		/* High byte is Attention Summary | Low is Offset Reg. */
	int	hkdc;		/* Desired Cylinder Register */
	int	dum;		/* Dummy for unused location */
	int	hkdb;		/* Data Buffer */
	int	hkmr1;		/* Maintenance Register 1 */
	int	hkec1;		/* ECC Position Register */
	int	hkec2;		/* ECC Pattern Register */
	int	hkmr2;		/* Maint. Register 2 */
	int	hkmr3;		/* Maint. Register 3 */
};

#define	HKADDR	((struct device *)0177440)	/* RK6/711 address */
#define	NHK	2				/* number of drives on system */
#define	NSECT	22				/* number of sectors per pack */
#define	NTRAC	3				/* number of tracks per cylinder */
#define NUMTRY 28				/* max retry count */

/*
*
*	The structure hk_sizes defines the logical separation of a disk pack
*	into mountable file systems.
*
*	The file systems are named in numeric order.
*
*		the first entry in hk_sizes describes file system hk0
*		the next hk1  , etc.
*
*	The nblocksnblocks entry specifies the number of blocks (512 bytes) in
*	the file system.
*
*	The cyloffcyloff entry specifies the offset+1 from the physical beginning
*	of the pack to the beginning of the file system in cylinderscylinders
*
*/
struct	size
{
	daddr_t	nblocks;
	int	cyloff;
} hk_sizes[8] =
{
	9636,	0,	/* cyl   0-145, root on rk06/7		*/
	8910,	146,	/* cyl 146-280, swap on rk06/7		*/
	8514,	281,	/* cyl 281-409, rest of rk06 pack	*/
	26598,	411,	/* cyl 411-813, rest of rk07 pack	*/
	0,	0,	/* spare, for avoiding bad blocks	*/
	0,	0,	/* spare, for avoiding bad blocks	*/
	27060,	0,	/* cyl   0-409, all of rk06 pack	*/
	53724,	0,	/* cyl   0-813, all of rk07 back	*/
};

/*
*
*		NOT IMPLEMENTED AT THIS TIME
*	The following definitions specify the offset values used during error recovery
*
*/
#define P400	020		/* +400  RK06 , +200  RK07 */
#define M400	0220		/* -400  RK06 , -200  RK07 */
#define P800	040		/* +800  RK06 , +400 RK07 */
#define M800	0240		/* -800  RK06 , -400  RK07 */
#define P1200	060		/* +1200  RK06 , +600  RK07 */
#define M1200	0260		/* -1200  RK06 , -600 Rk07 */
/*
*
*	The following array defines the order in which the offset values defined above
*	are used during error recovery.
*
*/
int	hk_offset[16] =
{
	P400, M400, P400, M400,
	P800, M800, P800, M800,
	P1200, M1200, P1200, M1200,
	0, 0, 0, 0,
};

int hk_drvtyp[NHK];		/* This array contains the drive type for each  drive on the system */
char hk_mntflg[NHK];		/* This array contains a special flag for each drive on the system */
				/* it is set to indicate that a drive type is known to the system */
char hk_recal[NHK];		/* recalibrate flag */

struct buf	hktab;		/* This is the buffer header used exclusivly by the RK06/07 for block I/O */
				/* the structure is the same as buf.h but useage is slightly different */

struct buf	rhkbuf;		/* This buffer header is used by the RK06/07 for raw I/O. struct. same as hktab */

/*
*	Control and Status bit definitions for  hkcs1
*/
#define GO	01			/* GO bit */
#define SELECT	01			/* Select Function */
#define PAKACK	02			/* Pack Acknowledge Function */
#define DCLR	04			/* Drive Clear Function */
#define UNLOAD	06			/* Unload Heads Function */
#define STRSPN	010			/* Start Spindle Function */
#define RECAL	012			/* Recalibrate Function */
#define OFFSET	014			/* Offset Function */
#define SEEK	016			/* Seek Function */
#define RCOM	020			/* Read Command */
#define WCOM	022			/* Write Command */
#define RHDR	024			/* Read Header	*/
#define WHDR	026			/* Write Header	*/
#define WCHK	030			/* Write Check Function */
#define IEI	0100			/* Interrupt Inable bit */
#define CRDY	0200			/* Controller Ready bit */
#define SEL7	02000			/* Select RK07 bit */
#define CTO	04000			/* Controller Time Out bit */
#define CFMT	010000			/* Controller Format bit */
#define DTCPAR	020000			/* Drive to Controller Parity Error */
#define DINTR	040000			/* Drive Interrupt bit */
#define CCLR	0100000			/* Controller Clear bit */
#define CERR	0100000			/* Controller Error bit */

/*
*	Control and Status bit definitions for  hkcs2
*/
#define DLT	0100000			/* Data Late error */
#define WCE	040000			/* Write Check Error */
#define UPE	020000			/* Unibus Parity Error */
#define NED	010000			/* Nonexistent Drive error */
#define NEM	04000			/* Nonexistent Memory error */
#define PGE	02000			/* Programming error */
#define MDS	01000			/* Multiple Drive Select error */
#define UFE	0400			/* Unit Field Error */
#define SCLR	040			/* Subsystem Clear bit */
#define BAI	020			/* Bus Address Increment Inhibit bit */
#define RLS	010			/* Release bit	*/

/*
*	Control and Status bit definitions for  hkds
*/
#define SVAL	0100000			/* Status Valid bit */
#define CDA	040000			/* Current Drive Attention bit */
#define PIP	020000			/* Position In Progress bit */
#define WRL	04000			/* Write Lock bit */
#define DDT	0400			/* Disk Drive Type bit */
#define DRDY	0200			/* Drive Ready bit */
#define VV	0100			/* Volume Valid bit */
#define DROT	040			/* Drive Off Track Error */
#define SPLS	020			/* Speed Loss Error	*/
#define ACLO	010			/* Drive AC Low */
#define DOFST	04			/* Drive Offset bit */
#define DRA	01			/* Drive Available bit */

/*
*	Control and Status bit definitions for  hkerr
*/
#define DCK	0100000			/* Data Check error */
#define DUNS	040000			/* Drive Unsafe error */
#define OPI	020000			/* Operation Incomplete error */
#define DTE	010000			/* Drive Timing error */
#define DWLE	04000			/* Drive Write Lock error */
#define IDAE	02000			/* Invalid Disk Address Error */
#define COE	01000			/* Cylinder Overflow Error	*/
#define HRVC	0400			/* Header Vertical Redundance Check Error */
#define BSE	0200			/* Bad Sector Error */
#define ECH	0100			/* Error Correction Hard error */
#define DTYE	040			/* Drive Type error */
#define FMTE	020			/* Format Error */
#define CDPAR	010			/* Controller To Driver Parity Error */
#define NXF	04			/* Nonexecutable Function Error */
#define SKI	02			/* Seek Incomplete error */
#define ILF	01			/* Illegal Function Error */

#define trksec av_back
#define cylin b_resid

struct	ios	hk_ios[NHK];
#define DK_N	1
#define	DK_T	3


/*
*
*	The following routine determines the drive type of the selected unit, saves drive type in hk_drvtyp
*	and sets flag in hk_mntflg.
*
*/
hkdsel(drn)
{
		int count, pri;

		count = drn;					/* pick up the drive number */
		hk_drvtyp[count] = 0;				/* set default drive type to RK06 */
		HKADDR->hkcs2 = count;				/* load drive number in hkcs2 */
		HKADDR->hkcs1 = SELECT;				/* do a select function */
		while((HKADDR->hkcs1 & CRDY) == 0);		/* wait for ready */
		if(HKADDR->hkcs1 & CERR && HKADDR->hkerr & DTYE){
			hk_drvtyp[count] = SEL7;		/* Error.  Drive type is RK07 */
			HKADDR->hkcs1 = CCLR;			/* Controller clear */
			while((HKADDR->hkcs1 & CRDY)==0);	/* wait for ready */
		}
		hk_mntflg[count] = '1';				/* set mnt flag and return */
		hk_ios[drn].dk_tr = DK_T;
		pri = spl6();
		dk_iop[DK_N] = &hk_ios[0];
		dk_nd[DK_N] = NHK;
		splx(pri);
}
/*
*
*	hkstrategy checks for overflow errors
*
*/
hkstrategy(bp)
register struct buf *bp;
{
	register int unit;
	long sz;

	if(bp->b_flags & B_PHYS)
		mapalloc(bp);		/* if not block i/o see about allocating ubmap */
	unit = minor(bp->b_dev);	/* pickup unit number from buffer header */
	sz = bp->b_bcount;		/* pickup size from buffer header. should be 512 bytes */
	sz = (sz+511)>>9;		/* convert to number of blocks */

	/* if unit requested is greater than number available 
	* or
	* block number is < 0
	* or
	* block number +size is > number of blocks in file system
	* ERROR
	*/
	if(unit >= (NHK<<3) ||
	  bp->b_blkno < 0 ||
	  bp->b_blkno+sz >= hk_sizes[unit&007].nblocks) {
		bp->b_flags |= B_ERROR;		/* set ERROR flag */
		iodone(bp);			/* call iodone to return buffer to pool */
		return;				/* bye bye */
	}

/*
*	no error so continue 
*/
	bp->av_forw = NULL;		/* clear the available forward link in the buffer header */
	spl5();				/* set priority to 5.  don't want to be interrupted by drive right now */
	if (hktab.b_actf == NULL)
		hktab.b_actf = bp;	/* grab the header pointer for later use by hkintr */
	else
		hktab.b_actl->av_forw = bp; /* already linked. so make a forward link for next buffer */
	hktab.b_actl = bp;		/* and make a back link */
	if(hktab.b_active == NULL)
		hkstart();		/* if drive not active call hkstart */
	spl0();
}

hkstart()
{
	register struct buf *bp;
	register int unit;
	int com,cn,tn,sn,dn;
	daddr_t bn;

	if ((bp = hktab.b_actf) == NULL)
		return;					/* no buffer link */
	hktab.b_active++;				/* say that we're active */
	unit = minor(bp->b_dev);			/* get the unit and file system number */
	dn = unit>>3;					/* strip file sys number and load drive number in dn */
	if(hk_mntflg[dn] != '1'){
		hkdsel(dn);				/* if no mntflg then call hkdsel to determine drive type */
		if(HKADDR->hkcs2 & NED){
			bp->b_flags |= B_ERROR;		/* returned from hkdsel with error */
			deverror(bp, HKADDR->hkcs2, HKADDR->hkerr);
			HKADDR->hkcs1 = CCLR;
			while((HKADDR->hkcs1 & CRDY) == 0);
			hktab.b_active = NULL;	/* not active */
			iodone(bp);		/* return buffer */
			return;			/* bye bye */
		}
	}
	bn = bp->b_blkno;				/* get the block number */
	cn = (bn/(NSECT*NTRAC)) + hk_sizes[unit&07].cyloff;		/* calculate the cylinder number */
	sn = bn%(NSECT*NTRAC);				/* calculate the */
	tn = sn/NSECT;					/* track number */
	sn = sn%NSECT;					/* get the sector number */
	if((HKADDR->hkds & VV) ==0){
		HKADDR->hkcs2 = dn;
		HKADDR->hkcs1 = hk_drvtyp[dn]|PAKACK|GO;		/* set volume valid */
		while ((HKADDR->hkcs1 & CRDY) == 0);	/* wait for ready */
	}
	HKADDR->hkdc = cn;				/* load the desired cylinder */
	HKADDR->hkda = (tn<<8)|sn;			/* and the track , sector */
	HKADDR->hkba = bp->b_un.b_addr;			/* get memory address */
	HKADDR->hkwc = -(bp->b_bcount>>1);		/*  compliment and load the word count */
	com = ((bp->b_xmem&3)<<8)|IEI|GO;		/* set up extended memory , interrupt enable , and go bits */
	if(bp->b_flags & B_READ)
		com |= RCOM; else
		com |= WCOM;				/* set write command */
	com |= hk_drvtyp[dn];				/* set drive type */
	HKADDR->hkcs2 = dn;				/* select drive number */
	HKADDR->hkcs1 = com;				/*  and load it all into hkcs1 */
	hk_ios[dn].dk_busy++;
	hk_ios[dn].dk_numb++;
	unit = bp->b_bcount>>6;			/* more here */
	hk_ios[dn].dk_wds += unit;
/*				Thats all.	*/
}


hkintr()
{
	register struct buf *bp;
	register int ctr,as,i,j,dn;


	if(hktab.b_active == NULL)
		return;			/* false interrupt. just return */
	while((HKADDR->hkcs1 & CRDY) == 0);	/* !Wait for controller ready! */
	dn = HKADDR->hkcs2 & 07;	/* get drive number */
	bp = hktab.b_actf;		/* grab buffer header pointer */
	if(hk_recal[dn] == '1')
		goto drecal;		/* recalibrate in progress */
	if(HKADDR->hkcs1 & CERR)
	{
		if(++hktab.b_errcnt >= NUMTRY || HKADDR->hkcs2 & NED ||
			HKADDR->hkerr & (DWLE|FMTE|BSE))
		{
			bp->b_flags |= B_ERROR;	/* Fatal error End it */
			deverror(bp, HKADDR->hkcs2, HKADDR->hkerr);
			HKADDR->hkcs2 = SCLR; /* Subsystem clear */
			while((HKADDR->hkcs1 & CRDY) == 0);
			hk_recal[dn] = ' '; /* reset the recal in progess flag */
			hktab.b_active = NULL; /* reset the active flag */
			goto out;
		}
		if(HKADDR->hkerr & (DTE|IDAE|BSE|NXF|DUNS) &&
			(HKADDR->hkcs2 & (MDS|UFE)) == 0 &&
			(HKADDR->hkcs1 & CTO) == 0)
		{
			HKADDR->hkcs1 = CCLR;
			while((HKADDR->hkcs1 & CRDY)==0);
			HKADDR->hkcs2 = dn;
			HKADDR->hkcs1 = (hk_drvtyp[dn]|DCLR|GO);
			while((HKADDR->hkcs1 & CRDY)==0);
		}
		if(HKADDR->hkcs1 & CTO || HKADDR->hkcs2 & (MDS|UFE))
		{
			HKADDR->hkcs2 = SCLR;
			while((HKADDR->hkcs1 & CRDY)==0);
		}
		if(HKADDR->hkds & DROT || HKADDR->hkerr & (OPI|SKI))
		{
			hk_recal[dn]  = '1';
			HKADDR->hkcs1 = CCLR;
			while((HKADDR->hkcs1 & CRDY)== 0);
			HKADDR->hkcs2 = dn;
			HKADDR->hkcs1 = (hk_drvtyp[dn]|DCLR|GO);
			while((HKADDR->hkcs1& CRDY)==0);
			HKADDR->hkcs1 = (hk_drvtyp[dn]|IEI|RECAL|GO);
			return;
	drecal:
			HKADDR->hkcs1 = (hk_drvtyp[dn]|SELECT);
			while((HKADDR->hkcs1 & CRDY)==0);
			if((HKADDR->hkds & DRDY)==0)
			{
				HKADDR->hkcs1 = (hk_drvtyp[dn]|IEI|SELECT);
				return;
			}
			hk_recal[dn] = ' ';
		}
		if((bp->b_flags & B_PHYS) == 0 &&
			(HKADDR->hkerr & (DCK|ECH)) == DCK)
		{
			i = HKADDR->hkec1 -1;
			j = i & 017;
			i >>=4;
			if(i >= 0 && i <256)
			{
			bp->b_un.b_words[i] ^= HKADDR->hkec2 << j;
			bp->b_un.b_words[i+1] ^= HKADDR->hkec2 >> (16 - j);
			}
			printf("%D ",bp->b_blkno);
			prdev("ECC",bp->b_dev);
			HKADDR->hkcs1 = CCLR;
			while((HKADDR->hkcs1 & CRDY)==0);
			hktab.b_active = NULL;
		}
		if(hktab.b_active != NULL)
		{
			HKADDR->hkcs1 = CCLR;
			while ((HKADDR->hkcs1 & CRDY)==0);
			hktab.b_active = NULL;
			hkstart();
			return;
		}
	}
out:
	hktab.b_active = NULL;
	hk_ios[dn].dk_busy = 0;
	hktab.b_errcnt = 0;
	hktab.b_actf = bp->av_forw;
	bp->b_resid = 0;
	iodone(bp);
	hkstart();
}



hkread(dev)
dev_t dev;
{
	physio(hkstrategy, &rhkbuf, dev, B_READ);
}

hkwrite(dev)
dev_t dev;
{
	physio(hkstrategy, &rhkbuf, dev, B_WRITE);
}