1*12504Ssam /* rl.c 4.3 83/05/18 */ 210770Ssam 310770Ssam #include "rl.h" 412452Ssam #if NRL > 0 510770Ssam /* 610770Ssam * UNIBUS RL02 disk driver 710770Ssam * (not yet converted to 4.1c) 810770Ssam */ 910770Ssam 1010770Ssam #include "../h/param.h" 1110770Ssam #include "../h/systm.h" 1210770Ssam #include "../h/cpu.h" 1310770Ssam #include "../h/nexus.h" 1410770Ssam #include "../h/dk.h" 1510770Ssam #include "../h/buf.h" 1610770Ssam #include "../h/conf.h" 1710770Ssam #include "../h/dir.h" 1810770Ssam #include "../h/user.h" 1910770Ssam #include "../h/map.h" 2010770Ssam #include "../h/pte.h" 2110770Ssam #include "../h/mtpr.h" 2210770Ssam #include "../h/vm.h" 2310770Ssam #include "../h/ubavar.h" 2410770Ssam #include "../h/ubareg.h" 2510770Ssam #include "../h/cmap.h" 2610770Ssam 2710770Ssam #include "../h/rlreg.h" 2810770Ssam 2910770Ssam /* Pending Controller items and statistics */ 3010770Ssam struct rl_softc { 3110770Ssam int rl_softas; /* Attention sumary, (seeks pending) */ 3210770Ssam int rl_ndrive; /* Number of drives on controller */ 3310770Ssam int rl_wticks; /* Monitor time for function */ 3410770Ssam } rl_softc[NHL]; 3510770Ssam 3610770Ssam /* 3710770Ssam * this struct is used to keep the state of the controller for the last 3810770Ssam * transfer done. Since only one transfer can be done at a time per 3910770Ssam * controller, only allocate one for each controller. 4010770Ssam */ 4110770Ssam struct rl_stat { 4210770Ssam short rl_cyl[4]; /* Current cylinder for each drive */ 4310770Ssam short rl_dn; /* drive number currently transferring */ 4410770Ssam short rl_cylnhd; /* current cylinder and head of transfer */ 4510770Ssam u_short rl_bleft; /* bytes left to transfer */ 4610770Ssam u_short rl_bpart; /* bytes transferred */ 4710770Ssam } rl_stat[NHL]; 4810770Ssam 4910770Ssam /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 5010770Ssam struct size { 5110770Ssam daddr_t nblocks; 5210770Ssam int cyloff; 5310770Ssam } rl02_sizes[8] = { 5410770Ssam 14440, 0, /* A=cyl 0 thru 360 */ 5510770Ssam 6040, 361, /* B=cyl 361 thru 511 */ 5610770Ssam 20480, 0, /* C=cyl 0 thru 511 */ 5710770Ssam 0, 0, /* D= Not Defined */ 5810770Ssam 0, 0, /* E= Not Defined */ 5910770Ssam 0, 0, /* F= Not Defined */ 6010770Ssam 0, 0, /* G= Not Defined */ 6110770Ssam 0, 0, /* H= Not Defined */ 6210770Ssam }; 6310770Ssam /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 6410770Ssam 6510770Ssam int rlprobe(), rlslave(), rlattach(), rldgo(), rlintr(); 6610770Ssam struct uba_ctlr *rlminfo[NHL]; 6710770Ssam struct uba_device *rldinfo[NRL]; 6810770Ssam struct uba_device *rlip[NHL][4]; 6910770Ssam 7010770Ssam /* RL02 driver structure */ 7110770Ssam u_short rlstd[] = { 0174400 }; 7210770Ssam struct uba_driver hldriver = 7310770Ssam { rlprobe, rlslave, rlattach, rldgo, rlstd, "rl", rldinfo, "hl", rlminfo }; 7410770Ssam 7510770Ssam /* User table per controller */ 7610770Ssam struct buf rlutab[NRL]; 7710770Ssam 7810770Ssam /* RL02 drive structure */ 7910770Ssam struct RL02 { 8010770Ssam short nbpt; /* Number of 512 byte blocks/track */ 8110770Ssam short ntrak; 8210770Ssam short nbpc; /* Number of 512 byte blocks/cylinder */ 8310770Ssam short ncyl; 8410770Ssam short btrak; /* Number of bytes/track */ 8510770Ssam struct size *sizes; 8610770Ssam } rl02 = { 8710770Ssam 20, 2, 40, 512, 20*512, rl02_sizes /* rl02/DEC*/ 8810770Ssam }; 8910770Ssam 9010770Ssam struct buf rrlbuf[NRL]; 9110770Ssam 9210770Ssam #define b_cylin b_resid /* Last seek as CYL<<1 | HD */ 9310770Ssam 9410770Ssam #ifdef INTRLVE 9510770Ssam daddr_t dkblock(); 9610770Ssam #endif 9710770Ssam 9810770Ssam int rlwstart, rlwatch(); /* Have started guardian */ 9910770Ssam 10010770Ssam /* Check that controller exists */ 10110770Ssam /*ARGSUSED*/ 10210770Ssam rlprobe(reg) 10310770Ssam caddr_t reg; 10410770Ssam { 10510770Ssam register int br, cvec; 10610770Ssam 10710770Ssam #ifdef lint 10810770Ssam br = 0; cvec = br; br = cvec; 10910770Ssam #endif 11010770Ssam ((struct rldevice *)reg)->rlcs = RL_IE | RL_NOOP; /* Enable intrpt */ 11110770Ssam DELAY(10); /* Ensure interrupt takes place (10 microsec ) */ 11210770Ssam ((struct rldevice *)reg)->rlcs &= ~RL_IE; /* Disable intrpt */ 11312452Ssam return (sizeof (struct rldevice)); 11410770Ssam } 11510770Ssam 11610770Ssam /* Check that drive exists and is functional*/ 11710770Ssam rlslave(ui, reg) 11810770Ssam struct uba_device *ui; 11910770Ssam caddr_t reg; 12010770Ssam { 12110770Ssam register struct rldevice *rladdr = (struct rldevice *)reg; 12210770Ssam short ctr = 0; 12310770Ssam 12410770Ssam /* 12510770Ssam * DEC reports that: 12610770Ssam * For some unknown reason the RL02 (seems to be only drive 1) 12710770Ssam * does not return a valid drive status the first time that a 12810770Ssam * GET STATUS request is issued for the drive, in fact it can 12910770Ssam * take up to three or more GET STATUS requests to obtain the 13010770Ssam * correct status. 13110770Ssam * In order to overcome this, the driver has been modified to 13210770Ssam * issue a GET STATUS request and validate the drive status 13310770Ssam * returned. If a valid status is not returned after eight 13410770Ssam * attempts, then an error message is printed. 13510770Ssam */ 13610770Ssam do { 13710770Ssam rladdr->rlda.getstat = RL_RESET; 13810770Ssam rladdr->rlcs = (ui->ui_slave <<8) | RL_GETSTAT; /* Get status*/ 13910770Ssam rlwait(rladdr); 14010770Ssam } while( (rladdr->rlmp.getstat&RLMP_STATUS) != RLMP_STATOK && ++ctr<8 ); 14110770Ssam 14210770Ssam 14310770Ssam if ((rladdr->rlcs & RL_DE) || (ctr >= 8)) 14410770Ssam return (0); /* Error return */ 14510770Ssam if ((rladdr->rlmp.getstat & RLMP_DT) == 0 ) { /* NO RL01'S */ 14610770Ssam printf("rl01 drives not supported (drive %d)\n", ui->ui_slave ); 14710770Ssam return(0); 14810770Ssam } 14910770Ssam return (1); 15010770Ssam } 15110770Ssam 15210770Ssam /* Initialize controller */ 15310770Ssam rlattach(ui) 15410770Ssam register struct uba_device *ui; 15510770Ssam { 15610770Ssam register struct rldevice *rladdr; 15710770Ssam 15810770Ssam if (rlwstart == 0) { 15910770Ssam timeout(rlwatch, (caddr_t)0, hz); /* Watch for lost intr */ 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; 16610770Ssam rl_softc[ui->ui_ctlr].rl_ndrive++; /* increment device/ctrl */ 16710770Ssam rladdr = (struct rldevice *)ui->ui_addr; 16810770Ssam 16910770Ssam /* reset controller */ 17010770Ssam rladdr->rlda.getstat = RL_RESET; /* SHOULD BE REPEATED? */ 17110770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_GETSTAT; /* Reset DE bit */ 17210770Ssam rlwait(rladdr); 17310770Ssam 17410770Ssam /* Determine disk posistion */ 17510770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_RHDR; 17610770Ssam rlwait(rladdr); 17710770Ssam 17810770Ssam /* save disk drive posistion */ 17910770Ssam rl_stat[ui->ui_ctlr].rl_cyl[ui->ui_slave] = 18010770Ssam (rladdr->rlmp.readhdr & 0177700) >> 6; 18110770Ssam rl_stat[ui->ui_ctlr].rl_dn = -1; 18210770Ssam } 18310770Ssam 18412452Ssam rlopen(dev) 18512452Ssam dev_t dev; 18612452Ssam { 18712452Ssam register int unit = minor(dev) >> 3; 18812452Ssam register struct uba_device *mi; 18912452Ssam 19012452Ssam if (unit >= NRL || (ui = rldinfo[unit]) == 0 || ui->ui_alive == 0) 19112452Ssam return (ENXIO); 19212452Ssam return (0); 19312452Ssam } 19412452Ssam 19510770Ssam rlstrategy(bp) 19610770Ssam register struct buf *bp; 19710770Ssam { 19810770Ssam register struct uba_device *ui; 19910770Ssam register int drive; 20010770Ssam register struct buf *dp; 20110770Ssam int partition = minor(bp->b_dev) & 07; 20210770Ssam long bn, sz; 20310770Ssam 20410770Ssam sz = (bp->b_bcount+511) >> 9; /* Blocks to transfer */ 20510770Ssam 20610770Ssam drive = dkunit(bp); /* Drive number */ 20710770Ssam if (drive >= NRL) 20810770Ssam goto bad; 20910770Ssam ui = rldinfo[drive]; /* Controller uba_device */ 21010770Ssam if (ui == 0 || ui->ui_alive == 0) 21110770Ssam goto bad; 21210770Ssam if (bp->b_blkno < 0 || 21310770Ssam (bn = dkblock(bp))+sz > rl02.sizes[partition].nblocks) 21410770Ssam goto bad; 21510770Ssam 21610770Ssam /* bn is in 512 byte block size */ 21710770Ssam bp->b_cylin = bn/rl02.nbpc + rl02.sizes[partition].cyloff; 21810770Ssam (void) spl5(); 21910770Ssam dp = &rlutab[ui->ui_unit]; 22010770Ssam disksort(dp, bp); 22110770Ssam if (dp->b_active == 0) { 22210770Ssam (void) rlustart(ui); 22310770Ssam bp = &ui->ui_mi->um_tab; 22410770Ssam if (bp->b_actf && bp->b_active == 0) 22510770Ssam (void) rlstart(ui->ui_mi); 22610770Ssam } 22710770Ssam (void) spl0(); 22810770Ssam return; 22910770Ssam 23010770Ssam bad: 23110770Ssam bp->b_flags |= B_ERROR; 23210770Ssam iodone(bp); 23310770Ssam return; 23410770Ssam } 23510770Ssam 23610770Ssam /* 23710770Ssam * Unit start routine. 23810770Ssam * Seek the drive to be where the data is 23910770Ssam * and then generate another interrupt 24010770Ssam * to actually start the transfer. 24110770Ssam */ 24210770Ssam rlustart(ui) 24310770Ssam register struct uba_device *ui; 24410770Ssam { 24510770Ssam register struct buf *bp, *dp; 24610770Ssam register struct uba_ctlr *um; 24710770Ssam register struct rldevice *rladdr; 24810770Ssam daddr_t bn; 24910770Ssam short cyl, sn, hd, diff; 25010770Ssam 25110770Ssam if (ui == 0) 25210770Ssam return (0); 25310770Ssam um = ui->ui_mi; 25410770Ssam dk_busy &= ~(1<<ui->ui_dk); /* Kernel define, drives busy */ 25510770Ssam dp = &rlutab[ui->ui_unit]; 25610770Ssam if ((bp = dp->b_actf) == NULL) 25710770Ssam goto out; 25810770Ssam /* 25910770Ssam * If the controller is active, just remember 26010770Ssam * that this device has to be positioned... 26110770Ssam */ 26210770Ssam if (um->um_tab.b_active) { 26310770Ssam rl_softc[um->um_ctlr].rl_softas |= 1<<ui->ui_slave; 26410770Ssam return (0); 26510770Ssam } 26610770Ssam /* 26710770Ssam * If we have already positioned this drive, 26810770Ssam * then just put it on the ready queue. 26910770Ssam */ 27010770Ssam if (dp->b_active) 27110770Ssam goto done; 27210770Ssam dp->b_active = 1; /* Posistioning drive */ 27310770Ssam rladdr = (struct rldevice *)um->um_addr; 27410770Ssam 27510770Ssam /* 27610770Ssam * Figure out where this transfer is going to 27710770Ssam * and see if we are seeked correctly. 27810770Ssam */ 27910770Ssam bn = dkblock(bp); /* Block # desired */ 28010770Ssam /* 28110770Ssam * these next two look funky... but we need to map 28210770Ssam * 512 byte logical disk blocks to 256 byte sectors. 28310770Ssam * (rl02's are stupid). 28410770Ssam */ 28510770Ssam sn = (bn % rl02.nbpt) << 1; /* Sector # desired */ 28610770Ssam hd = (bn / rl02.nbpt) & 1; /* Get head required */ 28710770Ssam 28810770Ssam diff = (rl_stat[um->um_ctlr].rl_cyl[ui->ui_slave] >> 1) - bp->b_cylin; 28910770Ssam if ( diff == 0 && (rl_stat[um->um_ctlr].rl_cyl[ui->ui_slave] & 1) == hd) 29010770Ssam goto done; /* on cylinder and head */ 29110770Ssam 29210770Ssam search: 29310770Ssam /* 29410770Ssam * Not at correct position. 29510770Ssam */ 29610770Ssam 29710770Ssam rl_stat[um->um_ctlr].rl_cyl[ui->ui_slave] = (bp->b_cylin << 1) | hd; 29810770Ssam 29910770Ssam if (diff < 0) 30010770Ssam rladdr->rlda.seek = -diff << 7 | RLDA_HGH | hd << 4; 30110770Ssam else 30210770Ssam rladdr->rlda.seek = diff << 7 | RLDA_LOW | hd << 4; 30310770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_SEEK; 30410770Ssam 30510770Ssam /* 30610770Ssam * Mark unit busy for iostat. 30710770Ssam */ 30810770Ssam if (ui->ui_dk >= 0) { 30910770Ssam dk_busy |= 1<<ui->ui_dk; 31010770Ssam dk_seek[ui->ui_dk]++; 31110770Ssam } 31212452Ssam rlwait(rladdr); 31310770Ssam 31410770Ssam /* 31510770Ssam * fall through since we are now at the correct cylinder 31610770Ssam */ 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 out: 33310770Ssam return (0); 33410770Ssam } 33510770Ssam 33610770Ssam /* 33710770Ssam * Start up a transfer on a drive. 33810770Ssam */ 33910770Ssam rlstart(um) 34010770Ssam register struct uba_ctlr *um; 34110770Ssam { 34210770Ssam register struct buf *bp, *dp; 34310770Ssam register struct uba_device *ui; 34410770Ssam register struct rldevice *rladdr; 34510770Ssam register struct rl_stat *st = &rl_stat[um->um_ctlr]; 34610770Ssam daddr_t bn; 34710770Ssam short sn, cyl, cmd; 34810770Ssam 34910770Ssam loop: 35010770Ssam /* 35110770Ssam * Pull a request off the controller queue 35210770Ssam */ 35310770Ssam if ((dp = um->um_tab.b_actf) == NULL) { 35410770Ssam st->rl_dn = -1; 35510770Ssam st->rl_cylnhd = 0; 35610770Ssam st->rl_bleft = 0; 35710770Ssam st->rl_bpart = 0; 35810770Ssam return (0); 35910770Ssam } 36010770Ssam if ((bp = dp->b_actf) == NULL) { 36110770Ssam um->um_tab.b_actf = dp->b_forw; 36210770Ssam goto loop; 36310770Ssam } 36410770Ssam /* 36510770Ssam * Mark controller busy, and 36610770Ssam * determine destinationst. 36710770Ssam */ 36810770Ssam um->um_tab.b_active++; 36910770Ssam ui = rldinfo[dkunit(bp)]; /* Controller */ 37010770Ssam bn = dkblock(bp); /* 512 byte Block number */ 37110770Ssam cyl = bp->b_cylin << 1; /* Cylinder */ 37210770Ssam cyl |= (bn / rl02.nbpt) & 1; /* Get head required */ 37310770Ssam sn = (bn % rl02.nbpt) << 1; /* Sector number */ 37410770Ssam rladdr = (struct rldevice *)ui->ui_addr; 37510770Ssam 37610770Ssam /* 37710770Ssam * Check that controller is ready 37810770Ssam */ 37912452Ssam rlwait(rladdr); 38010770Ssam 38110770Ssam /* 38210770Ssam * Setup for the transfer, and get in the 38310770Ssam * UNIBUS adaptor queue. 38410770Ssam */ 38510770Ssam rladdr->rlda.rw = cyl<<6 | sn; 38610770Ssam 38710770Ssam /* save away current transfers drive status */ 38810770Ssam st->rl_dn = ui->ui_slave; 38910770Ssam st->rl_cylnhd = cyl; 39010770Ssam st->rl_bleft = bp->b_bcount; 39110770Ssam st->rl_bpart = rl02.btrak - (sn * NRLBPSC); 39210770Ssam 39310770Ssam /* RL02 must seek between cylinders and between tracks */ 39410770Ssam /* Determine maximum data transfer at this time */ 39510770Ssam if( st->rl_bleft < st->rl_bpart) 39610770Ssam st->rl_bpart = st->rl_bleft; 39710770Ssam 39810770Ssam rladdr->rlmp.rw = -(st->rl_bpart >> 1); 39910770Ssam if (bp->b_flags & B_READ) 40010770Ssam cmd = RL_IE | RL_READ | (ui->ui_slave << 8); 40110770Ssam else 40210770Ssam cmd = RL_IE | RL_WRITE | (ui->ui_slave << 8); 40310770Ssam um->um_cmd = cmd; 40410770Ssam (void) ubago(ui); 40510770Ssam return (1); 40610770Ssam } 40710770Ssam 40810770Ssam /* 40910770Ssam * Now all ready to go, stuff the registers. 41010770Ssam */ 41110770Ssam rldgo(um) 41210770Ssam register struct uba_ctlr *um; 41310770Ssam { 41410770Ssam register struct rldevice *rladdr = (struct rldevice *)um->um_addr; 41510770Ssam 41610770Ssam 41710770Ssam /* Place in unibus address for transfer (lower 18 bits of um_ubinfo) */ 41810770Ssam /* Then execute instruction */ 41910770Ssam rladdr->rlba = um->um_ubinfo; 42010770Ssam rladdr->rlcs = um->um_cmd|((um->um_ubinfo>>12)&RL_BAE); 42110770Ssam } 42210770Ssam 42310770Ssam /* 42410770Ssam * Handle a disk interrupt. 42510770Ssam */ 42610770Ssam rlintr(rl21) 42710770Ssam register rl21; 42810770Ssam { 42910770Ssam register struct buf *bp, *dp; 43010770Ssam register struct uba_ctlr *um = rlminfo[rl21]; 43110770Ssam register struct uba_device *ui; 43210770Ssam register struct rldevice *rladdr = (struct rldevice *)um->um_addr; 43310770Ssam register unit; 43410770Ssam struct rl_softc *rl = &rl_softc[um->um_ctlr]; 43510770Ssam struct rl_stat *st = &rl_stat[um->um_ctlr]; 43610770Ssam int as = rl->rl_softas; 43710770Ssam int needie = 1, waitdry, status; 43810770Ssam 43910770Ssam rl->rl_wticks = 0; 44010770Ssam rl->rl_softas = 0; 44110770Ssam 44210770Ssam /* 44310770Ssam * Get device and block structures, and a pointer 44410770Ssam * to the uba_device for the drive. 44510770Ssam */ 44610770Ssam dp = um->um_tab.b_actf; 44710770Ssam bp = dp->b_actf; 44810770Ssam ui = rldinfo[dkunit(bp)]; 44910770Ssam dk_busy &= ~(1 << ui->ui_dk); /* Clear busy bit */ 45010770Ssam 45110770Ssam /* 45210770Ssam * Check for and process errors on 45310770Ssam * either the drive or the controller. 45410770Ssam */ 45510770Ssam if (rladdr->rlcs & RL_ERR) { 45610770Ssam u_short err; 45710770Ssam rlwait( rladdr ); 45810770Ssam 45910770Ssam err = rladdr->rlcs; 46010770Ssam 46110770Ssam /* get staus and reset controller */ 46210770Ssam rladdr->rlda.getstat = RL_GSTAT; 46310770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_GETSTAT; 46410770Ssam rlwait(rladdr); 46510770Ssam status = rladdr->rlmp.getstat; 46610770Ssam 46710770Ssam /* reset drive */ 46810770Ssam rladdr->rlda.getstat = RL_RESET; 46910770Ssam rladdr->rlcs = (ui->ui_slave <<8) | RL_GETSTAT; /* Get status*/ 47010770Ssam rlwait(rladdr); 47110770Ssam 47210770Ssam if ( (status & RLMP_WL) == RLMP_WL ) { 47310770Ssam /* 47410770Ssam * Give up on write protected devices 47510770Ssam * immediately. 47610770Ssam */ 47710770Ssam printf("rl%d: write protected\n", dkunit(bp)); 47810770Ssam bp->b_flags |= B_ERROR; 47910770Ssam } else if (++um->um_tab.b_errcnt > 10) { 48010770Ssam /* 48110770Ssam * After 10 retries give up. 48210770Ssam */ 48310770Ssam harderr(bp, "rl"); 48410770Ssam printf("cs=%b mp=%b\n", 48510770Ssam err, RLCS_BITS, status, RLER_BITS); 48610770Ssam 48710770Ssam bp->b_flags |= B_ERROR; 48810770Ssam } else 48910770Ssam um->um_tab.b_active = 0; /* force retry */ 49010770Ssam 49110770Ssam /* Determine disk posistion */ 49210770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_RHDR; 49310770Ssam rlwait(rladdr); 49410770Ssam 49510770Ssam /* save disk drive posistion */ 49610770Ssam st->rl_cyl[ui->ui_slave] = (rladdr->rlmp.readhdr & 0177700) >> 6; 49710770Ssam } 49810770Ssam 49910770Ssam /* 50010770Ssam * If still ``active'', then don't need any more retries. 50110770Ssam */ 50210770Ssam if (um->um_tab.b_active) { 50310770Ssam /* RL02 check if more data from previous request */ 50410770Ssam if ( (bp->b_flags & B_ERROR) == 0 && 50510770Ssam (st->rl_bleft -= st->rl_bpart) > 0 ) { 50610770Ssam /* 50710770Ssam * the following code was modeled from the rk07 50810770Ssam * driver when an ECC error occured. It has to 50910770Ssam * fix the bits then restart the transfer which is 51010770Ssam * what we have to do (restart transfer). 51110770Ssam */ 51210770Ssam int reg, npf, o, cmd, ubaddr, diff, head; 51310770Ssam 51410770Ssam 51510770Ssam /* seek to next head/track */ 51610770Ssam 51710770Ssam /* increment head and/or cylinder */ 51810770Ssam st->rl_cylnhd++; 51910770Ssam diff = (st->rl_cyl[ui->ui_slave] >> 1) - 52010770Ssam (st->rl_cylnhd >> 1); 52110770Ssam st->rl_cyl[ui->ui_slave] = st->rl_cylnhd; 52210770Ssam head = st->rl_cylnhd & 1; 52310770Ssam rlwait( rladdr ); 52410770Ssam 52510770Ssam if ( diff < 0 ) 52610770Ssam rladdr->rlda.seek = -diff << 7 | RLDA_HGH | head << 4; 52710770Ssam else 52810770Ssam rladdr->rlda.seek = diff << 7 | RLDA_LOW | head << 4; 52910770Ssam rladdr->rlcs = (ui->ui_slave << 8) | RL_SEEK; 53010770Ssam 53110770Ssam npf = btop( bp->b_bcount - st->rl_bleft ); 53210770Ssam reg = btop(um->um_ubinfo&0x3ffff) + npf; 53310770Ssam o = (int)bp->b_un.b_addr & PGOFSET; 53410770Ssam ubapurge(um); 53510770Ssam um->um_tab.b_active++; 53610770Ssam 53710770Ssam rlwait( rladdr ); 53810770Ssam rladdr->rlda.rw = st->rl_cylnhd << 6; 53910770Ssam if ( st->rl_bleft < (st->rl_bpart = rl02.btrak) ) 54010770Ssam st->rl_bpart = st->rl_bleft; 54110770Ssam rladdr->rlmp.rw = -(st->rl_bpart >> 1); 54210770Ssam cmd = (bp->b_flags&B_READ ? RL_READ : RL_WRITE) | 54310770Ssam RL_IE | (ui->ui_slave << 8); 54410770Ssam ubaddr = (int)ptob(reg) + o; 54510770Ssam cmd |= ((ubaddr >> 12) & RL_BAE); 54610770Ssam 54710770Ssam rladdr->rlba = ubaddr; 54810770Ssam rladdr->rlcs = cmd; 54910770Ssam return; 55010770Ssam } 55110770Ssam 55210770Ssam um->um_tab.b_active = 0; 55310770Ssam um->um_tab.b_errcnt = 0; 55410770Ssam dp->b_active = 0; 55510770Ssam dp->b_errcnt = 0; 55610770Ssam 55710770Ssam /* "b_resid" words remaining after error */ 55810770Ssam bp->b_resid = st->rl_bleft; 55910770Ssam um->um_tab.b_actf = dp->b_forw; 56010770Ssam dp->b_actf = bp->av_forw; 56110770Ssam 56210770Ssam retry: 56310770Ssam st->rl_dn = -1; 56410770Ssam st->rl_bpart = st->rl_bleft = 0; 56510770Ssam iodone(bp); 56610770Ssam /* 56710770Ssam * If this unit has more work to do, 56810770Ssam * then start it up right away. 56910770Ssam */ 57010770Ssam if (dp->b_actf) 57110770Ssam if (rlustart(ui)) 57210770Ssam needie = 0; 57310770Ssam as &= ~(1<<ui->ui_slave); 57410770Ssam } else 57510770Ssam as |= (1<<ui->ui_slave); 57610770Ssam /* 57710770Ssam * Release unibus resources and flush data paths. 57810770Ssam */ 57910770Ssam ubadone(um); 58010770Ssam 58110770Ssam /* reset state info */ 58210770Ssam st->rl_dn = -1; 58310770Ssam st->rl_cylnhd = st->rl_bpart = st->rl_bleft = 0; 58410770Ssam 58510770Ssam doattn: 58610770Ssam /* 58710770Ssam * Process other units which need attention. 58810770Ssam * For each unit which needs attention, call 58910770Ssam * the unit start routine to place the slave 59010770Ssam * on the controller device queue. 59110770Ssam */ 59210770Ssam while (unit = ffs(as)) { 59310770Ssam unit--; /* was 1 origin */ 59410770Ssam as &= ~(1<<unit); 59510770Ssam (void) rlustart(rlip[rl21][unit]); 59610770Ssam } 59710770Ssam /* 59810770Ssam * If the controller is not transferring, but 59910770Ssam * there are devices ready to transfer, start 60010770Ssam * the controller. 60110770Ssam */ 60210770Ssam if (um->um_tab.b_actf && um->um_tab.b_active == 0) 60310770Ssam (void) rlstart(um); 60410770Ssam } 60510770Ssam 60612452Ssam rlwait(rladdr) 60712452Ssam register struct rldevice *rladdr; 60810770Ssam { 60912452Ssam 61010770Ssam while ((rladdr->rlcs & RL_CRDY) == 0) 61110770Ssam continue; /* Wait */ 61210770Ssam } 61310770Ssam 61412452Ssam rlread(dev, uio) 61510770Ssam dev_t dev; 61612452Ssam struct uio *uio; 61710770Ssam { 61810770Ssam register int unit = minor(dev) >> 3; 61910770Ssam 62010770Ssam if (unit >= NRL) 62112452Ssam return (ENXIO); 62212452Ssam return (physio(rlstrategy, &rrlbuf[unit], dev, B_READ, minphys, uio)); 62310770Ssam } 62410770Ssam 62512452Ssam rlwrite(dev, uio) 62610770Ssam dev_t dev; 62712452Ssam struct uio *uio; 62810770Ssam { 62910770Ssam register int unit = minor(dev) >> 3; 63010770Ssam 63110770Ssam if (unit >= NRL) 63212452Ssam return (ENXIO); 63312452Ssam return (physio(rlstrategy, &rrlbuf[unit], dev, B_WRITE, minphys, uio)); 63410770Ssam } 63510770Ssam 63610770Ssam /* 63710770Ssam * Reset driver after UBA init. 63810770Ssam * Cancel software state of all pending transfers 63910770Ssam * and restart all units and the controller. 64010770Ssam */ 64110770Ssam rlreset(uban) 64210770Ssam int uban; 64310770Ssam { 64410770Ssam register struct uba_ctlr *um; 64510770Ssam register struct uba_device *ui; 64610770Ssam register struct rldevice *rladdr; 64710770Ssam register struct rl_stat *st; 64810770Ssam register int rl21, unit; 64910770Ssam 65010770Ssam for (rl21 = 0; rl21 < NHL; rl21++) { 65110770Ssam if ((um = rlminfo[rl21]) == 0 || um->um_ubanum != uban || 65210770Ssam um->um_alive == 0) 65310770Ssam continue; 65410770Ssam printf(" Reset hl%d", rl21); 65510770Ssam rladdr = (struct rldevice *)um->um_addr; 65610770Ssam st = &rl_stat[rl21]; 65710770Ssam um->um_tab.b_active = 0; 65810770Ssam um->um_tab.b_actf = um->um_tab.b_actl = 0; 65910770Ssam if (um->um_ubinfo) { 66010770Ssam printf("<%d>", (um->um_ubinfo>>28)&0xf); 66112452Ssam um->um_ubinfo = 0; 66210770Ssam } 66310770Ssam 66410770Ssam /* reset controller */ 66510770Ssam st->rl_dn = -1; 66610770Ssam st->rl_cylnhd = 0; 66710770Ssam st->rl_bleft = 0; 66810770Ssam st->rl_bpart = 0; 66912452Ssam rlwait(rladdr); 67010770Ssam 67110770Ssam for (unit = 0; unit < NRL; unit++) { 67210770Ssam rladdr->rlcs = (unit << 8) | RL_GETSTAT; 67312452Ssam rlwait(rladdr); 67410770Ssam 67510770Ssam /* Determine disk posistion */ 67610770Ssam rladdr->rlcs = (unit << 8) | RL_RHDR; 67710770Ssam rlwait(rladdr); 67810770Ssam 67910770Ssam /* save disk drive posistion */ 68010770Ssam st->rl_cyl[unit] = 68110770Ssam (rladdr->rlmp.readhdr & 0177700) >> 6; 68210770Ssam 68310770Ssam if ((ui = rldinfo[unit]) == 0) 68410770Ssam continue; 68510770Ssam if (ui->ui_alive == 0 || ui->ui_mi != um) 68610770Ssam continue; 68710770Ssam rlutab[unit].b_active = 0; 68810770Ssam (void) rlustart(ui); 68910770Ssam } 69010770Ssam (void) rlstart(um); 69110770Ssam } 69210770Ssam } 69310770Ssam 69410770Ssam /* 69510770Ssam * Wake up every second and if an interrupt is pending 69610770Ssam * but nothing has happened increment a counter. 69710770Ssam * If nothing happens for 20 seconds, reset the UNIBUS 69810770Ssam * and begin anew. 69910770Ssam */ 70010770Ssam rlwatch() 70110770Ssam { 70210770Ssam register struct uba_ctlr *um; 70310770Ssam register rl21, unit; 70410770Ssam register struct rl_softc *rl; 70510770Ssam 70610770Ssam timeout(rlwatch, (caddr_t)0, hz); 70710770Ssam for (rl21 = 0; rl21 < NHL; rl21++) { 70810770Ssam um = rlminfo[rl21]; 70910770Ssam if (um == 0 || um->um_alive == 0) 71010770Ssam continue; 71110770Ssam rl = &rl_softc[rl21]; 71210770Ssam if (um->um_tab.b_active == 0) { 71310770Ssam for (unit = 0; unit < NRL; unit++) 71410770Ssam if (rlutab[unit].b_active && 71510770Ssam rldinfo[unit]->ui_mi == um) 71610770Ssam goto active; 71710770Ssam rl->rl_wticks = 0; 71810770Ssam continue; 71910770Ssam } 72010770Ssam active: 72110770Ssam rl->rl_wticks++; 72210770Ssam if (rl->rl_wticks >= 20) { 72310770Ssam rl->rl_wticks = 0; 72410770Ssam printf("hl%d: lost interrupt\n", rl21); 72510770Ssam ubareset(um->um_ubanum); 72610770Ssam } 72710770Ssam } 72810770Ssam } 72910770Ssam 73010770Ssam rldump(dev) 73110770Ssam dev_t dev; 73210770Ssam { 73310770Ssam /* don't think there is room on swap for it anyway. */ 73410770Ssam } 735*12504Ssam 736*12504Ssam rlsize(dev) 737*12504Ssam dev_t dev; 738*12504Ssam { 739*12504Ssam int unit = minor(dev) >> 3; 740*12504Ssam struct uba_device *ui; 741*12504Ssam struct rlst *st; 742*12504Ssam 743*12504Ssam if (unit >= NRL || (ui = rldinfo[unit]) == 0 || ui->ui_alive == 0) 744*12504Ssam return (-1); 745*12504Ssam st = &rl02; 746*12504Ssam return (st->sizes[minor(dev) & 07].nblocks); 747*12504Ssam } 748*12504Ssam #endif 749