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