1*17077Sbloom /* rl.c 6.2 84/08/29 */ 210770Ssam 310770Ssam #include "rl.h" 412452Ssam #if NRL > 0 510770Ssam /* 610770Ssam * UNIBUS RL02 disk driver 710770Ssam */ 813091Ssam #include "../machine/pte.h" 910770Ssam 10*17077Sbloom #include "param.h" 11*17077Sbloom #include "systm.h" 12*17077Sbloom #include "dk.h" 13*17077Sbloom #include "dkbad.h" 14*17077Sbloom #include "buf.h" 15*17077Sbloom #include "conf.h" 16*17077Sbloom #include "dir.h" 17*17077Sbloom #include "user.h" 18*17077Sbloom #include "map.h" 19*17077Sbloom #include "vm.h" 20*17077Sbloom #include "cmap.h" 21*17077Sbloom #include "uio.h" 22*17077Sbloom #include "kernel.h" 2310770Ssam 2413091Ssam #include "../vax/cpu.h" 2513091Ssam #include "../vax/nexus.h" 26*17077Sbloom #include "ubavar.h" 27*17077Sbloom #include "ubareg.h" 28*17077Sbloom #include "rlreg.h" 2910770Ssam 3010770Ssam /* Pending Controller items and statistics */ 3110770Ssam struct rl_softc { 3210770Ssam int rl_softas; /* Attention sumary, (seeks pending) */ 3310770Ssam int rl_ndrive; /* Number of drives on controller */ 3410770Ssam int rl_wticks; /* Monitor time for function */ 3510770Ssam } rl_softc[NHL]; 3610770Ssam 3710770Ssam /* 3813091Ssam * State of controller from last transfer. 3913091Ssam * Since only one transfer can be done at a time per 4010770Ssam * controller, only allocate one for each controller. 4110770Ssam */ 4210770Ssam struct rl_stat { 4310770Ssam short rl_cyl[4]; /* Current cylinder for each drive */ 4410770Ssam short rl_dn; /* drive number currently transferring */ 4510770Ssam short rl_cylnhd; /* current cylinder and head of transfer */ 4610770Ssam u_short rl_bleft; /* bytes left to transfer */ 4710770Ssam u_short rl_bpart; /* bytes transferred */ 4810770Ssam } rl_stat[NHL]; 4910770Ssam 5010770Ssam /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 5113091Ssam /* Last cylinder not used. Saved for Bad Sector File */ 5210770Ssam struct size { 5310770Ssam daddr_t nblocks; 5410770Ssam int cyloff; 5510770Ssam } rl02_sizes[8] = { 5613091Ssam 15884, 0, /* A=cyl 0 thru 397 */ 5713091Ssam 4520, 398, /* B=cyl 398 thru 510 */ 5813091Ssam -1, 0, /* C=cyl 0 thru 511 */ 5913091Ssam 4520, 398, /* D=cyl 398 thru 510 */ 6010770Ssam 0, 0, /* F= Not Defined */ 6113091Ssam 20440, 0, /* G=cyl 0 thru 510 */ 6210770Ssam 0, 0, /* H= Not Defined */ 6310770Ssam }; 6410770Ssam /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 6510770Ssam 6610770Ssam int rlprobe(), rlslave(), rlattach(), rldgo(), rlintr(); 6710770Ssam struct uba_ctlr *rlminfo[NHL]; 6810770Ssam struct uba_device *rldinfo[NRL]; 6910770Ssam struct uba_device *rlip[NHL][4]; 7010770Ssam 7110770Ssam /* RL02 driver structure */ 7210770Ssam u_short rlstd[] = { 0174400 }; 7310770Ssam struct uba_driver hldriver = 7410770Ssam { rlprobe, rlslave, rlattach, rldgo, rlstd, "rl", rldinfo, "hl", rlminfo }; 7510770Ssam 7610770Ssam /* User table per controller */ 7710770Ssam struct buf rlutab[NRL]; 7810770Ssam 7910770Ssam /* RL02 drive structure */ 8010770Ssam struct RL02 { 8110770Ssam short nbpt; /* Number of 512 byte blocks/track */ 8210770Ssam short ntrak; 8310770Ssam short nbpc; /* Number of 512 byte blocks/cylinder */ 8410770Ssam short ncyl; 8510770Ssam short btrak; /* Number of bytes/track */ 8610770Ssam struct size *sizes; 8710770Ssam } rl02 = { 8810770Ssam 20, 2, 40, 512, 20*512, rl02_sizes /* rl02/DEC*/ 8910770Ssam }; 9010770Ssam 9110770Ssam struct buf rrlbuf[NRL]; 9210770Ssam 9310770Ssam #define b_cylin b_resid /* Last seek as CYL<<1 | HD */ 9410770Ssam 9510770Ssam #ifdef INTRLVE 9610770Ssam daddr_t dkblock(); 9710770Ssam #endif 9810770Ssam 9910770Ssam int rlwstart, rlwatch(); /* Have started guardian */ 10010770Ssam 10110770Ssam /* Check that controller exists */ 10210770Ssam /*ARGSUSED*/ 10310770Ssam rlprobe(reg) 10410770Ssam caddr_t reg; 10510770Ssam { 10610770Ssam register int br, cvec; 10710770Ssam 10810770Ssam #ifdef lint 10910770Ssam br = 0; cvec = br; br = cvec; 11013091Ssam rlintr(0); 11110770Ssam #endif 11213091Ssam ((struct rldevice *)reg)->rlcs = RL_IE | RL_NOOP; 11313091Ssam DELAY(10); 11413091Ssam ((struct rldevice *)reg)->rlcs &= ~RL_IE; 11512452Ssam return (sizeof (struct rldevice)); 11610770Ssam } 11710770Ssam 11810770Ssam rlslave(ui, reg) 11910770Ssam struct uba_device *ui; 12010770Ssam caddr_t reg; 12110770Ssam { 12210770Ssam register struct rldevice *rladdr = (struct rldevice *)reg; 12310770Ssam short ctr = 0; 12410770Ssam 12510770Ssam /* 12610770Ssam * DEC reports that: 12710770Ssam * For some unknown reason the RL02 (seems to be only drive 1) 12810770Ssam * does not return a valid drive status the first time that a 12910770Ssam * GET STATUS request is issued for the drive, in fact it can 13010770Ssam * take up to three or more GET STATUS requests to obtain the 13110770Ssam * correct status. 13210770Ssam * In order to overcome this, the driver has been modified to 13310770Ssam * issue a GET STATUS request and validate the drive status 13410770Ssam * returned. If a valid status is not returned after eight 13510770Ssam * attempts, then an error message is printed. 13610770Ssam */ 13710770Ssam do { 13810770Ssam rladdr->rlda.getstat = RL_RESET; 13910770Ssam rladdr->rlcs = (ui->ui_slave <<8) | RL_GETSTAT; /* Get status*/ 14010770Ssam rlwait(rladdr); 14113091Ssam } while ((rladdr->rlmp.getstat&RLMP_STATUS) != RLMP_STATOK && ++ctr<8); 14210770Ssam if ((rladdr->rlcs & RL_DE) || (ctr >= 8)) 14313091Ssam return (0); 14413091Ssam if ((rladdr->rlmp.getstat & RLMP_DT) == 0 ) { 14513091Ssam printf("rl%d: rl01's not supported\n", ui->ui_slave); 14610770Ssam return(0); 14710770Ssam } 14810770Ssam return (1); 14910770Ssam } 15010770Ssam 15110770Ssam rlattach(ui) 15210770Ssam register struct uba_device *ui; 15310770Ssam { 15410770Ssam register struct rldevice *rladdr; 15510770Ssam 15610770Ssam if (rlwstart == 0) { 15713091Ssam timeout(rlwatch, (caddr_t)0, hz); 15810770Ssam rlwstart++; 15910770Ssam } 16010770Ssam /* Initialize iostat values */ 16110770Ssam if (ui->ui_dk >= 0) 16210770Ssam dk_mspw[ui->ui_dk] = .000003906; /* 16bit transfer time? */ 16310770Ssam rlip[ui->ui_ctlr][ui->ui_slave] = ui; 16413091Ssam rl_softc[ui->ui_ctlr].rl_ndrive++; 16510770Ssam rladdr = (struct rldevice *)ui->ui_addr; 16610770Ssam /* reset controller */ 16710770Ssam rladdr->rlda.getstat = RL_RESET; /* SHOULD BE REPEATED? */ 16810770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_GETSTAT; /* Reset DE bit */ 16910770Ssam rlwait(rladdr); 17013091Ssam /* determine disk posistion */ 17110770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_RHDR; 17210770Ssam rlwait(rladdr); 17310770Ssam /* save disk drive posistion */ 17410770Ssam rl_stat[ui->ui_ctlr].rl_cyl[ui->ui_slave] = 17513091Ssam (rladdr->rlmp.readhdr & 0177700) >> 6; 17610770Ssam rl_stat[ui->ui_ctlr].rl_dn = -1; 17710770Ssam } 17810770Ssam 17912452Ssam rlopen(dev) 18012452Ssam dev_t dev; 18112452Ssam { 18212452Ssam register int unit = minor(dev) >> 3; 18313091Ssam register struct uba_device *ui; 18412452Ssam 18512452Ssam if (unit >= NRL || (ui = rldinfo[unit]) == 0 || ui->ui_alive == 0) 18612452Ssam return (ENXIO); 18712452Ssam return (0); 18812452Ssam } 18912452Ssam 19010770Ssam rlstrategy(bp) 19110770Ssam register struct buf *bp; 19210770Ssam { 19310770Ssam register struct uba_device *ui; 19410770Ssam register int drive; 19510770Ssam register struct buf *dp; 19613091Ssam int partition = minor(bp->b_dev) & 07, s; 19710770Ssam long bn, sz; 19810770Ssam 19913091Ssam sz = (bp->b_bcount+511) >> 9; 20013091Ssam drive = dkunit(bp); 20110770Ssam if (drive >= NRL) 20210770Ssam goto bad; 20313091Ssam ui = rldinfo[drive]; 20410770Ssam if (ui == 0 || ui->ui_alive == 0) 20510770Ssam goto bad; 20610770Ssam if (bp->b_blkno < 0 || 20710770Ssam (bn = dkblock(bp))+sz > rl02.sizes[partition].nblocks) 20810770Ssam goto bad; 20910770Ssam /* bn is in 512 byte block size */ 21010770Ssam bp->b_cylin = bn/rl02.nbpc + rl02.sizes[partition].cyloff; 21113091Ssam s = spl5(); 21210770Ssam dp = &rlutab[ui->ui_unit]; 21310770Ssam disksort(dp, bp); 21410770Ssam if (dp->b_active == 0) { 21513091Ssam rlustart(ui); 21610770Ssam bp = &ui->ui_mi->um_tab; 21710770Ssam if (bp->b_actf && bp->b_active == 0) 21813091Ssam rlstart(ui->ui_mi); 21910770Ssam } 22013091Ssam splx(s); 22110770Ssam return; 22210770Ssam 22310770Ssam bad: 22410770Ssam bp->b_flags |= B_ERROR; 22510770Ssam iodone(bp); 22610770Ssam return; 22710770Ssam } 22810770Ssam 22910770Ssam /* 23010770Ssam * Unit start routine. 23110770Ssam * Seek the drive to be where the data is 23210770Ssam * and then generate another interrupt 23310770Ssam * to actually start the transfer. 23410770Ssam */ 23510770Ssam rlustart(ui) 23610770Ssam register struct uba_device *ui; 23710770Ssam { 23810770Ssam register struct buf *bp, *dp; 23910770Ssam register struct uba_ctlr *um; 24010770Ssam register struct rldevice *rladdr; 24110770Ssam daddr_t bn; 24213091Ssam short hd, diff; 24310770Ssam 24410770Ssam if (ui == 0) 24513091Ssam return; 24610770Ssam um = ui->ui_mi; 24713091Ssam dk_busy &= ~(1 << ui->ui_dk); 24810770Ssam dp = &rlutab[ui->ui_unit]; 24910770Ssam if ((bp = dp->b_actf) == NULL) 25013091Ssam return; 25110770Ssam /* 25210770Ssam * If the controller is active, just remember 25310770Ssam * that this device has to be positioned... 25410770Ssam */ 25510770Ssam if (um->um_tab.b_active) { 25610770Ssam rl_softc[um->um_ctlr].rl_softas |= 1<<ui->ui_slave; 25713091Ssam return; 25810770Ssam } 25910770Ssam /* 26010770Ssam * If we have already positioned this drive, 26110770Ssam * then just put it on the ready queue. 26210770Ssam */ 26310770Ssam if (dp->b_active) 26410770Ssam goto done; 26513091Ssam dp->b_active = 1; /* positioning drive */ 26610770Ssam rladdr = (struct rldevice *)um->um_addr; 26710770Ssam 26810770Ssam /* 26910770Ssam * Figure out where this transfer is going to 27010770Ssam * and see if we are seeked correctly. 27110770Ssam */ 27210770Ssam bn = dkblock(bp); /* Block # desired */ 27310770Ssam /* 27413091Ssam * Map 512 byte logical disk blocks 27513091Ssam * to 256 byte sectors (rl02's are stupid). 27610770Ssam */ 27710770Ssam hd = (bn / rl02.nbpt) & 1; /* Get head required */ 27810770Ssam diff = (rl_stat[um->um_ctlr].rl_cyl[ui->ui_slave] >> 1) - bp->b_cylin; 27910770Ssam if ( diff == 0 && (rl_stat[um->um_ctlr].rl_cyl[ui->ui_slave] & 1) == hd) 28010770Ssam goto done; /* on cylinder and head */ 28110770Ssam /* 28210770Ssam * Not at correct position. 28310770Ssam */ 28410770Ssam rl_stat[um->um_ctlr].rl_cyl[ui->ui_slave] = (bp->b_cylin << 1) | hd; 28510770Ssam if (diff < 0) 28610770Ssam rladdr->rlda.seek = -diff << 7 | RLDA_HGH | hd << 4; 28710770Ssam else 28810770Ssam rladdr->rlda.seek = diff << 7 | RLDA_LOW | hd << 4; 28910770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_SEEK; 29010770Ssam 29110770Ssam /* 29210770Ssam * Mark unit busy for iostat. 29310770Ssam */ 29410770Ssam if (ui->ui_dk >= 0) { 29510770Ssam dk_busy |= 1<<ui->ui_dk; 29610770Ssam dk_seek[ui->ui_dk]++; 29710770Ssam } 29812452Ssam rlwait(rladdr); 29910770Ssam done: 30010770Ssam /* 30110770Ssam * Device is ready to go. 30210770Ssam * Put it on the ready queue for the controller 30310770Ssam * (unless its already there.) 30410770Ssam */ 30510770Ssam if (dp->b_active != 2) { 30610770Ssam dp->b_forw = NULL; 30710770Ssam if (um->um_tab.b_actf == NULL) 30810770Ssam um->um_tab.b_actf = dp; 30910770Ssam else 31010770Ssam um->um_tab.b_actl->b_forw = dp; 31110770Ssam um->um_tab.b_actl = dp; 31210770Ssam dp->b_active = 2; /* Request on ready queue */ 31310770Ssam } 31410770Ssam } 31510770Ssam 31610770Ssam /* 31710770Ssam * Start up a transfer on a drive. 31810770Ssam */ 31910770Ssam rlstart(um) 32010770Ssam register struct uba_ctlr *um; 32110770Ssam { 32210770Ssam register struct buf *bp, *dp; 32310770Ssam register struct uba_device *ui; 32410770Ssam register struct rldevice *rladdr; 32510770Ssam register struct rl_stat *st = &rl_stat[um->um_ctlr]; 32610770Ssam daddr_t bn; 32710770Ssam short sn, cyl, cmd; 32810770Ssam 32910770Ssam loop: 33010770Ssam if ((dp = um->um_tab.b_actf) == NULL) { 33110770Ssam st->rl_dn = -1; 33210770Ssam st->rl_cylnhd = 0; 33310770Ssam st->rl_bleft = 0; 33410770Ssam st->rl_bpart = 0; 33513091Ssam return; 33610770Ssam } 33710770Ssam if ((bp = dp->b_actf) == NULL) { 33810770Ssam um->um_tab.b_actf = dp->b_forw; 33910770Ssam goto loop; 34010770Ssam } 34110770Ssam /* 34210770Ssam * Mark controller busy, and 34313091Ssam * determine destination. 34410770Ssam */ 34510770Ssam um->um_tab.b_active++; 34610770Ssam ui = rldinfo[dkunit(bp)]; /* Controller */ 34710770Ssam bn = dkblock(bp); /* 512 byte Block number */ 34810770Ssam cyl = bp->b_cylin << 1; /* Cylinder */ 34910770Ssam cyl |= (bn / rl02.nbpt) & 1; /* Get head required */ 35010770Ssam sn = (bn % rl02.nbpt) << 1; /* Sector number */ 35110770Ssam rladdr = (struct rldevice *)ui->ui_addr; 35212452Ssam rlwait(rladdr); 35310770Ssam rladdr->rlda.rw = cyl<<6 | sn; 35410770Ssam /* save away current transfers drive status */ 35510770Ssam st->rl_dn = ui->ui_slave; 35610770Ssam st->rl_cylnhd = cyl; 35710770Ssam st->rl_bleft = bp->b_bcount; 35810770Ssam st->rl_bpart = rl02.btrak - (sn * NRLBPSC); 35913091Ssam /* 36013091Ssam * RL02 must seek between cylinders and between tracks, 36113091Ssam * determine maximum data transfer at this time. 36213091Ssam */ 36313091Ssam if (st->rl_bleft < st->rl_bpart) 36410770Ssam st->rl_bpart = st->rl_bleft; 36510770Ssam rladdr->rlmp.rw = -(st->rl_bpart >> 1); 36610770Ssam if (bp->b_flags & B_READ) 36710770Ssam cmd = RL_IE | RL_READ | (ui->ui_slave << 8); 36810770Ssam else 36910770Ssam cmd = RL_IE | RL_WRITE | (ui->ui_slave << 8); 37010770Ssam um->um_cmd = cmd; 37110770Ssam (void) ubago(ui); 37210770Ssam } 37310770Ssam 37410770Ssam rldgo(um) 37510770Ssam register struct uba_ctlr *um; 37610770Ssam { 37710770Ssam register struct rldevice *rladdr = (struct rldevice *)um->um_addr; 37810770Ssam 37910770Ssam rladdr->rlba = um->um_ubinfo; 38010770Ssam rladdr->rlcs = um->um_cmd|((um->um_ubinfo>>12)&RL_BAE); 38110770Ssam } 38210770Ssam 38310770Ssam /* 38410770Ssam * Handle a disk interrupt. 38510770Ssam */ 38610770Ssam rlintr(rl21) 38710770Ssam register rl21; 38810770Ssam { 38910770Ssam register struct buf *bp, *dp; 39010770Ssam register struct uba_ctlr *um = rlminfo[rl21]; 39110770Ssam register struct uba_device *ui; 39210770Ssam register struct rldevice *rladdr = (struct rldevice *)um->um_addr; 39310770Ssam register unit; 39410770Ssam struct rl_softc *rl = &rl_softc[um->um_ctlr]; 39510770Ssam struct rl_stat *st = &rl_stat[um->um_ctlr]; 39613091Ssam int as = rl->rl_softas, status; 39710770Ssam 39810770Ssam rl->rl_wticks = 0; 39910770Ssam rl->rl_softas = 0; 40010770Ssam dp = um->um_tab.b_actf; 40110770Ssam bp = dp->b_actf; 40210770Ssam ui = rldinfo[dkunit(bp)]; 40313091Ssam dk_busy &= ~(1 << ui->ui_dk); 40410770Ssam 40510770Ssam /* 40610770Ssam * Check for and process errors on 40710770Ssam * either the drive or the controller. 40810770Ssam */ 40910770Ssam if (rladdr->rlcs & RL_ERR) { 41010770Ssam u_short err; 41113091Ssam rlwait(rladdr); 41210770Ssam err = rladdr->rlcs; 41310770Ssam /* get staus and reset controller */ 41410770Ssam rladdr->rlda.getstat = RL_GSTAT; 41510770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_GETSTAT; 41610770Ssam rlwait(rladdr); 41710770Ssam status = rladdr->rlmp.getstat; 41810770Ssam /* reset drive */ 41910770Ssam rladdr->rlda.getstat = RL_RESET; 42010770Ssam rladdr->rlcs = (ui->ui_slave <<8) | RL_GETSTAT; /* Get status*/ 42110770Ssam rlwait(rladdr); 42213091Ssam if ((status & RLMP_WL) == RLMP_WL) { 42310770Ssam /* 42410770Ssam * Give up on write protected devices 42510770Ssam * immediately. 42610770Ssam */ 42710770Ssam printf("rl%d: write protected\n", dkunit(bp)); 42810770Ssam bp->b_flags |= B_ERROR; 42910770Ssam } else if (++um->um_tab.b_errcnt > 10) { 43010770Ssam /* 43110770Ssam * After 10 retries give up. 43210770Ssam */ 43310770Ssam harderr(bp, "rl"); 43413091Ssam printf("cs=%b mp=%b\n", err, RLCS_BITS, 43513091Ssam status, RLER_BITS); 43610770Ssam bp->b_flags |= B_ERROR; 43710770Ssam } else 43810770Ssam um->um_tab.b_active = 0; /* force retry */ 43913091Ssam /* determine disk position */ 44010770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_RHDR; 44110770Ssam rlwait(rladdr); 44213091Ssam /* save disk drive position */ 44313091Ssam st->rl_cyl[ui->ui_slave] = 44413091Ssam (rladdr->rlmp.readhdr & 0177700) >> 6; 44510770Ssam } 44610770Ssam /* 44710770Ssam * If still ``active'', then don't need any more retries. 44810770Ssam */ 44910770Ssam if (um->um_tab.b_active) { 45010770Ssam /* RL02 check if more data from previous request */ 45113091Ssam if ((bp->b_flags & B_ERROR) == 0 && 45213091Ssam (int)(st->rl_bleft -= st->rl_bpart) > 0) { 45310770Ssam /* 45413091Ssam * The following code was modeled from the rk07 45510770Ssam * driver when an ECC error occured. It has to 45610770Ssam * fix the bits then restart the transfer which is 45710770Ssam * what we have to do (restart transfer). 45810770Ssam */ 45910770Ssam int reg, npf, o, cmd, ubaddr, diff, head; 46010770Ssam 46110770Ssam /* seek to next head/track */ 46210770Ssam /* increment head and/or cylinder */ 46310770Ssam st->rl_cylnhd++; 46410770Ssam diff = (st->rl_cyl[ui->ui_slave] >> 1) - 46510770Ssam (st->rl_cylnhd >> 1); 46610770Ssam st->rl_cyl[ui->ui_slave] = st->rl_cylnhd; 46710770Ssam head = st->rl_cylnhd & 1; 46813091Ssam rlwait(rladdr); 46913091Ssam if (diff < 0) 47013091Ssam rladdr->rlda.seek = 47113091Ssam -diff << 7 | RLDA_HGH | head << 4; 47210770Ssam else 47313091Ssam rladdr->rlda.seek = 47413091Ssam diff << 7 | RLDA_LOW | head << 4; 47510770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_SEEK; 47610770Ssam npf = btop( bp->b_bcount - st->rl_bleft ); 47710770Ssam reg = btop(um->um_ubinfo&0x3ffff) + npf; 47810770Ssam o = (int)bp->b_un.b_addr & PGOFSET; 47910770Ssam ubapurge(um); 48010770Ssam um->um_tab.b_active++; 48113091Ssam rlwait(rladdr); 48210770Ssam rladdr->rlda.rw = st->rl_cylnhd << 6; 48313091Ssam if (st->rl_bleft < (st->rl_bpart = rl02.btrak)) 48410770Ssam st->rl_bpart = st->rl_bleft; 48510770Ssam rladdr->rlmp.rw = -(st->rl_bpart >> 1); 48610770Ssam cmd = (bp->b_flags&B_READ ? RL_READ : RL_WRITE) | 48713091Ssam RL_IE | (ui->ui_slave << 8); 48810770Ssam ubaddr = (int)ptob(reg) + o; 48910770Ssam cmd |= ((ubaddr >> 12) & RL_BAE); 49010770Ssam rladdr->rlba = ubaddr; 49110770Ssam rladdr->rlcs = cmd; 49210770Ssam return; 49310770Ssam } 49410770Ssam um->um_tab.b_active = 0; 49510770Ssam um->um_tab.b_errcnt = 0; 49610770Ssam dp->b_active = 0; 49710770Ssam dp->b_errcnt = 0; 49810770Ssam /* "b_resid" words remaining after error */ 49910770Ssam bp->b_resid = st->rl_bleft; 50010770Ssam um->um_tab.b_actf = dp->b_forw; 50110770Ssam dp->b_actf = bp->av_forw; 50210770Ssam st->rl_dn = -1; 50310770Ssam st->rl_bpart = st->rl_bleft = 0; 50410770Ssam iodone(bp); 50510770Ssam /* 50610770Ssam * If this unit has more work to do, 50710770Ssam * then start it up right away. 50810770Ssam */ 50910770Ssam if (dp->b_actf) 51013091Ssam rlustart(ui); 51110770Ssam as &= ~(1<<ui->ui_slave); 51210770Ssam } else 51310770Ssam as |= (1<<ui->ui_slave); 51410770Ssam ubadone(um); 51510770Ssam /* reset state info */ 51610770Ssam st->rl_dn = -1; 51710770Ssam st->rl_cylnhd = st->rl_bpart = st->rl_bleft = 0; 51810770Ssam /* 51910770Ssam * Process other units which need attention. 52010770Ssam * For each unit which needs attention, call 52110770Ssam * the unit start routine to place the slave 52210770Ssam * on the controller device queue. 52310770Ssam */ 52410770Ssam while (unit = ffs(as)) { 52510770Ssam unit--; /* was 1 origin */ 52610770Ssam as &= ~(1<<unit); 52713091Ssam rlustart(rlip[rl21][unit]); 52810770Ssam } 52910770Ssam /* 53010770Ssam * If the controller is not transferring, but 53110770Ssam * there are devices ready to transfer, start 53210770Ssam * the controller. 53310770Ssam */ 53410770Ssam if (um->um_tab.b_actf && um->um_tab.b_active == 0) 53513091Ssam rlstart(um); 53610770Ssam } 53710770Ssam 53812452Ssam rlwait(rladdr) 53912452Ssam register struct rldevice *rladdr; 54010770Ssam { 54112452Ssam 54210770Ssam while ((rladdr->rlcs & RL_CRDY) == 0) 54313091Ssam ; 54410770Ssam } 54510770Ssam 54612452Ssam rlread(dev, uio) 54710770Ssam dev_t dev; 54812452Ssam struct uio *uio; 54910770Ssam { 55010770Ssam register int unit = minor(dev) >> 3; 55110770Ssam 55210770Ssam if (unit >= NRL) 55312452Ssam return (ENXIO); 55412452Ssam return (physio(rlstrategy, &rrlbuf[unit], dev, B_READ, minphys, uio)); 55510770Ssam } 55610770Ssam 55712452Ssam rlwrite(dev, uio) 55810770Ssam dev_t dev; 55912452Ssam struct uio *uio; 56010770Ssam { 56110770Ssam register int unit = minor(dev) >> 3; 56210770Ssam 56310770Ssam if (unit >= NRL) 56412452Ssam return (ENXIO); 56512452Ssam return (physio(rlstrategy, &rrlbuf[unit], dev, B_WRITE, minphys, uio)); 56610770Ssam } 56710770Ssam 56810770Ssam /* 56910770Ssam * Reset driver after UBA init. 57010770Ssam * Cancel software state of all pending transfers 57110770Ssam * and restart all units and the controller. 57210770Ssam */ 57310770Ssam rlreset(uban) 57410770Ssam int uban; 57510770Ssam { 57610770Ssam register struct uba_ctlr *um; 57710770Ssam register struct uba_device *ui; 57810770Ssam register struct rldevice *rladdr; 57910770Ssam register struct rl_stat *st; 58013091Ssam register int rl21, unit; 58110770Ssam 58210770Ssam for (rl21 = 0; rl21 < NHL; rl21++) { 58310770Ssam if ((um = rlminfo[rl21]) == 0 || um->um_ubanum != uban || 58410770Ssam um->um_alive == 0) 58510770Ssam continue; 58613091Ssam printf(" hl%d", rl21); 58710770Ssam rladdr = (struct rldevice *)um->um_addr; 58810770Ssam st = &rl_stat[rl21]; 58910770Ssam um->um_tab.b_active = 0; 59010770Ssam um->um_tab.b_actf = um->um_tab.b_actl = 0; 59110770Ssam if (um->um_ubinfo) { 59210770Ssam printf("<%d>", (um->um_ubinfo>>28)&0xf); 59312452Ssam um->um_ubinfo = 0; 59410770Ssam } 59510770Ssam /* reset controller */ 59610770Ssam st->rl_dn = -1; 59710770Ssam st->rl_cylnhd = 0; 59810770Ssam st->rl_bleft = 0; 59910770Ssam st->rl_bpart = 0; 60012452Ssam rlwait(rladdr); 60110770Ssam for (unit = 0; unit < NRL; unit++) { 60210770Ssam rladdr->rlcs = (unit << 8) | RL_GETSTAT; 60312452Ssam rlwait(rladdr); 60410770Ssam /* Determine disk posistion */ 60510770Ssam rladdr->rlcs = (unit << 8) | RL_RHDR; 60610770Ssam rlwait(rladdr); 60710770Ssam /* save disk drive posistion */ 60810770Ssam st->rl_cyl[unit] = 60910770Ssam (rladdr->rlmp.readhdr & 0177700) >> 6; 61010770Ssam if ((ui = rldinfo[unit]) == 0) 61110770Ssam continue; 61210770Ssam if (ui->ui_alive == 0 || ui->ui_mi != um) 61310770Ssam continue; 61410770Ssam rlutab[unit].b_active = 0; 61513091Ssam rlustart(ui); 61610770Ssam } 61713091Ssam rlstart(um); 61810770Ssam } 61910770Ssam } 62010770Ssam 62110770Ssam /* 62210770Ssam * Wake up every second and if an interrupt is pending 62310770Ssam * but nothing has happened increment a counter. 62410770Ssam * If nothing happens for 20 seconds, reset the UNIBUS 62510770Ssam * and begin anew. 62610770Ssam */ 62710770Ssam rlwatch() 62810770Ssam { 62910770Ssam register struct uba_ctlr *um; 63010770Ssam register rl21, unit; 63110770Ssam register struct rl_softc *rl; 63210770Ssam 63310770Ssam timeout(rlwatch, (caddr_t)0, hz); 63410770Ssam for (rl21 = 0; rl21 < NHL; rl21++) { 63510770Ssam um = rlminfo[rl21]; 63610770Ssam if (um == 0 || um->um_alive == 0) 63710770Ssam continue; 63810770Ssam rl = &rl_softc[rl21]; 63910770Ssam if (um->um_tab.b_active == 0) { 64010770Ssam for (unit = 0; unit < NRL; unit++) 64110770Ssam if (rlutab[unit].b_active && 64210770Ssam rldinfo[unit]->ui_mi == um) 64310770Ssam goto active; 64410770Ssam rl->rl_wticks = 0; 64510770Ssam continue; 64610770Ssam } 64710770Ssam active: 64810770Ssam rl->rl_wticks++; 64910770Ssam if (rl->rl_wticks >= 20) { 65010770Ssam rl->rl_wticks = 0; 65110770Ssam printf("hl%d: lost interrupt\n", rl21); 65210770Ssam ubareset(um->um_ubanum); 65310770Ssam } 65410770Ssam } 65510770Ssam } 65610770Ssam 65713091Ssam /*ARGSUSED*/ 65810770Ssam rldump(dev) 65910770Ssam dev_t dev; 66010770Ssam { 66113091Ssam 66210770Ssam /* don't think there is room on swap for it anyway. */ 66310770Ssam } 66413272Ssam 66513272Ssam rlsize(dev) 66613272Ssam dev_t dev; 66713272Ssam { 66813272Ssam register int unit = minor(dev) >> 3; 66913272Ssam register struct uba_device *ui; 67013272Ssam 67113272Ssam if (unit >= NRL || (ui = rldinfo[unit]) == 0 || ui->ui_alive == 0) 67213272Ssam return (-1); 67313272Ssam return (rl02.sizes[minor(dev) & 07].nblocks); 67413272Ssam } 67512504Ssam #endif 676