xref: /csrg-svn/sys/vax/stand/hp.c (revision 11115)
1 /*	hp.c	4.14	83/02/17	*/
2 
3 /*
4  * RP??/RM?? disk driver
5  * with ECC handling and bad block forwarding.
6  * Also supports header io operations and
7  * commands to write check header and data.
8  */
9 
10 #include "../h/param.h"
11 #include "../h/inode.h"
12 #include "../h/fs.h"
13 #include "../h/dkbad.h"
14 
15 #include "../vax/pte.h"
16 #include "../vaxmba/hpreg.h"
17 #include "../vaxmba/mbareg.h"
18 
19 #include "saio.h"
20 #include "savax.h"
21 
22 #define	MASKREG(reg)	((reg)&0xffff)
23 
24 #define MAXBADDESC	126
25 #define SECTSIZ 	512	/* sector size in bytes */
26 #define HDRSIZ		4	/* number of bytes in sector header */
27 #define MAXECC		5	/* the maximum number of bad bits accepted in
28 				 * an ecc error when F_ECCLM is set */
29 
30 char	hp_type[MAXNMBA*8] = { 0 };
31 
32 /* THIS SHOULD BE READ IN OFF THE PACK, PER DRIVE */
33 short	hp6_off[8] =	{ 0, 38, 0, -1, -1, -1, 118, -1 };
34 short	rm3_off[8] =	{ 0, 100, 0, -1, -1, -1, 310, -1 };
35 short	rm5_off[8] =	{ 0, 27, 0, 562, 589, 681, 562, 82 };
36 short	rm80_off[8] =	{ 0, 37, 0, -1, -1, -1, 115, 305 };
37 short	hp7_off[8] = 	{ 0, 10, 0, 330, 340, 500, 330, 50 };
38 short	ml_off[8] =	{ 0, -1, -1, -1, -1, -1, -1, -1 };
39 short	si9775_off[8] =	{ 0, 13, 0, -1, -1, -1, 40, 441 };
40 short	si9730_off[8] = { 0, 50, 0, -1, -1, -1, -1, 155 };
41 short	hpam_off[8] =	{ 0, 32, 0, 668, 723, 778, 668, 98 };
42 short	hpfj_off[8] =	{ 0, 19, 0, -1, -1, -1, 398, 59 };
43 /* END SHOULD BE READ IN */
44 
45 short	hptypes[] = {
46 	MBDT_RM03,	MBDT_RM05,	MBDT_RP06,	MBDT_RM80,
47 	MBDT_RP05,	MBDT_RP07,	MBDT_ML11A,	MBDT_ML11B,
48 	-1 /*9755*/,	-1 /*9730*/,	-1 /*Cap*/,	-1 /* Eagle */,
49 	-1 /* Eagle */,	MBDT_RM02,	0
50 };
51 
52 #define RP06 (hptypes[hp_type[unit]] <= MBDT_RP06)
53 #define ML11 (hptypes[hp_type[unit]] == MBDT_ML11A)
54 #define RM80 (hptypes[hp_type[unit]] == MBDT_RM80)
55 
56 u_char	hp_offset[16] = {
57     HPOF_P400, HPOF_M400, HPOF_P400, HPOF_M400,
58     HPOF_P800, HPOF_M800, HPOF_P800, HPOF_M800,
59     HPOF_P1200, HPOF_M1200, HPOF_P1200, HPOF_M1200,
60     0, 0, 0, 0,
61 };
62 
63 struct st hpst[] = {
64 	32,	5,	32*5,	823,	rm3_off,	/* RM03 */
65 	32,	19,	32*19,	823,	rm5_off,	/* RM05 */
66 	22,	19,	22*19,	815,	hp6_off,	/* RP06 */
67 	31,	14, 	31*14,	559,	rm80_off,	/* RM80 */
68 	22,	19,	22*19,	411,	hp6_off,	/* RP06 */
69 	50,	32,	50*32,	630,	hp7_off,	/* RP07 */
70 	1,	1,	1,	1,	ml_off,		/* ML11A */
71 	1,	1,	1,	1,	ml_off,		/* ML11B */
72 	32,	40,	32*40,	843,	si9775_off,	/* 9775 */
73 	32,	10,	32*10,	823,	si9730_off,	/* 9730 */
74 	32,	16,	32*16,	1024,	hpam_off,	/* capricorn */
75 	43,	20,	43*20,	842,	hpfj_off,	/* Eagle */
76 	48,	20,	48*20,	842,	hpfj_off,	/* modif. eagle */
77 	1,	1,	1,	1,	0,		/* rm02 - not used */
78 };
79 
80 struct dkbad hpbad[MAXNMBA*8];
81 int sectsiz;
82 
83 /*
84  * When awaiting command completion, don't
85  * hang on to the status register since
86  * this ties up the controller.
87  */
88 #define	HPWAIT(addr)	while ((((addr)->hpds)&HPDS_DRY)==0) DELAY(500);
89 
90 hpopen(io)
91 	register struct iob *io;
92 {
93 	register unit = io->i_unit;
94 	struct hpdevice *hpaddr = (struct hpdevice *)mbadrv(unit);
95 	register struct st *st;
96 
97 	mbainit(UNITTOMBA(unit));
98 	if (hp_type[unit] == 0) {
99 		register type = hpaddr->hpdt & MBDT_TYPE;
100 		register int i;
101 		struct iob tio;
102 
103 		for (i = 0; hptypes[i]; i++)
104 			if (hptypes[i] == type)
105 				goto found;
106 		_stop("unknown drive type");
107 found:
108 		hpaddr->hpcs1 = HP_DCLR|HP_GO;		/* init drive */
109 		hpaddr->hpcs1 = HP_PRESET|HP_GO;
110 		if (!ML11)
111 			hpaddr->hpof = HPOF_FMT22;
112 		hp_type[unit] = hpmaptype(hpaddr, i, unit);
113 		/*
114 		 * Read in the bad sector table:
115 		 *	copy the contents of the io structure
116 		 *	to tio for use during the bb pointer
117 		 *	read operation.
118 		 */
119 		st = &hpst[i];
120 		tio = *io;
121 		tio.i_bn = st->nspc * st->ncyl - st->nsect;
122 		tio.i_ma = (char *)&hpbad[unit];
123 		tio.i_cc = sizeof (struct dkbad);
124 		tio.i_flgs |= F_RDDATA;
125 		for (i = 0; i < 5; i++) {
126 			if (hpstrategy(&tio, READ) == sizeof (struct dkbad))
127 				break;
128 			tio.i_bn += 2;
129 		}
130 		if (i == 5) {
131 			printf("Unable to read bad sector table\n");
132 			for (i = 0; i < MAXBADDESC; i++) {
133 				hpbad[unit].bt_bad[i].bt_cyl = -1;
134 				hpbad[unit].bt_bad[i].bt_trksec = -1;
135 			}
136 		}
137 	}
138 	if (io->i_boff < 0 || io->i_boff > 7 ||
139 	    st->off[io->i_boff]== -1)
140 		_stop("hp bad minor");
141 	io->i_boff = st->off[io->i_boff] * st->nspc;
142 }
143 
144 hpmaptype(hpaddr, type, unit)
145 	register struct hpdevice *hpaddr;
146 	unsigned type;
147 	int unit;
148 {
149 	int ntracks, hpsn;
150 
151 	/*
152 	 * Handle SI model byte stuff when
153 	 * we think it's an RM03 or RM05.
154 	 */
155 	if (type == 0 || type == 1) {
156 		hpsn = hpaddr->hpsn;
157 		if ((hpsn & SIMB_LU) != unit)
158 			return (type);
159 		switch ((hpsn & SIMB_MB) &~ (SIMB_S6|SIRM03|SIRM05)) {
160 		case SI9775D:
161 			return (8);
162 		case SI9730D:
163 			return (9);
164 		case SI9766:
165 			hpaddr->hpcs1 = HP_RECAL|HP_GO;
166 			DELAY(100000);
167 			return (1);
168 
169 		case SI9762:
170 			return (0);
171 		}
172 		return (type);
173 	}
174 	/*
175 	 * RM03: EMULEX controller.  Map to correct
176 	 * drive type by checking the holding
177 	 * register for the disk geometry.
178 	 */
179 	if (type == 13) {
180 		hpaddr->hpcs1 = HP_NOP;
181 		hpaddr->hphr = HPHR_MAXTRAK;
182 		ntracks = MASKREG(hpaddr->hphr) + 1;
183 		if (ntracks == 16)
184 			return (10);	/* AMPEX capricorn */
185 		hpaddr->hphr = HPHR_MAXSECT;
186 		ntracks = MASKREG(hpaddr->hphr) + 1;
187 		if (ntracks == 48)
188 			return (12);	/* 48 sector Eagle */
189 		if (ntracks == 43)
190 			return (11);	/* 43 sector Eagle */
191 		printf("RM02 with %d sectors/track?\n", ntracks);
192 		return (type);
193 	}
194 	/*
195 	 * ML11's all map to the same type.
196 	 */
197 	if (type == 6 || type == 7)
198 		return (6);
199 	return (type);
200 }
201 
202 int	ssect;		/* set to 1 if we are on a track with skip sectors */
203 
204 hpstrategy(io, func)
205 	register struct iob *io;
206 {
207 	register unit = io->i_unit;
208 	struct mba_regs *mba = mbamba(unit);
209 	daddr_t bn;
210 	struct hpdevice *hpaddr = (struct hpdevice *)mbadrv(unit);
211 	struct st *st = &hpst[hp_type[unit]];
212 	int cn, tn, sn, bytecnt, bytesleft;
213 	daddr_t startblock;
214 	char *membase;
215 	int er1, er2, hprecal;
216 
217 	sectsiz = SECTSIZ;
218 	if ((io->i_flgs & (F_HDR|F_HCHECK)) != 0)
219 		sectsiz += HDRSIZ;
220 	if ((hpaddr->hpds & HPDS_VV) == 0) {
221 		hpaddr->hpcs1 = HP_DCLR|HP_GO;
222 		hpaddr->hpcs1 = HP_PRESET|HP_GO;
223 		if (!ML11)
224 			hpaddr->hpof = HPOF_FMT22;
225 	}
226 	io->i_errcnt = 0;
227 	ssect = 0;
228 	bytecnt = io->i_cc;
229 	membase = io->i_ma;
230 	startblock = io->i_bn;
231 	hprecal = 0;
232 restart:
233 	bn = io->i_bn;
234 	cn = bn/st->nspc;
235 	sn = bn%st->nspc;
236 	tn = sn/st->nsect;
237 	sn = sn%st->nsect + ssect;
238 
239 	HPWAIT(hpaddr);
240 	mba->mba_sr = -1;
241 	if (ML11)
242 		hpaddr->hpda = bn;
243 	else {
244 		hpaddr->hpdc = cn;
245 		hpaddr->hpda = (tn << 8) + sn;
246 	}
247 	if (mbastart(io, func) != 0)		/* start transfer */
248 		return (-1);
249 	HPWAIT(hpaddr);
250 	if ((hpaddr->hpds&HPDS_ERR) == 0 && (mba->mba_sr&MBSR_EBITS) == 0)
251 		return (bytecnt);
252 
253 	/* ------- error handling ------- */
254 
255 	if (bytesleft = MASKREG(mba->mba_bcr>>16))
256 		bytesleft |= 0xffff0000;	/* sign ext */
257 	bn = io->i_bn + (io->i_cc + bytesleft)/sectsiz;
258 	cn = bn/st->nspc;
259 	sn = bn%st->nspc;
260 	tn = sn/st->nsect;
261 	sn = sn%st->nsect;
262 	er1 = MASKREG(hpaddr->hper1);
263 	er2 = MASKREG(hpaddr->hper2);
264 #ifdef HPDEBUG
265 	printf("hp error: (cyl,trk,sec)=(%d,%d,%d) ds=%b \n",
266 		cn, tn, sn, MASKREG(hpaddr->hpds), HPDS_BITS);
267 	printf("er1=%b er2=%b", er1, HPER1_BITS, er2, HPER2_BITS);
268 	printf("\nbytes left: %d, of 0x%x, da 0x%x",-bytesleft,
269 	hpaddr->hpof, hpaddr->hpda);
270 	printf("\n");
271 #endif
272 	if (er1 & HPER1_HCRC) {
273 		er1 &= ~(HPER1_HCE|HPER1_FER);
274 		er2 &= ~HPER2_BSE;
275 	}
276 	if (er1&HPER1_WLE) {
277 		printf("hp%d: write locked\n", unit);
278 		return (-1);
279 	}
280 	if (MASKREG(er1) == HPER1_FER && RP06)
281 		goto badsect;
282 	if (++io->i_errcnt > 27 || (er1 & HPER1_HARD) ||
283 	    (!ML11 && (er2 & HPER2_HARD))) {
284 hard0:
285 		io->i_error = EHER;
286 		if (mba->mba_sr & (MBSR_WCKUP|MBSR_WCKLWR))
287 			io->i_error = EWCK;
288 hard:
289 		io->i_errblk = bn + ssect;
290 		printf("hp error: (cyl,trk,sec)=(%d,%d,%d) ds=%b \n",
291 			   cn, tn, sn, MASKREG(hpaddr->hpds), HPDS_BITS);
292 		printf("er1=%b er2=%b", er1, HPER1_BITS, er2, HPER2_BITS);
293 		if (hpaddr->hpmr)
294 			printf(" mr1=%o", MASKREG(hpaddr->hpmr));
295 		if (hpaddr->hpmr2)
296 			printf(" mr2=%o", MASKREG(hpaddr->hpmr2));
297 #ifdef HPDEBUG
298 		printf("dc: %d, da: 0x%x",MASKREG(hpaddr->hpdc),
299 		  MASKREG(hpaddr->hpda));
300 #endif
301 		hpaddr->hpcs1 = HP_DCLR|HP_GO;
302 		printf("\n");
303 		return (-1);
304 
305 	}
306 	if ((er2 & HPER2_BSE) && !ML11) {
307 badsect:
308 		if (!ssect && (er2&HPER2_SSE))
309 			goto skipsect;
310 		if (io->i_flgs & F_NBSF) {
311 			io->i_error = EBSE;
312 			goto hard;
313 		}
314 		if (hpecc(io, BSE) == 0)
315 			goto success;
316 		io->i_error = EBSE;
317 		goto hard;
318 	}
319 	if (RM80 && er2&HPER2_SSE) {
320 skipsect:
321 		(void) hpecc(io, SSE);
322 		ssect = 1;
323 		goto success;
324 	}
325 	if ((er1 & (HPER1_DCK|HPER1_ECH)) == HPER1_DCK) {
326 		if (hpecc(io, ECC) == 0)
327 			goto success;
328 		io->i_error = EECC;
329 		return (-1);
330 	}
331 	if (ML11 && (io->i_errcnt >= 16))
332 		goto hard0;
333 	/* fall thru to retry */
334 	hpaddr->hpcs1 = HP_DCLR|HP_GO;
335 	HPWAIT(hpaddr);
336 	if (((io->i_errcnt&07) == 4) ) {
337 		hpaddr->hpcs1 = HP_RECAL|HP_GO;
338 		hprecal = 1;
339 		goto again;
340 	}
341 	switch (hprecal) {
342 
343 	case 1:
344 		hpaddr->hpdc = cn;
345 		hpaddr->hpcs1 = HP_SEEK|HP_GO;
346 		hprecal = 2;
347 		goto again;
348 
349 	case 2:
350 		if (io->i_errcnt < 16 || (io->i_flgs & F_READ) == 0)
351 			goto donerecal;
352 		hpaddr->hpof = hp_offset[io->i_errcnt & 017]|HPOF_FMT22;
353 		hpaddr->hpcs1 = HP_OFFSET|HP_GO;
354 		hprecal = 3;
355 		goto again;
356 
357 	case 3:
358 	donerecal:
359 		hprecal = 0;
360 		goto again;
361 	}
362 	if (io->i_errcnt >= 16) {
363 		hpaddr->hpcs1 = HP_RTC|HP_GO;
364 		while (hpaddr->hpds & HPDS_PIP)
365 			;
366 	}
367 	goto again;
368 
369 success:		 		/* continue with the next block */
370 	bn++;
371 	if ((bn-startblock) * sectsiz < bytecnt) {
372 again:					/* re-read same block */
373 		io->i_bn = bn;
374 		io->i_ma = membase + (io->i_bn - startblock)*sectsiz;
375 		io->i_cc = bytecnt - (io->i_bn - startblock)*sectsiz;
376 #ifdef HPDEBUG
377 		printf("restart: bl %d, byte %d, mem 0x%x hprecal %d\n",
378 			io->i_bn, io->i_cc, io->i_ma, hprecal);
379 #endif
380 		goto restart;
381 	}
382 	return (bytecnt);
383 }
384 
385 hpecc(io, flag)
386 	register struct iob *io;
387 	int flag;
388 {
389 	register unit = io->i_unit;
390 	register struct mba_regs *mbp = mbamba(unit);
391 	register struct hpdevice *rp = (struct hpdevice *)mbadrv(unit);
392 	register struct st *st = &hpst[hp_type[unit]];
393 	int npf, bn, cn, tn, sn, bcr;
394 
395 	if (bcr = MASKREG(mbp->mba_bcr>>16))
396 		bcr |= 0xffff0000;		/* sxt */
397 	npf = (bcr + io->i_cc) / sectsiz;	/* # sectors read */
398 	bn = io->i_bn + npf + ssect;		/* physical block #*/
399 	switch (flag) {
400 
401 	case ECC: {
402 		register int i;
403 		caddr_t addr;
404 		int bit, byte, mask, ecccnt = 0;
405 
406 		printf("hp%d: soft ecc sn%d\n", unit, bn);
407 		mask = MASKREG(rp->hpec2);
408 		i = MASKREG(rp->hpec1) - 1;	/* -1 makes 0 origin */
409 		bit = i&07;
410 		i = (i&~07)>>3;
411 		byte = i;
412 		rp->hpcs1 = HP_DCLR | HP_GO;
413 		while (i <sectsiz && npf*sectsiz + i < io->i_cc && bit > -11) {
414 			addr = io->i_ma + (npf*sectsiz) + byte;
415 #ifdef HPECCDEBUG
416 			printf("addr %x old:%x ",addr, (*addr&0xff));
417 #endif
418 			if ((io->i_flgs & (F_CHECK|F_HCHECK)) == 0)
419 				*addr ^= (mask << bit);	/* don't 'correct' mem-
420 							 * ory during Wcheck */
421 #ifdef HPECCDEBUG
422 			printf("new:%x\n",(*addr&0xff));
423 #endif
424 			byte++;
425 			i++;
426 			bit -= 8;
427 			if ((io->i_flgs & F_ECCLM) && ecccnt++ >= MAXECC)
428 				return (1);
429 		}
430 		return(0);
431 	}
432 
433 	/*
434 	 * Skip sector error.
435 	 * Set skip-sector-inhibit and
436 	 * read next sector
437 	 */
438 	case SSE:
439 		rp->hpcs1 = HP_DCLR | HP_GO;
440 		HPWAIT(rp);
441 		rp->hpof |= HPOF_SSEI;
442 		return (0);
443 
444 	case BSE: {
445 		int bbn;
446 
447 		rp->hpcs1 = HP_DCLR | HP_GO;
448 #ifdef HPDEBUG
449 		printf("hpecc: BSE @ bn %d\n", bn);
450 #endif
451 		cn = bn/st->nspc;
452 		sn = bn%st->nspc;
453 		tn = sn/st->nsect;
454 		sn = sn%st->nsect;
455 		bcr += sectsiz;
456 		if ((bbn = isbad(&hpbad[unit], cn, tn, sn)) < 0)
457 			return (1);
458 		bbn = st->ncyl*st->nspc - st->nsect - 1 - bbn;
459 		cn = bbn/st->nspc;
460 		sn = bbn%st->nspc;
461 		tn = sn/st->nsect;
462 		sn = sn%st->nsect;
463 		io->i_cc = sectsiz;
464 		io->i_ma += npf*sectsiz;
465 #ifdef HPDEBUG
466 		printf("revector to cn %d tn %d sn %d mem: 0x%x\n",
467 			cn, tn, sn, io->i_ma);
468 #endif
469 		rp->hpof &= ~HPOF_SSEI;	/* clear skip sector inhibit if set */
470 		mbp->mba_sr = -1;
471 		rp->hpdc = cn;
472 		rp->hpda = (tn<<8) + sn;
473 		mbastart(io,io->i_flgs);
474 		io->i_errcnt = 0;	/* error has been corrected */
475 		HPWAIT(rp);
476 		return (rp->hpds&HPDS_ERR);
477 	}
478 	}
479 	printf("hpecc: flag=%d\n", flag);
480 	return (1);
481 }
482 /*ARGSUSED*/
483 hpioctl(io, cmd, arg)
484 	struct iob *io;
485 	int cmd;
486 	caddr_t arg;
487 {
488 	register unit = io->i_unit;
489 	struct st *st = &hpst[hp_type[unit]], *tmp;
490 	struct mba_drv *drv = mbadrv(unit);
491 
492 	switch(cmd) {
493 
494 	case SAIODEVDATA:
495 		if ((drv->mbd_dt&MBDT_TAP) == 0) {
496 			tmp = (struct st *)arg;
497 			*tmp = *st;
498 			return (0);
499 		}
500 		return (ECMD);
501 
502 	case SAIOSSI:			/* skip-sector-inhibit */
503 		if (drv->mbd_dt&MBDT_TAP)
504 			return (ECMD);
505 		if ((io->i_flgs&F_SSI) == 0) {
506 			/* make sure this is done once only */
507 			io->i_flgs |= F_SSI;
508 			st->nsect++;
509 			st->nspc += st->ntrak;
510 		}
511 		return (0);
512 
513 	case SAIONOSSI:			/* remove skip-sector-inhibit */
514 		if (io->i_flgs & F_SSI) {
515 			io->i_flgs &= ~F_SSI;
516 			drv->mbd_of &= ~HPOF_SSEI;
517 			st->nsect--;
518 			st->nspc -= st->ntrak;
519 		}
520 		return(0);
521 
522 	case SAIOSSDEV:			/* drive have skip sector? */
523 		return (RM80 ? 0 : ECMD);
524 	}
525 	return (ECMD);
526 }
527