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