xref: /csrg-svn/sys/vax/mba/hp.c (revision 2298)
1 /*	hp.c	4.4	01/28/81	*/
2 
3 #include "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 (HPDK_N + unit <= HPDK_NMAX)
168 			dk_mspw[HPDK_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, ns;
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+HPDK_N <= HPDK_NMAX)
223 		dk_busy &= ~(1<<(unit+HPDK_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 = DCLR|GO;
230 		hpaddr->hpcs1 = PRESET|GO;
231 		hpaddr->hpof = FMT22;
232 	}
233 	if(dp->b_active)
234 		goto done;
235 	dp->b_active++;
236 	if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL))
237 		goto done;
238 
239 #if NHP > 1
240 	bn = dkblock(bp);
241 	cn = bp->b_cylin;
242 	switch (hp_type[unit]) {
243 
244 	case RM:
245 		sn = bn%(NRMSECT*NRMTRAC);
246 		sn = (sn+NRMSECT-hpSDIST)%NRMSECT;
247 		ns = NRMSECT;
248 		break;
249 	case RM5:
250 		sn = bn%(NRMSECT*NTRAC);
251 		sn = (sn+NRMSECT-hpSDIST)%NRMSECT;
252 		ns = NRMSECT;
253 		break;
254 	case RP:
255 		sn = bn%(NSECT*NTRAC);
256 		sn = (sn+NSECT-hpSDIST)%NSECT;
257 		ns = NSECT;
258 		break;
259 	default:
260 		panic("hpustart");
261 	}
262 
263 	if(cn - (hpaddr->hpdc & 0xffff))
264 		goto search;
265 	else if (hpseek)
266 		goto done;
267 	csn = ((hpaddr->hpla & 0xffff)>>6) - sn + 1;
268 	if(csn < 0)
269 		csn += ns;
270 	if(csn > ns-hpRDIST)
271 		goto done;
272 
273 search:
274 	hpaddr->hpdc = cn;
275 	if (hpseek)
276 		hpaddr->hpcs1 = SEEK|GO;
277 	else {
278 		hpaddr->hpda = sn;
279 		hpaddr->hpcs1 = SEARCH|GO;
280 	}
281 	unit += HPDK_N;
282 	if (unit <= HPDK_NMAX) {
283 		dk_busy |= 1<<unit;
284 		dk_seek[unit]++;
285 	}
286 	return;
287 #endif
288 
289 done:
290 	dp->b_forw = NULL;
291 	if(hptab.b_actf == NULL)
292 		hptab.b_actf = dp;
293 	else
294 		hptab.b_actl->b_forw = dp;
295 	hptab.b_actl = dp;
296 }
297 
298 hpstart()
299 {
300 	register struct buf *bp, *dp;
301 	register unit;
302 	register struct device *hpaddr;
303 	daddr_t bn;
304 	int dn, sn, tn, cn, nspc, ns;
305 
306 loop:
307 	if ((dp = hptab.b_actf) == NULL)
308 		return;
309 	if ((bp = dp->b_actf) == NULL) {
310 		hptab.b_actf = dp->b_forw;
311 		goto loop;
312 	}
313 	hptab.b_active++;
314 	unit = minor(bp->b_dev) & 077;
315 	dn = dkunit(bp);
316 	bn = dkblock(bp);
317 	switch (hp_type[dn]) {
318 	case RM:
319 		nspc = NRMSECT*NRMTRAC;
320 		ns = NRMSECT;
321 		cn = rm_sizes[unit&07].cyloff;
322 		break;
323 	case RM5:
324 		nspc = NRMSECT*NTRAC;
325 		ns = NRMSECT;
326 		cn = rm5_sizes[unit&07].cyloff;
327 		break;
328 	case RP:
329 		nspc = NSECT*NTRAC;
330 		ns = NSECT;
331 		cn = hp_sizes[unit&07].cyloff;
332 		break;
333 	default:
334 		panic("hpstart");
335 	}
336 	cn += bn/nspc;
337 	sn = bn%nspc;
338 	tn = sn/ns;
339 	sn = sn%ns;
340 
341 	hpaddr = mbadev(HPMBA, dn);
342 	if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL)) {
343 		hptab.b_active = 0;
344 		hptab.b_errcnt = 0;
345 		dp->b_actf = bp->av_forw;
346 		bp->b_flags |= B_ERROR;
347 		iodone(bp);
348 		goto loop;
349 	}
350 	if(hptab.b_errcnt >= 16 && (bp->b_flags&B_READ) != 0) {
351 		hpaddr->hpof = hp_offset[hptab.b_errcnt & 017] | FMT22;
352 		HPMBA->mba_cr &= ~MBAIE;
353 		hpaddr->hpcs1 = OFFSET|GO;
354 		while(hpaddr->hpds & PIP)
355 			;
356 		HPMBA->mba_cr |= MBAIE;
357 	}
358 	hpaddr->hpdc = cn;
359 	hpaddr->hpda = (tn << 8) + sn;
360 	mbastart(bp, (int *)hpaddr);
361 
362 	unit = dn+HPDK_N;
363 	if (unit <= HPDK_NMAX) {
364 		dk_busy |= 1<<unit;
365 		dk_xfer[unit]++;
366 		dk_wds[unit] += bp->b_bcount>>6;
367 	}
368 }
369 
370 hpintr(mbastat, as)
371 {
372 	register struct buf *bp, *dp;
373 	register unit;
374 	register struct device *hpaddr;
375 
376 	if(hptab.b_active) {
377 		dp = hptab.b_actf;
378 		bp = dp->b_actf;
379 		unit = dkunit(bp);
380 		if (HPDK_N+unit <= HPDK_NMAX)
381 			dk_busy &= ~(1<<(HPDK_N+unit));
382 		hpaddr = mbadev(HPMBA, unit);
383 		if (hpaddr->hpds & ERR || mbastat & MBAEBITS) {
384 			while((hpaddr->hpds & DRY) == 0)
385 				;
386 			if(++hptab.b_errcnt > 28 || hpaddr->hper1&WLE)
387 				bp->b_flags |= B_ERROR;
388 			else
389 				hptab.b_active = 0;
390 			if(hptab.b_errcnt > 27)
391 				deverror(bp, mbastat, hpaddr->hper1);
392 			if ((hpaddr->hper1&0xffff) == DCK) {
393 				if (hpecc(hpaddr, bp))
394 					return;
395 			}
396 			hpaddr->hpcs1 = DCLR|GO;
397 			if((hptab.b_errcnt&07) == 4) {
398 				HPMBA->mba_cr &= ~MBAIE;
399 				hpaddr->hpcs1 = RECAL|GO;
400 				while(hpaddr->hpds & PIP)
401 					;
402 				HPMBA->mba_cr |= MBAIE;
403 			}
404 		}
405 		if(hptab.b_active) {
406 			if(hptab.b_errcnt) {
407 				HPMBA->mba_cr &= ~MBAIE;
408 				hpaddr->hpcs1 = RTC|GO;
409 				while(hpaddr->hpds & PIP)
410 					;
411 				HPMBA->mba_cr |= MBAIE;
412 			}
413 			hptab.b_active = 0;
414 			hptab.b_errcnt = 0;
415 			hptab.b_actf = dp->b_forw;
416 			dp->b_active = 0;
417 			dp->b_errcnt = 0;
418 			dp->b_actf = bp->av_forw;
419 			bp->b_resid = -HPMBA->mba_bcr & 0xffff;
420 			iodone(bp);
421 			if(dp->b_actf)
422 				hpustart(unit);
423 		}
424 		as &= ~(1<<unit);
425 	} else {
426 		if(as == 0)
427 			HPMBA->mba_cr |= MBAIE;
428 	}
429 	for(unit=0; unit<NHP; unit++)
430 		if(as & (1<<unit))
431 			hpustart(unit);
432 	hpstart();
433 }
434 
435 hpread(dev)
436 {
437 
438 	physio(hpstrategy, &rhpbuf, dev, B_READ, minphys);
439 }
440 
441 hpwrite(dev)
442 {
443 
444 	physio(hpstrategy, &rhpbuf, dev, B_WRITE, minphys);
445 }
446 
447 hpecc(rp, bp)
448 register struct device *rp;
449 register struct buf *bp;
450 {
451 	struct mba_regs *mbp = HPMBA;
452 	register int i;
453 	caddr_t addr;
454 	int reg, bit, byte, npf, mask, o;
455 	int dn, bn, cn, tn, sn, ns, nt;
456 	extern char buffers[NBUF][BSIZE];
457 	struct pte mpte;
458 	int bcr;
459 
460 	/*
461 	 * Npf is the number of sectors transferred before the sector
462 	 * containing the ECC error, and reg is the MBA register
463 	 * mapping (the first part of)the transfer.
464 	 * O is offset within a memory page of the first byte transferred.
465 	 */
466 	bcr = mbp->mba_bcr & 0xffff;
467 	if (bcr)
468 		bcr |= 0xffff0000;		/* sxt */
469 	npf = btop(bcr + bp->b_bcount) - 1;
470 	reg = npf;
471 	o = (int)bp->b_un.b_addr & PGOFSET;
472 	printf("%D ", bp->b_blkno + npf);
473 	prdev("ECC", bp->b_dev);
474 	mask = rp->hpec2&0xffff;
475 	if (mask == 0) {
476 		rp->hpof = FMT22;
477 		return (0);
478 	}
479 
480 	/*
481 	 * Compute the byte and bit position of the error.
482 	 * The variable i is the byte offset in the transfer,
483 	 * the variable byte is the offset from a page boundary
484 	 * in main memory.
485 	 */
486 	i = (rp->hpec1&0xffff) - 1;		/* -1 makes 0 origin */
487 	bit = i&07;
488 	i = (i&~07)>>3;
489 	byte = i + o;
490 	/*
491 	 * Correct while possible bits remain of mask.  Since mask
492 	 * contains 11 bits, we continue while the bit offset is > -11.
493 	 * Also watch out for end of this block and the end of the whole
494 	 * transfer.
495 	 */
496 	while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) {
497 		mpte = mbp->mba_map[reg+btop(byte)];
498 		addr = ptob(mpte.pg_pfnum) + (byte & PGOFSET);
499 		putmemc(addr, getmemc(addr)^(mask<<bit));
500 		byte++;
501 		i++;
502 		bit -= 8;
503 	}
504 	hptab.b_active++;		/* Either complete or continuing */
505 	if (bcr == 0)
506 		return (0);
507 	/*
508 	 * Have to continue the transfer... clear the drive,
509 	 * and compute the position where the transfer is to continue.
510 	 * We have completed npf+1 sectores of the transfer already;
511 	 * restart at offset o of next sector (i.e. in MBA register reg+1).
512 	 */
513 	rp->hpcs1 = DCLR|GO;
514 	dn = dkunit(bp);
515 	bn = dkblock(bp);
516 	switch (hp_type[dn]) {
517 
518 	case RM:
519 		ns = NRMSECT; nt = NRMTRAC; break;
520 	case RM5:
521 		ns = NRMSECT; nt = NTRAC; break;
522 	case RP:
523 		ns = NSECT; nt = NTRAC; break;
524 	default:
525 		panic("hpecc");
526 	}
527 	cn = bp->b_cylin;
528 	sn = bn%(ns*nt) + npf + 1;
529 	tn = sn/ns;
530 	sn %= ns;
531 	cn += tn/nt;
532 	tn %= nt;
533 	rp->hpdc = cn;
534 	rp->hpda = (tn<<8) + sn;
535 	mbp->mba_sr = -1;
536 	mbp->mba_var = (int)ptob(reg+1) + o;
537 	rp->hpcs1 = RCOM|GO;
538 	return (1);
539 }
540 #endif
541