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