|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1988 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: * @(#)up.c 7.9 (Berkeley) 4/4/90
7: */
8:
9: /*
10: * UNIBUS peripheral standalone driver with ECC correction and bad
11: * block forwarding. Also supports header operation and write check
12: * for data and/or header.
13: */
14: #include "param.h"
15: #include "dkbad.h"
16: #include "disklabel.h"
17:
18: #include "../vax/pte.h"
19:
20: #include "../vaxuba/upreg.h"
21: #include "../vaxuba/ubareg.h"
22:
23: #include "saio.h"
24: #include "savax.h"
25:
26: #define RETRIES 27
27:
28: #define MAXBADDESC 126 /* max number of bad sectors recorded */
29: #define SECTSIZ 512 /* sector size in bytes */
30: #define HDRSIZ 4 /* number of bytes in sector header */
31:
32: #define MAXUNIT 8
33: #define MAXCTLR 1 /* all addresses must be specified */
34: static u_short upstd[MAXCTLR] = { 0776700 };
35: static struct disklabel uplabel[MAXNUBA][MAXCTLR][MAXUNIT];
36: static char lbuf[SECTSIZ];
37:
38: extern struct st upst[];
39:
40: #ifndef SMALL
41: struct dkbad upbad[MAXNUBA][MAXCTLR][MAXUNIT]; /* bad sector table */
42: #endif
43: int sectsiz; /* real sector size */
44:
45: struct up_softc {
46: char gottype;
47: char type;
48: char debug;
49: # define UPF_BSEDEBUG 01 /* debugging bad sector forwarding */
50: # define UPF_ECCDEBUG 02 /* debugging ecc correction */
51: int retries;
52: int ecclim;
53: } up_softc[MAXNUBA][MAXCTLR][MAXUNIT];
54:
55: u_char up_offset[16] = {
56: UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400,
57: UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800,
58: UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200,
59: 0, 0, 0, 0
60: };
61:
62: upopen(io)
63: register struct iob *io;
64: {
65: register struct updevice *upaddr;
66: register struct up_softc *sc;
67: register struct st *st;
68: register struct disklabel *lp;
69: struct disklabel *dlp;
70: register int unit;
71: int error = 0, uba, ctlr;
72:
73: if ((u_int)(uba = io->i_adapt) >= nuba)
74: return (EADAPT);
75: if ((u_int)(ctlr = io->i_ctlr) >= MAXCTLR)
76: return (ECTLR);
77: unit = io->i_unit;
78: if ((u_int)unit >= MAXUNIT)
79: return (EUNIT);
80: upaddr = (struct updevice *)ubamem(uba, upstd[ctlr]);
81: upaddr->upcs2 = unit;
82: while ((upaddr->upcs1 & UP_DVA) == 0);
83: sc = &up_softc[uba][ctlr][unit];
84: lp = &uplabel[uba][ctlr][unit];
85: if (sc->gottype == 0) {
86: register int i;
87: struct iob tio;
88:
89: #ifndef SMALL
90: sc->retries = RETRIES;
91: sc->ecclim = 11;
92: sc->debug = 0;
93: #endif
94: /* Read in the pack label. */
95: lp->d_nsectors = 32;
96: lp->d_secpercyl = 19*32;
97: tio = *io;
98: tio.i_bn = LABELSECTOR;
99: tio.i_ma = lbuf;
100: tio.i_cc = SECTSIZ;
101: tio.i_flgs |= F_RDDATA;
102: if (upstrategy(&tio, READ) != SECTSIZ)
103: error = ERDLAB;
104: dlp = (struct disklabel *)(lbuf + LABELOFFSET);
105: if (error == 0 && (dlp->d_magic != DISKMAGIC ||
106: dlp->d_magic2 != DISKMAGIC))
107: error = EUNLAB;
108: if (error == 0)
109: *lp = *dlp;
110: else
111: #ifdef COMPAT_42
112: if (upmaptype(unit, upaddr, lp) == 0)
113: #endif
114: return (error);
115:
116: #ifndef SMALL
117: /* Read in the bad sector table. */
118: tio.i_bn = lp->d_secpercyl * lp->d_ncylinders - lp->d_nsectors;
119: tio.i_ma = (char *)&upbad[uba][ctlr][unit];
120: tio.i_cc = sizeof(struct dkbad);
121: tio.i_flgs |= F_RDDATA;
122: for (i = 0; i < 5; i++) {
123: if (upstrategy(&tio, READ) == sizeof(struct dkbad))
124: break;
125: tio.i_bn += 2;
126: }
127: if (i == 5) {
128: printf("up: can't read bad sector table\n");
129: for (i = 0; i < MAXBADDESC; i++) {
130: upbad[uba][ctlr][unit].bt_bad[i].bt_cyl = -1;
131: upbad[uba][ctlr][unit].bt_bad[i].bt_trksec = -1;
132: }
133: }
134: #endif
135: sc->gottype = 1;
136: }
137: if (io->i_part >= lp->d_npartitions ||
138: lp->d_partitions[io->i_part].p_size == 0)
139: return (EPART);
140: io->i_boff = lp->d_partitions[io->i_part].p_offset;
141: io->i_flgs &= ~F_TYPEMASK;
142: return (0);
143: }
144:
145: upstrategy(io, func)
146: register struct iob *io;
147: int func;
148: {
149: int cn, tn, sn, o;
150: register unit = io->i_unit;
151: register daddr_t bn;
152: int recal, info, waitdry;
153: register struct updevice *upaddr;
154: register struct disklabel *lp;
155: struct up_softc *sc;
156: int error, rv = io->i_cc;
157: #ifndef SMALL
158: int doprintf = 0;
159: #endif
160:
161: upaddr = (struct updevice *)ubamem(io->i_adapt, upstd[io->i_ctlr]);
162: sc = &up_softc[io->i_adapt][io->i_ctlr][unit];
163: lp = &uplabel[io->i_adapt][io->i_ctlr][unit];
164: sectsiz = SECTSIZ;
165: #ifndef SMALL
166: if (io->i_flgs & (F_HDR|F_HCHECK))
167: sectsiz += HDRSIZ;
168: #endif
169: upaddr->upcs2 = unit;
170: if ((upaddr->upds & UPDS_VV) == 0) {
171: upaddr->upcs1 = UP_DCLR|UP_GO;
172: upaddr->upcs1 = UP_PRESET|UP_GO;
173: upaddr->upof = UPOF_FMT22;
174: }
175: if ((upaddr->upds & UPDS_DREADY) == 0) {
176: printf("up%d not ready\n", unit);
177: return (-1);
178: }
179: info = ubasetup(io, 1);
180: upaddr->upwc = -io->i_cc / sizeof (short);
181: recal = 0;
182: io->i_errcnt = 0;
183:
184: restart:
185: o = io->i_cc + (upaddr->upwc * sizeof (short));
186: upaddr->upba = info + o;
187: bn = io->i_bn + o / sectsiz;
188: #ifndef SMALL
189: error = 0;
190: if (doprintf && sc->debug & (UPF_ECCDEBUG|UPF_BSEDEBUG))
191: printf("wc=%d o=%d i_bn=%d bn=%d\n",
192: upaddr->upwc, o, io->i_bn, bn);
193: #endif
194: upwaitdry(upaddr);
195: if (upstart(io, bn, lp) != 0) {
196: rv = -1;
197: goto done;
198: }
199: upwaitrdy(upaddr);
200: /*
201: * If transfer has completed, free UNIBUS
202: * resources and return transfer size.
203: */
204: if ((upaddr->upds&UPDS_ERR) == 0 && (upaddr->upcs1&UP_TRE) == 0)
205: goto done;
206: bn = io->i_bn +
207: (io->i_cc + upaddr->upwc * sizeof (short)) / sectsiz;
208: if (upaddr->uper1 & (UPER1_DCK|UPER1_ECH))
209: bn--;
210: cn = bn / lp->d_secpercyl;
211: sn = bn % lp->d_secpercyl;
212: tn = sn / lp->d_nsectors;
213: sn = sn % lp->d_nsectors;
214: #ifndef SMALL
215: if (sc->debug & (UPF_ECCDEBUG|UPF_BSEDEBUG)) {
216: printf("up error: sn%d (cyl,trk,sec)=(%d,%d,%d) ",
217: bn, cn, tn, sn);
218: printf("cs2=%b er1=%b er2=%b wc=%d\n",
219: upaddr->upcs2, UPCS2_BITS, upaddr->uper1,
220: UPER1_BITS, upaddr->uper2, UPER2_BITS, upaddr->upwc);
221: }
222: #endif
223: waitdry = 0;
224: while ((upaddr->upds&UPDS_DRY) == 0 && ++waitdry < sectsiz)
225: DELAY(5);
226: #ifndef SMALL
227: if (upaddr->uper1&UPER1_WLE) {
228: /*
229: * Give up on write locked devices immediately.
230: */
231: printf("up%d: write locked\n", unit);
232: rv = -1;
233: goto done;
234: }
235: if (upaddr->uper2 & UPER2_BSE) {
236: if ((io->i_flgs&F_NBSF) == 0 && upecc(io, BSE) == 0)
237: goto success;
238: error = EBSE;
239: goto hard;
240: }
241: /*
242: * ECC error. If a soft error, correct it;
243: * if correction is too large, no more retries.
244: */
245: if ((upaddr->uper1 & (UPER1_DCK|UPER1_ECH|UPER1_HCRC)) == UPER1_DCK) {
246: if (upecc(io, ECC) == 0)
247: goto success;
248: error = EECC;
249: goto hard;
250: }
251: /*
252: * If the error is a header CRC, check if a replacement sector
253: * exists in the bad sector table.
254: */
255: if ((upaddr->uper1&UPER1_HCRC) && (io->i_flgs&F_NBSF) == 0 &&
256: upecc(io, BSE) == 0)
257: goto success;
258: #endif
259: if (++io->i_errcnt > sc->retries) {
260: /*
261: * After 28 retries (16 without offset, and
262: * 12 with offset positioning) give up.
263: */
264: hard:
265: #ifndef SMALL
266: if (error == 0) {
267: error = EHER;
268: if (upaddr->upcs2 & UPCS2_WCE)
269: error = EWCK;
270: }
271: io->i_error = error;
272: #endif
273: printf("up error: sn%d (cyl,trk,sec)=(%d,%d,%d) ",
274: bn, cn, tn, sn);
275: printf("cs2=%b er1=%b er2=%b\n",
276: upaddr->upcs2, UPCS2_BITS, upaddr->uper1,
277: UPER1_BITS, upaddr->uper2, UPER2_BITS);
278: upaddr->upcs1 = UP_TRE|UP_DCLR|UP_GO;
279: io->i_errblk = bn;
280: if (io->i_errcnt >= 16) {
281: upaddr->upof = UPOF_FMT22;
282: upaddr->upcs1 = UP_RTC|UP_GO;
283: upwaitdry(upaddr);
284: }
285: rv = -1;
286: goto done;
287: }
288: /*
289: * Clear drive error and, every eight attempts, (starting with the
290: * fourth) recalibrate to clear the slate.
291: */
292: upaddr->upcs1 = UP_TRE|UP_DCLR|UP_GO;
293: if ((io->i_errcnt&07) == 4 ) {
294: upaddr->upcs1 = UP_RECAL|UP_GO;
295: upwaitdry(upaddr);
296: upaddr->updc = cn;
297: upaddr->upcs1 = UP_SEEK|UP_GO;
298: upwaitdry(upaddr);
299: }
300: if (io->i_errcnt >= 16 && (func & READ)) {
301: upaddr->upof = up_offset[io->i_errcnt & 017] | UPOF_FMT22;
302: upaddr->upcs1 = UP_OFFSET|UP_GO;
303: upwaitdry(upaddr);
304: }
305: goto restart;
306:
307: success:
308: #define rounddown(x, y) (((x) / (y)) * (y))
309: upaddr->upwc = rounddown(upaddr->upwc, sectsiz / sizeof (short));
310: if (upaddr->upwc) {
311: #ifndef SMALL
312: doprintf++;
313: #endif
314: goto restart;
315: }
316: done:
317: ubafree(io, info);
318: /*
319: * If we were offset positioning,
320: * return to centerline.
321: */
322: if (io->i_errcnt >= 16) {
323: upaddr->upof = UPOF_FMT22;
324: upaddr->upcs1 = UP_RTC|UP_GO;
325: upwaitdry(upaddr);
326: }
327: return (rv);
328: }
329:
330: upwaitrdy(upaddr)
331: register struct updevice *upaddr;
332: {
333: do {
334: DELAY(25);
335: } while ((upaddr->upcs1 & UP_RDY) == 0);
336: }
337:
338: upwaitdry(upaddr)
339: register struct updevice *upaddr;
340: {
341: while ((upaddr->upds&UPDS_DRY) == 0)
342: DELAY(25);
343: }
344:
345: #ifndef SMALL
346: /*
347: * Correct an ECC error, and restart the i/o to complete the transfer (if
348: * necessary). This is quite complicated because the transfer may be going
349: * to an odd memory address base and/or across a page boundary.
350: */
351: upecc(io, flag)
352: register struct iob *io;
353: int flag;
354: {
355: register i, unit;
356: register struct up_softc *sc;
357: register struct updevice *up;
358: register struct disklabel *lp;
359: caddr_t addr;
360: int bn, twc, npf, mask, cn, tn, sn;
361: daddr_t bbn;
362:
363: /*
364: * Npf is the number of sectors transferred
365: * before the sector containing the ECC error;
366: * bn is the current block number.
367: */
368: unit = io->i_unit;
369: sc = &up_softc[io->i_adapt][io->i_ctlr][unit];
370: lp = &uplabel[io->i_adapt][io->i_ctlr][unit];
371: up = (struct updevice *)ubamem(io->i_adapt, upstd[io->i_ctlr]);
372: twc = up->upwc;
373: npf = ((twc * sizeof(short)) + io->i_cc) / sectsiz;
374: if (flag == ECC)
375: npf--;
376: if (sc->debug & UPF_ECCDEBUG)
377: printf("npf=%d mask=0x%x ec1=%d wc=%d\n",
378: npf, up->upec2, up->upec1, twc);
379: bn = io->i_bn + npf;
380: cn = bn / lp->d_secpercyl;
381: sn = bn % lp->d_secpercyl;
382: tn = sn / lp->d_nsectors;
383: sn = sn % lp->d_nsectors;
384:
385: /*
386: * ECC correction.
387: */
388: if (flag == ECC) {
389: int bit, o;
390:
391: mask = up->upec2;
392: printf("up%d: soft ecc sn%d\n", unit, bn);
393: for (i = mask, bit = 0; i; i >>= 1)
394: if (i & 1)
395: bit++;
396: if (bit > sc->ecclim) {
397: printf("%d-bit error\n", bit);
398: return (1);
399: }
400: /*
401: * Compute the byte and bit position of
402: * the error. o is the byte offset in
403: * the transfer at which the correction
404: * applied.
405: */
406: i = up->upec1 - 1; /* -1 makes 0 origin */
407: bit = i & 07;
408: o = (i & ~07) >> 3;
409: up->upcs1 = UP_TRE|UP_DCLR|UP_GO;
410: /*
411: * Correct while possible bits remain of mask.
412: * Since mask contains 11 bits, we continue while
413: * the bit offset is > -11. Also watch out for
414: * end of this block and the end of the transfer.
415: */
416: while (o < sectsiz && (npf*sectsiz)+o < io->i_cc && bit > -11) {
417: /*
418: * addr =
419: * (base address of transfer) +
420: * (# sectors transferred before the error) *
421: * (sector size) +
422: * (byte offset to incorrect data)
423: */
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 & UPF_ECCDEBUG)
431: printf("addr=0x%x old=0x%x ", addr,
432: (*addr&0xff));
433: *addr ^= (mask << bit);
434: if (sc->debug & UPF_ECCDEBUG)
435: printf("new=0x%x\n", (*addr&0xff));
436: }
437: o++, bit -= 8;
438: }
439: return (0);
440: }
441:
442: /*
443: * Bad sector forwarding.
444: */
445: if (flag == BSE) {
446: /*
447: * If not in bad sector table,
448: * indicate a hard error to caller.
449: */
450: up->upcs1 = UP_TRE|UP_DCLR|UP_GO;
451: if ((bbn = isbad(&upbad[io->i_adapt][io->i_ctlr][unit], cn, tn, sn)) < 0)
452: return (1);
453: bbn = (lp->d_ncylinders * lp->d_secpercyl) -
454: lp->d_nsectors - 1 - bbn;
455: twc = up->upwc + sectsiz;
456: up->upwc = - (sectsiz / sizeof (short));
457: if (sc->debug & UPF_BSEDEBUG)
458: printf("revector sn %d to %d\n", sn, bbn);
459: /*
460: * Clear the drive & read the replacement
461: * sector. If this is in the middle of a
462: * transfer, then set up the controller
463: * registers in a normal fashion.
464: * The UNIBUS address need not be changed.
465: */
466: upwaitrdy(up);
467: if (upstart(io, bbn, lp))
468: return (1); /* error */
469: io->i_errcnt = 0; /* success */
470: upwaitrdy(up);
471: if ((up->upds & UPDS_ERR) || (up->upcs1 & UP_TRE)) {
472: up->upwc = twc - sectsiz;
473: return (1);
474: }
475: }
476: if (twc)
477: up->upwc = twc;
478: return (0);
479: }
480: #endif /* !SMALL */
481:
482: upstart(io, bn, lp)
483: register struct iob *io;
484: daddr_t bn;
485: register struct disklabel *lp;
486: {
487: register struct updevice *upaddr;
488: register struct up_softc *sc;
489: int sn, tn;
490:
491: upaddr = (struct updevice *)ubamem(io->i_adapt, upstd[io->i_ctlr]);
492: sc = &up_softc[io->i_adapt][io->i_ctlr][io->i_unit];
493: sn = bn % lp->d_secpercyl;
494: tn = sn / lp->d_nsectors;
495: sn = sn % lp->d_nsectors;
496: upaddr->updc = bn / lp->d_secpercyl;
497: upaddr->upda = (tn << 8) + sn;
498: switch (io->i_flgs & F_TYPEMASK) {
499:
500: case F_RDDATA:
501: upaddr->upcs1 = UP_RCOM|UP_GO;
502: break;
503:
504: case F_WRDATA:
505: upaddr->upcs1 = UP_WCOM|UP_GO;
506: break;
507:
508: #ifndef SMALL
509: case F_HDR|F_RDDATA:
510: upaddr->upcs1 = UP_RHDR|UP_GO;
511: break;
512:
513: case F_HDR|F_WRDATA:
514: upaddr->upcs1 = UP_WHDR|UP_GO;
515: break;
516:
517: case F_CHECK|F_WRDATA:
518: case F_CHECK|F_RDDATA:
519: upaddr->upcs1 = UP_WCDATA|UP_GO;
520: break;
521:
522: case F_HCHECK|F_WRDATA:
523: case F_HCHECK|F_RDDATA:
524: upaddr->upcs1 = UP_WCHDR|UP_GO;
525: break;
526: #endif
527:
528: default:
529: io->i_error = ECMD;
530: io->i_flgs &= ~F_TYPEMASK;
531: return (1);
532: }
533: return (0);
534: }
535:
536: #ifndef SMALL
537: /*ARGSUSED*/
538: upioctl(io, cmd, arg)
539: struct iob *io;
540: int cmd;
541: caddr_t arg;
542: {
543: register struct up_softc *sc;
544:
545: sc = &up_softc[io->i_adapt][io->i_ctlr][io->i_unit];
546: switch(cmd) {
547: case SAIODEBUG:
548: sc->debug = (int)arg;
549: break;
550: case SAIODEVDATA:
551: *(struct disklabel *)arg =
552: uplabel[io->i_adapt][io->i_ctlr][io->i_unit];
553: break;
554: case SAIOGBADINFO:
555: *(struct dkbad *)arg =
556: upbad[io->i_adapt][io->i_ctlr][io->i_unit];
557: break;
558: case SAIOECCLIM:
559: sc->ecclim = (int)arg;
560: break;
561: case SAIORETRIES:
562: sc->retries = (int)arg;
563: break;
564: default:
565: return (ECMD);
566: }
567: return (0);
568: }
569: #endif /* !SMALL */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.