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