xref: /csrg-svn/sys/vax/mba/hp.c (revision 2362)
1 /*	hp.c	4.5	02/07/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 #include "../h/cmap.h"
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	RP	022
44 #define	RM	024
45 #define	RM5	027
46 #define	NSECT	22
47 #define	NTRAC	19
48 #define	NRMSECT	32
49 #define	NRMTRAC	5
50 
51 #define	_hpSDIST	2
52 #define	_hpRDIST	3
53 
54 int	hpSDIST = _hpSDIST;
55 int	hpRDIST = _hpRDIST;
56 int	hpseek;
57 
58 struct	size
59 {
60 	daddr_t	nblocks;
61 	int	cyloff;
62 } hp_sizes[8] =
63 {
64 	15884,	0,		/* A=cyl 0 thru 37 */
65 	33440,	38,		/* B=cyl 38 thru 117 */
66 	340670,	0,		/* C=cyl 0 thru 814 */
67 	0,	0,
68 	0,	0,
69 	0,	0,
70 	291346,	118,		/* G=cyl 118 thru 814 */
71 	0,	0,
72 }, rm_sizes[8] = {
73 	15884,	0,		/* A=cyl 0 thru 99 */
74 	33440,	100,		/* B=cyl 100 thru 309 */
75 	131680,	0,		/* C=cyl 0 thru 822 */
76 	2720,	291,
77 	0,	0,
78 	0,	0,
79 	82080,	310,		/* G=cyl 310 thru 822 */
80 	0,	0,
81 }, rm5_sizes[8] = {
82 	15884,	0,		/* A=cyl 0 thru 26 */
83 	33440,	27,		/* B=cyl 27 thru 81 */
84 	500992,	0,		/* C=cyl 0 thru 823 */
85 	15884,	562,		/* D=cyl 562 thru 588 */
86 	55936,	589,		/* E=cyl 589 thru 680 */
87 	86944,	681,		/* F=cyl 681 thru 823 */
88 	159296,	562,		/* G=cyl 562 thru 823 */
89 	291346,	82,		/* H=cyl 82 thru 561 */
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 	if ((mbaact&(1<<HPMBANUM)) == 0)
150 		mbainit(HPMBANUM);
151 	xunit = minor(bp->b_dev) & 077;
152 	sz = bp->b_bcount;
153 	sz = (sz+511) >> 9;
154 	unit = dkunit(bp);
155 	if (hp_type[unit] == 0) {
156 		struct device *hpaddr;
157 		double mspw;
158 
159 		/* determine device type */
160 		hpaddr = mbadev(HPMBA, unit);
161 
162 		/* record transfer rate (these are guesstimates secs/word) */
163 		switch (hp_type[unit] = hpaddr->hpdt) {
164 		case RM:	mspw = .0000019728; break;
165 		case RM5:	mspw = .0000020345; break;
166 		case RP:	mspw = .0000029592; break;
167 		}
168 		if (HPDK_N + unit <= HPDK_NMAX)
169 			dk_mspw[HPDK_N+unit] = mspw;
170 	}
171 	switch (hp_type[unit]) {
172 
173 	case RM:
174 		sizes = rm_sizes;
175 		nspc = NRMSECT*NRMTRAC;
176 		break;
177 	case RM5:
178 		sizes = rm5_sizes;
179 		nspc = NRMSECT*NTRAC;
180 		break;
181 	case RP:
182 		sizes = hp_sizes;
183 		nspc = NSECT*NTRAC;
184 		break;
185 	default:
186 		printf("hp: unknown device type 0%o\n", hp_type[unit]);
187 		u.u_error = ENXIO;
188 		unit = NHP+1;	/* force error */
189 	}
190 	if (unit >= NHP ||
191 	    bp->b_blkno < 0 ||
192 	    (bn = dkblock(bp))+sz > sizes[xunit&07].nblocks) {
193 		bp->b_flags |= B_ERROR;
194 		iodone(bp);
195 		return;
196 	}
197 	bp->b_cylin = bn/nspc + sizes[xunit&07].cyloff;
198 	dp = &hputab[unit];
199 	(void) spl5();
200 	disksort(dp, bp);
201 	if (dp->b_active == 0) {
202 		hpustart(unit);
203 		if(hptab.b_active == 0)
204 			hpstart();
205 	}
206 	(void) spl0();
207 }
208 
209 hpustart(unit)
210 register unit;
211 {
212 	register struct buf *bp, *dp;
213 	register struct device *hpaddr;
214 	daddr_t bn;
215 	int sn, cn, csn, ns;
216 
217 	((struct mba_regs *)HPMBA)->mba_cr |= MBAIE;
218 	hpaddr = mbadev(HPMBA, 0);
219 	hpaddr->hpas = 1<<unit;
220 
221 	if(unit >= NHP)
222 		return;
223 	if (unit+HPDK_N <= HPDK_NMAX)
224 		dk_busy &= ~(1<<(unit+HPDK_N));
225 	dp = &hputab[unit];
226 	if((bp=dp->b_actf) == NULL)
227 		return;
228 	hpaddr = mbadev(HPMBA, unit);
229 	if((hpaddr->hpds & VV) == 0) {
230 		hpaddr->hpcs1 = DCLR|GO;
231 		hpaddr->hpcs1 = PRESET|GO;
232 		hpaddr->hpof = FMT22;
233 	}
234 	if(dp->b_active)
235 		goto done;
236 	dp->b_active++;
237 	if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL))
238 		goto done;
239 
240 #if NHP > 1
241 	bn = dkblock(bp);
242 	cn = bp->b_cylin;
243 	switch (hp_type[unit]) {
244 
245 	case RM:
246 		sn = bn%(NRMSECT*NRMTRAC);
247 		sn = (sn+NRMSECT-hpSDIST)%NRMSECT;
248 		ns = NRMSECT;
249 		break;
250 	case RM5:
251 		sn = bn%(NRMSECT*NTRAC);
252 		sn = (sn+NRMSECT-hpSDIST)%NRMSECT;
253 		ns = NRMSECT;
254 		break;
255 	case RP:
256 		sn = bn%(NSECT*NTRAC);
257 		sn = (sn+NSECT-hpSDIST)%NSECT;
258 		ns = NSECT;
259 		break;
260 	default:
261 		panic("hpustart");
262 	}
263 
264 	if(cn - (hpaddr->hpdc & 0xffff))
265 		goto search;
266 	else if (hpseek)
267 		goto done;
268 	csn = ((hpaddr->hpla & 0xffff)>>6) - sn + 1;
269 	if(csn < 0)
270 		csn += ns;
271 	if(csn > ns-hpRDIST)
272 		goto done;
273 
274 search:
275 	hpaddr->hpdc = cn;
276 	if (hpseek)
277 		hpaddr->hpcs1 = SEEK|GO;
278 	else {
279 		hpaddr->hpda = sn;
280 		hpaddr->hpcs1 = SEARCH|GO;
281 	}
282 	unit += HPDK_N;
283 	if (unit <= HPDK_NMAX) {
284 		dk_busy |= 1<<unit;
285 		dk_seek[unit]++;
286 	}
287 	return;
288 #endif
289 
290 done:
291 	dp->b_forw = NULL;
292 	if(hptab.b_actf == NULL)
293 		hptab.b_actf = dp;
294 	else
295 		hptab.b_actl->b_forw = dp;
296 	hptab.b_actl = dp;
297 }
298 
299 hpstart()
300 {
301 	register struct buf *bp, *dp;
302 	register unit;
303 	register struct device *hpaddr;
304 	daddr_t bn;
305 	int dn, sn, tn, cn, nspc, ns;
306 
307 loop:
308 	if ((dp = hptab.b_actf) == NULL)
309 		return;
310 	if ((bp = dp->b_actf) == NULL) {
311 		hptab.b_actf = dp->b_forw;
312 		goto loop;
313 	}
314 	hptab.b_active++;
315 	unit = minor(bp->b_dev) & 077;
316 	dn = dkunit(bp);
317 	bn = dkblock(bp);
318 	switch (hp_type[dn]) {
319 	case RM:
320 		nspc = NRMSECT*NRMTRAC;
321 		ns = NRMSECT;
322 		cn = rm_sizes[unit&07].cyloff;
323 		break;
324 	case RM5:
325 		nspc = NRMSECT*NTRAC;
326 		ns = NRMSECT;
327 		cn = rm5_sizes[unit&07].cyloff;
328 		break;
329 	case RP:
330 		nspc = NSECT*NTRAC;
331 		ns = NSECT;
332 		cn = hp_sizes[unit&07].cyloff;
333 		break;
334 	default:
335 		panic("hpstart");
336 	}
337 	cn += bn/nspc;
338 	sn = bn%nspc;
339 	tn = sn/ns;
340 	sn = sn%ns;
341 
342 	hpaddr = mbadev(HPMBA, dn);
343 	if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL)) {
344 		hptab.b_active = 0;
345 		hptab.b_errcnt = 0;
346 		dp->b_actf = bp->av_forw;
347 		bp->b_flags |= B_ERROR;
348 		iodone(bp);
349 		goto loop;
350 	}
351 	if(hptab.b_errcnt >= 16 && (bp->b_flags&B_READ) != 0) {
352 		hpaddr->hpof = hp_offset[hptab.b_errcnt & 017] | FMT22;
353 		HPMBA->mba_cr &= ~MBAIE;
354 		hpaddr->hpcs1 = OFFSET|GO;
355 		while(hpaddr->hpds & PIP)
356 			;
357 		HPMBA->mba_cr |= MBAIE;
358 	}
359 	hpaddr->hpdc = cn;
360 	hpaddr->hpda = (tn << 8) + sn;
361 	mbastart(bp, (int *)hpaddr);
362 
363 	unit = dn+HPDK_N;
364 	if (unit <= HPDK_NMAX) {
365 		dk_busy |= 1<<unit;
366 		dk_xfer[unit]++;
367 		dk_wds[unit] += bp->b_bcount>>6;
368 	}
369 }
370 
371 hpintr(mbastat, as)
372 {
373 	register struct buf *bp, *dp;
374 	register unit;
375 	register struct device *hpaddr;
376 
377 	if(hptab.b_active) {
378 		dp = hptab.b_actf;
379 		bp = dp->b_actf;
380 		unit = dkunit(bp);
381 		if (HPDK_N+unit <= HPDK_NMAX)
382 			dk_busy &= ~(1<<(HPDK_N+unit));
383 		hpaddr = mbadev(HPMBA, unit);
384 		if (hpaddr->hpds & ERR || mbastat & MBAEBITS) {
385 			while((hpaddr->hpds & DRY) == 0)
386 				;
387 			if(++hptab.b_errcnt > 28 || hpaddr->hper1&WLE)
388 				bp->b_flags |= B_ERROR;
389 			else
390 				hptab.b_active = 0;
391 			if(hptab.b_errcnt > 27)
392 				deverror(bp, mbastat, hpaddr->hper1);
393 			if ((hpaddr->hper1&0xffff) == DCK) {
394 				if (hpecc(hpaddr, bp))
395 					return;
396 			}
397 			hpaddr->hpcs1 = DCLR|GO;
398 			if((hptab.b_errcnt&07) == 4) {
399 				HPMBA->mba_cr &= ~MBAIE;
400 				hpaddr->hpcs1 = RECAL|GO;
401 				while(hpaddr->hpds & PIP)
402 					;
403 				HPMBA->mba_cr |= MBAIE;
404 			}
405 		}
406 		if(hptab.b_active) {
407 			if(hptab.b_errcnt) {
408 				HPMBA->mba_cr &= ~MBAIE;
409 				hpaddr->hpcs1 = RTC|GO;
410 				while(hpaddr->hpds & PIP)
411 					;
412 				HPMBA->mba_cr |= MBAIE;
413 			}
414 			hptab.b_active = 0;
415 			hptab.b_errcnt = 0;
416 			hptab.b_actf = dp->b_forw;
417 			dp->b_active = 0;
418 			dp->b_errcnt = 0;
419 			dp->b_actf = bp->av_forw;
420 			bp->b_resid = -HPMBA->mba_bcr & 0xffff;
421 			iodone(bp);
422 			if(dp->b_actf)
423 				hpustart(unit);
424 		}
425 		as &= ~(1<<unit);
426 	} else {
427 		if(as == 0)
428 			HPMBA->mba_cr |= MBAIE;
429 	}
430 	for(unit=0; unit<NHP; unit++)
431 		if(as & (1<<unit))
432 			hpustart(unit);
433 	hpstart();
434 }
435 
436 hpread(dev)
437 {
438 
439 	physio(hpstrategy, &rhpbuf, dev, B_READ, minphys);
440 }
441 
442 hpwrite(dev)
443 {
444 
445 	physio(hpstrategy, &rhpbuf, dev, B_WRITE, minphys);
446 }
447 
448 hpecc(rp, bp)
449 register struct device *rp;
450 register struct buf *bp;
451 {
452 	struct mba_regs *mbp = HPMBA;
453 	register int i;
454 	caddr_t addr;
455 	int reg, bit, byte, npf, mask, o;
456 	int dn, bn, cn, tn, sn, ns, nt;
457 	extern char buffers[NBUF][BSIZE];
458 	struct pte mpte;
459 	int bcr;
460 
461 	/*
462 	 * Npf is the number of sectors transferred before the sector
463 	 * containing the ECC error, and reg is the MBA register
464 	 * mapping (the first part of)the transfer.
465 	 * O is offset within a memory page of the first byte transferred.
466 	 */
467 	bcr = mbp->mba_bcr & 0xffff;
468 	if (bcr)
469 		bcr |= 0xffff0000;		/* sxt */
470 	npf = btop(bcr + bp->b_bcount) - 1;
471 	reg = npf;
472 	o = (int)bp->b_un.b_addr & PGOFSET;
473 	printf("%D ", bp->b_blkno + npf);
474 	prdev("ECC", bp->b_dev);
475 	mask = rp->hpec2&0xffff;
476 	if (mask == 0) {
477 		rp->hpof = FMT22;
478 		return (0);
479 	}
480 
481 	/*
482 	 * Compute the byte and bit position of the error.
483 	 * The variable i is the byte offset in the transfer,
484 	 * the variable byte is the offset from a page boundary
485 	 * in main memory.
486 	 */
487 	i = (rp->hpec1&0xffff) - 1;		/* -1 makes 0 origin */
488 	bit = i&07;
489 	i = (i&~07)>>3;
490 	byte = i + o;
491 	/*
492 	 * Correct while possible bits remain of mask.  Since mask
493 	 * contains 11 bits, we continue while the bit offset is > -11.
494 	 * Also watch out for end of this block and the end of the whole
495 	 * transfer.
496 	 */
497 	while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) {
498 		mpte = mbp->mba_map[reg+btop(byte)];
499 		addr = ptob(mpte.pg_pfnum) + (byte & PGOFSET);
500 		putmemc(addr, getmemc(addr)^(mask<<bit));
501 		byte++;
502 		i++;
503 		bit -= 8;
504 	}
505 	hptab.b_active++;		/* Either complete or continuing */
506 	if (bcr == 0)
507 		return (0);
508 	/*
509 	 * Have to continue the transfer... clear the drive,
510 	 * and compute the position where the transfer is to continue.
511 	 * We have completed npf+1 sectores of the transfer already;
512 	 * restart at offset o of next sector (i.e. in MBA register reg+1).
513 	 */
514 	rp->hpcs1 = DCLR|GO;
515 	dn = dkunit(bp);
516 	bn = dkblock(bp);
517 	switch (hp_type[dn]) {
518 
519 	case RM:
520 		ns = NRMSECT; nt = NRMTRAC; break;
521 	case RM5:
522 		ns = NRMSECT; nt = NTRAC; break;
523 	case RP:
524 		ns = NSECT; nt = NTRAC; break;
525 	default:
526 		panic("hpecc");
527 	}
528 	cn = bp->b_cylin;
529 	sn = bn%(ns*nt) + npf + 1;
530 	tn = sn/ns;
531 	sn %= ns;
532 	cn += tn/nt;
533 	tn %= nt;
534 	rp->hpdc = cn;
535 	rp->hpda = (tn<<8) + sn;
536 	mbp->mba_sr = -1;
537 	mbp->mba_var = (int)ptob(reg+1) + o;
538 	rp->hpcs1 = RCOM|GO;
539 	return (1);
540 }
541 
542 #define	DBSIZE	20
543 
544 hpdump(dev)
545 	dev_t dev;
546 {
547 	struct device *hpaddr;
548 	char *start;
549 	int num, blk, unit, nsect, ntrak, nspc;
550 	struct size *sizes;
551 
552 	num = maxfree;
553 	start = 0;
554 	unit = minor(dev) >> 3;
555 	if (unit >= NHP) {
556 		printf("bad unit\n");
557 		return (-1);
558 	}
559 	HPPHYSMBA->mba_cr = MBAINIT;
560 	hpaddr = mbadev(HPPHYSMBA, unit);
561 	if (hp_type[unit] == 0)
562 		hp_type[unit] = hpaddr->hpdt;
563 	if((hpaddr->hpds & VV) == 0) {
564 		hpaddr->hpcs1 = PRESET|GO;
565 		hpaddr->hpof = FMT22;
566 	}
567 	switch (hp_type[unit]) {
568 	case RM5:
569 		nsect = NRMSECT; ntrak = NTRAC; sizes = rm5_sizes; break;
570 	case RM:
571 		nsect = NRMSECT; ntrak = NRMTRAC; sizes = rm_sizes; break;
572 	case RP:
573 		nsect = NSECT; ntrak = NTRAC; sizes = hp_sizes; break;
574 	default:
575 		printf("hp unknown type %x\n", hp_type[unit]);
576 		return (-1);
577 	}
578 	if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) {
579 		printf("dumplo+num, sizes %d %d\n", dumplo+num, sizes[minor(dev)&07].nblocks);
580 		return (-1);
581 	}
582 	nspc = nsect * ntrak;
583 	while (num > 0) {
584 		register struct pte *hpte = HPPHYSMBA->mba_map;
585 		register int i;
586 		int cn, sn, tn;
587 		daddr_t bn;
588 
589 		blk = num > DBSIZE ? DBSIZE : num;
590 		bn = dumplo + btop(start);
591 		cn = bn/nspc + sizes[minor(dev)&07].cyloff;
592 		sn = bn%nspc;
593 		tn = sn/nsect;
594 		sn = sn%nsect;
595 		hpaddr->hpdc = cn;
596 		hpaddr->hpda = (tn << 8) + sn;
597 		for (i = 0; i < blk; i++)
598 			*(int *)hpte++ = (btop(start)+i) | PG_V;
599 		((struct mba_regs *)HPPHYSMBA)->mba_sr = -1;
600 		((struct mba_regs *)HPPHYSMBA)->mba_bcr = -(blk*NBPG);
601 		((struct mba_regs *)HPPHYSMBA)->mba_var = 0;
602 		hpaddr->hpcs1 = WCOM | GO;
603 		while ((hpaddr->hpds & DRY) == 0)
604 			;
605 		if (hpaddr->hpds&ERR) {
606 			printf("hp dump dsk err: (%d,%d,%d) ds=%X er=%X\n",
607 			    cn, tn, sn, hpaddr->hpds, hpaddr->hper1);
608 			return (-1);
609 		}
610 		start += blk*NBPG;
611 		num -= blk;
612 	}
613 	return (0);
614 }
615 #endif
616