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