xref: /csrg-svn/sys/vax/mba/hp.c (revision 344)
1 /*	hp.c	3.8	07/03/80	*/
2 
3 /*
4  * RP06/RM03 disk driver
5  */
6 
7 #include "../h/param.h"
8 #include "../h/systm.h"
9 #include "../h/dk.h"
10 #include "../h/dk.h"
11 #include "../h/buf.h"
12 #include "../h/conf.h"
13 #include "../h/dir.h"
14 #include "../h/user.h"
15 #include "../h/map.h"
16 #include "../h/mba.h"
17 #include "../h/mtpr.h"
18 #include "../h/pte.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	HPADDR	((struct device *)(MBA0 + MBA_ERB))
44 #define	NHP	2
45 #define	RP	022
46 #define	RM	024
47 #define	NSECT	22
48 #define	NTRAC	19
49 #define	NRMSECT	32
50 #define	NRMTRAC	5
51 
52 #define	_hpSDIST	3
53 #define	_hpRDIST	6
54 
55 int	hpSDIST = _hpSDIST;
56 int	hpRDIST = _hpRDIST;
57 int	hpseek;
58 
59 struct	size
60 {
61 	daddr_t	nblocks;
62 	int	cyloff;
63 } hp_sizes[8] =
64 {
65 	15884,	0,		/* cyl 0 thru 37 */
66 	33440,	38,		/* cyl 38 thru 117 */
67 	8360,	98,		/* cyl 98 thru 117 */
68 #ifdef ERNIE
69 	15884,	118,		/* cyl 118 thru 155 */
70 	66880,	156,		/* cyl 156 thru 315 */
71 	0,	0,
72 	291346,	118,		/* cyl 118 thru 814, (like distrib) */
73 	208582,	316,		/* cyl 316 thru 814 */
74 #else
75 	0,	0,
76 	0,	0,
77 	0,	0,
78 	291346,	118,		/* cyl 118 thru 814 */
79 	0,	0,
80 #endif
81 }, rm_sizes[8] = {
82 	15884,	0,		/* cyl 0 thru 99 */
83 	33440,	100,		/* cyl 100 thru 309 */
84 	0,	0,
85 	0,	0,
86 	0,	0,
87 	0,	0,
88 	82080,	310,		/* cyl 310 thru 822 */
89 	0,	0,
90 };
91 
92 #define	P400	020
93 #define	M400	0220
94 #define	P800	040
95 #define	M800	0240
96 #define	P1200	060
97 #define	M1200	0260
98 int	hp_offset[16] =
99 {
100 	P400, M400, P400, M400,
101 	P800, M800, P800, M800,
102 	P1200, M1200, P1200, M1200,
103 	0, 0, 0, 0,
104 };
105 
106 struct	buf	hptab;
107 struct	buf	rhpbuf;
108 struct	buf	hputab[NHP];
109 char	hp_type[NHP];	/* drive type */
110 
111 #define	GO	01
112 #define	PRESET	020
113 #define	RTC	016
114 #define	OFFSET	014
115 #define	SEEK	04
116 #define	SEARCH	030
117 #define	RECAL	06
118 #define	DCLR	010
119 #define	WCOM	060
120 #define	RCOM	070
121 
122 #define	IE	0100
123 #define	PIP	020000
124 #define	DRY	0200
125 #define	ERR	040000
126 #define	TRE	040000
127 #define	DCK	0100000
128 #define	WLE	04000
129 #define	ECH	0100
130 #define	VV	0100
131 #define	DPR	0400
132 #define	MOL	010000
133 #define	FMT22	010000
134 
135 #define	b_cylin b_resid
136 
137 #ifdef INTRLVE
138 daddr_t dkblock();
139 #endif
140 
141 hpstrategy(bp)
142 register struct buf *bp;
143 {
144 	register struct buf *dp;
145 	register unit, xunit, nspc;
146 	long sz, bn;
147 	struct size *sizes;
148 
149 	xunit = minor(bp->b_dev) & 077;
150 	sz = bp->b_bcount;
151 	sz = (sz+511) >> 9;
152 	unit = dkunit(bp);
153 	if (hp_type[unit] == 0) {
154 		struct device *hpaddr;
155 
156 		/* determine device type */
157 		hpaddr = (struct device *)((int*)HPADDR + 32*unit);
158 		hp_type[unit] = hpaddr->hpdt;
159 	}
160 	if (hp_type[unit] == RM) {
161 		sizes = rm_sizes;
162 		nspc = NRMSECT*NRMTRAC;
163 	} else {
164 		sizes = hp_sizes;
165 		nspc = NSECT*NTRAC;
166 	}
167 	if (unit >= NHP ||
168 	    bp->b_blkno < 0 ||
169 	    (bn = dkblock(bp))+sz > sizes[xunit&07].nblocks) {
170 		bp->b_flags |= B_ERROR;
171 		iodone(bp);
172 		return;
173 	}
174 	bp->b_cylin = bn/nspc + sizes[xunit&07].cyloff;
175 	dp = &hputab[unit];
176 	(void) spl5();
177 	disksort(dp, bp);
178 	if (dp->b_active == 0) {
179 		hpustart(unit);
180 		if(hptab.b_active == 0)
181 			hpstart();
182 	}
183 	(void) spl0();
184 }
185 
186 hpustart(unit)
187 register unit;
188 {
189 	register struct buf *bp, *dp;
190 	register struct device *hpaddr;
191 	daddr_t bn;
192 	int sn, cn, csn;
193 
194 	((struct mba_regs *)MBA0)->mba_cr |= MBAIE;
195 	HPADDR->hpas = 1<<unit;
196 
197 	if(unit >= NHP)
198 		return;
199 	if (unit+DK_N <= DK_NMAX)
200 		dk_busy &= ~(1<<(unit+DK_N));
201 	dp = &hputab[unit];
202 	if((bp=dp->b_actf) == NULL)
203 		return;
204 	hpaddr = (struct device *)((int *)HPADDR + 32*unit);
205 	if((hpaddr->hpds & VV) == 0) {
206 		hpaddr->hpcs1 = PRESET|GO;
207 		hpaddr->hpof = FMT22;
208 	}
209 	if(dp->b_active)
210 		goto done;
211 	dp->b_active++;
212 	if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL))
213 		goto done;
214 
215 	bn = dkblock(bp);
216 	cn = bp->b_cylin;
217 	if(hp_type[unit] == RM) {
218 		sn = bn%(NRMSECT*NRMTRAC);
219 		sn = (sn+NRMSECT-hpSDIST)%NRMSECT;
220 	} else {
221 		sn = bn%(NSECT*NTRAC);
222 		sn = (sn+NSECT-hpSDIST)%NSECT;
223 	}
224 
225 	if(cn - (hpaddr->hpdc & 0xffff))
226 		goto search;
227 	else if (hpseek)
228 		goto done;
229 	csn = ((hpaddr->hpla & 0xffff)>>6) - sn + 1;
230 	if(csn < 0)
231 		csn += NSECT;
232 	if(csn > NSECT-hpRDIST)
233 		goto done;
234 
235 search:
236 	hpaddr->hpdc = cn;
237 	if (hpseek)
238 		hpaddr->hpcs1 = SEEK|GO;
239 	else {
240 		hpaddr->hpda = sn;
241 		hpaddr->hpcs1 = SEARCH|GO;
242 	}
243 	unit += DK_N;
244 	if (unit <= DK_NMAX && DK_N+NHP <= DK_NMAX) {
245 		dk_busy |= 1<<unit;
246 		dk_numb[unit]++;
247 	}
248 	return;
249 
250 done:
251 	dp->b_forw = NULL;
252 	if(hptab.b_actf == NULL)
253 		hptab.b_actf = dp;
254 	else
255 		hptab.b_actl->b_forw = dp;
256 	hptab.b_actl = dp;
257 }
258 
259 hpstart()
260 {
261 	register struct buf *bp, *dp;
262 	register unit;
263 	register struct device *hpaddr;
264 	daddr_t bn;
265 	int dn, sn, tn, cn, nspc, ns;
266 
267 loop:
268 	if ((dp = hptab.b_actf) == NULL)
269 		return;
270 	if ((bp = dp->b_actf) == NULL) {
271 		hptab.b_actf = dp->b_forw;
272 		goto loop;
273 	}
274 	hptab.b_active++;
275 	unit = minor(bp->b_dev) & 077;
276 	dn = dkunit(bp);
277 	bn = dkblock(bp);
278 	if (hp_type[dn] == RM) {
279 		nspc = NRMSECT*NRMTRAC;
280 		ns = NRMSECT;
281 		cn = rm_sizes[unit&07].cyloff;
282 	} else {
283 		nspc = NSECT*NTRAC;
284 		ns = NSECT;
285 		cn = hp_sizes[unit&07].cyloff;
286 	}
287 	cn += bn/nspc;
288 	sn = bn%nspc;
289 	tn = sn/ns;
290 	sn = sn%ns;
291 
292 	hpaddr =  (struct device *)((int *)HPADDR + 32*dn);
293 	if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL)) {
294 		hptab.b_active = 0;
295 		hptab.b_errcnt = 0;
296 		dp->b_actf = bp->av_forw;
297 		bp->b_flags |= B_ERROR;
298 		iodone(bp);
299 		goto loop;
300 	}
301 	if(hptab.b_errcnt >= 16) {
302 		hpaddr->hpof = hp_offset[hptab.b_errcnt & 017] | FMT22;
303 		((struct mba_regs *)MBA0)->mba_cr &= ~MBAIE;
304 		hpaddr->hpcs1 = OFFSET|GO;
305 		while(hpaddr->hpds & PIP)
306 			;
307 		((struct mba_regs *)MBA0)->mba_cr |= MBAIE;
308 	}
309 	hpaddr->hpdc = cn;
310 	hpaddr->hpda = (tn << 8) + sn;
311 	mbastart(bp, (int *)hpaddr);
312 
313 	unit = dn+DK_N;
314 	if (NHP+DK_N == DK_NMAX)
315 		unit = NHP+DK_N;
316 	if (unit <= DK_NMAX) {
317 		dk_busy |= 1<<unit;
318 		dk_numb[unit]++;
319 		dk_wds[unit] += bp->b_bcount>>6;
320 	}
321 }
322 
323 hpintr(mbastat, as)
324 {
325 	register struct buf *bp, *dp;
326 	register unit;
327 	register struct device *hpaddr;
328 
329 	if(hptab.b_active) {
330 		dp = hptab.b_actf;
331 		bp = dp->b_actf;
332 		unit = dkunit(bp);
333 		if (DK_N+NHP == DK_NMAX)
334 			dk_busy &= ~(1<<(DK_N+NHP));
335 		else if (DK_N+unit <= DK_NMAX)
336 			dk_busy &= ~(1<<(DK_N+unit));
337 		hpaddr = (struct device *)((int *)HPADDR + 32*unit);
338 		if (hpaddr->hpds & ERR || mbastat & MBAEBITS) {		/* error bit */
339 			while((hpaddr->hpds & DRY) == 0)
340 				;
341 			if(++hptab.b_errcnt > 28 || hpaddr->hper1&WLE)
342 				bp->b_flags |= B_ERROR; else
343 				hptab.b_active = 0;
344 			if(hptab.b_errcnt > 27)
345 				deverror(bp, mbastat, hpaddr->hper1);
346 			if ((hpaddr->hper1&0xffff) == DCK) {
347 				if (hpecc(hpaddr, bp))
348 					return;
349 			}
350 			hpaddr->hpcs1 = DCLR|GO;
351 			if((hptab.b_errcnt&07) == 4) {
352 				((struct mba_regs *)MBA0)->mba_cr &= ~MBAIE;
353 				hpaddr->hpcs1 = RECAL|GO;
354 				while(hpaddr->hpds & PIP)
355 					;
356 				((struct mba_regs *)MBA0)->mba_cr |= MBAIE;
357 			}
358 		}
359 		if(hptab.b_active) {
360 			if(hptab.b_errcnt) {
361 				((struct mba_regs *)MBA0)->mba_cr &= ~MBAIE;
362 				hpaddr->hpcs1 = RTC|GO;
363 				while(hpaddr->hpds & PIP)
364 					;
365 				((struct mba_regs *)MBA0)->mba_cr |= MBAIE;
366 			}
367 			hptab.b_active = 0;
368 			hptab.b_errcnt = 0;
369 			hptab.b_actf = dp->b_forw;
370 			dp->b_active = 0;
371 			dp->b_errcnt = 0;
372 			dp->b_actf = bp->av_forw;
373 			bp->b_resid = -(((struct mba_regs *)MBA0)->mba_bcr) & 0xffff;
374 			iodone(bp);
375 			if(dp->b_actf)
376 				hpustart(unit);
377 		}
378 		as &= ~(1<<unit);
379 	} else {
380 		if(as == 0)
381 			((struct mba_regs *)MBA0)->mba_cr |= MBAIE;
382 	}
383 	for(unit=0; unit<NHP; unit++)
384 		if(as & (1<<unit))
385 			hpustart(unit);
386 	hpstart();
387 }
388 
389 hpread(dev)
390 {
391 
392 	physio(hpstrategy, &rhpbuf, dev, B_READ, minphys);
393 }
394 
395 hpwrite(dev)
396 {
397 
398 	physio(hpstrategy, &rhpbuf, dev, B_WRITE, minphys);
399 }
400 
401 hpecc(rp, bp)
402 register struct device *rp;
403 register struct buf *bp;
404 {
405 	register i;
406 	register b, n, map, mix;
407 	register char *cp;
408 	register mask;
409 	short piget();
410 	extern char buffers[NBUF][BSIZE];
411 
412 	b = (((((struct mba_regs *)MBA0)->mba_bcr&0xffff) +
413 		(bp->b_bcount) - 1)>>9)&0177;
414 	printf("%D ", bp->b_blkno+b);
415 	prdev("ECC", bp->b_dev);
416 	mask = rp->hpec2&0xffff;
417 	if (mask == 0) {
418 		rp->hpof = FMT22;
419 		return(0);
420 	}
421 	i = (rp->hpec1&0xffff) - 1;
422 	n = i&017;
423 	i = (i&~017)>>3;
424 	if (bp->b_flags&B_PHYS)
425 		map = 128 + b;
426 	else
427 		map = ((bp->b_un.b_addr - (char *)buffers)>>9) + b;
428 	mix = i + ((int)bp->b_un.b_addr&0x1ff);
429 	i += b<<9;
430 	if ( i < bp->b_bcount) {
431 		cp = (char *)((((int *)MBA0_MAP)[map+(mix>>9)]&0x1fffff)<<9)+(mix&0x1ff);
432 		piput((int)cp,piget((int)cp)^(mask<<n));
433 	}
434 	mix += 2;
435 	i += 2;
436 	if (i < bp->b_bcount) {
437 		cp = (char *)((((int *)MBA0_MAP)[map+(mix>>9)]&0x1fffff)<<9)+(mix&0x1ff);
438 		piput((int)cp,piget((int)cp)^(mask>>(16-n)));
439 	}
440 	hptab.b_active++;
441 	if (((struct mba_regs *)MBA0)->mba_bcr) {
442 		i = bp->b_blkno%(NSECT*NTRAC);
443 		i = ((i/NSECT)<<8)+(i%NSECT);
444 		i = NSECT*(i>>8) + (i&0377) + b + 1;
445 		if (i >= NSECT*NTRAC) {
446 			i -= NSECT*NTRAC;
447 			rp->hpdc = bp->b_cylin + 1;
448 		} else
449 			rp->hpdc = bp->b_cylin;
450 		rp->hpda = ((i/NSECT)<<8) + (i%NSECT);
451 		rp->hpcs1 = DCLR|GO;
452 		((struct mba_regs *)MBA0)->mba_sr = -1;
453 		((struct mba_regs *)MBA0)->mba_var =
454 			((map+1)<<9)|((int)bp->b_un.b_addr&0x1ff);
455 		rp->hpcs1 = RCOM|GO;
456 		return(1);
457 	} else
458 		return(0);
459 }
460 
461 short
462 piget(pad)
463 {
464 	register b, savemap;
465 	register short s;
466 
467 	savemap = (int)mmap;
468 	b = (pad>>9)&0x7fffff;
469 	*(int *)mmap = b|(PG_V|PG_KR);
470 	mtpr(TBIS, vmmap);
471 	s = *(short *)&vmmap[pad&0x1ff];
472 	*(int *)mmap = savemap;
473 	mtpr(TBIS, vmmap);
474 	return(s);
475 }
476 
477 piput(pad, val)
478 {
479 	register b, savemap;
480 	register short *p;
481 
482 	savemap = (int)mmap;
483 	b = (pad>>9)&0x7fffff;
484 	*(int *)mmap = b|(PG_V|PG_KW);
485 	mtpr(TBIS, vmmap);
486 	p = (short *)&vmmap[pad&0x1ff];
487 	*p = val;
488 	*(int *)mmap = savemap;
489 	mtpr(TBIS, vmmap);
490 }
491