1*12837Ssam /* up.c 4.75 83/05/30 */ 2264Sbill 31937Swnj #include "up.h" 42646Swnj #if NSC > 0 5264Sbill /* 69548Ssam * UNIBUS disk driver with: 79548Ssam * overlapped seeks, 89548Ssam * ECC recovery, and 99548Ssam * bad sector forwarding. 102889Swnj * 112889Swnj * TODO: 123445Sroot * Check that offset recovery code works 13264Sbill */ 149782Ssam #include "../machine/pte.h" 15264Sbill 16264Sbill #include "../h/param.h" 17264Sbill #include "../h/systm.h" 18308Sbill #include "../h/dk.h" 199548Ssam #include "../h/dkbad.h" 20264Sbill #include "../h/buf.h" 21264Sbill #include "../h/conf.h" 22264Sbill #include "../h/dir.h" 23264Sbill #include "../h/user.h" 24264Sbill #include "../h/map.h" 252571Swnj #include "../h/vm.h" 262379Swnj #include "../h/cmap.h" 279357Ssam #include "../h/uio.h" 2810871Ssam #include "../h/kernel.h" 29264Sbill 309357Ssam #include "../vax/cpu.h" 319357Ssam #include "../vax/nexus.h" 329357Ssam #include "../vaxuba/ubavar.h" 339357Ssam #include "../vaxuba/ubareg.h" 349357Ssam #include "../vaxuba/upreg.h" 359357Ssam 362395Swnj struct up_softc { 372395Swnj int sc_softas; 382607Swnj int sc_ndrive; 392395Swnj int sc_wticks; 402674Swnj int sc_recal; 412646Swnj } up_softc[NSC]; 42275Sbill 432395Swnj /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 4410858Ssam struct size { 45264Sbill daddr_t nblocks; 46264Sbill int cyloff; 4711211Ssam } up9300_sizes[8] = { 48264Sbill 15884, 0, /* A=cyl 0 thru 26 */ 49264Sbill 33440, 27, /* B=cyl 27 thru 81 */ 50341Sbill 495520, 0, /* C=cyl 0 thru 814 */ 51264Sbill 15884, 562, /* D=cyl 562 thru 588 */ 52264Sbill 55936, 589, /* E=cyl 589 thru 680 */ 533730Sroot 81376, 681, /* F=cyl 681 thru 814 */ 543730Sroot 153728, 562, /* G=cyl 562 thru 814 */ 55264Sbill 291346, 82, /* H=cyl 82 thru 561 */ 5611211Ssam }, up9766_sizes[8] = { 5711211Ssam 15884, 0, /* A=cyl 0 thru 26 */ 5811211Ssam 33440, 27, /* B=cyl 27 thru 81 */ 5911211Ssam 500384, 0, /* C=cyl 0 thru 822 */ 6011211Ssam 15884, 562, /* D=cyl 562 thru 588 */ 6111211Ssam 55936, 589, /* E=cyl 589 thru 680 */ 6211211Ssam 86240, 681, /* F=cyl 681 thru 822 */ 6311211Ssam 158592, 562, /* G=cyl 562 thru 822 */ 6411211Ssam 291346, 82, /* H=cyl 82 thru 561 */ 6511211Ssam }, up160_sizes[8] = { 662395Swnj 15884, 0, /* A=cyl 0 thru 49 */ 672395Swnj 33440, 50, /* B=cyl 50 thru 154 */ 682395Swnj 263360, 0, /* C=cyl 0 thru 822 */ 6911211Ssam 15884, 155, /* D=cyl 155 thru 204 */ 7011211Ssam 55936, 205, /* E=cyl 205 thru 379 */ 7111211Ssam 141664, 380, /* F=cyl 380 thru 822 */ 7211211Ssam 213664, 155, /* G=cyl 155 thru 822 */ 732395Swnj 0, 0, 746851Ssam }, upam_sizes[8] = { 756305Sroot 15884, 0, /* A=cyl 0 thru 31 */ 766305Sroot 33440, 32, /* B=cyl 32 thru 97 */ 776305Sroot 524288, 0, /* C=cyl 0 thru 1023 */ 7811211Ssam 15884, 668, /* D=cyl 668 thru 699 */ 7911211Ssam 55936, 700, /* E=cyl 700 thru 809 */ 8011211Ssam 109472, 810, /* F=cyl 810 thru 1023 */ 8111211Ssam 182176, 668, /* G=cyl 668 thru 1023 */ 826305Sroot 291346, 98, /* H=cyl 98 thru 667 */ 83264Sbill }; 842395Swnj /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 85264Sbill 862607Swnj int upprobe(), upslave(), upattach(), updgo(), upintr(); 872983Swnj struct uba_ctlr *upminfo[NSC]; 882983Swnj struct uba_device *updinfo[NUP]; 896383Swnj #define UPIPUNITS 8 906383Swnj struct uba_device *upip[NSC][UPIPUNITS]; /* fuji w/fixed head gives n,n+4 */ 912395Swnj 922607Swnj u_short upstd[] = { 0776700, 0774400, 0776300, 0 }; 932616Swnj struct uba_driver scdriver = 942607Swnj { upprobe, upslave, upattach, updgo, upstd, "up", updinfo, "sc", upminfo }; 952395Swnj struct buf uputab[NUP]; 969548Ssam char upinit[NUP]; 972395Swnj 982395Swnj struct upst { 99*12837Ssam short nsect; /* # sectors/track */ 100*12837Ssam short ntrak; /* # tracks/cylinder */ 101*12837Ssam short nspc; /* # sectors/cylinder */ 102*12837Ssam short ncyl; /* # cylinders */ 103*12837Ssam struct size *sizes; /* partition tables */ 104*12837Ssam short sdist; /* seek distance metric */ 105*12837Ssam short rdist; /* rotational distance metric */ 1062395Swnj } upst[] = { 107*12837Ssam { 32, 19, 32*19, 815, up9300_sizes, 3, 4 }, /* 9300 */ 108*12837Ssam { 32, 19, 32*19, 823, up9766_sizes, 3, 4 }, /* 9766 */ 109*12837Ssam { 32, 10, 32*10, 823, up160_sizes, 3, 4 }, /* fuji 160m */ 110*12837Ssam { 32, 16, 32*16, 1024, upam_sizes, 7, 8 }, /* Capricorn */ 111*12837Ssam { 0, 0, 0, 0, 0, 0, 0 } 1122395Swnj }; 1132395Swnj 1142629Swnj u_char up_offset[16] = { 1159548Ssam UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400, 1169548Ssam UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800, 1179548Ssam UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200, 1189548Ssam 0, 0, 0, 0 1192629Swnj }; 120264Sbill 1212616Swnj struct buf rupbuf[NUP]; 1229548Ssam struct buf bupbuf[NUP]; 1239548Ssam struct dkbad upbad[NUP]; 124264Sbill 125264Sbill #define b_cylin b_resid 126264Sbill 127264Sbill #ifdef INTRLVE 128264Sbill daddr_t dkblock(); 129264Sbill #endif 1302395Swnj 1312395Swnj int upwstart, upwatch(); /* Have started guardian */ 1322470Swnj int upseek; 1332681Swnj int upwaitdry; 1342395Swnj 1352395Swnj /*ARGSUSED*/ 1362607Swnj upprobe(reg) 1372395Swnj caddr_t reg; 1382395Swnj { 1392459Swnj register int br, cvec; 1402459Swnj 1412607Swnj #ifdef lint 14212779Ssam br = 0; cvec = br; br = cvec; upintr(0); 1432607Swnj #endif 1442629Swnj ((struct updevice *)reg)->upcs1 = UP_IE|UP_RDY; 1452607Swnj DELAY(10); 1462629Swnj ((struct updevice *)reg)->upcs1 = 0; 1479357Ssam return (sizeof (struct updevice)); 1482395Swnj } 1492395Swnj 1502607Swnj upslave(ui, reg) 1512983Swnj struct uba_device *ui; 1522395Swnj caddr_t reg; 1532395Swnj { 1542629Swnj register struct updevice *upaddr = (struct updevice *)reg; 1552395Swnj 1562395Swnj upaddr->upcs1 = 0; /* conservative */ 1572607Swnj upaddr->upcs2 = ui->ui_slave; 1586843Swnj upaddr->upcs1 = UP_NOP|UP_GO; 1593445Sroot if (upaddr->upcs2&UPCS2_NED) { 1602629Swnj upaddr->upcs1 = UP_DCLR|UP_GO; 1612395Swnj return (0); 1622395Swnj } 1632607Swnj return (1); 1642607Swnj } 1652607Swnj 1662607Swnj upattach(ui) 1672983Swnj register struct uba_device *ui; 1682607Swnj { 1692607Swnj 1702395Swnj if (upwstart == 0) { 1712759Swnj timeout(upwatch, (caddr_t)0, hz); 1722395Swnj upwstart++; 1732395Swnj } 1742571Swnj if (ui->ui_dk >= 0) 1752571Swnj dk_mspw[ui->ui_dk] = .0000020345; 1762607Swnj upip[ui->ui_ctlr][ui->ui_slave] = ui; 1772607Swnj up_softc[ui->ui_ctlr].sc_ndrive++; 17811119Ssam ui->ui_type = upmaptype(ui); 17911119Ssam } 18011119Ssam 18111119Ssam upmaptype(ui) 18211119Ssam register struct uba_device *ui; 18311119Ssam { 18411119Ssam register struct updevice *upaddr = (struct updevice *)ui->ui_addr; 18511119Ssam int type = ui->ui_type; 18611119Ssam register struct upst *st; 18711119Ssam 1882629Swnj upaddr->upcs1 = 0; 1892629Swnj upaddr->upcs2 = ui->ui_slave; 1903496Sroot upaddr->uphr = UPHR_MAXTRAK; 19111119Ssam for (st = upst; st->nsect != 0; st++) 19211119Ssam if (upaddr->uphr == st->ntrak - 1) { 19311119Ssam type = st - upst; 19411119Ssam break; 19511119Ssam } 19611119Ssam if (st->nsect == 0) 19711119Ssam printf("up%d: uphr=%x\n", ui->ui_slave, upaddr->uphr); 19811119Ssam if (type == 0) { 19911112Shelge upaddr->uphr = UPHR_MAXCYL; 20011112Shelge if (upaddr->uphr == 822) 20111119Ssam type++; 20211112Shelge } 2033496Sroot upaddr->upcs2 = UPCS2_CLR; 20411119Ssam return (type); 2052395Swnj } 206264Sbill 2079548Ssam upopen(dev) 2089548Ssam dev_t dev; 2099548Ssam { 2109548Ssam register int unit = minor(dev) >> 3; 2119548Ssam register struct uba_device *ui; 2129548Ssam 2139548Ssam if (unit >= NUP || (ui = updinfo[unit]) == 0 || ui->ui_alive == 0) 2149548Ssam return (ENXIO); 2159548Ssam return (0); 2169548Ssam } 2179548Ssam 218264Sbill upstrategy(bp) 2192395Swnj register struct buf *bp; 220264Sbill { 2212983Swnj register struct uba_device *ui; 2222395Swnj register struct upst *st; 2232395Swnj register int unit; 2242470Swnj register struct buf *dp; 2252395Swnj int xunit = minor(bp->b_dev) & 07; 2262470Swnj long bn, sz; 227264Sbill 2282470Swnj sz = (bp->b_bcount+511) >> 9; 229264Sbill unit = dkunit(bp); 2302395Swnj if (unit >= NUP) 2312395Swnj goto bad; 2322395Swnj ui = updinfo[unit]; 2332395Swnj if (ui == 0 || ui->ui_alive == 0) 2342395Swnj goto bad; 2352395Swnj st = &upst[ui->ui_type]; 2362395Swnj if (bp->b_blkno < 0 || 2372395Swnj (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) 2382395Swnj goto bad; 2392395Swnj bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 2406305Sroot (void) spl5(); 2412470Swnj dp = &uputab[ui->ui_unit]; 2422470Swnj disksort(dp, bp); 2432470Swnj if (dp->b_active == 0) { 2442395Swnj (void) upustart(ui); 2452395Swnj bp = &ui->ui_mi->um_tab; 2462395Swnj if (bp->b_actf && bp->b_active == 0) 2472395Swnj (void) upstart(ui->ui_mi); 248264Sbill } 2496305Sroot (void) spl0(); 2502395Swnj return; 2512395Swnj 2522395Swnj bad: 2532395Swnj bp->b_flags |= B_ERROR; 2542395Swnj iodone(bp); 2552395Swnj return; 256264Sbill } 257264Sbill 2582674Swnj /* 2592674Swnj * Unit start routine. 2602674Swnj * Seek the drive to be where the data is 2612674Swnj * and then generate another interrupt 2622674Swnj * to actually start the transfer. 2632674Swnj * If there is only one drive on the controller, 2642674Swnj * or we are very close to the data, don't 2652674Swnj * bother with the search. If called after 2662674Swnj * searching once, don't bother to look where 2672674Swnj * we are, just queue for transfer (to avoid 2682674Swnj * positioning forever without transferrring.) 2692674Swnj */ 2702395Swnj upustart(ui) 2712983Swnj register struct uba_device *ui; 272264Sbill { 273264Sbill register struct buf *bp, *dp; 2742983Swnj register struct uba_ctlr *um; 2752629Swnj register struct updevice *upaddr; 2762395Swnj register struct upst *st; 277264Sbill daddr_t bn; 2782674Swnj int sn, csn; 2792607Swnj /* 2802607Swnj * The SC21 cancels commands if you just say 2812629Swnj * cs1 = UP_IE 2822607Swnj * so we are cautious about handling of cs1. 2832607Swnj * Also don't bother to clear as bits other than in upintr(). 2842607Swnj */ 2852674Swnj int didie = 0; 2862674Swnj 2872674Swnj if (ui == 0) 2882674Swnj return (0); 2892983Swnj um = ui->ui_mi; 2902395Swnj dk_busy &= ~(1<<ui->ui_dk); 2912395Swnj dp = &uputab[ui->ui_unit]; 292266Sbill if ((bp = dp->b_actf) == NULL) 293268Sbill goto out; 2942674Swnj /* 2952674Swnj * If the controller is active, just remember 2962674Swnj * that this device would like to be positioned... 2972674Swnj * if we tried to position now we would confuse the SC21. 2982674Swnj */ 2992395Swnj if (um->um_tab.b_active) { 3002459Swnj up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave; 301275Sbill return (0); 302275Sbill } 3032674Swnj /* 3042674Swnj * If we have already positioned this drive, 3052674Swnj * then just put it on the ready queue. 3062674Swnj */ 307276Sbill if (dp->b_active) 308276Sbill goto done; 309276Sbill dp->b_active = 1; 3102629Swnj upaddr = (struct updevice *)um->um_addr; 3112395Swnj upaddr->upcs2 = ui->ui_slave; 3122674Swnj /* 3132674Swnj * If drive has just come up, 3142674Swnj * setup the pack. 3152674Swnj */ 3169548Ssam if ((upaddr->upds & UPDS_VV) == 0 || upinit[ui->ui_unit] == 0) { 3179548Ssam struct buf *bbp = &bupbuf[ui->ui_unit]; 31810858Ssam 3192607Swnj /* SHOULD WARN SYSTEM THAT THIS HAPPENED */ 3209548Ssam upinit[ui->ui_unit] = 1; 3212629Swnj upaddr->upcs1 = UP_IE|UP_DCLR|UP_GO; 3222629Swnj upaddr->upcs1 = UP_IE|UP_PRESET|UP_GO; 3233445Sroot upaddr->upof = UPOF_FMT22; 324268Sbill didie = 1; 3259548Ssam st = &upst[ui->ui_type]; 3269548Ssam bbp->b_flags = B_READ|B_BUSY; 3279548Ssam bbp->b_dev = bp->b_dev; 3289548Ssam bbp->b_bcount = 512; 3299548Ssam bbp->b_un.b_addr = (caddr_t)&upbad[ui->ui_unit]; 3309548Ssam bbp->b_blkno = st->ncyl * st->nspc - st->nsect; 3319548Ssam bbp->b_cylin = st->ncyl - 1; 3329548Ssam dp->b_actf = bbp; 3339548Ssam bbp->av_forw = bp; 3349548Ssam bp = bbp; 335264Sbill } 3362674Swnj /* 3372674Swnj * If drive is offline, forget about positioning. 3382674Swnj */ 3393445Sroot if ((upaddr->upds & (UPDS_DPR|UPDS_MOL)) != (UPDS_DPR|UPDS_MOL)) 340275Sbill goto done; 3412674Swnj /* 3422674Swnj * If there is only one drive, 3432674Swnj * dont bother searching. 3442674Swnj */ 3452607Swnj if (up_softc[um->um_ctlr].sc_ndrive == 1) 3462607Swnj goto done; 3472674Swnj /* 3482674Swnj * Figure out where this transfer is going to 3492674Swnj * and see if we are close enough to justify not searching. 3502674Swnj */ 3512395Swnj st = &upst[ui->ui_type]; 352264Sbill bn = dkblock(bp); 3532395Swnj sn = bn%st->nspc; 354*12837Ssam sn = (sn + st->nsect - st->sdist) % st->nsect; 3552674Swnj if (bp->b_cylin - upaddr->updc) 356266Sbill goto search; /* Not on-cylinder */ 357275Sbill else if (upseek) 358275Sbill goto done; /* Ok just to be on-cylinder */ 359264Sbill csn = (upaddr->upla>>6) - sn - 1; 360266Sbill if (csn < 0) 3612395Swnj csn += st->nsect; 362*12837Ssam if (csn > st->nsect - st->rdist) 363264Sbill goto done; 364264Sbill search: 3652674Swnj upaddr->updc = bp->b_cylin; 3662674Swnj /* 3672674Swnj * Not on cylinder at correct position, 3682674Swnj * seek/search. 3692674Swnj */ 370275Sbill if (upseek) 3712629Swnj upaddr->upcs1 = UP_IE|UP_SEEK|UP_GO; 3722470Swnj else { 373275Sbill upaddr->upda = sn; 3742629Swnj upaddr->upcs1 = UP_IE|UP_SEARCH|UP_GO; 375275Sbill } 376268Sbill didie = 1; 3772674Swnj /* 3782674Swnj * Mark unit busy for iostat. 3792674Swnj */ 3802395Swnj if (ui->ui_dk >= 0) { 3812395Swnj dk_busy |= 1<<ui->ui_dk; 3822395Swnj dk_seek[ui->ui_dk]++; 383264Sbill } 384268Sbill goto out; 385264Sbill done: 3862674Swnj /* 3872674Swnj * Device is ready to go. 3882674Swnj * Put it on the ready queue for the controller 3892674Swnj * (unless its already there.) 3902674Swnj */ 3912629Swnj if (dp->b_active != 2) { 3922629Swnj dp->b_forw = NULL; 3932629Swnj if (um->um_tab.b_actf == NULL) 3942629Swnj um->um_tab.b_actf = dp; 3952629Swnj else 3962629Swnj um->um_tab.b_actl->b_forw = dp; 3972629Swnj um->um_tab.b_actl = dp; 3982629Swnj dp->b_active = 2; 3992629Swnj } 400268Sbill out: 401268Sbill return (didie); 402264Sbill } 403264Sbill 4042674Swnj /* 4052674Swnj * Start up a transfer on a drive. 4062674Swnj */ 4072395Swnj upstart(um) 4082983Swnj register struct uba_ctlr *um; 409264Sbill { 410264Sbill register struct buf *bp, *dp; 4112983Swnj register struct uba_device *ui; 4122629Swnj register struct updevice *upaddr; 4132470Swnj struct upst *st; 414264Sbill daddr_t bn; 4152681Swnj int dn, sn, tn, cmd, waitdry; 416264Sbill 417264Sbill loop: 4182674Swnj /* 4192674Swnj * Pull a request off the controller queue 4202674Swnj */ 4212395Swnj if ((dp = um->um_tab.b_actf) == NULL) 422268Sbill return (0); 423264Sbill if ((bp = dp->b_actf) == NULL) { 4242395Swnj um->um_tab.b_actf = dp->b_forw; 425264Sbill goto loop; 426264Sbill } 4272674Swnj /* 4282674Swnj * Mark controller busy, and 4292674Swnj * determine destination of this request. 4302674Swnj */ 4312395Swnj um->um_tab.b_active++; 4322395Swnj ui = updinfo[dkunit(bp)]; 433264Sbill bn = dkblock(bp); 4342395Swnj dn = ui->ui_slave; 4352395Swnj st = &upst[ui->ui_type]; 4362395Swnj sn = bn%st->nspc; 4372395Swnj tn = sn/st->nsect; 4382395Swnj sn %= st->nsect; 4392629Swnj upaddr = (struct updevice *)ui->ui_addr; 4402674Swnj /* 4412674Swnj * Select drive if not selected already. 4422674Swnj */ 4432674Swnj if ((upaddr->upcs2&07) != dn) 4442674Swnj upaddr->upcs2 = dn; 4452674Swnj /* 4462674Swnj * Check that it is ready and online 4472674Swnj */ 4482681Swnj waitdry = 0; 4493445Sroot while ((upaddr->upds&UPDS_DRY) == 0) { 4507036Swnj printf("up%d: ds wait ds=%o\n",dkunit(bp),upaddr->upds); 4512681Swnj if (++waitdry > 512) 4522681Swnj break; 4532681Swnj upwaitdry++; 4542681Swnj } 4553445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 4562931Swnj printf("up%d: not ready", dkunit(bp)); 4573445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 4582607Swnj printf("\n"); 4592395Swnj um->um_tab.b_active = 0; 4602395Swnj um->um_tab.b_errcnt = 0; 461893Sbill dp->b_actf = bp->av_forw; 462893Sbill dp->b_active = 0; 463893Sbill bp->b_flags |= B_ERROR; 464893Sbill iodone(bp); 465893Sbill goto loop; 466893Sbill } 4672674Swnj /* 4682674Swnj * Oh, well, sometimes this 4692674Swnj * happens, for reasons unknown. 4702674Swnj */ 4712629Swnj printf(" (flakey)\n"); 472264Sbill } 4732674Swnj /* 4742674Swnj * Setup for the transfer, and get in the 4752674Swnj * UNIBUS adaptor queue. 4762674Swnj */ 4772424Skre upaddr->updc = bp->b_cylin; 478264Sbill upaddr->upda = (tn << 8) + sn; 479264Sbill upaddr->upwc = -bp->b_bcount / sizeof (short); 480264Sbill if (bp->b_flags & B_READ) 4812629Swnj cmd = UP_IE|UP_RCOM|UP_GO; 482264Sbill else 4832629Swnj cmd = UP_IE|UP_WCOM|UP_GO; 4842571Swnj um->um_cmd = cmd; 4853107Swnj (void) ubago(ui); 486268Sbill return (1); 487264Sbill } 488264Sbill 4892674Swnj /* 4902674Swnj * Now all ready to go, stuff the registers. 4912674Swnj */ 4922571Swnj updgo(um) 4932983Swnj struct uba_ctlr *um; 4942395Swnj { 4952629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 4962470Swnj 4976953Swnj um->um_tab.b_active = 2; /* should now be 2 */ 4982571Swnj upaddr->upba = um->um_ubinfo; 4992571Swnj upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300); 5002395Swnj } 5012395Swnj 5022674Swnj /* 5032674Swnj * Handle a disk interrupt. 5042674Swnj */ 5052707Swnj upintr(sc21) 5062395Swnj register sc21; 507264Sbill { 508264Sbill register struct buf *bp, *dp; 5092983Swnj register struct uba_ctlr *um = upminfo[sc21]; 5102983Swnj register struct uba_device *ui; 5112629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 512264Sbill register unit; 5132470Swnj struct up_softc *sc = &up_softc[um->um_ctlr]; 5142607Swnj int as = (upaddr->upas & 0377) | sc->sc_softas; 5152681Swnj int needie = 1, waitdry; 516264Sbill 5172470Swnj sc->sc_wticks = 0; 5182607Swnj sc->sc_softas = 0; 5192674Swnj /* 5202674Swnj * If controller wasn't transferring, then this is an 5212674Swnj * interrupt for attention status on seeking drives. 5222674Swnj * Just service them. 5232674Swnj */ 5246346Swnj if (um->um_tab.b_active != 2 && !sc->sc_recal) { 5252674Swnj if (upaddr->upcs1 & UP_TRE) 5262674Swnj upaddr->upcs1 = UP_TRE; 5272674Swnj goto doattn; 5282674Swnj } 5296953Swnj um->um_tab.b_active = 1; 5302674Swnj /* 5312674Swnj * Get device and block structures, and a pointer 5322983Swnj * to the uba_device for the drive. Select the drive. 5332674Swnj */ 5342674Swnj dp = um->um_tab.b_actf; 5352674Swnj bp = dp->b_actf; 5362674Swnj ui = updinfo[dkunit(bp)]; 5372674Swnj dk_busy &= ~(1 << ui->ui_dk); 5382674Swnj if ((upaddr->upcs2&07) != ui->ui_slave) 5392395Swnj upaddr->upcs2 = ui->ui_slave; 5409548Ssam if (bp->b_flags&B_BAD) { 5419548Ssam if (upecc(ui, CONT)) 5429548Ssam return; 5439548Ssam } 5442674Swnj /* 5452674Swnj * Check for and process errors on 5462674Swnj * either the drive or the controller. 5472674Swnj */ 5483445Sroot if ((upaddr->upds&UPDS_ERR) || (upaddr->upcs1&UP_TRE)) { 5492681Swnj waitdry = 0; 5503445Sroot while ((upaddr->upds & UPDS_DRY) == 0) { 5512681Swnj if (++waitdry > 512) 5522681Swnj break; 5532681Swnj upwaitdry++; 5542681Swnj } 5553445Sroot if (upaddr->uper1&UPER1_WLE) { 5562674Swnj /* 5572674Swnj * Give up on write locked devices 5582674Swnj * immediately. 5592674Swnj */ 5602931Swnj printf("up%d: write locked\n", dkunit(bp)); 5612674Swnj bp->b_flags |= B_ERROR; 5622674Swnj } else if (++um->um_tab.b_errcnt > 27) { 5632674Swnj /* 5642674Swnj * After 28 retries (16 without offset, and 5652674Swnj * 12 with offset positioning) give up. 56610904Shelge * If the error was header CRC, the header is 56710904Shelge * screwed up, and the sector may in fact exist 56810904Shelge * in the bad sector table, better check... 5692674Swnj */ 57010904Shelge if (upaddr->uper1&UPER1_HCRC) { 57110904Shelge if (upecc(ui, BSE)) 57210904Shelge return; 57310904Shelge } 5749548Ssam hard: 5752931Swnj harderr(bp, "up"); 5769548Ssam printf("cn=%d tn=%d sn=%d cs2=%b er1=%b er2=%b\n", 5779548Ssam upaddr->updc, ((upaddr->upda)>>8)&077, 5789548Ssam (upaddr->upda)&037, 5799548Ssam upaddr->upcs2, UPCS2_BITS, 5809548Ssam upaddr->uper1, UPER1_BITS, 5819548Ssam upaddr->uper2, UPER2_BITS); 5822674Swnj bp->b_flags |= B_ERROR; 5839548Ssam } else if (upaddr->uper2 & UPER2_BSE) { 5849548Ssam if (upecc(ui, BSE)) 5859548Ssam return; 5869548Ssam else 5879548Ssam goto hard; 5882674Swnj } else { 5892674Swnj /* 5902674Swnj * Retriable error. 5912674Swnj * If a soft ecc, correct it (continuing 5922674Swnj * by returning if necessary. 5932674Swnj * Otherwise fall through and retry the transfer 5942674Swnj */ 5957183Sroot if ((upaddr->uper1&(UPER1_DCK|UPER1_ECH))==UPER1_DCK) { 5969548Ssam if (upecc(ui, ECC)) 5972629Swnj return; 5987183Sroot } else 5997183Sroot um->um_tab.b_active = 0; /* force retry */ 6002674Swnj } 6012674Swnj /* 6022674Swnj * Clear drive error and, every eight attempts, 6032674Swnj * (starting with the fourth) 6042674Swnj * recalibrate to clear the slate. 6052674Swnj */ 6062674Swnj upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 6072674Swnj needie = 0; 6083182Swnj if ((um->um_tab.b_errcnt&07) == 4 && um->um_tab.b_active == 0) { 6092674Swnj upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO; 6103160Swnj sc->sc_recal = 0; 6113160Swnj goto nextrecal; 6122674Swnj } 6132674Swnj } 6142674Swnj /* 6153160Swnj * Advance recalibration finite state machine 6163160Swnj * if recalibrate in progress, through 6173160Swnj * RECAL 6183160Swnj * SEEK 6193160Swnj * OFFSET (optional) 6203160Swnj * RETRY 6212674Swnj */ 6223160Swnj switch (sc->sc_recal) { 6233160Swnj 6243160Swnj case 1: 6253160Swnj upaddr->updc = bp->b_cylin; 6263160Swnj upaddr->upcs1 = UP_SEEK|UP_IE|UP_GO; 6273160Swnj goto nextrecal; 6283160Swnj case 2: 6293160Swnj if (um->um_tab.b_errcnt < 16 || (bp->b_flags&B_READ) == 0) 6303160Swnj goto donerecal; 6313445Sroot upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | UPOF_FMT22; 6323160Swnj upaddr->upcs1 = UP_IE|UP_OFFSET|UP_GO; 6333160Swnj goto nextrecal; 6343160Swnj nextrecal: 6353160Swnj sc->sc_recal++; 6363160Swnj um->um_tab.b_active = 1; 6373160Swnj return; 6383160Swnj donerecal: 6393160Swnj case 3: 6402674Swnj sc->sc_recal = 0; 6413160Swnj um->um_tab.b_active = 0; 6423160Swnj break; 6432674Swnj } 6442674Swnj /* 6452674Swnj * If still ``active'', then don't need any more retries. 6462674Swnj */ 6472674Swnj if (um->um_tab.b_active) { 6482674Swnj /* 6492674Swnj * If we were offset positioning, 6502674Swnj * return to centerline. 6512674Swnj */ 6522674Swnj if (um->um_tab.b_errcnt >= 16) { 6533445Sroot upaddr->upof = UPOF_FMT22; 6542674Swnj upaddr->upcs1 = UP_RTC|UP_GO|UP_IE; 6553445Sroot while (upaddr->upds & UPDS_PIP) 6562674Swnj DELAY(25); 657268Sbill needie = 0; 658264Sbill } 6592674Swnj um->um_tab.b_active = 0; 6602674Swnj um->um_tab.b_errcnt = 0; 6612674Swnj um->um_tab.b_actf = dp->b_forw; 6622674Swnj dp->b_active = 0; 6632674Swnj dp->b_errcnt = 0; 6642674Swnj dp->b_actf = bp->av_forw; 6652674Swnj bp->b_resid = (-upaddr->upwc * sizeof(short)); 6662674Swnj iodone(bp); 6672674Swnj /* 6682674Swnj * If this unit has more work to do, 6692674Swnj * then start it up right away. 6702674Swnj */ 6712674Swnj if (dp->b_actf) 6722674Swnj if (upustart(ui)) 673268Sbill needie = 0; 674264Sbill } 6752674Swnj as &= ~(1<<ui->ui_slave); 6763403Swnj /* 6773403Swnj * Release unibus resources and flush data paths. 6783403Swnj */ 6793403Swnj ubadone(um); 6802674Swnj doattn: 6812674Swnj /* 6822674Swnj * Process other units which need attention. 6832674Swnj * For each unit which needs attention, call 6842674Swnj * the unit start routine to place the slave 6852674Swnj * on the controller device queue. 6862674Swnj */ 6873160Swnj while (unit = ffs(as)) { 6883160Swnj unit--; /* was 1 origin */ 6893160Swnj as &= ~(1<<unit); 6903160Swnj upaddr->upas = 1<<unit; 6916383Swnj if (unit < UPIPUNITS && upustart(upip[sc21][unit])) 6923160Swnj needie = 0; 6933160Swnj } 6942674Swnj /* 6952674Swnj * If the controller is not transferring, but 6962674Swnj * there are devices ready to transfer, start 6972674Swnj * the controller. 6982674Swnj */ 6992395Swnj if (um->um_tab.b_actf && um->um_tab.b_active == 0) 7002395Swnj if (upstart(um)) 701268Sbill needie = 0; 702275Sbill if (needie) 7032629Swnj upaddr->upcs1 = UP_IE; 704264Sbill } 705264Sbill 7069357Ssam upread(dev, uio) 7072616Swnj dev_t dev; 7089357Ssam struct uio *uio; 709264Sbill { 7102616Swnj register int unit = minor(dev) >> 3; 7112470Swnj 7122616Swnj if (unit >= NUP) 7139357Ssam return (ENXIO); 7149357Ssam return (physio(upstrategy, &rupbuf[unit], dev, B_READ, minphys, uio)); 715264Sbill } 716264Sbill 7179357Ssam upwrite(dev, uio) 7182616Swnj dev_t dev; 7199357Ssam struct uio *uio; 720264Sbill { 7212616Swnj register int unit = minor(dev) >> 3; 7222470Swnj 7232616Swnj if (unit >= NUP) 7249357Ssam return (ENXIO); 7259357Ssam return (physio(upstrategy, &rupbuf[unit], dev, B_WRITE, minphys, uio)); 726264Sbill } 727264Sbill 728266Sbill /* 729266Sbill * Correct an ECC error, and restart the i/o to complete 730266Sbill * the transfer if necessary. This is quite complicated because 731266Sbill * the transfer may be going to an odd memory address base and/or 732266Sbill * across a page boundary. 733266Sbill */ 7349548Ssam upecc(ui, flag) 7352983Swnj register struct uba_device *ui; 7369548Ssam int flag; 737264Sbill { 7382629Swnj register struct updevice *up = (struct updevice *)ui->ui_addr; 7392395Swnj register struct buf *bp = uputab[ui->ui_unit].b_actf; 7402983Swnj register struct uba_ctlr *um = ui->ui_mi; 7412395Swnj register struct upst *st; 7422395Swnj struct uba_regs *ubp = ui->ui_hd->uh_uba; 743266Sbill register int i; 744264Sbill caddr_t addr; 745266Sbill int reg, bit, byte, npf, mask, o, cmd, ubaddr; 746264Sbill int bn, cn, tn, sn; 747264Sbill 748264Sbill /* 749266Sbill * Npf is the number of sectors transferred before the sector 750266Sbill * containing the ECC error, and reg is the UBA register 751266Sbill * mapping (the first part of) the transfer. 752266Sbill * O is offset within a memory page of the first byte transferred. 753264Sbill */ 7549548Ssam if (flag == CONT) 7559548Ssam npf = bp->b_error; 7569548Ssam else 75710858Ssam npf = btop((up->upwc * sizeof(short)) + bp->b_bcount); 7582571Swnj reg = btop(um->um_ubinfo&0x3ffff) + npf; 759264Sbill o = (int)bp->b_un.b_addr & PGOFSET; 760264Sbill mask = up->upec2; 7613445Sroot #ifdef UPECCDEBUG 7623403Swnj printf("npf %d reg %x o %d mask %o pos %d\n", npf, reg, o, mask, 7633403Swnj up->upec1); 7643445Sroot #endif 7659548Ssam bn = dkblock(bp); 7669548Ssam st = &upst[ui->ui_type]; 7679548Ssam cn = bp->b_cylin; 7689548Ssam sn = bn%st->nspc + npf; 7699548Ssam tn = sn/st->nsect; 7709548Ssam sn %= st->nsect; 7719548Ssam cn += tn/st->ntrak; 7729548Ssam tn %= st->ntrak; 7732725Swnj ubapurge(um); 7749548Ssam um->um_tab.b_active=2; 775266Sbill /* 7769548Ssam * action taken depends on the flag 777266Sbill */ 7789548Ssam switch(flag){ 7799548Ssam case ECC: 7809548Ssam npf--; 7819548Ssam reg--; 7829548Ssam mask = up->upec2; 7839548Ssam printf("up%d%c: soft ecc sn%d\n", dkunit(bp), 7849548Ssam 'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf); 7859548Ssam /* 7869548Ssam * Flush the buffered data path, and compute the 7879548Ssam * byte and bit position of the error. The variable i 7889548Ssam * is the byte offset in the transfer, the variable byte 7899548Ssam * is the offset from a page boundary in main memory. 7909548Ssam */ 7919548Ssam i = up->upec1 - 1; /* -1 makes 0 origin */ 7929548Ssam bit = i&07; 7939548Ssam i = (i&~07)>>3; 7949548Ssam byte = i + o; 7959548Ssam /* 7969548Ssam * Correct while possible bits remain of mask. Since mask 7979548Ssam * contains 11 bits, we continue while the bit offset is > -11. 7989548Ssam * Also watch out for end of this block and the end of the whole 7999548Ssam * transfer. 8009548Ssam */ 8019548Ssam while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 8029548Ssam addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ 8039548Ssam (byte & PGOFSET); 8043445Sroot #ifdef UPECCDEBUG 8059548Ssam printf("addr %x map reg %x\n", 8069548Ssam addr, *(int *)(&ubp->uba_map[reg+btop(byte)])); 8079548Ssam printf("old: %x, ", getmemc(addr)); 8083445Sroot #endif 8099548Ssam putmemc(addr, getmemc(addr)^(mask<<bit)); 8103445Sroot #ifdef UPECCDEBUG 8119548Ssam printf("new: %x\n", getmemc(addr)); 8123445Sroot #endif 8139548Ssam byte++; 8149548Ssam i++; 8159580Shelge bit -= 8; 8169548Ssam } 8179548Ssam if (up->upwc == 0) 8189548Ssam return (0); 8199548Ssam npf++; 8209548Ssam reg++; 8219548Ssam break; 8229548Ssam case BSE: 8239548Ssam /* 8249548Ssam * if not in bad sector table, return 0 8259548Ssam */ 8269548Ssam if ((bn = isbad(&upbad[ui->ui_unit], cn, tn, sn)) < 0) 8279548Ssam return(0); 8289548Ssam /* 8299548Ssam * flag this one as bad 8309548Ssam */ 8319548Ssam bp->b_flags |= B_BAD; 8329548Ssam bp->b_error = npf + 1; 8339548Ssam #ifdef UPECCDEBUG 8349548Ssam printf("BSE: restart at %d\n",npf+1); 8359548Ssam #endif 8369548Ssam bn = st->ncyl * st->nspc -st->nsect - 1 - bn; 8379548Ssam cn = bn / st->nspc; 8389548Ssam sn = bn % st->nspc; 8399548Ssam tn = sn / st->nsect; 8409548Ssam sn %= st->nsect; 8419548Ssam up->upwc = -(512 / sizeof (short)); 8429548Ssam #ifdef UPECCDEBUG 8439548Ssam printf("revector to cn %d tn %d sn %d\n", cn, tn, sn); 8449548Ssam #endif 8459548Ssam break; 8469548Ssam case CONT: 8479548Ssam #ifdef UPECCDEBUG 8489548Ssam printf("upecc, CONT: bn %d cn %d tn %d sn %d\n", bn, cn, tn, sn); 8499548Ssam #endif 8509548Ssam bp->b_flags &= ~B_BAD; 8519548Ssam up->upwc = -((bp->b_bcount - (int)ptob(npf)) / sizeof(short)); 8529548Ssam if (up->upwc == 0) 8539548Ssam return(0); 8549548Ssam break; 855264Sbill } 8567183Sroot if (up->upwc == 0) { 8577183Sroot um->um_tab.b_active = 0; 858264Sbill return (0); 8597183Sroot } 860266Sbill /* 861266Sbill * Have to continue the transfer... clear the drive, 862266Sbill * and compute the position where the transfer is to continue. 863266Sbill * We have completed npf+1 sectors of the transfer already; 864266Sbill * restart at offset o of next sector (i.e. in UBA register reg+1). 865266Sbill */ 8662629Swnj #ifdef notdef 8672629Swnj up->uper1 = 0; 8682629Swnj up->upcs1 |= UP_GO; 8692629Swnj #else 8702629Swnj up->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 871264Sbill up->updc = cn; 872266Sbill up->upda = (tn << 8) | sn; 8739548Ssam ubaddr = (int)ptob(reg) + o; 874266Sbill up->upba = ubaddr; 875266Sbill cmd = (ubaddr >> 8) & 0x300; 8769548Ssam cmd |= ((bp->b_flags&B_READ)?UP_RCOM:UP_WCOM)|UP_IE|UP_GO; 8779548Ssam um->um_tab.b_errcnt = 0; 878266Sbill up->upcs1 = cmd; 8792629Swnj #endif 880264Sbill return (1); 881264Sbill } 882286Sbill 883286Sbill /* 884286Sbill * Reset driver after UBA init. 885286Sbill * Cancel software state of all pending transfers 886286Sbill * and restart all units and the controller. 887286Sbill */ 8882395Swnj upreset(uban) 8892931Swnj int uban; 890286Sbill { 8912983Swnj register struct uba_ctlr *um; 8922983Swnj register struct uba_device *ui; 8932395Swnj register sc21, unit; 894286Sbill 8952646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 8962470Swnj if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban || 8972470Swnj um->um_alive == 0) 8982395Swnj continue; 8992931Swnj printf(" sc%d", sc21); 9002395Swnj um->um_tab.b_active = 0; 9012395Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 9022931Swnj up_softc[sc21].sc_recal = 0; 9036346Swnj up_softc[sc21].sc_wticks = 0; 9042571Swnj if (um->um_ubinfo) { 9052571Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 9069357Ssam um->um_ubinfo = 0; 9072395Swnj } 9083445Sroot ((struct updevice *)(um->um_addr))->upcs2 = UPCS2_CLR; 9092395Swnj for (unit = 0; unit < NUP; unit++) { 9102395Swnj if ((ui = updinfo[unit]) == 0) 9112395Swnj continue; 9122931Swnj if (ui->ui_alive == 0 || ui->ui_mi != um) 9132395Swnj continue; 9142395Swnj uputab[unit].b_active = 0; 9152395Swnj (void) upustart(ui); 9162395Swnj } 9172395Swnj (void) upstart(um); 918286Sbill } 919286Sbill } 920313Sbill 921313Sbill /* 922313Sbill * Wake up every second and if an interrupt is pending 923313Sbill * but nothing has happened increment a counter. 9242931Swnj * If nothing happens for 20 seconds, reset the UNIBUS 925313Sbill * and begin anew. 926313Sbill */ 927313Sbill upwatch() 928313Sbill { 9292983Swnj register struct uba_ctlr *um; 9302395Swnj register sc21, unit; 9312470Swnj register struct up_softc *sc; 932313Sbill 9332759Swnj timeout(upwatch, (caddr_t)0, hz); 9342646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 9352395Swnj um = upminfo[sc21]; 9362470Swnj if (um == 0 || um->um_alive == 0) 9372470Swnj continue; 9382470Swnj sc = &up_softc[sc21]; 9392395Swnj if (um->um_tab.b_active == 0) { 9402395Swnj for (unit = 0; unit < NUP; unit++) 9412629Swnj if (uputab[unit].b_active && 9422629Swnj updinfo[unit]->ui_mi == um) 9432395Swnj goto active; 9442470Swnj sc->sc_wticks = 0; 9452395Swnj continue; 9462395Swnj } 9472931Swnj active: 9482470Swnj sc->sc_wticks++; 9492470Swnj if (sc->sc_wticks >= 20) { 9502470Swnj sc->sc_wticks = 0; 9512931Swnj printf("sc%d: lost interrupt\n", sc21); 9522646Swnj ubareset(um->um_ubanum); 9532395Swnj } 954313Sbill } 955313Sbill } 9562379Swnj 9572379Swnj #define DBSIZE 20 9582379Swnj 9592379Swnj updump(dev) 9602379Swnj dev_t dev; 9612379Swnj { 9622629Swnj struct updevice *upaddr; 9632379Swnj char *start; 9643107Swnj int num, blk, unit; 9652379Swnj struct size *sizes; 9662395Swnj register struct uba_regs *uba; 9672983Swnj register struct uba_device *ui; 9682379Swnj register short *rp; 9692395Swnj struct upst *st; 9706848Ssam register int retry; 9712379Swnj 9722395Swnj unit = minor(dev) >> 3; 9732889Swnj if (unit >= NUP) 9742889Swnj return (ENXIO); 9752470Swnj #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) 9762983Swnj ui = phys(struct uba_device *, updinfo[unit]); 9772889Swnj if (ui->ui_alive == 0) 9782889Swnj return (ENXIO); 9792395Swnj uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 9802983Swnj ubainit(uba); 9812629Swnj upaddr = (struct updevice *)ui->ui_physaddr; 9826848Ssam DELAY(5000000); 9832379Swnj num = maxfree; 9842379Swnj upaddr->upcs2 = unit; 9852983Swnj DELAY(100); 9866848Ssam upaddr->upcs1 = UP_DCLR|UP_GO; 9876848Ssam upaddr->upcs1 = UP_PRESET|UP_GO; 9886848Ssam upaddr->upof = UPOF_FMT22; 9896848Ssam retry = 0; 9906848Ssam do { 9916848Ssam DELAY(25); 9926848Ssam if (++retry > 527) 9936848Ssam break; 9946861Ssam } while ((upaddr->upds & UP_RDY) == 0); 9953445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) 9962889Swnj return (EFAULT); 9979357Ssam start = 0; 9988489Sroot st = &upst[ui->ui_type]; 9992395Swnj sizes = phys(struct size *, st->sizes); 10002889Swnj if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) 10012889Swnj return (EINVAL); 10022379Swnj while (num > 0) { 10032379Swnj register struct pte *io; 10042379Swnj register int i; 10052379Swnj int cn, sn, tn; 10062379Swnj daddr_t bn; 10072379Swnj 10082379Swnj blk = num > DBSIZE ? DBSIZE : num; 10092395Swnj io = uba->uba_map; 10102379Swnj for (i = 0; i < blk; i++) 10112983Swnj *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV; 10122379Swnj *(int *)io = 0; 10132379Swnj bn = dumplo + btop(start); 10142607Swnj cn = bn/st->nspc + sizes[minor(dev)&07].cyloff; 10152607Swnj sn = bn%st->nspc; 10162607Swnj tn = sn/st->nsect; 10172607Swnj sn = sn%st->nsect; 10182379Swnj upaddr->updc = cn; 10192379Swnj rp = (short *) &upaddr->upda; 10202379Swnj *rp = (tn << 8) + sn; 10212379Swnj *--rp = 0; 10222379Swnj *--rp = -blk*NBPG / sizeof (short); 10232629Swnj *--rp = UP_GO|UP_WCOM; 10246848Ssam retry = 0; 10252379Swnj do { 10262379Swnj DELAY(25); 10276848Ssam if (++retry > 527) 10286848Ssam break; 10292629Swnj } while ((upaddr->upcs1 & UP_RDY) == 0); 10306848Ssam if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 10316861Ssam printf("up%d: not ready", unit); 10326848Ssam if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 10336848Ssam printf("\n"); 10346848Ssam return (EIO); 10356848Ssam } 10366848Ssam printf(" (flakey)\n"); 10376848Ssam } 10383445Sroot if (upaddr->upds&UPDS_ERR) 10392889Swnj return (EIO); 10402379Swnj start += blk*NBPG; 10412379Swnj num -= blk; 10422379Swnj } 10432379Swnj return (0); 10442379Swnj } 104512505Ssam 104612505Ssam upsize(dev) 104712505Ssam dev_t dev; 104812505Ssam { 104912505Ssam int unit = minor(dev) >> 3; 105012505Ssam struct uba_device *ui; 105112505Ssam struct upst *st; 105212505Ssam 105312505Ssam if (unit >= NUP || (ui = updinfo[unit]) == 0 || ui->ui_alive == 0) 105412505Ssam return (-1); 105512505Ssam st = &upst[ui->ui_type]; 105612505Ssam return (st->sizes[minor(dev) & 07].nblocks); 105712505Ssam } 10581902Swnj #endif 1059