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