123338Smckusick /* 229238Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 323338Smckusick * All rights reserved. The Berkeley software License Agreement 423338Smckusick * specifies the terms and conditions for redistribution. 523338Smckusick * 6*38175Smckusick * @(#)rl.c 7.8 (Berkeley) 05/29/89 723338Smckusick */ 810770Ssam 910770Ssam #include "rl.h" 1012452Ssam #if NRL > 0 1110770Ssam /* 1210770Ssam * UNIBUS RL02 disk driver 1310770Ssam */ 1437511Smckusick #include "machine/pte.h" 1510770Ssam 1617077Sbloom #include "param.h" 1717077Sbloom #include "systm.h" 1830388Skarels #include "dkstat.h" 1917077Sbloom #include "dkbad.h" 2034524Skarels #include "ioctl.h" 2134524Skarels #include "disklabel.h" 2217077Sbloom #include "buf.h" 2317077Sbloom #include "conf.h" 2417077Sbloom #include "dir.h" 2517077Sbloom #include "user.h" 2617077Sbloom #include "map.h" 2717077Sbloom #include "vm.h" 2817077Sbloom #include "cmap.h" 2917077Sbloom #include "uio.h" 3017077Sbloom #include "kernel.h" 3134537Skarels #include "syslog.h" 3210770Ssam 3313091Ssam #include "../vax/cpu.h" 3413091Ssam #include "../vax/nexus.h" 3517077Sbloom #include "ubavar.h" 3617077Sbloom #include "ubareg.h" 3717077Sbloom #include "rlreg.h" 3810770Ssam 3910770Ssam /* Pending Controller items and statistics */ 4010770Ssam struct rl_softc { 4110770Ssam int rl_softas; /* Attention sumary, (seeks pending) */ 4210770Ssam int rl_ndrive; /* Number of drives on controller */ 4310770Ssam int rl_wticks; /* Monitor time for function */ 4410770Ssam } rl_softc[NHL]; 4510770Ssam 4610770Ssam /* 4713091Ssam * State of controller from last transfer. 4813091Ssam * Since only one transfer can be done at a time per 4910770Ssam * controller, only allocate one for each controller. 5010770Ssam */ 5110770Ssam struct rl_stat { 5210770Ssam short rl_cyl[4]; /* Current cylinder for each drive */ 5310770Ssam short rl_dn; /* drive number currently transferring */ 5410770Ssam short rl_cylnhd; /* current cylinder and head of transfer */ 5510770Ssam u_short rl_bleft; /* bytes left to transfer */ 5610770Ssam u_short rl_bpart; /* bytes transferred */ 5710770Ssam } rl_stat[NHL]; 5810770Ssam 5924741Sbloom #define rlunit(dev) (minor(dev) >> 3) 6024741Sbloom 6110770Ssam /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 6213091Ssam /* Last cylinder not used. Saved for Bad Sector File */ 6310770Ssam struct size { 6410770Ssam daddr_t nblocks; 6510770Ssam int cyloff; 6610770Ssam } rl02_sizes[8] = { 6713091Ssam 15884, 0, /* A=cyl 0 thru 397 */ 6813091Ssam 4520, 398, /* B=cyl 398 thru 510 */ 6913091Ssam -1, 0, /* C=cyl 0 thru 511 */ 7013091Ssam 4520, 398, /* D=cyl 398 thru 510 */ 7117431Skarels 0, 0, /* E= Not Defined */ 7210770Ssam 0, 0, /* F= Not Defined */ 7313091Ssam 20440, 0, /* G=cyl 0 thru 510 */ 7410770Ssam 0, 0, /* H= Not Defined */ 7510770Ssam }; 7610770Ssam /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 7710770Ssam 7810770Ssam int rlprobe(), rlslave(), rlattach(), rldgo(), rlintr(); 7910770Ssam struct uba_ctlr *rlminfo[NHL]; 8010770Ssam struct uba_device *rldinfo[NRL]; 8110770Ssam struct uba_device *rlip[NHL][4]; 8210770Ssam 8310770Ssam /* RL02 driver structure */ 8417431Skarels u_short rlstd[] = { 0174400, 0 }; 8510770Ssam struct uba_driver hldriver = 8610770Ssam { rlprobe, rlslave, rlattach, rldgo, rlstd, "rl", rldinfo, "hl", rlminfo }; 8710770Ssam 8810770Ssam /* User table per controller */ 8910770Ssam struct buf rlutab[NRL]; 9010770Ssam 9110770Ssam /* RL02 drive structure */ 9210770Ssam struct RL02 { 9310770Ssam short nbpt; /* Number of 512 byte blocks/track */ 9410770Ssam short ntrak; 9510770Ssam short nbpc; /* Number of 512 byte blocks/cylinder */ 9610770Ssam short ncyl; 9710770Ssam short btrak; /* Number of bytes/track */ 9810770Ssam struct size *sizes; 9910770Ssam } rl02 = { 10010770Ssam 20, 2, 40, 512, 20*512, rl02_sizes /* rl02/DEC*/ 10110770Ssam }; 10210770Ssam 10310770Ssam #define b_cylin b_resid /* Last seek as CYL<<1 | HD */ 10410770Ssam 10510770Ssam int rlwstart, rlwatch(); /* Have started guardian */ 10610770Ssam 10710770Ssam /* Check that controller exists */ 10810770Ssam /*ARGSUSED*/ 10910770Ssam rlprobe(reg) 11010770Ssam caddr_t reg; 11110770Ssam { 11210770Ssam register int br, cvec; 11310770Ssam 11410770Ssam #ifdef lint 11510770Ssam br = 0; cvec = br; br = cvec; 11613091Ssam rlintr(0); 11710770Ssam #endif 11813091Ssam ((struct rldevice *)reg)->rlcs = RL_IE | RL_NOOP; 11913091Ssam DELAY(10); 12013091Ssam ((struct rldevice *)reg)->rlcs &= ~RL_IE; 12112452Ssam return (sizeof (struct rldevice)); 12210770Ssam } 12310770Ssam 12410770Ssam rlslave(ui, reg) 12510770Ssam struct uba_device *ui; 12610770Ssam caddr_t reg; 12710770Ssam { 12810770Ssam register struct rldevice *rladdr = (struct rldevice *)reg; 12910770Ssam short ctr = 0; 13010770Ssam 13110770Ssam /* 13210770Ssam * DEC reports that: 13310770Ssam * For some unknown reason the RL02 (seems to be only drive 1) 13410770Ssam * does not return a valid drive status the first time that a 13510770Ssam * GET STATUS request is issued for the drive, in fact it can 13610770Ssam * take up to three or more GET STATUS requests to obtain the 13710770Ssam * correct status. 13810770Ssam * In order to overcome this, the driver has been modified to 13910770Ssam * issue a GET STATUS request and validate the drive status 14010770Ssam * returned. If a valid status is not returned after eight 14110770Ssam * attempts, then an error message is printed. 14210770Ssam */ 14310770Ssam do { 14410770Ssam rladdr->rlda.getstat = RL_RESET; 14510770Ssam rladdr->rlcs = (ui->ui_slave <<8) | RL_GETSTAT; /* Get status*/ 14610770Ssam rlwait(rladdr); 14717431Skarels } while ((rladdr->rlcs & (RL_CRDY|RL_ERR)) != RL_CRDY && ++ctr < 8); 14817431Skarels 14910770Ssam if ((rladdr->rlcs & RL_DE) || (ctr >= 8)) 15017431Skarels return (0); 15113091Ssam if ((rladdr->rlmp.getstat & RLMP_DT) == 0 ) { 15213091Ssam printf("rl%d: rl01's not supported\n", ui->ui_slave); 15310770Ssam return(0); 15410770Ssam } 15510770Ssam return (1); 15610770Ssam } 15710770Ssam 15810770Ssam rlattach(ui) 15910770Ssam register struct uba_device *ui; 16010770Ssam { 16110770Ssam register struct rldevice *rladdr; 16210770Ssam 16310770Ssam if (rlwstart == 0) { 16413091Ssam timeout(rlwatch, (caddr_t)0, hz); 16510770Ssam rlwstart++; 16610770Ssam } 16710770Ssam /* Initialize iostat values */ 16810770Ssam if (ui->ui_dk >= 0) 169*38175Smckusick dk_wpms[ui->ui_dk] = 256016; /* 16bit transfer time? */ 17010770Ssam rlip[ui->ui_ctlr][ui->ui_slave] = ui; 17113091Ssam rl_softc[ui->ui_ctlr].rl_ndrive++; 17210770Ssam rladdr = (struct rldevice *)ui->ui_addr; 17310770Ssam /* reset controller */ 17410770Ssam rladdr->rlda.getstat = RL_RESET; /* SHOULD BE REPEATED? */ 17510770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_GETSTAT; /* Reset DE bit */ 17610770Ssam rlwait(rladdr); 17713091Ssam /* determine disk posistion */ 17810770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_RHDR; 17910770Ssam rlwait(rladdr); 18010770Ssam /* save disk drive posistion */ 18110770Ssam rl_stat[ui->ui_ctlr].rl_cyl[ui->ui_slave] = 18213091Ssam (rladdr->rlmp.readhdr & 0177700) >> 6; 18310770Ssam rl_stat[ui->ui_ctlr].rl_dn = -1; 18410770Ssam } 18510770Ssam 18612452Ssam rlopen(dev) 18712452Ssam dev_t dev; 18812452Ssam { 18924741Sbloom register int unit = rlunit(dev); 19013091Ssam register struct uba_device *ui; 19112452Ssam 19212452Ssam if (unit >= NRL || (ui = rldinfo[unit]) == 0 || ui->ui_alive == 0) 19312452Ssam return (ENXIO); 19412452Ssam return (0); 19512452Ssam } 19612452Ssam 19710770Ssam rlstrategy(bp) 19810770Ssam register struct buf *bp; 19910770Ssam { 20010770Ssam register struct uba_device *ui; 20110770Ssam register int drive; 20210770Ssam register struct buf *dp; 20313091Ssam int partition = minor(bp->b_dev) & 07, s; 20410770Ssam long bn, sz; 20510770Ssam 20613091Ssam sz = (bp->b_bcount+511) >> 9; 20724741Sbloom drive = rlunit(bp->b_dev); 20824741Sbloom if (drive >= NRL) { 20924741Sbloom bp->b_error = ENXIO; 21010770Ssam goto bad; 21124741Sbloom } 21213091Ssam ui = rldinfo[drive]; 21324741Sbloom if (ui == 0 || ui->ui_alive == 0) { 21424741Sbloom bp->b_error = ENXIO; 21510770Ssam goto bad; 21624741Sbloom } 21710770Ssam if (bp->b_blkno < 0 || 21824741Sbloom (bn = bp->b_blkno)+sz > rl02.sizes[partition].nblocks) { 21924786Skarels if (bp->b_blkno == rl02.sizes[partition].nblocks) { 22024786Skarels bp->b_resid = bp->b_bcount; 22124741Sbloom goto done; 22224786Skarels } 22324741Sbloom bp->b_error = EINVAL; 22410770Ssam goto bad; 22524741Sbloom } 22610770Ssam /* bn is in 512 byte block size */ 22710770Ssam bp->b_cylin = bn/rl02.nbpc + rl02.sizes[partition].cyloff; 22813091Ssam s = spl5(); 22910770Ssam dp = &rlutab[ui->ui_unit]; 23010770Ssam disksort(dp, bp); 23110770Ssam if (dp->b_active == 0) { 23213091Ssam rlustart(ui); 23310770Ssam bp = &ui->ui_mi->um_tab; 23410770Ssam if (bp->b_actf && bp->b_active == 0) 23513091Ssam rlstart(ui->ui_mi); 23610770Ssam } 23713091Ssam splx(s); 23810770Ssam return; 23910770Ssam 24010770Ssam bad: 24110770Ssam bp->b_flags |= B_ERROR; 24224741Sbloom done: 24310770Ssam iodone(bp); 24410770Ssam return; 24510770Ssam } 24610770Ssam 24710770Ssam /* 24810770Ssam * Unit start routine. 24910770Ssam * Seek the drive to be where the data is 25010770Ssam * and then generate another interrupt 25110770Ssam * to actually start the transfer. 25210770Ssam */ 25310770Ssam rlustart(ui) 25410770Ssam register struct uba_device *ui; 25510770Ssam { 25610770Ssam register struct buf *bp, *dp; 25710770Ssam register struct uba_ctlr *um; 25810770Ssam register struct rldevice *rladdr; 25910770Ssam daddr_t bn; 26013091Ssam short hd, diff; 26110770Ssam 26210770Ssam if (ui == 0) 26313091Ssam return; 26410770Ssam um = ui->ui_mi; 26513091Ssam dk_busy &= ~(1 << ui->ui_dk); 26610770Ssam dp = &rlutab[ui->ui_unit]; 26710770Ssam if ((bp = dp->b_actf) == NULL) 26813091Ssam return; 26910770Ssam /* 27010770Ssam * If the controller is active, just remember 27110770Ssam * that this device has to be positioned... 27210770Ssam */ 27310770Ssam if (um->um_tab.b_active) { 27410770Ssam rl_softc[um->um_ctlr].rl_softas |= 1<<ui->ui_slave; 27513091Ssam return; 27610770Ssam } 27710770Ssam /* 27810770Ssam * If we have already positioned this drive, 27910770Ssam * then just put it on the ready queue. 28010770Ssam */ 28110770Ssam if (dp->b_active) 28210770Ssam goto done; 28313091Ssam dp->b_active = 1; /* positioning drive */ 28410770Ssam rladdr = (struct rldevice *)um->um_addr; 28510770Ssam 28610770Ssam /* 28710770Ssam * Figure out where this transfer is going to 28810770Ssam * and see if we are seeked correctly. 28910770Ssam */ 29024741Sbloom bn = bp->b_blkno; /* Block # desired */ 29110770Ssam /* 29213091Ssam * Map 512 byte logical disk blocks 29313091Ssam * to 256 byte sectors (rl02's are stupid). 29410770Ssam */ 29510770Ssam hd = (bn / rl02.nbpt) & 1; /* Get head required */ 29610770Ssam diff = (rl_stat[um->um_ctlr].rl_cyl[ui->ui_slave] >> 1) - bp->b_cylin; 29710770Ssam if ( diff == 0 && (rl_stat[um->um_ctlr].rl_cyl[ui->ui_slave] & 1) == hd) 29810770Ssam goto done; /* on cylinder and head */ 29910770Ssam /* 30010770Ssam * Not at correct position. 30110770Ssam */ 30210770Ssam rl_stat[um->um_ctlr].rl_cyl[ui->ui_slave] = (bp->b_cylin << 1) | hd; 30310770Ssam if (diff < 0) 30410770Ssam rladdr->rlda.seek = -diff << 7 | RLDA_HGH | hd << 4; 30510770Ssam else 30610770Ssam rladdr->rlda.seek = diff << 7 | RLDA_LOW | hd << 4; 30710770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_SEEK; 30810770Ssam 30910770Ssam /* 31010770Ssam * Mark unit busy for iostat. 31110770Ssam */ 31210770Ssam if (ui->ui_dk >= 0) { 31310770Ssam dk_busy |= 1<<ui->ui_dk; 31410770Ssam dk_seek[ui->ui_dk]++; 31510770Ssam } 31612452Ssam rlwait(rladdr); 31710770Ssam done: 31810770Ssam /* 31910770Ssam * Device is ready to go. 32010770Ssam * Put it on the ready queue for the controller 32110770Ssam * (unless its already there.) 32210770Ssam */ 32310770Ssam if (dp->b_active != 2) { 32410770Ssam dp->b_forw = NULL; 32510770Ssam if (um->um_tab.b_actf == NULL) 32610770Ssam um->um_tab.b_actf = dp; 32710770Ssam else 32810770Ssam um->um_tab.b_actl->b_forw = dp; 32910770Ssam um->um_tab.b_actl = dp; 33010770Ssam dp->b_active = 2; /* Request on ready queue */ 33110770Ssam } 33210770Ssam } 33310770Ssam 33410770Ssam /* 33510770Ssam * Start up a transfer on a drive. 33610770Ssam */ 33710770Ssam rlstart(um) 33810770Ssam register struct uba_ctlr *um; 33910770Ssam { 34010770Ssam register struct buf *bp, *dp; 34110770Ssam register struct uba_device *ui; 34210770Ssam register struct rldevice *rladdr; 34310770Ssam register struct rl_stat *st = &rl_stat[um->um_ctlr]; 34410770Ssam daddr_t bn; 34510770Ssam short sn, cyl, cmd; 34610770Ssam 34710770Ssam loop: 34810770Ssam if ((dp = um->um_tab.b_actf) == NULL) { 34910770Ssam st->rl_dn = -1; 35010770Ssam st->rl_cylnhd = 0; 35110770Ssam st->rl_bleft = 0; 35210770Ssam st->rl_bpart = 0; 35313091Ssam return; 35410770Ssam } 35510770Ssam if ((bp = dp->b_actf) == NULL) { 35610770Ssam um->um_tab.b_actf = dp->b_forw; 35710770Ssam goto loop; 35810770Ssam } 35910770Ssam /* 36010770Ssam * Mark controller busy, and 36113091Ssam * determine destination. 36210770Ssam */ 36310770Ssam um->um_tab.b_active++; 36424741Sbloom ui = rldinfo[rlunit(bp->b_dev)]; /* Controller */ 36524741Sbloom bn = bp->b_blkno; /* 512 byte Block number */ 36610770Ssam cyl = bp->b_cylin << 1; /* Cylinder */ 36710770Ssam cyl |= (bn / rl02.nbpt) & 1; /* Get head required */ 36810770Ssam sn = (bn % rl02.nbpt) << 1; /* Sector number */ 36910770Ssam rladdr = (struct rldevice *)ui->ui_addr; 37012452Ssam rlwait(rladdr); 37110770Ssam rladdr->rlda.rw = cyl<<6 | sn; 37210770Ssam /* save away current transfers drive status */ 37310770Ssam st->rl_dn = ui->ui_slave; 37410770Ssam st->rl_cylnhd = cyl; 37510770Ssam st->rl_bleft = bp->b_bcount; 37610770Ssam st->rl_bpart = rl02.btrak - (sn * NRLBPSC); 37713091Ssam /* 37813091Ssam * RL02 must seek between cylinders and between tracks, 37913091Ssam * determine maximum data transfer at this time. 38013091Ssam */ 38113091Ssam if (st->rl_bleft < st->rl_bpart) 38210770Ssam st->rl_bpart = st->rl_bleft; 38310770Ssam rladdr->rlmp.rw = -(st->rl_bpart >> 1); 38410770Ssam if (bp->b_flags & B_READ) 38510770Ssam cmd = RL_IE | RL_READ | (ui->ui_slave << 8); 38610770Ssam else 38710770Ssam cmd = RL_IE | RL_WRITE | (ui->ui_slave << 8); 38810770Ssam um->um_cmd = cmd; 38910770Ssam (void) ubago(ui); 39010770Ssam } 39110770Ssam 39210770Ssam rldgo(um) 39310770Ssam register struct uba_ctlr *um; 39410770Ssam { 39510770Ssam register struct rldevice *rladdr = (struct rldevice *)um->um_addr; 39610770Ssam 39710770Ssam rladdr->rlba = um->um_ubinfo; 39810770Ssam rladdr->rlcs = um->um_cmd|((um->um_ubinfo>>12)&RL_BAE); 39910770Ssam } 40010770Ssam 40110770Ssam /* 40210770Ssam * Handle a disk interrupt. 40310770Ssam */ 40410770Ssam rlintr(rl21) 40510770Ssam register rl21; 40610770Ssam { 40710770Ssam register struct buf *bp, *dp; 40810770Ssam register struct uba_ctlr *um = rlminfo[rl21]; 40910770Ssam register struct uba_device *ui; 41010770Ssam register struct rldevice *rladdr = (struct rldevice *)um->um_addr; 41110770Ssam register unit; 41210770Ssam struct rl_softc *rl = &rl_softc[um->um_ctlr]; 41310770Ssam struct rl_stat *st = &rl_stat[um->um_ctlr]; 41413091Ssam int as = rl->rl_softas, status; 41510770Ssam 41610770Ssam rl->rl_wticks = 0; 41710770Ssam rl->rl_softas = 0; 41810770Ssam dp = um->um_tab.b_actf; 41910770Ssam bp = dp->b_actf; 42024741Sbloom ui = rldinfo[rlunit(bp->b_dev)]; 42113091Ssam dk_busy &= ~(1 << ui->ui_dk); 42210770Ssam 42310770Ssam /* 42410770Ssam * Check for and process errors on 42510770Ssam * either the drive or the controller. 42610770Ssam */ 42710770Ssam if (rladdr->rlcs & RL_ERR) { 42810770Ssam u_short err; 42913091Ssam rlwait(rladdr); 43010770Ssam err = rladdr->rlcs; 43110770Ssam /* get staus and reset controller */ 43210770Ssam rladdr->rlda.getstat = RL_GSTAT; 43310770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_GETSTAT; 43410770Ssam rlwait(rladdr); 43510770Ssam status = rladdr->rlmp.getstat; 43610770Ssam /* reset drive */ 43710770Ssam rladdr->rlda.getstat = RL_RESET; 43810770Ssam rladdr->rlcs = (ui->ui_slave <<8) | RL_GETSTAT; /* Get status*/ 43910770Ssam rlwait(rladdr); 44013091Ssam if ((status & RLMP_WL) == RLMP_WL) { 44110770Ssam /* 44210770Ssam * Give up on write protected devices 44310770Ssam * immediately. 44410770Ssam */ 44524741Sbloom printf("rl%d: write protected\n", rlunit(bp->b_dev)); 44610770Ssam bp->b_flags |= B_ERROR; 44710770Ssam } else if (++um->um_tab.b_errcnt > 10) { 44810770Ssam /* 44910770Ssam * After 10 retries give up. 45010770Ssam */ 45134524Skarels diskerr(bp, "rl", "hard error", LOG_PRINTF, -1, 45234524Skarels (struct disklabel *)0); 45334524Skarels printf(" cs=%b mp=%b\n", err, RLCS_BITS, 45413091Ssam status, RLER_BITS); 45510770Ssam bp->b_flags |= B_ERROR; 45610770Ssam } else 45710770Ssam um->um_tab.b_active = 0; /* force retry */ 45813091Ssam /* determine disk position */ 45910770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_RHDR; 46010770Ssam rlwait(rladdr); 46113091Ssam /* save disk drive position */ 46213091Ssam st->rl_cyl[ui->ui_slave] = 46313091Ssam (rladdr->rlmp.readhdr & 0177700) >> 6; 46410770Ssam } 46510770Ssam /* 46610770Ssam * If still ``active'', then don't need any more retries. 46710770Ssam */ 46810770Ssam if (um->um_tab.b_active) { 46910770Ssam /* RL02 check if more data from previous request */ 47013091Ssam if ((bp->b_flags & B_ERROR) == 0 && 47113091Ssam (int)(st->rl_bleft -= st->rl_bpart) > 0) { 47210770Ssam /* 47313091Ssam * The following code was modeled from the rk07 47410770Ssam * driver when an ECC error occured. It has to 47510770Ssam * fix the bits then restart the transfer which is 47610770Ssam * what we have to do (restart transfer). 47710770Ssam */ 47810770Ssam int reg, npf, o, cmd, ubaddr, diff, head; 47910770Ssam 48010770Ssam /* seek to next head/track */ 48110770Ssam /* increment head and/or cylinder */ 48210770Ssam st->rl_cylnhd++; 48310770Ssam diff = (st->rl_cyl[ui->ui_slave] >> 1) - 48410770Ssam (st->rl_cylnhd >> 1); 48510770Ssam st->rl_cyl[ui->ui_slave] = st->rl_cylnhd; 48610770Ssam head = st->rl_cylnhd & 1; 48713091Ssam rlwait(rladdr); 48813091Ssam if (diff < 0) 48913091Ssam rladdr->rlda.seek = 49013091Ssam -diff << 7 | RLDA_HGH | head << 4; 49110770Ssam else 49213091Ssam rladdr->rlda.seek = 49313091Ssam diff << 7 | RLDA_LOW | head << 4; 49410770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_SEEK; 49510770Ssam npf = btop( bp->b_bcount - st->rl_bleft ); 49636035Skarels reg = btop(UBAI_ADDR(um->um_ubinfo)) + npf; 49710770Ssam o = (int)bp->b_un.b_addr & PGOFSET; 49810770Ssam ubapurge(um); 49910770Ssam um->um_tab.b_active++; 50013091Ssam rlwait(rladdr); 50110770Ssam rladdr->rlda.rw = st->rl_cylnhd << 6; 50213091Ssam if (st->rl_bleft < (st->rl_bpart = rl02.btrak)) 50310770Ssam st->rl_bpart = st->rl_bleft; 50410770Ssam rladdr->rlmp.rw = -(st->rl_bpart >> 1); 50510770Ssam cmd = (bp->b_flags&B_READ ? RL_READ : RL_WRITE) | 50613091Ssam RL_IE | (ui->ui_slave << 8); 50710770Ssam ubaddr = (int)ptob(reg) + o; 50810770Ssam cmd |= ((ubaddr >> 12) & RL_BAE); 50910770Ssam rladdr->rlba = ubaddr; 51010770Ssam rladdr->rlcs = cmd; 51110770Ssam return; 51210770Ssam } 51310770Ssam um->um_tab.b_active = 0; 51410770Ssam um->um_tab.b_errcnt = 0; 51510770Ssam dp->b_active = 0; 51610770Ssam dp->b_errcnt = 0; 51710770Ssam /* "b_resid" words remaining after error */ 51810770Ssam bp->b_resid = st->rl_bleft; 51910770Ssam um->um_tab.b_actf = dp->b_forw; 52010770Ssam dp->b_actf = bp->av_forw; 52110770Ssam st->rl_dn = -1; 52210770Ssam st->rl_bpart = st->rl_bleft = 0; 52310770Ssam iodone(bp); 52410770Ssam /* 52510770Ssam * If this unit has more work to do, 52610770Ssam * then start it up right away. 52710770Ssam */ 52810770Ssam if (dp->b_actf) 52913091Ssam rlustart(ui); 53010770Ssam as &= ~(1<<ui->ui_slave); 53110770Ssam } else 53210770Ssam as |= (1<<ui->ui_slave); 53310770Ssam ubadone(um); 53410770Ssam /* reset state info */ 53510770Ssam st->rl_dn = -1; 53610770Ssam st->rl_cylnhd = st->rl_bpart = st->rl_bleft = 0; 53710770Ssam /* 53810770Ssam * Process other units which need attention. 53910770Ssam * For each unit which needs attention, call 54010770Ssam * the unit start routine to place the slave 54110770Ssam * on the controller device queue. 54210770Ssam */ 54326369Skarels while (unit = ffs((long)as)) { 54410770Ssam unit--; /* was 1 origin */ 54510770Ssam as &= ~(1<<unit); 54613091Ssam rlustart(rlip[rl21][unit]); 54710770Ssam } 54810770Ssam /* 54910770Ssam * If the controller is not transferring, but 55010770Ssam * there are devices ready to transfer, start 55110770Ssam * the controller. 55210770Ssam */ 55310770Ssam if (um->um_tab.b_actf && um->um_tab.b_active == 0) 55413091Ssam rlstart(um); 55510770Ssam } 55610770Ssam 55712452Ssam rlwait(rladdr) 55812452Ssam register struct rldevice *rladdr; 55910770Ssam { 56012452Ssam 56110770Ssam while ((rladdr->rlcs & RL_CRDY) == 0) 56213091Ssam ; 56310770Ssam } 56410770Ssam 56510770Ssam /* 56610770Ssam * Reset driver after UBA init. 56710770Ssam * Cancel software state of all pending transfers 56810770Ssam * and restart all units and the controller. 56910770Ssam */ 57010770Ssam rlreset(uban) 57110770Ssam int uban; 57210770Ssam { 57310770Ssam register struct uba_ctlr *um; 57410770Ssam register struct uba_device *ui; 57510770Ssam register struct rldevice *rladdr; 57610770Ssam register struct rl_stat *st; 57713091Ssam register int rl21, unit; 57810770Ssam 57910770Ssam for (rl21 = 0; rl21 < NHL; rl21++) { 58010770Ssam if ((um = rlminfo[rl21]) == 0 || um->um_ubanum != uban || 58110770Ssam um->um_alive == 0) 58210770Ssam continue; 58313091Ssam printf(" hl%d", rl21); 58410770Ssam rladdr = (struct rldevice *)um->um_addr; 58510770Ssam st = &rl_stat[rl21]; 58610770Ssam um->um_tab.b_active = 0; 58710770Ssam um->um_tab.b_actf = um->um_tab.b_actl = 0; 58810770Ssam if (um->um_ubinfo) { 58910770Ssam printf("<%d>", (um->um_ubinfo>>28)&0xf); 59012452Ssam um->um_ubinfo = 0; 59110770Ssam } 59210770Ssam /* reset controller */ 59310770Ssam st->rl_dn = -1; 59410770Ssam st->rl_cylnhd = 0; 59510770Ssam st->rl_bleft = 0; 59610770Ssam st->rl_bpart = 0; 59712452Ssam rlwait(rladdr); 59810770Ssam for (unit = 0; unit < NRL; unit++) { 59910770Ssam rladdr->rlcs = (unit << 8) | RL_GETSTAT; 60012452Ssam rlwait(rladdr); 60110770Ssam /* Determine disk posistion */ 60210770Ssam rladdr->rlcs = (unit << 8) | RL_RHDR; 60310770Ssam rlwait(rladdr); 60410770Ssam /* save disk drive posistion */ 60510770Ssam st->rl_cyl[unit] = 60610770Ssam (rladdr->rlmp.readhdr & 0177700) >> 6; 60710770Ssam if ((ui = rldinfo[unit]) == 0) 60810770Ssam continue; 60910770Ssam if (ui->ui_alive == 0 || ui->ui_mi != um) 61010770Ssam continue; 61110770Ssam rlutab[unit].b_active = 0; 61213091Ssam rlustart(ui); 61310770Ssam } 61413091Ssam rlstart(um); 61510770Ssam } 61610770Ssam } 61710770Ssam 61810770Ssam /* 61910770Ssam * Wake up every second and if an interrupt is pending 62010770Ssam * but nothing has happened increment a counter. 62110770Ssam * If nothing happens for 20 seconds, reset the UNIBUS 62210770Ssam * and begin anew. 62310770Ssam */ 62410770Ssam rlwatch() 62510770Ssam { 62610770Ssam register struct uba_ctlr *um; 62710770Ssam register rl21, unit; 62810770Ssam register struct rl_softc *rl; 62910770Ssam 63010770Ssam timeout(rlwatch, (caddr_t)0, hz); 63110770Ssam for (rl21 = 0; rl21 < NHL; rl21++) { 63210770Ssam um = rlminfo[rl21]; 63310770Ssam if (um == 0 || um->um_alive == 0) 63410770Ssam continue; 63510770Ssam rl = &rl_softc[rl21]; 63610770Ssam if (um->um_tab.b_active == 0) { 63710770Ssam for (unit = 0; unit < NRL; unit++) 63810770Ssam if (rlutab[unit].b_active && 63910770Ssam rldinfo[unit]->ui_mi == um) 64010770Ssam goto active; 64110770Ssam rl->rl_wticks = 0; 64210770Ssam continue; 64310770Ssam } 64410770Ssam active: 64510770Ssam rl->rl_wticks++; 64610770Ssam if (rl->rl_wticks >= 20) { 64710770Ssam rl->rl_wticks = 0; 64810770Ssam printf("hl%d: lost interrupt\n", rl21); 64910770Ssam ubareset(um->um_ubanum); 65010770Ssam } 65110770Ssam } 65210770Ssam } 65310770Ssam 65413091Ssam /*ARGSUSED*/ 65510770Ssam rldump(dev) 65610770Ssam dev_t dev; 65710770Ssam { 65813091Ssam 65910770Ssam /* don't think there is room on swap for it anyway. */ 66010770Ssam } 66113272Ssam 66213272Ssam rlsize(dev) 66313272Ssam dev_t dev; 66413272Ssam { 66524741Sbloom register int unit = rlunit(dev); 66613272Ssam register struct uba_device *ui; 66713272Ssam 66813272Ssam if (unit >= NRL || (ui = rldinfo[unit]) == 0 || ui->ui_alive == 0) 66913272Ssam return (-1); 67013272Ssam return (rl02.sizes[minor(dev) & 07].nblocks); 67113272Ssam } 67212504Ssam #endif 673