xref: /csrg-svn/sys/vax/mba/hp.c (revision 2604)
1 /*	hp.c	4.10	81/02/21	*/
2 
3 #include "hp.h"
4 #if NHP > 0
5 /*
6  * RP/RM 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 #include "../h/hpreg.h"
24 
25 /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */
26 struct	size {
27 	daddr_t	nblocks;
28 	int	cyloff;
29 } hp_sizes[8] = {
30 	15884,	0,		/* A=cyl 0 thru 37 */
31 	33440,	38,		/* B=cyl 38 thru 117 */
32 	340670,	0,		/* C=cyl 0 thru 814 */
33 	0,	0,
34 	0,	0,
35 	0,	0,
36 	291346,	118,		/* G=cyl 118 thru 814 */
37 	0,	0,
38 }, rm_sizes[8] = {
39 	15884,	0,		/* A=cyl 0 thru 99 */
40 	33440,	100,		/* B=cyl 100 thru 309 */
41 	131680,	0,		/* C=cyl 0 thru 822 */
42 	2720,	291,
43 	0,	0,
44 	0,	0,
45 	82080,	310,		/* G=cyl 310 thru 822 */
46 	0,	0,
47 }, rm5_sizes[8] = {
48 	15884,	0,		/* A=cyl 0 thru 26 */
49 	33440,	27,		/* B=cyl 27 thru 81 */
50 	500992,	0,		/* C=cyl 0 thru 823 */
51 	15884,	562,		/* D=cyl 562 thru 588 */
52 	55936,	589,		/* E=cyl 589 thru 680 */
53 	86944,	681,		/* F=cyl 681 thru 823 */
54 	159296,	562,		/* G=cyl 562 thru 823 */
55 	291346,	82,		/* H=cyl 82 thru 561 */
56 }, rm80_sizes[8] = {
57 	15884,	0,		/* A=cyl 0 thru 36 */
58 	33440,	37,		/* B=cyl 37 thru 114 */
59 	242606,	0,		/* C=cyl 0 thru 558 */
60 	0,	0,
61 	0,	0,
62 	0,	0,
63 	82080,	115,		/* G=cyl 115 thru 304 */
64 	110236,	305,		/* H=cyl 305 thru 558 */
65 };
66 /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */
67 
68 #define	_hpSDIST	2
69 #define	_hpRDIST	3
70 
71 int	hpSDIST = _hpSDIST;
72 int	hpRDIST = _hpRDIST;
73 
74 short	hptypes[] =
75 	{ MBDT_RM03, MBDT_RM05, MBDT_RP06, MBDT_RM80, 0 };
76 struct	mba_info *hpinfo[NHP];
77 int	hpdkinit(),hpustart(),hpstart(),hpdtint();
78 struct	mba_driver hpdriver =
79 	{ hpdkinit, hpustart, hpstart, hpdtint, 0, hptypes, hpinfo };
80 
81 struct hpst {
82 	short	nsect;
83 	short	ntrak;
84 	short	nspc;
85 	short	ncyl;
86 	struct	size *sizes;
87 } hpst[] = {
88 	32,	5,	32*5,	823,	rm_sizes,	/* RM03 */
89 	32,	19,	32*19,	823,	rm5_sizes,	/* RM05 */
90 	22,	19,	22*19,	815,	hp_sizes,	/* RP06 */
91 	31,	14, 	31*14,	559,	rm80_sizes	/* RM80 */
92 };
93 
94 int	hp_offset[16] = {
95 	P400, M400, P400, M400,
96 	P800, M800, P800, M800,
97 	P1200, M1200, P1200, M1200,
98 	0, 0, 0, 0,
99 };
100 
101 struct	buf	rhpbuf;
102 
103 #define	b_cylin b_resid
104 
105 #ifdef INTRLVE
106 daddr_t dkblock();
107 #endif
108 
109 int	hpseek;
110 
111 hpdkinit(mi)
112 	struct mba_info *mi;
113 {
114 	register struct hpst *st = &hpst[mi->mi_type];
115 
116 	if (mi->mi_dk >= 0)
117 		dk_mspw[mi->mi_dk] = 1.0 / HZ / (st->nsect * 256);
118 }
119 
120 hpstrategy(bp)
121 	register struct buf *bp;
122 {
123 	register struct mba_info *mi;
124 	register struct hpst *st;
125 	register int unit;
126 	long sz, bn;
127 	int xunit = minor(bp->b_dev) & 07;
128 
129 	sz = bp->b_bcount;
130 	sz = (sz+511) >> 9;
131 	unit = dkunit(bp);
132 	if (unit >= NHP)
133 		goto bad;
134 	mi = hpinfo[unit];
135 	if (mi == 0 || mi->mi_alive == 0)
136 		goto bad;
137 	st = &hpst[mi->mi_type];
138 	if (bp->b_blkno < 0 ||
139 	    (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks)
140 		goto bad;
141 	bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff;
142 	(void) spl5();
143 	disksort(&mi->mi_tab, bp);
144 	if (mi->mi_tab.b_active == 0)
145 		mbustart(mi);
146 	(void) spl0();
147 	return;
148 
149 bad:
150 	bp->b_flags |= B_ERROR;
151 	iodone(bp);
152 	return;
153 }
154 
155 hpustart(mi)
156 	register struct mba_info *mi;
157 {
158 	register struct device *hpaddr = (struct device *)mi->mi_drv;
159 	register struct buf *bp = mi->mi_tab.b_actf;
160 	register struct hpst *st;
161 	daddr_t bn;
162 	int sn, dist, flags;
163 
164 	if ((hpaddr->hpcs1&DVA) == 0)
165 		return (MBU_BUSY);
166 	if ((hpaddr->hpds & VV) == 0) {
167 		hpaddr->hpcs1 = DCLR|GO;
168 		hpaddr->hpcs1 = PRESET|GO;
169 		hpaddr->hpof = FMT22;
170 	}
171 	if (mi->mi_tab.b_active || mi->mi_hd->mh_ndrive == 1)
172 		return (MBU_DODATA);
173 	if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL))
174 		return (MBU_DODATA);
175 	hpaddr->hpdc = bp->b_cylin;
176 	st = &hpst[mi->mi_type];
177 	bn = dkblock(bp);
178 	sn = bn%st->nspc;
179 	sn = (sn+st->nsect-hpSDIST)%st->nsect;
180 	if (bp->b_cylin == (hpaddr->hpdc & 0xffff)) {
181 		if (hpseek)
182 			return (MBU_DODATA);
183 		dist = ((hpaddr->hpla & 0xffff)>>6) - st->nsect + 1;
184 		if (dist < 0)
185 			dist += st->nsect;
186 		if (dist > st->nsect - hpRDIST)
187 			return (MBU_DODATA);
188 	}
189 	if (hpseek)
190 		hpaddr->hpcs1 = SEEK|GO;
191 	else {
192 		hpaddr->hpda = sn;
193 		hpaddr->hpcs1 = SEARCH|GO;
194 	}
195 	return (MBU_STARTED);
196 }
197 
198 hpstart(mi)
199 	register struct mba_info *mi;
200 {
201 	register struct device *hpaddr = (struct device *)mi->mi_drv;
202 	register struct buf *bp = mi->mi_tab.b_actf;
203 	register struct hpst *st = &hpst[mi->mi_type];
204 	daddr_t bn;
205 	int sn, tn;
206 
207 	bn = dkblock(bp);
208 	sn = bn%st->nspc;
209 	tn = sn/st->nsect;
210 	sn %= st->nsect;
211 	if (mi->mi_tab.b_errcnt >= 16 && (bp->b_flags&B_READ) != 0) {
212 		hpaddr->hpof = hp_offset[mi->mi_tab.b_errcnt & 017] | FMT22;
213 		hpaddr->hpcs1 = OFFSET|GO;
214 		while (hpaddr->hpds & PIP)
215 			;
216 		mbclrattn(mi);
217 	}
218 	hpaddr->hpdc = bp->b_cylin;
219 	hpaddr->hpda = (tn << 8) + sn;
220 }
221 
222 hpdtint(mi, mbastat)
223 	register struct mba_info *mi;
224 	int mbastat;
225 {
226 	register struct device *hpaddr = (struct device *)mi->mi_drv;
227 	register struct buf *bp = mi->mi_tab.b_actf;
228 
229 	while ((hpaddr->hpds & DRY) == 0)	/* shouldn't happen */
230 		printf("hp dry not set\n");
231 	if (hpaddr->hpds & ERR || mbastat & MBAEBITS)
232 		if (++mi->mi_tab.b_errcnt < 28 && (hpaddr->hper1&WLE) == 0) {
233 			if ((hpaddr->hper1&0xffff) != DCK) {
234 				hpaddr->hpcs1 = DCLR|GO;
235 				if ((mi->mi_tab.b_errcnt&07) == 4) {
236 					hpaddr->hpcs1 = RECAL|GO;
237 					while (hpaddr->hpds & PIP)
238 						;
239 					mbclrattn(mi);
240 				}
241 				return (MBD_RETRY);
242 			} else if (hpecc(mi))
243 				return (MBD_RESTARTED);
244 		} else {
245 			deverror(bp, mbastat, hpaddr->hper1);
246 			bp->b_flags |= B_ERROR;
247 		}
248 	bp->b_resid = -(mi->mi_mba->mba_bcr) & 0xffff;
249 	if (mi->mi_tab.b_errcnt) {
250 		hpaddr->hpcs1 = RTC|GO;
251 		while (hpaddr->hpds & PIP)
252 			;
253 		mbclrattn(mi);
254 	}
255 	hpaddr->hpcs1 = RELEASE|GO;
256 	return (MBD_DONE);
257 }
258 
259 hpread(dev)
260 {
261 
262 	physio(hpstrategy, &rhpbuf, dev, B_READ, minphys);
263 }
264 
265 hpwrite(dev)
266 {
267 
268 	physio(hpstrategy, &rhpbuf, dev, B_WRITE, minphys);
269 }
270 
271 hpecc(mi)
272 	register struct mba_info *mi;
273 {
274 	register struct mba_regs *mbp = mi->mi_mba;
275 	register struct device *rp = (struct device *)mi->mi_drv;
276 	register struct buf *bp = mi->mi_tab.b_actf;
277 	register struct hpst *st;
278 	register int i;
279 	caddr_t addr;
280 	int reg, bit, byte, npf, mask, o;
281 	int bn, cn, tn, sn;
282 	struct pte mpte;
283 	int bcr;
284 
285 	/*
286 	 * Npf is the number of sectors transferred before the sector
287 	 * containing the ECC error, and reg is the MBA register
288 	 * mapping (the first part of)the transfer.
289 	 * O is offset within a memory page of the first byte transferred.
290 	 */
291 	bcr = mbp->mba_bcr & 0xffff;
292 	if (bcr)
293 		bcr |= 0xffff0000;		/* sxt */
294 	npf = btop(bcr + bp->b_bcount) - 1;
295 	reg = npf;
296 	o = (int)bp->b_un.b_addr & PGOFSET;
297 	printf("%D ", bp->b_blkno + npf);
298 	prdev("ECC", bp->b_dev);
299 	mask = rp->hpec2&0xffff;
300 	if (mask == 0) {
301 		rp->hpof = FMT22;
302 		return (0);
303 	}
304 
305 	/*
306 	 * Compute the byte and bit position of the error.
307 	 * The variable i is the byte offset in the transfer,
308 	 * the variable byte is the offset from a page boundary
309 	 * in main memory.
310 	 */
311 	i = (rp->hpec1&0xffff) - 1;		/* -1 makes 0 origin */
312 	bit = i&07;
313 	i = (i&~07)>>3;
314 	byte = i + o;
315 	/*
316 	 * Correct while possible bits remain of mask.  Since mask
317 	 * contains 11 bits, we continue while the bit offset is > -11.
318 	 * Also watch out for end of this block and the end of the whole
319 	 * transfer.
320 	 */
321 	while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) {
322 		mpte = mbp->mba_map[reg+btop(byte)];
323 		addr = ptob(mpte.pg_pfnum) + (byte & PGOFSET);
324 		putmemc(addr, getmemc(addr)^(mask<<bit));
325 		byte++;
326 		i++;
327 		bit -= 8;
328 	}
329 	mi->mi_hd->mh_active++;		/* Either complete or continuing */
330 	if (bcr == 0)
331 		return (0);
332 	/*
333 	 * Have to continue the transfer... clear the drive,
334 	 * and compute the position where the transfer is to continue.
335 	 * We have completed npf+1 sectores of the transfer already;
336 	 * restart at offset o of next sector (i.e. in MBA register reg+1).
337 	 */
338 	rp->hpcs1 = DCLR|GO;
339 	bn = dkblock(bp);
340 	st = &hpst[mi->mi_type];
341 	cn = bp->b_cylin;
342 	sn = bn%(st->nspc) + npf + 1;
343 	tn = sn/st->nsect;
344 	sn %= st->nsect;
345 	cn += tn/st->ntrak;
346 	tn %= st->ntrak;
347 	rp->hpdc = cn;
348 	rp->hpda = (tn<<8) + sn;
349 	mbp->mba_sr = -1;
350 	mbp->mba_var = (int)ptob(reg+1) + o;
351 	rp->hpcs1 = RCOM|GO;
352 	return (1);
353 }
354 
355 #define	DBSIZE	20
356 
357 hpdump(dev)
358 	dev_t dev;
359 {
360 	register struct mba_info *mi;
361 	register struct mba_regs *mba;
362 	struct device *hpaddr;
363 	char *start;
364 	int num, unit;
365 	register struct hpst *st;
366 
367 	num = maxfree;
368 	start = 0;
369 	unit = minor(dev) >> 3;
370 	if (unit >= NHP) {
371 		printf("bad unit\n");
372 		return (-1);
373 	}
374 #define	phys(a,b)	((b)((int)(a)&0x7fffffff))
375 	mi = phys(hpinfo[unit],struct mba_info *);
376 	if (mi->mi_alive == 0) {
377 		printf("dna\n");
378 		return (-1);
379 	}
380 	mba = phys(mi->mi_hd, struct mba_hd *)->mh_physmba;
381 	mba->mba_cr = MBAINIT;
382 	hpaddr = (struct device *)&mba->mba_drv[mi->mi_drive];
383 	if ((hpaddr->hpds & VV) == 0) {
384 		hpaddr->hpcs1 = DCLR|GO;
385 		hpaddr->hpcs1 = PRESET|GO;
386 		hpaddr->hpof = FMT22;
387 	}
388 	st = &hpst[mi->mi_type];
389 	if (dumplo < 0 || dumplo + num >= st->sizes[minor(dev)&07].nblocks) {
390 		printf("oor\n");
391 		return (-1);
392 	}
393 	while (num > 0) {
394 		register struct pte *hpte = mba->mba_map;
395 		register int i;
396 		int blk, cn, sn, tn;
397 		daddr_t bn;
398 
399 		blk = num > DBSIZE ? DBSIZE : num;
400 		bn = dumplo + btop(start);
401 		cn = bn/st->nspc + st->sizes[minor(dev)&07].cyloff;
402 		sn = bn%st->nspc;
403 		tn = sn/st->nsect;
404 		sn = sn%st->nsect;
405 		hpaddr->hpdc = cn;
406 		hpaddr->hpda = (tn << 8) + sn;
407 		for (i = 0; i < blk; i++)
408 			*(int *)hpte++ = (btop(start)+i) | PG_V;
409 		mba->mba_sr = -1;
410 		mba->mba_bcr = -(blk*NBPG);
411 		mba->mba_var = 0;
412 		hpaddr->hpcs1 = WCOM | GO;
413 		while ((hpaddr->hpds & DRY) == 0)
414 			;
415 		if (hpaddr->hpds&ERR) {
416 			printf("dskerr: (%d,%d,%d) ds=%x er=%x\n",
417 			    cn, tn, sn, hpaddr->hpds, hpaddr->hper1);
418 			return (-1);
419 		}
420 		start += blk*NBPG;
421 		num -= blk;
422 	}
423 	return (0);
424 }
425 #endif
426