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*45804Sbostic * @(#)idc.c 7.10 (Berkeley) 12/16/90
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 */
26*45804Sbostic #include "sys/param.h"
27*45804Sbostic #include "sys/systm.h"
28*45804Sbostic #include "sys/buf.h"
29*45804Sbostic #include "sys/conf.h"
30*45804Sbostic #include "sys/user.h"
31*45804Sbostic #include "sys/map.h"
32*45804Sbostic #include "sys/vm.h"
33*45804Sbostic #include "sys/ioctl.h"
34*45804Sbostic #include "sys/disklabel.h"
35*45804Sbostic #include "sys/dkstat.h"
36*45804Sbostic #include "sys/cmap.h"
37*45804Sbostic #include "sys/dkbad.h"
38*45804Sbostic #include "sys/uio.h"
39*45804Sbostic #include "sys/kernel.h"
40*45804Sbostic #include "sys/syslog.h"
416941Ssam
42*45804Sbostic #include "../include/pte.h"
43*45804Sbostic #include "../include/cpu.h"
4417073Sbloom #include "ubareg.h"
4517073Sbloom #include "ubavar.h"
4617073Sbloom #include "idcreg.h"
476941Ssam
486941Ssam struct idc_softc {
496941Ssam int sc_bcnt; /* number of bytes to transfer */
506941Ssam int sc_resid; /* total number of bytes to transfer */
516941Ssam int sc_ubaddr; /* Unibus address of data */
526941Ssam short sc_unit; /* unit doing transfer */
536941Ssam short sc_softas; /* software attention summary bits */
546941Ssam union idc_dar {
556941Ssam long dar_l;
566941Ssam u_short dar_w[2];
576941Ssam u_char dar_b[4];
586941Ssam } sc_un; /* prototype disk address register */
596941Ssam } idc_softc;
606941Ssam
616941Ssam #define dar_dar dar_l /* the whole disk address */
626941Ssam #define dar_cyl dar_w[1] /* cylinder address */
636941Ssam #define dar_trk dar_b[1] /* track */
646941Ssam #define dar_sect dar_b[0] /* sector */
656941Ssam #define sc_dar sc_un.dar_dar
666941Ssam #define sc_cyl sc_un.dar_cyl
676941Ssam #define sc_trk sc_un.dar_trk
686941Ssam #define sc_sect sc_un.dar_sect
696941Ssam
7024739Sbloom #define idcunit(dev) (minor(dev) >> 3)
7124739Sbloom
726941Ssam /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */
736941Ssam struct size {
746941Ssam daddr_t nblocks;
756941Ssam int cyloff;
766941Ssam } rb02_sizes[8] ={
776941Ssam 15884, 0, /* A=cyl 0 thru 399 */
786941Ssam 4480, 400, /* B=cyl 400 thru 510 */
796941Ssam 20480, 0, /* C=cyl 0 thru 511 */
806941Ssam 0, 0,
816941Ssam 0, 0,
826941Ssam 0, 0,
836941Ssam 0, 0,
846941Ssam 0, 0,
856941Ssam }, rb80_sizes[8] ={
866941Ssam 15884, 0, /* A=cyl 0 thru 36 */
876941Ssam 33440, 37, /* B=cyl 37 thru 114 */
886941Ssam 242606, 0, /* C=cyl 0 thru 558 */
896941Ssam 0, 0,
906941Ssam 0, 0,
916941Ssam 0, 0,
926941Ssam 82080, 115, /* G=cyl 115 thru 304 */
936941Ssam 110143, 305, /* H=cyl 305 thru 558 */
946941Ssam };
956941Ssam /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */
966941Ssam
976941Ssam int idcprobe(), idcslave(), idcattach(), idcdgo(), idcintr();
986941Ssam struct uba_ctlr *idcminfo[NIDC];
996941Ssam struct uba_device *idcdinfo[NRB];
1006941Ssam
1016941Ssam u_short idcstd[] = { 0174400, 0};
1026941Ssam struct uba_driver idcdriver =
1036941Ssam { idcprobe, idcslave, idcattach, idcdgo, idcstd, "rb", idcdinfo, "idc", idcminfo, 0 };
1046941Ssam struct buf idcutab[NRB];
1056941Ssam union idc_dar idccyl[NRB];
1066941Ssam
1076941Ssam struct idcst {
1086941Ssam short nbps;
1096941Ssam short nsect;
1106941Ssam short ntrak;
1116941Ssam short nspc;
1126941Ssam short ncyl;
1136941Ssam struct size *sizes;
1146941Ssam } idcst[] = {
1156941Ssam 256, NRB02SECT, NRB02TRK, NRB02SECT*NRB02TRK, NRB02CYL, rb02_sizes,
1166941Ssam 512, NRB80SECT, NRB80TRK, NRB80SECT*NRB80TRK, NRB80CYL, rb80_sizes,
1176941Ssam };
1186941Ssam
1196941Ssam #define b_cylin b_resid
1206941Ssam
1216941Ssam int idcwstart, idcwticks, idcwatch();
1226941Ssam
1238608Sroot /*ARGSUSED*/
idcprobe(reg)1246941Ssam idcprobe(reg)
1256941Ssam caddr_t reg;
1266941Ssam {
1276941Ssam register int br, cvec;
1286941Ssam register struct idcdevice *idcaddr;
1296941Ssam
1306941Ssam #ifdef lint
1316941Ssam br = 0; cvec = br; br = cvec;
1326941Ssam #endif
1336941Ssam idcaddr = (struct idcdevice *)((caddr_t)uba_hd[0].uh_uba + 0x200);
1346941Ssam idcaddr->idccsr = IDC_ATTN|IDC_IE;
1356941Ssam while ((idcaddr->idccsr & IDC_CRDY) == 0)
1366941Ssam ;
1376941Ssam idcaddr->idccsr = IDC_ATTN|IDC_CRDY;
1387414Skre return (sizeof (struct idcdevice));
1396941Ssam }
1406941Ssam
1418608Sroot /*ARGSUSED*/
1426941Ssam idcslave(ui, reg)
1436941Ssam struct uba_device *ui;
1446941Ssam caddr_t reg;
1456941Ssam {
1466941Ssam register struct idcdevice *idcaddr;
1476941Ssam register int i;
1486941Ssam
1496941Ssam idcaddr = (struct idcdevice *)((caddr_t)uba_hd[0].uh_uba + 0x200);
1506941Ssam ui->ui_type = 0;
1516941Ssam idcaddr->idcmpr = IDCGS_GETSTAT;
1526941Ssam idcaddr->idccsr = IDC_GETSTAT|(ui->ui_slave<<8);
1538721Sroot (void) idcwait(idcaddr, 0);
1546941Ssam i = idcaddr->idcmpr;
1556941Ssam idcaddr->idccsr = IDC_CRDY|(1<<(ui->ui_slave+16));
1568721Sroot (void) idcwait(idcaddr, 0);
15719914Sedward /* read header to synchronize microcode */
15819914Sedward idcaddr->idccsr = (ui->ui_slave<<8)|IDC_RHDR;
15919914Sedward (void) idcwait(idcaddr, 0);
16019914Sedward i = idcaddr->idcmpr; /* read header word 1 */
16119914Sedward i = idcaddr->idcmpr; /* read header word 2 */
1628608Sroot #ifdef lint
16319914Sedward i = i;
1648608Sroot #endif
16519914Sedward if ((idcaddr->idccsr & (IDC_ERR|IDC_R80)) == IDC_R80)
1666941Ssam ui->ui_type = 1;
16719914Sedward else if ((idcaddr->idccsr & (IDC_DE|IDC_R80)) == 0)
16817558Skarels /*
16917558Skarels * RB02 may not have pack spun up, just look for drive error.
17017558Skarels */
17119914Sedward ui->ui_type = 0;
17219914Sedward else
17319914Sedward return (0);
1746941Ssam return (1);
1756941Ssam }
1766941Ssam
idcattach(ui)1776941Ssam idcattach(ui)
1786941Ssam register struct uba_device *ui;
1796941Ssam {
1806941Ssam
1816941Ssam /*
1826941Ssam * Fix all addresses to correspond
1836941Ssam * to the "real" IDC address.
1846941Ssam */
1856941Ssam ui->ui_mi->um_addr = ui->ui_addr = (caddr_t)uba_hd[0].uh_uba + 0x200;
1866941Ssam ui->ui_physaddr = (caddr_t)uba_hd[0].uh_physuba + 0x200;
1876941Ssam if (idcwstart == 0) {
1886941Ssam timeout(idcwatch, (caddr_t)0, hz);
1896941Ssam idcwstart++;
1906941Ssam }
1916941Ssam if (ui->ui_dk >= 0)
1926941Ssam if (ui->ui_type)
19338173Smckusick dk_wpms[ui->ui_dk] = (60 * NRB80SECT * 256);
1946941Ssam else
19538173Smckusick dk_wpms[ui->ui_dk] = (60 * NRB02SECT * 128);
1966941Ssam idccyl[ui->ui_unit].dar_dar = -1;
1976941Ssam ui->ui_flags = 0;
1986941Ssam }
1998569Sroot
idcopen(dev)2008569Sroot idcopen(dev)
2018569Sroot dev_t dev;
2028569Sroot {
20324739Sbloom register int unit = idcunit(dev);
2048569Sroot register struct uba_device *ui;
2058569Sroot
2068569Sroot if (unit >= NRB || (ui = idcdinfo[unit]) == 0 || ui->ui_alive == 0)
2078569Sroot return (ENXIO);
2088569Sroot return (0);
2098569Sroot }
2106941Ssam
idcstrategy(bp)2116941Ssam idcstrategy(bp)
2126941Ssam register struct buf *bp;
2136941Ssam {
2146941Ssam register struct uba_device *ui;
2156941Ssam register struct idcst *st;
2166941Ssam register int unit;
2176941Ssam register struct buf *dp;
2186941Ssam int xunit = minor(bp->b_dev) & 07;
2196941Ssam long bn, sz;
2206941Ssam
2216941Ssam sz = (bp->b_bcount+511) >> 9;
22224739Sbloom unit = idcunit(bp->b_dev);
22324739Sbloom if (unit >= NRB) {
22424739Sbloom bp->b_error = ENXIO;
2256941Ssam goto bad;
22624739Sbloom }
2276941Ssam ui = idcdinfo[unit];
22824739Sbloom if (ui == 0 || ui->ui_alive == 0) {
22924739Sbloom bp->b_error = ENXIO;
2306941Ssam goto bad;
23124739Sbloom }
2326941Ssam st = &idcst[ui->ui_type];
2336941Ssam if (bp->b_blkno < 0 ||
23424739Sbloom (bn = bp->b_blkno)+sz > st->sizes[xunit].nblocks) {
23524784Skarels if (bp->b_blkno == st->sizes[xunit].nblocks) {
23624784Skarels bp->b_resid = bp->b_bcount;
23724739Sbloom goto done;
23824784Skarels }
23924739Sbloom bp->b_error = EINVAL;
2406941Ssam goto bad;
24124739Sbloom }
2426941Ssam if (ui->ui_type == 0)
2436941Ssam bn *= 2;
2446941Ssam bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff;
2456941Ssam (void) spl5();
2468608Sroot trace("strt",bp);
2476941Ssam dp = &idcutab[ui->ui_unit];
2486941Ssam disksort(dp, bp);
2496941Ssam if (dp->b_active == 0) {
2508608Sroot trace("!act",dp);
2516941Ssam (void) idcustart(ui);
2526941Ssam bp = &ui->ui_mi->um_tab;
2536941Ssam if (bp->b_actf && bp->b_active == 0)
2546941Ssam (void) idcstart(ui->ui_mi);
2556941Ssam }
2566941Ssam (void) spl0();
2576941Ssam return;
2586941Ssam
2596941Ssam bad:
2606941Ssam bp->b_flags |= B_ERROR;
26124739Sbloom done:
2626941Ssam iodone(bp);
2636941Ssam return;
2646941Ssam }
2656941Ssam
idcustart(ui)2666941Ssam idcustart(ui)
2676941Ssam register struct uba_device *ui;
2686941Ssam {
2696941Ssam register struct buf *bp, *dp;
2706941Ssam register struct uba_ctlr *um;
2716941Ssam register struct idcdevice *idcaddr;
2726941Ssam register struct idcst *st;
2736941Ssam union idc_dar cyltrk;
2746941Ssam daddr_t bn;
2756941Ssam int unit;
2766941Ssam
2776941Ssam if (ui == 0)
2786941Ssam return (0);
2796941Ssam dk_busy &= ~(1<<ui->ui_dk);
2806941Ssam dp = &idcutab[ui->ui_unit];
2816941Ssam um = ui->ui_mi;
2826941Ssam unit = ui->ui_slave;
2838608Sroot trace("ust", dp);
2846941Ssam idcaddr = (struct idcdevice *)um->um_addr;
2856941Ssam if (um->um_tab.b_active) {
2866941Ssam idc_softc.sc_softas |= 1<<unit;
2878608Sroot trace("umac",idc_softc.sc_softas);
2886941Ssam return (0);
2896941Ssam }
2906941Ssam if ((bp = dp->b_actf) == NULL) {
2918608Sroot trace("!bp",0);
2926941Ssam return (0);
2936941Ssam }
2946941Ssam if (dp->b_active) {
2958608Sroot trace("dpac",dp->b_active);
2966941Ssam goto done;
2976941Ssam }
2986941Ssam dp->b_active = 1;
2996941Ssam /* CHECK DRIVE READY? */
30024739Sbloom bn = bp->b_blkno;
3018608Sroot trace("seek", bn);
3026941Ssam if (ui->ui_type == 0)
3036941Ssam bn *= 2;
3046941Ssam st = &idcst[ui->ui_type];
3056941Ssam cyltrk.dar_cyl = bp->b_cylin;
3066941Ssam cyltrk.dar_trk = (bn / st->nsect) % st->ntrak;
3076941Ssam cyltrk.dar_sect = 0;
3086941Ssam printd("idcustart, unit %d, cyltrk 0x%x\n", unit, cyltrk.dar_dar);
3096941Ssam /*
3106941Ssam * If on cylinder, no need to seek.
3116941Ssam */
3126941Ssam if (cyltrk.dar_dar == idccyl[ui->ui_unit].dar_dar)
3136941Ssam goto done;
3146941Ssam /*
3156941Ssam * RB80 can change heads (tracks) just by loading
3166941Ssam * the disk address register, perform optimization
3176941Ssam * here instead of doing a full seek.
3186941Ssam */
3196941Ssam if (ui->ui_type && cyltrk.dar_cyl == idccyl[ui->ui_unit].dar_cyl) {
3206941Ssam idcaddr->idccsr = IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8);
3216941Ssam idcaddr->idcdar = cyltrk.dar_dar;
3226941Ssam idccyl[ui->ui_unit].dar_dar = cyltrk.dar_dar;
3236941Ssam goto done;
3246941Ssam }
3256941Ssam /*
3266941Ssam * Need to do a full seek. Select the unit, clear
3276941Ssam * its attention bit, set the command, load the
3286941Ssam * disk address register, and then go.
3296941Ssam */
3306941Ssam idcaddr->idccsr =
3316941Ssam IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8)|(1<<(unit+16));
3326941Ssam idcaddr->idcdar = cyltrk.dar_dar;
3336941Ssam idccyl[ui->ui_unit].dar_dar = cyltrk.dar_dar;
3346941Ssam printd(" seek");
3356941Ssam idcaddr->idccsr = IDC_IE|IDC_SEEK|(unit<<8);
3366941Ssam if (ui->ui_dk >= 0) {
3376941Ssam dk_busy |= 1<<ui->ui_dk;
3386941Ssam dk_seek[ui->ui_dk]++;
3396941Ssam }
3406941Ssam /*
3416941Ssam * RB80's initiate seeks very quickly. Wait for it
3426941Ssam * to come ready rather than taking the interrupt.
3436941Ssam */
3446941Ssam if (ui->ui_type) {
3456941Ssam if (idcwait(idcaddr, 10) == 0)
3466941Ssam return (1);
3476941Ssam idcaddr->idccsr &= ~IDC_ATTN;
3486941Ssam /* has the seek completed? */
3496941Ssam if (idcaddr->idccsr & IDC_DRDY) {
3506941Ssam printd(", drdy");
3516941Ssam idcaddr->idccsr =
3526941Ssam IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8)|(1<<(unit+16));
3536941Ssam goto done;
3546941Ssam }
3556941Ssam }
3566941Ssam printd(", idccsr = 0x%x\n", idcaddr->idccsr);
3576941Ssam return (1);
3586941Ssam done:
3596941Ssam if (dp->b_active != 2) {
3608608Sroot trace("!=2",dp->b_active);
3616941Ssam dp->b_forw = NULL;
3626941Ssam if (um->um_tab.b_actf == NULL)
3636941Ssam um->um_tab.b_actf = dp;
3646941Ssam else {
3658608Sroot trace("!NUL",um->um_tab.b_actl);
3666941Ssam um->um_tab.b_actl->b_forw = dp;
3676941Ssam }
3686941Ssam um->um_tab.b_actl = dp;
3696941Ssam dp->b_active = 2;
3706941Ssam }
3716941Ssam return (0);
3726941Ssam }
3736941Ssam
idcstart(um)3746941Ssam idcstart(um)
3756941Ssam register struct uba_ctlr *um;
3766941Ssam {
3776941Ssam register struct buf *bp, *dp;
3786941Ssam register struct uba_device *ui;
3796941Ssam register struct idcdevice *idcaddr;
3806941Ssam register struct idc_softc *sc;
3816941Ssam struct idcst *st;
3826941Ssam daddr_t bn;
3836941Ssam int sn, tn, cmd;
3846941Ssam
3856941Ssam loop:
3866941Ssam if ((dp = um->um_tab.b_actf) == NULL) {
3878608Sroot trace("nodp",um);
3886941Ssam return (0);
3896941Ssam }
3906941Ssam if ((bp = dp->b_actf) == NULL) {
3918608Sroot trace("nobp", dp);
3926941Ssam um->um_tab.b_actf = dp->b_forw;
3936941Ssam goto loop;
3946941Ssam }
3956941Ssam um->um_tab.b_active = 1;
39624739Sbloom ui = idcdinfo[idcunit(bp->b_dev)];
39724739Sbloom bn = bp->b_blkno;
3988608Sroot trace("star",bp);
3996941Ssam if (ui->ui_type == 0)
4006941Ssam bn *= 2;
4016941Ssam sc = &idc_softc;
4026941Ssam st = &idcst[ui->ui_type];
4036941Ssam sn = bn%st->nspc;
4046941Ssam tn = sn/st->nsect;
4056941Ssam sn %= st->nsect;
4066941Ssam sc->sc_sect = sn;
4076941Ssam sc->sc_trk = tn;
4086941Ssam sc->sc_cyl = bp->b_cylin;
4096941Ssam idcaddr = (struct idcdevice *)ui->ui_addr;
4106941Ssam printd("idcstart, unit %d, dar 0x%x", ui->ui_slave, sc->sc_dar);
4116941Ssam if (bp->b_flags & B_READ)
4126941Ssam cmd = IDC_IE|IDC_READ|(ui->ui_slave<<8);
4136941Ssam else
4146941Ssam cmd = IDC_IE|IDC_WRITE|(ui->ui_slave<<8);
4156941Ssam idcaddr->idccsr = IDC_CRDY|cmd;
4166941Ssam if ((idcaddr->idccsr&IDC_DRDY) == 0) {
41724739Sbloom printf("rb%d: not ready\n", idcunit(bp->b_dev));
4186941Ssam um->um_tab.b_active = 0;
4196941Ssam um->um_tab.b_errcnt = 0;
4206941Ssam dp->b_actf = bp->av_forw;
4216941Ssam dp->b_active = 0;
4226941Ssam bp->b_flags |= B_ERROR;
4236941Ssam iodone(bp);
4246941Ssam goto loop;
4256941Ssam }
4266941Ssam idccyl[ui->ui_unit].dar_dar = sc->sc_dar;
4276941Ssam idccyl[ui->ui_unit].dar_sect = 0;
4286941Ssam sn = (st->nsect - sn) * st->nbps;
4296941Ssam if (sn > bp->b_bcount)
4306941Ssam sn = bp->b_bcount;
4316941Ssam sc->sc_bcnt = sn;
4326941Ssam sc->sc_resid = bp->b_bcount;
4336941Ssam sc->sc_unit = ui->ui_slave;
4346941Ssam printd(", bcr 0x%x, cmd 0x%x\n", sn, cmd);
4356941Ssam um->um_cmd = cmd;
4366941Ssam (void) ubago(ui);
4376941Ssam return (1);
4386941Ssam }
4396941Ssam
idcdgo(um)4406941Ssam idcdgo(um)
4416941Ssam register struct uba_ctlr *um;
4426941Ssam {
4436941Ssam register struct idcdevice *idcaddr = (struct idcdevice *)um->um_addr;
4446941Ssam register struct idc_softc *sc = &idc_softc;
4456941Ssam
4466941Ssam /*
4476941Ssam * VERY IMPORTANT: must load registers in this order.
4486941Ssam */
44936035Skarels idcaddr->idcbar = sc->sc_ubaddr = UBAI_ADDR(um->um_ubinfo);
4506941Ssam idcaddr->idcbcr = -sc->sc_bcnt;
4516941Ssam idcaddr->idcdar = sc->sc_dar;
4526941Ssam printd("idcdgo, ubinfo 0x%x, cmd 0x%x\n", um->um_ubinfo, um->um_cmd);
4536941Ssam idcaddr->idccsr = um->um_cmd;
4548608Sroot trace("go", um);
4556941Ssam um->um_tab.b_active = 2;
4566941Ssam /*** CLEAR SPURIOUS ATTN ON R80? ***/
4576941Ssam }
4586941Ssam
idcintr(idc)4596941Ssam idcintr(idc)
4606941Ssam int idc;
4616941Ssam {
4626941Ssam register struct uba_ctlr *um = idcminfo[idc];
4636941Ssam register struct uba_device *ui;
4646941Ssam register struct idcdevice *idcaddr = (struct idcdevice *)um->um_addr;
4656941Ssam register struct idc_softc *sc = &idc_softc;
4666941Ssam register struct buf *bp, *dp;
4676941Ssam struct idcst *st;
4686941Ssam int unit, as, er, cmd, ds = 0;
4696941Ssam
4706941Ssam printd("idcintr, idccsr 0x%x", idcaddr->idccsr);
4716941Ssam top:
4726941Ssam idcwticks = 0;
4738608Sroot trace("intr", um->um_tab.b_active);
4746941Ssam if (um->um_tab.b_active == 2) {
4756941Ssam /*
4766941Ssam * Process a data transfer complete interrupt.
4776941Ssam */
4786941Ssam um->um_tab.b_active = 1;
4796941Ssam dp = um->um_tab.b_actf;
4806941Ssam bp = dp->b_actf;
48124739Sbloom ui = idcdinfo[idcunit(bp->b_dev)];
4826941Ssam unit = ui->ui_slave;
4836941Ssam st = &idcst[ui->ui_type];
4846941Ssam idcaddr->idccsr = IDC_IE|IDC_CRDY|(unit<<8);
4856941Ssam if ((er = idcaddr->idccsr) & IDC_ERR) {
4866941Ssam if (er & IDC_DE) {
4876941Ssam idcaddr->idcmpr = IDCGS_GETSTAT;
4886941Ssam idcaddr->idccsr = IDC_GETSTAT|(unit<<8);
4898721Sroot (void) idcwait(idcaddr, 0);
4906941Ssam ds = idcaddr->idcmpr;
4916941Ssam idcaddr->idccsr =
4926941Ssam IDC_IE|IDC_CRDY|(1<<(unit+16));
4936941Ssam }
4946941Ssam printd(", er 0x%x, ds 0x%x", er, ds);
4956941Ssam if (ds & IDCDS_WL) {
49624739Sbloom printf("rb%d: write locked\n",
49724739Sbloom idcunit(bp->b_dev));
4986941Ssam bp->b_flags |= B_ERROR;
4996941Ssam } else if (++um->um_tab.b_errcnt > 28 || er&IDC_HARD) {
5006941Ssam hard:
50134524Skarels diskerr(bp, "rb", "hard error", LOG_PRINTF, -1,
50234524Skarels (struct disklabel *)0);
50334524Skarels printf(" csr=%b ds=%b\n", er, IDCCSR_BITS, ds,
5046941Ssam ui->ui_type?IDCRB80DS_BITS:IDCRB02DS_BITS);
5056941Ssam bp->b_flags |= B_ERROR;
5066941Ssam } else if (er & IDC_DCK) {
50726476Skarels switch ((int)(er & IDC_ECS)) {
5086941Ssam case IDC_ECS_NONE:
5096941Ssam break;
5106941Ssam case IDC_ECS_SOFT:
5116941Ssam idcecc(ui);
5126941Ssam break;
5136941Ssam case IDC_ECS_HARD:
5146941Ssam default:
5156941Ssam goto hard;
5166941Ssam }
5176941Ssam } else
5186941Ssam /* recoverable error, set up for retry */
5196941Ssam goto seek;
5206941Ssam }
5216941Ssam if ((sc->sc_resid -= sc->sc_bcnt) != 0) {
5226941Ssam sc->sc_ubaddr += sc->sc_bcnt;
5236941Ssam /*
5246941Ssam * Current transfer is complete, have
5256941Ssam * we overflowed to the next track?
5266941Ssam */
5276941Ssam if ((sc->sc_sect += sc->sc_bcnt/st->nbps) == st->nsect) {
5286941Ssam sc->sc_sect = 0;
5296941Ssam if (++sc->sc_trk == st->ntrak) {
5306941Ssam sc->sc_trk = 0;
5316941Ssam sc->sc_cyl++;
5326941Ssam } else if (ui->ui_type) {
5336941Ssam /*
5346941Ssam * RB80 can change heads just by
5356941Ssam * loading the disk address register.
5366941Ssam */
5376941Ssam idcaddr->idccsr = IDC_SEEK|IDC_CRDY|
5386941Ssam IDC_IE|(unit<<8);
5396941Ssam printd(", change to track 0x%x", sc->sc_dar);
5406941Ssam idcaddr->idcdar = sc->sc_dar;
5416941Ssam idccyl[ui->ui_unit].dar_dar = sc->sc_dar;
5426941Ssam idccyl[ui->ui_unit].dar_sect = 0;
5436941Ssam goto cont;
5446941Ssam }
5456941Ssam /*
5466941Ssam * Changing tracks on RB02 or cylinders
5476941Ssam * on RB80, start a seek.
5486941Ssam */
5496941Ssam seek:
5506941Ssam cmd = IDC_IE|IDC_SEEK|(unit<<8);
5516941Ssam idcaddr->idccsr = cmd|IDC_CRDY;
5526941Ssam idcaddr->idcdar = sc->sc_dar;
5536941Ssam printd(", seek to 0x%x\n", sc->sc_dar);
5546941Ssam idccyl[ui->ui_unit].dar_dar = sc->sc_dar;
5556941Ssam idccyl[ui->ui_unit].dar_sect = 0;
5566941Ssam sc->sc_bcnt = 0;
5576941Ssam idcaddr->idccsr = cmd;
5586941Ssam if (ui->ui_type) {
5596941Ssam if (idcwait(idcaddr, 10) == 0)
5606941Ssam return;
5616941Ssam idcaddr->idccsr &= ~IDC_ATTN;
5626941Ssam if (idcaddr->idccsr & IDC_DRDY)
5636941Ssam goto top;
5646941Ssam }
5656941Ssam } else {
5666941Ssam /*
5676941Ssam * Continue transfer on current track.
5686941Ssam */
5696941Ssam cont:
5706941Ssam sc->sc_bcnt = (st->nsect-sc->sc_sect)*st->nbps;
5716941Ssam if (sc->sc_bcnt > sc->sc_resid)
5726941Ssam sc->sc_bcnt = sc->sc_resid;
5736941Ssam if (bp->b_flags & B_READ)
5746941Ssam cmd = IDC_IE|IDC_READ|(unit<<8);
5756941Ssam else
5766941Ssam cmd = IDC_IE|IDC_WRITE|(unit<<8);
5776941Ssam idcaddr->idccsr = cmd|IDC_CRDY;
5786941Ssam idcaddr->idcbar = sc->sc_ubaddr;
5796941Ssam idcaddr->idcbcr = -sc->sc_bcnt;
5806941Ssam idcaddr->idcdar = sc->sc_dar;
5816941Ssam printd(", continue I/O 0x%x, 0x%x\n", sc->sc_dar, sc->sc_bcnt);
5826941Ssam idcaddr->idccsr = cmd;
5836941Ssam um->um_tab.b_active = 2;
5846941Ssam }
5856941Ssam return;
5866941Ssam }
5876941Ssam /*
5886941Ssam * Entire transfer is done, clean up.
5896941Ssam */
5906941Ssam ubadone(um);
5916941Ssam dk_busy &= ~(1 << ui->ui_dk);
5926941Ssam um->um_tab.b_active = 0;
5936941Ssam um->um_tab.b_errcnt = 0;
5946941Ssam um->um_tab.b_actf = dp->b_forw;
5956941Ssam dp->b_active = 0;
5966941Ssam dp->b_errcnt = 0;
5976941Ssam dp->b_actf = bp->av_forw;
5988608Sroot trace("done", dp); trace(&um->um_tab.b_actf, dp->b_actf);
5996941Ssam bp->b_resid = sc->sc_resid;
6006941Ssam printd(", iodone, resid 0x%x\n", bp->b_resid);
6016941Ssam iodone(bp);
6026941Ssam if (dp->b_actf)
6036941Ssam if (idcustart(ui))
6046941Ssam return;
6056941Ssam } else if (um->um_tab.b_active == 1) {
6066941Ssam /*
6076941Ssam * Got an interrupt while setting up for a command
6086941Ssam * or doing a mid-transfer seek. Save any attentions
6096941Ssam * for later and process a mid-transfer seek complete.
6106941Ssam */
6116941Ssam as = idcaddr->idccsr;
6126941Ssam idcaddr->idccsr = IDC_IE|IDC_CRDY|(as&IDC_ATTN);
6136941Ssam as = (as >> 16) & 0xf;
6146941Ssam unit = sc->sc_unit;
6156941Ssam sc->sc_softas |= as & ~(1<<unit);
6166941Ssam if (as & (1<<unit)) {
6176941Ssam printd(", seek1 complete");
6186941Ssam um->um_tab.b_active = 2;
6196941Ssam goto top;
6206941Ssam }
6216941Ssam printd(", as1 %o\n", as);
6226941Ssam return;
6236941Ssam }
6246941Ssam /*
6256941Ssam * Process any seek initiated or complete interrupts.
6266941Ssam */
6276941Ssam as = idcaddr->idccsr;
6286941Ssam idcaddr->idccsr = IDC_IE|IDC_CRDY|(as&IDC_ATTN);
6296941Ssam as = ((as >> 16) & 0xf) | sc->sc_softas;
6306941Ssam sc->sc_softas = 0;
6318608Sroot trace("as", as);
6326941Ssam printd(", as %o", as);
6336941Ssam for (unit = 0; unit < NRB; unit++)
6346941Ssam if (as & (1<<unit)) {
6356941Ssam as &= ~(1<<unit);
6366941Ssam idcaddr->idccsr = IDC_IE|IDC_CRDY|(unit<<8);
6376941Ssam ui = idcdinfo[unit];
6386941Ssam if (ui) {
6396941Ssam printd(", attn unit %d", unit);
6406941Ssam if (idcaddr->idccsr & IDC_DRDY)
6416941Ssam if (idcustart(ui)) {
6426941Ssam sc->sc_softas = as;
6436941Ssam return;
6446941Ssam }
6456941Ssam } else {
6466941Ssam printd(", unsol. intr. unit %d", unit);
6476941Ssam }
6486941Ssam }
6496941Ssam printd("\n");
6506941Ssam if (um->um_tab.b_actf && um->um_tab.b_active == 0) {
6518608Sroot trace("stum",um->um_tab.b_actf);
6528721Sroot (void) idcstart(um);
6536941Ssam }
6546941Ssam }
6556941Ssam
idcwait(addr,n)6568608Sroot idcwait(addr, n)
6576941Ssam register struct idcdevice *addr;
6588608Sroot register int n;
6596941Ssam {
6606941Ssam register int i;
6616941Ssam
6628608Sroot while (--n && (addr->idccsr & IDC_CRDY) == 0)
6636941Ssam for (i = 10; i; i--)
6646941Ssam ;
6658608Sroot return (n);
6666941Ssam }
6676941Ssam
idcecc(ui)6686941Ssam idcecc(ui)
6696941Ssam register struct uba_device *ui;
6706941Ssam {
6716941Ssam register struct idcdevice *idc = (struct idcdevice *)ui->ui_addr;
6726941Ssam register struct buf *bp = idcutab[ui->ui_unit].b_actf;
6736941Ssam register struct uba_ctlr *um = ui->ui_mi;
6746941Ssam register int i;
6756941Ssam struct uba_regs *ubp = ui->ui_hd->uh_uba;
6766941Ssam int bit, byte, mask;
6776941Ssam caddr_t addr;
6786941Ssam int reg, npf, o;
6796941Ssam
6806941Ssam npf = btop(idc->idcbcr + idc_softc.sc_bcnt) - 1;;
6816941Ssam reg = btop(idc_softc.sc_ubaddr) + npf;
6826941Ssam o = (int)bp->b_un.b_addr & PGOFSET;
6836941Ssam um->um_tab.b_active = 1; /* Either complete or continuing... */
68434524Skarels diskerr(bp, "rb", "soft ecc", LOG_WARNING, npf, (struct disklabel *)0);
68534524Skarels addlog("\n");
6866941Ssam mask = idc->idceccpat;
6876941Ssam i = idc->idceccpos - 1; /* -1 makes 0 origin */
6886941Ssam bit = i&07;
6896941Ssam i = (i&~07)>>3;
6906941Ssam byte = i + o;
6916941Ssam while (i < 512 && (int)ptob(npf)+i < idc_softc.sc_bcnt && bit > -11) {
69225169Smckusick /*
69325169Smckusick * should be:
69425169Smckusick * addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+
69525169Smckusick * (byte & PGOFSET);
69625169Smckusick * but this generates an extzv which hangs the UNIBUS.
69725169Smckusick */
69825169Smckusick addr = ptob(*(int *)&ubp->uba_map[reg+btop(byte)]&0x1fffff)+
6996941Ssam (byte & PGOFSET);
7006941Ssam putmemc(addr, getmemc(addr)^(mask<<bit));
7016941Ssam byte++;
7026941Ssam i++;
7036941Ssam bit -= 8;
7046941Ssam }
7056941Ssam idc_softc.sc_bcnt += idc->idcbcr;
7066941Ssam um->um_tab.b_errcnt = 0; /* error has been corrected */
7076941Ssam return;
7086941Ssam }
7096941Ssam
idcreset(uban)7106941Ssam idcreset(uban)
7116941Ssam int uban;
7126941Ssam {
7136941Ssam register struct uba_ctlr *um;
7146941Ssam register struct uba_device *ui;
7156941Ssam register unit;
7166941Ssam
7176941Ssam if ((um = idcminfo[0]) == 0 || um->um_ubanum != uban ||
7186941Ssam um->um_alive == 0)
7196941Ssam return;
7206941Ssam printf(" idc0");
7216941Ssam um->um_tab.b_active = 0;
7226941Ssam um->um_tab.b_actf = um->um_tab.b_actl = 0;
7236941Ssam if (um->um_ubinfo) {
7246941Ssam printf("<%d>", (um->um_ubinfo>>28)&0xf);
7259354Ssam um->um_ubinfo = 0;
7266941Ssam }
7276941Ssam for (unit = 0; unit < NRB; unit++) {
7286941Ssam if ((ui = idcdinfo[unit]) == 0 || ui->ui_alive == 0)
7296941Ssam continue;
7306941Ssam idcutab[unit].b_active = 0;
7316941Ssam (void) idcustart(ui);
7326941Ssam }
7336941Ssam (void) idcstart(um);
7346941Ssam }
7356941Ssam
idcwatch()7366941Ssam idcwatch()
7376941Ssam {
7386941Ssam register struct uba_ctlr *um;
7396941Ssam register unit;
7406941Ssam
7416941Ssam timeout(idcwatch, (caddr_t)0, hz);
7426941Ssam um = idcminfo[0];
7436941Ssam if (um == 0 || um->um_alive == 0)
7446941Ssam return;
7456941Ssam if (um->um_tab.b_active == 0) {
7466941Ssam for (unit = 0; unit < NRB; unit++)
7476941Ssam if (idcutab[unit].b_active)
7486941Ssam goto active;
7496941Ssam idcwticks = 0;
7506941Ssam return;
7516941Ssam }
7526941Ssam active:
7536941Ssam idcwticks++;
7546941Ssam if (idcwticks >= 20) {
7556941Ssam idcwticks = 0;
7566941Ssam printf("idc0: lost interrupt\n");
7576941Ssam idcintr(0);
7586941Ssam }
7596941Ssam }
7606941Ssam
7618608Sroot /*ARGSUSED*/
idcdump(dev)7626941Ssam idcdump(dev)
7636941Ssam dev_t dev;
7646941Ssam {
7656941Ssam struct idcdevice *idcaddr;
7666941Ssam char *start;
76712147Sroot int num, blk, unit;
7686941Ssam struct size *sizes;
7696941Ssam register struct uba_regs *uba;
7706941Ssam register struct uba_device *ui;
7716941Ssam struct idcst *st;
77212778Ssam union idc_dar dar;
77312147Sroot int nspg;
7746941Ssam
77524739Sbloom unit = idcunit(dev);
7766941Ssam if (unit >= NRB)
7776941Ssam return (ENXIO);
7786941Ssam #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff))
7796941Ssam ui = phys(struct uba_device *, idcdinfo[unit]);
7806941Ssam if (ui->ui_alive == 0)
7816941Ssam return (ENXIO);
7826941Ssam uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba;
7836941Ssam ubainit(uba);
7846941Ssam idcaddr = (struct idcdevice *)ui->ui_physaddr;
78512147Sroot if (idcwait(idcaddr, 100) == 0)
78612147Sroot return (EFAULT);
78712147Sroot /*
78812147Sroot * Since we can only transfer one track at a time, and
78912147Sroot * the rl02 has 256 byte sectors, all the calculations
79012147Sroot * are done in terms of physical sectors (i.e. num and blk
79112147Sroot * are in sectors not NBPG blocks.
79212147Sroot */
79312147Sroot st = phys(struct idcst *, &idcst[ui->ui_type]);
7946941Ssam sizes = phys(struct size *, st->sizes);
79524211Sbloom if (dumplo < 0)
7966941Ssam return (EINVAL);
79724211Sbloom if (dumplo + maxfree >= sizes[minor(dev)&07].nblocks)
79824211Sbloom num = sizes[minor(dev)&07].nblocks - dumplo;
79912147Sroot nspg = NBPG / st->nbps;
80024211Sbloom num = num * nspg;
80112147Sroot start = 0;
80212147Sroot
8036941Ssam while (num > 0) {
8046941Ssam register struct pte *io;
8056941Ssam register int i;
8066941Ssam daddr_t bn;
8076941Ssam
80812147Sroot bn = (dumplo + btop(start)) * nspg;
80912147Sroot dar.dar_cyl = bn / st->nspc + sizes[minor(dev)&07].cyloff;
81012147Sroot bn %= st->nspc;
81112147Sroot dar.dar_trk = bn / st->nsect;
81212147Sroot dar.dar_sect = bn % st->nsect;
81312147Sroot blk = st->nsect - dar.dar_sect;
81412147Sroot if (num < blk)
81512147Sroot blk = num;
81612147Sroot
8176941Ssam io = uba->uba_map;
81812147Sroot for (i = 0; i < (blk + nspg - 1) / nspg; i++)
8196941Ssam *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV;
8206941Ssam *(int *)io = 0;
82112147Sroot
82212147Sroot idcaddr->idccsr = IDC_CRDY | IDC_SEEK | unit<<8;
82312147Sroot if ((idcaddr->idccsr&IDC_DRDY) == 0)
82412147Sroot return (EFAULT);
82512147Sroot idcaddr->idcdar = dar.dar_dar;
82612147Sroot idcaddr->idccsr = IDC_SEEK | unit << 8;
82712147Sroot while ((idcaddr->idccsr & (IDC_CRDY|IDC_DRDY))
82812147Sroot != (IDC_CRDY|IDC_DRDY))
82912147Sroot ;
83012147Sroot if (idcaddr->idccsr & IDC_ERR) {
83112147Sroot printf("rb%d: seek, csr=%b\n",
83212147Sroot unit, idcaddr->idccsr, IDCCSR_BITS);
8336941Ssam return (EIO);
83412147Sroot }
83512147Sroot
83612147Sroot idcaddr->idccsr = IDC_CRDY | IDC_WRITE | unit<<8;
83712147Sroot if ((idcaddr->idccsr&IDC_DRDY) == 0)
83812147Sroot return (EFAULT);
83912147Sroot idcaddr->idcbar = 0; /* start addr 0 */
84012147Sroot idcaddr->idcbcr = - (blk * st->nbps);
84112147Sroot idcaddr->idcdar = dar.dar_dar;
84212147Sroot idcaddr->idccsr = IDC_WRITE | unit << 8;
84312147Sroot while ((idcaddr->idccsr & (IDC_CRDY|IDC_DRDY))
84412147Sroot != (IDC_CRDY|IDC_DRDY))
84512147Sroot ;
84612147Sroot if (idcaddr->idccsr & IDC_ERR) {
84712147Sroot printf("rb%d: write, csr=%b\n",
84812147Sroot unit, idcaddr->idccsr, IDCCSR_BITS);
84912147Sroot return (EIO);
85012147Sroot }
85112147Sroot
85212147Sroot start += blk * st->nbps;
8536941Ssam num -= blk;
8546941Ssam }
8556941Ssam return (0);
8566941Ssam }
85712503Ssam
idcsize(dev)85812503Ssam idcsize(dev)
85912503Ssam dev_t dev;
86012503Ssam {
86124739Sbloom int unit = idcunit(dev);
86212503Ssam struct uba_device *ui;
86312503Ssam struct idcst *st;
86412503Ssam
86512503Ssam if (unit >= NRB || (ui = idcdinfo[unit]) == 0 || ui->ui_alive == 0)
86612503Ssam return (-1);
86712503Ssam st = &idcst[ui->ui_type];
86812503Ssam return (st->sizes[minor(dev) & 07].nblocks);
86912503Ssam }
8706941Ssam #endif
871