1*8161Sroot /* idc.c 4.5 82/09/12 */ 26941Ssam 36941Ssam #include "rb.h" 46941Ssam #if NIDC > 0 56941Ssam int idcdebug = 0; 66941Ssam #define printd if(idcdebug)printf 76941Ssam int idctrb[1000]; 86941Ssam int *trp = idctrb; 96941Ssam #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 * dump 216941Ssam */ 226941Ssam #include "../h/param.h" 236941Ssam #include "../h/systm.h" 246941Ssam #include "../h/buf.h" 256941Ssam #include "../h/conf.h" 266941Ssam #include "../h/dir.h" 276941Ssam #include "../h/user.h" 286941Ssam #include "../h/pte.h" 296941Ssam #include "../h/map.h" 306941Ssam #include "../h/vm.h" 316941Ssam #include "../h/ubareg.h" 326941Ssam #include "../h/ubavar.h" 336941Ssam #include "../h/dk.h" 346941Ssam #include "../h/cpu.h" 356941Ssam #include "../h/cmap.h" 366941Ssam #include "../h/dkbad.h" 377728Sroot #include "../h/uio.h" 386941Ssam 396941Ssam #include "../h/idcreg.h" 406941Ssam 416941Ssam struct idc_softc { 426941Ssam int sc_bcnt; /* number of bytes to transfer */ 436941Ssam int sc_resid; /* total number of bytes to transfer */ 446941Ssam int sc_ubaddr; /* Unibus address of data */ 456941Ssam short sc_unit; /* unit doing transfer */ 466941Ssam short sc_softas; /* software attention summary bits */ 476941Ssam union idc_dar { 486941Ssam long dar_l; 496941Ssam u_short dar_w[2]; 506941Ssam u_char dar_b[4]; 516941Ssam } sc_un; /* prototype disk address register */ 526941Ssam } idc_softc; 536941Ssam 546941Ssam #define dar_dar dar_l /* the whole disk address */ 556941Ssam #define dar_cyl dar_w[1] /* cylinder address */ 566941Ssam #define dar_trk dar_b[1] /* track */ 576941Ssam #define dar_sect dar_b[0] /* sector */ 586941Ssam #define sc_dar sc_un.dar_dar 596941Ssam #define sc_cyl sc_un.dar_cyl 606941Ssam #define sc_trk sc_un.dar_trk 616941Ssam #define sc_sect sc_un.dar_sect 626941Ssam 636941Ssam /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 646941Ssam struct size { 656941Ssam daddr_t nblocks; 666941Ssam int cyloff; 676941Ssam } rb02_sizes[8] ={ 686941Ssam 15884, 0, /* A=cyl 0 thru 399 */ 696941Ssam 4480, 400, /* B=cyl 400 thru 510 */ 706941Ssam 20480, 0, /* C=cyl 0 thru 511 */ 716941Ssam 0, 0, 726941Ssam 0, 0, 736941Ssam 0, 0, 746941Ssam 0, 0, 756941Ssam 0, 0, 766941Ssam }, rb80_sizes[8] ={ 776941Ssam 15884, 0, /* A=cyl 0 thru 36 */ 786941Ssam 33440, 37, /* B=cyl 37 thru 114 */ 796941Ssam 242606, 0, /* C=cyl 0 thru 558 */ 806941Ssam 0, 0, 816941Ssam 0, 0, 826941Ssam 0, 0, 836941Ssam 82080, 115, /* G=cyl 115 thru 304 */ 846941Ssam 110143, 305, /* H=cyl 305 thru 558 */ 856941Ssam }; 866941Ssam /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 876941Ssam 886941Ssam int idcprobe(), idcslave(), idcattach(), idcdgo(), idcintr(); 896941Ssam struct uba_ctlr *idcminfo[NIDC]; 906941Ssam struct uba_device *idcdinfo[NRB]; 916941Ssam 926941Ssam u_short idcstd[] = { 0174400, 0}; 936941Ssam struct uba_driver idcdriver = 946941Ssam { idcprobe, idcslave, idcattach, idcdgo, idcstd, "rb", idcdinfo, "idc", idcminfo, 0 }; 956941Ssam struct buf idcutab[NRB]; 966941Ssam union idc_dar idccyl[NRB]; 976941Ssam 986941Ssam struct idcst { 996941Ssam short nbps; 1006941Ssam short nsect; 1016941Ssam short ntrak; 1026941Ssam short nspc; 1036941Ssam short ncyl; 1046941Ssam struct size *sizes; 1056941Ssam } idcst[] = { 1066941Ssam 256, NRB02SECT, NRB02TRK, NRB02SECT*NRB02TRK, NRB02CYL, rb02_sizes, 1076941Ssam 512, NRB80SECT, NRB80TRK, NRB80SECT*NRB80TRK, NRB80CYL, rb80_sizes, 1086941Ssam }; 1096941Ssam 1106941Ssam struct buf ridcbuf[NRB]; 1116941Ssam 1126941Ssam #define b_cylin b_resid 1136941Ssam 1146941Ssam #ifdef INTRLVE 1156941Ssam daddr_t dkblock(); 1166941Ssam #endif 1176941Ssam 1186941Ssam int idcwstart, idcwticks, idcwatch(); 1196941Ssam 1206941Ssam idcprobe(reg) 1216941Ssam caddr_t reg; 1226941Ssam { 1236941Ssam register int br, cvec; 1246941Ssam register struct idcdevice *idcaddr; 1256941Ssam 1266941Ssam #ifdef lint 1276941Ssam br = 0; cvec = br; br = cvec; 1286941Ssam #endif 1296941Ssam idcaddr = (struct idcdevice *)((caddr_t)uba_hd[0].uh_uba + 0x200); 1306941Ssam idcaddr->idccsr = IDC_ATTN|IDC_IE; 1316941Ssam while ((idcaddr->idccsr & IDC_CRDY) == 0) 1326941Ssam ; 1336941Ssam idcaddr->idccsr = IDC_ATTN|IDC_CRDY; 1347414Skre return (sizeof (struct idcdevice)); 1356941Ssam } 1366941Ssam 1376941Ssam idcslave(ui, reg) 1386941Ssam struct uba_device *ui; 1396941Ssam caddr_t reg; 1406941Ssam { 1416941Ssam register struct idcdevice *idcaddr; 1426941Ssam register int i; 1436941Ssam 1446941Ssam idcaddr = (struct idcdevice *)((caddr_t)uba_hd[0].uh_uba + 0x200); 1456941Ssam ui->ui_type = 0; 1466941Ssam idcaddr->idcmpr = IDCGS_GETSTAT; 1476941Ssam idcaddr->idccsr = IDC_GETSTAT|(ui->ui_slave<<8); 1486941Ssam idcwait(idcaddr, 0); 1496941Ssam i = idcaddr->idcmpr; 1506941Ssam idcaddr->idccsr = IDC_CRDY|(1<<(ui->ui_slave+16)); 1516941Ssam /* read header to synchronize microcode */ 1526941Ssam idcwait(idcaddr, 0); 1536941Ssam idcaddr->idccsr = (ui->ui_slave<<8)|IDC_RHDR; 1546941Ssam idcwait(idcaddr, 0); 1556941Ssam if (idcaddr->idccsr & IDC_ERR) 1566941Ssam return (0); 1576941Ssam i = idcaddr->idcmpr; /* read header word 1 */ 1586941Ssam i = idcaddr->idcmpr; /* read header word 2 */ 1596941Ssam if (idcaddr->idccsr&IDC_R80) 1606941Ssam ui->ui_type = 1; 1616941Ssam return (1); 1626941Ssam } 1636941Ssam 1646941Ssam idcattach(ui) 1656941Ssam register struct uba_device *ui; 1666941Ssam { 1676941Ssam 1686941Ssam /* 1696941Ssam * Fix all addresses to correspond 1706941Ssam * to the "real" IDC address. 1716941Ssam */ 1726941Ssam ui->ui_mi->um_addr = ui->ui_addr = (caddr_t)uba_hd[0].uh_uba + 0x200; 1736941Ssam ui->ui_physaddr = (caddr_t)uba_hd[0].uh_physuba + 0x200; 1746941Ssam if (idcwstart == 0) { 1756941Ssam timeout(idcwatch, (caddr_t)0, hz); 1766941Ssam idcwstart++; 1776941Ssam } 1786941Ssam if (ui->ui_dk >= 0) 1796941Ssam if (ui->ui_type) 1806941Ssam dk_mspw[ui->ui_dk] = 1.0 / (60 * NRB80SECT * 256); 1816941Ssam else 1826941Ssam dk_mspw[ui->ui_dk] = 1.0 / (60 * NRB02SECT * 128); 1836941Ssam idccyl[ui->ui_unit].dar_dar = -1; 1846941Ssam ui->ui_flags = 0; 1856941Ssam } 1866941Ssam 1876941Ssam idcstrategy(bp) 1886941Ssam register struct buf *bp; 1896941Ssam { 1906941Ssam register struct uba_device *ui; 1916941Ssam register struct idcst *st; 1926941Ssam register int unit; 1936941Ssam register struct buf *dp; 1946941Ssam int xunit = minor(bp->b_dev) & 07; 1956941Ssam long bn, sz; 1966941Ssam 1976941Ssam sz = (bp->b_bcount+511) >> 9; 1986941Ssam unit = dkunit(bp); 1996941Ssam if (unit >= NRB) 2006941Ssam goto bad; 2016941Ssam ui = idcdinfo[unit]; 2026941Ssam if (ui == 0 || ui->ui_alive == 0) 2036941Ssam goto bad; 2046941Ssam st = &idcst[ui->ui_type]; 2056941Ssam if (bp->b_blkno < 0 || 2066941Ssam (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) 2076941Ssam goto bad; 2086941Ssam if (ui->ui_type == 0) 2096941Ssam bn *= 2; 2106941Ssam bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 2116941Ssam (void) spl5(); 2126941Ssam trace('strt',bp); 2136941Ssam dp = &idcutab[ui->ui_unit]; 2146941Ssam disksort(dp, bp); 2156941Ssam if (dp->b_active == 0) { 2166941Ssam trace('!act',dp); 2176941Ssam (void) idcustart(ui); 2186941Ssam bp = &ui->ui_mi->um_tab; 2196941Ssam if (bp->b_actf && bp->b_active == 0) 2206941Ssam (void) idcstart(ui->ui_mi); 2216941Ssam } 2226941Ssam (void) spl0(); 2236941Ssam return; 2246941Ssam 2256941Ssam bad: 2266941Ssam bp->b_flags |= B_ERROR; 2276941Ssam iodone(bp); 2286941Ssam return; 2296941Ssam } 2306941Ssam 2316941Ssam idcustart(ui) 2326941Ssam register struct uba_device *ui; 2336941Ssam { 2346941Ssam register struct buf *bp, *dp; 2356941Ssam register struct uba_ctlr *um; 2366941Ssam register struct idcdevice *idcaddr; 2376941Ssam register struct idcst *st; 2386941Ssam union idc_dar cyltrk; 2396941Ssam daddr_t bn; 2406941Ssam int unit; 2416941Ssam 2426941Ssam if (ui == 0) 2436941Ssam return (0); 2446941Ssam dk_busy &= ~(1<<ui->ui_dk); 2456941Ssam dp = &idcutab[ui->ui_unit]; 2466941Ssam um = ui->ui_mi; 2476941Ssam unit = ui->ui_slave; 2486941Ssam trace('ust', dp); 2496941Ssam idcaddr = (struct idcdevice *)um->um_addr; 2506941Ssam if (um->um_tab.b_active) { 2516941Ssam idc_softc.sc_softas |= 1<<unit; 2526941Ssam trace('umac',idc_softc.sc_softas); 2536941Ssam return (0); 2546941Ssam } 2556941Ssam if ((bp = dp->b_actf) == NULL) { 2566941Ssam trace('!bp',0); 2576941Ssam return (0); 2586941Ssam } 2596941Ssam if (dp->b_active) { 2606941Ssam trace('dpac',dp->b_active); 2616941Ssam goto done; 2626941Ssam } 2636941Ssam dp->b_active = 1; 2646941Ssam /* CHECK DRIVE READY? */ 2656941Ssam bn = dkblock(bp); 2666941Ssam trace('seek', bn); 2676941Ssam if (ui->ui_type == 0) 2686941Ssam bn *= 2; 2696941Ssam st = &idcst[ui->ui_type]; 2706941Ssam cyltrk.dar_cyl = bp->b_cylin; 2716941Ssam cyltrk.dar_trk = (bn / st->nsect) % st->ntrak; 2726941Ssam cyltrk.dar_sect = 0; 2736941Ssam printd("idcustart, unit %d, cyltrk 0x%x\n", unit, cyltrk.dar_dar); 2746941Ssam /* 2756941Ssam * If on cylinder, no need to seek. 2766941Ssam */ 2776941Ssam if (cyltrk.dar_dar == idccyl[ui->ui_unit].dar_dar) 2786941Ssam goto done; 2796941Ssam /* 2806941Ssam * RB80 can change heads (tracks) just by loading 2816941Ssam * the disk address register, perform optimization 2826941Ssam * here instead of doing a full seek. 2836941Ssam */ 2846941Ssam if (ui->ui_type && cyltrk.dar_cyl == idccyl[ui->ui_unit].dar_cyl) { 2856941Ssam idcaddr->idccsr = IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8); 2866941Ssam idcaddr->idcdar = cyltrk.dar_dar; 2876941Ssam idccyl[ui->ui_unit].dar_dar = cyltrk.dar_dar; 2886941Ssam goto done; 2896941Ssam } 2906941Ssam /* 2916941Ssam * Need to do a full seek. Select the unit, clear 2926941Ssam * its attention bit, set the command, load the 2936941Ssam * disk address register, and then go. 2946941Ssam */ 2956941Ssam idcaddr->idccsr = 2966941Ssam IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8)|(1<<(unit+16)); 2976941Ssam idcaddr->idcdar = cyltrk.dar_dar; 2986941Ssam idccyl[ui->ui_unit].dar_dar = cyltrk.dar_dar; 2996941Ssam printd(" seek"); 3006941Ssam idcaddr->idccsr = IDC_IE|IDC_SEEK|(unit<<8); 3016941Ssam if (ui->ui_dk >= 0) { 3026941Ssam dk_busy |= 1<<ui->ui_dk; 3036941Ssam dk_seek[ui->ui_dk]++; 3046941Ssam } 3056941Ssam /* 3066941Ssam * RB80's initiate seeks very quickly. Wait for it 3076941Ssam * to come ready rather than taking the interrupt. 3086941Ssam */ 3096941Ssam if (ui->ui_type) { 3106941Ssam if (idcwait(idcaddr, 10) == 0) 3116941Ssam return (1); 3126941Ssam idcaddr->idccsr &= ~IDC_ATTN; 3136941Ssam /* has the seek completed? */ 3146941Ssam if (idcaddr->idccsr & IDC_DRDY) { 3156941Ssam printd(", drdy"); 3166941Ssam idcaddr->idccsr = 3176941Ssam IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8)|(1<<(unit+16)); 3186941Ssam goto done; 3196941Ssam } 3206941Ssam } 3216941Ssam printd(", idccsr = 0x%x\n", idcaddr->idccsr); 3226941Ssam return (1); 3236941Ssam done: 3246941Ssam if (dp->b_active != 2) { 3256941Ssam trace('!=2',dp->b_active); 3266941Ssam dp->b_forw = NULL; 3276941Ssam if (um->um_tab.b_actf == NULL) 3286941Ssam um->um_tab.b_actf = dp; 3296941Ssam else { 3306941Ssam trace('!NUL',um->um_tab.b_actl); 3316941Ssam um->um_tab.b_actl->b_forw = dp; 3326941Ssam } 3336941Ssam um->um_tab.b_actl = dp; 3346941Ssam dp->b_active = 2; 3356941Ssam } 3366941Ssam return (0); 3376941Ssam } 3386941Ssam 3396941Ssam idcstart(um) 3406941Ssam register struct uba_ctlr *um; 3416941Ssam { 3426941Ssam register struct buf *bp, *dp; 3436941Ssam register struct uba_device *ui; 3446941Ssam register struct idcdevice *idcaddr; 3456941Ssam register struct idc_softc *sc; 3466941Ssam struct idcst *st; 3476941Ssam daddr_t bn; 3486941Ssam int sn, tn, cmd; 3496941Ssam 3506941Ssam loop: 3516941Ssam if ((dp = um->um_tab.b_actf) == NULL) { 3526941Ssam trace('nodp',um); 3536941Ssam return (0); 3546941Ssam } 3556941Ssam if ((bp = dp->b_actf) == NULL) { 3566941Ssam trace('nobp', dp); 3576941Ssam um->um_tab.b_actf = dp->b_forw; 3586941Ssam goto loop; 3596941Ssam } 3606941Ssam um->um_tab.b_active = 1; 3616941Ssam ui = idcdinfo[dkunit(bp)]; 3626941Ssam bn = dkblock(bp); 3636941Ssam trace('star',bp); 3646941Ssam if (ui->ui_type == 0) 3656941Ssam bn *= 2; 3666941Ssam sc = &idc_softc; 3676941Ssam st = &idcst[ui->ui_type]; 3686941Ssam sn = bn%st->nspc; 3696941Ssam tn = sn/st->nsect; 3706941Ssam sn %= st->nsect; 3716941Ssam sc->sc_sect = sn; 3726941Ssam sc->sc_trk = tn; 3736941Ssam sc->sc_cyl = bp->b_cylin; 3746941Ssam idcaddr = (struct idcdevice *)ui->ui_addr; 3756941Ssam printd("idcstart, unit %d, dar 0x%x", ui->ui_slave, sc->sc_dar); 3766941Ssam if (bp->b_flags & B_READ) 3776941Ssam cmd = IDC_IE|IDC_READ|(ui->ui_slave<<8); 3786941Ssam else 3796941Ssam cmd = IDC_IE|IDC_WRITE|(ui->ui_slave<<8); 3806941Ssam idcaddr->idccsr = IDC_CRDY|cmd; 3816941Ssam if ((idcaddr->idccsr&IDC_DRDY) == 0) { 3826941Ssam printf("rb%d: not ready\n", dkunit(bp)); 3836941Ssam um->um_tab.b_active = 0; 3846941Ssam um->um_tab.b_errcnt = 0; 3856941Ssam dp->b_actf = bp->av_forw; 3866941Ssam dp->b_active = 0; 3876941Ssam bp->b_flags |= B_ERROR; 3886941Ssam iodone(bp); 3896941Ssam goto loop; 3906941Ssam } 3916941Ssam idccyl[ui->ui_unit].dar_dar = sc->sc_dar; 3926941Ssam idccyl[ui->ui_unit].dar_sect = 0; 3936941Ssam sn = (st->nsect - sn) * st->nbps; 3946941Ssam if (sn > bp->b_bcount) 3956941Ssam sn = bp->b_bcount; 3966941Ssam sc->sc_bcnt = sn; 3976941Ssam sc->sc_resid = bp->b_bcount; 3986941Ssam sc->sc_unit = ui->ui_slave; 3996941Ssam printd(", bcr 0x%x, cmd 0x%x\n", sn, cmd); 4006941Ssam um->um_cmd = cmd; 4016941Ssam (void) ubago(ui); 4026941Ssam return (1); 4036941Ssam } 4046941Ssam 4056941Ssam idcdgo(um) 4066941Ssam register struct uba_ctlr *um; 4076941Ssam { 4086941Ssam register struct idcdevice *idcaddr = (struct idcdevice *)um->um_addr; 4096941Ssam register struct idc_softc *sc = &idc_softc; 4106941Ssam 4116941Ssam /* 4126941Ssam * VERY IMPORTANT: must load registers in this order. 4136941Ssam */ 4146941Ssam idcaddr->idcbar = sc->sc_ubaddr = um->um_ubinfo&0x3ffff; 4156941Ssam idcaddr->idcbcr = -sc->sc_bcnt; 4166941Ssam idcaddr->idcdar = sc->sc_dar; 4176941Ssam printd("idcdgo, ubinfo 0x%x, cmd 0x%x\n", um->um_ubinfo, um->um_cmd); 4186941Ssam idcaddr->idccsr = um->um_cmd; 4196941Ssam trace('go', um); 4206941Ssam um->um_tab.b_active = 2; 4216941Ssam /*** CLEAR SPURIOUS ATTN ON R80? ***/ 4226941Ssam } 4236941Ssam 4246941Ssam idcintr(idc) 4256941Ssam int idc; 4266941Ssam { 4276941Ssam register struct uba_ctlr *um = idcminfo[idc]; 4286941Ssam register struct uba_device *ui; 4296941Ssam register struct idcdevice *idcaddr = (struct idcdevice *)um->um_addr; 4306941Ssam register struct idc_softc *sc = &idc_softc; 4316941Ssam register struct buf *bp, *dp; 4326941Ssam struct idcst *st; 4336941Ssam int unit, as, er, cmd, ds = 0; 4346941Ssam 4356941Ssam printd("idcintr, idccsr 0x%x", idcaddr->idccsr); 4366941Ssam top: 4376941Ssam idcwticks = 0; 4386941Ssam trace('intr', um->um_tab.b_active); 4396941Ssam if (um->um_tab.b_active == 2) { 4406941Ssam /* 4416941Ssam * Process a data transfer complete interrupt. 4426941Ssam */ 4436941Ssam um->um_tab.b_active = 1; 4446941Ssam dp = um->um_tab.b_actf; 4456941Ssam bp = dp->b_actf; 4466941Ssam ui = idcdinfo[dkunit(bp)]; 4476941Ssam unit = ui->ui_slave; 4486941Ssam st = &idcst[ui->ui_type]; 4496941Ssam idcaddr->idccsr = IDC_IE|IDC_CRDY|(unit<<8); 4506941Ssam if ((er = idcaddr->idccsr) & IDC_ERR) { 4516941Ssam if (er & IDC_DE) { 4526941Ssam idcaddr->idcmpr = IDCGS_GETSTAT; 4536941Ssam idcaddr->idccsr = IDC_GETSTAT|(unit<<8); 4546941Ssam idcwait(idcaddr, 0); 4556941Ssam ds = idcaddr->idcmpr; 4566941Ssam idcaddr->idccsr = 4576941Ssam IDC_IE|IDC_CRDY|(1<<(unit+16)); 4586941Ssam } 4596941Ssam printd(", er 0x%x, ds 0x%x", er, ds); 4606941Ssam if (ds & IDCDS_WL) { 4616941Ssam printf("rb%d: write locked\n", dkunit(bp)); 4626941Ssam bp->b_flags |= B_ERROR; 4636941Ssam } else if (++um->um_tab.b_errcnt > 28 || er&IDC_HARD) { 4646941Ssam hard: 4656941Ssam harderr(bp, "rb"); 4666941Ssam printf("csr=%b ds=%b\n", er, IDCCSR_BITS, ds, 4676941Ssam ui->ui_type?IDCRB80DS_BITS:IDCRB02DS_BITS); 4686941Ssam bp->b_flags |= B_ERROR; 4696941Ssam } else if (er & IDC_DCK) { 4706941Ssam switch (er & IDC_ECS) { 4716941Ssam case IDC_ECS_NONE: 4726941Ssam break; 4736941Ssam case IDC_ECS_SOFT: 4746941Ssam idcecc(ui); 4756941Ssam break; 4766941Ssam case IDC_ECS_HARD: 4776941Ssam default: 4786941Ssam goto hard; 4796941Ssam } 4806941Ssam } else 4816941Ssam /* recoverable error, set up for retry */ 4826941Ssam goto seek; 4836941Ssam } 4846941Ssam if ((sc->sc_resid -= sc->sc_bcnt) != 0) { 4856941Ssam sc->sc_ubaddr += sc->sc_bcnt; 4866941Ssam /* 4876941Ssam * Current transfer is complete, have 4886941Ssam * we overflowed to the next track? 4896941Ssam */ 4906941Ssam if ((sc->sc_sect += sc->sc_bcnt/st->nbps) == st->nsect) { 4916941Ssam sc->sc_sect = 0; 4926941Ssam if (++sc->sc_trk == st->ntrak) { 4936941Ssam sc->sc_trk = 0; 4946941Ssam sc->sc_cyl++; 4956941Ssam } else if (ui->ui_type) { 4966941Ssam /* 4976941Ssam * RB80 can change heads just by 4986941Ssam * loading the disk address register. 4996941Ssam */ 5006941Ssam idcaddr->idccsr = IDC_SEEK|IDC_CRDY| 5016941Ssam IDC_IE|(unit<<8); 5026941Ssam printd(", change to track 0x%x", sc->sc_dar); 5036941Ssam idcaddr->idcdar = sc->sc_dar; 5046941Ssam idccyl[ui->ui_unit].dar_dar = sc->sc_dar; 5056941Ssam idccyl[ui->ui_unit].dar_sect = 0; 5066941Ssam goto cont; 5076941Ssam } 5086941Ssam /* 5096941Ssam * Changing tracks on RB02 or cylinders 5106941Ssam * on RB80, start a seek. 5116941Ssam */ 5126941Ssam seek: 5136941Ssam cmd = IDC_IE|IDC_SEEK|(unit<<8); 5146941Ssam idcaddr->idccsr = cmd|IDC_CRDY; 5156941Ssam idcaddr->idcdar = sc->sc_dar; 5166941Ssam printd(", seek to 0x%x\n", sc->sc_dar); 5176941Ssam idccyl[ui->ui_unit].dar_dar = sc->sc_dar; 5186941Ssam idccyl[ui->ui_unit].dar_sect = 0; 5196941Ssam sc->sc_bcnt = 0; 5206941Ssam idcaddr->idccsr = cmd; 5216941Ssam if (ui->ui_type) { 5226941Ssam if (idcwait(idcaddr, 10) == 0) 5236941Ssam return; 5246941Ssam idcaddr->idccsr &= ~IDC_ATTN; 5256941Ssam if (idcaddr->idccsr & IDC_DRDY) 5266941Ssam goto top; 5276941Ssam } 5286941Ssam } else { 5296941Ssam /* 5306941Ssam * Continue transfer on current track. 5316941Ssam */ 5326941Ssam cont: 5336941Ssam sc->sc_bcnt = (st->nsect-sc->sc_sect)*st->nbps; 5346941Ssam if (sc->sc_bcnt > sc->sc_resid) 5356941Ssam sc->sc_bcnt = sc->sc_resid; 5366941Ssam if (bp->b_flags & B_READ) 5376941Ssam cmd = IDC_IE|IDC_READ|(unit<<8); 5386941Ssam else 5396941Ssam cmd = IDC_IE|IDC_WRITE|(unit<<8); 5406941Ssam idcaddr->idccsr = cmd|IDC_CRDY; 5416941Ssam idcaddr->idcbar = sc->sc_ubaddr; 5426941Ssam idcaddr->idcbcr = -sc->sc_bcnt; 5436941Ssam idcaddr->idcdar = sc->sc_dar; 5446941Ssam printd(", continue I/O 0x%x, 0x%x\n", sc->sc_dar, sc->sc_bcnt); 5456941Ssam idcaddr->idccsr = cmd; 5466941Ssam um->um_tab.b_active = 2; 5476941Ssam } 5486941Ssam return; 5496941Ssam } 5506941Ssam /* 5516941Ssam * Entire transfer is done, clean up. 5526941Ssam */ 5536941Ssam ubadone(um); 5546941Ssam dk_busy &= ~(1 << ui->ui_dk); 5556941Ssam um->um_tab.b_active = 0; 5566941Ssam um->um_tab.b_errcnt = 0; 5576941Ssam um->um_tab.b_actf = dp->b_forw; 5586941Ssam dp->b_active = 0; 5596941Ssam dp->b_errcnt = 0; 5606941Ssam dp->b_actf = bp->av_forw; 5616941Ssam trace('done', dp); trace(um->um_tab.b_actf, dp->b_actf); 5626941Ssam bp->b_resid = sc->sc_resid; 5636941Ssam printd(", iodone, resid 0x%x\n", bp->b_resid); 5646941Ssam iodone(bp); 5656941Ssam if (dp->b_actf) 5666941Ssam if (idcustart(ui)) 5676941Ssam return; 5686941Ssam } else if (um->um_tab.b_active == 1) { 5696941Ssam /* 5706941Ssam * Got an interrupt while setting up for a command 5716941Ssam * or doing a mid-transfer seek. Save any attentions 5726941Ssam * for later and process a mid-transfer seek complete. 5736941Ssam */ 5746941Ssam as = idcaddr->idccsr; 5756941Ssam idcaddr->idccsr = IDC_IE|IDC_CRDY|(as&IDC_ATTN); 5766941Ssam as = (as >> 16) & 0xf; 5776941Ssam unit = sc->sc_unit; 5786941Ssam sc->sc_softas |= as & ~(1<<unit); 5796941Ssam if (as & (1<<unit)) { 5806941Ssam printd(", seek1 complete"); 5816941Ssam um->um_tab.b_active = 2; 5826941Ssam goto top; 5836941Ssam } 5846941Ssam printd(", as1 %o\n", as); 5856941Ssam return; 5866941Ssam } 5876941Ssam /* 5886941Ssam * Process any seek initiated or complete interrupts. 5896941Ssam */ 5906941Ssam as = idcaddr->idccsr; 5916941Ssam idcaddr->idccsr = IDC_IE|IDC_CRDY|(as&IDC_ATTN); 5926941Ssam as = ((as >> 16) & 0xf) | sc->sc_softas; 5936941Ssam sc->sc_softas = 0; 5946941Ssam trace('as', as); 5956941Ssam printd(", as %o", as); 5966941Ssam for (unit = 0; unit < NRB; unit++) 5976941Ssam if (as & (1<<unit)) { 5986941Ssam as &= ~(1<<unit); 5996941Ssam idcaddr->idccsr = IDC_IE|IDC_CRDY|(unit<<8); 6006941Ssam ui = idcdinfo[unit]; 6016941Ssam if (ui) { 6026941Ssam printd(", attn unit %d", unit); 6036941Ssam if (idcaddr->idccsr & IDC_DRDY) 6046941Ssam if (idcustart(ui)) { 6056941Ssam sc->sc_softas = as; 6066941Ssam return; 6076941Ssam } 6086941Ssam } else { 6096941Ssam printd(", unsol. intr. unit %d", unit); 6106941Ssam } 6116941Ssam } 6126941Ssam printd("\n"); 6136941Ssam if (um->um_tab.b_actf && um->um_tab.b_active == 0) { 6146941Ssam trace('stum',um->um_tab.b_actf); 6156941Ssam idcstart(um); 6166941Ssam } 6176941Ssam } 6186941Ssam 6196941Ssam idcwait(addr, cnt) 6206941Ssam register struct idcdevice *addr; 6216941Ssam register int cnt; 6226941Ssam { 6236941Ssam register int i; 6246941Ssam 6256941Ssam while (--cnt && (addr->idccsr & IDC_CRDY) == 0) 6266941Ssam for (i = 10; i; i--) 6276941Ssam ; 6286941Ssam return (cnt); 6296941Ssam } 6306941Ssam 6317728Sroot idcread(dev, uio) 6326941Ssam dev_t dev; 6337728Sroot struct uio *uio; 6346941Ssam { 6356941Ssam register int unit = minor(dev) >> 3; 6366941Ssam 6376941Ssam if (unit >= NRB) 638*8161Sroot return (ENXIO); 639*8161Sroot return (physio(idcstrategy, &ridcbuf[unit], dev, B_READ, minphys, uio)); 6406941Ssam } 6416941Ssam 6427834Sroot idcwrite(dev, uio) 6436941Ssam dev_t dev; 6447834Sroot struct uio *uio; 6456941Ssam { 6466941Ssam register int unit = minor(dev) >> 3; 6476941Ssam 6486941Ssam if (unit >= NRB) 649*8161Sroot return (ENXIO); 650*8161Sroot return (physio(idcstrategy, &ridcbuf[unit], dev, B_WRITE, minphys, uio)); 6516941Ssam } 6526941Ssam 6536941Ssam idcecc(ui) 6546941Ssam register struct uba_device *ui; 6556941Ssam { 6566941Ssam register struct idcdevice *idc = (struct idcdevice *)ui->ui_addr; 6576941Ssam register struct buf *bp = idcutab[ui->ui_unit].b_actf; 6586941Ssam register struct uba_ctlr *um = ui->ui_mi; 6596941Ssam register struct idcst *st; 6606941Ssam register int i; 6616941Ssam struct uba_regs *ubp = ui->ui_hd->uh_uba; 6626941Ssam int bit, byte, mask; 6636941Ssam caddr_t addr; 6646941Ssam int reg, npf, o; 6656941Ssam int cn, tn, sn; 6666941Ssam 6676941Ssam printf("idcecc: HELP!\n"); 6686941Ssam npf = btop(idc->idcbcr + idc_softc.sc_bcnt) - 1;; 6696941Ssam reg = btop(idc_softc.sc_ubaddr) + npf; 6706941Ssam o = (int)bp->b_un.b_addr & PGOFSET; 6716941Ssam st = &idcst[ui->ui_type]; 6726941Ssam cn = idc_softc.sc_cyl; 6736941Ssam tn = idc_softc.sc_trk; 6746941Ssam sn = idc_softc.sc_sect; 6756941Ssam um->um_tab.b_active = 1; /* Either complete or continuing... */ 6766941Ssam printf("rb%d%c: soft ecc sn%d\n", dkunit(bp), 6776941Ssam 'a'+(minor(bp->b_dev)&07), 6786941Ssam (cn*st->ntrak + tn) * st->nsect + sn + npf); 6796941Ssam mask = idc->idceccpat; 6806941Ssam i = idc->idceccpos - 1; /* -1 makes 0 origin */ 6816941Ssam bit = i&07; 6826941Ssam i = (i&~07)>>3; 6836941Ssam byte = i + o; 6846941Ssam while (i < 512 && (int)ptob(npf)+i < idc_softc.sc_bcnt && bit > -11) { 6856941Ssam addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ 6866941Ssam (byte & PGOFSET); 6876941Ssam putmemc(addr, getmemc(addr)^(mask<<bit)); 6886941Ssam byte++; 6896941Ssam i++; 6906941Ssam bit -= 8; 6916941Ssam } 6926941Ssam idc_softc.sc_bcnt += idc->idcbcr; 6936941Ssam um->um_tab.b_errcnt = 0; /* error has been corrected */ 6946941Ssam return; 6956941Ssam } 6966941Ssam 6976941Ssam idcreset(uban) 6986941Ssam int uban; 6996941Ssam { 7006941Ssam register struct uba_ctlr *um; 7016941Ssam register struct uba_device *ui; 7026941Ssam register unit; 7036941Ssam 7046941Ssam if ((um = idcminfo[0]) == 0 || um->um_ubanum != uban || 7056941Ssam um->um_alive == 0) 7066941Ssam return; 7076941Ssam printf(" idc0"); 7086941Ssam um->um_tab.b_active = 0; 7096941Ssam um->um_tab.b_actf = um->um_tab.b_actl = 0; 7106941Ssam if (um->um_ubinfo) { 7116941Ssam printf("<%d>", (um->um_ubinfo>>28)&0xf); 7126941Ssam ubadone(um); 7136941Ssam } 7146941Ssam for (unit = 0; unit < NRB; unit++) { 7156941Ssam if ((ui = idcdinfo[unit]) == 0 || ui->ui_alive == 0) 7166941Ssam continue; 7176941Ssam idcutab[unit].b_active = 0; 7186941Ssam (void) idcustart(ui); 7196941Ssam } 7206941Ssam (void) idcstart(um); 7216941Ssam } 7226941Ssam 7236941Ssam idcwatch() 7246941Ssam { 7256941Ssam register struct uba_ctlr *um; 7266941Ssam register unit; 7276941Ssam 7286941Ssam timeout(idcwatch, (caddr_t)0, hz); 7296941Ssam um = idcminfo[0]; 7306941Ssam if (um == 0 || um->um_alive == 0) 7316941Ssam return; 7326941Ssam if (um->um_tab.b_active == 0) { 7336941Ssam for (unit = 0; unit < NRB; unit++) 7346941Ssam if (idcutab[unit].b_active) 7356941Ssam goto active; 7366941Ssam idcwticks = 0; 7376941Ssam return; 7386941Ssam } 7396941Ssam active: 7406941Ssam idcwticks++; 7416941Ssam if (idcwticks >= 20) { 7426941Ssam idcwticks = 0; 7436941Ssam printf("idc0: lost interrupt\n"); 7446941Ssam idcintr(0); 7456941Ssam } 7466941Ssam } 7476941Ssam 7486941Ssam idcdump(dev) 7496941Ssam dev_t dev; 7506941Ssam { 7516941Ssam #ifdef notdef 7526941Ssam struct idcdevice *idcaddr; 7536941Ssam char *start; 7546941Ssam int num, blk, unit, dbsize; 7556941Ssam struct size *sizes; 7566941Ssam register struct uba_regs *uba; 7576941Ssam register struct uba_device *ui; 7586941Ssam struct idcst *st; 7596941Ssam 7606941Ssam unit = minor(dev) >> 3; 7616941Ssam if (unit >= NRB) 7626941Ssam return (ENXIO); 7636941Ssam #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) 7646941Ssam ui = phys(struct uba_device *, idcdinfo[unit]); 7656941Ssam if (ui->ui_alive == 0) 7666941Ssam return (ENXIO); 7676941Ssam uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 7686941Ssam ubainit(uba); 7696941Ssam idcaddr = (struct idcdevice *)ui->ui_physaddr; 7706941Ssam num = maxfree; 7716941Ssam start = 0; 7726941Ssam /*** 7736941Ssam idcaddr->idccs1 = IDC_CCLR; 7746941Ssam idcaddr->idccs2 = unit; 7756941Ssam idcaddr->idccs1 = idctypes[ui->ui_type]|IDC_DCLR|IDC_GO; 7766941Ssam idcwait(idcaddr); 7776941Ssam dbsize = 20 or 31; 7786941Ssam ***/ 7796941Ssam st = &idcst[ui->ui_type]; 7806941Ssam sizes = phys(struct size *, st->sizes); 7816941Ssam if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) 7826941Ssam return (EINVAL); 7836941Ssam while (num > 0) { 7846941Ssam register struct pte *io; 7856941Ssam register int i; 7866941Ssam int cn, sn, tn; 7876941Ssam daddr_t bn; 7886941Ssam 7896941Ssam blk = num > dbsize ? dbsize : num; 7906941Ssam io = uba->uba_map; 7916941Ssam for (i = 0; i < blk; i++) 7926941Ssam *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV; 7936941Ssam *(int *)io = 0; 7946941Ssam bn = dumplo + btop(start); 7956941Ssam cn = bn/st->nspc + sizes[minor(dev)&07].cyloff; 7966941Ssam sn = bn%st->nspc; 7976941Ssam tn = sn/st->nsect; 7986941Ssam sn = sn%st->nsect; 7996941Ssam /*** 8006941Ssam idcaddr->idccyl = cn; 8016941Ssam rp = (short *) &idcaddr->idcda; 8026941Ssam *rp = (tn << 8) + sn; 8036941Ssam *--rp = 0; 8046941Ssam *--rp = -blk*NBPG / sizeof (short); 8056941Ssam *--rp = idctypes[ui->ui_type]|IDC_GO|IDC_WRITE; 8066941Ssam idcwait(idcaddr); 8076941Ssam ***/ 8086941Ssam if (idcaddr->idccsr & IDC_ERR) 8096941Ssam return (EIO); 8106941Ssam start += blk*NBPG; 8116941Ssam num -= blk; 8126941Ssam } 8136941Ssam return (0); 8146941Ssam #else 8156941Ssam return (ENXIO); 8166941Ssam #endif 8176941Ssam } 8186941Ssam #endif 819