xref: /csrg-svn/sys/vax/mba/hp.c (revision 420)
1*420Sbill /*	hp.c	3.9	07/29/80	*/
221Sbill 
321Sbill /*
4344Sbill  * RP06/RM03 disk driver
521Sbill  */
621Sbill 
721Sbill #include "../h/param.h"
821Sbill #include "../h/systm.h"
9305Sbill #include "../h/dk.h"
1021Sbill #include "../h/buf.h"
1121Sbill #include "../h/conf.h"
1221Sbill #include "../h/dir.h"
1321Sbill #include "../h/user.h"
1421Sbill #include "../h/map.h"
15*420Sbill #include "../h/pte.h"
1621Sbill #include "../h/mba.h"
1721Sbill #include "../h/mtpr.h"
18*420Sbill #include "../h/vm.h"
1921Sbill 
2021Sbill #define	DK_N	0
21344Sbill #define	DK_NMAX	1
2221Sbill 
2321Sbill struct	device
2421Sbill {
2521Sbill 	int	hpcs1;		/* control and Status register 1 */
2621Sbill 	int	hpds;		/* Drive Status */
2721Sbill 	int	hper1;		/* Error register 1 */
2821Sbill 	int	hpmr;		/* Maintenance */
2921Sbill 	int	hpas;		/* Attention Summary */
3021Sbill 	int	hpda;		/* Desired address register */
3121Sbill 	int	hpdt;		/* Drive type */
3221Sbill 	int	hpla;		/* Look ahead */
3321Sbill 	int	hpsn;		/* serial number */
3421Sbill 	int	hpof;		/* Offset register */
3521Sbill 	int	hpdc;		/* Desired Cylinder address register */
3621Sbill 	int	hpcc;		/* Current Cylinder */
3721Sbill 	int	hper2;		/* Error register 2 */
3821Sbill 	int	hper3;		/* Error register 3 */
3921Sbill 	int	hpec1;		/* Burst error bit position */
4021Sbill 	int	hpec2;		/* Burst error bit pattern */
4121Sbill };
4221Sbill 
43*420Sbill #define	HPMBA		MBA0
44*420Sbill #define	HPMBANUM	0
45*420Sbill 
46342Sbill #define	NHP	2
4721Sbill #define	RP	022
4821Sbill #define	RM	024
4921Sbill #define	NSECT	22
5021Sbill #define	NTRAC	19
5121Sbill #define	NRMSECT	32
5221Sbill #define	NRMTRAC	5
5321Sbill 
54305Sbill #define	_hpSDIST	3
55305Sbill #define	_hpRDIST	6
56305Sbill 
57305Sbill int	hpSDIST = _hpSDIST;
58305Sbill int	hpRDIST = _hpRDIST;
59305Sbill int	hpseek;
60305Sbill 
6121Sbill struct	size
6221Sbill {
6321Sbill 	daddr_t	nblocks;
6421Sbill 	int	cyloff;
6521Sbill } hp_sizes[8] =
6621Sbill {
6721Sbill 	15884,	0,		/* cyl 0 thru 37 */
6821Sbill 	33440,	38,		/* cyl 38 thru 117 */
6921Sbill 	8360,	98,		/* cyl 98 thru 117 */
7021Sbill #ifdef ERNIE
7121Sbill 	15884,	118,		/* cyl 118 thru 155 */
7221Sbill 	66880,	156,		/* cyl 156 thru 315 */
7321Sbill 	0,	0,
7421Sbill 	291346,	118,		/* cyl 118 thru 814, (like distrib) */
7521Sbill 	208582,	316,		/* cyl 316 thru 814 */
7621Sbill #else
7721Sbill 	0,	0,
7821Sbill 	0,	0,
7921Sbill 	0,	0,
8021Sbill 	291346,	118,		/* cyl 118 thru 814 */
8121Sbill 	0,	0,
8221Sbill #endif
8321Sbill }, rm_sizes[8] = {
8421Sbill 	15884,	0,		/* cyl 0 thru 99 */
8521Sbill 	33440,	100,		/* cyl 100 thru 309 */
8621Sbill 	0,	0,
8721Sbill 	0,	0,
8821Sbill 	0,	0,
8921Sbill 	0,	0,
9021Sbill 	82080,	310,		/* cyl 310 thru 822 */
9121Sbill 	0,	0,
9221Sbill };
9321Sbill 
9421Sbill #define	P400	020
9521Sbill #define	M400	0220
9621Sbill #define	P800	040
9721Sbill #define	M800	0240
9821Sbill #define	P1200	060
9921Sbill #define	M1200	0260
10021Sbill int	hp_offset[16] =
10121Sbill {
10221Sbill 	P400, M400, P400, M400,
10321Sbill 	P800, M800, P800, M800,
10421Sbill 	P1200, M1200, P1200, M1200,
10521Sbill 	0, 0, 0, 0,
10621Sbill };
10721Sbill 
10821Sbill struct	buf	hptab;
10921Sbill struct	buf	rhpbuf;
11021Sbill struct	buf	hputab[NHP];
11121Sbill char	hp_type[NHP];	/* drive type */
11221Sbill 
11321Sbill #define	GO	01
11421Sbill #define	PRESET	020
11521Sbill #define	RTC	016
11621Sbill #define	OFFSET	014
117305Sbill #define	SEEK	04
11821Sbill #define	SEARCH	030
11921Sbill #define	RECAL	06
12021Sbill #define	DCLR	010
12121Sbill #define	WCOM	060
12221Sbill #define	RCOM	070
12321Sbill 
12421Sbill #define	IE	0100
12521Sbill #define	PIP	020000
12621Sbill #define	DRY	0200
12721Sbill #define	ERR	040000
12821Sbill #define	TRE	040000
12921Sbill #define	DCK	0100000
13021Sbill #define	WLE	04000
13121Sbill #define	ECH	0100
13221Sbill #define	VV	0100
13321Sbill #define	DPR	0400
13421Sbill #define	MOL	010000
13521Sbill #define	FMT22	010000
13621Sbill 
13721Sbill #define	b_cylin b_resid
13821Sbill 
13921Sbill #ifdef INTRLVE
14021Sbill daddr_t dkblock();
14121Sbill #endif
14221Sbill 
14321Sbill hpstrategy(bp)
14421Sbill register struct buf *bp;
14521Sbill {
14621Sbill 	register struct buf *dp;
14721Sbill 	register unit, xunit, nspc;
14821Sbill 	long sz, bn;
14921Sbill 	struct size *sizes;
15021Sbill 
151*420Sbill 	if ((mbaact&(1<<HPMBANUM)) == 0)
152*420Sbill 		mbainit(HPMBANUM);
15321Sbill 	xunit = minor(bp->b_dev) & 077;
15421Sbill 	sz = bp->b_bcount;
15521Sbill 	sz = (sz+511) >> 9;
15621Sbill 	unit = dkunit(bp);
15721Sbill 	if (hp_type[unit] == 0) {
15821Sbill 		struct device *hpaddr;
15921Sbill 
16021Sbill 		/* determine device type */
161*420Sbill 		hpaddr = mbadev(HPMBA, unit);
16221Sbill 		hp_type[unit] = hpaddr->hpdt;
16321Sbill 	}
16421Sbill 	if (hp_type[unit] == RM) {
16521Sbill 		sizes = rm_sizes;
16621Sbill 		nspc = NRMSECT*NRMTRAC;
16721Sbill 	} else {
16821Sbill 		sizes = hp_sizes;
16921Sbill 		nspc = NSECT*NTRAC;
17021Sbill 	}
17121Sbill 	if (unit >= NHP ||
17221Sbill 	    bp->b_blkno < 0 ||
17321Sbill 	    (bn = dkblock(bp))+sz > sizes[xunit&07].nblocks) {
17421Sbill 		bp->b_flags |= B_ERROR;
17521Sbill 		iodone(bp);
17621Sbill 		return;
17721Sbill 	}
17821Sbill 	bp->b_cylin = bn/nspc + sizes[xunit&07].cyloff;
17921Sbill 	dp = &hputab[unit];
180127Sbill 	(void) spl5();
18121Sbill 	disksort(dp, bp);
18221Sbill 	if (dp->b_active == 0) {
18321Sbill 		hpustart(unit);
18421Sbill 		if(hptab.b_active == 0)
18521Sbill 			hpstart();
18621Sbill 	}
187127Sbill 	(void) spl0();
18821Sbill }
18921Sbill 
19021Sbill hpustart(unit)
19121Sbill register unit;
19221Sbill {
19321Sbill 	register struct buf *bp, *dp;
19421Sbill 	register struct device *hpaddr;
19521Sbill 	daddr_t bn;
19621Sbill 	int sn, cn, csn;
19721Sbill 
19821Sbill 	((struct mba_regs *)MBA0)->mba_cr |= MBAIE;
199*420Sbill 	hpaddr = mbadev(HPMBA, 0);
200*420Sbill 	hpaddr->hpas = 1<<unit;
20121Sbill 
20221Sbill 	if(unit >= NHP)
20321Sbill 		return;
204344Sbill 	if (unit+DK_N <= DK_NMAX)
205344Sbill 		dk_busy &= ~(1<<(unit+DK_N));
20621Sbill 	dp = &hputab[unit];
20721Sbill 	if((bp=dp->b_actf) == NULL)
20821Sbill 		return;
209*420Sbill 	hpaddr = mbadev(HPMBA, unit);
21021Sbill 	if((hpaddr->hpds & VV) == 0) {
21121Sbill 		hpaddr->hpcs1 = PRESET|GO;
21221Sbill 		hpaddr->hpof = FMT22;
21321Sbill 	}
21421Sbill 	if(dp->b_active)
21521Sbill 		goto done;
21621Sbill 	dp->b_active++;
21721Sbill 	if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL))
21821Sbill 		goto done;
21921Sbill 
22021Sbill 	bn = dkblock(bp);
22121Sbill 	cn = bp->b_cylin;
22221Sbill 	if(hp_type[unit] == RM) {
22321Sbill 		sn = bn%(NRMSECT*NRMTRAC);
224305Sbill 		sn = (sn+NRMSECT-hpSDIST)%NRMSECT;
22521Sbill 	} else {
22621Sbill 		sn = bn%(NSECT*NTRAC);
227305Sbill 		sn = (sn+NSECT-hpSDIST)%NSECT;
22821Sbill 	}
22921Sbill 
23021Sbill 	if(cn - (hpaddr->hpdc & 0xffff))
23121Sbill 		goto search;
232305Sbill 	else if (hpseek)
233305Sbill 		goto done;
234305Sbill 	csn = ((hpaddr->hpla & 0xffff)>>6) - sn + 1;
23521Sbill 	if(csn < 0)
23621Sbill 		csn += NSECT;
237305Sbill 	if(csn > NSECT-hpRDIST)
23821Sbill 		goto done;
23921Sbill 
24021Sbill search:
24121Sbill 	hpaddr->hpdc = cn;
242305Sbill 	if (hpseek)
243305Sbill 		hpaddr->hpcs1 = SEEK|GO;
244305Sbill 	else {
245305Sbill 		hpaddr->hpda = sn;
246305Sbill 		hpaddr->hpcs1 = SEARCH|GO;
247305Sbill 	}
24821Sbill 	unit += DK_N;
249344Sbill 	if (unit <= DK_NMAX && DK_N+NHP <= DK_NMAX) {
250344Sbill 		dk_busy |= 1<<unit;
251344Sbill 		dk_numb[unit]++;
252344Sbill 	}
25321Sbill 	return;
25421Sbill 
25521Sbill done:
25621Sbill 	dp->b_forw = NULL;
25721Sbill 	if(hptab.b_actf == NULL)
258344Sbill 		hptab.b_actf = dp;
259344Sbill 	else
26021Sbill 		hptab.b_actl->b_forw = dp;
26121Sbill 	hptab.b_actl = dp;
26221Sbill }
26321Sbill 
26421Sbill hpstart()
26521Sbill {
26621Sbill 	register struct buf *bp, *dp;
26721Sbill 	register unit;
26821Sbill 	register struct device *hpaddr;
26921Sbill 	daddr_t bn;
27021Sbill 	int dn, sn, tn, cn, nspc, ns;
27121Sbill 
27221Sbill loop:
27321Sbill 	if ((dp = hptab.b_actf) == NULL)
27421Sbill 		return;
27521Sbill 	if ((bp = dp->b_actf) == NULL) {
27621Sbill 		hptab.b_actf = dp->b_forw;
27721Sbill 		goto loop;
27821Sbill 	}
27921Sbill 	hptab.b_active++;
28021Sbill 	unit = minor(bp->b_dev) & 077;
28121Sbill 	dn = dkunit(bp);
28221Sbill 	bn = dkblock(bp);
28321Sbill 	if (hp_type[dn] == RM) {
28421Sbill 		nspc = NRMSECT*NRMTRAC;
28521Sbill 		ns = NRMSECT;
28621Sbill 		cn = rm_sizes[unit&07].cyloff;
28721Sbill 	} else {
28821Sbill 		nspc = NSECT*NTRAC;
28921Sbill 		ns = NSECT;
29021Sbill 		cn = hp_sizes[unit&07].cyloff;
29121Sbill 	}
29221Sbill 	cn += bn/nspc;
29321Sbill 	sn = bn%nspc;
29421Sbill 	tn = sn/ns;
29521Sbill 	sn = sn%ns;
29621Sbill 
297*420Sbill 	hpaddr = mbadev(HPMBA, dn);
29821Sbill 	if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL)) {
29921Sbill 		hptab.b_active = 0;
30021Sbill 		hptab.b_errcnt = 0;
30121Sbill 		dp->b_actf = bp->av_forw;
30221Sbill 		bp->b_flags |= B_ERROR;
30321Sbill 		iodone(bp);
30421Sbill 		goto loop;
30521Sbill 	}
30621Sbill 	if(hptab.b_errcnt >= 16) {
30721Sbill 		hpaddr->hpof = hp_offset[hptab.b_errcnt & 017] | FMT22;
308*420Sbill 		HPMBA->mba_cr &= ~MBAIE;
30921Sbill 		hpaddr->hpcs1 = OFFSET|GO;
31021Sbill 		while(hpaddr->hpds & PIP)
31121Sbill 			;
312*420Sbill 		HPMBA->mba_cr |= MBAIE;
31321Sbill 	}
31421Sbill 	hpaddr->hpdc = cn;
31521Sbill 	hpaddr->hpda = (tn << 8) + sn;
31621Sbill 	mbastart(bp, (int *)hpaddr);
31721Sbill 
318344Sbill 	unit = dn+DK_N;
319344Sbill 	if (NHP+DK_N == DK_NMAX)
320344Sbill 		unit = NHP+DK_N;
321344Sbill 	if (unit <= DK_NMAX) {
322344Sbill 		dk_busy |= 1<<unit;
323344Sbill 		dk_numb[unit]++;
324344Sbill 		dk_wds[unit] += bp->b_bcount>>6;
325344Sbill 	}
32621Sbill }
32721Sbill 
32821Sbill hpintr(mbastat, as)
32921Sbill {
33021Sbill 	register struct buf *bp, *dp;
33121Sbill 	register unit;
33221Sbill 	register struct device *hpaddr;
33321Sbill 
33421Sbill 	if(hptab.b_active) {
33521Sbill 		dp = hptab.b_actf;
33621Sbill 		bp = dp->b_actf;
33721Sbill 		unit = dkunit(bp);
338344Sbill 		if (DK_N+NHP == DK_NMAX)
339344Sbill 			dk_busy &= ~(1<<(DK_N+NHP));
340344Sbill 		else if (DK_N+unit <= DK_NMAX)
341344Sbill 			dk_busy &= ~(1<<(DK_N+unit));
342*420Sbill 		hpaddr = mbadev(HPMBA, unit);
343*420Sbill 		if (hpaddr->hpds & ERR || mbastat & MBAEBITS) {
34421Sbill 			while((hpaddr->hpds & DRY) == 0)
34521Sbill 				;
34621Sbill 			if(++hptab.b_errcnt > 28 || hpaddr->hper1&WLE)
347*420Sbill 				bp->b_flags |= B_ERROR;
348*420Sbill 			else
34921Sbill 				hptab.b_active = 0;
35021Sbill 			if(hptab.b_errcnt > 27)
35121Sbill 				deverror(bp, mbastat, hpaddr->hper1);
35221Sbill 			if ((hpaddr->hper1&0xffff) == DCK) {
35321Sbill 				if (hpecc(hpaddr, bp))
35421Sbill 					return;
35521Sbill 			}
35621Sbill 			hpaddr->hpcs1 = DCLR|GO;
35721Sbill 			if((hptab.b_errcnt&07) == 4) {
358*420Sbill 				HPMBA->mba_cr &= ~MBAIE;
35921Sbill 				hpaddr->hpcs1 = RECAL|GO;
36021Sbill 				while(hpaddr->hpds & PIP)
36121Sbill 					;
362*420Sbill 				HPMBA->mba_cr |= MBAIE;
36321Sbill 			}
36421Sbill 		}
36521Sbill 		if(hptab.b_active) {
36621Sbill 			if(hptab.b_errcnt) {
367*420Sbill 				HPMBA->mba_cr &= ~MBAIE;
36821Sbill 				hpaddr->hpcs1 = RTC|GO;
36921Sbill 				while(hpaddr->hpds & PIP)
37021Sbill 					;
371*420Sbill 				HPMBA->mba_cr |= MBAIE;
37221Sbill 			}
37321Sbill 			hptab.b_active = 0;
37421Sbill 			hptab.b_errcnt = 0;
37521Sbill 			hptab.b_actf = dp->b_forw;
37621Sbill 			dp->b_active = 0;
37721Sbill 			dp->b_errcnt = 0;
37821Sbill 			dp->b_actf = bp->av_forw;
379*420Sbill 			bp->b_resid = -HPMBA->mba_bcr & 0xffff;
38021Sbill 			iodone(bp);
38121Sbill 			if(dp->b_actf)
38221Sbill 				hpustart(unit);
38321Sbill 		}
38421Sbill 		as &= ~(1<<unit);
38521Sbill 	} else {
38621Sbill 		if(as == 0)
387*420Sbill 			HPMBA->mba_cr |= MBAIE;
38821Sbill 	}
38921Sbill 	for(unit=0; unit<NHP; unit++)
39021Sbill 		if(as & (1<<unit))
39121Sbill 			hpustart(unit);
39221Sbill 	hpstart();
39321Sbill }
39421Sbill 
39521Sbill hpread(dev)
39621Sbill {
39721Sbill 
39821Sbill 	physio(hpstrategy, &rhpbuf, dev, B_READ, minphys);
39921Sbill }
40021Sbill 
40121Sbill hpwrite(dev)
40221Sbill {
40321Sbill 
40421Sbill 	physio(hpstrategy, &rhpbuf, dev, B_WRITE, minphys);
40521Sbill }
40621Sbill 
40721Sbill hpecc(rp, bp)
40821Sbill register struct device *rp;
40921Sbill register struct buf *bp;
41021Sbill {
411*420Sbill 	struct mba_regs *mbp = HPMBA;
412*420Sbill 	register int i;
413*420Sbill 	caddr_t addr;
414*420Sbill 	int reg, bit, byte, npf, mask, o;
415*420Sbill 	int dn, bn, cn, tn, sn, ns, nt;
416106Sbill 	extern char buffers[NBUF][BSIZE];
417*420Sbill 	struct pte mpte;
41821Sbill 
419*420Sbill 	/*
420*420Sbill 	 * Npf is the number of sectors transferred before the sector
421*420Sbill 	 * containing the ECC error, and reg is the MBA register
422*420Sbill 	 * mapping (the first part of)the transfer.
423*420Sbill 	 * O is offset within a memory page of the first byte transferred.
424*420Sbill 	 */
425*420Sbill 	npf = btop((mbp->mba_bcr&0xffff) + bp->b_bcount) - 1;
426*420Sbill 	if (bp->b_flags&B_PHYS)
427*420Sbill 		reg = 128 + npf;
428*420Sbill 	else
429*420Sbill 		reg = btop(bp->b_un.b_addr - buffers[0]) + npf;
430*420Sbill 	o = (int)bp->b_un.b_addr & PGOFSET;
431*420Sbill 	printf("%D ", bp->b_blkno + npf);
43221Sbill 	prdev("ECC", bp->b_dev);
43321Sbill 	mask = rp->hpec2&0xffff;
43421Sbill 	if (mask == 0) {
43521Sbill 		rp->hpof = FMT22;
436*420Sbill 		return (0);
43721Sbill 	}
438*420Sbill 
439*420Sbill 	/*
440*420Sbill 	 * Compute the byte and bit position of the error.
441*420Sbill 	 * The variable i is the byte offset in the transfer,
442*420Sbill 	 * the variable byte is the offset from a page boundary
443*420Sbill 	 * in main memory.
444*420Sbill 	 */
445*420Sbill 	i = (rp->hpec1&0xffff) - 1;		/* -1 makes 0 origin */
446*420Sbill 	bit = i&017;
447*420Sbill 	i = (i&~07)>>3;
448*420Sbill 	byte = i + o;
449*420Sbill 	/*
450*420Sbill 	 * Correct while possible bits remain of mask.  Since mask
451*420Sbill 	 * contains 11 bits, we continue while the bit offset is > -11.
452*420Sbill 	 * Also watch out for end of this block and the end of the whole
453*420Sbill 	 * transfer.
454*420Sbill 	 */
455*420Sbill 	while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) {
456*420Sbill 		mpte = mbp->mba_map[reg+btop(byte)];
457*420Sbill 		addr = ptob(mpte.pg_pfnum) + (byte & PGOFSET);
458*420Sbill 		putmemc(addr, getmemc(addr)^(mask<<bit));
459*420Sbill 		byte++;
460*420Sbill 		i++;
461*420Sbill 		bit -= 8;
46221Sbill 	}
463*420Sbill 	hptab.b_active++;		/* Either complete or continuing */
464*420Sbill 	if (mbp->mba_bcr == 0)
465*420Sbill 		return (0);
466*420Sbill 	/*
467*420Sbill 	 * Have to continue the transfer... clear the drive,
468*420Sbill 	 * and compute the position where the transfer is to continue.
469*420Sbill 	 * We have completed npf+1 sectores of the transfer already;
470*420Sbill 	 * restart at offset o of next sector (i.e. in MBA register reg+1).
471*420Sbill 	 */
472*420Sbill 	rp->hpcs1 = DCLR|GO;
473*420Sbill 	dn = dkunit(bp);
474*420Sbill 	bn = dkblock(bp);
475*420Sbill 	if (hp_type[dn] == RM) {
476*420Sbill 		ns = NRMSECT;
477*420Sbill 		nt = NRMTRAC;
478*420Sbill 	} else {
479*420Sbill 		ns = NSECT;
480*420Sbill 		nt = NTRAC;
48121Sbill 	}
482*420Sbill 	cn = bp->b_cylin;
483*420Sbill 	sn = bn%(ns*nt) + npf + 1;
484*420Sbill 	tn = sn/ns;
485*420Sbill 	sn %= ns;
486*420Sbill 	cn += tn/nt;
487*420Sbill 	tn %= nt;
488*420Sbill 	rp->hpdc = cn;
489*420Sbill 	rp->hpda = (tn<<8) + sn;
490*420Sbill 	mbp->mba_sr = -1;
491*420Sbill 	mbp->mba_var = (int)ptob(reg+1) + o;
492*420Sbill 	rp->hpcs1 = RCOM|GO;
493*420Sbill 	return (1);
49421Sbill }
495