123338Smckusick /* 223338Smckusick * Copyright (c) 1982 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*26369Skarels * @(#)rl.c 6.7 (Berkeley) 02/23/86 723338Smckusick */ 810770Ssam 910770Ssam #include "rl.h" 1012452Ssam #if NRL > 0 1110770Ssam /* 1210770Ssam * UNIBUS RL02 disk driver 1310770Ssam */ 1413091Ssam #include "../machine/pte.h" 1510770Ssam 1617077Sbloom #include "param.h" 1717077Sbloom #include "systm.h" 1817077Sbloom #include "dk.h" 1917077Sbloom #include "dkbad.h" 2017077Sbloom #include "buf.h" 2117077Sbloom #include "conf.h" 2217077Sbloom #include "dir.h" 2317077Sbloom #include "user.h" 2417077Sbloom #include "map.h" 2517077Sbloom #include "vm.h" 2617077Sbloom #include "cmap.h" 2717077Sbloom #include "uio.h" 2817077Sbloom #include "kernel.h" 2910770Ssam 3013091Ssam #include "../vax/cpu.h" 3113091Ssam #include "../vax/nexus.h" 3217077Sbloom #include "ubavar.h" 3317077Sbloom #include "ubareg.h" 3417077Sbloom #include "rlreg.h" 3510770Ssam 3610770Ssam /* Pending Controller items and statistics */ 3710770Ssam struct rl_softc { 3810770Ssam int rl_softas; /* Attention sumary, (seeks pending) */ 3910770Ssam int rl_ndrive; /* Number of drives on controller */ 4010770Ssam int rl_wticks; /* Monitor time for function */ 4110770Ssam } rl_softc[NHL]; 4210770Ssam 4310770Ssam /* 4413091Ssam * State of controller from last transfer. 4513091Ssam * Since only one transfer can be done at a time per 4610770Ssam * controller, only allocate one for each controller. 4710770Ssam */ 4810770Ssam struct rl_stat { 4910770Ssam short rl_cyl[4]; /* Current cylinder for each drive */ 5010770Ssam short rl_dn; /* drive number currently transferring */ 5110770Ssam short rl_cylnhd; /* current cylinder and head of transfer */ 5210770Ssam u_short rl_bleft; /* bytes left to transfer */ 5310770Ssam u_short rl_bpart; /* bytes transferred */ 5410770Ssam } rl_stat[NHL]; 5510770Ssam 5624741Sbloom #define rlunit(dev) (minor(dev) >> 3) 5724741Sbloom 5810770Ssam /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 5913091Ssam /* Last cylinder not used. Saved for Bad Sector File */ 6010770Ssam struct size { 6110770Ssam daddr_t nblocks; 6210770Ssam int cyloff; 6310770Ssam } rl02_sizes[8] = { 6413091Ssam 15884, 0, /* A=cyl 0 thru 397 */ 6513091Ssam 4520, 398, /* B=cyl 398 thru 510 */ 6613091Ssam -1, 0, /* C=cyl 0 thru 511 */ 6713091Ssam 4520, 398, /* D=cyl 398 thru 510 */ 6817431Skarels 0, 0, /* E= Not Defined */ 6910770Ssam 0, 0, /* F= Not Defined */ 7013091Ssam 20440, 0, /* G=cyl 0 thru 510 */ 7110770Ssam 0, 0, /* H= Not Defined */ 7210770Ssam }; 7310770Ssam /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 7410770Ssam 7510770Ssam int rlprobe(), rlslave(), rlattach(), rldgo(), rlintr(); 7610770Ssam struct uba_ctlr *rlminfo[NHL]; 7710770Ssam struct uba_device *rldinfo[NRL]; 7810770Ssam struct uba_device *rlip[NHL][4]; 7910770Ssam 8010770Ssam /* RL02 driver structure */ 8117431Skarels u_short rlstd[] = { 0174400, 0 }; 8210770Ssam struct uba_driver hldriver = 8310770Ssam { rlprobe, rlslave, rlattach, rldgo, rlstd, "rl", rldinfo, "hl", rlminfo }; 8410770Ssam 8510770Ssam /* User table per controller */ 8610770Ssam struct buf rlutab[NRL]; 8710770Ssam 8810770Ssam /* RL02 drive structure */ 8910770Ssam struct RL02 { 9010770Ssam short nbpt; /* Number of 512 byte blocks/track */ 9110770Ssam short ntrak; 9210770Ssam short nbpc; /* Number of 512 byte blocks/cylinder */ 9310770Ssam short ncyl; 9410770Ssam short btrak; /* Number of bytes/track */ 9510770Ssam struct size *sizes; 9610770Ssam } rl02 = { 9710770Ssam 20, 2, 40, 512, 20*512, rl02_sizes /* rl02/DEC*/ 9810770Ssam }; 9910770Ssam 10010770Ssam struct buf rrlbuf[NRL]; 10110770Ssam 10210770Ssam #define b_cylin b_resid /* Last seek as CYL<<1 | HD */ 10310770Ssam 10410770Ssam int rlwstart, rlwatch(); /* Have started guardian */ 10510770Ssam 10610770Ssam /* Check that controller exists */ 10710770Ssam /*ARGSUSED*/ 10810770Ssam rlprobe(reg) 10910770Ssam caddr_t reg; 11010770Ssam { 11110770Ssam register int br, cvec; 11210770Ssam 11310770Ssam #ifdef lint 11410770Ssam br = 0; cvec = br; br = cvec; 11513091Ssam rlintr(0); 11610770Ssam #endif 11713091Ssam ((struct rldevice *)reg)->rlcs = RL_IE | RL_NOOP; 11813091Ssam DELAY(10); 11913091Ssam ((struct rldevice *)reg)->rlcs &= ~RL_IE; 12012452Ssam return (sizeof (struct rldevice)); 12110770Ssam } 12210770Ssam 12310770Ssam rlslave(ui, reg) 12410770Ssam struct uba_device *ui; 12510770Ssam caddr_t reg; 12610770Ssam { 12710770Ssam register struct rldevice *rladdr = (struct rldevice *)reg; 12810770Ssam short ctr = 0; 12910770Ssam 13010770Ssam /* 13110770Ssam * DEC reports that: 13210770Ssam * For some unknown reason the RL02 (seems to be only drive 1) 13310770Ssam * does not return a valid drive status the first time that a 13410770Ssam * GET STATUS request is issued for the drive, in fact it can 13510770Ssam * take up to three or more GET STATUS requests to obtain the 13610770Ssam * correct status. 13710770Ssam * In order to overcome this, the driver has been modified to 13810770Ssam * issue a GET STATUS request and validate the drive status 13910770Ssam * returned. If a valid status is not returned after eight 14010770Ssam * attempts, then an error message is printed. 14110770Ssam */ 14210770Ssam do { 14310770Ssam rladdr->rlda.getstat = RL_RESET; 14410770Ssam rladdr->rlcs = (ui->ui_slave <<8) | RL_GETSTAT; /* Get status*/ 14510770Ssam rlwait(rladdr); 14617431Skarels } while ((rladdr->rlcs & (RL_CRDY|RL_ERR)) != RL_CRDY && ++ctr < 8); 14717431Skarels 14810770Ssam if ((rladdr->rlcs & RL_DE) || (ctr >= 8)) 14917431Skarels return (0); 15013091Ssam if ((rladdr->rlmp.getstat & RLMP_DT) == 0 ) { 15113091Ssam printf("rl%d: rl01's not supported\n", ui->ui_slave); 15210770Ssam return(0); 15310770Ssam } 15410770Ssam return (1); 15510770Ssam } 15610770Ssam 15710770Ssam rlattach(ui) 15810770Ssam register struct uba_device *ui; 15910770Ssam { 16010770Ssam register struct rldevice *rladdr; 16110770Ssam 16210770Ssam if (rlwstart == 0) { 16313091Ssam timeout(rlwatch, (caddr_t)0, hz); 16410770Ssam rlwstart++; 16510770Ssam } 16610770Ssam /* Initialize iostat values */ 16710770Ssam if (ui->ui_dk >= 0) 16810770Ssam dk_mspw[ui->ui_dk] = .000003906; /* 16bit transfer time? */ 16910770Ssam rlip[ui->ui_ctlr][ui->ui_slave] = ui; 17013091Ssam rl_softc[ui->ui_ctlr].rl_ndrive++; 17110770Ssam rladdr = (struct rldevice *)ui->ui_addr; 17210770Ssam /* reset controller */ 17310770Ssam rladdr->rlda.getstat = RL_RESET; /* SHOULD BE REPEATED? */ 17410770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_GETSTAT; /* Reset DE bit */ 17510770Ssam rlwait(rladdr); 17613091Ssam /* determine disk posistion */ 17710770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_RHDR; 17810770Ssam rlwait(rladdr); 17910770Ssam /* save disk drive posistion */ 18010770Ssam rl_stat[ui->ui_ctlr].rl_cyl[ui->ui_slave] = 18113091Ssam (rladdr->rlmp.readhdr & 0177700) >> 6; 18210770Ssam rl_stat[ui->ui_ctlr].rl_dn = -1; 18310770Ssam } 18410770Ssam 18512452Ssam rlopen(dev) 18612452Ssam dev_t dev; 18712452Ssam { 18824741Sbloom register int unit = rlunit(dev); 18913091Ssam register struct uba_device *ui; 19012452Ssam 19112452Ssam if (unit >= NRL || (ui = rldinfo[unit]) == 0 || ui->ui_alive == 0) 19212452Ssam return (ENXIO); 19312452Ssam return (0); 19412452Ssam } 19512452Ssam 19610770Ssam rlstrategy(bp) 19710770Ssam register struct buf *bp; 19810770Ssam { 19910770Ssam register struct uba_device *ui; 20010770Ssam register int drive; 20110770Ssam register struct buf *dp; 20213091Ssam int partition = minor(bp->b_dev) & 07, s; 20310770Ssam long bn, sz; 20410770Ssam 20513091Ssam sz = (bp->b_bcount+511) >> 9; 20624741Sbloom drive = rlunit(bp->b_dev); 20724741Sbloom if (drive >= NRL) { 20824741Sbloom bp->b_error = ENXIO; 20910770Ssam goto bad; 21024741Sbloom } 21113091Ssam ui = rldinfo[drive]; 21224741Sbloom if (ui == 0 || ui->ui_alive == 0) { 21324741Sbloom bp->b_error = ENXIO; 21410770Ssam goto bad; 21524741Sbloom } 21610770Ssam if (bp->b_blkno < 0 || 21724741Sbloom (bn = bp->b_blkno)+sz > rl02.sizes[partition].nblocks) { 21824786Skarels if (bp->b_blkno == rl02.sizes[partition].nblocks) { 21924786Skarels bp->b_resid = bp->b_bcount; 22024741Sbloom goto done; 22124786Skarels } 22224741Sbloom bp->b_error = EINVAL; 22310770Ssam goto bad; 22424741Sbloom } 22510770Ssam /* bn is in 512 byte block size */ 22610770Ssam bp->b_cylin = bn/rl02.nbpc + rl02.sizes[partition].cyloff; 22713091Ssam s = spl5(); 22810770Ssam dp = &rlutab[ui->ui_unit]; 22910770Ssam disksort(dp, bp); 23010770Ssam if (dp->b_active == 0) { 23113091Ssam rlustart(ui); 23210770Ssam bp = &ui->ui_mi->um_tab; 23310770Ssam if (bp->b_actf && bp->b_active == 0) 23413091Ssam rlstart(ui->ui_mi); 23510770Ssam } 23613091Ssam splx(s); 23710770Ssam return; 23810770Ssam 23910770Ssam bad: 24010770Ssam bp->b_flags |= B_ERROR; 24124741Sbloom done: 24210770Ssam iodone(bp); 24310770Ssam return; 24410770Ssam } 24510770Ssam 24610770Ssam /* 24710770Ssam * Unit start routine. 24810770Ssam * Seek the drive to be where the data is 24910770Ssam * and then generate another interrupt 25010770Ssam * to actually start the transfer. 25110770Ssam */ 25210770Ssam rlustart(ui) 25310770Ssam register struct uba_device *ui; 25410770Ssam { 25510770Ssam register struct buf *bp, *dp; 25610770Ssam register struct uba_ctlr *um; 25710770Ssam register struct rldevice *rladdr; 25810770Ssam daddr_t bn; 25913091Ssam short hd, diff; 26010770Ssam 26110770Ssam if (ui == 0) 26213091Ssam return; 26310770Ssam um = ui->ui_mi; 26413091Ssam dk_busy &= ~(1 << ui->ui_dk); 26510770Ssam dp = &rlutab[ui->ui_unit]; 26610770Ssam if ((bp = dp->b_actf) == NULL) 26713091Ssam return; 26810770Ssam /* 26910770Ssam * If the controller is active, just remember 27010770Ssam * that this device has to be positioned... 27110770Ssam */ 27210770Ssam if (um->um_tab.b_active) { 27310770Ssam rl_softc[um->um_ctlr].rl_softas |= 1<<ui->ui_slave; 27413091Ssam return; 27510770Ssam } 27610770Ssam /* 27710770Ssam * If we have already positioned this drive, 27810770Ssam * then just put it on the ready queue. 27910770Ssam */ 28010770Ssam if (dp->b_active) 28110770Ssam goto done; 28213091Ssam dp->b_active = 1; /* positioning drive */ 28310770Ssam rladdr = (struct rldevice *)um->um_addr; 28410770Ssam 28510770Ssam /* 28610770Ssam * Figure out where this transfer is going to 28710770Ssam * and see if we are seeked correctly. 28810770Ssam */ 28924741Sbloom bn = bp->b_blkno; /* Block # desired */ 29010770Ssam /* 29113091Ssam * Map 512 byte logical disk blocks 29213091Ssam * to 256 byte sectors (rl02's are stupid). 29310770Ssam */ 29410770Ssam hd = (bn / rl02.nbpt) & 1; /* Get head required */ 29510770Ssam diff = (rl_stat[um->um_ctlr].rl_cyl[ui->ui_slave] >> 1) - bp->b_cylin; 29610770Ssam if ( diff == 0 && (rl_stat[um->um_ctlr].rl_cyl[ui->ui_slave] & 1) == hd) 29710770Ssam goto done; /* on cylinder and head */ 29810770Ssam /* 29910770Ssam * Not at correct position. 30010770Ssam */ 30110770Ssam rl_stat[um->um_ctlr].rl_cyl[ui->ui_slave] = (bp->b_cylin << 1) | hd; 30210770Ssam if (diff < 0) 30310770Ssam rladdr->rlda.seek = -diff << 7 | RLDA_HGH | hd << 4; 30410770Ssam else 30510770Ssam rladdr->rlda.seek = diff << 7 | RLDA_LOW | hd << 4; 30610770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_SEEK; 30710770Ssam 30810770Ssam /* 30910770Ssam * Mark unit busy for iostat. 31010770Ssam */ 31110770Ssam if (ui->ui_dk >= 0) { 31210770Ssam dk_busy |= 1<<ui->ui_dk; 31310770Ssam dk_seek[ui->ui_dk]++; 31410770Ssam } 31512452Ssam rlwait(rladdr); 31610770Ssam done: 31710770Ssam /* 31810770Ssam * Device is ready to go. 31910770Ssam * Put it on the ready queue for the controller 32010770Ssam * (unless its already there.) 32110770Ssam */ 32210770Ssam if (dp->b_active != 2) { 32310770Ssam dp->b_forw = NULL; 32410770Ssam if (um->um_tab.b_actf == NULL) 32510770Ssam um->um_tab.b_actf = dp; 32610770Ssam else 32710770Ssam um->um_tab.b_actl->b_forw = dp; 32810770Ssam um->um_tab.b_actl = dp; 32910770Ssam dp->b_active = 2; /* Request on ready queue */ 33010770Ssam } 33110770Ssam } 33210770Ssam 33310770Ssam /* 33410770Ssam * Start up a transfer on a drive. 33510770Ssam */ 33610770Ssam rlstart(um) 33710770Ssam register struct uba_ctlr *um; 33810770Ssam { 33910770Ssam register struct buf *bp, *dp; 34010770Ssam register struct uba_device *ui; 34110770Ssam register struct rldevice *rladdr; 34210770Ssam register struct rl_stat *st = &rl_stat[um->um_ctlr]; 34310770Ssam daddr_t bn; 34410770Ssam short sn, cyl, cmd; 34510770Ssam 34610770Ssam loop: 34710770Ssam if ((dp = um->um_tab.b_actf) == NULL) { 34810770Ssam st->rl_dn = -1; 34910770Ssam st->rl_cylnhd = 0; 35010770Ssam st->rl_bleft = 0; 35110770Ssam st->rl_bpart = 0; 35213091Ssam return; 35310770Ssam } 35410770Ssam if ((bp = dp->b_actf) == NULL) { 35510770Ssam um->um_tab.b_actf = dp->b_forw; 35610770Ssam goto loop; 35710770Ssam } 35810770Ssam /* 35910770Ssam * Mark controller busy, and 36013091Ssam * determine destination. 36110770Ssam */ 36210770Ssam um->um_tab.b_active++; 36324741Sbloom ui = rldinfo[rlunit(bp->b_dev)]; /* Controller */ 36424741Sbloom bn = bp->b_blkno; /* 512 byte Block number */ 36510770Ssam cyl = bp->b_cylin << 1; /* Cylinder */ 36610770Ssam cyl |= (bn / rl02.nbpt) & 1; /* Get head required */ 36710770Ssam sn = (bn % rl02.nbpt) << 1; /* Sector number */ 36810770Ssam rladdr = (struct rldevice *)ui->ui_addr; 36912452Ssam rlwait(rladdr); 37010770Ssam rladdr->rlda.rw = cyl<<6 | sn; 37110770Ssam /* save away current transfers drive status */ 37210770Ssam st->rl_dn = ui->ui_slave; 37310770Ssam st->rl_cylnhd = cyl; 37410770Ssam st->rl_bleft = bp->b_bcount; 37510770Ssam st->rl_bpart = rl02.btrak - (sn * NRLBPSC); 37613091Ssam /* 37713091Ssam * RL02 must seek between cylinders and between tracks, 37813091Ssam * determine maximum data transfer at this time. 37913091Ssam */ 38013091Ssam if (st->rl_bleft < st->rl_bpart) 38110770Ssam st->rl_bpart = st->rl_bleft; 38210770Ssam rladdr->rlmp.rw = -(st->rl_bpart >> 1); 38310770Ssam if (bp->b_flags & B_READ) 38410770Ssam cmd = RL_IE | RL_READ | (ui->ui_slave << 8); 38510770Ssam else 38610770Ssam cmd = RL_IE | RL_WRITE | (ui->ui_slave << 8); 38710770Ssam um->um_cmd = cmd; 38810770Ssam (void) ubago(ui); 38910770Ssam } 39010770Ssam 39110770Ssam rldgo(um) 39210770Ssam register struct uba_ctlr *um; 39310770Ssam { 39410770Ssam register struct rldevice *rladdr = (struct rldevice *)um->um_addr; 39510770Ssam 39610770Ssam rladdr->rlba = um->um_ubinfo; 39710770Ssam rladdr->rlcs = um->um_cmd|((um->um_ubinfo>>12)&RL_BAE); 39810770Ssam } 39910770Ssam 40010770Ssam /* 40110770Ssam * Handle a disk interrupt. 40210770Ssam */ 40310770Ssam rlintr(rl21) 40410770Ssam register rl21; 40510770Ssam { 40610770Ssam register struct buf *bp, *dp; 40710770Ssam register struct uba_ctlr *um = rlminfo[rl21]; 40810770Ssam register struct uba_device *ui; 40910770Ssam register struct rldevice *rladdr = (struct rldevice *)um->um_addr; 41010770Ssam register unit; 41110770Ssam struct rl_softc *rl = &rl_softc[um->um_ctlr]; 41210770Ssam struct rl_stat *st = &rl_stat[um->um_ctlr]; 41313091Ssam int as = rl->rl_softas, status; 41410770Ssam 41510770Ssam rl->rl_wticks = 0; 41610770Ssam rl->rl_softas = 0; 41710770Ssam dp = um->um_tab.b_actf; 41810770Ssam bp = dp->b_actf; 41924741Sbloom ui = rldinfo[rlunit(bp->b_dev)]; 42013091Ssam dk_busy &= ~(1 << ui->ui_dk); 42110770Ssam 42210770Ssam /* 42310770Ssam * Check for and process errors on 42410770Ssam * either the drive or the controller. 42510770Ssam */ 42610770Ssam if (rladdr->rlcs & RL_ERR) { 42710770Ssam u_short err; 42813091Ssam rlwait(rladdr); 42910770Ssam err = rladdr->rlcs; 43010770Ssam /* get staus and reset controller */ 43110770Ssam rladdr->rlda.getstat = RL_GSTAT; 43210770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_GETSTAT; 43310770Ssam rlwait(rladdr); 43410770Ssam status = rladdr->rlmp.getstat; 43510770Ssam /* reset drive */ 43610770Ssam rladdr->rlda.getstat = RL_RESET; 43710770Ssam rladdr->rlcs = (ui->ui_slave <<8) | RL_GETSTAT; /* Get status*/ 43810770Ssam rlwait(rladdr); 43913091Ssam if ((status & RLMP_WL) == RLMP_WL) { 44010770Ssam /* 44110770Ssam * Give up on write protected devices 44210770Ssam * immediately. 44310770Ssam */ 44424741Sbloom printf("rl%d: write protected\n", rlunit(bp->b_dev)); 44510770Ssam bp->b_flags |= B_ERROR; 44610770Ssam } else if (++um->um_tab.b_errcnt > 10) { 44710770Ssam /* 44810770Ssam * After 10 retries give up. 44910770Ssam */ 45010770Ssam harderr(bp, "rl"); 45113091Ssam printf("cs=%b mp=%b\n", err, RLCS_BITS, 45213091Ssam status, RLER_BITS); 45310770Ssam bp->b_flags |= B_ERROR; 45410770Ssam } else 45510770Ssam um->um_tab.b_active = 0; /* force retry */ 45613091Ssam /* determine disk position */ 45710770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_RHDR; 45810770Ssam rlwait(rladdr); 45913091Ssam /* save disk drive position */ 46013091Ssam st->rl_cyl[ui->ui_slave] = 46113091Ssam (rladdr->rlmp.readhdr & 0177700) >> 6; 46210770Ssam } 46310770Ssam /* 46410770Ssam * If still ``active'', then don't need any more retries. 46510770Ssam */ 46610770Ssam if (um->um_tab.b_active) { 46710770Ssam /* RL02 check if more data from previous request */ 46813091Ssam if ((bp->b_flags & B_ERROR) == 0 && 46913091Ssam (int)(st->rl_bleft -= st->rl_bpart) > 0) { 47010770Ssam /* 47113091Ssam * The following code was modeled from the rk07 47210770Ssam * driver when an ECC error occured. It has to 47310770Ssam * fix the bits then restart the transfer which is 47410770Ssam * what we have to do (restart transfer). 47510770Ssam */ 47610770Ssam int reg, npf, o, cmd, ubaddr, diff, head; 47710770Ssam 47810770Ssam /* seek to next head/track */ 47910770Ssam /* increment head and/or cylinder */ 48010770Ssam st->rl_cylnhd++; 48110770Ssam diff = (st->rl_cyl[ui->ui_slave] >> 1) - 48210770Ssam (st->rl_cylnhd >> 1); 48310770Ssam st->rl_cyl[ui->ui_slave] = st->rl_cylnhd; 48410770Ssam head = st->rl_cylnhd & 1; 48513091Ssam rlwait(rladdr); 48613091Ssam if (diff < 0) 48713091Ssam rladdr->rlda.seek = 48813091Ssam -diff << 7 | RLDA_HGH | head << 4; 48910770Ssam else 49013091Ssam rladdr->rlda.seek = 49113091Ssam diff << 7 | RLDA_LOW | head << 4; 49210770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_SEEK; 49310770Ssam npf = btop( bp->b_bcount - st->rl_bleft ); 49410770Ssam reg = btop(um->um_ubinfo&0x3ffff) + npf; 49510770Ssam o = (int)bp->b_un.b_addr & PGOFSET; 49610770Ssam ubapurge(um); 49710770Ssam um->um_tab.b_active++; 49813091Ssam rlwait(rladdr); 49910770Ssam rladdr->rlda.rw = st->rl_cylnhd << 6; 50013091Ssam if (st->rl_bleft < (st->rl_bpart = rl02.btrak)) 50110770Ssam st->rl_bpart = st->rl_bleft; 50210770Ssam rladdr->rlmp.rw = -(st->rl_bpart >> 1); 50310770Ssam cmd = (bp->b_flags&B_READ ? RL_READ : RL_WRITE) | 50413091Ssam RL_IE | (ui->ui_slave << 8); 50510770Ssam ubaddr = (int)ptob(reg) + o; 50610770Ssam cmd |= ((ubaddr >> 12) & RL_BAE); 50710770Ssam rladdr->rlba = ubaddr; 50810770Ssam rladdr->rlcs = cmd; 50910770Ssam return; 51010770Ssam } 51110770Ssam um->um_tab.b_active = 0; 51210770Ssam um->um_tab.b_errcnt = 0; 51310770Ssam dp->b_active = 0; 51410770Ssam dp->b_errcnt = 0; 51510770Ssam /* "b_resid" words remaining after error */ 51610770Ssam bp->b_resid = st->rl_bleft; 51710770Ssam um->um_tab.b_actf = dp->b_forw; 51810770Ssam dp->b_actf = bp->av_forw; 51910770Ssam st->rl_dn = -1; 52010770Ssam st->rl_bpart = st->rl_bleft = 0; 52110770Ssam iodone(bp); 52210770Ssam /* 52310770Ssam * If this unit has more work to do, 52410770Ssam * then start it up right away. 52510770Ssam */ 52610770Ssam if (dp->b_actf) 52713091Ssam rlustart(ui); 52810770Ssam as &= ~(1<<ui->ui_slave); 52910770Ssam } else 53010770Ssam as |= (1<<ui->ui_slave); 53110770Ssam ubadone(um); 53210770Ssam /* reset state info */ 53310770Ssam st->rl_dn = -1; 53410770Ssam st->rl_cylnhd = st->rl_bpart = st->rl_bleft = 0; 53510770Ssam /* 53610770Ssam * Process other units which need attention. 53710770Ssam * For each unit which needs attention, call 53810770Ssam * the unit start routine to place the slave 53910770Ssam * on the controller device queue. 54010770Ssam */ 541*26369Skarels while (unit = ffs((long)as)) { 54210770Ssam unit--; /* was 1 origin */ 54310770Ssam as &= ~(1<<unit); 54413091Ssam rlustart(rlip[rl21][unit]); 54510770Ssam } 54610770Ssam /* 54710770Ssam * If the controller is not transferring, but 54810770Ssam * there are devices ready to transfer, start 54910770Ssam * the controller. 55010770Ssam */ 55110770Ssam if (um->um_tab.b_actf && um->um_tab.b_active == 0) 55213091Ssam rlstart(um); 55310770Ssam } 55410770Ssam 55512452Ssam rlwait(rladdr) 55612452Ssam register struct rldevice *rladdr; 55710770Ssam { 55812452Ssam 55910770Ssam while ((rladdr->rlcs & RL_CRDY) == 0) 56013091Ssam ; 56110770Ssam } 56210770Ssam 56312452Ssam rlread(dev, uio) 56410770Ssam dev_t dev; 56512452Ssam struct uio *uio; 56610770Ssam { 56724741Sbloom register int unit = rlunit(dev); 56810770Ssam 56910770Ssam if (unit >= NRL) 57012452Ssam return (ENXIO); 57112452Ssam return (physio(rlstrategy, &rrlbuf[unit], dev, B_READ, minphys, uio)); 57210770Ssam } 57310770Ssam 57412452Ssam rlwrite(dev, uio) 57510770Ssam dev_t dev; 57612452Ssam struct uio *uio; 57710770Ssam { 57824741Sbloom register int unit = rlunit(dev); 57910770Ssam 58010770Ssam if (unit >= NRL) 58112452Ssam return (ENXIO); 58212452Ssam return (physio(rlstrategy, &rrlbuf[unit], dev, B_WRITE, minphys, uio)); 58310770Ssam } 58410770Ssam 58510770Ssam /* 58610770Ssam * Reset driver after UBA init. 58710770Ssam * Cancel software state of all pending transfers 58810770Ssam * and restart all units and the controller. 58910770Ssam */ 59010770Ssam rlreset(uban) 59110770Ssam int uban; 59210770Ssam { 59310770Ssam register struct uba_ctlr *um; 59410770Ssam register struct uba_device *ui; 59510770Ssam register struct rldevice *rladdr; 59610770Ssam register struct rl_stat *st; 59713091Ssam register int rl21, unit; 59810770Ssam 59910770Ssam for (rl21 = 0; rl21 < NHL; rl21++) { 60010770Ssam if ((um = rlminfo[rl21]) == 0 || um->um_ubanum != uban || 60110770Ssam um->um_alive == 0) 60210770Ssam continue; 60313091Ssam printf(" hl%d", rl21); 60410770Ssam rladdr = (struct rldevice *)um->um_addr; 60510770Ssam st = &rl_stat[rl21]; 60610770Ssam um->um_tab.b_active = 0; 60710770Ssam um->um_tab.b_actf = um->um_tab.b_actl = 0; 60810770Ssam if (um->um_ubinfo) { 60910770Ssam printf("<%d>", (um->um_ubinfo>>28)&0xf); 61012452Ssam um->um_ubinfo = 0; 61110770Ssam } 61210770Ssam /* reset controller */ 61310770Ssam st->rl_dn = -1; 61410770Ssam st->rl_cylnhd = 0; 61510770Ssam st->rl_bleft = 0; 61610770Ssam st->rl_bpart = 0; 61712452Ssam rlwait(rladdr); 61810770Ssam for (unit = 0; unit < NRL; unit++) { 61910770Ssam rladdr->rlcs = (unit << 8) | RL_GETSTAT; 62012452Ssam rlwait(rladdr); 62110770Ssam /* Determine disk posistion */ 62210770Ssam rladdr->rlcs = (unit << 8) | RL_RHDR; 62310770Ssam rlwait(rladdr); 62410770Ssam /* save disk drive posistion */ 62510770Ssam st->rl_cyl[unit] = 62610770Ssam (rladdr->rlmp.readhdr & 0177700) >> 6; 62710770Ssam if ((ui = rldinfo[unit]) == 0) 62810770Ssam continue; 62910770Ssam if (ui->ui_alive == 0 || ui->ui_mi != um) 63010770Ssam continue; 63110770Ssam rlutab[unit].b_active = 0; 63213091Ssam rlustart(ui); 63310770Ssam } 63413091Ssam rlstart(um); 63510770Ssam } 63610770Ssam } 63710770Ssam 63810770Ssam /* 63910770Ssam * Wake up every second and if an interrupt is pending 64010770Ssam * but nothing has happened increment a counter. 64110770Ssam * If nothing happens for 20 seconds, reset the UNIBUS 64210770Ssam * and begin anew. 64310770Ssam */ 64410770Ssam rlwatch() 64510770Ssam { 64610770Ssam register struct uba_ctlr *um; 64710770Ssam register rl21, unit; 64810770Ssam register struct rl_softc *rl; 64910770Ssam 65010770Ssam timeout(rlwatch, (caddr_t)0, hz); 65110770Ssam for (rl21 = 0; rl21 < NHL; rl21++) { 65210770Ssam um = rlminfo[rl21]; 65310770Ssam if (um == 0 || um->um_alive == 0) 65410770Ssam continue; 65510770Ssam rl = &rl_softc[rl21]; 65610770Ssam if (um->um_tab.b_active == 0) { 65710770Ssam for (unit = 0; unit < NRL; unit++) 65810770Ssam if (rlutab[unit].b_active && 65910770Ssam rldinfo[unit]->ui_mi == um) 66010770Ssam goto active; 66110770Ssam rl->rl_wticks = 0; 66210770Ssam continue; 66310770Ssam } 66410770Ssam active: 66510770Ssam rl->rl_wticks++; 66610770Ssam if (rl->rl_wticks >= 20) { 66710770Ssam rl->rl_wticks = 0; 66810770Ssam printf("hl%d: lost interrupt\n", rl21); 66910770Ssam ubareset(um->um_ubanum); 67010770Ssam } 67110770Ssam } 67210770Ssam } 67310770Ssam 67413091Ssam /*ARGSUSED*/ 67510770Ssam rldump(dev) 67610770Ssam dev_t dev; 67710770Ssam { 67813091Ssam 67910770Ssam /* don't think there is room on swap for it anyway. */ 68010770Ssam } 68113272Ssam 68213272Ssam rlsize(dev) 68313272Ssam dev_t dev; 68413272Ssam { 68524741Sbloom register int unit = rlunit(dev); 68613272Ssam register struct uba_device *ui; 68713272Ssam 68813272Ssam if (unit >= NRL || (ui = rldinfo[unit]) == 0 || ui->ui_alive == 0) 68913272Ssam return (-1); 69013272Ssam return (rl02.sizes[minor(dev) & 07].nblocks); 69113272Ssam } 69212504Ssam #endif 693