|
|
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: * @(#)idc.c 7.9 (Berkeley) 2/17/90 ! 7: */ ! 8: ! 9: #include "rb.h" ! 10: #if NIDC > 0 ! 11: int idcdebug = 0; ! 12: #define printd if(idcdebug)printf ! 13: int idctrb[1000]; ! 14: int *trp = idctrb; ! 15: #define trace(a,b) {*trp++ = *(int*)a; *trp++ = (int)b; if(trp>&idctrb[998])trp=idctrb;} ! 16: /* ! 17: * IDC (RB730) disk driver ! 18: * ! 19: * There can only ever be one IDC on a machine, ! 20: * and only on a VAX-11/730. We take advantage ! 21: * of that to simplify the driver. ! 22: * ! 23: * TODO: ! 24: * ecc ! 25: */ ! 26: #include "param.h" ! 27: #include "systm.h" ! 28: #include "buf.h" ! 29: #include "conf.h" ! 30: #include "user.h" ! 31: #include "map.h" ! 32: #include "vm.h" ! 33: #include "ioctl.h" ! 34: #include "disklabel.h" ! 35: #include "dkstat.h" ! 36: #include "cmap.h" ! 37: #include "dkbad.h" ! 38: #include "uio.h" ! 39: #include "kernel.h" ! 40: #include "syslog.h" ! 41: ! 42: #include "machine/pte.h" ! 43: #include "../vax/cpu.h" ! 44: #include "ubareg.h" ! 45: #include "ubavar.h" ! 46: #include "idcreg.h" ! 47: ! 48: struct idc_softc { ! 49: int sc_bcnt; /* number of bytes to transfer */ ! 50: int sc_resid; /* total number of bytes to transfer */ ! 51: int sc_ubaddr; /* Unibus address of data */ ! 52: short sc_unit; /* unit doing transfer */ ! 53: short sc_softas; /* software attention summary bits */ ! 54: union idc_dar { ! 55: long dar_l; ! 56: u_short dar_w[2]; ! 57: u_char dar_b[4]; ! 58: } sc_un; /* prototype disk address register */ ! 59: } idc_softc; ! 60: ! 61: #define dar_dar dar_l /* the whole disk address */ ! 62: #define dar_cyl dar_w[1] /* cylinder address */ ! 63: #define dar_trk dar_b[1] /* track */ ! 64: #define dar_sect dar_b[0] /* sector */ ! 65: #define sc_dar sc_un.dar_dar ! 66: #define sc_cyl sc_un.dar_cyl ! 67: #define sc_trk sc_un.dar_trk ! 68: #define sc_sect sc_un.dar_sect ! 69: ! 70: #define idcunit(dev) (minor(dev) >> 3) ! 71: ! 72: /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ ! 73: struct size { ! 74: daddr_t nblocks; ! 75: int cyloff; ! 76: } rb02_sizes[8] ={ ! 77: 15884, 0, /* A=cyl 0 thru 399 */ ! 78: 4480, 400, /* B=cyl 400 thru 510 */ ! 79: 20480, 0, /* C=cyl 0 thru 511 */ ! 80: 0, 0, ! 81: 0, 0, ! 82: 0, 0, ! 83: 0, 0, ! 84: 0, 0, ! 85: }, rb80_sizes[8] ={ ! 86: 15884, 0, /* A=cyl 0 thru 36 */ ! 87: 33440, 37, /* B=cyl 37 thru 114 */ ! 88: 242606, 0, /* C=cyl 0 thru 558 */ ! 89: 0, 0, ! 90: 0, 0, ! 91: 0, 0, ! 92: 82080, 115, /* G=cyl 115 thru 304 */ ! 93: 110143, 305, /* H=cyl 305 thru 558 */ ! 94: }; ! 95: /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ ! 96: ! 97: int idcprobe(), idcslave(), idcattach(), idcdgo(), idcintr(); ! 98: struct uba_ctlr *idcminfo[NIDC]; ! 99: struct uba_device *idcdinfo[NRB]; ! 100: ! 101: u_short idcstd[] = { 0174400, 0}; ! 102: struct uba_driver idcdriver = ! 103: { idcprobe, idcslave, idcattach, idcdgo, idcstd, "rb", idcdinfo, "idc", idcminfo, 0 }; ! 104: struct buf idcutab[NRB]; ! 105: union idc_dar idccyl[NRB]; ! 106: ! 107: struct idcst { ! 108: short nbps; ! 109: short nsect; ! 110: short ntrak; ! 111: short nspc; ! 112: short ncyl; ! 113: struct size *sizes; ! 114: } idcst[] = { ! 115: 256, NRB02SECT, NRB02TRK, NRB02SECT*NRB02TRK, NRB02CYL, rb02_sizes, ! 116: 512, NRB80SECT, NRB80TRK, NRB80SECT*NRB80TRK, NRB80CYL, rb80_sizes, ! 117: }; ! 118: ! 119: #define b_cylin b_resid ! 120: ! 121: int idcwstart, idcwticks, idcwatch(); ! 122: ! 123: /*ARGSUSED*/ ! 124: idcprobe(reg) ! 125: caddr_t reg; ! 126: { ! 127: register int br, cvec; ! 128: register struct idcdevice *idcaddr; ! 129: ! 130: #ifdef lint ! 131: br = 0; cvec = br; br = cvec; ! 132: #endif ! 133: idcaddr = (struct idcdevice *)((caddr_t)uba_hd[0].uh_uba + 0x200); ! 134: idcaddr->idccsr = IDC_ATTN|IDC_IE; ! 135: while ((idcaddr->idccsr & IDC_CRDY) == 0) ! 136: ; ! 137: idcaddr->idccsr = IDC_ATTN|IDC_CRDY; ! 138: return (sizeof (struct idcdevice)); ! 139: } ! 140: ! 141: /*ARGSUSED*/ ! 142: idcslave(ui, reg) ! 143: struct uba_device *ui; ! 144: caddr_t reg; ! 145: { ! 146: register struct idcdevice *idcaddr; ! 147: register int i; ! 148: ! 149: idcaddr = (struct idcdevice *)((caddr_t)uba_hd[0].uh_uba + 0x200); ! 150: ui->ui_type = 0; ! 151: idcaddr->idcmpr = IDCGS_GETSTAT; ! 152: idcaddr->idccsr = IDC_GETSTAT|(ui->ui_slave<<8); ! 153: (void) idcwait(idcaddr, 0); ! 154: i = idcaddr->idcmpr; ! 155: idcaddr->idccsr = IDC_CRDY|(1<<(ui->ui_slave+16)); ! 156: (void) idcwait(idcaddr, 0); ! 157: /* read header to synchronize microcode */ ! 158: idcaddr->idccsr = (ui->ui_slave<<8)|IDC_RHDR; ! 159: (void) idcwait(idcaddr, 0); ! 160: i = idcaddr->idcmpr; /* read header word 1 */ ! 161: i = idcaddr->idcmpr; /* read header word 2 */ ! 162: #ifdef lint ! 163: i = i; ! 164: #endif ! 165: if ((idcaddr->idccsr & (IDC_ERR|IDC_R80)) == IDC_R80) ! 166: ui->ui_type = 1; ! 167: else if ((idcaddr->idccsr & (IDC_DE|IDC_R80)) == 0) ! 168: /* ! 169: * RB02 may not have pack spun up, just look for drive error. ! 170: */ ! 171: ui->ui_type = 0; ! 172: else ! 173: return (0); ! 174: return (1); ! 175: } ! 176: ! 177: idcattach(ui) ! 178: register struct uba_device *ui; ! 179: { ! 180: ! 181: /* ! 182: * Fix all addresses to correspond ! 183: * to the "real" IDC address. ! 184: */ ! 185: ui->ui_mi->um_addr = ui->ui_addr = (caddr_t)uba_hd[0].uh_uba + 0x200; ! 186: ui->ui_physaddr = (caddr_t)uba_hd[0].uh_physuba + 0x200; ! 187: if (idcwstart == 0) { ! 188: timeout(idcwatch, (caddr_t)0, hz); ! 189: idcwstart++; ! 190: } ! 191: if (ui->ui_dk >= 0) ! 192: if (ui->ui_type) ! 193: dk_wpms[ui->ui_dk] = (60 * NRB80SECT * 256); ! 194: else ! 195: dk_wpms[ui->ui_dk] = (60 * NRB02SECT * 128); ! 196: idccyl[ui->ui_unit].dar_dar = -1; ! 197: ui->ui_flags = 0; ! 198: } ! 199: ! 200: idcopen(dev) ! 201: dev_t dev; ! 202: { ! 203: register int unit = idcunit(dev); ! 204: register struct uba_device *ui; ! 205: ! 206: if (unit >= NRB || (ui = idcdinfo[unit]) == 0 || ui->ui_alive == 0) ! 207: return (ENXIO); ! 208: return (0); ! 209: } ! 210: ! 211: idcstrategy(bp) ! 212: register struct buf *bp; ! 213: { ! 214: register struct uba_device *ui; ! 215: register struct idcst *st; ! 216: register int unit; ! 217: register struct buf *dp; ! 218: int xunit = minor(bp->b_dev) & 07; ! 219: long bn, sz; ! 220: ! 221: sz = (bp->b_bcount+511) >> 9; ! 222: unit = idcunit(bp->b_dev); ! 223: if (unit >= NRB) { ! 224: bp->b_error = ENXIO; ! 225: goto bad; ! 226: } ! 227: ui = idcdinfo[unit]; ! 228: if (ui == 0 || ui->ui_alive == 0) { ! 229: bp->b_error = ENXIO; ! 230: goto bad; ! 231: } ! 232: st = &idcst[ui->ui_type]; ! 233: if (bp->b_blkno < 0 || ! 234: (bn = bp->b_blkno)+sz > st->sizes[xunit].nblocks) { ! 235: if (bp->b_blkno == st->sizes[xunit].nblocks) { ! 236: bp->b_resid = bp->b_bcount; ! 237: goto done; ! 238: } ! 239: bp->b_error = EINVAL; ! 240: goto bad; ! 241: } ! 242: if (ui->ui_type == 0) ! 243: bn *= 2; ! 244: bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; ! 245: (void) spl5(); ! 246: trace("strt",bp); ! 247: dp = &idcutab[ui->ui_unit]; ! 248: disksort(dp, bp); ! 249: if (dp->b_active == 0) { ! 250: trace("!act",dp); ! 251: (void) idcustart(ui); ! 252: bp = &ui->ui_mi->um_tab; ! 253: if (bp->b_actf && bp->b_active == 0) ! 254: (void) idcstart(ui->ui_mi); ! 255: } ! 256: (void) spl0(); ! 257: return; ! 258: ! 259: bad: ! 260: bp->b_flags |= B_ERROR; ! 261: done: ! 262: iodone(bp); ! 263: return; ! 264: } ! 265: ! 266: idcustart(ui) ! 267: register struct uba_device *ui; ! 268: { ! 269: register struct buf *bp, *dp; ! 270: register struct uba_ctlr *um; ! 271: register struct idcdevice *idcaddr; ! 272: register struct idcst *st; ! 273: union idc_dar cyltrk; ! 274: daddr_t bn; ! 275: int unit; ! 276: ! 277: if (ui == 0) ! 278: return (0); ! 279: dk_busy &= ~(1<<ui->ui_dk); ! 280: dp = &idcutab[ui->ui_unit]; ! 281: um = ui->ui_mi; ! 282: unit = ui->ui_slave; ! 283: trace("ust", dp); ! 284: idcaddr = (struct idcdevice *)um->um_addr; ! 285: if (um->um_tab.b_active) { ! 286: idc_softc.sc_softas |= 1<<unit; ! 287: trace("umac",idc_softc.sc_softas); ! 288: return (0); ! 289: } ! 290: if ((bp = dp->b_actf) == NULL) { ! 291: trace("!bp",0); ! 292: return (0); ! 293: } ! 294: if (dp->b_active) { ! 295: trace("dpac",dp->b_active); ! 296: goto done; ! 297: } ! 298: dp->b_active = 1; ! 299: /* CHECK DRIVE READY? */ ! 300: bn = bp->b_blkno; ! 301: trace("seek", bn); ! 302: if (ui->ui_type == 0) ! 303: bn *= 2; ! 304: st = &idcst[ui->ui_type]; ! 305: cyltrk.dar_cyl = bp->b_cylin; ! 306: cyltrk.dar_trk = (bn / st->nsect) % st->ntrak; ! 307: cyltrk.dar_sect = 0; ! 308: printd("idcustart, unit %d, cyltrk 0x%x\n", unit, cyltrk.dar_dar); ! 309: /* ! 310: * If on cylinder, no need to seek. ! 311: */ ! 312: if (cyltrk.dar_dar == idccyl[ui->ui_unit].dar_dar) ! 313: goto done; ! 314: /* ! 315: * RB80 can change heads (tracks) just by loading ! 316: * the disk address register, perform optimization ! 317: * here instead of doing a full seek. ! 318: */ ! 319: if (ui->ui_type && cyltrk.dar_cyl == idccyl[ui->ui_unit].dar_cyl) { ! 320: idcaddr->idccsr = IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8); ! 321: idcaddr->idcdar = cyltrk.dar_dar; ! 322: idccyl[ui->ui_unit].dar_dar = cyltrk.dar_dar; ! 323: goto done; ! 324: } ! 325: /* ! 326: * Need to do a full seek. Select the unit, clear ! 327: * its attention bit, set the command, load the ! 328: * disk address register, and then go. ! 329: */ ! 330: idcaddr->idccsr = ! 331: IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8)|(1<<(unit+16)); ! 332: idcaddr->idcdar = cyltrk.dar_dar; ! 333: idccyl[ui->ui_unit].dar_dar = cyltrk.dar_dar; ! 334: printd(" seek"); ! 335: idcaddr->idccsr = IDC_IE|IDC_SEEK|(unit<<8); ! 336: if (ui->ui_dk >= 0) { ! 337: dk_busy |= 1<<ui->ui_dk; ! 338: dk_seek[ui->ui_dk]++; ! 339: } ! 340: /* ! 341: * RB80's initiate seeks very quickly. Wait for it ! 342: * to come ready rather than taking the interrupt. ! 343: */ ! 344: if (ui->ui_type) { ! 345: if (idcwait(idcaddr, 10) == 0) ! 346: return (1); ! 347: idcaddr->idccsr &= ~IDC_ATTN; ! 348: /* has the seek completed? */ ! 349: if (idcaddr->idccsr & IDC_DRDY) { ! 350: printd(", drdy"); ! 351: idcaddr->idccsr = ! 352: IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8)|(1<<(unit+16)); ! 353: goto done; ! 354: } ! 355: } ! 356: printd(", idccsr = 0x%x\n", idcaddr->idccsr); ! 357: return (1); ! 358: done: ! 359: if (dp->b_active != 2) { ! 360: trace("!=2",dp->b_active); ! 361: dp->b_forw = NULL; ! 362: if (um->um_tab.b_actf == NULL) ! 363: um->um_tab.b_actf = dp; ! 364: else { ! 365: trace("!NUL",um->um_tab.b_actl); ! 366: um->um_tab.b_actl->b_forw = dp; ! 367: } ! 368: um->um_tab.b_actl = dp; ! 369: dp->b_active = 2; ! 370: } ! 371: return (0); ! 372: } ! 373: ! 374: idcstart(um) ! 375: register struct uba_ctlr *um; ! 376: { ! 377: register struct buf *bp, *dp; ! 378: register struct uba_device *ui; ! 379: register struct idcdevice *idcaddr; ! 380: register struct idc_softc *sc; ! 381: struct idcst *st; ! 382: daddr_t bn; ! 383: int sn, tn, cmd; ! 384: ! 385: loop: ! 386: if ((dp = um->um_tab.b_actf) == NULL) { ! 387: trace("nodp",um); ! 388: return (0); ! 389: } ! 390: if ((bp = dp->b_actf) == NULL) { ! 391: trace("nobp", dp); ! 392: um->um_tab.b_actf = dp->b_forw; ! 393: goto loop; ! 394: } ! 395: um->um_tab.b_active = 1; ! 396: ui = idcdinfo[idcunit(bp->b_dev)]; ! 397: bn = bp->b_blkno; ! 398: trace("star",bp); ! 399: if (ui->ui_type == 0) ! 400: bn *= 2; ! 401: sc = &idc_softc; ! 402: st = &idcst[ui->ui_type]; ! 403: sn = bn%st->nspc; ! 404: tn = sn/st->nsect; ! 405: sn %= st->nsect; ! 406: sc->sc_sect = sn; ! 407: sc->sc_trk = tn; ! 408: sc->sc_cyl = bp->b_cylin; ! 409: idcaddr = (struct idcdevice *)ui->ui_addr; ! 410: printd("idcstart, unit %d, dar 0x%x", ui->ui_slave, sc->sc_dar); ! 411: if (bp->b_flags & B_READ) ! 412: cmd = IDC_IE|IDC_READ|(ui->ui_slave<<8); ! 413: else ! 414: cmd = IDC_IE|IDC_WRITE|(ui->ui_slave<<8); ! 415: idcaddr->idccsr = IDC_CRDY|cmd; ! 416: if ((idcaddr->idccsr&IDC_DRDY) == 0) { ! 417: printf("rb%d: not ready\n", idcunit(bp->b_dev)); ! 418: um->um_tab.b_active = 0; ! 419: um->um_tab.b_errcnt = 0; ! 420: dp->b_actf = bp->av_forw; ! 421: dp->b_active = 0; ! 422: bp->b_flags |= B_ERROR; ! 423: iodone(bp); ! 424: goto loop; ! 425: } ! 426: idccyl[ui->ui_unit].dar_dar = sc->sc_dar; ! 427: idccyl[ui->ui_unit].dar_sect = 0; ! 428: sn = (st->nsect - sn) * st->nbps; ! 429: if (sn > bp->b_bcount) ! 430: sn = bp->b_bcount; ! 431: sc->sc_bcnt = sn; ! 432: sc->sc_resid = bp->b_bcount; ! 433: sc->sc_unit = ui->ui_slave; ! 434: printd(", bcr 0x%x, cmd 0x%x\n", sn, cmd); ! 435: um->um_cmd = cmd; ! 436: (void) ubago(ui); ! 437: return (1); ! 438: } ! 439: ! 440: idcdgo(um) ! 441: register struct uba_ctlr *um; ! 442: { ! 443: register struct idcdevice *idcaddr = (struct idcdevice *)um->um_addr; ! 444: register struct idc_softc *sc = &idc_softc; ! 445: ! 446: /* ! 447: * VERY IMPORTANT: must load registers in this order. ! 448: */ ! 449: idcaddr->idcbar = sc->sc_ubaddr = UBAI_ADDR(um->um_ubinfo); ! 450: idcaddr->idcbcr = -sc->sc_bcnt; ! 451: idcaddr->idcdar = sc->sc_dar; ! 452: printd("idcdgo, ubinfo 0x%x, cmd 0x%x\n", um->um_ubinfo, um->um_cmd); ! 453: idcaddr->idccsr = um->um_cmd; ! 454: trace("go", um); ! 455: um->um_tab.b_active = 2; ! 456: /*** CLEAR SPURIOUS ATTN ON R80? ***/ ! 457: } ! 458: ! 459: idcintr(idc) ! 460: int idc; ! 461: { ! 462: register struct uba_ctlr *um = idcminfo[idc]; ! 463: register struct uba_device *ui; ! 464: register struct idcdevice *idcaddr = (struct idcdevice *)um->um_addr; ! 465: register struct idc_softc *sc = &idc_softc; ! 466: register struct buf *bp, *dp; ! 467: struct idcst *st; ! 468: int unit, as, er, cmd, ds = 0; ! 469: ! 470: printd("idcintr, idccsr 0x%x", idcaddr->idccsr); ! 471: top: ! 472: idcwticks = 0; ! 473: trace("intr", um->um_tab.b_active); ! 474: if (um->um_tab.b_active == 2) { ! 475: /* ! 476: * Process a data transfer complete interrupt. ! 477: */ ! 478: um->um_tab.b_active = 1; ! 479: dp = um->um_tab.b_actf; ! 480: bp = dp->b_actf; ! 481: ui = idcdinfo[idcunit(bp->b_dev)]; ! 482: unit = ui->ui_slave; ! 483: st = &idcst[ui->ui_type]; ! 484: idcaddr->idccsr = IDC_IE|IDC_CRDY|(unit<<8); ! 485: if ((er = idcaddr->idccsr) & IDC_ERR) { ! 486: if (er & IDC_DE) { ! 487: idcaddr->idcmpr = IDCGS_GETSTAT; ! 488: idcaddr->idccsr = IDC_GETSTAT|(unit<<8); ! 489: (void) idcwait(idcaddr, 0); ! 490: ds = idcaddr->idcmpr; ! 491: idcaddr->idccsr = ! 492: IDC_IE|IDC_CRDY|(1<<(unit+16)); ! 493: } ! 494: printd(", er 0x%x, ds 0x%x", er, ds); ! 495: if (ds & IDCDS_WL) { ! 496: printf("rb%d: write locked\n", ! 497: idcunit(bp->b_dev)); ! 498: bp->b_flags |= B_ERROR; ! 499: } else if (++um->um_tab.b_errcnt > 28 || er&IDC_HARD) { ! 500: hard: ! 501: diskerr(bp, "rb", "hard error", LOG_PRINTF, -1, ! 502: (struct disklabel *)0); ! 503: printf(" csr=%b ds=%b\n", er, IDCCSR_BITS, ds, ! 504: ui->ui_type?IDCRB80DS_BITS:IDCRB02DS_BITS); ! 505: bp->b_flags |= B_ERROR; ! 506: } else if (er & IDC_DCK) { ! 507: switch ((int)(er & IDC_ECS)) { ! 508: case IDC_ECS_NONE: ! 509: break; ! 510: case IDC_ECS_SOFT: ! 511: idcecc(ui); ! 512: break; ! 513: case IDC_ECS_HARD: ! 514: default: ! 515: goto hard; ! 516: } ! 517: } else ! 518: /* recoverable error, set up for retry */ ! 519: goto seek; ! 520: } ! 521: if ((sc->sc_resid -= sc->sc_bcnt) != 0) { ! 522: sc->sc_ubaddr += sc->sc_bcnt; ! 523: /* ! 524: * Current transfer is complete, have ! 525: * we overflowed to the next track? ! 526: */ ! 527: if ((sc->sc_sect += sc->sc_bcnt/st->nbps) == st->nsect) { ! 528: sc->sc_sect = 0; ! 529: if (++sc->sc_trk == st->ntrak) { ! 530: sc->sc_trk = 0; ! 531: sc->sc_cyl++; ! 532: } else if (ui->ui_type) { ! 533: /* ! 534: * RB80 can change heads just by ! 535: * loading the disk address register. ! 536: */ ! 537: idcaddr->idccsr = IDC_SEEK|IDC_CRDY| ! 538: IDC_IE|(unit<<8); ! 539: printd(", change to track 0x%x", sc->sc_dar); ! 540: idcaddr->idcdar = sc->sc_dar; ! 541: idccyl[ui->ui_unit].dar_dar = sc->sc_dar; ! 542: idccyl[ui->ui_unit].dar_sect = 0; ! 543: goto cont; ! 544: } ! 545: /* ! 546: * Changing tracks on RB02 or cylinders ! 547: * on RB80, start a seek. ! 548: */ ! 549: seek: ! 550: cmd = IDC_IE|IDC_SEEK|(unit<<8); ! 551: idcaddr->idccsr = cmd|IDC_CRDY; ! 552: idcaddr->idcdar = sc->sc_dar; ! 553: printd(", seek to 0x%x\n", sc->sc_dar); ! 554: idccyl[ui->ui_unit].dar_dar = sc->sc_dar; ! 555: idccyl[ui->ui_unit].dar_sect = 0; ! 556: sc->sc_bcnt = 0; ! 557: idcaddr->idccsr = cmd; ! 558: if (ui->ui_type) { ! 559: if (idcwait(idcaddr, 10) == 0) ! 560: return; ! 561: idcaddr->idccsr &= ~IDC_ATTN; ! 562: if (idcaddr->idccsr & IDC_DRDY) ! 563: goto top; ! 564: } ! 565: } else { ! 566: /* ! 567: * Continue transfer on current track. ! 568: */ ! 569: cont: ! 570: sc->sc_bcnt = (st->nsect-sc->sc_sect)*st->nbps; ! 571: if (sc->sc_bcnt > sc->sc_resid) ! 572: sc->sc_bcnt = sc->sc_resid; ! 573: if (bp->b_flags & B_READ) ! 574: cmd = IDC_IE|IDC_READ|(unit<<8); ! 575: else ! 576: cmd = IDC_IE|IDC_WRITE|(unit<<8); ! 577: idcaddr->idccsr = cmd|IDC_CRDY; ! 578: idcaddr->idcbar = sc->sc_ubaddr; ! 579: idcaddr->idcbcr = -sc->sc_bcnt; ! 580: idcaddr->idcdar = sc->sc_dar; ! 581: printd(", continue I/O 0x%x, 0x%x\n", sc->sc_dar, sc->sc_bcnt); ! 582: idcaddr->idccsr = cmd; ! 583: um->um_tab.b_active = 2; ! 584: } ! 585: return; ! 586: } ! 587: /* ! 588: * Entire transfer is done, clean up. ! 589: */ ! 590: ubadone(um); ! 591: dk_busy &= ~(1 << ui->ui_dk); ! 592: um->um_tab.b_active = 0; ! 593: um->um_tab.b_errcnt = 0; ! 594: um->um_tab.b_actf = dp->b_forw; ! 595: dp->b_active = 0; ! 596: dp->b_errcnt = 0; ! 597: dp->b_actf = bp->av_forw; ! 598: trace("done", dp); trace(&um->um_tab.b_actf, dp->b_actf); ! 599: bp->b_resid = sc->sc_resid; ! 600: printd(", iodone, resid 0x%x\n", bp->b_resid); ! 601: iodone(bp); ! 602: if (dp->b_actf) ! 603: if (idcustart(ui)) ! 604: return; ! 605: } else if (um->um_tab.b_active == 1) { ! 606: /* ! 607: * Got an interrupt while setting up for a command ! 608: * or doing a mid-transfer seek. Save any attentions ! 609: * for later and process a mid-transfer seek complete. ! 610: */ ! 611: as = idcaddr->idccsr; ! 612: idcaddr->idccsr = IDC_IE|IDC_CRDY|(as&IDC_ATTN); ! 613: as = (as >> 16) & 0xf; ! 614: unit = sc->sc_unit; ! 615: sc->sc_softas |= as & ~(1<<unit); ! 616: if (as & (1<<unit)) { ! 617: printd(", seek1 complete"); ! 618: um->um_tab.b_active = 2; ! 619: goto top; ! 620: } ! 621: printd(", as1 %o\n", as); ! 622: return; ! 623: } ! 624: /* ! 625: * Process any seek initiated or complete interrupts. ! 626: */ ! 627: as = idcaddr->idccsr; ! 628: idcaddr->idccsr = IDC_IE|IDC_CRDY|(as&IDC_ATTN); ! 629: as = ((as >> 16) & 0xf) | sc->sc_softas; ! 630: sc->sc_softas = 0; ! 631: trace("as", as); ! 632: printd(", as %o", as); ! 633: for (unit = 0; unit < NRB; unit++) ! 634: if (as & (1<<unit)) { ! 635: as &= ~(1<<unit); ! 636: idcaddr->idccsr = IDC_IE|IDC_CRDY|(unit<<8); ! 637: ui = idcdinfo[unit]; ! 638: if (ui) { ! 639: printd(", attn unit %d", unit); ! 640: if (idcaddr->idccsr & IDC_DRDY) ! 641: if (idcustart(ui)) { ! 642: sc->sc_softas = as; ! 643: return; ! 644: } ! 645: } else { ! 646: printd(", unsol. intr. unit %d", unit); ! 647: } ! 648: } ! 649: printd("\n"); ! 650: if (um->um_tab.b_actf && um->um_tab.b_active == 0) { ! 651: trace("stum",um->um_tab.b_actf); ! 652: (void) idcstart(um); ! 653: } ! 654: } ! 655: ! 656: idcwait(addr, n) ! 657: register struct idcdevice *addr; ! 658: register int n; ! 659: { ! 660: register int i; ! 661: ! 662: while (--n && (addr->idccsr & IDC_CRDY) == 0) ! 663: for (i = 10; i; i--) ! 664: ; ! 665: return (n); ! 666: } ! 667: ! 668: idcecc(ui) ! 669: register struct uba_device *ui; ! 670: { ! 671: register struct idcdevice *idc = (struct idcdevice *)ui->ui_addr; ! 672: register struct buf *bp = idcutab[ui->ui_unit].b_actf; ! 673: register struct uba_ctlr *um = ui->ui_mi; ! 674: register int i; ! 675: struct uba_regs *ubp = ui->ui_hd->uh_uba; ! 676: int bit, byte, mask; ! 677: caddr_t addr; ! 678: int reg, npf, o; ! 679: ! 680: npf = btop(idc->idcbcr + idc_softc.sc_bcnt) - 1;; ! 681: reg = btop(idc_softc.sc_ubaddr) + npf; ! 682: o = (int)bp->b_un.b_addr & PGOFSET; ! 683: um->um_tab.b_active = 1; /* Either complete or continuing... */ ! 684: diskerr(bp, "rb", "soft ecc", LOG_WARNING, npf, (struct disklabel *)0); ! 685: addlog("\n"); ! 686: mask = idc->idceccpat; ! 687: i = idc->idceccpos - 1; /* -1 makes 0 origin */ ! 688: bit = i&07; ! 689: i = (i&~07)>>3; ! 690: byte = i + o; ! 691: while (i < 512 && (int)ptob(npf)+i < idc_softc.sc_bcnt && bit > -11) { ! 692: /* ! 693: * should be: ! 694: * addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ ! 695: * (byte & PGOFSET); ! 696: * but this generates an extzv which hangs the UNIBUS. ! 697: */ ! 698: addr = ptob(*(int *)&ubp->uba_map[reg+btop(byte)]&0x1fffff)+ ! 699: (byte & PGOFSET); ! 700: putmemc(addr, getmemc(addr)^(mask<<bit)); ! 701: byte++; ! 702: i++; ! 703: bit -= 8; ! 704: } ! 705: idc_softc.sc_bcnt += idc->idcbcr; ! 706: um->um_tab.b_errcnt = 0; /* error has been corrected */ ! 707: return; ! 708: } ! 709: ! 710: idcreset(uban) ! 711: int uban; ! 712: { ! 713: register struct uba_ctlr *um; ! 714: register struct uba_device *ui; ! 715: register unit; ! 716: ! 717: if ((um = idcminfo[0]) == 0 || um->um_ubanum != uban || ! 718: um->um_alive == 0) ! 719: return; ! 720: printf(" idc0"); ! 721: um->um_tab.b_active = 0; ! 722: um->um_tab.b_actf = um->um_tab.b_actl = 0; ! 723: if (um->um_ubinfo) { ! 724: printf("<%d>", (um->um_ubinfo>>28)&0xf); ! 725: um->um_ubinfo = 0; ! 726: } ! 727: for (unit = 0; unit < NRB; unit++) { ! 728: if ((ui = idcdinfo[unit]) == 0 || ui->ui_alive == 0) ! 729: continue; ! 730: idcutab[unit].b_active = 0; ! 731: (void) idcustart(ui); ! 732: } ! 733: (void) idcstart(um); ! 734: } ! 735: ! 736: idcwatch() ! 737: { ! 738: register struct uba_ctlr *um; ! 739: register unit; ! 740: ! 741: timeout(idcwatch, (caddr_t)0, hz); ! 742: um = idcminfo[0]; ! 743: if (um == 0 || um->um_alive == 0) ! 744: return; ! 745: if (um->um_tab.b_active == 0) { ! 746: for (unit = 0; unit < NRB; unit++) ! 747: if (idcutab[unit].b_active) ! 748: goto active; ! 749: idcwticks = 0; ! 750: return; ! 751: } ! 752: active: ! 753: idcwticks++; ! 754: if (idcwticks >= 20) { ! 755: idcwticks = 0; ! 756: printf("idc0: lost interrupt\n"); ! 757: idcintr(0); ! 758: } ! 759: } ! 760: ! 761: /*ARGSUSED*/ ! 762: idcdump(dev) ! 763: dev_t dev; ! 764: { ! 765: struct idcdevice *idcaddr; ! 766: char *start; ! 767: int num, blk, unit; ! 768: struct size *sizes; ! 769: register struct uba_regs *uba; ! 770: register struct uba_device *ui; ! 771: struct idcst *st; ! 772: union idc_dar dar; ! 773: int nspg; ! 774: ! 775: unit = idcunit(dev); ! 776: if (unit >= NRB) ! 777: return (ENXIO); ! 778: #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) ! 779: ui = phys(struct uba_device *, idcdinfo[unit]); ! 780: if (ui->ui_alive == 0) ! 781: return (ENXIO); ! 782: uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; ! 783: ubainit(uba); ! 784: idcaddr = (struct idcdevice *)ui->ui_physaddr; ! 785: if (idcwait(idcaddr, 100) == 0) ! 786: return (EFAULT); ! 787: /* ! 788: * Since we can only transfer one track at a time, and ! 789: * the rl02 has 256 byte sectors, all the calculations ! 790: * are done in terms of physical sectors (i.e. num and blk ! 791: * are in sectors not NBPG blocks. ! 792: */ ! 793: st = phys(struct idcst *, &idcst[ui->ui_type]); ! 794: sizes = phys(struct size *, st->sizes); ! 795: if (dumplo < 0) ! 796: return (EINVAL); ! 797: if (dumplo + maxfree >= sizes[minor(dev)&07].nblocks) ! 798: num = sizes[minor(dev)&07].nblocks - dumplo; ! 799: nspg = NBPG / st->nbps; ! 800: num = num * nspg; ! 801: start = 0; ! 802: ! 803: while (num > 0) { ! 804: register struct pte *io; ! 805: register int i; ! 806: daddr_t bn; ! 807: ! 808: bn = (dumplo + btop(start)) * nspg; ! 809: dar.dar_cyl = bn / st->nspc + sizes[minor(dev)&07].cyloff; ! 810: bn %= st->nspc; ! 811: dar.dar_trk = bn / st->nsect; ! 812: dar.dar_sect = bn % st->nsect; ! 813: blk = st->nsect - dar.dar_sect; ! 814: if (num < blk) ! 815: blk = num; ! 816: ! 817: io = uba->uba_map; ! 818: for (i = 0; i < (blk + nspg - 1) / nspg; i++) ! 819: *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV; ! 820: *(int *)io = 0; ! 821: ! 822: idcaddr->idccsr = IDC_CRDY | IDC_SEEK | unit<<8; ! 823: if ((idcaddr->idccsr&IDC_DRDY) == 0) ! 824: return (EFAULT); ! 825: idcaddr->idcdar = dar.dar_dar; ! 826: idcaddr->idccsr = IDC_SEEK | unit << 8; ! 827: while ((idcaddr->idccsr & (IDC_CRDY|IDC_DRDY)) ! 828: != (IDC_CRDY|IDC_DRDY)) ! 829: ; ! 830: if (idcaddr->idccsr & IDC_ERR) { ! 831: printf("rb%d: seek, csr=%b\n", ! 832: unit, idcaddr->idccsr, IDCCSR_BITS); ! 833: return (EIO); ! 834: } ! 835: ! 836: idcaddr->idccsr = IDC_CRDY | IDC_WRITE | unit<<8; ! 837: if ((idcaddr->idccsr&IDC_DRDY) == 0) ! 838: return (EFAULT); ! 839: idcaddr->idcbar = 0; /* start addr 0 */ ! 840: idcaddr->idcbcr = - (blk * st->nbps); ! 841: idcaddr->idcdar = dar.dar_dar; ! 842: idcaddr->idccsr = IDC_WRITE | unit << 8; ! 843: while ((idcaddr->idccsr & (IDC_CRDY|IDC_DRDY)) ! 844: != (IDC_CRDY|IDC_DRDY)) ! 845: ; ! 846: if (idcaddr->idccsr & IDC_ERR) { ! 847: printf("rb%d: write, csr=%b\n", ! 848: unit, idcaddr->idccsr, IDCCSR_BITS); ! 849: return (EIO); ! 850: } ! 851: ! 852: start += blk * st->nbps; ! 853: num -= blk; ! 854: } ! 855: return (0); ! 856: } ! 857: ! 858: idcsize(dev) ! 859: dev_t dev; ! 860: { ! 861: int unit = idcunit(dev); ! 862: struct uba_device *ui; ! 863: struct idcst *st; ! 864: ! 865: if (unit >= NRB || (ui = idcdinfo[unit]) == 0 || ui->ui_alive == 0) ! 866: return (-1); ! 867: st = &idcst[ui->ui_type]; ! 868: return (st->sizes[minor(dev) & 07].nblocks); ! 869: } ! 870: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.