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