xref: /csrg-svn/sys/vax/mba/hp.c (revision 2383)
1 /*	hp.c	4.7	81/02/08	*/
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 hpstrategy(bp)
110 	register struct buf *bp;
111 {
112 	register struct mba_info *mi;
113 	register struct hpst *st;
114 	register int unit;
115 	long sz, bn;
116 	int xunit = minor(bp->b_dev) & 07;
117 
118 	sz = bp->b_bcount;
119 	sz = (sz+511) >> 9;
120 	unit = dkunit(bp);
121 	if (unit >= NHP)
122 		goto bad;
123 	mi = hpinfo[unit];
124 	if (mi->mi_alive == 0)
125 		goto bad;
126 	st = &hpst[mi->mi_type];
127 	if (bp->b_blkno < 0 ||
128 	    (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks)
129 		goto bad;
130 	bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff;
131 	(void) spl5();
132 	disksort(&mi->mi_tab, bp);
133 	if (mi->mi_tab.b_active == 0)
134 		mbustart(mi);
135 	(void) spl0();
136 	return;
137 
138 bad:
139 	bp->b_flags |= B_ERROR;
140 	iodone(bp);
141 	return;
142 }
143 
144 hpustart(mi)
145 	register struct mba_info *mi;
146 {
147 	register struct device *hpaddr = (struct device *)mi->mi_drv;
148 	register struct buf *bp = mi->mi_tab.b_actf;
149 	register struct hpst *st;
150 	daddr_t bn;
151 	int sn, dist, flags;
152 
153 	if ((hpaddr->hpcs1&DVA) == 0)
154 		return (MBU_BUSY);
155 	if ((hpaddr->hpds & VV) == 0) {
156 		hpaddr->hpcs1 = DCLR|GO;
157 		hpaddr->hpcs1 = PRESET|GO;
158 		hpaddr->hpof = FMT22;
159 	}
160 	if (mi->mi_tab.b_active)
161 		return (MBU_DODATA);
162 	if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL))
163 		return (MBU_DODATA);
164 	hpaddr->hpdc = bp->b_cylin;
165 	flags = mi->mi_hd->mh_flags;
166 	if (flags&MH_NOSEEK)
167 		return (MBU_DODATA);
168 	if (bp->b_cylin == (hpaddr->hpdc & 0xffff)) {
169 		if (flags&MH_NOSEARCH)
170 			return (MBU_DODATA);
171 		bn = dkblock(bp);
172 		st = &hpst[mi->mi_type];
173 		sn = bn%st->nspc;
174 		sn = (sn+st->nsect-hpSDIST)%st->nsect;
175 		dist = ((hpaddr->hpla & 0xffff)>>6) - st->nsect + 1;
176 		if (dist < 0)
177 			dist += st->nsect;
178 		if (dist > st->nsect - hpRDIST)
179 			return (MBU_DODATA);
180 	}
181 	if (flags&MH_NOSEARCH)
182 		hpaddr->hpcs1 = SEEK|GO;
183 	else {
184 		hpaddr->hpda = sn;
185 		hpaddr->hpcs1 = SEARCH|GO;
186 	}
187 	return (MBU_STARTED);
188 }
189 
190 hpstart(mi)
191 	register struct mba_info *mi;
192 {
193 	register struct device *hpaddr = (struct device *)mi->mi_drv;
194 	register struct buf *bp = mi->mi_tab.b_actf;
195 	register struct hpst *st = &hpst[mi->mi_type];
196 	daddr_t bn;
197 	int sn, tn;
198 
199 	bn = dkblock(bp);
200 	sn = bn%st->nspc;
201 	tn = sn/st->nsect;
202 	sn = sn%st->nsect;
203 	if (mi->mi_tab.b_errcnt >= 16 && (bp->b_flags&B_READ) != 0) {
204 		hpaddr->hpof = hp_offset[mi->mi_tab.b_errcnt & 017] | FMT22;
205 		hpaddr->hpcs1 = OFFSET|GO;
206 		while (hpaddr->hpds & PIP)
207 			;
208 		mbclrattn(mi);
209 	}
210 	hpaddr->hpdc = bp->b_cylin;
211 	hpaddr->hpda = (tn << 8) + sn;
212 }
213 
214 hpdtint(mi, mbastat)
215 	register struct mba_info *mi;
216 	int mbastat;
217 {
218 	register struct device *hpaddr = (struct device *)mi->mi_drv;
219 	register struct buf *bp = mi->mi_tab.b_actf;
220 
221 	while ((hpaddr->hpds & DRY) == 0)	/* shouldn't happen */
222 		printf("hp dry not set\n");
223 	if (hpaddr->hpds & ERR || mbastat & MBAEBITS)
224 		if (++mi->mi_tab.b_errcnt < 28 && (hpaddr->hper1&WLE) == 0) {
225 			if ((hpaddr->hper1&0xffff) != DCK) {
226 				hpaddr->hpcs1 = DCLR|GO;
227 				if ((mi->mi_tab.b_errcnt&07) == 4) {
228 					hpaddr->hpcs1 = RECAL|GO;
229 					while (hpaddr->hpds & PIP)
230 						;
231 					mbclrattn(mi);
232 				}
233 				return (MBD_RETRY);
234 			} else if (hpecc(mi))
235 				return (MBD_RESTARTED);
236 		} else {
237 			deverror(bp, mbastat, hpaddr->hper1);
238 			bp->b_flags |= B_ERROR;
239 		}
240 	bp->b_resid = -(mi->mi_mba->mba_bcr) & 0xffff;
241 	if (mi->mi_tab.b_errcnt) {
242 		hpaddr->hpcs1 = RTC|GO;
243 		while (hpaddr->hpds & PIP)
244 			;
245 		mbclrattn(mi);
246 	}
247 	hpaddr->hpcs1 = RELEASE|GO;
248 	return (MBD_DONE);
249 }
250 
251 hpread(dev)
252 {
253 
254 	physio(hpstrategy, &rhpbuf, dev, B_READ, minphys);
255 }
256 
257 hpwrite(dev)
258 {
259 
260 	physio(hpstrategy, &rhpbuf, dev, B_WRITE, minphys);
261 }
262 
263 hpecc(mi)
264 	register struct mba_info *mi;
265 {
266 	register struct mba_regs *mbp = mi->mi_mba;
267 	register struct device *rp = (struct device *)mi->mi_drv;
268 	register struct buf *bp = mi->mi_tab.b_actf;
269 	register struct hpst *st;
270 	register int i;
271 	caddr_t addr;
272 	int reg, bit, byte, npf, mask, o;
273 	int bn, cn, tn, sn;
274 	struct pte mpte;
275 	int bcr;
276 
277 	/*
278 	 * Npf is the number of sectors transferred before the sector
279 	 * containing the ECC error, and reg is the MBA register
280 	 * mapping (the first part of)the transfer.
281 	 * O is offset within a memory page of the first byte transferred.
282 	 */
283 	bcr = mbp->mba_bcr & 0xffff;
284 	if (bcr)
285 		bcr |= 0xffff0000;		/* sxt */
286 	npf = btop(bcr + bp->b_bcount) - 1;
287 	reg = npf;
288 	o = (int)bp->b_un.b_addr & PGOFSET;
289 	printf("%D ", bp->b_blkno + npf);
290 	prdev("ECC", bp->b_dev);
291 	mask = rp->hpec2&0xffff;
292 	if (mask == 0) {
293 		rp->hpof = FMT22;
294 		return (0);
295 	}
296 
297 	/*
298 	 * Compute the byte and bit position of the error.
299 	 * The variable i is the byte offset in the transfer,
300 	 * the variable byte is the offset from a page boundary
301 	 * in main memory.
302 	 */
303 	i = (rp->hpec1&0xffff) - 1;		/* -1 makes 0 origin */
304 	bit = i&07;
305 	i = (i&~07)>>3;
306 	byte = i + o;
307 	/*
308 	 * Correct while possible bits remain of mask.  Since mask
309 	 * contains 11 bits, we continue while the bit offset is > -11.
310 	 * Also watch out for end of this block and the end of the whole
311 	 * transfer.
312 	 */
313 	while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) {
314 		mpte = mbp->mba_map[reg+btop(byte)];
315 		addr = ptob(mpte.pg_pfnum) + (byte & PGOFSET);
316 		putmemc(addr, getmemc(addr)^(mask<<bit));
317 		byte++;
318 		i++;
319 		bit -= 8;
320 	}
321 	mi->mi_hd->mh_active++;		/* Either complete or continuing */
322 	if (bcr == 0)
323 		return (0);
324 	/*
325 	 * Have to continue the transfer... clear the drive,
326 	 * and compute the position where the transfer is to continue.
327 	 * We have completed npf+1 sectores of the transfer already;
328 	 * restart at offset o of next sector (i.e. in MBA register reg+1).
329 	 */
330 	rp->hpcs1 = DCLR|GO;
331 	bn = dkblock(bp);
332 	st = &hpst[mi->mi_type];
333 	cn = bp->b_cylin;
334 	sn = bn%(st->nspc) + npf + 1;
335 	tn = sn/st->nsect;
336 	sn %= st->nsect;
337 	cn += tn/st->ntrak;
338 	tn %= st->ntrak;
339 	rp->hpdc = cn;
340 	rp->hpda = (tn<<8) + sn;
341 	mbp->mba_sr = -1;
342 	mbp->mba_var = (int)ptob(reg+1) + o;
343 	rp->hpcs1 = RCOM|GO;
344 	return (1);
345 }
346 
347 #define	DBSIZE	20
348 
349 hpdump(dev)
350 	dev_t dev;
351 {
352 	register struct mba_info *mi;
353 	register struct mba_regs *mba;
354 	struct device *hpaddr;
355 	char *start;
356 	int num, unit;
357 	register struct hpst *st;
358 
359 	num = maxfree;
360 	start = 0;
361 	unit = minor(dev) >> 3;
362 	if (unit >= NHP) {
363 		printf("bad unit\n");
364 		return (-1);
365 	}
366 #define	phys(a,b)	((b)((int)(a)&0x7fffffff))
367 	mi = phys(hpinfo[unit],struct mba_info *);
368 	if (mi->mi_alive == 0) {
369 		printf("dna\n");
370 		return (-1);
371 	}
372 	mba = phys(mi->mi_hd, struct mba_hd *)->mh_physmba;
373 	mba->mba_cr = MBAINIT;
374 	hpaddr = (struct device *)&mba->mba_drv[mi->mi_drive];
375 	if ((hpaddr->hpds & VV) == 0) {
376 		hpaddr->hpcs1 = DCLR|GO;
377 		hpaddr->hpcs1 = PRESET|GO;
378 		hpaddr->hpof = FMT22;
379 	}
380 	st = &hpst[mi->mi_type];
381 	if (dumplo < 0 || dumplo + num >= st->sizes[minor(dev)&07].nblocks) {
382 		printf("oor\n");
383 		return (-1);
384 	}
385 	while (num > 0) {
386 		register struct pte *hpte = mba->mba_map;
387 		register int i;
388 		int blk, cn, sn, tn;
389 		daddr_t bn;
390 
391 		blk = num > DBSIZE ? DBSIZE : num;
392 		bn = dumplo + btop(start);
393 		cn = bn/st->nspc + st->sizes[minor(dev)&07].cyloff;
394 		sn = bn%st->nspc;
395 		tn = sn/st->nsect;
396 		sn = sn%st->nsect;
397 		hpaddr->hpdc = cn;
398 		hpaddr->hpda = (tn << 8) + sn;
399 		for (i = 0; i < blk; i++)
400 			*(int *)hpte++ = (btop(start)+i) | PG_V;
401 		mba->mba_sr = -1;
402 		mba->mba_bcr = -(blk*NBPG);
403 		mba->mba_var = 0;
404 		hpaddr->hpcs1 = WCOM | GO;
405 		while ((hpaddr->hpds & DRY) == 0)
406 			;
407 		if (hpaddr->hpds&ERR) {
408 			printf("dskerr: (%d,%d,%d) ds=%x er=%x\n",
409 			    cn, tn, sn, hpaddr->hpds, hpaddr->hper1);
410 			return (-1);
411 		}
412 		start += blk*NBPG;
413 		num -= blk;
414 	}
415 	return (0);
416 }
417 
418 hpdkinit()
419 {
420 	/* I don't really care what this does .. kre */
421 }
422 #endif
423