SRI-NOSC/dmr/si.c

Compare this file to the similar file:
Show the results in this format:

#
/*
 * System Industries (SI) controller driver for CDC 9760/9762 disk.
 *
 */
#include "param.h"
#include "buf.h"
#include "conf.h"
#include "user.h"

#define	logical	char *		/* don't say logical i,j; !!! */

/*
 * Use 2 cells in struct buf for physical disk address pieces.
 */
#define	hdsec	av_back		/* head & sector */
#define	pcyl	b_resid		/* port & cylinder */

#define	SIADDR	0176700

struct siregs		/* device registers */
{	int sicnr;		/* control */
	int siwcr;		/* word count (not 2's complement!) */
	int sipcr;		/* port/cylinder */
	int sihsr;		/* head/sector */
	int simar;		/* memory address */
	int sierr;		/* errors & status */
/* unused for now...
	int sissr;
	int sisar;
	int sidbr;
	int sictr;
	int siscr;
 */
};
/*
 * sicnr layout
 */
#define	POFFSET	040000		/* offset+  (toward spindle) */
#define	MOFFSET	020000		/* offset- */
#define	ESTROBE	010000		/* strobe early */
#define	LSTROBE	004000		/* strobe late */
#define	FENABLE	001000		/* format enable */
#define	MARINH	000400		/* inhibit simar increment */
#define	RDY	000200		/* controller ready */
#define	IENABLE	000100		/* interrupt enable */
#define	MAREXT	000060		/* simar extension bits */
#define	VERIFY	000010		/* read or write verify function */
#define	READ	000004		/* read enable */
#define	WRITE	000002		/* write enable */
#define	GO	000001		/* initiate indicated function */
#define	RESET	0		/* clear simar & controller */

#ifdef SI9762
#define HEADS	19		/* # of heads (or surfaces) 9762 */
#define NSI	16		/* # of minor device slots per drive */
#endif 9762
#ifndef SI9762
#define HEADS	5		/* # of heads for 9760 */
#define	NSI	8		/* # of minor device slots per drive */
#endif 9760

#define	TRKSIZ	32		/* # of 512 byte sectors/track */
#define	CYLSIZ	(HEADS*TRKSIZ)

#define	RKSIZ	4872		/* # of sectors on a DEC RK05 drive */
#define	RKTRKS	153		/* # of tracks to simulate RK05 */

#define	MAXSIZ	0		/* 65,536 blocks on largest UNIX device */
#define	MAXTRKS	2048		/* # of tracks for largest UNIX device */

/*
 * Disk is organized to place tmp, swap, root, and user file systems
 * close together and near the center of the drive.
 */

struct siminor		/* layout of minor devices for each drive */
{	int trkoff;		/* starting track # (not cylinder!) */
	logical nblocks;	/* # of sectors in minor device */
} sisizes[NSI] {
#ifdef SI9762		/* disk layout for 300 Mb disk */
		/* this mapping is not correct, but it will do
		   as a filler untill a better one is defined.
		*/
	0*MAXTRKS+0*RKTRKS,	MAXSIZ,		/* si0 */
	1*MAXTRKS+0*RKTRKS,	MAXSIZ,		/* si1 */
	2*MAXTRKS+0*RKTRKS,	MAXSIZ,		/* si2 */
	3*MAXTRKS+0*RKTRKS,	RKSIZ,		/* si3 */
	3*MAXTRKS+1*RKTRKS,	RKSIZ,		/* si4 */
	3*MAXTRKS+2*RKTRKS,	RKSIZ,		/* si5 */
	3*MAXTRKS+3*RKTRKS,	RKSIZ,		/* si6 */
	3*MAXTRKS+4*RKTRKS,	RKSIZ,		/* si7 */
	3*MAXTRKS+5*RKTRKS,	RKSIZ,		/* si8 */
	3*MAXTRKS+6*RKTRKS,	RKSIZ,		/* si9 */
	3*MAXTRKS+7*RKTRKS,	MAXSIZ,		/* si10 */
	4*MAXTRKS+7*RKTRKS,	MAXSIZ,		/* si11 */
	5*MAXTRKS+7*RKTRKS,	MAXSIZ,		/* si12 */
	6*MAXTRKS+7*RKTRKS,	MAXSIZ,		/* si13 */
	7*MAXTRKS+7*RKTRKS,	MAXSIZ,		/* si14 */
	8*MAXTRKS+7*RKTRKS,	MAXSIZ,		/* si15 */
#endif 9762
#ifndef SI9762		/* disk layout for 80 Mb disk */
	0*HEADS,	40*CYLSIZ,	/* si0 */
	40*HEADS,	40*CYLSIZ,	/* si1 */
	80*HEADS,	40*CYLSIZ,	/* si2 */
	120*HEADS,	40*CYLSIZ,	/* si3 */
	160*HEADS,	80*CYLSIZ,	/* si4 */
	240*HEADS,	171*CYLSIZ,	/* si5 */
	80*HEADS,	80*CYLSIZ,	/* si6 -- overlays si[23] */
	0*HEADS,	411*CYLSIZ	/* si7 -- the entire disk */
#endif 9760
};

