1*6941Ssam /* idc.c 4.1 82/05/26 */ 2*6941Ssam 3*6941Ssam #include "rb.h" 4*6941Ssam #if NIDC > 0 5*6941Ssam int idcdebug = 0; 6*6941Ssam #define printd if(idcdebug)printf 7*6941Ssam int idctrb[1000]; 8*6941Ssam int *trp = idctrb; 9*6941Ssam #define trace(a,b) {*trp++ = (int)a; *trp++ = (int)b; if(trp>&idctrb[998])trp=idctrb;} 10*6941Ssam /* 11*6941Ssam * IDC (RB730) disk driver 12*6941Ssam * 13*6941Ssam * There can only ever be one IDC on a machine, 14*6941Ssam * and only on a VAX-11/730. We take advantage 15*6941Ssam * of that to simplify the driver. 16*6941Ssam * 17*6941Ssam * TODO: 18*6941Ssam * dk_busy 19*6941Ssam * ecc 20*6941Ssam * dump 21*6941Ssam */ 22*6941Ssam #include "../h/param.h" 23*6941Ssam #include "../h/systm.h" 24*6941Ssam #include "../h/buf.h" 25*6941Ssam #include "../h/conf.h" 26*6941Ssam #include "../h/dir.h" 27*6941Ssam #include "../h/user.h" 28*6941Ssam #include "../h/pte.h" 29*6941Ssam #include "../h/map.h" 30*6941Ssam #include "../h/vm.h" 31*6941Ssam #include "../h/ubareg.h" 32*6941Ssam #include "../h/ubavar.h" 33*6941Ssam #include "../h/dk.h" 34*6941Ssam #include "../h/cpu.h" 35*6941Ssam #include "../h/cmap.h" 36*6941Ssam #include "../h/dkbad.h" 37*6941Ssam 38*6941Ssam #include "../h/idcreg.h" 39*6941Ssam 40*6941Ssam struct idc_softc { 41*6941Ssam int sc_bcnt; /* number of bytes to transfer */ 42*6941Ssam int sc_resid; /* total number of bytes to transfer */ 43*6941Ssam int sc_ubaddr; /* Unibus address of data */ 44*6941Ssam short sc_unit; /* unit doing transfer */ 45*6941Ssam short sc_softas; /* software attention summary bits */ 46*6941Ssam union idc_dar { 47*6941Ssam long dar_l; 48*6941Ssam u_short dar_w[2]; 49*6941Ssam u_char dar_b[4]; 50*6941Ssam } sc_un; /* prototype disk address register */ 51*6941Ssam } idc_softc; 52*6941Ssam 53*6941Ssam #define dar_dar dar_l /* the whole disk address */ 54*6941Ssam #define dar_cyl dar_w[1] /* cylinder address */ 55*6941Ssam #define dar_trk dar_b[1] /* track */ 56*6941Ssam #define dar_sect dar_b[0] /* sector */ 57*6941Ssam #define sc_dar sc_un.dar_dar 58*6941Ssam #define sc_cyl sc_un.dar_cyl 59*6941Ssam #define sc_trk sc_un.dar_trk 60*6941Ssam #define sc_sect sc_un.dar_sect 61*6941Ssam 62*6941Ssam /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 63*6941Ssam struct size { 64*6941Ssam daddr_t nblocks; 65*6941Ssam int cyloff; 66*6941Ssam } rb02_sizes[8] ={ 67*6941Ssam 15884, 0, /* A=cyl 0 thru 399 */ 68*6941Ssam 4480, 400, /* B=cyl 400 thru 510 */ 69*6941Ssam 20480, 0, /* C=cyl 0 thru 511 */ 70*6941Ssam 0, 0, 71*6941Ssam 0, 0, 72*6941Ssam 0, 0, 73*6941Ssam 0, 0, 74*6941Ssam 0, 0, 75*6941Ssam }, rb80_sizes[8] ={ 76*6941Ssam 15884, 0, /* A=cyl 0 thru 36 */ 77*6941Ssam 33440, 37, /* B=cyl 37 thru 114 */ 78*6941Ssam 242606, 0, /* C=cyl 0 thru 558 */ 79*6941Ssam 0, 0, 80*6941Ssam 0, 0, 81*6941Ssam 0, 0, 82*6941Ssam 82080, 115, /* G=cyl 115 thru 304 */ 83*6941Ssam 110143, 305, /* H=cyl 305 thru 558 */ 84*6941Ssam }; 85*6941Ssam /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 86*6941Ssam 87*6941Ssam int idcprobe(), idcslave(), idcattach(), idcdgo(), idcintr(); 88*6941Ssam struct uba_ctlr *idcminfo[NIDC]; 89*6941Ssam struct uba_device *idcdinfo[NRB]; 90*6941Ssam 91*6941Ssam u_short idcstd[] = { 0174400, 0}; 92*6941Ssam struct uba_driver idcdriver = 93*6941Ssam { idcprobe, idcslave, idcattach, idcdgo, idcstd, "rb", idcdinfo, "idc", idcminfo, 0 }; 94*6941Ssam struct buf idcutab[NRB]; 95*6941Ssam union idc_dar idccyl[NRB]; 96*6941Ssam 97*6941Ssam struct idcst { 98*6941Ssam short nbps; 99*6941Ssam short nsect; 100*6941Ssam short ntrak; 101*6941Ssam short nspc; 102*6941Ssam short ncyl; 103*6941Ssam struct size *sizes; 104*6941Ssam } idcst[] = { 105*6941Ssam 256, NRB02SECT, NRB02TRK, NRB02SECT*NRB02TRK, NRB02CYL, rb02_sizes, 106*6941Ssam 512, NRB80SECT, NRB80TRK, NRB80SECT*NRB80TRK, NRB80CYL, rb80_sizes, 107*6941Ssam }; 108*6941Ssam 109*6941Ssam struct buf ridcbuf[NRB]; 110*6941Ssam 111*6941Ssam #define b_cylin b_resid 112*6941Ssam 113*6941Ssam #ifdef INTRLVE 114*6941Ssam daddr_t dkblock(); 115*6941Ssam #endif 116*6941Ssam 117*6941Ssam int idcwstart, idcwticks, idcwatch(); 118*6941Ssam 119*6941Ssam idcprobe(reg) 120*6941Ssam caddr_t reg; 121*6941Ssam { 122*6941Ssam register int br, cvec; 123*6941Ssam register struct idcdevice *idcaddr; 124*6941Ssam 125*6941Ssam #ifdef lint 126*6941Ssam br = 0; cvec = br; br = cvec; 127*6941Ssam #endif 128*6941Ssam idcaddr = (struct idcdevice *)((caddr_t)uba_hd[0].uh_uba + 0x200); 129*6941Ssam idcaddr->idccsr = IDC_ATTN|IDC_IE; 130*6941Ssam while ((idcaddr->idccsr & IDC_CRDY) == 0) 131*6941Ssam ; 132*6941Ssam idcaddr->idccsr = IDC_ATTN|IDC_CRDY; 133*6941Ssam return (1); 134*6941Ssam } 135*6941Ssam 136*6941Ssam idcslave(ui, reg) 137*6941Ssam struct uba_device *ui; 138*6941Ssam caddr_t reg; 139*6941Ssam { 140*6941Ssam register struct idcdevice *idcaddr; 141*6941Ssam register int i; 142*6941Ssam 143*6941Ssam idcaddr = (struct idcdevice *)((caddr_t)uba_hd[0].uh_uba + 0x200); 144*6941Ssam ui->ui_type = 0; 145*6941Ssam idcaddr->idcmpr = IDCGS_GETSTAT; 146*6941Ssam idcaddr->idccsr = IDC_GETSTAT|(ui->ui_slave<<8); 147*6941Ssam idcwait(idcaddr, 0); 148*6941Ssam i = idcaddr->idcmpr; 149*6941Ssam idcaddr->idccsr = IDC_CRDY|(1<<(ui->ui_slave+16)); 150*6941Ssam /* read header to synchronize microcode */ 151*6941Ssam idcwait(idcaddr, 0); 152*6941Ssam idcaddr->idccsr = (ui->ui_slave<<8)|IDC_RHDR; 153*6941Ssam idcwait(idcaddr, 0); 154*6941Ssam if (idcaddr->idccsr & IDC_ERR) 155*6941Ssam return (0); 156*6941Ssam i = idcaddr->idcmpr; /* read header word 1 */ 157*6941Ssam i = idcaddr->idcmpr; /* read header word 2 */ 158*6941Ssam if (idcaddr->idccsr&IDC_R80) 159*6941Ssam ui->ui_type = 1; 160*6941Ssam return (1); 161*6941Ssam } 162*6941Ssam 163*6941Ssam idcattach(ui) 164*6941Ssam register struct uba_device *ui; 165*6941Ssam { 166*6941Ssam 167*6941Ssam /* 168*6941Ssam * Fix all addresses to correspond 169*6941Ssam * to the "real" IDC address. 170*6941Ssam */ 171*6941Ssam ui->ui_mi->um_addr = ui->ui_addr = (caddr_t)uba_hd[0].uh_uba + 0x200; 172*6941Ssam ui->ui_physaddr = (caddr_t)uba_hd[0].uh_physuba + 0x200; 173*6941Ssam if (idcwstart == 0) { 174*6941Ssam timeout(idcwatch, (caddr_t)0, hz); 175*6941Ssam idcwstart++; 176*6941Ssam } 177*6941Ssam if (ui->ui_dk >= 0) 178*6941Ssam if (ui->ui_type) 179*6941Ssam dk_mspw[ui->ui_dk] = 1.0 / (60 * NRB80SECT * 256); 180*6941Ssam else 181*6941Ssam dk_mspw[ui->ui_dk] = 1.0 / (60 * NRB02SECT * 128); 182*6941Ssam idccyl[ui->ui_unit].dar_dar = -1; 183*6941Ssam ui->ui_flags = 0; 184*6941Ssam } 185*6941Ssam 186*6941Ssam idcstrategy(bp) 187*6941Ssam register struct buf *bp; 188*6941Ssam { 189*6941Ssam register struct uba_device *ui; 190*6941Ssam register struct idcst *st; 191*6941Ssam register int unit; 192*6941Ssam register struct buf *dp; 193*6941Ssam int xunit = minor(bp->b_dev) & 07; 194*6941Ssam long bn, sz; 195*6941Ssam 196*6941Ssam sz = (bp->b_bcount+511) >> 9; 197*6941Ssam unit = dkunit(bp); 198*6941Ssam if (unit >= NRB) 199*6941Ssam goto bad; 200*6941Ssam ui = idcdinfo[unit]; 201*6941Ssam if (ui == 0 || ui->ui_alive == 0) 202*6941Ssam goto bad; 203*6941Ssam st = &idcst[ui->ui_type]; 204*6941Ssam if (bp->b_blkno < 0 || 205*6941Ssam (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) 206*6941Ssam goto bad; 207*6941Ssam if (ui->ui_type == 0) 208*6941Ssam bn *= 2; 209*6941Ssam bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 210*6941Ssam (void) spl5(); 211*6941Ssam trace('strt',bp); 212*6941Ssam dp = &idcutab[ui->ui_unit]; 213*6941Ssam disksort(dp, bp); 214*6941Ssam if (dp->b_active == 0) { 215*6941Ssam trace('!act',dp); 216*6941Ssam (void) idcustart(ui); 217*6941Ssam bp = &ui->ui_mi->um_tab; 218*6941Ssam if (bp->b_actf && bp->b_active == 0) 219*6941Ssam (void) idcstart(ui->ui_mi); 220*6941Ssam } 221*6941Ssam (void) spl0(); 222*6941Ssam return; 223*6941Ssam 224*6941Ssam bad: 225*6941Ssam bp->b_flags |= B_ERROR; 226*6941Ssam iodone(bp); 227*6941Ssam return; 228*6941Ssam } 229*6941Ssam 230*6941Ssam idcustart(ui) 231*6941Ssam register struct uba_device *ui; 232*6941Ssam { 233*6941Ssam register struct buf *bp, *dp; 234*6941Ssam register struct uba_ctlr *um; 235*6941Ssam register struct idcdevice *idcaddr; 236*6941Ssam register struct idcst *st; 237*6941Ssam union idc_dar cyltrk; 238*6941Ssam daddr_t bn; 239*6941Ssam int unit; 240*6941Ssam 241*6941Ssam if (ui == 0) 242*6941Ssam return (0); 243*6941Ssam dk_busy &= ~(1<<ui->ui_dk); 244*6941Ssam dp = &idcutab[ui->ui_unit]; 245*6941Ssam um = ui->ui_mi; 246*6941Ssam unit = ui->ui_slave; 247*6941Ssam trace('ust', dp); 248*6941Ssam idcaddr = (struct idcdevice *)um->um_addr; 249*6941Ssam if (um->um_tab.b_active) { 250*6941Ssam idc_softc.sc_softas |= 1<<unit; 251*6941Ssam trace('umac',idc_softc.sc_softas); 252*6941Ssam return (0); 253*6941Ssam } 254*6941Ssam if ((bp = dp->b_actf) == NULL) { 255*6941Ssam trace('!bp',0); 256*6941Ssam return (0); 257*6941Ssam } 258*6941Ssam if (dp->b_active) { 259*6941Ssam trace('dpac',dp->b_active); 260*6941Ssam goto done; 261*6941Ssam } 262*6941Ssam dp->b_active = 1; 263*6941Ssam /* CHECK DRIVE READY? */ 264*6941Ssam bn = dkblock(bp); 265*6941Ssam trace('seek', bn); 266*6941Ssam if (ui->ui_type == 0) 267*6941Ssam bn *= 2; 268*6941Ssam st = &idcst[ui->ui_type]; 269*6941Ssam cyltrk.dar_cyl = bp->b_cylin; 270*6941Ssam cyltrk.dar_trk = (bn / st->nsect) % st->ntrak; 271*6941Ssam cyltrk.dar_sect = 0; 272*6941Ssam printd("idcustart, unit %d, cyltrk 0x%x\n", unit, cyltrk.dar_dar); 273*6941Ssam /* 274*6941Ssam * If on cylinder, no need to seek. 275*6941Ssam */ 276*6941Ssam if (cyltrk.dar_dar == idccyl[ui->ui_unit].dar_dar) 277*6941Ssam goto done; 278*6941Ssam /* 279*6941Ssam * RB80 can change heads (tracks) just by loading 280*6941Ssam * the disk address register, perform optimization 281*6941Ssam * here instead of doing a full seek. 282*6941Ssam */ 283*6941Ssam if (ui->ui_type && cyltrk.dar_cyl == idccyl[ui->ui_unit].dar_cyl) { 284*6941Ssam idcaddr->idccsr = IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8); 285*6941Ssam idcaddr->idcdar = cyltrk.dar_dar; 286*6941Ssam idccyl[ui->ui_unit].dar_dar = cyltrk.dar_dar; 287*6941Ssam goto done; 288*6941Ssam } 289*6941Ssam /* 290*6941Ssam * Need to do a full seek. Select the unit, clear 291*6941Ssam * its attention bit, set the command, load the 292*6941Ssam * disk address register, and then go. 293*6941Ssam */ 294*6941Ssam idcaddr->idccsr = 295*6941Ssam IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8)|(1<<(unit+16)); 296*6941Ssam idcaddr->idcdar = cyltrk.dar_dar; 297*6941Ssam idccyl[ui->ui_unit].dar_dar = cyltrk.dar_dar; 298*6941Ssam printd(" seek"); 299*6941Ssam idcaddr->idccsr = IDC_IE|IDC_SEEK|(unit<<8); 300*6941Ssam if (ui->ui_dk >= 0) { 301*6941Ssam dk_busy |= 1<<ui->ui_dk; 302*6941Ssam dk_seek[ui->ui_dk]++; 303*6941Ssam } 304*6941Ssam /* 305*6941Ssam * RB80's initiate seeks very quickly. Wait for it 306*6941Ssam * to come ready rather than taking the interrupt. 307*6941Ssam */ 308*6941Ssam if (ui->ui_type) { 309*6941Ssam if (idcwait(idcaddr, 10) == 0) 310*6941Ssam return (1); 311*6941Ssam idcaddr->idccsr &= ~IDC_ATTN; 312*6941Ssam /* has the seek completed? */ 313*6941Ssam if (idcaddr->idccsr & IDC_DRDY) { 314*6941Ssam printd(", drdy"); 315*6941Ssam idcaddr->idccsr = 316*6941Ssam IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8)|(1<<(unit+16)); 317*6941Ssam goto done; 318*6941Ssam } 319*6941Ssam } 320*6941Ssam printd(", idccsr = 0x%x\n", idcaddr->idccsr); 321*6941Ssam return (1); 322*6941Ssam done: 323*6941Ssam if (dp->b_active != 2) { 324*6941Ssam trace('!=2',dp->b_active); 325*6941Ssam dp->b_forw = NULL; 326*6941Ssam if (um->um_tab.b_actf == NULL) 327*6941Ssam um->um_tab.b_actf = dp; 328*6941Ssam else { 329*6941Ssam trace('!NUL',um->um_tab.b_actl); 330*6941Ssam um->um_tab.b_actl->b_forw = dp; 331*6941Ssam } 332*6941Ssam um->um_tab.b_actl = dp; 333*6941Ssam dp->b_active = 2; 334*6941Ssam } 335*6941Ssam return (0); 336*6941Ssam } 337*6941Ssam 338*6941Ssam idcstart(um) 339*6941Ssam register struct uba_ctlr *um; 340*6941Ssam { 341*6941Ssam register struct buf *bp, *dp; 342*6941Ssam register struct uba_device *ui; 343*6941Ssam register struct idcdevice *idcaddr; 344*6941Ssam register struct idc_softc *sc; 345*6941Ssam struct idcst *st; 346*6941Ssam daddr_t bn; 347*6941Ssam int sn, tn, cmd; 348*6941Ssam 349*6941Ssam loop: 350*6941Ssam if ((dp = um->um_tab.b_actf) == NULL) { 351*6941Ssam trace('nodp',um); 352*6941Ssam return (0); 353*6941Ssam } 354*6941Ssam if ((bp = dp->b_actf) == NULL) { 355*6941Ssam trace('nobp', dp); 356*6941Ssam um->um_tab.b_actf = dp->b_forw; 357*6941Ssam goto loop; 358*6941Ssam } 359*6941Ssam um->um_tab.b_active = 1; 360*6941Ssam ui = idcdinfo[dkunit(bp)]; 361*6941Ssam bn = dkblock(bp); 362*6941Ssam trace('star',bp); 363*6941Ssam if (ui->ui_type == 0) 364*6941Ssam bn *= 2; 365*6941Ssam sc = &idc_softc; 366*6941Ssam st = &idcst[ui->ui_type]; 367*6941Ssam sn = bn%st->nspc; 368*6941Ssam tn = sn/st->nsect; 369*6941Ssam sn %= st->nsect; 370*6941Ssam sc->sc_sect = sn; 371*6941Ssam sc->sc_trk = tn; 372*6941Ssam sc->sc_cyl = bp->b_cylin; 373*6941Ssam idcaddr = (struct idcdevice *)ui->ui_addr; 374*6941Ssam printd("idcstart, unit %d, dar 0x%x", ui->ui_slave, sc->sc_dar); 375*6941Ssam if (bp->b_flags & B_READ) 376*6941Ssam cmd = IDC_IE|IDC_READ|(ui->ui_slave<<8); 377*6941Ssam else 378*6941Ssam cmd = IDC_IE|IDC_WRITE|(ui->ui_slave<<8); 379*6941Ssam idcaddr->idccsr = IDC_CRDY|cmd; 380*6941Ssam if ((idcaddr->idccsr&IDC_DRDY) == 0) { 381*6941Ssam printf("rb%d: not ready\n", dkunit(bp)); 382*6941Ssam um->um_tab.b_active = 0; 383*6941Ssam um->um_tab.b_errcnt = 0; 384*6941Ssam dp->b_actf = bp->av_forw; 385*6941Ssam dp->b_active = 0; 386*6941Ssam bp->b_flags |= B_ERROR; 387*6941Ssam iodone(bp); 388*6941Ssam goto loop; 389*6941Ssam } 390*6941Ssam idccyl[ui->ui_unit].dar_dar = sc->sc_dar; 391*6941Ssam idccyl[ui->ui_unit].dar_sect = 0; 392*6941Ssam sn = (st->nsect - sn) * st->nbps; 393*6941Ssam if (sn > bp->b_bcount) 394*6941Ssam sn = bp->b_bcount; 395*6941Ssam sc->sc_bcnt = sn; 396*6941Ssam sc->sc_resid = bp->b_bcount; 397*6941Ssam sc->sc_unit = ui->ui_slave; 398*6941Ssam printd(", bcr 0x%x, cmd 0x%x\n", sn, cmd); 399*6941Ssam um->um_cmd = cmd; 400*6941Ssam (void) ubago(ui); 401*6941Ssam return (1); 402*6941Ssam } 403*6941Ssam 404*6941Ssam idcdgo(um) 405*6941Ssam register struct uba_ctlr *um; 406*6941Ssam { 407*6941Ssam register struct idcdevice *idcaddr = (struct idcdevice *)um->um_addr; 408*6941Ssam register struct idc_softc *sc = &idc_softc; 409*6941Ssam 410*6941Ssam /* 411*6941Ssam * VERY IMPORTANT: must load registers in this order. 412*6941Ssam */ 413*6941Ssam idcaddr->idcbar = sc->sc_ubaddr = um->um_ubinfo&0x3ffff; 414*6941Ssam idcaddr->idcbcr = -sc->sc_bcnt; 415*6941Ssam idcaddr->idcdar = sc->sc_dar; 416*6941Ssam printd("idcdgo, ubinfo 0x%x, cmd 0x%x\n", um->um_ubinfo, um->um_cmd); 417*6941Ssam idcaddr->idccsr = um->um_cmd; 418*6941Ssam trace('go', um); 419*6941Ssam um->um_tab.b_active = 2; 420*6941Ssam /*** CLEAR SPURIOUS ATTN ON R80? ***/ 421*6941Ssam } 422*6941Ssam 423*6941Ssam idcintr(idc) 424*6941Ssam int idc; 425*6941Ssam { 426*6941Ssam register struct uba_ctlr *um = idcminfo[idc]; 427*6941Ssam register struct uba_device *ui; 428*6941Ssam register struct idcdevice *idcaddr = (struct idcdevice *)um->um_addr; 429*6941Ssam register struct idc_softc *sc = &idc_softc; 430*6941Ssam register struct buf *bp, *dp; 431*6941Ssam struct idcst *st; 432*6941Ssam int unit, as, er, cmd, ds = 0; 433*6941Ssam 434*6941Ssam printd("idcintr, idccsr 0x%x", idcaddr->idccsr); 435*6941Ssam top: 436*6941Ssam idcwticks = 0; 437*6941Ssam trace('intr', um->um_tab.b_active); 438*6941Ssam if (um->um_tab.b_active == 2) { 439*6941Ssam /* 440*6941Ssam * Process a data transfer complete interrupt. 441*6941Ssam */ 442*6941Ssam um->um_tab.b_active = 1; 443*6941Ssam dp = um->um_tab.b_actf; 444*6941Ssam bp = dp->b_actf; 445*6941Ssam ui = idcdinfo[dkunit(bp)]; 446*6941Ssam unit = ui->ui_slave; 447*6941Ssam st = &idcst[ui->ui_type]; 448*6941Ssam idcaddr->idccsr = IDC_IE|IDC_CRDY|(unit<<8); 449*6941Ssam if ((er = idcaddr->idccsr) & IDC_ERR) { 450*6941Ssam if (er & IDC_DE) { 451*6941Ssam idcaddr->idcmpr = IDCGS_GETSTAT; 452*6941Ssam idcaddr->idccsr = IDC_GETSTAT|(unit<<8); 453*6941Ssam idcwait(idcaddr, 0); 454*6941Ssam ds = idcaddr->idcmpr; 455*6941Ssam idcaddr->idccsr = 456*6941Ssam IDC_IE|IDC_CRDY|(1<<(unit+16)); 457*6941Ssam } 458*6941Ssam printd(", er 0x%x, ds 0x%x", er, ds); 459*6941Ssam if (ds & IDCDS_WL) { 460*6941Ssam printf("rb%d: write locked\n", dkunit(bp)); 461*6941Ssam bp->b_flags |= B_ERROR; 462*6941Ssam } else if (++um->um_tab.b_errcnt > 28 || er&IDC_HARD) { 463*6941Ssam hard: 464*6941Ssam harderr(bp, "rb"); 465*6941Ssam printf("csr=%b ds=%b\n", er, IDCCSR_BITS, ds, 466*6941Ssam ui->ui_type?IDCRB80DS_BITS:IDCRB02DS_BITS); 467*6941Ssam bp->b_flags |= B_ERROR; 468*6941Ssam } else if (er & IDC_DCK) { 469*6941Ssam switch (er & IDC_ECS) { 470*6941Ssam case IDC_ECS_NONE: 471*6941Ssam break; 472*6941Ssam case IDC_ECS_SOFT: 473*6941Ssam idcecc(ui); 474*6941Ssam break; 475*6941Ssam case IDC_ECS_HARD: 476*6941Ssam default: 477*6941Ssam goto hard; 478*6941Ssam } 479*6941Ssam } else 480*6941Ssam /* recoverable error, set up for retry */ 481*6941Ssam goto seek; 482*6941Ssam } 483*6941Ssam if ((sc->sc_resid -= sc->sc_bcnt) != 0) { 484*6941Ssam sc->sc_ubaddr += sc->sc_bcnt; 485*6941Ssam /* 486*6941Ssam * Current transfer is complete, have 487*6941Ssam * we overflowed to the next track? 488*6941Ssam */ 489*6941Ssam if ((sc->sc_sect += sc->sc_bcnt/st->nbps) == st->nsect) { 490*6941Ssam sc->sc_sect = 0; 491*6941Ssam if (++sc->sc_trk == st->ntrak) { 492*6941Ssam sc->sc_trk = 0; 493*6941Ssam sc->sc_cyl++; 494*6941Ssam } else if (ui->ui_type) { 495*6941Ssam /* 496*6941Ssam * RB80 can change heads just by 497*6941Ssam * loading the disk address register. 498*6941Ssam */ 499*6941Ssam idcaddr->idccsr = IDC_SEEK|IDC_CRDY| 500*6941Ssam IDC_IE|(unit<<8); 501*6941Ssam printd(", change to track 0x%x", sc->sc_dar); 502*6941Ssam idcaddr->idcdar = sc->sc_dar; 503*6941Ssam idccyl[ui->ui_unit].dar_dar = sc->sc_dar; 504*6941Ssam idccyl[ui->ui_unit].dar_sect = 0; 505*6941Ssam goto cont; 506*6941Ssam } 507*6941Ssam /* 508*6941Ssam * Changing tracks on RB02 or cylinders 509*6941Ssam * on RB80, start a seek. 510*6941Ssam */ 511*6941Ssam seek: 512*6941Ssam cmd = IDC_IE|IDC_SEEK|(unit<<8); 513*6941Ssam idcaddr->idccsr = cmd|IDC_CRDY; 514*6941Ssam idcaddr->idcdar = sc->sc_dar; 515*6941Ssam printd(", seek to 0x%x\n", sc->sc_dar); 516*6941Ssam idccyl[ui->ui_unit].dar_dar = sc->sc_dar; 517*6941Ssam idccyl[ui->ui_unit].dar_sect = 0; 518*6941Ssam sc->sc_bcnt = 0; 519*6941Ssam idcaddr->idccsr = cmd; 520*6941Ssam if (ui->ui_type) { 521*6941Ssam if (idcwait(idcaddr, 10) == 0) 522*6941Ssam return; 523*6941Ssam idcaddr->idccsr &= ~IDC_ATTN; 524*6941Ssam if (idcaddr->idccsr & IDC_DRDY) 525*6941Ssam goto top; 526*6941Ssam } 527*6941Ssam } else { 528*6941Ssam /* 529*6941Ssam * Continue transfer on current track. 530*6941Ssam */ 531*6941Ssam cont: 532*6941Ssam sc->sc_bcnt = (st->nsect-sc->sc_sect)*st->nbps; 533*6941Ssam if (sc->sc_bcnt > sc->sc_resid) 534*6941Ssam sc->sc_bcnt = sc->sc_resid; 535*6941Ssam if (bp->b_flags & B_READ) 536*6941Ssam cmd = IDC_IE|IDC_READ|(unit<<8); 537*6941Ssam else 538*6941Ssam cmd = IDC_IE|IDC_WRITE|(unit<<8); 539*6941Ssam idcaddr->idccsr = cmd|IDC_CRDY; 540*6941Ssam idcaddr->idcbar = sc->sc_ubaddr; 541*6941Ssam idcaddr->idcbcr = -sc->sc_bcnt; 542*6941Ssam idcaddr->idcdar = sc->sc_dar; 543*6941Ssam printd(", continue I/O 0x%x, 0x%x\n", sc->sc_dar, sc->sc_bcnt); 544*6941Ssam idcaddr->idccsr = cmd; 545*6941Ssam um->um_tab.b_active = 2; 546*6941Ssam } 547*6941Ssam return; 548*6941Ssam } 549*6941Ssam /* 550*6941Ssam * Entire transfer is done, clean up. 551*6941Ssam */ 552*6941Ssam ubadone(um); 553*6941Ssam dk_busy &= ~(1 << ui->ui_dk); 554*6941Ssam um->um_tab.b_active = 0; 555*6941Ssam um->um_tab.b_errcnt = 0; 556*6941Ssam um->um_tab.b_actf = dp->b_forw; 557*6941Ssam dp->b_active = 0; 558*6941Ssam dp->b_errcnt = 0; 559*6941Ssam dp->b_actf = bp->av_forw; 560*6941Ssam trace('done', dp); trace(um->um_tab.b_actf, dp->b_actf); 561*6941Ssam bp->b_resid = sc->sc_resid; 562*6941Ssam printd(", iodone, resid 0x%x\n", bp->b_resid); 563*6941Ssam iodone(bp); 564*6941Ssam if (dp->b_actf) 565*6941Ssam if (idcustart(ui)) 566*6941Ssam return; 567*6941Ssam } else if (um->um_tab.b_active == 1) { 568*6941Ssam /* 569*6941Ssam * Got an interrupt while setting up for a command 570*6941Ssam * or doing a mid-transfer seek. Save any attentions 571*6941Ssam * for later and process a mid-transfer seek complete. 572*6941Ssam */ 573*6941Ssam as = idcaddr->idccsr; 574*6941Ssam idcaddr->idccsr = IDC_IE|IDC_CRDY|(as&IDC_ATTN); 575*6941Ssam as = (as >> 16) & 0xf; 576*6941Ssam unit = sc->sc_unit; 577*6941Ssam sc->sc_softas |= as & ~(1<<unit); 578*6941Ssam if (as & (1<<unit)) { 579*6941Ssam printd(", seek1 complete"); 580*6941Ssam um->um_tab.b_active = 2; 581*6941Ssam goto top; 582*6941Ssam } 583*6941Ssam printd(", as1 %o\n", as); 584*6941Ssam return; 585*6941Ssam } 586*6941Ssam /* 587*6941Ssam * Process any seek initiated or complete interrupts. 588*6941Ssam */ 589*6941Ssam as = idcaddr->idccsr; 590*6941Ssam idcaddr->idccsr = IDC_IE|IDC_CRDY|(as&IDC_ATTN); 591*6941Ssam as = ((as >> 16) & 0xf) | sc->sc_softas; 592*6941Ssam sc->sc_softas = 0; 593*6941Ssam trace('as', as); 594*6941Ssam printd(", as %o", as); 595*6941Ssam for (unit = 0; unit < NRB; unit++) 596*6941Ssam if (as & (1<<unit)) { 597*6941Ssam as &= ~(1<<unit); 598*6941Ssam idcaddr->idccsr = IDC_IE|IDC_CRDY|(unit<<8); 599*6941Ssam ui = idcdinfo[unit]; 600*6941Ssam if (ui) { 601*6941Ssam printd(", attn unit %d", unit); 602*6941Ssam if (idcaddr->idccsr & IDC_DRDY) 603*6941Ssam if (idcustart(ui)) { 604*6941Ssam sc->sc_softas = as; 605*6941Ssam return; 606*6941Ssam } 607*6941Ssam } else { 608*6941Ssam printd(", unsol. intr. unit %d", unit); 609*6941Ssam } 610*6941Ssam } 611*6941Ssam printd("\n"); 612*6941Ssam if (um->um_tab.b_actf && um->um_tab.b_active == 0) { 613*6941Ssam trace('stum',um->um_tab.b_actf); 614*6941Ssam idcstart(um); 615*6941Ssam } 616*6941Ssam } 617*6941Ssam 618*6941Ssam idcwait(addr, cnt) 619*6941Ssam register struct idcdevice *addr; 620*6941Ssam register int cnt; 621*6941Ssam { 622*6941Ssam register int i; 623*6941Ssam 624*6941Ssam while (--cnt && (addr->idccsr & IDC_CRDY) == 0) 625*6941Ssam for (i = 10; i; i--) 626*6941Ssam ; 627*6941Ssam return (cnt); 628*6941Ssam } 629*6941Ssam 630*6941Ssam idcread(dev) 631*6941Ssam dev_t dev; 632*6941Ssam { 633*6941Ssam register int unit = minor(dev) >> 3; 634*6941Ssam 635*6941Ssam if (unit >= NRB) 636*6941Ssam u.u_error = ENXIO; 637*6941Ssam else 638*6941Ssam physio(idcstrategy, &ridcbuf[unit], dev, B_READ, minphys); 639*6941Ssam } 640*6941Ssam 641*6941Ssam idcwrite(dev) 642*6941Ssam dev_t dev; 643*6941Ssam { 644*6941Ssam register int unit = minor(dev) >> 3; 645*6941Ssam 646*6941Ssam if (unit >= NRB) 647*6941Ssam u.u_error = ENXIO; 648*6941Ssam else 649*6941Ssam physio(idcstrategy, &ridcbuf[unit], dev, B_WRITE, minphys); 650*6941Ssam } 651*6941Ssam 652*6941Ssam idcecc(ui) 653*6941Ssam register struct uba_device *ui; 654*6941Ssam { 655*6941Ssam register struct idcdevice *idc = (struct idcdevice *)ui->ui_addr; 656*6941Ssam register struct buf *bp = idcutab[ui->ui_unit].b_actf; 657*6941Ssam register struct uba_ctlr *um = ui->ui_mi; 658*6941Ssam register struct idcst *st; 659*6941Ssam register int i; 660*6941Ssam struct uba_regs *ubp = ui->ui_hd->uh_uba; 661*6941Ssam int bit, byte, mask; 662*6941Ssam caddr_t addr; 663*6941Ssam int reg, npf, o; 664*6941Ssam int cn, tn, sn; 665*6941Ssam 666*6941Ssam printf("idcecc: HELP!\n"); 667*6941Ssam npf = btop(idc->idcbcr + idc_softc.sc_bcnt) - 1;; 668*6941Ssam reg = btop(idc_softc.sc_ubaddr) + npf; 669*6941Ssam o = (int)bp->b_un.b_addr & PGOFSET; 670*6941Ssam st = &idcst[ui->ui_type]; 671*6941Ssam cn = idc_softc.sc_cyl; 672*6941Ssam tn = idc_softc.sc_trk; 673*6941Ssam sn = idc_softc.sc_sect; 674*6941Ssam um->um_tab.b_active = 1; /* Either complete or continuing... */ 675*6941Ssam printf("rb%d%c: soft ecc sn%d\n", dkunit(bp), 676*6941Ssam 'a'+(minor(bp->b_dev)&07), 677*6941Ssam (cn*st->ntrak + tn) * st->nsect + sn + npf); 678*6941Ssam mask = idc->idceccpat; 679*6941Ssam i = idc->idceccpos - 1; /* -1 makes 0 origin */ 680*6941Ssam bit = i&07; 681*6941Ssam i = (i&~07)>>3; 682*6941Ssam byte = i + o; 683*6941Ssam while (i < 512 && (int)ptob(npf)+i < idc_softc.sc_bcnt && bit > -11) { 684*6941Ssam addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ 685*6941Ssam (byte & PGOFSET); 686*6941Ssam putmemc(addr, getmemc(addr)^(mask<<bit)); 687*6941Ssam byte++; 688*6941Ssam i++; 689*6941Ssam bit -= 8; 690*6941Ssam } 691*6941Ssam idc_softc.sc_bcnt += idc->idcbcr; 692*6941Ssam um->um_tab.b_errcnt = 0; /* error has been corrected */ 693*6941Ssam return; 694*6941Ssam } 695*6941Ssam 696*6941Ssam idcreset(uban) 697*6941Ssam int uban; 698*6941Ssam { 699*6941Ssam register struct uba_ctlr *um; 700*6941Ssam register struct uba_device *ui; 701*6941Ssam register unit; 702*6941Ssam 703*6941Ssam if ((um = idcminfo[0]) == 0 || um->um_ubanum != uban || 704*6941Ssam um->um_alive == 0) 705*6941Ssam return; 706*6941Ssam printf(" idc0"); 707*6941Ssam um->um_tab.b_active = 0; 708*6941Ssam um->um_tab.b_actf = um->um_tab.b_actl = 0; 709*6941Ssam if (um->um_ubinfo) { 710*6941Ssam printf("<%d>", (um->um_ubinfo>>28)&0xf); 711*6941Ssam ubadone(um); 712*6941Ssam } 713*6941Ssam for (unit = 0; unit < NRB; unit++) { 714*6941Ssam if ((ui = idcdinfo[unit]) == 0 || ui->ui_alive == 0) 715*6941Ssam continue; 716*6941Ssam idcutab[unit].b_active = 0; 717*6941Ssam (void) idcustart(ui); 718*6941Ssam } 719*6941Ssam (void) idcstart(um); 720*6941Ssam } 721*6941Ssam 722*6941Ssam idcwatch() 723*6941Ssam { 724*6941Ssam register struct uba_ctlr *um; 725*6941Ssam register unit; 726*6941Ssam 727*6941Ssam timeout(idcwatch, (caddr_t)0, hz); 728*6941Ssam um = idcminfo[0]; 729*6941Ssam if (um == 0 || um->um_alive == 0) 730*6941Ssam return; 731*6941Ssam if (um->um_tab.b_active == 0) { 732*6941Ssam for (unit = 0; unit < NRB; unit++) 733*6941Ssam if (idcutab[unit].b_active) 734*6941Ssam goto active; 735*6941Ssam idcwticks = 0; 736*6941Ssam return; 737*6941Ssam } 738*6941Ssam active: 739*6941Ssam idcwticks++; 740*6941Ssam if (idcwticks >= 20) { 741*6941Ssam idcwticks = 0; 742*6941Ssam printf("idc0: lost interrupt\n"); 743*6941Ssam idcintr(0); 744*6941Ssam } 745*6941Ssam } 746*6941Ssam 747*6941Ssam idcdump(dev) 748*6941Ssam dev_t dev; 749*6941Ssam { 750*6941Ssam #ifdef notdef 751*6941Ssam struct idcdevice *idcaddr; 752*6941Ssam char *start; 753*6941Ssam int num, blk, unit, dbsize; 754*6941Ssam struct size *sizes; 755*6941Ssam register struct uba_regs *uba; 756*6941Ssam register struct uba_device *ui; 757*6941Ssam struct idcst *st; 758*6941Ssam 759*6941Ssam unit = minor(dev) >> 3; 760*6941Ssam if (unit >= NRB) 761*6941Ssam return (ENXIO); 762*6941Ssam #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) 763*6941Ssam ui = phys(struct uba_device *, idcdinfo[unit]); 764*6941Ssam if (ui->ui_alive == 0) 765*6941Ssam return (ENXIO); 766*6941Ssam uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 767*6941Ssam ubainit(uba); 768*6941Ssam idcaddr = (struct idcdevice *)ui->ui_physaddr; 769*6941Ssam num = maxfree; 770*6941Ssam start = 0; 771*6941Ssam /*** 772*6941Ssam idcaddr->idccs1 = IDC_CCLR; 773*6941Ssam idcaddr->idccs2 = unit; 774*6941Ssam idcaddr->idccs1 = idctypes[ui->ui_type]|IDC_DCLR|IDC_GO; 775*6941Ssam idcwait(idcaddr); 776*6941Ssam dbsize = 20 or 31; 777*6941Ssam ***/ 778*6941Ssam st = &idcst[ui->ui_type]; 779*6941Ssam sizes = phys(struct size *, st->sizes); 780*6941Ssam if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) 781*6941Ssam return (EINVAL); 782*6941Ssam while (num > 0) { 783*6941Ssam register struct pte *io; 784*6941Ssam register int i; 785*6941Ssam int cn, sn, tn; 786*6941Ssam daddr_t bn; 787*6941Ssam 788*6941Ssam blk = num > dbsize ? dbsize : num; 789*6941Ssam io = uba->uba_map; 790*6941Ssam for (i = 0; i < blk; i++) 791*6941Ssam *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV; 792*6941Ssam *(int *)io = 0; 793*6941Ssam bn = dumplo + btop(start); 794*6941Ssam cn = bn/st->nspc + sizes[minor(dev)&07].cyloff; 795*6941Ssam sn = bn%st->nspc; 796*6941Ssam tn = sn/st->nsect; 797*6941Ssam sn = sn%st->nsect; 798*6941Ssam /*** 799*6941Ssam idcaddr->idccyl = cn; 800*6941Ssam rp = (short *) &idcaddr->idcda; 801*6941Ssam *rp = (tn << 8) + sn; 802*6941Ssam *--rp = 0; 803*6941Ssam *--rp = -blk*NBPG / sizeof (short); 804*6941Ssam *--rp = idctypes[ui->ui_type]|IDC_GO|IDC_WRITE; 805*6941Ssam idcwait(idcaddr); 806*6941Ssam ***/ 807*6941Ssam if (idcaddr->idccsr & IDC_ERR) 808*6941Ssam return (EIO); 809*6941Ssam start += blk*NBPG; 810*6941Ssam num -= blk; 811*6941Ssam } 812*6941Ssam return (0); 813*6941Ssam #else 814*6941Ssam return (ENXIO); 815*6941Ssam #endif 816*6941Ssam } 817*6941Ssam #endif 818