xref: /original-bsd/sys/vax/mba/hp.c (revision d25e1985)
1 /*	hp.c	3.14	09/27/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 
162 		/* determine device type */
163 		hpaddr = mbadev(HPMBA, unit);
164 		hp_type[unit] = hpaddr->hpdt;
165 	}
166 	switch (hp_type[unit]) {
167 
168 	case RM:
169 		sizes = rm_sizes;
170 		nspc = NRMSECT*NRMTRAC;
171 		break;
172 	case RM5:
173 		sizes = rm5_sizes;
174 		nspc = NRMSECT*NTRAC;
175 		break;
176 	case RP:
177 		sizes = hp_sizes;
178 		nspc = NSECT*NTRAC;
179 		break;
180 	default:
181 		printf("hp: unknown device type 0%o\n", hp_type[unit]);
182 		u.u_error = ENXIO;
183 		unit = NHP+1;	/* force error */
184 	}
185 	if (unit >= NHP ||
186 	    bp->b_blkno < 0 ||
187 	    (bn = dkblock(bp))+sz > sizes[xunit&07].nblocks) {
188 		bp->b_flags |= B_ERROR;
189 		iodone(bp);
190 		return;
191 	}
192 	bp->b_cylin = bn/nspc + sizes[xunit&07].cyloff;
193 	dp = &hputab[unit];
194 	(void) spl5();
195 	disksort(dp, bp);
196 	if (dp->b_active == 0) {
197 		hpustart(unit);
198 		if(hptab.b_active == 0)
199 			hpstart();
200 	}
201 	(void) spl0();
202 }
203 
204 hpustart(unit)
205 register unit;
206 {
207 	register struct buf *bp, *dp;
208 	register struct device *hpaddr;
209 	daddr_t bn;
210 	int sn, cn, csn;
211 
212 	((struct mba_regs *)MBA0)->mba_cr |= MBAIE;
213 	hpaddr = mbadev(HPMBA, 0);
214 	hpaddr->hpas = 1<<unit;
215 
216 	if(unit >= NHP)
217 		return;
218 	if (unit+DK_N <= DK_NMAX)
219 		dk_busy &= ~(1<<(unit+DK_N));
220 	dp = &hputab[unit];
221 	if((bp=dp->b_actf) == NULL)
222 		return;
223 	hpaddr = mbadev(HPMBA, unit);
224 	if((hpaddr->hpds & VV) == 0) {
225 		hpaddr->hpcs1 = PRESET|GO;
226 		hpaddr->hpof = FMT22;
227 	}
228 	if(dp->b_active)
229 		goto done;
230 	dp->b_active++;
231 	if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL))
232 		goto done;
233 
234 	bn = dkblock(bp);
235 	cn = bp->b_cylin;
236 	switch (hp_type[unit]) {
237 
238 	case RM:
239 		sn = bn%(NRMSECT*NRMTRAC);
240 		sn = (sn+NRMSECT-hpSDIST)%NRMSECT;
241 		break;
242 	case RM5:
243 		sn = bn%(NRMSECT*NTRAC);
244 		sn = (sn+NRMSECT-hpSDIST)%NRMSECT;
245 		break;
246 	case RP:
247 		sn = bn%(NSECT*NTRAC);
248 		sn = (sn+NSECT-hpSDIST)%NSECT;
249 		break;
250 	default:
251 		panic("hpustart");
252 	}
253 
254 	if(cn - (hpaddr->hpdc & 0xffff))
255 		goto search;
256 	else if (hpseek)
257 		goto done;
258 	csn = ((hpaddr->hpla & 0xffff)>>6) - sn + 1;
259 	if(csn < 0)
260 		csn += NSECT;
261 	if(csn > NSECT-hpRDIST)
262 		goto done;
263 
264 search:
265 	hpaddr->hpdc = cn;
266 	if (hpseek)
267 		hpaddr->hpcs1 = SEEK|GO;
268 	else {
269 		hpaddr->hpda = sn;
270 		hpaddr->hpcs1 = SEARCH|GO;
271 	}
272 	unit += DK_N;
273 	if (unit <= DK_NMAX && DK_N+NHP <= DK_NMAX) {
274 		dk_busy |= 1<<unit;
275 		dk_numb[unit]++;
276 	}
277 	return;
278 
279 done:
280 	dp->b_forw = NULL;
281 	if(hptab.b_actf == NULL)
282 		hptab.b_actf = dp;
283 	else
284 		hptab.b_actl->b_forw = dp;
285 	hptab.b_actl = dp;
286 }
287 
288 hpstart()
289 {
290 	register struct buf *bp, *dp;
291 	register unit;
292 	register struct device *hpaddr;
293 	daddr_t bn;
294 	int dn, sn, tn, cn, nspc, ns;
295 
296 loop:
297 	if ((dp = hptab.b_actf) == NULL)
298 		return;
299 	if ((bp = dp->b_actf) == NULL) {
300 		hptab.b_actf = dp->b_forw;
301 		goto loop;
302 	}
303 	hptab.b_active++;
304 	unit = minor(bp->b_dev) & 077;
305 	dn = dkunit(bp);
306 	bn = dkblock(bp);
307 	switch (hp_type[dn]) {
308 	case RM:
309 		nspc = NRMSECT*NRMTRAC;
310 		ns = NRMSECT;
311 		cn = rm_sizes[unit&07].cyloff;
312 		break;
313 	case RM5:
314 		nspc = NRMSECT*NTRAC;
315 		ns = NRMSECT;
316 		cn = rm5_sizes[unit&07].cyloff;
317 		break;
318 	case RP:
319 		nspc = NSECT*NTRAC;
320 		ns = NSECT;
321 		cn = hp_sizes[unit&07].cyloff;
322 		break;
323 	default:
324 		panic("hpstart");
325 	}
326 	cn += bn/nspc;
327 	sn = bn%nspc;
328 	tn = sn/ns;
329 	sn = sn%ns;
330 
331 	hpaddr = mbadev(HPMBA, dn);
332 	if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL)) {
333 		hptab.b_active = 0;
334 		hptab.b_errcnt = 0;
335 		dp->b_actf = bp->av_forw;
336 		bp->b_flags |= B_ERROR;
337 		iodone(bp);
338 		goto loop;
339 	}
340 	if(hptab.b_errcnt >= 16 && (bp->b_flags&B_WRITE) == 0) {
341 		hpaddr->hpof = hp_offset[hptab.b_errcnt & 017] | FMT22;
342 		HPMBA->mba_cr &= ~MBAIE;
343 		hpaddr->hpcs1 = OFFSET|GO;
344 		while(hpaddr->hpds & PIP)
345 			;
346 		HPMBA->mba_cr |= MBAIE;
347 	}
348 	hpaddr->hpdc = cn;
349 	hpaddr->hpda = (tn << 8) + sn;
350 	mbastart(bp, (int *)hpaddr);
351 
352 	unit = dn+DK_N;
353 	if (NHP+DK_N == DK_NMAX)
354 		unit = NHP+DK_N;
355 	if (unit <= DK_NMAX) {
356 		dk_busy |= 1<<unit;
357 		dk_numb[unit]++;
358 		dk_wds[unit] += bp->b_bcount>>6;
359 	}
360 }
361 
362 hpintr(mbastat, as)
363 {
364 	register struct buf *bp, *dp;
365 	register unit;
366 	register struct device *hpaddr;
367 
368 	if(hptab.b_active) {
369 		dp = hptab.b_actf;
370 		bp = dp->b_actf;
371 		unit = dkunit(bp);
372 		if (DK_N+NHP == DK_NMAX)
373 			dk_busy &= ~(1<<(DK_N+NHP));
374 		else 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 	printf("bcr %d npf %d\n", bcr, npf);
465 	if (bp->b_flags&B_PHYS)
466 		reg = 128 + npf;
467 	else
468 		reg = btop(bp->b_un.b_addr - buffers[0]) + npf;
469 	o = (int)bp->b_un.b_addr & PGOFSET;
470 	printf("%D ", bp->b_blkno + npf);
471 	prdev("ECC", bp->b_dev);
472 	mask = rp->hpec2&0xffff;
473 	if (mask == 0) {
474 		rp->hpof = FMT22;
475 		return (0);
476 	}
477 
478 	/*
479 	 * Compute the byte and bit position of the error.
480 	 * The variable i is the byte offset in the transfer,
481 	 * the variable byte is the offset from a page boundary
482 	 * in main memory.
483 	 */
484 	i = (rp->hpec1&0xffff) - 1;		/* -1 makes 0 origin */
485 	bit = i&07;
486 	i = (i&~07)>>3;
487 	byte = i + o;
488 	/*
489 	 * Correct while possible bits remain of mask.  Since mask
490 	 * contains 11 bits, we continue while the bit offset is > -11.
491 	 * Also watch out for end of this block and the end of the whole
492 	 * transfer.
493 	 */
494 	while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) {
495 		mpte = mbp->mba_map[reg+btop(byte)];
496 		addr = ptob(mpte.pg_pfnum) + (byte & PGOFSET);
497 		putmemc(addr, getmemc(addr)^(mask<<bit));
498 		byte++;
499 		i++;
500 		bit -= 8;
501 	}
502 	hptab.b_active++;		/* Either complete or continuing */
503 	if (bcr == 0)
504 		return (0);
505 	/*
506 	 * Have to continue the transfer... clear the drive,
507 	 * and compute the position where the transfer is to continue.
508 	 * We have completed npf+1 sectores of the transfer already;
509 	 * restart at offset o of next sector (i.e. in MBA register reg+1).
510 	 */
511 	rp->hpcs1 = DCLR|GO;
512 	dn = dkunit(bp);
513 	bn = dkblock(bp);
514 	switch (hp_type[dn]) {
515 
516 	case RM:
517 		ns = NRMSECT; nt = NRMTRAC; break;
518 	case RM5:
519 		ns = NRMSECT; nt = NTRAC; break;
520 	case RP:
521 		ns = NSECT; nt = NTRAC; break;
522 	default:
523 		panic("hpecc");
524 	}
525 	cn = bp->b_cylin;
526 	sn = bn%(ns*nt) + npf + 1;
527 	tn = sn/ns;
528 	sn %= ns;
529 	cn += tn/nt;
530 	tn %= nt;
531 	rp->hpdc = cn;
532 	rp->hpda = (tn<<8) + sn;
533 	mbp->mba_sr = -1;
534 	mbp->mba_var = (int)ptob(reg+1) + o;
535 	rp->hpcs1 = RCOM|GO;
536 	return (1);
537 }
538