struct devtab sitab;
struct buf sibuf;		/* for raw i/o */


sistrategy(abp)
struct buf *abp;
{
	register struct buf *bp;

	bp = abp;
	if (bp->b_flags&B_PHYS)
		mapalloc(bp);
	if (siaddr(bp))		/* check transfer & form disk address */
	{	iodone(bp);
		return;
	}
	bp->av_forw = 0;
	spl5();		/* link buffer into I/O queue */
	if (sitab.d_actf == 0)
		sitab.d_actf = bp;
	else
		sitab.d_actl->av_forw = bp;
	sitab.d_actl = bp;
	if (sitab.d_active == 0)
		sistart();
	spl0();
}


int siaddr(abp)
struct buf *abp;
/*
 * Compute port/cylinder and head/sector disk addresses
 * and place in bp->pcyl and bp->hdsec.  A non-zero return value
 * indicates that the transfer specified by b_dev, b_blkno, and
 * b_wcount is invalid, and pcyl & hdsec are left untouched.
 */
{
	register struct buf *bp;
	register struct siminor *mp;
	register logical blkcnt;	/* # of blocks in transfer */
	int blkoff;
	int i;

/*
 * Validate the transfer; check minor device existence & extent.
 */
	bp = abp;
	i = bp->b_dev.d_minor&(NSI-1);
	mp = &sisizes[i];
	if ((mp->nblocks != 0 && bp->b_blkno >= mp->nblocks) ||
	    (blkcnt = (255 - bp->b_wcount)/256) == 0 ||
	    (bp->b_blkno != 0 && blkcnt > mp->nblocks - bp->b_blkno) ||
	    (bp->b_blkno == 0 && mp->nblocks != 0 && blkcnt > mp->nblocks) )
	{	bp->b_flags =| B_ERROR;
		bp->b_error = ENXIO;
		bp->b_resid = bp->b_wcount;
		return(1);
	}
/*
 * Form port/cylinder and head/sector disk addresses.
 */
	blkoff = (mp->trkoff%HEADS)*TRKSIZ + lrem(bp->b_blkno, CYLSIZ);
	bp->pcyl = (mp->trkoff/HEADS) + ldiv(bp->b_blkno, CYLSIZ) +
	    blkoff/CYLSIZ + (bp->b_dev.d_minor/NSI << 10);
	bp->hdsec = blkoff%CYLSIZ;
	return(0);
}


sistart()
{
	register struct buf *bp;
	register int *rp;		/* for siregs */
	int cmd, m;

	if ((bp = sitab.d_actf) == 0)
		return;
	sitab.d_active++;
	cmd = ((bp->b_xmem&03) << 4)
	      |((bp->b_flags&B_READ)? READ:WRITE);

	rp = &SIADDR->simar;

	SIADDR->sicnr = RESET;
	*rp   =  bp->b_addr;		/* simar */
	*--rp =  bp->hdsec;		/* sihsr */
	*--rp =  bp->pcyl;		/* sipcr */
	*--rp =  -bp->b_wcount;		/* siwcr */
	*--rp =  IENABLE|cmd|GO;	/* sicnr */
}


siintr()
{
	register struct buf *bp;

	if (sitab.d_active == 0)
		return;
	bp = sitab.d_actf;
	sitab.d_active = 0;
	if (SIADDR->sierr < 0)	/* error summary */
	{	deverror(bp, SIADDR->sierr, SIADDR->sicnr);
		if (++sitab.d_errcnt <= 10)
		{	sistart();
			return;
		}
		bp->b_flags =| B_ERROR;
	}
	sitab.d_errcnt = 0;
	sitab.d_actf = bp->av_forw;
	bp->b_resid = 1 + SIADDR->siwcr;   /* reads back as 1's complement */
	iodone(bp);
	sistart();
}


siread(dev)
int dev;
{
	physio(&sistrategy, &sibuf, dev, B_READ);
}


siwrite(dev)
int dev;
{
	physio(&sistrategy, &sibuf, dev, B_WRITE);
}