1*17558Skarels /* idc.c 6.3 84/12/20 */ 26941Ssam 36941Ssam #include "rb.h" 46941Ssam #if NIDC > 0 58569Sroot int idcdebug = 0; 68569Sroot #define printd if(idcdebug)printf 78569Sroot int idctrb[1000]; 88569Sroot int *trp = idctrb; 98608Sroot #define trace(a,b) {*trp++ = *(int*)a; *trp++ = (int)b; if(trp>&idctrb[998])trp=idctrb;} 106941Ssam /* 116941Ssam * IDC (RB730) disk driver 126941Ssam * 136941Ssam * There can only ever be one IDC on a machine, 146941Ssam * and only on a VAX-11/730. We take advantage 156941Ssam * of that to simplify the driver. 166941Ssam * 176941Ssam * TODO: 186941Ssam * dk_busy 196941Ssam * ecc 206941Ssam */ 219774Ssam #include "../machine/pte.h" 229774Ssam 2317073Sbloom #include "param.h" 2417073Sbloom #include "systm.h" 2517073Sbloom #include "buf.h" 2617073Sbloom #include "conf.h" 2717073Sbloom #include "dir.h" 2817073Sbloom #include "user.h" 2917073Sbloom #include "map.h" 3017073Sbloom #include "vm.h" 3117073Sbloom #include "dk.h" 3217073Sbloom #include "cmap.h" 3317073Sbloom #include "dkbad.h" 3417073Sbloom #include "uio.h" 3517073Sbloom #include "kernel.h" 366941Ssam 378475Sroot #include "../vax/cpu.h" 3817073Sbloom #include "ubareg.h" 3917073Sbloom #include "ubavar.h" 4017073Sbloom #include "idcreg.h" 416941Ssam 426941Ssam struct idc_softc { 436941Ssam int sc_bcnt; /* number of bytes to transfer */ 446941Ssam int sc_resid; /* total number of bytes to transfer */ 456941Ssam int sc_ubaddr; /* Unibus address of data */ 466941Ssam short sc_unit; /* unit doing transfer */ 476941Ssam short sc_softas; /* software attention summary bits */ 486941Ssam union idc_dar { 496941Ssam long dar_l; 506941Ssam u_short dar_w[2]; 516941Ssam u_char dar_b[4]; 526941Ssam } sc_un; /* prototype disk address register */ 536941Ssam } idc_softc; 546941Ssam 556941Ssam #define dar_dar dar_l /* the whole disk address */ 566941Ssam #define dar_cyl dar_w[1] /* cylinder address */ 576941Ssam #define dar_trk dar_b[1] /* track */ 586941Ssam #define dar_sect dar_b[0] /* sector */ 596941Ssam #define sc_dar sc_un.dar_dar 606941Ssam #define sc_cyl sc_un.dar_cyl 616941Ssam #define sc_trk sc_un.dar_trk 626941Ssam #define sc_sect sc_un.dar_sect 636941Ssam 646941Ssam /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 656941Ssam struct size { 666941Ssam daddr_t nblocks; 676941Ssam int cyloff; 686941Ssam } rb02_sizes[8] ={ 696941Ssam 15884, 0, /* A=cyl 0 thru 399 */ 706941Ssam 4480, 400, /* B=cyl 400 thru 510 */ 716941Ssam 20480, 0, /* C=cyl 0 thru 511 */ 726941Ssam 0, 0, 736941Ssam 0, 0, 746941Ssam 0, 0, 756941Ssam 0, 0, 766941Ssam 0, 0, 776941Ssam }, rb80_sizes[8] ={ 786941Ssam 15884, 0, /* A=cyl 0 thru 36 */ 796941Ssam 33440, 37, /* B=cyl 37 thru 114 */ 806941Ssam 242606, 0, /* C=cyl 0 thru 558 */ 816941Ssam 0, 0, 826941Ssam 0, 0, 836941Ssam 0, 0, 846941Ssam 82080, 115, /* G=cyl 115 thru 304 */ 856941Ssam 110143, 305, /* H=cyl 305 thru 558 */ 866941Ssam }; 876941Ssam /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 886941Ssam 896941Ssam int idcprobe(), idcslave(), idcattach(), idcdgo(), idcintr(); 906941Ssam struct uba_ctlr *idcminfo[NIDC]; 916941Ssam struct uba_device *idcdinfo[NRB]; 926941Ssam 936941Ssam u_short idcstd[] = { 0174400, 0}; 946941Ssam struct uba_driver idcdriver = 956941Ssam { idcprobe, idcslave, idcattach, idcdgo, idcstd, "rb", idcdinfo, "idc", idcminfo, 0 }; 966941Ssam struct buf idcutab[NRB]; 976941Ssam union idc_dar idccyl[NRB]; 986941Ssam 996941Ssam struct idcst { 1006941Ssam short nbps; 1016941Ssam short nsect; 1026941Ssam short ntrak; 1036941Ssam short nspc; 1046941Ssam short ncyl; 1056941Ssam struct size *sizes; 1066941Ssam } idcst[] = { 1076941Ssam 256, NRB02SECT, NRB02TRK, NRB02SECT*NRB02TRK, NRB02CYL, rb02_sizes, 1086941Ssam 512, NRB80SECT, NRB80TRK, NRB80SECT*NRB80TRK, NRB80CYL, rb80_sizes, 1096941Ssam }; 1106941Ssam 1116941Ssam struct buf ridcbuf[NRB]; 1126941Ssam 1136941Ssam #define b_cylin b_resid 1146941Ssam 1156941Ssam #ifdef INTRLVE 1166941Ssam daddr_t dkblock(); 1176941Ssam #endif 1186941Ssam 1196941Ssam int idcwstart, idcwticks, idcwatch(); 1206941Ssam 1218608Sroot /*ARGSUSED*/ 1226941Ssam idcprobe(reg) 1236941Ssam caddr_t reg; 1246941Ssam { 1256941Ssam register int br, cvec; 1266941Ssam register struct idcdevice *idcaddr; 1276941Ssam 1286941Ssam #ifdef lint 1296941Ssam br = 0; cvec = br; br = cvec; 1306941Ssam #endif 1316941Ssam idcaddr = (struct idcdevice *)((caddr_t)uba_hd[0].uh_uba + 0x200); 1326941Ssam idcaddr->idccsr = IDC_ATTN|IDC_IE; 1336941Ssam while ((idcaddr->idccsr & IDC_CRDY) == 0) 1346941Ssam ; 1356941Ssam idcaddr->idccsr = IDC_ATTN|IDC_CRDY; 1367414Skre return (sizeof (struct idcdevice)); 1376941Ssam } 1386941Ssam 1398608Sroot /*ARGSUSED*/ 1406941Ssam idcslave(ui, reg) 1416941Ssam struct uba_device *ui; 1426941Ssam caddr_t reg; 1436941Ssam { 1446941Ssam register struct idcdevice *idcaddr; 1456941Ssam register int i; 1466941Ssam 1476941Ssam idcaddr = (struct idcdevice *)((caddr_t)uba_hd[0].uh_uba + 0x200); 1486941Ssam ui->ui_type = 0; 1496941Ssam idcaddr->idcmpr = IDCGS_GETSTAT; 1506941Ssam idcaddr->idccsr = IDC_GETSTAT|(ui->ui_slave<<8); 1518721Sroot (void) idcwait(idcaddr, 0); 1526941Ssam i = idcaddr->idcmpr; 1536941Ssam idcaddr->idccsr = IDC_CRDY|(1<<(ui->ui_slave+16)); 1548721Sroot (void) idcwait(idcaddr, 0); 155*17558Skarels if (idcaddr->idccsr&IDC_R80) { 156*17558Skarels /* read header to synchronize microcode */ 157*17558Skarels idcaddr->idccsr = (ui->ui_slave<<8)|IDC_RHDR; 158*17558Skarels (void) idcwait(idcaddr, 0); 159*17558Skarels if (idcaddr->idccsr & IDC_ERR) 160*17558Skarels return (0); 161*17558Skarels i = idcaddr->idcmpr; /* read header word 1 */ 162*17558Skarels i = idcaddr->idcmpr; /* read header word 2 */ 1638608Sroot #ifdef lint 164*17558Skarels i = i; 1658608Sroot #endif 1666941Ssam ui->ui_type = 1; 167*17558Skarels } else 168*17558Skarels /* 169*17558Skarels * RB02 may not have pack spun up, just look for drive error. 170*17558Skarels */ 171*17558Skarels if (idcaddr->idccsr & IDC_DE) 172*17558Skarels return (0); 1736941Ssam return (1); 1746941Ssam } 1756941Ssam 1766941Ssam idcattach(ui) 1776941Ssam register struct uba_device *ui; 1786941Ssam { 1796941Ssam 1806941Ssam /* 1816941Ssam * Fix all addresses to correspond 1826941Ssam * to the "real" IDC address. 1836941Ssam */ 1846941Ssam ui->ui_mi->um_addr = ui->ui_addr = (caddr_t)uba_hd[0].uh_uba + 0x200; 1856941Ssam ui->ui_physaddr = (caddr_t)uba_hd[0].uh_physuba + 0x200; 1866941Ssam if (idcwstart == 0) { 1876941Ssam timeout(idcwatch, (caddr_t)0, hz); 1886941Ssam idcwstart++; 1896941Ssam } 1906941Ssam if (ui->ui_dk >= 0) 1916941Ssam if (ui->ui_type) 1926941Ssam dk_mspw[ui->ui_dk] = 1.0 / (60 * NRB80SECT * 256); 1936941Ssam else 1946941Ssam dk_mspw[ui->ui_dk] = 1.0 / (60 * NRB02SECT * 128); 1956941Ssam idccyl[ui->ui_unit].dar_dar = -1; 1966941Ssam ui->ui_flags = 0; 1976941Ssam } 1988569Sroot 1998569Sroot idcopen(dev) 2008569Sroot dev_t dev; 2018569Sroot { 2028569Sroot register int unit = minor(dev) >> 3; 2038569Sroot register struct uba_device *ui; 2048569Sroot 2058569Sroot if (unit >= NRB || (ui = idcdinfo[unit]) == 0 || ui->ui_alive == 0) 2068569Sroot return (ENXIO); 2078569Sroot return (0); 2088569Sroot } 2096941Ssam 2106941Ssam idcstrategy(bp) 2116941Ssam register struct buf *bp; 2126941Ssam { 2136941Ssam register struct uba_device *ui; 2146941Ssam register struct idcst *st; 2156941Ssam register int unit; 2166941Ssam register struct buf *dp; 2176941Ssam int xunit = minor(bp->b_dev) & 07; 2186941Ssam long bn, sz; 2196941Ssam 2206941Ssam sz = (bp->b_bcount+511) >> 9; 2216941Ssam unit = dkunit(bp); 2226941Ssam if (unit >= NRB) 2236941Ssam goto bad; 2246941Ssam ui = idcdinfo[unit]; 2256941Ssam if (ui == 0 || ui->ui_alive == 0) 2266941Ssam goto bad; 2276941Ssam st = &idcst[ui->ui_type]; 2286941Ssam if (bp->b_blkno < 0 || 2296941Ssam (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) 2306941Ssam goto bad; 2316941Ssam if (ui->ui_type == 0) 2326941Ssam bn *= 2; 2336941Ssam bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 2346941Ssam (void) spl5(); 2358608Sroot trace("strt",bp); 2366941Ssam dp = &idcutab[ui->ui_unit]; 2376941Ssam disksort(dp, bp); 2386941Ssam if (dp->b_active == 0) { 2398608Sroot trace("!act",dp); 2406941Ssam (void) idcustart(ui); 2416941Ssam bp = &ui->ui_mi->um_tab; 2426941Ssam if (bp->b_actf && bp->b_active == 0) 2436941Ssam (void) idcstart(ui->ui_mi); 2446941Ssam } 2456941Ssam (void) spl0(); 2466941Ssam return; 2476941Ssam 2486941Ssam bad: 2496941Ssam bp->b_flags |= B_ERROR; 2506941Ssam iodone(bp); 2516941Ssam return; 2526941Ssam } 2536941Ssam 2546941Ssam idcustart(ui) 2556941Ssam register struct uba_device *ui; 2566941Ssam { 2576941Ssam register struct buf *bp, *dp; 2586941Ssam register struct uba_ctlr *um; 2596941Ssam register struct idcdevice *idcaddr; 2606941Ssam register struct idcst *st; 2616941Ssam union idc_dar cyltrk; 2626941Ssam daddr_t bn; 2636941Ssam int unit; 2646941Ssam 2656941Ssam if (ui == 0) 2666941Ssam return (0); 2676941Ssam dk_busy &= ~(1<<ui->ui_dk); 2686941Ssam dp = &idcutab[ui->ui_unit]; 2696941Ssam um = ui->ui_mi; 2706941Ssam unit = ui->ui_slave; 2718608Sroot trace("ust", dp); 2726941Ssam idcaddr = (struct idcdevice *)um->um_addr; 2736941Ssam if (um->um_tab.b_active) { 2746941Ssam idc_softc.sc_softas |= 1<<unit; 2758608Sroot trace("umac",idc_softc.sc_softas); 2766941Ssam return (0); 2776941Ssam } 2786941Ssam if ((bp = dp->b_actf) == NULL) { 2798608Sroot trace("!bp",0); 2806941Ssam return (0); 2816941Ssam } 2826941Ssam if (dp->b_active) { 2838608Sroot trace("dpac",dp->b_active); 2846941Ssam goto done; 2856941Ssam } 2866941Ssam dp->b_active = 1; 2876941Ssam /* CHECK DRIVE READY? */ 2886941Ssam bn = dkblock(bp); 2898608Sroot trace("seek", bn); 2906941Ssam if (ui->ui_type == 0) 2916941Ssam bn *= 2; 2926941Ssam st = &idcst[ui->ui_type]; 2936941Ssam cyltrk.dar_cyl = bp->b_cylin; 2946941Ssam cyltrk.dar_trk = (bn / st->nsect) % st->ntrak; 2956941Ssam cyltrk.dar_sect = 0; 2966941Ssam printd("idcustart, unit %d, cyltrk 0x%x\n", unit, cyltrk.dar_dar); 2976941Ssam /* 2986941Ssam * If on cylinder, no need to seek. 2996941Ssam */ 3006941Ssam if (cyltrk.dar_dar == idccyl[ui->ui_unit].dar_dar) 3016941Ssam goto done; 3026941Ssam /* 3036941Ssam * RB80 can change heads (tracks) just by loading 3046941Ssam * the disk address register, perform optimization 3056941Ssam * here instead of doing a full seek. 3066941Ssam */ 3076941Ssam if (ui->ui_type && cyltrk.dar_cyl == idccyl[ui->ui_unit].dar_cyl) { 3086941Ssam idcaddr->idccsr = IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8); 3096941Ssam idcaddr->idcdar = cyltrk.dar_dar; 3106941Ssam idccyl[ui->ui_unit].dar_dar = cyltrk.dar_dar; 3116941Ssam goto done; 3126941Ssam } 3136941Ssam /* 3146941Ssam * Need to do a full seek. Select the unit, clear 3156941Ssam * its attention bit, set the command, load the 3166941Ssam * disk address register, and then go. 3176941Ssam */ 3186941Ssam idcaddr->idccsr = 3196941Ssam IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8)|(1<<(unit+16)); 3206941Ssam idcaddr->idcdar = cyltrk.dar_dar; 3216941Ssam idccyl[ui->ui_unit].dar_dar = cyltrk.dar_dar; 3226941Ssam printd(" seek"); 3236941Ssam idcaddr->idccsr = IDC_IE|IDC_SEEK|(unit<<8); 3246941Ssam if (ui->ui_dk >= 0) { 3256941Ssam dk_busy |= 1<<ui->ui_dk; 3266941Ssam dk_seek[ui->ui_dk]++; 3276941Ssam } 3286941Ssam /* 3296941Ssam * RB80's initiate seeks very quickly. Wait for it 3306941Ssam * to come ready rather than taking the interrupt. 3316941Ssam */ 3326941Ssam if (ui->ui_type) { 3336941Ssam if (idcwait(idcaddr, 10) == 0) 3346941Ssam return (1); 3356941Ssam idcaddr->idccsr &= ~IDC_ATTN; 3366941Ssam /* has the seek completed? */ 3376941Ssam if (idcaddr->idccsr & IDC_DRDY) { 3386941Ssam printd(", drdy"); 3396941Ssam idcaddr->idccsr = 3406941Ssam IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8)|(1<<(unit+16)); 3416941Ssam goto done; 3426941Ssam } 3436941Ssam } 3446941Ssam printd(", idccsr = 0x%x\n", idcaddr->idccsr); 3456941Ssam return (1); 3466941Ssam done: 3476941Ssam if (dp->b_active != 2) { 3488608Sroot trace("!=2",dp->b_active); 3496941Ssam dp->b_forw = NULL; 3506941Ssam if (um->um_tab.b_actf == NULL) 3516941Ssam um->um_tab.b_actf = dp; 3526941Ssam else { 3538608Sroot trace("!NUL",um->um_tab.b_actl); 3546941Ssam um->um_tab.b_actl->b_forw = dp; 3556941Ssam } 3566941Ssam um->um_tab.b_actl = dp; 3576941Ssam dp->b_active = 2; 3586941Ssam } 3596941Ssam return (0); 3606941Ssam } 3616941Ssam 3626941Ssam idcstart(um) 3636941Ssam register struct uba_ctlr *um; 3646941Ssam { 3656941Ssam register struct buf *bp, *dp; 3666941Ssam register struct uba_device *ui; 3676941Ssam register struct idcdevice *idcaddr; 3686941Ssam register struct idc_softc *sc; 3696941Ssam struct idcst *st; 3706941Ssam daddr_t bn; 3716941Ssam int sn, tn, cmd; 3726941Ssam 3736941Ssam loop: 3746941Ssam if ((dp = um->um_tab.b_actf) == NULL) { 3758608Sroot trace("nodp",um); 3766941Ssam return (0); 3776941Ssam } 3786941Ssam if ((bp = dp->b_actf) == NULL) { 3798608Sroot trace("nobp", dp); 3806941Ssam um->um_tab.b_actf = dp->b_forw; 3816941Ssam goto loop; 3826941Ssam } 3836941Ssam um->um_tab.b_active = 1; 3846941Ssam ui = idcdinfo[dkunit(bp)]; 3856941Ssam bn = dkblock(bp); 3868608Sroot trace("star",bp); 3876941Ssam if (ui->ui_type == 0) 3886941Ssam bn *= 2; 3896941Ssam sc = &idc_softc; 3906941Ssam st = &idcst[ui->ui_type]; 3916941Ssam sn = bn%st->nspc; 3926941Ssam tn = sn/st->nsect; 3936941Ssam sn %= st->nsect; 3946941Ssam sc->sc_sect = sn; 3956941Ssam sc->sc_trk = tn; 3966941Ssam sc->sc_cyl = bp->b_cylin; 3976941Ssam idcaddr = (struct idcdevice *)ui->ui_addr; 3986941Ssam printd("idcstart, unit %d, dar 0x%x", ui->ui_slave, sc->sc_dar); 3996941Ssam if (bp->b_flags & B_READ) 4006941Ssam cmd = IDC_IE|IDC_READ|(ui->ui_slave<<8); 4016941Ssam else 4026941Ssam cmd = IDC_IE|IDC_WRITE|(ui->ui_slave<<8); 4036941Ssam idcaddr->idccsr = IDC_CRDY|cmd; 4046941Ssam if ((idcaddr->idccsr&IDC_DRDY) == 0) { 4056941Ssam printf("rb%d: not ready\n", dkunit(bp)); 4066941Ssam um->um_tab.b_active = 0; 4076941Ssam um->um_tab.b_errcnt = 0; 4086941Ssam dp->b_actf = bp->av_forw; 4096941Ssam dp->b_active = 0; 4106941Ssam bp->b_flags |= B_ERROR; 4116941Ssam iodone(bp); 4126941Ssam goto loop; 4136941Ssam } 4146941Ssam idccyl[ui->ui_unit].dar_dar = sc->sc_dar; 4156941Ssam idccyl[ui->ui_unit].dar_sect = 0; 4166941Ssam sn = (st->nsect - sn) * st->nbps; 4176941Ssam if (sn > bp->b_bcount) 4186941Ssam sn = bp->b_bcount; 4196941Ssam sc->sc_bcnt = sn; 4206941Ssam sc->sc_resid = bp->b_bcount; 4216941Ssam sc->sc_unit = ui->ui_slave; 4226941Ssam printd(", bcr 0x%x, cmd 0x%x\n", sn, cmd); 4236941Ssam um->um_cmd = cmd; 4246941Ssam (void) ubago(ui); 4256941Ssam return (1); 4266941Ssam } 4276941Ssam 4286941Ssam idcdgo(um) 4296941Ssam register struct uba_ctlr *um; 4306941Ssam { 4316941Ssam register struct idcdevice *idcaddr = (struct idcdevice *)um->um_addr; 4326941Ssam register struct idc_softc *sc = &idc_softc; 4336941Ssam 4346941Ssam /* 4356941Ssam * VERY IMPORTANT: must load registers in this order. 4366941Ssam */ 4376941Ssam idcaddr->idcbar = sc->sc_ubaddr = um->um_ubinfo&0x3ffff; 4386941Ssam idcaddr->idcbcr = -sc->sc_bcnt; 4396941Ssam idcaddr->idcdar = sc->sc_dar; 4406941Ssam printd("idcdgo, ubinfo 0x%x, cmd 0x%x\n", um->um_ubinfo, um->um_cmd); 4416941Ssam idcaddr->idccsr = um->um_cmd; 4428608Sroot trace("go", um); 4436941Ssam um->um_tab.b_active = 2; 4446941Ssam /*** CLEAR SPURIOUS ATTN ON R80? ***/ 4456941Ssam } 4466941Ssam 4476941Ssam idcintr(idc) 4486941Ssam int idc; 4496941Ssam { 4506941Ssam register struct uba_ctlr *um = idcminfo[idc]; 4516941Ssam register struct uba_device *ui; 4526941Ssam register struct idcdevice *idcaddr = (struct idcdevice *)um->um_addr; 4536941Ssam register struct idc_softc *sc = &idc_softc; 4546941Ssam register struct buf *bp, *dp; 4556941Ssam struct idcst *st; 4566941Ssam int unit, as, er, cmd, ds = 0; 4576941Ssam 4586941Ssam printd("idcintr, idccsr 0x%x", idcaddr->idccsr); 4596941Ssam top: 4606941Ssam idcwticks = 0; 4618608Sroot trace("intr", um->um_tab.b_active); 4626941Ssam if (um->um_tab.b_active == 2) { 4636941Ssam /* 4646941Ssam * Process a data transfer complete interrupt. 4656941Ssam */ 4666941Ssam um->um_tab.b_active = 1; 4676941Ssam dp = um->um_tab.b_actf; 4686941Ssam bp = dp->b_actf; 4696941Ssam ui = idcdinfo[dkunit(bp)]; 4706941Ssam unit = ui->ui_slave; 4716941Ssam st = &idcst[ui->ui_type]; 4726941Ssam idcaddr->idccsr = IDC_IE|IDC_CRDY|(unit<<8); 4736941Ssam if ((er = idcaddr->idccsr) & IDC_ERR) { 4746941Ssam if (er & IDC_DE) { 4756941Ssam idcaddr->idcmpr = IDCGS_GETSTAT; 4766941Ssam idcaddr->idccsr = IDC_GETSTAT|(unit<<8); 4778721Sroot (void) idcwait(idcaddr, 0); 4786941Ssam ds = idcaddr->idcmpr; 4796941Ssam idcaddr->idccsr = 4806941Ssam IDC_IE|IDC_CRDY|(1<<(unit+16)); 4816941Ssam } 4826941Ssam printd(", er 0x%x, ds 0x%x", er, ds); 4836941Ssam if (ds & IDCDS_WL) { 4846941Ssam printf("rb%d: write locked\n", dkunit(bp)); 4856941Ssam bp->b_flags |= B_ERROR; 4866941Ssam } else if (++um->um_tab.b_errcnt > 28 || er&IDC_HARD) { 4876941Ssam hard: 4886941Ssam harderr(bp, "rb"); 4896941Ssam printf("csr=%b ds=%b\n", er, IDCCSR_BITS, ds, 4906941Ssam ui->ui_type?IDCRB80DS_BITS:IDCRB02DS_BITS); 4916941Ssam bp->b_flags |= B_ERROR; 4926941Ssam } else if (er & IDC_DCK) { 4936941Ssam switch (er & IDC_ECS) { 4946941Ssam case IDC_ECS_NONE: 4956941Ssam break; 4966941Ssam case IDC_ECS_SOFT: 4976941Ssam idcecc(ui); 4986941Ssam break; 4996941Ssam case IDC_ECS_HARD: 5006941Ssam default: 5016941Ssam goto hard; 5026941Ssam } 5036941Ssam } else 5046941Ssam /* recoverable error, set up for retry */ 5056941Ssam goto seek; 5066941Ssam } 5076941Ssam if ((sc->sc_resid -= sc->sc_bcnt) != 0) { 5086941Ssam sc->sc_ubaddr += sc->sc_bcnt; 5096941Ssam /* 5106941Ssam * Current transfer is complete, have 5116941Ssam * we overflowed to the next track? 5126941Ssam */ 5136941Ssam if ((sc->sc_sect += sc->sc_bcnt/st->nbps) == st->nsect) { 5146941Ssam sc->sc_sect = 0; 5156941Ssam if (++sc->sc_trk == st->ntrak) { 5166941Ssam sc->sc_trk = 0; 5176941Ssam sc->sc_cyl++; 5186941Ssam } else if (ui->ui_type) { 5196941Ssam /* 5206941Ssam * RB80 can change heads just by 5216941Ssam * loading the disk address register. 5226941Ssam */ 5236941Ssam idcaddr->idccsr = IDC_SEEK|IDC_CRDY| 5246941Ssam IDC_IE|(unit<<8); 5256941Ssam printd(", change to track 0x%x", sc->sc_dar); 5266941Ssam idcaddr->idcdar = sc->sc_dar; 5276941Ssam idccyl[ui->ui_unit].dar_dar = sc->sc_dar; 5286941Ssam idccyl[ui->ui_unit].dar_sect = 0; 5296941Ssam goto cont; 5306941Ssam } 5316941Ssam /* 5326941Ssam * Changing tracks on RB02 or cylinders 5336941Ssam * on RB80, start a seek. 5346941Ssam */ 5356941Ssam seek: 5366941Ssam cmd = IDC_IE|IDC_SEEK|(unit<<8); 5376941Ssam idcaddr->idccsr = cmd|IDC_CRDY; 5386941Ssam idcaddr->idcdar = sc->sc_dar; 5396941Ssam printd(", seek to 0x%x\n", sc->sc_dar); 5406941Ssam idccyl[ui->ui_unit].dar_dar = sc->sc_dar; 5416941Ssam idccyl[ui->ui_unit].dar_sect = 0; 5426941Ssam sc->sc_bcnt = 0; 5436941Ssam idcaddr->idccsr = cmd; 5446941Ssam if (ui->ui_type) { 5456941Ssam if (idcwait(idcaddr, 10) == 0) 5466941Ssam return; 5476941Ssam idcaddr->idccsr &= ~IDC_ATTN; 5486941Ssam if (idcaddr->idccsr & IDC_DRDY) 5496941Ssam goto top; 5506941Ssam } 5516941Ssam } else { 5526941Ssam /* 5536941Ssam * Continue transfer on current track. 5546941Ssam */ 5556941Ssam cont: 5566941Ssam sc->sc_bcnt = (st->nsect-sc->sc_sect)*st->nbps; 5576941Ssam if (sc->sc_bcnt > sc->sc_resid) 5586941Ssam sc->sc_bcnt = sc->sc_resid; 5596941Ssam if (bp->b_flags & B_READ) 5606941Ssam cmd = IDC_IE|IDC_READ|(unit<<8); 5616941Ssam else 5626941Ssam cmd = IDC_IE|IDC_WRITE|(unit<<8); 5636941Ssam idcaddr->idccsr = cmd|IDC_CRDY; 5646941Ssam idcaddr->idcbar = sc->sc_ubaddr; 5656941Ssam idcaddr->idcbcr = -sc->sc_bcnt; 5666941Ssam idcaddr->idcdar = sc->sc_dar; 5676941Ssam printd(", continue I/O 0x%x, 0x%x\n", sc->sc_dar, sc->sc_bcnt); 5686941Ssam idcaddr->idccsr = cmd; 5696941Ssam um->um_tab.b_active = 2; 5706941Ssam } 5716941Ssam return; 5726941Ssam } 5736941Ssam /* 5746941Ssam * Entire transfer is done, clean up. 5756941Ssam */ 5766941Ssam ubadone(um); 5776941Ssam dk_busy &= ~(1 << ui->ui_dk); 5786941Ssam um->um_tab.b_active = 0; 5796941Ssam um->um_tab.b_errcnt = 0; 5806941Ssam um->um_tab.b_actf = dp->b_forw; 5816941Ssam dp->b_active = 0; 5826941Ssam dp->b_errcnt = 0; 5836941Ssam dp->b_actf = bp->av_forw; 5848608Sroot trace("done", dp); trace(&um->um_tab.b_actf, dp->b_actf); 5856941Ssam bp->b_resid = sc->sc_resid; 5866941Ssam printd(", iodone, resid 0x%x\n", bp->b_resid); 5876941Ssam iodone(bp); 5886941Ssam if (dp->b_actf) 5896941Ssam if (idcustart(ui)) 5906941Ssam return; 5916941Ssam } else if (um->um_tab.b_active == 1) { 5926941Ssam /* 5936941Ssam * Got an interrupt while setting up for a command 5946941Ssam * or doing a mid-transfer seek. Save any attentions 5956941Ssam * for later and process a mid-transfer seek complete. 5966941Ssam */ 5976941Ssam as = idcaddr->idccsr; 5986941Ssam idcaddr->idccsr = IDC_IE|IDC_CRDY|(as&IDC_ATTN); 5996941Ssam as = (as >> 16) & 0xf; 6006941Ssam unit = sc->sc_unit; 6016941Ssam sc->sc_softas |= as & ~(1<<unit); 6026941Ssam if (as & (1<<unit)) { 6036941Ssam printd(", seek1 complete"); 6046941Ssam um->um_tab.b_active = 2; 6056941Ssam goto top; 6066941Ssam } 6076941Ssam printd(", as1 %o\n", as); 6086941Ssam return; 6096941Ssam } 6106941Ssam /* 6116941Ssam * Process any seek initiated or complete interrupts. 6126941Ssam */ 6136941Ssam as = idcaddr->idccsr; 6146941Ssam idcaddr->idccsr = IDC_IE|IDC_CRDY|(as&IDC_ATTN); 6156941Ssam as = ((as >> 16) & 0xf) | sc->sc_softas; 6166941Ssam sc->sc_softas = 0; 6178608Sroot trace("as", as); 6186941Ssam printd(", as %o", as); 6196941Ssam for (unit = 0; unit < NRB; unit++) 6206941Ssam if (as & (1<<unit)) { 6216941Ssam as &= ~(1<<unit); 6226941Ssam idcaddr->idccsr = IDC_IE|IDC_CRDY|(unit<<8); 6236941Ssam ui = idcdinfo[unit]; 6246941Ssam if (ui) { 6256941Ssam printd(", attn unit %d", unit); 6266941Ssam if (idcaddr->idccsr & IDC_DRDY) 6276941Ssam if (idcustart(ui)) { 6286941Ssam sc->sc_softas = as; 6296941Ssam return; 6306941Ssam } 6316941Ssam } else { 6326941Ssam printd(", unsol. intr. unit %d", unit); 6336941Ssam } 6346941Ssam } 6356941Ssam printd("\n"); 6366941Ssam if (um->um_tab.b_actf && um->um_tab.b_active == 0) { 6378608Sroot trace("stum",um->um_tab.b_actf); 6388721Sroot (void) idcstart(um); 6396941Ssam } 6406941Ssam } 6416941Ssam 6428608Sroot idcwait(addr, n) 6436941Ssam register struct idcdevice *addr; 6448608Sroot register int n; 6456941Ssam { 6466941Ssam register int i; 6476941Ssam 6488608Sroot while (--n && (addr->idccsr & IDC_CRDY) == 0) 6496941Ssam for (i = 10; i; i--) 6506941Ssam ; 6518608Sroot return (n); 6526941Ssam } 6536941Ssam 6547728Sroot idcread(dev, uio) 6556941Ssam dev_t dev; 6567728Sroot struct uio *uio; 6576941Ssam { 6586941Ssam register int unit = minor(dev) >> 3; 6596941Ssam 6606941Ssam if (unit >= NRB) 6618161Sroot return (ENXIO); 6628161Sroot return (physio(idcstrategy, &ridcbuf[unit], dev, B_READ, minphys, uio)); 6636941Ssam } 6646941Ssam 6657834Sroot idcwrite(dev, uio) 6666941Ssam dev_t dev; 6677834Sroot struct uio *uio; 6686941Ssam { 6696941Ssam register int unit = minor(dev) >> 3; 6706941Ssam 6716941Ssam if (unit >= NRB) 6728161Sroot return (ENXIO); 6738161Sroot return (physio(idcstrategy, &ridcbuf[unit], dev, B_WRITE, minphys, uio)); 6746941Ssam } 6756941Ssam 6766941Ssam idcecc(ui) 6776941Ssam register struct uba_device *ui; 6786941Ssam { 6796941Ssam register struct idcdevice *idc = (struct idcdevice *)ui->ui_addr; 6806941Ssam register struct buf *bp = idcutab[ui->ui_unit].b_actf; 6816941Ssam register struct uba_ctlr *um = ui->ui_mi; 6826941Ssam register struct idcst *st; 6836941Ssam register int i; 6846941Ssam struct uba_regs *ubp = ui->ui_hd->uh_uba; 6856941Ssam int bit, byte, mask; 6866941Ssam caddr_t addr; 6876941Ssam int reg, npf, o; 6886941Ssam int cn, tn, sn; 6896941Ssam 6906941Ssam printf("idcecc: HELP!\n"); 6916941Ssam npf = btop(idc->idcbcr + idc_softc.sc_bcnt) - 1;; 6926941Ssam reg = btop(idc_softc.sc_ubaddr) + npf; 6936941Ssam o = (int)bp->b_un.b_addr & PGOFSET; 6946941Ssam st = &idcst[ui->ui_type]; 6956941Ssam cn = idc_softc.sc_cyl; 6966941Ssam tn = idc_softc.sc_trk; 6976941Ssam sn = idc_softc.sc_sect; 6986941Ssam um->um_tab.b_active = 1; /* Either complete or continuing... */ 6996941Ssam printf("rb%d%c: soft ecc sn%d\n", dkunit(bp), 7006941Ssam 'a'+(minor(bp->b_dev)&07), 7016941Ssam (cn*st->ntrak + tn) * st->nsect + sn + npf); 7026941Ssam mask = idc->idceccpat; 7036941Ssam i = idc->idceccpos - 1; /* -1 makes 0 origin */ 7046941Ssam bit = i&07; 7056941Ssam i = (i&~07)>>3; 7066941Ssam byte = i + o; 7076941Ssam while (i < 512 && (int)ptob(npf)+i < idc_softc.sc_bcnt && bit > -11) { 7086941Ssam addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ 7096941Ssam (byte & PGOFSET); 7106941Ssam putmemc(addr, getmemc(addr)^(mask<<bit)); 7116941Ssam byte++; 7126941Ssam i++; 7136941Ssam bit -= 8; 7146941Ssam } 7156941Ssam idc_softc.sc_bcnt += idc->idcbcr; 7166941Ssam um->um_tab.b_errcnt = 0; /* error has been corrected */ 7176941Ssam return; 7186941Ssam } 7196941Ssam 7206941Ssam idcreset(uban) 7216941Ssam int uban; 7226941Ssam { 7236941Ssam register struct uba_ctlr *um; 7246941Ssam register struct uba_device *ui; 7256941Ssam register unit; 7266941Ssam 7276941Ssam if ((um = idcminfo[0]) == 0 || um->um_ubanum != uban || 7286941Ssam um->um_alive == 0) 7296941Ssam return; 7306941Ssam printf(" idc0"); 7316941Ssam um->um_tab.b_active = 0; 7326941Ssam um->um_tab.b_actf = um->um_tab.b_actl = 0; 7336941Ssam if (um->um_ubinfo) { 7346941Ssam printf("<%d>", (um->um_ubinfo>>28)&0xf); 7359354Ssam um->um_ubinfo = 0; 7366941Ssam } 7376941Ssam for (unit = 0; unit < NRB; unit++) { 7386941Ssam if ((ui = idcdinfo[unit]) == 0 || ui->ui_alive == 0) 7396941Ssam continue; 7406941Ssam idcutab[unit].b_active = 0; 7416941Ssam (void) idcustart(ui); 7426941Ssam } 7436941Ssam (void) idcstart(um); 7446941Ssam } 7456941Ssam 7466941Ssam idcwatch() 7476941Ssam { 7486941Ssam register struct uba_ctlr *um; 7496941Ssam register unit; 7506941Ssam 7516941Ssam timeout(idcwatch, (caddr_t)0, hz); 7526941Ssam um = idcminfo[0]; 7536941Ssam if (um == 0 || um->um_alive == 0) 7546941Ssam return; 7556941Ssam if (um->um_tab.b_active == 0) { 7566941Ssam for (unit = 0; unit < NRB; unit++) 7576941Ssam if (idcutab[unit].b_active) 7586941Ssam goto active; 7596941Ssam idcwticks = 0; 7606941Ssam return; 7616941Ssam } 7626941Ssam active: 7636941Ssam idcwticks++; 7646941Ssam if (idcwticks >= 20) { 7656941Ssam idcwticks = 0; 7666941Ssam printf("idc0: lost interrupt\n"); 7676941Ssam idcintr(0); 7686941Ssam } 7696941Ssam } 7706941Ssam 7718608Sroot /*ARGSUSED*/ 7726941Ssam idcdump(dev) 7736941Ssam dev_t dev; 7746941Ssam { 7756941Ssam struct idcdevice *idcaddr; 7766941Ssam char *start; 77712147Sroot int num, blk, unit; 7786941Ssam struct size *sizes; 7796941Ssam register struct uba_regs *uba; 7806941Ssam register struct uba_device *ui; 7816941Ssam struct idcst *st; 78212778Ssam union idc_dar dar; 78312147Sroot int nspg; 7846941Ssam 7856941Ssam unit = minor(dev) >> 3; 7866941Ssam if (unit >= NRB) 7876941Ssam return (ENXIO); 7886941Ssam #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) 7896941Ssam ui = phys(struct uba_device *, idcdinfo[unit]); 7906941Ssam if (ui->ui_alive == 0) 7916941Ssam return (ENXIO); 7926941Ssam uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 7936941Ssam ubainit(uba); 7946941Ssam idcaddr = (struct idcdevice *)ui->ui_physaddr; 79512147Sroot if (idcwait(idcaddr, 100) == 0) 79612147Sroot return (EFAULT); 79712147Sroot /* 79812147Sroot * Since we can only transfer one track at a time, and 79912147Sroot * the rl02 has 256 byte sectors, all the calculations 80012147Sroot * are done in terms of physical sectors (i.e. num and blk 80112147Sroot * are in sectors not NBPG blocks. 80212147Sroot */ 80312147Sroot st = phys(struct idcst *, &idcst[ui->ui_type]); 8046941Ssam sizes = phys(struct size *, st->sizes); 80512147Sroot if (dumplo < 0 || dumplo + maxfree >= sizes[minor(dev)&07].nblocks) 8066941Ssam return (EINVAL); 80712147Sroot nspg = NBPG / st->nbps; 80812147Sroot num = maxfree * nspg; 80912147Sroot start = 0; 81012147Sroot 8116941Ssam while (num > 0) { 8126941Ssam register struct pte *io; 8136941Ssam register int i; 8146941Ssam daddr_t bn; 8156941Ssam 81612147Sroot bn = (dumplo + btop(start)) * nspg; 81712147Sroot dar.dar_cyl = bn / st->nspc + sizes[minor(dev)&07].cyloff; 81812147Sroot bn %= st->nspc; 81912147Sroot dar.dar_trk = bn / st->nsect; 82012147Sroot dar.dar_sect = bn % st->nsect; 82112147Sroot blk = st->nsect - dar.dar_sect; 82212147Sroot if (num < blk) 82312147Sroot blk = num; 82412147Sroot 8256941Ssam io = uba->uba_map; 82612147Sroot for (i = 0; i < (blk + nspg - 1) / nspg; i++) 8276941Ssam *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV; 8286941Ssam *(int *)io = 0; 82912147Sroot 83012147Sroot idcaddr->idccsr = IDC_CRDY | IDC_SEEK | unit<<8; 83112147Sroot if ((idcaddr->idccsr&IDC_DRDY) == 0) 83212147Sroot return (EFAULT); 83312147Sroot idcaddr->idcdar = dar.dar_dar; 83412147Sroot idcaddr->idccsr = IDC_SEEK | unit << 8; 83512147Sroot while ((idcaddr->idccsr & (IDC_CRDY|IDC_DRDY)) 83612147Sroot != (IDC_CRDY|IDC_DRDY)) 83712147Sroot ; 83812147Sroot if (idcaddr->idccsr & IDC_ERR) { 83912147Sroot printf("rb%d: seek, csr=%b\n", 84012147Sroot unit, idcaddr->idccsr, IDCCSR_BITS); 8416941Ssam return (EIO); 84212147Sroot } 84312147Sroot 84412147Sroot idcaddr->idccsr = IDC_CRDY | IDC_WRITE | unit<<8; 84512147Sroot if ((idcaddr->idccsr&IDC_DRDY) == 0) 84612147Sroot return (EFAULT); 84712147Sroot idcaddr->idcbar = 0; /* start addr 0 */ 84812147Sroot idcaddr->idcbcr = - (blk * st->nbps); 84912147Sroot idcaddr->idcdar = dar.dar_dar; 85012147Sroot idcaddr->idccsr = IDC_WRITE | unit << 8; 85112147Sroot while ((idcaddr->idccsr & (IDC_CRDY|IDC_DRDY)) 85212147Sroot != (IDC_CRDY|IDC_DRDY)) 85312147Sroot ; 85412147Sroot if (idcaddr->idccsr & IDC_ERR) { 85512147Sroot printf("rb%d: write, csr=%b\n", 85612147Sroot unit, idcaddr->idccsr, IDCCSR_BITS); 85712147Sroot return (EIO); 85812147Sroot } 85912147Sroot 86012147Sroot start += blk * st->nbps; 8616941Ssam num -= blk; 8626941Ssam } 8636941Ssam return (0); 8646941Ssam } 86512503Ssam 86612503Ssam idcsize(dev) 86712503Ssam dev_t dev; 86812503Ssam { 86912503Ssam int unit = minor(dev) >> 3; 87012503Ssam struct uba_device *ui; 87112503Ssam struct idcst *st; 87212503Ssam 87312503Ssam if (unit >= NRB || (ui = idcdinfo[unit]) == 0 || ui->ui_alive == 0) 87412503Ssam return (-1); 87512503Ssam st = &idcst[ui->ui_type]; 87612503Ssam return (st->sizes[minor(dev) & 07].nblocks); 87712503Ssam } 8786941Ssam #endif 879