xref: /csrg-svn/sys/vax/mba/hp.c (revision 1465)
1 /*	hp.c	3.16	10/16/80	*/
2 
3 /*
4  * RP06/RM03/RM05 disk driver
5  */
6 
7 #include "../h/param.h"
8 #include "../h/systm.h"
9 #include "../h/dk.h"
10 #include "../h/buf.h"
11 #include "../h/conf.h"
12 #include "../h/dir.h"
13 #include "../h/user.h"
14 #include "../h/map.h"
15 #include "../h/pte.h"
16 #include "../h/mba.h"
17 #include "../h/mtpr.h"
18 #include "../h/vm.h"
19 
20 #define	DK_N	0
21 #define	DK_NMAX	1
22 
23 struct	device
24 {
25 	int	hpcs1;		/* control and Status register 1 */
26 	int	hpds;		/* Drive Status */
27 	int	hper1;		/* Error register 1 */
28 	int	hpmr;		/* Maintenance */
29 	int	hpas;		/* Attention Summary */
30 	int	hpda;		/* Desired address register */
31 	int	hpdt;		/* Drive type */
32 	int	hpla;		/* Look ahead */
33 	int	hpsn;		/* serial number */
34 	int	hpof;		/* Offset register */
35 	int	hpdc;		/* Desired Cylinder address register */
36 	int	hpcc;		/* Current Cylinder */
37 	int	hper2;		/* Error register 2 */
38 	int	hper3;		/* Error register 3 */
39 	int	hpec1;		/* Burst error bit position */
40 	int	hpec2;		/* Burst error bit pattern */
41 };
42 
43 #define	HPMBA		MBA0
44 #define	HPMBANUM	0
45 
46 #define	NHP	2
47 #define	RP	022
48 #define	RM	024
49 #define	RM5	027
50 #define	NSECT	22
51 #define	NTRAC	19
52 #define	NRMSECT	32
53 #define	NRMTRAC	5
54 
55 #define	_hpSDIST	3
56 #define	_hpRDIST	6
57 
58 int	hpSDIST = _hpSDIST;
59 int	hpRDIST = _hpRDIST;
60 int	hpseek;
61 
62 struct	size
63 {
64 	daddr_t	nblocks;
65 	int	cyloff;
66 } hp_sizes[8] =
67 {
68 	15884,	0,		/* A=cyl 0 thru 37 */
69 	33440,	38,		/* B=cyl 38 thru 117 */
70 	340670,	0,		/* C=cyl 0 thru 814 */
71 	0,	0,
72 	0,	0,
73 	0,	0,
74 	291346,	118,		/* G=cyl 118 thru 814 */
75 	0,	0,
76 }, rm_sizes[8] = {
77 	15884,	0,		/* A=cyl 0 thru 99 */
78 	33440,	100,		/* B=cyl 100 thru 309 */
79 	131680,	0,		/* C=cyl 0 thru 822 */
80 	0,	0,
81 	0,	0,
82 	0,	0,
83 	82080,	310,		/* G=cyl 310 thru 822 */
84 	0,	0,
85 }, rm5_sizes[8] = {
86 	15884,	0,		/* A=cyl 0 thru 26 */
87 	33440,	27,		/* B=cyl 27 thru 81 */
88 	500992,	0,		/* C=cyl 0 thru 823 */
89 	15884,	562,		/* D=cyl 562 thru 588 */
90 	55936,	589,		/* E=cyl 589 thru 680 */
91 	86944,	681,		/* F=cyl 681 thru 823 */
92 	159296,	562,		/* G=cyl 562 thru 823 */
93 	291346,	82,		/* H=cyl 82 thru 561 */
94 };
95 
96 #define	P400	020
97 #define	M400	0220
98 #define	P800	040
99 #define	M800	0240
100 #define	P1200	060
101 #define	M1200	0260
102 int	hp_offset[16] =
103 {
104 	P400, M400, P400, M400,
105 	P800, M800, P800, M800,
106 	P1200, M1200, P1200, M1200,
107 	0, 0, 0, 0,
108 };
109 
110 struct	buf	hptab;
111 struct	buf	rhpbuf;
112 struct	buf	hputab[NHP];
113 char	hp_type[NHP];	/* drive type */
114 
115 #define	GO	01
116 #define	PRESET	020
117 #define	RTC	016
118 #define	OFFSET	014
119 #define	SEEK	04
120 #define	SEARCH	030
121 #define	RECAL	06
122 #define	DCLR	010
123 #define	WCOM	060
124 #define	RCOM	070
125 
126 #define	IE	0100
127 #define	PIP	020000
128 #define	DRY	0200
129 #define	ERR	040000
130 #define	TRE	040000
131 #define	DCK	0100000
132 #define	WLE	04000
133 #define	ECH	0100
134 #define	VV	0100
135 #define	DPR	0400
136 #define	MOL	010000
137 #define	FMT22	010000
138 
139 #define	b_cylin b_resid
140 
141 #ifdef INTRLVE
142 daddr_t dkblock();
143 #endif
144 
145 hpstrategy(bp)
146 register struct buf *bp;
147 {
148 	register struct buf *dp;
149 	register unit, xunit, nspc;
150 	long sz, bn;
151 	struct size *sizes;
152 
153 	if ((mbaact&(1<<HPMBANUM)) == 0)
154 		mbainit(HPMBANUM);
155 	xunit = minor(bp->b_dev) & 077;
156 	sz = bp->b_bcount;
157 	sz = (sz+511) >> 9;
158 	unit = dkunit(bp);
159 	if (hp_type[unit] == 0) {
160 		struct device *hpaddr;
161 		double mspw;
162 
163 		/* determine device type */
164 		hpaddr = mbadev(HPMBA, unit);
165 
166 		/* record transfer rate (these are guesstimates secs/word) */
167 		switch (hp_type[unit] = hpaddr->hpdt) {
168 		case RM:	mspw = .0000019728; break;
169 		case RM5:	mspw = .0000020345; break;
170 		case RP:	mspw = .0000029592; break;
171 		}
172 		if (DK_N + unit <= DK_NMAX)
173 			dk_mspw[DK_N+unit] = mspw;
174 	}
175 	switch (hp_type[unit]) {
176 
177 	case RM:
178 		sizes = rm_sizes;
179 		nspc = NRMSECT*NRMTRAC;
180 		break;
181 	case RM5:
182 		sizes = rm5_sizes;
183 		nspc = NRMSECT*NTRAC;
184 		break;
185 	case RP:
186 		sizes = hp_sizes;
187 		nspc = NSECT*NTRAC;
188 		break;
189 	default:
190 		printf("hp: unknown device type 0%o\n", hp_type[unit]);
191 		u.u_error = ENXIO;
192 		unit = NHP+1;	/* force error */
193 	}
194 	if (unit >= NHP ||
195 	    bp->b_blkno < 0 ||
196 	    (bn = dkblock(bp))+sz > sizes[xunit&07].nblocks) {
197 		bp->b_flags |= B_ERROR;
198 		iodone(bp);
199 		return;
200 	}
201 	bp->b_cylin = bn/nspc + sizes[xunit&07].cyloff;
202 	dp = &hputab[unit];
203 	(void) spl5();
204 	disksort(dp, bp);
205 	if (dp->b_active == 0) {
206 		hpustart(unit);
207 		if(hptab.b_active == 0)
208 			hpstart();
209 	}
210 	(void) spl0();
211 }
212 
213 hpustart(unit)
214 register unit;
215 {
216 	register struct buf *bp, *dp;
217 	register struct device *hpaddr;
218 	daddr_t bn;
219 	int sn, cn, csn;
220 
221 	((struct mba_regs *)MBA0)->mba_cr |= MBAIE;
222 	hpaddr = mbadev(HPMBA, 0);
223 	hpaddr->hpas = 1<<unit;
224 
225 	if(unit >= NHP)
226 		return;
227 	if (unit+DK_N <= DK_NMAX)
228 		dk_busy &= ~(1<<(unit+DK_N));
229 	dp = &hputab[unit];
230 	if((bp=dp->b_actf) == NULL)
231 		return;
232 	hpaddr = mbadev(HPMBA, unit);
233 	if((hpaddr->hpds & VV) == 0) {
234 		hpaddr->hpcs1 = PRESET|GO;
235 		hpaddr->hpof = FMT22;
236 	}
237 	if(dp->b_active)
238 		goto done;
239 	dp->b_active++;
240 	if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL))
241 		goto done;
242 
243 	bn = dkblock(bp);
244 	cn = bp->b_cylin;
245 	switch (hp_type[unit]) {
246 
247 	case RM:
248 		sn = bn%(NRMSECT*NRMTRAC);
249 		sn = (sn+NRMSECT-hpSDIST)%NRMSECT;
250 		break;
251 	case RM5:
252 		sn = bn%(NRMSECT*NTRAC);
253 		sn = (sn+NRMSECT-hpSDIST)%NRMSECT;
254 		break;
255 	case RP:
256 		sn = bn%(NSECT*NTRAC);
257 		sn = (sn+NSECT-hpSDIST)%NSECT;
258 		break;
259 	default:
260 		panic("hpustart");
261 	}
262 
263 	if(cn - (hpaddr->hpdc & 0xffff))
264 		goto search;
265 	else if (hpseek)
266 		goto done;
267 	csn = ((hpaddr->hpla & 0xffff)>>6) - sn + 1;
268 	if(csn < 0)
269 		csn += NSECT;
270 	if(csn > NSECT-hpRDIST)
271 		goto done;
272 
273 search:
274 	hpaddr->hpdc = cn;
275 	if (hpseek)
276 		hpaddr->hpcs1 = SEEK|GO;
277 	else {
278 		hpaddr->hpda = sn;
279 		hpaddr->hpcs1 = SEARCH|GO;
280 	}
281 	unit += DK_N;
282 	if (unit <= DK_NMAX) {
283 		dk_busy |= 1<<unit;
284 		dk_seek[unit]++;
285 	}
286 	return;
287 
288 done:
289 	dp->b_forw = NULL;
290 	if(hptab.b_actf == NULL)
291 		hptab.b_actf = dp;
292 	else
293 		hptab.b_actl->b_forw = dp;
294 	hptab.b_actl = dp;
295 }
296 
297 hpstart()
298 {
299 	register struct buf *bp, *dp;
300 	register unit;
301 	register struct device *hpaddr;
302 	daddr_t bn;
303 	int dn, sn, tn, cn, nspc, ns;
304 
305 loop:
306 	if ((dp = hptab.b_actf) == NULL)
307 		return;
308 	if ((bp = dp->b_actf) == NULL) {
309 		hptab.b_actf = dp->b_forw;
310 		goto loop;
311 	}
312 	hptab.b_active++;
313 	unit = minor(bp->b_dev) & 077;
314 	dn = dkunit(bp);
315 	bn = dkblock(bp);
316 	switch (hp_type[dn]) {
317 	case RM:
318 		nspc = NRMSECT*NRMTRAC;
319 		ns = NRMSECT;
320 		cn = rm_sizes[unit&07].cyloff;
321 		break;
322 	case RM5:
323 		nspc = NRMSECT*NTRAC;
324 		ns = NRMSECT;
325 		cn = rm5_sizes[unit&07].cyloff;
326 		break;
327 	case RP:
328 		nspc = NSECT*NTRAC;
329 		ns = NSECT;
330 		cn = hp_sizes[unit&07].cyloff;
331 		break;
332 	default:
333 		panic("hpstart");
334 	}
335 	cn += bn/nspc;
336 	sn = bn%nspc;
337 	tn = sn/ns;
338 	sn = sn%ns;
339 
340 	hpaddr = mbadev(HPMBA, dn);
341 	if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL)) {
342 		hptab.b_active = 0;
343 		hptab.b_errcnt = 0;
344 		dp->b_actf = bp->av_forw;
345 		bp->b_flags |= B_ERROR;
346 		iodone(bp);
347 		goto loop;
348 	}
349 	if(hptab.b_errcnt >= 16 && (bp->b_flags&B_WRITE) == 0) {
350 		hpaddr->hpof = hp_offset[hptab.b_errcnt & 017] | FMT22;
351 		HPMBA->mba_cr &= ~MBAIE;
352 		hpaddr->hpcs1 = OFFSET|GO;
353 		while(hpaddr->hpds & PIP)
354 			;
355 		HPMBA->mba_cr |= MBAIE;
356 	}
357 	hpaddr->hpdc = cn;
358 	hpaddr->hpda = (tn << 8) + sn;
359 	mbastart(bp, (int *)hpaddr);
360 
361 	unit = dn+DK_N;
362 	if (unit <= DK_NMAX) {
363 		dk_busy |= 1<<unit;
364 		dk_xfer[unit]++;
365 		dk_wds[unit] += bp->b_bcount>>6;
366 	}
367 }
368 
369 hpintr(mbastat, as)
370 {
371 	register struct buf *bp, *dp;
372 	register unit;
373 	register struct device *hpaddr;
374 
375 	if(hptab.b_active) {
376 		dp = hptab.b_actf;
377 		bp = dp->b_actf;
378 		unit = dkunit(bp);
379 		if (DK_N+unit <= DK_NMAX)
380 			dk_busy &= ~(1<<(DK_N+unit));
381 		hpaddr = mbadev(HPMBA, unit);
382 		if (hpaddr->hpds & ERR || mbastat & MBAEBITS) {
383 			while((hpaddr->hpds & DRY) == 0)
384 				;
385 			if(++hptab.b_errcnt > 28 || hpaddr->hper1&WLE)
386 				bp->b_flags |= B_ERROR;
387 			else
388 				hptab.b_active = 0;
389 			if(hptab.b_errcnt > 27)
390 				deverror(bp, mbastat, hpaddr->hper1);
391 			if ((hpaddr->hper1&0xffff) == DCK) {
392 				if (hpecc(hpaddr, bp))
393 					return;
394 			}
395 			hpaddr->hpcs1 = DCLR|GO;
396 			if((hptab.b_errcnt&07) == 4) {
397 				HPMBA->mba_cr &= ~MBAIE;
398 				hpaddr->hpcs1 = RECAL|GO;
399 				while(hpaddr->hpds & PIP)
400 					;
401 				HPMBA->mba_cr |= MBAIE;
402 			}
403 		}
404 		if(hptab.b_active) {
405 			if(hptab.b_errcnt) {
406 				HPMBA->mba_cr &= ~MBAIE;
407 				hpaddr->hpcs1 = RTC|GO;
408 				while(hpaddr->hpds & PIP)
409 					;
410 				HPMBA->mba_cr |= MBAIE;
411 			}
412 			hptab.b_active = 0;
413 			hptab.b_errcnt = 0;
414 			hptab.b_actf = dp->b_forw;
415 			dp->b_active = 0;
416 			dp->b_errcnt = 0;
417 			dp->b_actf = bp->av_forw;
418 			bp->b_resid = -HPMBA->mba_bcr & 0xffff;
419 			iodone(bp);
420 			if(dp->b_actf)
421 				hpustart(unit);
422 		}
423 		as &= ~(1<<unit);
424 	} else {
425 		if(as == 0)
426 			HPMBA->mba_cr |= MBAIE;
427 	}
428 	for(unit=0; unit<NHP; unit++)
429 		if(as & (1<<unit))
430 			hpustart(unit);
431 	hpstart();
432 }
433 
434 hpread(dev)
435 {
436 
437 	physio(hpstrategy, &rhpbuf, dev, B_READ, minphys);
438 }
439 
440 hpwrite(dev)
441 {
442 
443 	physio(hpstrategy, &rhpbuf, dev, B_WRITE, minphys);
444 }
445 
446 hpecc(rp, bp)
447 register struct device *rp;
448 register struct buf *bp;
449 {
450 	struct mba_regs *mbp = HPMBA;
451 	register int i;
452 	caddr_t addr;
453 	int reg, bit, byte, npf, mask, o;
454 	int dn, bn, cn, tn, sn, ns, nt;
455 	extern char buffers[NBUF][BSIZE];
456 	struct pte mpte;
457 	int bcr;
458 
459 	/*
460 	 * Npf is the number of sectors transferred before the sector
461 	 * containing the ECC error, and reg is the MBA register
462 	 * mapping (the first part of)the transfer.
463 	 * O is offset within a memory page of the first byte transferred.
464 	 */
465 	bcr = mbp->mba_bcr & 0xffff;
466 	if (bcr)
467 		bcr |= 0xffff0000;		/* sxt */
468 	npf = btop(bcr + bp->b_bcount) - 1;
469 	reg = npf;
470 	o = (int)bp->b_un.b_addr & PGOFSET;
471 	printf("%D ", bp->b_blkno + npf);
472 	prdev("ECC", bp->b_dev);
473 	mask = rp->hpec2&0xffff;
474 	if (mask == 0) {
475 		rp->hpof = FMT22;
476 		return (0);
477 	}
478 
479 	/*
480 	 * Compute the byte and bit position of the error.
481 	 * The variable i is the byte offset in the transfer,
482 	 * the variable byte is the offset from a page boundary
483 	 * in main memory.
484 	 */
485 	i = (rp->hpec1&0xffff) - 1;		/* -1 makes 0 origin */
486 	bit = i&07;
487 	i = (i&~07)>>3;
488 	byte = i + o;
489 	/*
490 	 * Correct while possible bits remain of mask.  Since mask
491 	 * contains 11 bits, we continue while the bit offset is > -11.
492 	 * Also watch out for end of this block and the end of the whole
493 	 * transfer.
494 	 */
495 	while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) {
496 		mpte = mbp->mba_map[reg+btop(byte)];
497 		addr = ptob(mpte.pg_pfnum) + (byte & PGOFSET);
498 		putmemc(addr, getmemc(addr)^(mask<<bit));
499 		byte++;
500 		i++;
501 		bit -= 8;
502 	}
503 	hptab.b_active++;		/* Either complete or continuing */
504 	if (bcr == 0)
505 		return (0);
506 	/*
507 	 * Have to continue the transfer... clear the drive,
508 	 * and compute the position where the transfer is to continue.
509 	 * We have completed npf+1 sectores of the transfer already;
510 	 * restart at offset o of next sector (i.e. in MBA register reg+1).
511 	 */
512 	rp->hpcs1 = DCLR|GO;
513 	dn = dkunit(bp);
514 	bn = dkblock(bp);
515 	switch (hp_type[dn]) {
516 
517 	case RM:
518 		ns = NRMSECT; nt = NRMTRAC; break;
519 	case RM5:
520 		ns = NRMSECT; nt = NTRAC; break;
521 	case RP:
522 		ns = NSECT; nt = NTRAC; break;
523 	default:
524 		panic("hpecc");
525 	}
526 	cn = bp->b_cylin;
527 	sn = bn%(ns*nt) + npf + 1;
528 	tn = sn/ns;
529 	sn %= ns;
530 	cn += tn/nt;
531 	tn %= nt;
532 	rp->hpdc = cn;
533 	rp->hpda = (tn<<8) + sn;
534 	mbp->mba_sr = -1;
535 	mbp->mba_var = (int)ptob(reg+1) + o;
536 	rp->hpcs1 = RCOM|GO;
537 	return (1);
538 }
539