|
|
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: * @(#)hp.c 7.1 (Berkeley) 6/5/86 ! 7: */ ! 8: ! 9: /* ! 10: * RP??/RM?? disk driver ! 11: * with ECC handling and bad block forwarding. ! 12: * Also supports header io operations and ! 13: * commands to write check header and data. ! 14: */ ! 15: #include "../h/param.h" ! 16: #include "../h/inode.h" ! 17: #include "../h/fs.h" ! 18: #include "../h/dkbad.h" ! 19: ! 20: #include "../vax/pte.h" ! 21: #include "../vaxmba/hpreg.h" ! 22: #include "../vaxmba/mbareg.h" ! 23: ! 24: #include "saio.h" ! 25: #include "savax.h" ! 26: ! 27: #define RETRIES 27 ! 28: ! 29: #define MASKREG(reg) ((reg)&0xffff) ! 30: ! 31: #define MAXBADDESC 126 ! 32: #define SECTSIZ 512 /* sector size in bytes */ ! 33: #define HDRSIZ 4 /* number of bytes in sector header */ ! 34: ! 35: extern struct st hpst[]; ! 36: extern short hptypes[]; ! 37: ! 38: #define RP06 (hptypes[sc->type] == MBDT_RP06 || hptypes[sc->type] == MBDT_RP05 \ ! 39: || hptypes[sc->type] == MBDT_RP04) ! 40: #define ML11 (hptypes[sc->type] == MBDT_ML11A) ! 41: #define RM80 (hptypes[sc->type] == MBDT_RM80) ! 42: ! 43: u_char hp_offset[16] = { ! 44: HPOF_P400, HPOF_M400, HPOF_P400, HPOF_M400, ! 45: HPOF_P800, HPOF_M800, HPOF_P800, HPOF_M800, ! 46: HPOF_P1200, HPOF_M1200, HPOF_P1200, HPOF_M1200, ! 47: 0, 0, 0, 0, ! 48: }; ! 49: ! 50: struct dkbad hpbad[MAXNMBA*8]; ! 51: ! 52: struct hp_softc { ! 53: char type; ! 54: char gottype; ! 55: char ssect; /* 1 when on track w/skip sector */ ! 56: char debug; ! 57: # define HPF_BSEDEBUG 01 /* debugging bad sector forwarding */ ! 58: # define HPF_ECCDEBUG 02 /* debugging ecc correction */ ! 59: int ecclim; ! 60: int retries; ! 61: } hp_softc[MAXNMBA * 8]; ! 62: ! 63: int sectsiz; ! 64: ! 65: /* ! 66: * When awaiting command completion, don't ! 67: * hang on to the status register since ! 68: * this ties up some controllers. ! 69: */ ! 70: #define HPWAIT(addr) \ ! 71: while ((((addr)->hpds)&HPDS_DRY)==0) DELAY(500); ! 72: ! 73: hpopen(io) ! 74: register struct iob *io; ! 75: { ! 76: register unit = io->i_unit; ! 77: struct hpdevice *hpaddr = (struct hpdevice *)mbadrv(unit); ! 78: register struct st *st; ! 79: register struct hp_softc *sc = &hp_softc[unit]; ! 80: ! 81: mbainit(UNITTOMBA(unit)); ! 82: if (sc->gottype == 0) { ! 83: register i, type = hpaddr->hpdt & MBDT_TYPE; ! 84: struct iob tio; ! 85: ! 86: for (i = 0; hptypes[i]; i++) ! 87: if (hptypes[i] == type) ! 88: goto found; ! 89: _stop("unknown drive type"); ! 90: found: ! 91: sc->retries = RETRIES; ! 92: sc->ecclim = 11; ! 93: sc->debug = 0; ! 94: hpaddr->hpcs1 = HP_DCLR|HP_GO; /* init drive */ ! 95: hpaddr->hpcs1 = HP_PRESET|HP_GO; ! 96: if (!ML11) ! 97: hpaddr->hpof = HPOF_FMT22; ! 98: sc->type = hpmaptype(hpaddr, i, UNITTODRIVE(unit)); ! 99: /* ! 100: * Read in the bad sector table. ! 101: */ ! 102: st = &hpst[sc->type]; ! 103: tio = *io; ! 104: tio.i_bn = st->nspc * st->ncyl - st->nsect; ! 105: tio.i_ma = (char *)&hpbad[unit]; ! 106: tio.i_cc = sizeof (struct dkbad); ! 107: tio.i_flgs |= F_RDDATA; ! 108: for (i = 0; i < 5; i++) { ! 109: if (hpstrategy(&tio, READ) == sizeof (struct dkbad)) ! 110: break; ! 111: tio.i_bn += 2; ! 112: } ! 113: if (i == 5) { ! 114: printf("Unable to read bad sector table\n"); ! 115: for (i = 0; i < MAXBADDESC; i++) { ! 116: hpbad[unit].bt_bad[i].bt_cyl = -1; ! 117: hpbad[unit].bt_bad[i].bt_trksec = -1; ! 118: } ! 119: } ! 120: sc->gottype = 1; ! 121: } ! 122: st = &hpst[sc->type]; ! 123: if (io->i_boff < 0 || io->i_boff > 7 || ! 124: st->off[io->i_boff]== -1) ! 125: _stop("hp bad minor"); ! 126: io->i_boff = st->off[io->i_boff] * st->nspc; ! 127: } ! 128: ! 129: hpstrategy(io, func) ! 130: register struct iob *io; ! 131: { ! 132: register unit = io->i_unit; ! 133: struct mba_regs *mba = mbamba(unit); ! 134: daddr_t bn, startblock; ! 135: struct hpdevice *hpaddr = (struct hpdevice *)mbadrv(unit); ! 136: register struct hp_softc *sc = &hp_softc[unit]; ! 137: struct st *st = &hpst[sc->type]; ! 138: int cn, tn, sn, bytecnt, bytesleft, rv; ! 139: char *membase; ! 140: int er1, er2, hprecal; ! 141: ! 142: sectsiz = SECTSIZ; ! 143: if ((io->i_flgs & (F_HDR|F_HCHECK)) != 0) ! 144: sectsiz += HDRSIZ; ! 145: if ((hpaddr->hpds & HPDS_VV) == 0) { ! 146: hpaddr->hpcs1 = HP_DCLR|HP_GO; ! 147: hpaddr->hpcs1 = HP_PRESET|HP_GO; ! 148: if (!ML11) ! 149: hpaddr->hpof = HPOF_FMT22; ! 150: } ! 151: io->i_errcnt = 0; ! 152: sc->ssect = 0; ! 153: rv = bytecnt = io->i_cc; ! 154: membase = io->i_ma; ! 155: startblock = io->i_bn; ! 156: hprecal = 0; ! 157: ! 158: restart: ! 159: bn = io->i_bn; ! 160: cn = bn/st->nspc; ! 161: sn = bn%st->nspc; ! 162: tn = sn/st->nsect; ! 163: sn = sn%st->nsect + sc->ssect; ! 164: ! 165: HPWAIT(hpaddr); ! 166: mba->mba_sr = -1; ! 167: if (ML11) ! 168: hpaddr->hpda = bn; ! 169: else { ! 170: hpaddr->hpdc = cn; ! 171: hpaddr->hpda = (tn << 8) + sn; ! 172: } ! 173: if (mbastart(io, func) != 0) { /* start transfer */ ! 174: rv = -1; ! 175: goto done; ! 176: } ! 177: HPWAIT(hpaddr); ! 178: /* ! 179: * Successful data transfer, return. ! 180: */ ! 181: if ((hpaddr->hpds&HPDS_ERR) == 0 && (mba->mba_sr&MBSR_EBITS) == 0) ! 182: goto done; ! 183: ! 184: /* ! 185: * Error handling. Calculate location of error. ! 186: */ ! 187: bytesleft = MASKREG(mba->mba_bcr); ! 188: if (bytesleft) ! 189: bytesleft |= 0xffff0000; /* sxt */ ! 190: bn = io->i_bn + (io->i_cc + bytesleft) / sectsiz; ! 191: er1 = MASKREG(hpaddr->hper1); ! 192: er2 = MASKREG(hpaddr->hper2); ! 193: if (er1 & (HPER1_DCK|HPER1_ECH)) ! 194: bn--; /* Error is in Prev block */ ! 195: cn = bn/st->nspc; ! 196: sn = bn%st->nspc; ! 197: tn = sn/st->nsect; ! 198: sn = sn%st->nsect; ! 199: if (sc->debug & (HPF_ECCDEBUG|HPF_BSEDEBUG)) { ! 200: printf("hp error: sn%d (cyl,trk,sec)=(%d,%d,%d) ds=%b\n", ! 201: bn, cn, tn, sn, MASKREG(hpaddr->hpds), HPDS_BITS); ! 202: printf("er1=%b er2=%b\n", er1, HPER1_BITS, er2, HPER2_BITS); ! 203: printf("bytes left: %d, of 0x%x, da 0x%x\n",-bytesleft, ! 204: hpaddr->hpof, hpaddr->hpda); ! 205: } ! 206: if (er1 & HPER1_HCRC) { ! 207: er1 &= ~(HPER1_HCE|HPER1_FER); ! 208: er2 &= ~HPER2_BSE; ! 209: if ((io->i_flgs&F_NBSF) == 0 && hpecc(io, BSE) == 0) ! 210: goto success; ! 211: } ! 212: /* ! 213: * Give up early if drive write locked. ! 214: */ ! 215: if (er1&HPER1_WLE) { ! 216: printf("hp%d: write locked\n", unit); ! 217: rv = -1; ! 218: goto done; ! 219: } ! 220: /* ! 221: * Skip sector handling. ! 222: */ ! 223: if (RM80 && (er2 & HPER2_SSE)) { ! 224: (void) hpecc(io, SSE); ! 225: sc->ssect = 1; ! 226: goto restart; ! 227: } ! 228: /* ! 229: * Attempt to forward bad sectors on anything but an ML11. ! 230: * Interpret format error bit as a bad block on RP06's. ! 231: */ ! 232: if (((er2 & HPER2_BSE) && !ML11) || ! 233: (MASKREG(er1) == HPER1_FER && RP06)) { ! 234: if (io->i_flgs & F_NBSF) { ! 235: io->i_error = EBSE; ! 236: goto hard; ! 237: } ! 238: if (hpecc(io, BSE) == 0) ! 239: goto success; ! 240: io->i_error = EBSE; ! 241: goto hard; ! 242: } ! 243: /* ! 244: * ECC correction? ! 245: */ ! 246: if ((er1 & (HPER1_DCK|HPER1_ECH)) == HPER1_DCK) { ! 247: if (hpecc(io, ECC) == 0) ! 248: goto success; ! 249: io->i_error = EECC; ! 250: goto hard; ! 251: } ! 252: ! 253: /* ! 254: * If a hard error, or maximum retry count ! 255: * exceeded, clear controller state and ! 256: * pass back error to caller. ! 257: */ ! 258: if (++io->i_errcnt > sc->retries || (er1 & HPER1_HARD) || ! 259: (!ML11 && (er2 & HPER2_HARD)) || (ML11 && (io->i_errcnt >= 16))) { ! 260: io->i_error = EHER; ! 261: if (mba->mba_sr & (MBSR_WCKUP|MBSR_WCKLWR)) ! 262: io->i_error = EWCK; ! 263: hard: ! 264: io->i_errblk = bn + sc->ssect; ! 265: if (sc->debug & (HPF_BSEDEBUG|HPF_ECCDEBUG)) ! 266: printf(" dc=%d, da=0x%x",MASKREG(hpaddr->hpdc), ! 267: MASKREG(hpaddr->hpda)); ! 268: else { ! 269: printf("hp error: sn%d (cyl,trk,sec)=(%d,%d,%d) ds=%b \n", ! 270: bn, cn, tn, sn, MASKREG(hpaddr->hpds), HPDS_BITS); ! 271: printf("er1=%b er2=%b", er1, HPER1_BITS, er2, HPER2_BITS); ! 272: } ! 273: hpaddr->hpcs1 = HP_DCLR|HP_GO; ! 274: printf("\n"); ! 275: rv = -1; ! 276: goto done; ! 277: ! 278: } ! 279: /* fall thru to retry */ ! 280: hpaddr->hpcs1 = HP_DCLR|HP_GO; ! 281: HPWAIT(hpaddr); ! 282: ! 283: /* ! 284: * Every fourth retry recalibrate. ! 285: */ ! 286: if (((io->i_errcnt & 07) == 4) ) { ! 287: hpaddr->hpcs1 = HP_RECAL|HP_GO; ! 288: HPWAIT(hpaddr); ! 289: hpaddr->hpdc = cn; ! 290: hpaddr->hpcs1 = HP_SEEK|HP_GO; ! 291: HPWAIT(hpaddr); ! 292: } ! 293: ! 294: if (io->i_errcnt >= 16 && (io->i_flgs & F_READ)) { ! 295: hpaddr->hpof = hp_offset[io->i_errcnt & 017]|HPOF_FMT22; ! 296: hpaddr->hpcs1 = HP_OFFSET|HP_GO; ! 297: HPWAIT(hpaddr); ! 298: } ! 299: if (sc->debug & (HPF_ECCDEBUG|HPF_BSEDEBUG)) ! 300: printf("restart: bn=%d, cc=%d, ma=0x%x hprecal=%d\n", ! 301: io->i_bn, io->i_cc, io->i_ma, hprecal); ! 302: goto restart; ! 303: ! 304: success: ! 305: /* ! 306: * On successful error recovery, bump ! 307: * block number to advance to next portion ! 308: * of i/o transfer. ! 309: */ ! 310: bn++; ! 311: if ((bn-startblock) * sectsiz < bytecnt) { ! 312: io->i_bn = bn; ! 313: io->i_ma = membase + (io->i_bn - startblock)*sectsiz; ! 314: io->i_cc = bytecnt - (io->i_bn - startblock)*sectsiz; ! 315: if (sc->debug & (HPF_ECCDEBUG|HPF_BSEDEBUG)) ! 316: printf("restart: bn=%d, cc=%d, ma=0x%x hprecal=%d\n", ! 317: io->i_bn, io->i_cc, io->i_ma, hprecal); ! 318: goto restart; ! 319: } ! 320: done: ! 321: if (io->i_errcnt >= 16) { ! 322: hpaddr->hpcs1 = HP_RTC|HP_GO; ! 323: while (hpaddr->hpds & HPDS_PIP) ! 324: ; ! 325: } ! 326: io->i_bn = startblock; /*reset i_bn to original */ ! 327: io->i_cc = bytecnt; /*reset i_cc to total count xfered*/ ! 328: io->i_ma = membase; /*reset i_ma to original */ ! 329: return (rv); ! 330: } ! 331: ! 332: hpecc(io, flag) ! 333: register struct iob *io; ! 334: int flag; ! 335: { ! 336: register unit = io->i_unit; ! 337: register struct mba_regs *mbp = mbamba(unit); ! 338: register struct hpdevice *rp = (struct hpdevice *)mbadrv(unit); ! 339: register struct hp_softc *sc = &hp_softc[unit]; ! 340: register struct st *st = &hpst[sc->type]; ! 341: int npf, bn, cn, tn, sn, bcr; ! 342: ! 343: bcr = MASKREG(mbp->mba_bcr); ! 344: if (bcr) ! 345: bcr |= 0xffff0000; /* sxt */ ! 346: npf = (bcr + io->i_cc) / sectsiz; /* # sectors read */ ! 347: if (flag == ECC) ! 348: npf--; /* Error is in prev block --ghg */ ! 349: bn = io->i_bn + npf + sc->ssect; /* physical block #*/ ! 350: if (sc->debug & HPF_ECCDEBUG) ! 351: printf("bcr=%d npf=%d ssect=%d sectsiz=%d i_cc=%d\n", ! 352: bcr, npf, sc->ssect, sectsiz, io->i_cc); ! 353: /* ! 354: * ECC correction logic. ! 355: */ ! 356: if (flag == ECC) { ! 357: register int i; ! 358: caddr_t addr; ! 359: int bit, o, mask; ! 360: ! 361: printf("hp%d: soft ecc sn%d\n", unit, bn); ! 362: mask = MASKREG(rp->hpec2); ! 363: for (i = mask, bit = 0; i; i >>= 1) ! 364: if (i & 1) ! 365: bit++; ! 366: if (bit > sc->ecclim) { ! 367: printf("%d-bit error\n", bit); ! 368: return (1); ! 369: } ! 370: i = MASKREG(rp->hpec1) - 1; /* -1 makes 0 origin */ ! 371: bit = i&07; ! 372: o = (i & ~07) >> 3; ! 373: rp->hpcs1 = HP_DCLR | HP_GO; ! 374: while (o <sectsiz && npf*sectsiz + o < io->i_cc && bit > -11) { ! 375: addr = io->i_ma + (npf*sectsiz) + o; ! 376: /* ! 377: * No data transfer occurs with a write check, ! 378: * so don't correct the resident copy of data. ! 379: */ ! 380: if ((io->i_flgs & (F_CHECK|F_HCHECK)) == 0) { ! 381: if (sc->debug & HPF_ECCDEBUG) ! 382: printf("addr=%x old=%x ", addr, ! 383: (*addr & 0xff)); ! 384: *addr ^= (mask << bit); ! 385: if (sc->debug & HPF_ECCDEBUG) ! 386: printf("new=%x\n",(*addr & 0xff)); ! 387: } ! 388: o++, bit -= 8; ! 389: } ! 390: return (0); ! 391: } ! 392: ! 393: /* ! 394: * Skip sector error. ! 395: * Set skip-sector-inhibit and ! 396: * read next sector ! 397: */ ! 398: if (flag == SSE) { ! 399: rp->hpcs1 = HP_DCLR | HP_GO; ! 400: HPWAIT(rp); ! 401: rp->hpof |= HPOF_SSEI; ! 402: return (0); ! 403: } ! 404: ! 405: /* ! 406: * Bad block forwarding. ! 407: */ ! 408: if (flag == BSE) { ! 409: int bbn; ! 410: ! 411: rp->hpcs1 = HP_DCLR | HP_GO; ! 412: if (sc->debug & HPF_BSEDEBUG) ! 413: printf("hpecc: BSE @ bn %d\n", bn); ! 414: cn = bn/st->nspc; ! 415: sn = bn%st->nspc; ! 416: tn = sn/st->nsect; ! 417: sn = sn%st->nsect; ! 418: bcr += sectsiz; ! 419: if ((bbn = isbad(&hpbad[unit], cn, tn, sn)) < 0) ! 420: return (1); ! 421: bbn = st->ncyl*st->nspc - st->nsect - 1 - bbn; ! 422: cn = bbn/st->nspc; ! 423: sn = bbn%st->nspc; ! 424: tn = sn/st->nsect; ! 425: sn = sn%st->nsect; ! 426: io->i_cc = sectsiz; ! 427: io->i_ma += npf*sectsiz; ! 428: if (sc->debug & HPF_BSEDEBUG) ! 429: printf("revector to cn %d tn %d sn %d\n", cn, tn, sn); ! 430: rp->hpof &= ~HPOF_SSEI; ! 431: mbp->mba_sr = -1; ! 432: rp->hpdc = cn; ! 433: rp->hpda = (tn<<8) + sn; ! 434: mbastart(io,io->i_flgs); ! 435: io->i_errcnt = 0; ! 436: HPWAIT(rp); ! 437: return (rp->hpds&HPDS_ERR); ! 438: } ! 439: printf("hpecc: flag=%d\n", flag); ! 440: return (1); ! 441: } ! 442: ! 443: /*ARGSUSED*/ ! 444: hpioctl(io, cmd, arg) ! 445: struct iob *io; ! 446: int cmd; ! 447: caddr_t arg; ! 448: { ! 449: register unit = io->i_unit; ! 450: register struct hp_softc *sc = &hp_softc[unit]; ! 451: struct st *st = &hpst[sc->type]; ! 452: struct mba_drv *drv = mbadrv(unit); ! 453: ! 454: switch(cmd) { ! 455: ! 456: case SAIODEBUG: ! 457: sc->debug = (int)arg; ! 458: break; ! 459: ! 460: case SAIODEVDATA: ! 461: if (drv->mbd_dt&MBDT_TAP) ! 462: return (ECMD); ! 463: *(struct st *)arg = *st; ! 464: break; ! 465: ! 466: case SAIOGBADINFO: ! 467: if (drv->mbd_dt&MBDT_TAP) ! 468: return (ECMD); ! 469: *(struct dkbad *)arg = hpbad[unit]; ! 470: break; ! 471: ! 472: case SAIOECCLIM: ! 473: sc->ecclim = (int)arg; ! 474: break; ! 475: ! 476: case SAIORETRIES: ! 477: sc->retries = (int)arg; ! 478: break; ! 479: ! 480: case SAIOSSI: /* skip-sector-inhibit */ ! 481: if (drv->mbd_dt&MBDT_TAP) ! 482: return (ECMD); ! 483: if ((io->i_flgs&F_SSI) == 0) { ! 484: /* make sure this is done once only */ ! 485: io->i_flgs |= F_SSI; ! 486: st->nsect++; ! 487: st->nspc += st->ntrak; ! 488: } ! 489: break; ! 490: ! 491: case SAIONOSSI: /* remove skip-sector-inhibit */ ! 492: if (io->i_flgs & F_SSI) { ! 493: io->i_flgs &= ~F_SSI; ! 494: drv->mbd_of &= ~HPOF_SSEI; ! 495: st->nsect--; ! 496: st->nspc -= st->ntrak; ! 497: } ! 498: break; ! 499: ! 500: case SAIOSSDEV: /* drive have skip sector? */ ! 501: return (RM80 ? 0 : ECMD); ! 502: ! 503: default: ! 504: return (ECMD); ! 505: } ! 506: return (0); ! 507: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.