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