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