123328Smckusick /* 229221Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 323328Smckusick * All rights reserved. The Berkeley software License Agreement 423328Smckusick * specifies the terms and conditions for redistribution. 523328Smckusick * 6*36035Skarels * @(#)idc.c 7.6 (Berkeley) 10/22/88 723328Smckusick */ 86941Ssam 96941Ssam #include "rb.h" 106941Ssam #if NIDC > 0 118569Sroot int idcdebug = 0; 128569Sroot #define printd if(idcdebug)printf 138569Sroot int idctrb[1000]; 148569Sroot int *trp = idctrb; 158608Sroot #define trace(a,b) {*trp++ = *(int*)a; *trp++ = (int)b; if(trp>&idctrb[998])trp=idctrb;} 166941Ssam /* 176941Ssam * IDC (RB730) disk driver 186941Ssam * 196941Ssam * There can only ever be one IDC on a machine, 206941Ssam * and only on a VAX-11/730. We take advantage 216941Ssam * of that to simplify the driver. 226941Ssam * 236941Ssam * TODO: 246941Ssam * ecc 256941Ssam */ 2617073Sbloom #include "param.h" 2717073Sbloom #include "systm.h" 2817073Sbloom #include "buf.h" 2917073Sbloom #include "conf.h" 3017073Sbloom #include "dir.h" 3117073Sbloom #include "user.h" 3217073Sbloom #include "map.h" 3317073Sbloom #include "vm.h" 3434524Skarels #include "ioctl.h" 3534524Skarels #include "disklabel.h" 3630388Skarels #include "dkstat.h" 3717073Sbloom #include "cmap.h" 3817073Sbloom #include "dkbad.h" 3917073Sbloom #include "uio.h" 4017073Sbloom #include "kernel.h" 4118316Sralph #include "syslog.h" 426941Ssam 4334524Skarels #include "../machine/pte.h" 448475Sroot #include "../vax/cpu.h" 4517073Sbloom #include "ubareg.h" 4617073Sbloom #include "ubavar.h" 4717073Sbloom #include "idcreg.h" 486941Ssam 496941Ssam struct idc_softc { 506941Ssam int sc_bcnt; /* number of bytes to transfer */ 516941Ssam int sc_resid; /* total number of bytes to transfer */ 526941Ssam int sc_ubaddr; /* Unibus address of data */ 536941Ssam short sc_unit; /* unit doing transfer */ 546941Ssam short sc_softas; /* software attention summary bits */ 556941Ssam union idc_dar { 566941Ssam long dar_l; 576941Ssam u_short dar_w[2]; 586941Ssam u_char dar_b[4]; 596941Ssam } sc_un; /* prototype disk address register */ 606941Ssam } idc_softc; 616941Ssam 626941Ssam #define dar_dar dar_l /* the whole disk address */ 636941Ssam #define dar_cyl dar_w[1] /* cylinder address */ 646941Ssam #define dar_trk dar_b[1] /* track */ 656941Ssam #define dar_sect dar_b[0] /* sector */ 666941Ssam #define sc_dar sc_un.dar_dar 676941Ssam #define sc_cyl sc_un.dar_cyl 686941Ssam #define sc_trk sc_un.dar_trk 696941Ssam #define sc_sect sc_un.dar_sect 706941Ssam 7124739Sbloom #define idcunit(dev) (minor(dev) >> 3) 7224739Sbloom 736941Ssam /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 746941Ssam struct size { 756941Ssam daddr_t nblocks; 766941Ssam int cyloff; 776941Ssam } rb02_sizes[8] ={ 786941Ssam 15884, 0, /* A=cyl 0 thru 399 */ 796941Ssam 4480, 400, /* B=cyl 400 thru 510 */ 806941Ssam 20480, 0, /* C=cyl 0 thru 511 */ 816941Ssam 0, 0, 826941Ssam 0, 0, 836941Ssam 0, 0, 846941Ssam 0, 0, 856941Ssam 0, 0, 866941Ssam }, rb80_sizes[8] ={ 876941Ssam 15884, 0, /* A=cyl 0 thru 36 */ 886941Ssam 33440, 37, /* B=cyl 37 thru 114 */ 896941Ssam 242606, 0, /* C=cyl 0 thru 558 */ 906941Ssam 0, 0, 916941Ssam 0, 0, 926941Ssam 0, 0, 936941Ssam 82080, 115, /* G=cyl 115 thru 304 */ 946941Ssam 110143, 305, /* H=cyl 305 thru 558 */ 956941Ssam }; 966941Ssam /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 976941Ssam 986941Ssam int idcprobe(), idcslave(), idcattach(), idcdgo(), idcintr(); 996941Ssam struct uba_ctlr *idcminfo[NIDC]; 1006941Ssam struct uba_device *idcdinfo[NRB]; 1016941Ssam 1026941Ssam u_short idcstd[] = { 0174400, 0}; 1036941Ssam struct uba_driver idcdriver = 1046941Ssam { idcprobe, idcslave, idcattach, idcdgo, idcstd, "rb", idcdinfo, "idc", idcminfo, 0 }; 1056941Ssam struct buf idcutab[NRB]; 1066941Ssam union idc_dar idccyl[NRB]; 1076941Ssam 1086941Ssam struct idcst { 1096941Ssam short nbps; 1106941Ssam short nsect; 1116941Ssam short ntrak; 1126941Ssam short nspc; 1136941Ssam short ncyl; 1146941Ssam struct size *sizes; 1156941Ssam } idcst[] = { 1166941Ssam 256, NRB02SECT, NRB02TRK, NRB02SECT*NRB02TRK, NRB02CYL, rb02_sizes, 1176941Ssam 512, NRB80SECT, NRB80TRK, NRB80SECT*NRB80TRK, NRB80CYL, rb80_sizes, 1186941Ssam }; 1196941Ssam 1206941Ssam #define b_cylin b_resid 1216941Ssam 1226941Ssam int idcwstart, idcwticks, idcwatch(); 1236941Ssam 1248608Sroot /*ARGSUSED*/ 1256941Ssam idcprobe(reg) 1266941Ssam caddr_t reg; 1276941Ssam { 1286941Ssam register int br, cvec; 1296941Ssam register struct idcdevice *idcaddr; 1306941Ssam 1316941Ssam #ifdef lint 1326941Ssam br = 0; cvec = br; br = cvec; 1336941Ssam #endif 1346941Ssam idcaddr = (struct idcdevice *)((caddr_t)uba_hd[0].uh_uba + 0x200); 1356941Ssam idcaddr->idccsr = IDC_ATTN|IDC_IE; 1366941Ssam while ((idcaddr->idccsr & IDC_CRDY) == 0) 1376941Ssam ; 1386941Ssam idcaddr->idccsr = IDC_ATTN|IDC_CRDY; 1397414Skre return (sizeof (struct idcdevice)); 1406941Ssam } 1416941Ssam 1428608Sroot /*ARGSUSED*/ 1436941Ssam idcslave(ui, reg) 1446941Ssam struct uba_device *ui; 1456941Ssam caddr_t reg; 1466941Ssam { 1476941Ssam register struct idcdevice *idcaddr; 1486941Ssam register int i; 1496941Ssam 1506941Ssam idcaddr = (struct idcdevice *)((caddr_t)uba_hd[0].uh_uba + 0x200); 1516941Ssam ui->ui_type = 0; 1526941Ssam idcaddr->idcmpr = IDCGS_GETSTAT; 1536941Ssam idcaddr->idccsr = IDC_GETSTAT|(ui->ui_slave<<8); 1548721Sroot (void) idcwait(idcaddr, 0); 1556941Ssam i = idcaddr->idcmpr; 1566941Ssam idcaddr->idccsr = IDC_CRDY|(1<<(ui->ui_slave+16)); 1578721Sroot (void) idcwait(idcaddr, 0); 15819914Sedward /* read header to synchronize microcode */ 15919914Sedward idcaddr->idccsr = (ui->ui_slave<<8)|IDC_RHDR; 16019914Sedward (void) idcwait(idcaddr, 0); 16119914Sedward i = idcaddr->idcmpr; /* read header word 1 */ 16219914Sedward i = idcaddr->idcmpr; /* read header word 2 */ 1638608Sroot #ifdef lint 16419914Sedward i = i; 1658608Sroot #endif 16619914Sedward if ((idcaddr->idccsr & (IDC_ERR|IDC_R80)) == IDC_R80) 1676941Ssam ui->ui_type = 1; 16819914Sedward else if ((idcaddr->idccsr & (IDC_DE|IDC_R80)) == 0) 16917558Skarels /* 17017558Skarels * RB02 may not have pack spun up, just look for drive error. 17117558Skarels */ 17219914Sedward ui->ui_type = 0; 17319914Sedward else 17419914Sedward return (0); 1756941Ssam return (1); 1766941Ssam } 1776941Ssam 1786941Ssam idcattach(ui) 1796941Ssam register struct uba_device *ui; 1806941Ssam { 1816941Ssam 1826941Ssam /* 1836941Ssam * Fix all addresses to correspond 1846941Ssam * to the "real" IDC address. 1856941Ssam */ 1866941Ssam ui->ui_mi->um_addr = ui->ui_addr = (caddr_t)uba_hd[0].uh_uba + 0x200; 1876941Ssam ui->ui_physaddr = (caddr_t)uba_hd[0].uh_physuba + 0x200; 1886941Ssam if (idcwstart == 0) { 1896941Ssam timeout(idcwatch, (caddr_t)0, hz); 1906941Ssam idcwstart++; 1916941Ssam } 1926941Ssam if (ui->ui_dk >= 0) 1936941Ssam if (ui->ui_type) 1946941Ssam dk_mspw[ui->ui_dk] = 1.0 / (60 * NRB80SECT * 256); 1956941Ssam else 1966941Ssam dk_mspw[ui->ui_dk] = 1.0 / (60 * NRB02SECT * 128); 1976941Ssam idccyl[ui->ui_unit].dar_dar = -1; 1986941Ssam ui->ui_flags = 0; 1996941Ssam } 2008569Sroot 2018569Sroot idcopen(dev) 2028569Sroot dev_t dev; 2038569Sroot { 20424739Sbloom register int unit = idcunit(dev); 2058569Sroot register struct uba_device *ui; 2068569Sroot 2078569Sroot if (unit >= NRB || (ui = idcdinfo[unit]) == 0 || ui->ui_alive == 0) 2088569Sroot return (ENXIO); 2098569Sroot return (0); 2108569Sroot } 2116941Ssam 2126941Ssam idcstrategy(bp) 2136941Ssam register struct buf *bp; 2146941Ssam { 2156941Ssam register struct uba_device *ui; 2166941Ssam register struct idcst *st; 2176941Ssam register int unit; 2186941Ssam register struct buf *dp; 2196941Ssam int xunit = minor(bp->b_dev) & 07; 2206941Ssam long bn, sz; 2216941Ssam 2226941Ssam sz = (bp->b_bcount+511) >> 9; 22324739Sbloom unit = idcunit(bp->b_dev); 22424739Sbloom if (unit >= NRB) { 22524739Sbloom bp->b_error = ENXIO; 2266941Ssam goto bad; 22724739Sbloom } 2286941Ssam ui = idcdinfo[unit]; 22924739Sbloom if (ui == 0 || ui->ui_alive == 0) { 23024739Sbloom bp->b_error = ENXIO; 2316941Ssam goto bad; 23224739Sbloom } 2336941Ssam st = &idcst[ui->ui_type]; 2346941Ssam if (bp->b_blkno < 0 || 23524739Sbloom (bn = bp->b_blkno)+sz > st->sizes[xunit].nblocks) { 23624784Skarels if (bp->b_blkno == st->sizes[xunit].nblocks) { 23724784Skarels bp->b_resid = bp->b_bcount; 23824739Sbloom goto done; 23924784Skarels } 24024739Sbloom bp->b_error = EINVAL; 2416941Ssam goto bad; 24224739Sbloom } 2436941Ssam if (ui->ui_type == 0) 2446941Ssam bn *= 2; 2456941Ssam bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 2466941Ssam (void) spl5(); 2478608Sroot trace("strt",bp); 2486941Ssam dp = &idcutab[ui->ui_unit]; 2496941Ssam disksort(dp, bp); 2506941Ssam if (dp->b_active == 0) { 2518608Sroot trace("!act",dp); 2526941Ssam (void) idcustart(ui); 2536941Ssam bp = &ui->ui_mi->um_tab; 2546941Ssam if (bp->b_actf && bp->b_active == 0) 2556941Ssam (void) idcstart(ui->ui_mi); 2566941Ssam } 2576941Ssam (void) spl0(); 2586941Ssam return; 2596941Ssam 2606941Ssam bad: 2616941Ssam bp->b_flags |= B_ERROR; 26224739Sbloom done: 2636941Ssam iodone(bp); 2646941Ssam return; 2656941Ssam } 2666941Ssam 2676941Ssam idcustart(ui) 2686941Ssam register struct uba_device *ui; 2696941Ssam { 2706941Ssam register struct buf *bp, *dp; 2716941Ssam register struct uba_ctlr *um; 2726941Ssam register struct idcdevice *idcaddr; 2736941Ssam register struct idcst *st; 2746941Ssam union idc_dar cyltrk; 2756941Ssam daddr_t bn; 2766941Ssam int unit; 2776941Ssam 2786941Ssam if (ui == 0) 2796941Ssam return (0); 2806941Ssam dk_busy &= ~(1<<ui->ui_dk); 2816941Ssam dp = &idcutab[ui->ui_unit]; 2826941Ssam um = ui->ui_mi; 2836941Ssam unit = ui->ui_slave; 2848608Sroot trace("ust", dp); 2856941Ssam idcaddr = (struct idcdevice *)um->um_addr; 2866941Ssam if (um->um_tab.b_active) { 2876941Ssam idc_softc.sc_softas |= 1<<unit; 2888608Sroot trace("umac",idc_softc.sc_softas); 2896941Ssam return (0); 2906941Ssam } 2916941Ssam if ((bp = dp->b_actf) == NULL) { 2928608Sroot trace("!bp",0); 2936941Ssam return (0); 2946941Ssam } 2956941Ssam if (dp->b_active) { 2968608Sroot trace("dpac",dp->b_active); 2976941Ssam goto done; 2986941Ssam } 2996941Ssam dp->b_active = 1; 3006941Ssam /* CHECK DRIVE READY? */ 30124739Sbloom bn = bp->b_blkno; 3028608Sroot trace("seek", bn); 3036941Ssam if (ui->ui_type == 0) 3046941Ssam bn *= 2; 3056941Ssam st = &idcst[ui->ui_type]; 3066941Ssam cyltrk.dar_cyl = bp->b_cylin; 3076941Ssam cyltrk.dar_trk = (bn / st->nsect) % st->ntrak; 3086941Ssam cyltrk.dar_sect = 0; 3096941Ssam printd("idcustart, unit %d, cyltrk 0x%x\n", unit, cyltrk.dar_dar); 3106941Ssam /* 3116941Ssam * If on cylinder, no need to seek. 3126941Ssam */ 3136941Ssam if (cyltrk.dar_dar == idccyl[ui->ui_unit].dar_dar) 3146941Ssam goto done; 3156941Ssam /* 3166941Ssam * RB80 can change heads (tracks) just by loading 3176941Ssam * the disk address register, perform optimization 3186941Ssam * here instead of doing a full seek. 3196941Ssam */ 3206941Ssam if (ui->ui_type && cyltrk.dar_cyl == idccyl[ui->ui_unit].dar_cyl) { 3216941Ssam idcaddr->idccsr = IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8); 3226941Ssam idcaddr->idcdar = cyltrk.dar_dar; 3236941Ssam idccyl[ui->ui_unit].dar_dar = cyltrk.dar_dar; 3246941Ssam goto done; 3256941Ssam } 3266941Ssam /* 3276941Ssam * Need to do a full seek. Select the unit, clear 3286941Ssam * its attention bit, set the command, load the 3296941Ssam * disk address register, and then go. 3306941Ssam */ 3316941Ssam idcaddr->idccsr = 3326941Ssam IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8)|(1<<(unit+16)); 3336941Ssam idcaddr->idcdar = cyltrk.dar_dar; 3346941Ssam idccyl[ui->ui_unit].dar_dar = cyltrk.dar_dar; 3356941Ssam printd(" seek"); 3366941Ssam idcaddr->idccsr = IDC_IE|IDC_SEEK|(unit<<8); 3376941Ssam if (ui->ui_dk >= 0) { 3386941Ssam dk_busy |= 1<<ui->ui_dk; 3396941Ssam dk_seek[ui->ui_dk]++; 3406941Ssam } 3416941Ssam /* 3426941Ssam * RB80's initiate seeks very quickly. Wait for it 3436941Ssam * to come ready rather than taking the interrupt. 3446941Ssam */ 3456941Ssam if (ui->ui_type) { 3466941Ssam if (idcwait(idcaddr, 10) == 0) 3476941Ssam return (1); 3486941Ssam idcaddr->idccsr &= ~IDC_ATTN; 3496941Ssam /* has the seek completed? */ 3506941Ssam if (idcaddr->idccsr & IDC_DRDY) { 3516941Ssam printd(", drdy"); 3526941Ssam idcaddr->idccsr = 3536941Ssam IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8)|(1<<(unit+16)); 3546941Ssam goto done; 3556941Ssam } 3566941Ssam } 3576941Ssam printd(", idccsr = 0x%x\n", idcaddr->idccsr); 3586941Ssam return (1); 3596941Ssam done: 3606941Ssam if (dp->b_active != 2) { 3618608Sroot trace("!=2",dp->b_active); 3626941Ssam dp->b_forw = NULL; 3636941Ssam if (um->um_tab.b_actf == NULL) 3646941Ssam um->um_tab.b_actf = dp; 3656941Ssam else { 3668608Sroot trace("!NUL",um->um_tab.b_actl); 3676941Ssam um->um_tab.b_actl->b_forw = dp; 3686941Ssam } 3696941Ssam um->um_tab.b_actl = dp; 3706941Ssam dp->b_active = 2; 3716941Ssam } 3726941Ssam return (0); 3736941Ssam } 3746941Ssam 3756941Ssam idcstart(um) 3766941Ssam register struct uba_ctlr *um; 3776941Ssam { 3786941Ssam register struct buf *bp, *dp; 3796941Ssam register struct uba_device *ui; 3806941Ssam register struct idcdevice *idcaddr; 3816941Ssam register struct idc_softc *sc; 3826941Ssam struct idcst *st; 3836941Ssam daddr_t bn; 3846941Ssam int sn, tn, cmd; 3856941Ssam 3866941Ssam loop: 3876941Ssam if ((dp = um->um_tab.b_actf) == NULL) { 3888608Sroot trace("nodp",um); 3896941Ssam return (0); 3906941Ssam } 3916941Ssam if ((bp = dp->b_actf) == NULL) { 3928608Sroot trace("nobp", dp); 3936941Ssam um->um_tab.b_actf = dp->b_forw; 3946941Ssam goto loop; 3956941Ssam } 3966941Ssam um->um_tab.b_active = 1; 39724739Sbloom ui = idcdinfo[idcunit(bp->b_dev)]; 39824739Sbloom bn = bp->b_blkno; 3998608Sroot trace("star",bp); 4006941Ssam if (ui->ui_type == 0) 4016941Ssam bn *= 2; 4026941Ssam sc = &idc_softc; 4036941Ssam st = &idcst[ui->ui_type]; 4046941Ssam sn = bn%st->nspc; 4056941Ssam tn = sn/st->nsect; 4066941Ssam sn %= st->nsect; 4076941Ssam sc->sc_sect = sn; 4086941Ssam sc->sc_trk = tn; 4096941Ssam sc->sc_cyl = bp->b_cylin; 4106941Ssam idcaddr = (struct idcdevice *)ui->ui_addr; 4116941Ssam printd("idcstart, unit %d, dar 0x%x", ui->ui_slave, sc->sc_dar); 4126941Ssam if (bp->b_flags & B_READ) 4136941Ssam cmd = IDC_IE|IDC_READ|(ui->ui_slave<<8); 4146941Ssam else 4156941Ssam cmd = IDC_IE|IDC_WRITE|(ui->ui_slave<<8); 4166941Ssam idcaddr->idccsr = IDC_CRDY|cmd; 4176941Ssam if ((idcaddr->idccsr&IDC_DRDY) == 0) { 41824739Sbloom printf("rb%d: not ready\n", idcunit(bp->b_dev)); 4196941Ssam um->um_tab.b_active = 0; 4206941Ssam um->um_tab.b_errcnt = 0; 4216941Ssam dp->b_actf = bp->av_forw; 4226941Ssam dp->b_active = 0; 4236941Ssam bp->b_flags |= B_ERROR; 4246941Ssam iodone(bp); 4256941Ssam goto loop; 4266941Ssam } 4276941Ssam idccyl[ui->ui_unit].dar_dar = sc->sc_dar; 4286941Ssam idccyl[ui->ui_unit].dar_sect = 0; 4296941Ssam sn = (st->nsect - sn) * st->nbps; 4306941Ssam if (sn > bp->b_bcount) 4316941Ssam sn = bp->b_bcount; 4326941Ssam sc->sc_bcnt = sn; 4336941Ssam sc->sc_resid = bp->b_bcount; 4346941Ssam sc->sc_unit = ui->ui_slave; 4356941Ssam printd(", bcr 0x%x, cmd 0x%x\n", sn, cmd); 4366941Ssam um->um_cmd = cmd; 4376941Ssam (void) ubago(ui); 4386941Ssam return (1); 4396941Ssam } 4406941Ssam 4416941Ssam idcdgo(um) 4426941Ssam register struct uba_ctlr *um; 4436941Ssam { 4446941Ssam register struct idcdevice *idcaddr = (struct idcdevice *)um->um_addr; 4456941Ssam register struct idc_softc *sc = &idc_softc; 4466941Ssam 4476941Ssam /* 4486941Ssam * VERY IMPORTANT: must load registers in this order. 4496941Ssam */ 450*36035Skarels idcaddr->idcbar = sc->sc_ubaddr = UBAI_ADDR(um->um_ubinfo); 4516941Ssam idcaddr->idcbcr = -sc->sc_bcnt; 4526941Ssam idcaddr->idcdar = sc->sc_dar; 4536941Ssam printd("idcdgo, ubinfo 0x%x, cmd 0x%x\n", um->um_ubinfo, um->um_cmd); 4546941Ssam idcaddr->idccsr = um->um_cmd; 4558608Sroot trace("go", um); 4566941Ssam um->um_tab.b_active = 2; 4576941Ssam /*** CLEAR SPURIOUS ATTN ON R80? ***/ 4586941Ssam } 4596941Ssam 4606941Ssam idcintr(idc) 4616941Ssam int idc; 4626941Ssam { 4636941Ssam register struct uba_ctlr *um = idcminfo[idc]; 4646941Ssam register struct uba_device *ui; 4656941Ssam register struct idcdevice *idcaddr = (struct idcdevice *)um->um_addr; 4666941Ssam register struct idc_softc *sc = &idc_softc; 4676941Ssam register struct buf *bp, *dp; 4686941Ssam struct idcst *st; 4696941Ssam int unit, as, er, cmd, ds = 0; 4706941Ssam 4716941Ssam printd("idcintr, idccsr 0x%x", idcaddr->idccsr); 4726941Ssam top: 4736941Ssam idcwticks = 0; 4748608Sroot trace("intr", um->um_tab.b_active); 4756941Ssam if (um->um_tab.b_active == 2) { 4766941Ssam /* 4776941Ssam * Process a data transfer complete interrupt. 4786941Ssam */ 4796941Ssam um->um_tab.b_active = 1; 4806941Ssam dp = um->um_tab.b_actf; 4816941Ssam bp = dp->b_actf; 48224739Sbloom ui = idcdinfo[idcunit(bp->b_dev)]; 4836941Ssam unit = ui->ui_slave; 4846941Ssam st = &idcst[ui->ui_type]; 4856941Ssam idcaddr->idccsr = IDC_IE|IDC_CRDY|(unit<<8); 4866941Ssam if ((er = idcaddr->idccsr) & IDC_ERR) { 4876941Ssam if (er & IDC_DE) { 4886941Ssam idcaddr->idcmpr = IDCGS_GETSTAT; 4896941Ssam idcaddr->idccsr = IDC_GETSTAT|(unit<<8); 4908721Sroot (void) idcwait(idcaddr, 0); 4916941Ssam ds = idcaddr->idcmpr; 4926941Ssam idcaddr->idccsr = 4936941Ssam IDC_IE|IDC_CRDY|(1<<(unit+16)); 4946941Ssam } 4956941Ssam printd(", er 0x%x, ds 0x%x", er, ds); 4966941Ssam if (ds & IDCDS_WL) { 49724739Sbloom printf("rb%d: write locked\n", 49824739Sbloom idcunit(bp->b_dev)); 4996941Ssam bp->b_flags |= B_ERROR; 5006941Ssam } else if (++um->um_tab.b_errcnt > 28 || er&IDC_HARD) { 5016941Ssam hard: 50234524Skarels diskerr(bp, "rb", "hard error", LOG_PRINTF, -1, 50334524Skarels (struct disklabel *)0); 50434524Skarels printf(" csr=%b ds=%b\n", er, IDCCSR_BITS, ds, 5056941Ssam ui->ui_type?IDCRB80DS_BITS:IDCRB02DS_BITS); 5066941Ssam bp->b_flags |= B_ERROR; 5076941Ssam } else if (er & IDC_DCK) { 50826476Skarels switch ((int)(er & IDC_ECS)) { 5096941Ssam case IDC_ECS_NONE: 5106941Ssam break; 5116941Ssam case IDC_ECS_SOFT: 5126941Ssam idcecc(ui); 5136941Ssam break; 5146941Ssam case IDC_ECS_HARD: 5156941Ssam default: 5166941Ssam goto hard; 5176941Ssam } 5186941Ssam } else 5196941Ssam /* recoverable error, set up for retry */ 5206941Ssam goto seek; 5216941Ssam } 5226941Ssam if ((sc->sc_resid -= sc->sc_bcnt) != 0) { 5236941Ssam sc->sc_ubaddr += sc->sc_bcnt; 5246941Ssam /* 5256941Ssam * Current transfer is complete, have 5266941Ssam * we overflowed to the next track? 5276941Ssam */ 5286941Ssam if ((sc->sc_sect += sc->sc_bcnt/st->nbps) == st->nsect) { 5296941Ssam sc->sc_sect = 0; 5306941Ssam if (++sc->sc_trk == st->ntrak) { 5316941Ssam sc->sc_trk = 0; 5326941Ssam sc->sc_cyl++; 5336941Ssam } else if (ui->ui_type) { 5346941Ssam /* 5356941Ssam * RB80 can change heads just by 5366941Ssam * loading the disk address register. 5376941Ssam */ 5386941Ssam idcaddr->idccsr = IDC_SEEK|IDC_CRDY| 5396941Ssam IDC_IE|(unit<<8); 5406941Ssam printd(", change to track 0x%x", sc->sc_dar); 5416941Ssam idcaddr->idcdar = sc->sc_dar; 5426941Ssam idccyl[ui->ui_unit].dar_dar = sc->sc_dar; 5436941Ssam idccyl[ui->ui_unit].dar_sect = 0; 5446941Ssam goto cont; 5456941Ssam } 5466941Ssam /* 5476941Ssam * Changing tracks on RB02 or cylinders 5486941Ssam * on RB80, start a seek. 5496941Ssam */ 5506941Ssam seek: 5516941Ssam cmd = IDC_IE|IDC_SEEK|(unit<<8); 5526941Ssam idcaddr->idccsr = cmd|IDC_CRDY; 5536941Ssam idcaddr->idcdar = sc->sc_dar; 5546941Ssam printd(", seek to 0x%x\n", sc->sc_dar); 5556941Ssam idccyl[ui->ui_unit].dar_dar = sc->sc_dar; 5566941Ssam idccyl[ui->ui_unit].dar_sect = 0; 5576941Ssam sc->sc_bcnt = 0; 5586941Ssam idcaddr->idccsr = cmd; 5596941Ssam if (ui->ui_type) { 5606941Ssam if (idcwait(idcaddr, 10) == 0) 5616941Ssam return; 5626941Ssam idcaddr->idccsr &= ~IDC_ATTN; 5636941Ssam if (idcaddr->idccsr & IDC_DRDY) 5646941Ssam goto top; 5656941Ssam } 5666941Ssam } else { 5676941Ssam /* 5686941Ssam * Continue transfer on current track. 5696941Ssam */ 5706941Ssam cont: 5716941Ssam sc->sc_bcnt = (st->nsect-sc->sc_sect)*st->nbps; 5726941Ssam if (sc->sc_bcnt > sc->sc_resid) 5736941Ssam sc->sc_bcnt = sc->sc_resid; 5746941Ssam if (bp->b_flags & B_READ) 5756941Ssam cmd = IDC_IE|IDC_READ|(unit<<8); 5766941Ssam else 5776941Ssam cmd = IDC_IE|IDC_WRITE|(unit<<8); 5786941Ssam idcaddr->idccsr = cmd|IDC_CRDY; 5796941Ssam idcaddr->idcbar = sc->sc_ubaddr; 5806941Ssam idcaddr->idcbcr = -sc->sc_bcnt; 5816941Ssam idcaddr->idcdar = sc->sc_dar; 5826941Ssam printd(", continue I/O 0x%x, 0x%x\n", sc->sc_dar, sc->sc_bcnt); 5836941Ssam idcaddr->idccsr = cmd; 5846941Ssam um->um_tab.b_active = 2; 5856941Ssam } 5866941Ssam return; 5876941Ssam } 5886941Ssam /* 5896941Ssam * Entire transfer is done, clean up. 5906941Ssam */ 5916941Ssam ubadone(um); 5926941Ssam dk_busy &= ~(1 << ui->ui_dk); 5936941Ssam um->um_tab.b_active = 0; 5946941Ssam um->um_tab.b_errcnt = 0; 5956941Ssam um->um_tab.b_actf = dp->b_forw; 5966941Ssam dp->b_active = 0; 5976941Ssam dp->b_errcnt = 0; 5986941Ssam dp->b_actf = bp->av_forw; 5998608Sroot trace("done", dp); trace(&um->um_tab.b_actf, dp->b_actf); 6006941Ssam bp->b_resid = sc->sc_resid; 6016941Ssam printd(", iodone, resid 0x%x\n", bp->b_resid); 6026941Ssam iodone(bp); 6036941Ssam if (dp->b_actf) 6046941Ssam if (idcustart(ui)) 6056941Ssam return; 6066941Ssam } else if (um->um_tab.b_active == 1) { 6076941Ssam /* 6086941Ssam * Got an interrupt while setting up for a command 6096941Ssam * or doing a mid-transfer seek. Save any attentions 6106941Ssam * for later and process a mid-transfer seek complete. 6116941Ssam */ 6126941Ssam as = idcaddr->idccsr; 6136941Ssam idcaddr->idccsr = IDC_IE|IDC_CRDY|(as&IDC_ATTN); 6146941Ssam as = (as >> 16) & 0xf; 6156941Ssam unit = sc->sc_unit; 6166941Ssam sc->sc_softas |= as & ~(1<<unit); 6176941Ssam if (as & (1<<unit)) { 6186941Ssam printd(", seek1 complete"); 6196941Ssam um->um_tab.b_active = 2; 6206941Ssam goto top; 6216941Ssam } 6226941Ssam printd(", as1 %o\n", as); 6236941Ssam return; 6246941Ssam } 6256941Ssam /* 6266941Ssam * Process any seek initiated or complete interrupts. 6276941Ssam */ 6286941Ssam as = idcaddr->idccsr; 6296941Ssam idcaddr->idccsr = IDC_IE|IDC_CRDY|(as&IDC_ATTN); 6306941Ssam as = ((as >> 16) & 0xf) | sc->sc_softas; 6316941Ssam sc->sc_softas = 0; 6328608Sroot trace("as", as); 6336941Ssam printd(", as %o", as); 6346941Ssam for (unit = 0; unit < NRB; unit++) 6356941Ssam if (as & (1<<unit)) { 6366941Ssam as &= ~(1<<unit); 6376941Ssam idcaddr->idccsr = IDC_IE|IDC_CRDY|(unit<<8); 6386941Ssam ui = idcdinfo[unit]; 6396941Ssam if (ui) { 6406941Ssam printd(", attn unit %d", unit); 6416941Ssam if (idcaddr->idccsr & IDC_DRDY) 6426941Ssam if (idcustart(ui)) { 6436941Ssam sc->sc_softas = as; 6446941Ssam return; 6456941Ssam } 6466941Ssam } else { 6476941Ssam printd(", unsol. intr. unit %d", unit); 6486941Ssam } 6496941Ssam } 6506941Ssam printd("\n"); 6516941Ssam if (um->um_tab.b_actf && um->um_tab.b_active == 0) { 6528608Sroot trace("stum",um->um_tab.b_actf); 6538721Sroot (void) idcstart(um); 6546941Ssam } 6556941Ssam } 6566941Ssam 6578608Sroot idcwait(addr, n) 6586941Ssam register struct idcdevice *addr; 6598608Sroot register int n; 6606941Ssam { 6616941Ssam register int i; 6626941Ssam 6638608Sroot while (--n && (addr->idccsr & IDC_CRDY) == 0) 6646941Ssam for (i = 10; i; i--) 6656941Ssam ; 6668608Sroot return (n); 6676941Ssam } 6686941Ssam 6696941Ssam idcecc(ui) 6706941Ssam register struct uba_device *ui; 6716941Ssam { 6726941Ssam register struct idcdevice *idc = (struct idcdevice *)ui->ui_addr; 6736941Ssam register struct buf *bp = idcutab[ui->ui_unit].b_actf; 6746941Ssam register struct uba_ctlr *um = ui->ui_mi; 6756941Ssam register int i; 6766941Ssam struct uba_regs *ubp = ui->ui_hd->uh_uba; 6776941Ssam int bit, byte, mask; 6786941Ssam caddr_t addr; 6796941Ssam int reg, npf, o; 6806941Ssam 6816941Ssam npf = btop(idc->idcbcr + idc_softc.sc_bcnt) - 1;; 6826941Ssam reg = btop(idc_softc.sc_ubaddr) + npf; 6836941Ssam o = (int)bp->b_un.b_addr & PGOFSET; 6846941Ssam um->um_tab.b_active = 1; /* Either complete or continuing... */ 68534524Skarels diskerr(bp, "rb", "soft ecc", LOG_WARNING, npf, (struct disklabel *)0); 68634524Skarels addlog("\n"); 6876941Ssam mask = idc->idceccpat; 6886941Ssam i = idc->idceccpos - 1; /* -1 makes 0 origin */ 6896941Ssam bit = i&07; 6906941Ssam i = (i&~07)>>3; 6916941Ssam byte = i + o; 6926941Ssam while (i < 512 && (int)ptob(npf)+i < idc_softc.sc_bcnt && bit > -11) { 69325169Smckusick /* 69425169Smckusick * should be: 69525169Smckusick * addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ 69625169Smckusick * (byte & PGOFSET); 69725169Smckusick * but this generates an extzv which hangs the UNIBUS. 69825169Smckusick */ 69925169Smckusick addr = ptob(*(int *)&ubp->uba_map[reg+btop(byte)]&0x1fffff)+ 7006941Ssam (byte & PGOFSET); 7016941Ssam putmemc(addr, getmemc(addr)^(mask<<bit)); 7026941Ssam byte++; 7036941Ssam i++; 7046941Ssam bit -= 8; 7056941Ssam } 7066941Ssam idc_softc.sc_bcnt += idc->idcbcr; 7076941Ssam um->um_tab.b_errcnt = 0; /* error has been corrected */ 7086941Ssam return; 7096941Ssam } 7106941Ssam 7116941Ssam idcreset(uban) 7126941Ssam int uban; 7136941Ssam { 7146941Ssam register struct uba_ctlr *um; 7156941Ssam register struct uba_device *ui; 7166941Ssam register unit; 7176941Ssam 7186941Ssam if ((um = idcminfo[0]) == 0 || um->um_ubanum != uban || 7196941Ssam um->um_alive == 0) 7206941Ssam return; 7216941Ssam printf(" idc0"); 7226941Ssam um->um_tab.b_active = 0; 7236941Ssam um->um_tab.b_actf = um->um_tab.b_actl = 0; 7246941Ssam if (um->um_ubinfo) { 7256941Ssam printf("<%d>", (um->um_ubinfo>>28)&0xf); 7269354Ssam um->um_ubinfo = 0; 7276941Ssam } 7286941Ssam for (unit = 0; unit < NRB; unit++) { 7296941Ssam if ((ui = idcdinfo[unit]) == 0 || ui->ui_alive == 0) 7306941Ssam continue; 7316941Ssam idcutab[unit].b_active = 0; 7326941Ssam (void) idcustart(ui); 7336941Ssam } 7346941Ssam (void) idcstart(um); 7356941Ssam } 7366941Ssam 7376941Ssam idcwatch() 7386941Ssam { 7396941Ssam register struct uba_ctlr *um; 7406941Ssam register unit; 7416941Ssam 7426941Ssam timeout(idcwatch, (caddr_t)0, hz); 7436941Ssam um = idcminfo[0]; 7446941Ssam if (um == 0 || um->um_alive == 0) 7456941Ssam return; 7466941Ssam if (um->um_tab.b_active == 0) { 7476941Ssam for (unit = 0; unit < NRB; unit++) 7486941Ssam if (idcutab[unit].b_active) 7496941Ssam goto active; 7506941Ssam idcwticks = 0; 7516941Ssam return; 7526941Ssam } 7536941Ssam active: 7546941Ssam idcwticks++; 7556941Ssam if (idcwticks >= 20) { 7566941Ssam idcwticks = 0; 7576941Ssam printf("idc0: lost interrupt\n"); 7586941Ssam idcintr(0); 7596941Ssam } 7606941Ssam } 7616941Ssam 7628608Sroot /*ARGSUSED*/ 7636941Ssam idcdump(dev) 7646941Ssam dev_t dev; 7656941Ssam { 7666941Ssam struct idcdevice *idcaddr; 7676941Ssam char *start; 76812147Sroot int num, blk, unit; 7696941Ssam struct size *sizes; 7706941Ssam register struct uba_regs *uba; 7716941Ssam register struct uba_device *ui; 7726941Ssam struct idcst *st; 77312778Ssam union idc_dar dar; 77412147Sroot int nspg; 7756941Ssam 77624739Sbloom unit = idcunit(dev); 7776941Ssam if (unit >= NRB) 7786941Ssam return (ENXIO); 7796941Ssam #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) 7806941Ssam ui = phys(struct uba_device *, idcdinfo[unit]); 7816941Ssam if (ui->ui_alive == 0) 7826941Ssam return (ENXIO); 7836941Ssam uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 7846941Ssam ubainit(uba); 7856941Ssam idcaddr = (struct idcdevice *)ui->ui_physaddr; 78612147Sroot if (idcwait(idcaddr, 100) == 0) 78712147Sroot return (EFAULT); 78812147Sroot /* 78912147Sroot * Since we can only transfer one track at a time, and 79012147Sroot * the rl02 has 256 byte sectors, all the calculations 79112147Sroot * are done in terms of physical sectors (i.e. num and blk 79212147Sroot * are in sectors not NBPG blocks. 79312147Sroot */ 79412147Sroot st = phys(struct idcst *, &idcst[ui->ui_type]); 7956941Ssam sizes = phys(struct size *, st->sizes); 79624211Sbloom if (dumplo < 0) 7976941Ssam return (EINVAL); 79824211Sbloom if (dumplo + maxfree >= sizes[minor(dev)&07].nblocks) 79924211Sbloom num = sizes[minor(dev)&07].nblocks - dumplo; 80012147Sroot nspg = NBPG / st->nbps; 80124211Sbloom num = num * nspg; 80212147Sroot start = 0; 80312147Sroot 8046941Ssam while (num > 0) { 8056941Ssam register struct pte *io; 8066941Ssam register int i; 8076941Ssam daddr_t bn; 8086941Ssam 80912147Sroot bn = (dumplo + btop(start)) * nspg; 81012147Sroot dar.dar_cyl = bn / st->nspc + sizes[minor(dev)&07].cyloff; 81112147Sroot bn %= st->nspc; 81212147Sroot dar.dar_trk = bn / st->nsect; 81312147Sroot dar.dar_sect = bn % st->nsect; 81412147Sroot blk = st->nsect - dar.dar_sect; 81512147Sroot if (num < blk) 81612147Sroot blk = num; 81712147Sroot 8186941Ssam io = uba->uba_map; 81912147Sroot for (i = 0; i < (blk + nspg - 1) / nspg; i++) 8206941Ssam *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV; 8216941Ssam *(int *)io = 0; 82212147Sroot 82312147Sroot idcaddr->idccsr = IDC_CRDY | IDC_SEEK | unit<<8; 82412147Sroot if ((idcaddr->idccsr&IDC_DRDY) == 0) 82512147Sroot return (EFAULT); 82612147Sroot idcaddr->idcdar = dar.dar_dar; 82712147Sroot idcaddr->idccsr = IDC_SEEK | unit << 8; 82812147Sroot while ((idcaddr->idccsr & (IDC_CRDY|IDC_DRDY)) 82912147Sroot != (IDC_CRDY|IDC_DRDY)) 83012147Sroot ; 83112147Sroot if (idcaddr->idccsr & IDC_ERR) { 83212147Sroot printf("rb%d: seek, csr=%b\n", 83312147Sroot unit, idcaddr->idccsr, IDCCSR_BITS); 8346941Ssam return (EIO); 83512147Sroot } 83612147Sroot 83712147Sroot idcaddr->idccsr = IDC_CRDY | IDC_WRITE | unit<<8; 83812147Sroot if ((idcaddr->idccsr&IDC_DRDY) == 0) 83912147Sroot return (EFAULT); 84012147Sroot idcaddr->idcbar = 0; /* start addr 0 */ 84112147Sroot idcaddr->idcbcr = - (blk * st->nbps); 84212147Sroot idcaddr->idcdar = dar.dar_dar; 84312147Sroot idcaddr->idccsr = IDC_WRITE | unit << 8; 84412147Sroot while ((idcaddr->idccsr & (IDC_CRDY|IDC_DRDY)) 84512147Sroot != (IDC_CRDY|IDC_DRDY)) 84612147Sroot ; 84712147Sroot if (idcaddr->idccsr & IDC_ERR) { 84812147Sroot printf("rb%d: write, csr=%b\n", 84912147Sroot unit, idcaddr->idccsr, IDCCSR_BITS); 85012147Sroot return (EIO); 85112147Sroot } 85212147Sroot 85312147Sroot start += blk * st->nbps; 8546941Ssam num -= blk; 8556941Ssam } 8566941Ssam return (0); 8576941Ssam } 85812503Ssam 85912503Ssam idcsize(dev) 86012503Ssam dev_t dev; 86112503Ssam { 86224739Sbloom int unit = idcunit(dev); 86312503Ssam struct uba_device *ui; 86412503Ssam struct idcst *st; 86512503Ssam 86612503Ssam if (unit >= NRB || (ui = idcdinfo[unit]) == 0 || ui->ui_alive == 0) 86712503Ssam return (-1); 86812503Ssam st = &idcst[ui->ui_type]; 86912503Ssam return (st->sizes[minor(dev) & 07].nblocks); 87012503Ssam } 8716941Ssam #endif 872