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: }