xref: /original-bsd/sys/vax/stand/hp.c (revision aba77441)
1 /*
2  * Copyright (c) 1982 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  *
6  *	@(#)hp.c	6.7 (Berkeley) 06/08/85
7  */
8 
9 /*
10  * RP??/RM?? disk driver
11  * with ECC handling and bad block forwarding.
12  * Also supports header io operations and
13  * commands to write check header and data.
14  */
15 #include "../h/param.h"
16 #include "../h/inode.h"
17 #include "../h/fs.h"
18 #include "../h/dkbad.h"
19 
20 #include "../vax/pte.h"
21 #include "../vaxmba/hpreg.h"
22 #include "../vaxmba/mbareg.h"
23 
24 #include "saio.h"
25 #include "savax.h"
26 
27 #define	MASKREG(reg)	((reg)&0xffff)
28 
29 #define	MAXBADDESC	126
30 #define	SECTSIZ 	512	/* sector size in bytes */
31 #define	HDRSIZ		4	/* number of bytes in sector header */
32 #define	MAXECC		5	/* max # bits allow in ecc error w/ F_ECCLM */
33 
34 char	hp_type[MAXNMBA*8] = { 0 };
35 extern	struct st hpst[];
36 
37 short	hptypes[] = {
38 	MBDT_RM03,
39 	MBDT_RM05,
40 	MBDT_RP06,
41 	MBDT_RM80,
42 	MBDT_RP05,
43 	MBDT_RP07,
44 	MBDT_ML11A,
45 	MBDT_ML11B,
46 	-1,		/* 9755 */
47 	-1,		/* 9730 */
48 	-1,		/* Capricorn */
49 	-1,		/* Eagle */
50 	MBDT_RM02,	/* actually something else */
51 	-1,		/* 9300 */
52 	0
53 };
54 
55 #define	RP06 (hptypes[hp_type[unit]] <= MBDT_RP06)
56 #define	ML11 (hptypes[hp_type[unit]] == MBDT_ML11A)
57 #define	RM80 (hptypes[hp_type[unit]] == MBDT_RM80)
58 
59 u_char	hp_offset[16] = {
60     HPOF_P400, HPOF_M400, HPOF_P400, HPOF_M400,
61     HPOF_P800, HPOF_M800, HPOF_P800, HPOF_M800,
62     HPOF_P1200, HPOF_M1200, HPOF_P1200, HPOF_M1200,
63     0, 0, 0, 0,
64 };
65 
66 struct	dkbad hpbad[MAXNMBA*8];
67 int	ssect[MAXNMBA*8];		/* 1 when on track w/skip sector */
68 
69 int	hpdebug[MAXNMBA*8];
70 #define	HPF_BSEDEBUG	01	/* debugging bad sector forwarding */
71 #define	HPF_ECCDEBUG	02	/* debugging ecc correction */
72 
73 int	sectsiz;
74 
75 /*
76  * When awaiting command completion, don't
77  * hang on to the status register since
78  * this ties up some controllers.
79  */
80 #define	HPWAIT(addr) \
81 	while ((((addr)->hpds)&HPDS_DRY)==0) DELAY(500);
82 
83 hpopen(io)
84 	register struct iob *io;
85 {
86 	register unit = io->i_unit;
87 	struct hpdevice *hpaddr = (struct hpdevice *)mbadrv(unit);
88 	register struct st *st;
89 
90 	mbainit(UNITTOMBA(unit));
91 	if (hp_type[unit] == 0) {
92 		register i, type = hpaddr->hpdt & MBDT_TYPE;
93 		struct iob tio;
94 
95 		for (i = 0; hptypes[i]; i++)
96 			if (hptypes[i] == type)
97 				goto found;
98 		_stop("unknown drive type");
99 found:
100 		hpaddr->hpcs1 = HP_DCLR|HP_GO;		/* init drive */
101 		hpaddr->hpcs1 = HP_PRESET|HP_GO;
102 		if (!ML11)
103 			hpaddr->hpof = HPOF_FMT22;
104 		hp_type[unit] = hpmaptype(hpaddr, i, UNITTODRIVE(unit));
105 		/*
106 		 * Read in the bad sector table.
107 		 */
108 		st = &hpst[hp_type[unit]];
109 		tio = *io;
110 		tio.i_bn = st->nspc * st->ncyl - st->nsect;
111 		tio.i_ma = (char *)&hpbad[unit];
112 		tio.i_cc = sizeof (struct dkbad);
113 		tio.i_flgs |= F_RDDATA;
114 		for (i = 0; i < 5; i++) {
115 			if (hpstrategy(&tio, READ) == sizeof (struct dkbad))
116 				break;
117 			tio.i_bn += 2;
118 		}
119 		if (i == 5) {
120 			printf("Unable to read bad sector table\n");
121 			for (i = 0; i < MAXBADDESC; i++) {
122 				hpbad[unit].bt_bad[i].bt_cyl = -1;
123 				hpbad[unit].bt_bad[i].bt_trksec = -1;
124 			}
125 		}
126 	}
127 	st = &hpst[hp_type[unit]];
128 	if (io->i_boff < 0 || io->i_boff > 7 ||
129 	    st->off[io->i_boff]== -1)
130 		_stop("hp bad minor");
131 	io->i_boff = st->off[io->i_boff] * st->nspc;
132 }
133 
134 hpstrategy(io, func)
135 	register struct iob *io;
136 {
137 	register unit = io->i_unit;
138 	struct mba_regs *mba = mbamba(unit);
139 	daddr_t bn, startblock;
140 	struct hpdevice *hpaddr = (struct hpdevice *)mbadrv(unit);
141 	struct st *st = &hpst[hp_type[unit]];
142 	int cn, tn, sn, bytecnt, bytesleft;
143 	char *membase;
144 	int er1, er2, hprecal;
145 
146 	sectsiz = SECTSIZ;
147 	if ((io->i_flgs & (F_HDR|F_HCHECK)) != 0)
148 		sectsiz += HDRSIZ;
149 	if ((hpaddr->hpds & HPDS_VV) == 0) {
150 		hpaddr->hpcs1 = HP_DCLR|HP_GO;
151 		hpaddr->hpcs1 = HP_PRESET|HP_GO;
152 		if (!ML11)
153 			hpaddr->hpof = HPOF_FMT22;
154 	}
155 	io->i_errcnt = 0;
156 	ssect[unit] = 0;
157 	bytecnt = io->i_cc;
158 	membase = io->i_ma;
159 	startblock = io->i_bn;
160 	hprecal = 0;
161 
162 restart:
163 	bn = io->i_bn;
164 	cn = bn/st->nspc;
165 	sn = bn%st->nspc;
166 	tn = sn/st->nsect;
167 	sn = sn%st->nsect + ssect[unit];
168 
169 	HPWAIT(hpaddr);
170 	mba->mba_sr = -1;
171 	if (ML11)
172 		hpaddr->hpda = bn;
173 	else {
174 		hpaddr->hpdc = cn;
175 		hpaddr->hpda = (tn << 8) + sn;
176 	}
177 	if (mbastart(io, func) != 0)		/* start transfer */
178 		return (-1);
179 	HPWAIT(hpaddr);
180 	/*
181 	 * Successful data transfer, return.
182 	 */
183 	if ((hpaddr->hpds&HPDS_ERR) == 0 && (mba->mba_sr&MBSR_EBITS) == 0)
184 		goto done;
185 
186 	/*
187 	 * Error handling.  Calculate location of error.
188 	 */
189 	bytesleft = MASKREG(mba->mba_bcr);
190 	if (bytesleft)
191 		bytesleft |= 0xffff0000;	/* sxt */
192 	bn = io->i_bn + (io->i_cc + bytesleft) / sectsiz;
193 	er1 = MASKREG(hpaddr->hper1);
194 	er2 = MASKREG(hpaddr->hper2);
195 	if (er1 & (HPER1_DCK|HPER1_ECH))
196 		bn--;	/* Error is in Prev block */
197 	cn = bn/st->nspc;
198 	sn = bn%st->nspc;
199 	tn = sn/st->nsect;
200 	sn = sn%st->nsect;
201 	if (hpdebug[unit] & (HPF_ECCDEBUG|HPF_BSEDEBUG)) {
202 		printf("hp error: (cyl,trk,sec)=(%d,%d,%d) ds=%b\n",
203 			cn, tn, sn, MASKREG(hpaddr->hpds), HPDS_BITS);
204 		printf("er1=%b er2=%b\n", er1, HPER1_BITS, er2, HPER2_BITS);
205 		printf("bytes left: %d, of 0x%x, da 0x%x\n",-bytesleft,
206 			hpaddr->hpof, hpaddr->hpda);
207 	}
208 	if (er1 & HPER1_HCRC) {
209 		er1 &= ~(HPER1_HCE|HPER1_FER);
210 		er2 &= ~HPER2_BSE;
211 	}
212 	/*
213 	 * Give up early if drive write locked.
214 	 */
215 	if (er1&HPER1_WLE) {
216 		printf("hp%d: write locked\n", unit);
217 		return (-1);
218 	}
219 	/*
220 	 * Interpret format error bit as a bad block on RP06's.
221 	 */
222 	if (MASKREG(er1) == HPER1_FER && RP06)
223 		goto badsect;
224 
225 	/*
226 	 * If a hard error, or maximum retry count
227 	 * exceeded, clear controller state and
228 	 * pass back error to caller.
229 	 */
230 	if (++io->i_errcnt > 27 || (er1 & HPER1_HARD) ||
231 	    (!ML11 && (er2 & HPER2_HARD))) {
232 		/*
233 		 * The last ditch effort to bad sector forward
234 		 * below will probably fail since mba byte ctr
235 		 * (bcr) is different for BSE and ECC errors and
236 		 * the wrong block will be revectored to if one
237 		 * has 2 contiguous bad blocks and reads the second.
238 		 * For now, we can probably just let a header CRC
239 		 * error be handled like a BSE since no data will
240 		 * have been transferred and the bcr should the same
241 		 * as it would with a BSE error.
242 		 * --ghg.
243 		 */
244 		if (er1 & HPER1_HCRC)
245 			if ((io->i_flgs&F_NBSF) == 0 && hpecc(io, BSE) == 0)
246 				goto success;
247 hard0:
248 		io->i_error = EHER;
249 		if (mba->mba_sr & (MBSR_WCKUP|MBSR_WCKLWR))
250 			io->i_error = EWCK;
251 hard:
252 		io->i_errblk = bn + ssect[unit];
253 		printf("hp error: (cyl,trk,sec)=(%d,%d,%d) ds=%b \n",
254 			   cn, tn, sn, MASKREG(hpaddr->hpds), HPDS_BITS);
255 		printf("er1=%b er2=%b", er1, HPER1_BITS, er2, HPER2_BITS);
256 		if (hpaddr->hpmr)
257 			printf(" mr1=%o", MASKREG(hpaddr->hpmr));
258 		if (hpaddr->hpmr2)
259 			printf(" mr2=%o", MASKREG(hpaddr->hpmr2));
260 		if (hpdebug[unit] & (HPF_BSEDEBUG|HPF_ECCDEBUG))
261 			printf(" dc=%d, da=0x%x",MASKREG(hpaddr->hpdc),
262 			  MASKREG(hpaddr->hpda));
263 		hpaddr->hpcs1 = HP_DCLR|HP_GO;
264 		printf("\n");
265 		bytecnt = -1;
266 		goto done;
267 
268 	}
269 	/*
270 	 * Attempt to forward bad sectors on
271 	 * anything but an ML11.
272 	 */
273 	if ((er2 & HPER2_BSE) && !ML11) {
274 badsect:
275 		if (!ssect[unit] && (er2&HPER2_SSE))
276 			goto skipsect;
277 		if (io->i_flgs & F_NBSF) {
278 			io->i_error = EBSE;
279 			goto hard;
280 		}
281 		if (hpecc(io, BSE) == 0)
282 			goto success;
283 		io->i_error = EBSE;
284 		goto hard;
285 	}
286 	/*
287 	 * Skip sector handling.
288 	 */
289 	if (RM80 && (er2 & HPER2_SSE)) {
290 skipsect:
291 		(void) hpecc(io, SSE);
292 		ssect[unit] = 1;
293 		goto restart;
294 	}
295 	/*
296 	 * ECC correction?
297 	 */
298 	if ((er1 & (HPER1_DCK|HPER1_ECH)) == HPER1_DCK) {
299 		if (hpecc(io, ECC) == 0)
300 			goto success;
301 		io->i_error = EECC;
302 		io->i_errblk = bn + ssect[unit];
303 		return (-1);
304 	}
305 #ifdef F_SEVRE
306 	if (io->i_flgs & F_SEVRE)
307 		goto hard;
308 #endif
309 	if (ML11 && (io->i_errcnt >= 16))
310 		goto hard0;
311 	/* fall thru to retry */
312 	hpaddr->hpcs1 = HP_DCLR|HP_GO;
313 	HPWAIT(hpaddr);
314 
315 	/*
316 	 * Every fourth retry recalibrate.
317 	 */
318 	if (((io->i_errcnt & 07) == 4) ) {
319 		hpaddr->hpcs1 = HP_RECAL|HP_GO;
320 		HPWAIT(hpaddr);
321 		hpaddr->hpdc = cn;
322 		hpaddr->hpcs1 = HP_SEEK|HP_GO;
323 		HPWAIT(hpaddr);
324 	}
325 
326 	if (io->i_errcnt >= 16 && (io->i_flgs & F_READ)) {
327 		hpaddr->hpof = hp_offset[io->i_errcnt & 017]|HPOF_FMT22;
328 		hpaddr->hpcs1 = HP_OFFSET|HP_GO;
329 		HPWAIT(hpaddr);
330 	}
331 	if (hpdebug[unit] & (HPF_ECCDEBUG|HPF_BSEDEBUG))
332 		printf("restart: bn=%d, cc=%d, ma=0x%x hprecal=%d\n",
333 		  io->i_bn, io->i_cc, io->i_ma, hprecal);
334 	goto restart;	/* retry whole transfer  --ghg */
335 
336 success:
337 	/*
338 	 * On successful error recovery, bump
339 	 * block number to advance to next portion
340 	 * of i/o transfer.
341 	 */
342 	bn++;
343 	if ((bn-startblock) * sectsiz < bytecnt) {
344 		io->i_bn = bn;
345 		io->i_ma = membase + (io->i_bn - startblock)*sectsiz;
346 		io->i_cc = bytecnt - (io->i_bn - startblock)*sectsiz;
347 		if (hpdebug[unit] & (HPF_ECCDEBUG|HPF_BSEDEBUG))
348 			printf("restart: bn=%d, cc=%d, ma=0x%x hprecal=%d\n",
349 			  io->i_bn, io->i_cc, io->i_ma, hprecal);
350 		goto restart;
351 	}
352 done:
353 	if (io->i_errcnt >= 16) {
354 		hpaddr->hpcs1 = HP_RTC|HP_GO;
355 		while (hpaddr->hpds & HPDS_PIP)
356 			;
357 	}
358 	io->i_cc = bytecnt;		/*reset i_cc to total count xfered*/
359 	return (bytecnt);
360 }
361 
362 hpecc(io, flag)
363 	register struct iob *io;
364 	int flag;
365 {
366 	register unit = io->i_unit;
367 	register struct mba_regs *mbp = mbamba(unit);
368 	register struct hpdevice *rp = (struct hpdevice *)mbadrv(unit);
369 	register struct st *st = &hpst[hp_type[unit]];
370 	int npf, bn, cn, tn, sn, bcr;
371 
372 	bcr = MASKREG(mbp->mba_bcr);
373 	if (bcr)
374 		bcr |= 0xffff0000;		/* sxt */
375 	npf = (bcr + io->i_cc) / sectsiz;	/* # sectors read */
376 	if (flag == ECC)
377 		npf--;		/* Error is in prev block --ghg */
378 	bn = io->i_bn + npf + ssect[unit];	/* physical block #*/
379 	if (hpdebug[unit]&HPF_ECCDEBUG)
380 		printf("bcr=%d npf=%d ssect=%d sectsiz=%d i_cc=%d\n",
381 			bcr, npf, ssect[unit], sectsiz, io->i_cc);
382 	/*
383 	 * ECC correction logic.
384 	 */
385 	if (flag == ECC) {
386 		register int i;
387 		caddr_t addr;
388 		int bit, o, mask, ecccnt = 0;
389 
390 		printf("hp%d: soft ecc sn%d\n", unit, bn);
391 		mask = MASKREG(rp->hpec2);
392 		i = MASKREG(rp->hpec1) - 1;	/* -1 makes 0 origin */
393 		bit = i&07;
394 		o = (i & ~07) >> 3;
395 		rp->hpcs1 = HP_DCLR | HP_GO;
396 		while (o <sectsiz && npf*sectsiz + o < io->i_cc && bit > -11) {
397 			addr = io->i_ma + (npf*sectsiz) + o;
398 			/*
399 			 * No data transfer occurs with a write check,
400 			 * so don't correct the resident copy of data.
401 			 */
402 			if ((io->i_flgs & (F_CHECK|F_HCHECK)) == 0) {
403 				if (hpdebug[unit] & HPF_ECCDEBUG)
404 					printf("addr=%x old=%x ", addr,
405 						(*addr & 0xff));
406 				*addr ^= (mask << bit);
407 				if (hpdebug[unit] & HPF_ECCDEBUG)
408 					printf("new=%x\n",(*addr & 0xff));
409 			}
410 			o++, bit -= 8;
411 			if ((io->i_flgs & F_ECCLM) && ecccnt++ >= MAXECC)
412 				return (1);
413 		}
414 #ifdef F_SEVRE
415 		if (io->i_flgs & F_SEVRE)
416 			return(1);
417 #endif
418 		return (0);
419 	}
420 
421 	/*
422 	 * Skip sector error.
423 	 * Set skip-sector-inhibit and
424 	 * read next sector
425 	 */
426 	if (flag == SSE) {
427 		rp->hpcs1 = HP_DCLR | HP_GO;
428 		HPWAIT(rp);
429 		rp->hpof |= HPOF_SSEI;
430 		return (0);
431 	}
432 
433 	/*
434 	 * Bad block forwarding.
435 	 */
436 	 if (flag == BSE) {
437 		int bbn;
438 
439 		rp->hpcs1 = HP_DCLR | HP_GO;
440 		if (hpdebug[unit] & HPF_BSEDEBUG)
441 			printf("hpecc: BSE @ bn %d\n", bn);
442 		cn = bn/st->nspc;
443 		sn = bn%st->nspc;
444 		tn = sn/st->nsect;
445 		sn = sn%st->nsect;
446 		bcr += sectsiz;
447 		if ((bbn = isbad(&hpbad[unit], cn, tn, sn)) < 0)
448 			return (1);
449 		bbn = st->ncyl*st->nspc - st->nsect - 1 - bbn;
450 		cn = bbn/st->nspc;
451 		sn = bbn%st->nspc;
452 		tn = sn/st->nsect;
453 		sn = sn%st->nsect;
454 		io->i_cc = sectsiz;
455 		io->i_ma += npf*sectsiz;
456 		if (hpdebug[unit] & HPF_BSEDEBUG)
457 			printf("revector to cn %d tn %d sn %d\n", cn, tn, sn);
458 		rp->hpof &= ~HPOF_SSEI;
459 		mbp->mba_sr = -1;
460 		rp->hpdc = cn;
461 		rp->hpda = (tn<<8) + sn;
462 		mbastart(io,io->i_flgs);
463 		io->i_errcnt = 0;
464 		HPWAIT(rp);
465 		return (rp->hpds&HPDS_ERR);
466 	}
467 	printf("hpecc: flag=%d\n", flag);
468 	return (1);
469 }
470 
471 /*ARGSUSED*/
472 hpioctl(io, cmd, arg)
473 	struct iob *io;
474 	int cmd;
475 	caddr_t arg;
476 {
477 	register unit = io->i_unit;
478 	struct st *st = &hpst[hp_type[unit]], *tmp;
479 	struct mba_drv *drv = mbadrv(unit);
480 	int flag;
481 
482 	switch(cmd) {
483 
484 	case SAIODEBUG:
485 		flag = (int)arg;
486 		if (flag > 0)
487 			hpdebug[unit] |= flag;
488 		else
489 			hpdebug[unit] &= ~flag;
490 		return (0);
491 
492 	case SAIODEVDATA:
493 		if ((drv->mbd_dt&MBDT_TAP) == 0) {
494 			tmp = (struct st *)arg;
495 			*tmp = *st;
496 			return (0);
497 		}
498 		return (ECMD);
499 
500 	case SAIOSSI:			/* skip-sector-inhibit */
501 		if (drv->mbd_dt&MBDT_TAP)
502 			return (ECMD);
503 		if ((io->i_flgs&F_SSI) == 0) {
504 			/* make sure this is done once only */
505 			io->i_flgs |= F_SSI;
506 			st->nsect++;
507 			st->nspc += st->ntrak;
508 		}
509 		return (0);
510 
511 	case SAIONOSSI:			/* remove skip-sector-inhibit */
512 		if (io->i_flgs & F_SSI) {
513 			io->i_flgs &= ~F_SSI;
514 			drv->mbd_of &= ~HPOF_SSEI;
515 			st->nsect--;
516 			st->nspc -= st->ntrak;
517 		}
518 		return(0);
519 
520 	case SAIOSSDEV:			/* drive have skip sector? */
521 		return (RM80 ? 0 : ECMD);
522 	}
523 	return (ECMD);
524 }
525