1*17431Skarels /* rl.c 6.3 84/11/27 */ 210770Ssam 310770Ssam #include "rl.h" 412452Ssam #if NRL > 0 510770Ssam /* 610770Ssam * UNIBUS RL02 disk driver 710770Ssam */ 813091Ssam #include "../machine/pte.h" 910770Ssam 1017077Sbloom #include "param.h" 1117077Sbloom #include "systm.h" 1217077Sbloom #include "dk.h" 1317077Sbloom #include "dkbad.h" 1417077Sbloom #include "buf.h" 1517077Sbloom #include "conf.h" 1617077Sbloom #include "dir.h" 1717077Sbloom #include "user.h" 1817077Sbloom #include "map.h" 1917077Sbloom #include "vm.h" 2017077Sbloom #include "cmap.h" 2117077Sbloom #include "uio.h" 2217077Sbloom #include "kernel.h" 2310770Ssam 2413091Ssam #include "../vax/cpu.h" 2513091Ssam #include "../vax/nexus.h" 2617077Sbloom #include "ubavar.h" 2717077Sbloom #include "ubareg.h" 2817077Sbloom #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 */ 60*17431Skarels 0, 0, /* E= Not Defined */ 6110770Ssam 0, 0, /* F= Not Defined */ 6213091Ssam 20440, 0, /* G=cyl 0 thru 510 */ 6310770Ssam 0, 0, /* H= Not Defined */ 6410770Ssam }; 6510770Ssam /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 6610770Ssam 6710770Ssam int rlprobe(), rlslave(), rlattach(), rldgo(), rlintr(); 6810770Ssam struct uba_ctlr *rlminfo[NHL]; 6910770Ssam struct uba_device *rldinfo[NRL]; 7010770Ssam struct uba_device *rlip[NHL][4]; 7110770Ssam 7210770Ssam /* RL02 driver structure */ 73*17431Skarels u_short rlstd[] = { 0174400, 0 }; 7410770Ssam struct uba_driver hldriver = 7510770Ssam { rlprobe, rlslave, rlattach, rldgo, rlstd, "rl", rldinfo, "hl", rlminfo }; 7610770Ssam 7710770Ssam /* User table per controller */ 7810770Ssam struct buf rlutab[NRL]; 7910770Ssam 8010770Ssam /* RL02 drive structure */ 8110770Ssam struct RL02 { 8210770Ssam short nbpt; /* Number of 512 byte blocks/track */ 8310770Ssam short ntrak; 8410770Ssam short nbpc; /* Number of 512 byte blocks/cylinder */ 8510770Ssam short ncyl; 8610770Ssam short btrak; /* Number of bytes/track */ 8710770Ssam struct size *sizes; 8810770Ssam } rl02 = { 8910770Ssam 20, 2, 40, 512, 20*512, rl02_sizes /* rl02/DEC*/ 9010770Ssam }; 9110770Ssam 9210770Ssam struct buf rrlbuf[NRL]; 9310770Ssam 9410770Ssam #define b_cylin b_resid /* Last seek as CYL<<1 | HD */ 9510770Ssam 9610770Ssam #ifdef INTRLVE 9710770Ssam daddr_t dkblock(); 9810770Ssam #endif 9910770Ssam 10010770Ssam int rlwstart, rlwatch(); /* Have started guardian */ 10110770Ssam 10210770Ssam /* Check that controller exists */ 10310770Ssam /*ARGSUSED*/ 10410770Ssam rlprobe(reg) 10510770Ssam caddr_t reg; 10610770Ssam { 10710770Ssam register int br, cvec; 10810770Ssam 10910770Ssam #ifdef lint 11010770Ssam br = 0; cvec = br; br = cvec; 11113091Ssam rlintr(0); 11210770Ssam #endif 11313091Ssam ((struct rldevice *)reg)->rlcs = RL_IE | RL_NOOP; 11413091Ssam DELAY(10); 11513091Ssam ((struct rldevice *)reg)->rlcs &= ~RL_IE; 11612452Ssam return (sizeof (struct rldevice)); 11710770Ssam } 11810770Ssam 11910770Ssam rlslave(ui, reg) 12010770Ssam struct uba_device *ui; 12110770Ssam caddr_t reg; 12210770Ssam { 12310770Ssam register struct rldevice *rladdr = (struct rldevice *)reg; 12410770Ssam short ctr = 0; 12510770Ssam 12610770Ssam /* 12710770Ssam * DEC reports that: 12810770Ssam * For some unknown reason the RL02 (seems to be only drive 1) 12910770Ssam * does not return a valid drive status the first time that a 13010770Ssam * GET STATUS request is issued for the drive, in fact it can 13110770Ssam * take up to three or more GET STATUS requests to obtain the 13210770Ssam * correct status. 13310770Ssam * In order to overcome this, the driver has been modified to 13410770Ssam * issue a GET STATUS request and validate the drive status 13510770Ssam * returned. If a valid status is not returned after eight 13610770Ssam * attempts, then an error message is printed. 13710770Ssam */ 13810770Ssam do { 13910770Ssam rladdr->rlda.getstat = RL_RESET; 14010770Ssam rladdr->rlcs = (ui->ui_slave <<8) | RL_GETSTAT; /* Get status*/ 14110770Ssam rlwait(rladdr); 142*17431Skarels } while ((rladdr->rlcs & (RL_CRDY|RL_ERR)) != RL_CRDY && ++ctr < 8); 143*17431Skarels 14410770Ssam if ((rladdr->rlcs & RL_DE) || (ctr >= 8)) 145*17431Skarels return (0); 14613091Ssam if ((rladdr->rlmp.getstat & RLMP_DT) == 0 ) { 14713091Ssam printf("rl%d: rl01's not supported\n", ui->ui_slave); 14810770Ssam return(0); 14910770Ssam } 15010770Ssam return (1); 15110770Ssam } 15210770Ssam 15310770Ssam rlattach(ui) 15410770Ssam register struct uba_device *ui; 15510770Ssam { 15610770Ssam register struct rldevice *rladdr; 15710770Ssam 15810770Ssam if (rlwstart == 0) { 15913091Ssam timeout(rlwatch, (caddr_t)0, hz); 16010770Ssam rlwstart++; 16110770Ssam } 16210770Ssam /* Initialize iostat values */ 16310770Ssam if (ui->ui_dk >= 0) 16410770Ssam dk_mspw[ui->ui_dk] = .000003906; /* 16bit transfer time? */ 16510770Ssam rlip[ui->ui_ctlr][ui->ui_slave] = ui; 16613091Ssam rl_softc[ui->ui_ctlr].rl_ndrive++; 16710770Ssam rladdr = (struct rldevice *)ui->ui_addr; 16810770Ssam /* reset controller */ 16910770Ssam rladdr->rlda.getstat = RL_RESET; /* SHOULD BE REPEATED? */ 17010770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_GETSTAT; /* Reset DE bit */ 17110770Ssam rlwait(rladdr); 17213091Ssam /* determine disk posistion */ 17310770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_RHDR; 17410770Ssam rlwait(rladdr); 17510770Ssam /* save disk drive posistion */ 17610770Ssam rl_stat[ui->ui_ctlr].rl_cyl[ui->ui_slave] = 17713091Ssam (rladdr->rlmp.readhdr & 0177700) >> 6; 17810770Ssam rl_stat[ui->ui_ctlr].rl_dn = -1; 17910770Ssam } 18010770Ssam 18112452Ssam rlopen(dev) 18212452Ssam dev_t dev; 18312452Ssam { 18412452Ssam register int unit = minor(dev) >> 3; 18513091Ssam register struct uba_device *ui; 18612452Ssam 18712452Ssam if (unit >= NRL || (ui = rldinfo[unit]) == 0 || ui->ui_alive == 0) 18812452Ssam return (ENXIO); 18912452Ssam return (0); 19012452Ssam } 19112452Ssam 19210770Ssam rlstrategy(bp) 19310770Ssam register struct buf *bp; 19410770Ssam { 19510770Ssam register struct uba_device *ui; 19610770Ssam register int drive; 19710770Ssam register struct buf *dp; 19813091Ssam int partition = minor(bp->b_dev) & 07, s; 19910770Ssam long bn, sz; 20010770Ssam 20113091Ssam sz = (bp->b_bcount+511) >> 9; 20213091Ssam drive = dkunit(bp); 20310770Ssam if (drive >= NRL) 20410770Ssam goto bad; 20513091Ssam ui = rldinfo[drive]; 20610770Ssam if (ui == 0 || ui->ui_alive == 0) 20710770Ssam goto bad; 20810770Ssam if (bp->b_blkno < 0 || 20910770Ssam (bn = dkblock(bp))+sz > rl02.sizes[partition].nblocks) 21010770Ssam goto bad; 21110770Ssam /* bn is in 512 byte block size */ 21210770Ssam bp->b_cylin = bn/rl02.nbpc + rl02.sizes[partition].cyloff; 21313091Ssam s = spl5(); 21410770Ssam dp = &rlutab[ui->ui_unit]; 21510770Ssam disksort(dp, bp); 21610770Ssam if (dp->b_active == 0) { 21713091Ssam rlustart(ui); 21810770Ssam bp = &ui->ui_mi->um_tab; 21910770Ssam if (bp->b_actf && bp->b_active == 0) 22013091Ssam rlstart(ui->ui_mi); 22110770Ssam } 22213091Ssam splx(s); 22310770Ssam return; 22410770Ssam 22510770Ssam bad: 22610770Ssam bp->b_flags |= B_ERROR; 22710770Ssam iodone(bp); 22810770Ssam return; 22910770Ssam } 23010770Ssam 23110770Ssam /* 23210770Ssam * Unit start routine. 23310770Ssam * Seek the drive to be where the data is 23410770Ssam * and then generate another interrupt 23510770Ssam * to actually start the transfer. 23610770Ssam */ 23710770Ssam rlustart(ui) 23810770Ssam register struct uba_device *ui; 23910770Ssam { 24010770Ssam register struct buf *bp, *dp; 24110770Ssam register struct uba_ctlr *um; 24210770Ssam register struct rldevice *rladdr; 24310770Ssam daddr_t bn; 24413091Ssam short hd, diff; 24510770Ssam 24610770Ssam if (ui == 0) 24713091Ssam return; 24810770Ssam um = ui->ui_mi; 24913091Ssam dk_busy &= ~(1 << ui->ui_dk); 25010770Ssam dp = &rlutab[ui->ui_unit]; 25110770Ssam if ((bp = dp->b_actf) == NULL) 25213091Ssam return; 25310770Ssam /* 25410770Ssam * If the controller is active, just remember 25510770Ssam * that this device has to be positioned... 25610770Ssam */ 25710770Ssam if (um->um_tab.b_active) { 25810770Ssam rl_softc[um->um_ctlr].rl_softas |= 1<<ui->ui_slave; 25913091Ssam return; 26010770Ssam } 26110770Ssam /* 26210770Ssam * If we have already positioned this drive, 26310770Ssam * then just put it on the ready queue. 26410770Ssam */ 26510770Ssam if (dp->b_active) 26610770Ssam goto done; 26713091Ssam dp->b_active = 1; /* positioning drive */ 26810770Ssam rladdr = (struct rldevice *)um->um_addr; 26910770Ssam 27010770Ssam /* 27110770Ssam * Figure out where this transfer is going to 27210770Ssam * and see if we are seeked correctly. 27310770Ssam */ 27410770Ssam bn = dkblock(bp); /* Block # desired */ 27510770Ssam /* 27613091Ssam * Map 512 byte logical disk blocks 27713091Ssam * to 256 byte sectors (rl02's are stupid). 27810770Ssam */ 27910770Ssam hd = (bn / rl02.nbpt) & 1; /* Get head required */ 28010770Ssam diff = (rl_stat[um->um_ctlr].rl_cyl[ui->ui_slave] >> 1) - bp->b_cylin; 28110770Ssam if ( diff == 0 && (rl_stat[um->um_ctlr].rl_cyl[ui->ui_slave] & 1) == hd) 28210770Ssam goto done; /* on cylinder and head */ 28310770Ssam /* 28410770Ssam * Not at correct position. 28510770Ssam */ 28610770Ssam rl_stat[um->um_ctlr].rl_cyl[ui->ui_slave] = (bp->b_cylin << 1) | hd; 28710770Ssam if (diff < 0) 28810770Ssam rladdr->rlda.seek = -diff << 7 | RLDA_HGH | hd << 4; 28910770Ssam else 29010770Ssam rladdr->rlda.seek = diff << 7 | RLDA_LOW | hd << 4; 29110770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_SEEK; 29210770Ssam 29310770Ssam /* 29410770Ssam * Mark unit busy for iostat. 29510770Ssam */ 29610770Ssam if (ui->ui_dk >= 0) { 29710770Ssam dk_busy |= 1<<ui->ui_dk; 29810770Ssam dk_seek[ui->ui_dk]++; 29910770Ssam } 30012452Ssam rlwait(rladdr); 30110770Ssam done: 30210770Ssam /* 30310770Ssam * Device is ready to go. 30410770Ssam * Put it on the ready queue for the controller 30510770Ssam * (unless its already there.) 30610770Ssam */ 30710770Ssam if (dp->b_active != 2) { 30810770Ssam dp->b_forw = NULL; 30910770Ssam if (um->um_tab.b_actf == NULL) 31010770Ssam um->um_tab.b_actf = dp; 31110770Ssam else 31210770Ssam um->um_tab.b_actl->b_forw = dp; 31310770Ssam um->um_tab.b_actl = dp; 31410770Ssam dp->b_active = 2; /* Request on ready queue */ 31510770Ssam } 31610770Ssam } 31710770Ssam 31810770Ssam /* 31910770Ssam * Start up a transfer on a drive. 32010770Ssam */ 32110770Ssam rlstart(um) 32210770Ssam register struct uba_ctlr *um; 32310770Ssam { 32410770Ssam register struct buf *bp, *dp; 32510770Ssam register struct uba_device *ui; 32610770Ssam register struct rldevice *rladdr; 32710770Ssam register struct rl_stat *st = &rl_stat[um->um_ctlr]; 32810770Ssam daddr_t bn; 32910770Ssam short sn, cyl, cmd; 33010770Ssam 33110770Ssam loop: 33210770Ssam if ((dp = um->um_tab.b_actf) == NULL) { 33310770Ssam st->rl_dn = -1; 33410770Ssam st->rl_cylnhd = 0; 33510770Ssam st->rl_bleft = 0; 33610770Ssam st->rl_bpart = 0; 33713091Ssam return; 33810770Ssam } 33910770Ssam if ((bp = dp->b_actf) == NULL) { 34010770Ssam um->um_tab.b_actf = dp->b_forw; 34110770Ssam goto loop; 34210770Ssam } 34310770Ssam /* 34410770Ssam * Mark controller busy, and 34513091Ssam * determine destination. 34610770Ssam */ 34710770Ssam um->um_tab.b_active++; 34810770Ssam ui = rldinfo[dkunit(bp)]; /* Controller */ 34910770Ssam bn = dkblock(bp); /* 512 byte Block number */ 35010770Ssam cyl = bp->b_cylin << 1; /* Cylinder */ 35110770Ssam cyl |= (bn / rl02.nbpt) & 1; /* Get head required */ 35210770Ssam sn = (bn % rl02.nbpt) << 1; /* Sector number */ 35310770Ssam rladdr = (struct rldevice *)ui->ui_addr; 35412452Ssam rlwait(rladdr); 35510770Ssam rladdr->rlda.rw = cyl<<6 | sn; 35610770Ssam /* save away current transfers drive status */ 35710770Ssam st->rl_dn = ui->ui_slave; 35810770Ssam st->rl_cylnhd = cyl; 35910770Ssam st->rl_bleft = bp->b_bcount; 36010770Ssam st->rl_bpart = rl02.btrak - (sn * NRLBPSC); 36113091Ssam /* 36213091Ssam * RL02 must seek between cylinders and between tracks, 36313091Ssam * determine maximum data transfer at this time. 36413091Ssam */ 36513091Ssam if (st->rl_bleft < st->rl_bpart) 36610770Ssam st->rl_bpart = st->rl_bleft; 36710770Ssam rladdr->rlmp.rw = -(st->rl_bpart >> 1); 36810770Ssam if (bp->b_flags & B_READ) 36910770Ssam cmd = RL_IE | RL_READ | (ui->ui_slave << 8); 37010770Ssam else 37110770Ssam cmd = RL_IE | RL_WRITE | (ui->ui_slave << 8); 37210770Ssam um->um_cmd = cmd; 37310770Ssam (void) ubago(ui); 37410770Ssam } 37510770Ssam 37610770Ssam rldgo(um) 37710770Ssam register struct uba_ctlr *um; 37810770Ssam { 37910770Ssam register struct rldevice *rladdr = (struct rldevice *)um->um_addr; 38010770Ssam 38110770Ssam rladdr->rlba = um->um_ubinfo; 38210770Ssam rladdr->rlcs = um->um_cmd|((um->um_ubinfo>>12)&RL_BAE); 38310770Ssam } 38410770Ssam 38510770Ssam /* 38610770Ssam * Handle a disk interrupt. 38710770Ssam */ 38810770Ssam rlintr(rl21) 38910770Ssam register rl21; 39010770Ssam { 39110770Ssam register struct buf *bp, *dp; 39210770Ssam register struct uba_ctlr *um = rlminfo[rl21]; 39310770Ssam register struct uba_device *ui; 39410770Ssam register struct rldevice *rladdr = (struct rldevice *)um->um_addr; 39510770Ssam register unit; 39610770Ssam struct rl_softc *rl = &rl_softc[um->um_ctlr]; 39710770Ssam struct rl_stat *st = &rl_stat[um->um_ctlr]; 39813091Ssam int as = rl->rl_softas, status; 39910770Ssam 40010770Ssam rl->rl_wticks = 0; 40110770Ssam rl->rl_softas = 0; 40210770Ssam dp = um->um_tab.b_actf; 40310770Ssam bp = dp->b_actf; 40410770Ssam ui = rldinfo[dkunit(bp)]; 40513091Ssam dk_busy &= ~(1 << ui->ui_dk); 40610770Ssam 40710770Ssam /* 40810770Ssam * Check for and process errors on 40910770Ssam * either the drive or the controller. 41010770Ssam */ 41110770Ssam if (rladdr->rlcs & RL_ERR) { 41210770Ssam u_short err; 41313091Ssam rlwait(rladdr); 41410770Ssam err = rladdr->rlcs; 41510770Ssam /* get staus and reset controller */ 41610770Ssam rladdr->rlda.getstat = RL_GSTAT; 41710770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_GETSTAT; 41810770Ssam rlwait(rladdr); 41910770Ssam status = rladdr->rlmp.getstat; 42010770Ssam /* reset drive */ 42110770Ssam rladdr->rlda.getstat = RL_RESET; 42210770Ssam rladdr->rlcs = (ui->ui_slave <<8) | RL_GETSTAT; /* Get status*/ 42310770Ssam rlwait(rladdr); 42413091Ssam if ((status & RLMP_WL) == RLMP_WL) { 42510770Ssam /* 42610770Ssam * Give up on write protected devices 42710770Ssam * immediately. 42810770Ssam */ 42910770Ssam printf("rl%d: write protected\n", dkunit(bp)); 43010770Ssam bp->b_flags |= B_ERROR; 43110770Ssam } else if (++um->um_tab.b_errcnt > 10) { 43210770Ssam /* 43310770Ssam * After 10 retries give up. 43410770Ssam */ 43510770Ssam harderr(bp, "rl"); 43613091Ssam printf("cs=%b mp=%b\n", err, RLCS_BITS, 43713091Ssam status, RLER_BITS); 43810770Ssam bp->b_flags |= B_ERROR; 43910770Ssam } else 44010770Ssam um->um_tab.b_active = 0; /* force retry */ 44113091Ssam /* determine disk position */ 44210770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_RHDR; 44310770Ssam rlwait(rladdr); 44413091Ssam /* save disk drive position */ 44513091Ssam st->rl_cyl[ui->ui_slave] = 44613091Ssam (rladdr->rlmp.readhdr & 0177700) >> 6; 44710770Ssam } 44810770Ssam /* 44910770Ssam * If still ``active'', then don't need any more retries. 45010770Ssam */ 45110770Ssam if (um->um_tab.b_active) { 45210770Ssam /* RL02 check if more data from previous request */ 45313091Ssam if ((bp->b_flags & B_ERROR) == 0 && 45413091Ssam (int)(st->rl_bleft -= st->rl_bpart) > 0) { 45510770Ssam /* 45613091Ssam * The following code was modeled from the rk07 45710770Ssam * driver when an ECC error occured. It has to 45810770Ssam * fix the bits then restart the transfer which is 45910770Ssam * what we have to do (restart transfer). 46010770Ssam */ 46110770Ssam int reg, npf, o, cmd, ubaddr, diff, head; 46210770Ssam 46310770Ssam /* seek to next head/track */ 46410770Ssam /* increment head and/or cylinder */ 46510770Ssam st->rl_cylnhd++; 46610770Ssam diff = (st->rl_cyl[ui->ui_slave] >> 1) - 46710770Ssam (st->rl_cylnhd >> 1); 46810770Ssam st->rl_cyl[ui->ui_slave] = st->rl_cylnhd; 46910770Ssam head = st->rl_cylnhd & 1; 47013091Ssam rlwait(rladdr); 47113091Ssam if (diff < 0) 47213091Ssam rladdr->rlda.seek = 47313091Ssam -diff << 7 | RLDA_HGH | head << 4; 47410770Ssam else 47513091Ssam rladdr->rlda.seek = 47613091Ssam diff << 7 | RLDA_LOW | head << 4; 47710770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_SEEK; 47810770Ssam npf = btop( bp->b_bcount - st->rl_bleft ); 47910770Ssam reg = btop(um->um_ubinfo&0x3ffff) + npf; 48010770Ssam o = (int)bp->b_un.b_addr & PGOFSET; 48110770Ssam ubapurge(um); 48210770Ssam um->um_tab.b_active++; 48313091Ssam rlwait(rladdr); 48410770Ssam rladdr->rlda.rw = st->rl_cylnhd << 6; 48513091Ssam if (st->rl_bleft < (st->rl_bpart = rl02.btrak)) 48610770Ssam st->rl_bpart = st->rl_bleft; 48710770Ssam rladdr->rlmp.rw = -(st->rl_bpart >> 1); 48810770Ssam cmd = (bp->b_flags&B_READ ? RL_READ : RL_WRITE) | 48913091Ssam RL_IE | (ui->ui_slave << 8); 49010770Ssam ubaddr = (int)ptob(reg) + o; 49110770Ssam cmd |= ((ubaddr >> 12) & RL_BAE); 49210770Ssam rladdr->rlba = ubaddr; 49310770Ssam rladdr->rlcs = cmd; 49410770Ssam return; 49510770Ssam } 49610770Ssam um->um_tab.b_active = 0; 49710770Ssam um->um_tab.b_errcnt = 0; 49810770Ssam dp->b_active = 0; 49910770Ssam dp->b_errcnt = 0; 50010770Ssam /* "b_resid" words remaining after error */ 50110770Ssam bp->b_resid = st->rl_bleft; 50210770Ssam um->um_tab.b_actf = dp->b_forw; 50310770Ssam dp->b_actf = bp->av_forw; 50410770Ssam st->rl_dn = -1; 50510770Ssam st->rl_bpart = st->rl_bleft = 0; 50610770Ssam iodone(bp); 50710770Ssam /* 50810770Ssam * If this unit has more work to do, 50910770Ssam * then start it up right away. 51010770Ssam */ 51110770Ssam if (dp->b_actf) 51213091Ssam rlustart(ui); 51310770Ssam as &= ~(1<<ui->ui_slave); 51410770Ssam } else 51510770Ssam as |= (1<<ui->ui_slave); 51610770Ssam ubadone(um); 51710770Ssam /* reset state info */ 51810770Ssam st->rl_dn = -1; 51910770Ssam st->rl_cylnhd = st->rl_bpart = st->rl_bleft = 0; 52010770Ssam /* 52110770Ssam * Process other units which need attention. 52210770Ssam * For each unit which needs attention, call 52310770Ssam * the unit start routine to place the slave 52410770Ssam * on the controller device queue. 52510770Ssam */ 52610770Ssam while (unit = ffs(as)) { 52710770Ssam unit--; /* was 1 origin */ 52810770Ssam as &= ~(1<<unit); 52913091Ssam rlustart(rlip[rl21][unit]); 53010770Ssam } 53110770Ssam /* 53210770Ssam * If the controller is not transferring, but 53310770Ssam * there are devices ready to transfer, start 53410770Ssam * the controller. 53510770Ssam */ 53610770Ssam if (um->um_tab.b_actf && um->um_tab.b_active == 0) 53713091Ssam rlstart(um); 53810770Ssam } 53910770Ssam 54012452Ssam rlwait(rladdr) 54112452Ssam register struct rldevice *rladdr; 54210770Ssam { 54312452Ssam 54410770Ssam while ((rladdr->rlcs & RL_CRDY) == 0) 54513091Ssam ; 54610770Ssam } 54710770Ssam 54812452Ssam rlread(dev, uio) 54910770Ssam dev_t dev; 55012452Ssam struct uio *uio; 55110770Ssam { 55210770Ssam register int unit = minor(dev) >> 3; 55310770Ssam 55410770Ssam if (unit >= NRL) 55512452Ssam return (ENXIO); 55612452Ssam return (physio(rlstrategy, &rrlbuf[unit], dev, B_READ, minphys, uio)); 55710770Ssam } 55810770Ssam 55912452Ssam rlwrite(dev, uio) 56010770Ssam dev_t dev; 56112452Ssam struct uio *uio; 56210770Ssam { 56310770Ssam register int unit = minor(dev) >> 3; 56410770Ssam 56510770Ssam if (unit >= NRL) 56612452Ssam return (ENXIO); 56712452Ssam return (physio(rlstrategy, &rrlbuf[unit], dev, B_WRITE, minphys, uio)); 56810770Ssam } 56910770Ssam 57010770Ssam /* 57110770Ssam * Reset driver after UBA init. 57210770Ssam * Cancel software state of all pending transfers 57310770Ssam * and restart all units and the controller. 57410770Ssam */ 57510770Ssam rlreset(uban) 57610770Ssam int uban; 57710770Ssam { 57810770Ssam register struct uba_ctlr *um; 57910770Ssam register struct uba_device *ui; 58010770Ssam register struct rldevice *rladdr; 58110770Ssam register struct rl_stat *st; 58213091Ssam register int rl21, unit; 58310770Ssam 58410770Ssam for (rl21 = 0; rl21 < NHL; rl21++) { 58510770Ssam if ((um = rlminfo[rl21]) == 0 || um->um_ubanum != uban || 58610770Ssam um->um_alive == 0) 58710770Ssam continue; 58813091Ssam printf(" hl%d", rl21); 58910770Ssam rladdr = (struct rldevice *)um->um_addr; 59010770Ssam st = &rl_stat[rl21]; 59110770Ssam um->um_tab.b_active = 0; 59210770Ssam um->um_tab.b_actf = um->um_tab.b_actl = 0; 59310770Ssam if (um->um_ubinfo) { 59410770Ssam printf("<%d>", (um->um_ubinfo>>28)&0xf); 59512452Ssam um->um_ubinfo = 0; 59610770Ssam } 59710770Ssam /* reset controller */ 59810770Ssam st->rl_dn = -1; 59910770Ssam st->rl_cylnhd = 0; 60010770Ssam st->rl_bleft = 0; 60110770Ssam st->rl_bpart = 0; 60212452Ssam rlwait(rladdr); 60310770Ssam for (unit = 0; unit < NRL; unit++) { 60410770Ssam rladdr->rlcs = (unit << 8) | RL_GETSTAT; 60512452Ssam rlwait(rladdr); 60610770Ssam /* Determine disk posistion */ 60710770Ssam rladdr->rlcs = (unit << 8) | RL_RHDR; 60810770Ssam rlwait(rladdr); 60910770Ssam /* save disk drive posistion */ 61010770Ssam st->rl_cyl[unit] = 61110770Ssam (rladdr->rlmp.readhdr & 0177700) >> 6; 61210770Ssam if ((ui = rldinfo[unit]) == 0) 61310770Ssam continue; 61410770Ssam if (ui->ui_alive == 0 || ui->ui_mi != um) 61510770Ssam continue; 61610770Ssam rlutab[unit].b_active = 0; 61713091Ssam rlustart(ui); 61810770Ssam } 61913091Ssam rlstart(um); 62010770Ssam } 62110770Ssam } 62210770Ssam 62310770Ssam /* 62410770Ssam * Wake up every second and if an interrupt is pending 62510770Ssam * but nothing has happened increment a counter. 62610770Ssam * If nothing happens for 20 seconds, reset the UNIBUS 62710770Ssam * and begin anew. 62810770Ssam */ 62910770Ssam rlwatch() 63010770Ssam { 63110770Ssam register struct uba_ctlr *um; 63210770Ssam register rl21, unit; 63310770Ssam register struct rl_softc *rl; 63410770Ssam 63510770Ssam timeout(rlwatch, (caddr_t)0, hz); 63610770Ssam for (rl21 = 0; rl21 < NHL; rl21++) { 63710770Ssam um = rlminfo[rl21]; 63810770Ssam if (um == 0 || um->um_alive == 0) 63910770Ssam continue; 64010770Ssam rl = &rl_softc[rl21]; 64110770Ssam if (um->um_tab.b_active == 0) { 64210770Ssam for (unit = 0; unit < NRL; unit++) 64310770Ssam if (rlutab[unit].b_active && 64410770Ssam rldinfo[unit]->ui_mi == um) 64510770Ssam goto active; 64610770Ssam rl->rl_wticks = 0; 64710770Ssam continue; 64810770Ssam } 64910770Ssam active: 65010770Ssam rl->rl_wticks++; 65110770Ssam if (rl->rl_wticks >= 20) { 65210770Ssam rl->rl_wticks = 0; 65310770Ssam printf("hl%d: lost interrupt\n", rl21); 65410770Ssam ubareset(um->um_ubanum); 65510770Ssam } 65610770Ssam } 65710770Ssam } 65810770Ssam 65913091Ssam /*ARGSUSED*/ 66010770Ssam rldump(dev) 66110770Ssam dev_t dev; 66210770Ssam { 66313091Ssam 66410770Ssam /* don't think there is room on swap for it anyway. */ 66510770Ssam } 66613272Ssam 66713272Ssam rlsize(dev) 66813272Ssam dev_t dev; 66913272Ssam { 67013272Ssam register int unit = minor(dev) >> 3; 67113272Ssam register struct uba_device *ui; 67213272Ssam 67313272Ssam if (unit >= NRL || (ui = rldinfo[unit]) == 0 || ui->ui_alive == 0) 67413272Ssam return (-1); 67513272Ssam return (rl02.sizes[minor(dev) & 07].nblocks); 67613272Ssam } 67712504Ssam #endif 678