|
|
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.