123355Smckusick /* 223355Smckusick * Copyright (c) 1982 Regents of the University of California. 323355Smckusick * All rights reserved. The Berkeley software License Agreement 423355Smckusick * specifies the terms and conditions for redistribution. 523355Smckusick * 6*24213Sbloom * @(#)up.c 6.6 (Berkeley) 08/08/85 723355Smckusick */ 8264Sbill 91937Swnj #include "up.h" 102646Swnj #if NSC > 0 11264Sbill /* 129548Ssam * UNIBUS disk driver with: 139548Ssam * overlapped seeks, 149548Ssam * ECC recovery, and 159548Ssam * bad sector forwarding. 162889Swnj * 172889Swnj * TODO: 183445Sroot * Check that offset recovery code works 19264Sbill */ 209782Ssam #include "../machine/pte.h" 21264Sbill 2217082Sbloom #include "param.h" 2317082Sbloom #include "systm.h" 2417082Sbloom #include "dk.h" 2517082Sbloom #include "dkbad.h" 2617082Sbloom #include "buf.h" 2717082Sbloom #include "conf.h" 2817082Sbloom #include "dir.h" 2917082Sbloom #include "user.h" 3017082Sbloom #include "map.h" 3117082Sbloom #include "vm.h" 3217082Sbloom #include "cmap.h" 3317082Sbloom #include "uio.h" 3417082Sbloom #include "kernel.h" 3518317Sralph #include "syslog.h" 36264Sbill 379357Ssam #include "../vax/cpu.h" 389357Ssam #include "../vax/nexus.h" 3917082Sbloom #include "ubavar.h" 4017082Sbloom #include "ubareg.h" 4117082Sbloom #include "upreg.h" 429357Ssam 432395Swnj struct up_softc { 442395Swnj int sc_softas; 452607Swnj int sc_ndrive; 462395Swnj int sc_wticks; 472674Swnj int sc_recal; 482646Swnj } up_softc[NSC]; 49275Sbill 502395Swnj /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 5110858Ssam struct size { 52264Sbill daddr_t nblocks; 53264Sbill int cyloff; 5411211Ssam } up9300_sizes[8] = { 55264Sbill 15884, 0, /* A=cyl 0 thru 26 */ 56264Sbill 33440, 27, /* B=cyl 27 thru 81 */ 57341Sbill 495520, 0, /* C=cyl 0 thru 814 */ 58264Sbill 15884, 562, /* D=cyl 562 thru 588 */ 59264Sbill 55936, 589, /* E=cyl 589 thru 680 */ 603730Sroot 81376, 681, /* F=cyl 681 thru 814 */ 613730Sroot 153728, 562, /* G=cyl 562 thru 814 */ 62264Sbill 291346, 82, /* H=cyl 82 thru 561 */ 6311211Ssam }, up9766_sizes[8] = { 6411211Ssam 15884, 0, /* A=cyl 0 thru 26 */ 6511211Ssam 33440, 27, /* B=cyl 27 thru 81 */ 6611211Ssam 500384, 0, /* C=cyl 0 thru 822 */ 6711211Ssam 15884, 562, /* D=cyl 562 thru 588 */ 6811211Ssam 55936, 589, /* E=cyl 589 thru 680 */ 6911211Ssam 86240, 681, /* F=cyl 681 thru 822 */ 7011211Ssam 158592, 562, /* G=cyl 562 thru 822 */ 7111211Ssam 291346, 82, /* H=cyl 82 thru 561 */ 7211211Ssam }, up160_sizes[8] = { 732395Swnj 15884, 0, /* A=cyl 0 thru 49 */ 742395Swnj 33440, 50, /* B=cyl 50 thru 154 */ 752395Swnj 263360, 0, /* C=cyl 0 thru 822 */ 7611211Ssam 15884, 155, /* D=cyl 155 thru 204 */ 7711211Ssam 55936, 205, /* E=cyl 205 thru 379 */ 7811211Ssam 141664, 380, /* F=cyl 380 thru 822 */ 7911211Ssam 213664, 155, /* G=cyl 155 thru 822 */ 802395Swnj 0, 0, 816851Ssam }, upam_sizes[8] = { 826305Sroot 15884, 0, /* A=cyl 0 thru 31 */ 836305Sroot 33440, 32, /* B=cyl 32 thru 97 */ 846305Sroot 524288, 0, /* C=cyl 0 thru 1023 */ 8511211Ssam 15884, 668, /* D=cyl 668 thru 699 */ 8611211Ssam 55936, 700, /* E=cyl 700 thru 809 */ 8711211Ssam 109472, 810, /* F=cyl 810 thru 1023 */ 8811211Ssam 182176, 668, /* G=cyl 668 thru 1023 */ 896305Sroot 291346, 98, /* H=cyl 98 thru 667 */ 9014002Ssam }, up980_sizes[8] = { 9114002Ssam 15884, 0, /* A=cyl 0 thru 99 */ 9214002Ssam 33440, 100, /* B=cyl 100 thru 308 */ 9314002Ssam 131680, 0, /* C=cyl 0 thru 822 */ 9414002Ssam 15884, 309, /* D=cyl 309 thru 408 */ 9514002Ssam 55936, 409, /* E=cyl 409 thru 758 */ 9614002Ssam 10080, 759, /* F=cyl 759 thru 822 */ 9714002Ssam 82080, 309, /* G=cyl 309 thru 822 */ 9814002Ssam 0, 0, 9921977Sbloom }, upeagle_sizes[8] = { 10021977Sbloom 15884, 0, /* A=cyl 0 thru 16 */ 10121977Sbloom 66880, 17, /* B=cyl 17 thru 86 */ 10221977Sbloom 808320, 0, /* C=cyl 0 thru 841 */ 10321977Sbloom 15884, 391, /* D=cyl 391 thru 407 */ 10421977Sbloom 307200, 408, /* E=cyl 408 thru 727 */ 10521977Sbloom 109296, 728, /* F=cyl 728 thru 841 */ 10621977Sbloom 432816, 391, /* G=cyl 391 thru 841 */ 10721977Sbloom 291346, 87, /* H=cyl 87 thru 390 */ 108264Sbill }; 1092395Swnj /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 110264Sbill 1112607Swnj int upprobe(), upslave(), upattach(), updgo(), upintr(); 1122983Swnj struct uba_ctlr *upminfo[NSC]; 1132983Swnj struct uba_device *updinfo[NUP]; 1146383Swnj #define UPIPUNITS 8 1156383Swnj struct uba_device *upip[NSC][UPIPUNITS]; /* fuji w/fixed head gives n,n+4 */ 1162395Swnj 1172607Swnj u_short upstd[] = { 0776700, 0774400, 0776300, 0 }; 1182616Swnj struct uba_driver scdriver = 1192607Swnj { upprobe, upslave, upattach, updgo, upstd, "up", updinfo, "sc", upminfo }; 1202395Swnj struct buf uputab[NUP]; 1219548Ssam char upinit[NUP]; 1222395Swnj 1232395Swnj struct upst { 12412837Ssam short nsect; /* # sectors/track */ 12512837Ssam short ntrak; /* # tracks/cylinder */ 12612837Ssam short nspc; /* # sectors/cylinder */ 12712837Ssam short ncyl; /* # cylinders */ 12812837Ssam struct size *sizes; /* partition tables */ 12912837Ssam short sdist; /* seek distance metric */ 13012837Ssam short rdist; /* rotational distance metric */ 1312395Swnj } upst[] = { 13212837Ssam { 32, 19, 32*19, 815, up9300_sizes, 3, 4 }, /* 9300 */ 13312837Ssam { 32, 19, 32*19, 823, up9766_sizes, 3, 4 }, /* 9766 */ 13412837Ssam { 32, 10, 32*10, 823, up160_sizes, 3, 4 }, /* fuji 160m */ 13512837Ssam { 32, 16, 32*16, 1024, upam_sizes, 7, 8 }, /* Capricorn */ 13614002Ssam { 32, 5, 32*5, 823, up980_sizes, 3, 4 }, /* DM980 */ 13721977Sbloom { 48, 20, 48*20, 842, upeagle_sizes, 15, 8 }, /* EAGLE */ 13812837Ssam { 0, 0, 0, 0, 0, 0, 0 } 1392395Swnj }; 1402395Swnj 1412629Swnj u_char up_offset[16] = { 1429548Ssam UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400, 1439548Ssam UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800, 1449548Ssam UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200, 1459548Ssam 0, 0, 0, 0 1462629Swnj }; 147264Sbill 1482616Swnj struct buf rupbuf[NUP]; 1499548Ssam struct buf bupbuf[NUP]; 1509548Ssam struct dkbad upbad[NUP]; 151264Sbill 152264Sbill #define b_cylin b_resid 153264Sbill 154264Sbill #ifdef INTRLVE 155264Sbill daddr_t dkblock(); 156264Sbill #endif 1572395Swnj 1582395Swnj int upwstart, upwatch(); /* Have started guardian */ 1592470Swnj int upseek; 1602681Swnj int upwaitdry; 1612395Swnj 1622395Swnj /*ARGSUSED*/ 1632607Swnj upprobe(reg) 1642395Swnj caddr_t reg; 1652395Swnj { 1662459Swnj register int br, cvec; 1672459Swnj 1682607Swnj #ifdef lint 16912779Ssam br = 0; cvec = br; br = cvec; upintr(0); 1702607Swnj #endif 1712629Swnj ((struct updevice *)reg)->upcs1 = UP_IE|UP_RDY; 1722607Swnj DELAY(10); 1732629Swnj ((struct updevice *)reg)->upcs1 = 0; 1749357Ssam return (sizeof (struct updevice)); 1752395Swnj } 1762395Swnj 1772607Swnj upslave(ui, reg) 1782983Swnj struct uba_device *ui; 1792395Swnj caddr_t reg; 1802395Swnj { 1812629Swnj register struct updevice *upaddr = (struct updevice *)reg; 1822395Swnj 1832395Swnj upaddr->upcs1 = 0; /* conservative */ 1842607Swnj upaddr->upcs2 = ui->ui_slave; 1856843Swnj upaddr->upcs1 = UP_NOP|UP_GO; 1863445Sroot if (upaddr->upcs2&UPCS2_NED) { 1872629Swnj upaddr->upcs1 = UP_DCLR|UP_GO; 1882395Swnj return (0); 1892395Swnj } 1902607Swnj return (1); 1912607Swnj } 1922607Swnj 1932607Swnj upattach(ui) 1942983Swnj register struct uba_device *ui; 1952607Swnj { 1962607Swnj 1972395Swnj if (upwstart == 0) { 1982759Swnj timeout(upwatch, (caddr_t)0, hz); 1992395Swnj upwstart++; 2002395Swnj } 2012571Swnj if (ui->ui_dk >= 0) 2022571Swnj dk_mspw[ui->ui_dk] = .0000020345; 2032607Swnj upip[ui->ui_ctlr][ui->ui_slave] = ui; 2042607Swnj up_softc[ui->ui_ctlr].sc_ndrive++; 20511119Ssam ui->ui_type = upmaptype(ui); 20611119Ssam } 20711119Ssam 20811119Ssam upmaptype(ui) 20911119Ssam register struct uba_device *ui; 21011119Ssam { 21111119Ssam register struct updevice *upaddr = (struct updevice *)ui->ui_addr; 21211119Ssam int type = ui->ui_type; 21311119Ssam register struct upst *st; 21411119Ssam 2152629Swnj upaddr->upcs1 = 0; 2162629Swnj upaddr->upcs2 = ui->ui_slave; 2173496Sroot upaddr->uphr = UPHR_MAXTRAK; 21811119Ssam for (st = upst; st->nsect != 0; st++) 21911119Ssam if (upaddr->uphr == st->ntrak - 1) { 22011119Ssam type = st - upst; 22111119Ssam break; 22211119Ssam } 22311119Ssam if (st->nsect == 0) 22411119Ssam printf("up%d: uphr=%x\n", ui->ui_slave, upaddr->uphr); 22511119Ssam if (type == 0) { 22611112Shelge upaddr->uphr = UPHR_MAXCYL; 22711112Shelge if (upaddr->uphr == 822) 22811119Ssam type++; 22911112Shelge } 2303496Sroot upaddr->upcs2 = UPCS2_CLR; 23111119Ssam return (type); 2322395Swnj } 233264Sbill 2349548Ssam upopen(dev) 2359548Ssam dev_t dev; 2369548Ssam { 2379548Ssam register int unit = minor(dev) >> 3; 2389548Ssam register struct uba_device *ui; 2399548Ssam 2409548Ssam if (unit >= NUP || (ui = updinfo[unit]) == 0 || ui->ui_alive == 0) 2419548Ssam return (ENXIO); 2429548Ssam return (0); 2439548Ssam } 2449548Ssam 245264Sbill upstrategy(bp) 2462395Swnj register struct buf *bp; 247264Sbill { 2482983Swnj register struct uba_device *ui; 2492395Swnj register struct upst *st; 2502395Swnj register int unit; 2512470Swnj register struct buf *dp; 2522395Swnj int xunit = minor(bp->b_dev) & 07; 2532470Swnj long bn, sz; 25421977Sbloom int s; 255264Sbill 2562470Swnj sz = (bp->b_bcount+511) >> 9; 257264Sbill unit = dkunit(bp); 2582395Swnj if (unit >= NUP) 2592395Swnj goto bad; 2602395Swnj ui = updinfo[unit]; 2612395Swnj if (ui == 0 || ui->ui_alive == 0) 2622395Swnj goto bad; 2632395Swnj st = &upst[ui->ui_type]; 2642395Swnj if (bp->b_blkno < 0 || 2652395Swnj (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) 2662395Swnj goto bad; 2672395Swnj bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 26821977Sbloom s = spl5(); 2692470Swnj dp = &uputab[ui->ui_unit]; 2702470Swnj disksort(dp, bp); 2712470Swnj if (dp->b_active == 0) { 2722395Swnj (void) upustart(ui); 2732395Swnj bp = &ui->ui_mi->um_tab; 2742395Swnj if (bp->b_actf && bp->b_active == 0) 2752395Swnj (void) upstart(ui->ui_mi); 276264Sbill } 27721977Sbloom splx(s); 2782395Swnj return; 2792395Swnj 2802395Swnj bad: 2812395Swnj bp->b_flags |= B_ERROR; 2822395Swnj iodone(bp); 2832395Swnj return; 284264Sbill } 285264Sbill 2862674Swnj /* 2872674Swnj * Unit start routine. 2882674Swnj * Seek the drive to be where the data is 2892674Swnj * and then generate another interrupt 2902674Swnj * to actually start the transfer. 2912674Swnj * If there is only one drive on the controller, 2922674Swnj * or we are very close to the data, don't 2932674Swnj * bother with the search. If called after 2942674Swnj * searching once, don't bother to look where 2952674Swnj * we are, just queue for transfer (to avoid 2962674Swnj * positioning forever without transferrring.) 2972674Swnj */ 2982395Swnj upustart(ui) 2992983Swnj register struct uba_device *ui; 300264Sbill { 301264Sbill register struct buf *bp, *dp; 3022983Swnj register struct uba_ctlr *um; 3032629Swnj register struct updevice *upaddr; 3042395Swnj register struct upst *st; 305264Sbill daddr_t bn; 3062674Swnj int sn, csn; 3072607Swnj /* 3082607Swnj * The SC21 cancels commands if you just say 3092629Swnj * cs1 = UP_IE 3102607Swnj * so we are cautious about handling of cs1. 3112607Swnj * Also don't bother to clear as bits other than in upintr(). 3122607Swnj */ 3132674Swnj int didie = 0; 3142674Swnj 3152674Swnj if (ui == 0) 3162674Swnj return (0); 3172983Swnj um = ui->ui_mi; 3182395Swnj dk_busy &= ~(1<<ui->ui_dk); 3192395Swnj dp = &uputab[ui->ui_unit]; 320266Sbill if ((bp = dp->b_actf) == NULL) 321268Sbill goto out; 3222674Swnj /* 3232674Swnj * If the controller is active, just remember 3242674Swnj * that this device would like to be positioned... 3252674Swnj * if we tried to position now we would confuse the SC21. 3262674Swnj */ 3272395Swnj if (um->um_tab.b_active) { 3282459Swnj up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave; 329275Sbill return (0); 330275Sbill } 3312674Swnj /* 3322674Swnj * If we have already positioned this drive, 3332674Swnj * then just put it on the ready queue. 3342674Swnj */ 335276Sbill if (dp->b_active) 336276Sbill goto done; 337276Sbill dp->b_active = 1; 3382629Swnj upaddr = (struct updevice *)um->um_addr; 3392395Swnj upaddr->upcs2 = ui->ui_slave; 3402674Swnj /* 3412674Swnj * If drive has just come up, 3422674Swnj * setup the pack. 3432674Swnj */ 3449548Ssam if ((upaddr->upds & UPDS_VV) == 0 || upinit[ui->ui_unit] == 0) { 3459548Ssam struct buf *bbp = &bupbuf[ui->ui_unit]; 34610858Ssam 3472607Swnj /* SHOULD WARN SYSTEM THAT THIS HAPPENED */ 3489548Ssam upinit[ui->ui_unit] = 1; 3492629Swnj upaddr->upcs1 = UP_IE|UP_DCLR|UP_GO; 3502629Swnj upaddr->upcs1 = UP_IE|UP_PRESET|UP_GO; 3513445Sroot upaddr->upof = UPOF_FMT22; 352268Sbill didie = 1; 3539548Ssam st = &upst[ui->ui_type]; 3549548Ssam bbp->b_flags = B_READ|B_BUSY; 3559548Ssam bbp->b_dev = bp->b_dev; 3569548Ssam bbp->b_bcount = 512; 3579548Ssam bbp->b_un.b_addr = (caddr_t)&upbad[ui->ui_unit]; 3589548Ssam bbp->b_blkno = st->ncyl * st->nspc - st->nsect; 3599548Ssam bbp->b_cylin = st->ncyl - 1; 3609548Ssam dp->b_actf = bbp; 3619548Ssam bbp->av_forw = bp; 3629548Ssam bp = bbp; 363264Sbill } 3642674Swnj /* 3652674Swnj * If drive is offline, forget about positioning. 3662674Swnj */ 3673445Sroot if ((upaddr->upds & (UPDS_DPR|UPDS_MOL)) != (UPDS_DPR|UPDS_MOL)) 368275Sbill goto done; 3692674Swnj /* 3702674Swnj * If there is only one drive, 3712674Swnj * dont bother searching. 3722674Swnj */ 3732607Swnj if (up_softc[um->um_ctlr].sc_ndrive == 1) 3742607Swnj goto done; 3752674Swnj /* 3762674Swnj * Figure out where this transfer is going to 3772674Swnj * and see if we are close enough to justify not searching. 3782674Swnj */ 3792395Swnj st = &upst[ui->ui_type]; 380264Sbill bn = dkblock(bp); 3812395Swnj sn = bn%st->nspc; 38212837Ssam sn = (sn + st->nsect - st->sdist) % st->nsect; 3832674Swnj if (bp->b_cylin - upaddr->updc) 384266Sbill goto search; /* Not on-cylinder */ 385275Sbill else if (upseek) 386275Sbill goto done; /* Ok just to be on-cylinder */ 387264Sbill csn = (upaddr->upla>>6) - sn - 1; 388266Sbill if (csn < 0) 3892395Swnj csn += st->nsect; 39012837Ssam if (csn > st->nsect - st->rdist) 391264Sbill goto done; 392264Sbill search: 3932674Swnj upaddr->updc = bp->b_cylin; 3942674Swnj /* 3952674Swnj * Not on cylinder at correct position, 3962674Swnj * seek/search. 3972674Swnj */ 398275Sbill if (upseek) 3992629Swnj upaddr->upcs1 = UP_IE|UP_SEEK|UP_GO; 4002470Swnj else { 401275Sbill upaddr->upda = sn; 4022629Swnj upaddr->upcs1 = UP_IE|UP_SEARCH|UP_GO; 403275Sbill } 404268Sbill didie = 1; 4052674Swnj /* 4062674Swnj * Mark unit busy for iostat. 4072674Swnj */ 4082395Swnj if (ui->ui_dk >= 0) { 4092395Swnj dk_busy |= 1<<ui->ui_dk; 4102395Swnj dk_seek[ui->ui_dk]++; 411264Sbill } 412268Sbill goto out; 413264Sbill done: 4142674Swnj /* 4152674Swnj * Device is ready to go. 4162674Swnj * Put it on the ready queue for the controller 4172674Swnj * (unless its already there.) 4182674Swnj */ 4192629Swnj if (dp->b_active != 2) { 4202629Swnj dp->b_forw = NULL; 4212629Swnj if (um->um_tab.b_actf == NULL) 4222629Swnj um->um_tab.b_actf = dp; 4232629Swnj else 4242629Swnj um->um_tab.b_actl->b_forw = dp; 4252629Swnj um->um_tab.b_actl = dp; 4262629Swnj dp->b_active = 2; 4272629Swnj } 428268Sbill out: 429268Sbill return (didie); 430264Sbill } 431264Sbill 4322674Swnj /* 4332674Swnj * Start up a transfer on a drive. 4342674Swnj */ 4352395Swnj upstart(um) 4362983Swnj register struct uba_ctlr *um; 437264Sbill { 438264Sbill register struct buf *bp, *dp; 4392983Swnj register struct uba_device *ui; 4402629Swnj register struct updevice *upaddr; 4412470Swnj struct upst *st; 442264Sbill daddr_t bn; 4432681Swnj int dn, sn, tn, cmd, waitdry; 444264Sbill 445264Sbill loop: 4462674Swnj /* 4472674Swnj * Pull a request off the controller queue 4482674Swnj */ 4492395Swnj if ((dp = um->um_tab.b_actf) == NULL) 450268Sbill return (0); 451264Sbill if ((bp = dp->b_actf) == NULL) { 4522395Swnj um->um_tab.b_actf = dp->b_forw; 453264Sbill goto loop; 454264Sbill } 4552674Swnj /* 4562674Swnj * Mark controller busy, and 4572674Swnj * determine destination of this request. 4582674Swnj */ 4592395Swnj um->um_tab.b_active++; 4602395Swnj ui = updinfo[dkunit(bp)]; 461264Sbill bn = dkblock(bp); 4622395Swnj dn = ui->ui_slave; 4632395Swnj st = &upst[ui->ui_type]; 4642395Swnj sn = bn%st->nspc; 4652395Swnj tn = sn/st->nsect; 4662395Swnj sn %= st->nsect; 4672629Swnj upaddr = (struct updevice *)ui->ui_addr; 4682674Swnj /* 4692674Swnj * Select drive if not selected already. 4702674Swnj */ 4712674Swnj if ((upaddr->upcs2&07) != dn) 4722674Swnj upaddr->upcs2 = dn; 4732674Swnj /* 4742674Swnj * Check that it is ready and online 4752674Swnj */ 4762681Swnj waitdry = 0; 4773445Sroot while ((upaddr->upds&UPDS_DRY) == 0) { 4787036Swnj printf("up%d: ds wait ds=%o\n",dkunit(bp),upaddr->upds); 4792681Swnj if (++waitdry > 512) 4802681Swnj break; 4812681Swnj upwaitdry++; 4822681Swnj } 4833445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 4842931Swnj printf("up%d: not ready", dkunit(bp)); 4853445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 4862607Swnj printf("\n"); 4872395Swnj um->um_tab.b_active = 0; 4882395Swnj um->um_tab.b_errcnt = 0; 489893Sbill dp->b_actf = bp->av_forw; 490893Sbill dp->b_active = 0; 491893Sbill bp->b_flags |= B_ERROR; 492893Sbill iodone(bp); 493893Sbill goto loop; 494893Sbill } 4952674Swnj /* 4962674Swnj * Oh, well, sometimes this 4972674Swnj * happens, for reasons unknown. 4982674Swnj */ 4992629Swnj printf(" (flakey)\n"); 500264Sbill } 5012674Swnj /* 5022674Swnj * Setup for the transfer, and get in the 5032674Swnj * UNIBUS adaptor queue. 5042674Swnj */ 5052424Skre upaddr->updc = bp->b_cylin; 506264Sbill upaddr->upda = (tn << 8) + sn; 507264Sbill upaddr->upwc = -bp->b_bcount / sizeof (short); 508264Sbill if (bp->b_flags & B_READ) 5092629Swnj cmd = UP_IE|UP_RCOM|UP_GO; 510264Sbill else 5112629Swnj cmd = UP_IE|UP_WCOM|UP_GO; 5122571Swnj um->um_cmd = cmd; 5133107Swnj (void) ubago(ui); 514268Sbill return (1); 515264Sbill } 516264Sbill 5172674Swnj /* 5182674Swnj * Now all ready to go, stuff the registers. 5192674Swnj */ 5202571Swnj updgo(um) 5212983Swnj struct uba_ctlr *um; 5222395Swnj { 5232629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 5242470Swnj 5256953Swnj um->um_tab.b_active = 2; /* should now be 2 */ 5262571Swnj upaddr->upba = um->um_ubinfo; 5272571Swnj upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300); 5282395Swnj } 5292395Swnj 5302674Swnj /* 5312674Swnj * Handle a disk interrupt. 5322674Swnj */ 5332707Swnj upintr(sc21) 5342395Swnj register sc21; 535264Sbill { 536264Sbill register struct buf *bp, *dp; 5372983Swnj register struct uba_ctlr *um = upminfo[sc21]; 5382983Swnj register struct uba_device *ui; 5392629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 540264Sbill register unit; 5412470Swnj struct up_softc *sc = &up_softc[um->um_ctlr]; 5422607Swnj int as = (upaddr->upas & 0377) | sc->sc_softas; 5432681Swnj int needie = 1, waitdry; 544264Sbill 5452470Swnj sc->sc_wticks = 0; 5462607Swnj sc->sc_softas = 0; 5472674Swnj /* 5482674Swnj * If controller wasn't transferring, then this is an 5492674Swnj * interrupt for attention status on seeking drives. 5502674Swnj * Just service them. 5512674Swnj */ 5526346Swnj if (um->um_tab.b_active != 2 && !sc->sc_recal) { 5532674Swnj if (upaddr->upcs1 & UP_TRE) 5542674Swnj upaddr->upcs1 = UP_TRE; 5552674Swnj goto doattn; 5562674Swnj } 5576953Swnj um->um_tab.b_active = 1; 5582674Swnj /* 5592674Swnj * Get device and block structures, and a pointer 5602983Swnj * to the uba_device for the drive. Select the drive. 5612674Swnj */ 5622674Swnj dp = um->um_tab.b_actf; 5632674Swnj bp = dp->b_actf; 5642674Swnj ui = updinfo[dkunit(bp)]; 5652674Swnj dk_busy &= ~(1 << ui->ui_dk); 5662674Swnj if ((upaddr->upcs2&07) != ui->ui_slave) 5672395Swnj upaddr->upcs2 = ui->ui_slave; 5689548Ssam if (bp->b_flags&B_BAD) { 5699548Ssam if (upecc(ui, CONT)) 5709548Ssam return; 5719548Ssam } 5722674Swnj /* 5732674Swnj * Check for and process errors on 5742674Swnj * either the drive or the controller. 5752674Swnj */ 5763445Sroot if ((upaddr->upds&UPDS_ERR) || (upaddr->upcs1&UP_TRE)) { 5772681Swnj waitdry = 0; 5783445Sroot while ((upaddr->upds & UPDS_DRY) == 0) { 5792681Swnj if (++waitdry > 512) 5802681Swnj break; 5812681Swnj upwaitdry++; 5822681Swnj } 5833445Sroot if (upaddr->uper1&UPER1_WLE) { 5842674Swnj /* 5852674Swnj * Give up on write locked devices 5862674Swnj * immediately. 5872674Swnj */ 5882931Swnj printf("up%d: write locked\n", dkunit(bp)); 5892674Swnj bp->b_flags |= B_ERROR; 5902674Swnj } else if (++um->um_tab.b_errcnt > 27) { 5912674Swnj /* 5922674Swnj * After 28 retries (16 without offset, and 5932674Swnj * 12 with offset positioning) give up. 59410904Shelge * If the error was header CRC, the header is 59510904Shelge * screwed up, and the sector may in fact exist 59610904Shelge * in the bad sector table, better check... 5972674Swnj */ 59810904Shelge if (upaddr->uper1&UPER1_HCRC) { 59910904Shelge if (upecc(ui, BSE)) 60010904Shelge return; 60110904Shelge } 6029548Ssam hard: 6032931Swnj harderr(bp, "up"); 6049548Ssam printf("cn=%d tn=%d sn=%d cs2=%b er1=%b er2=%b\n", 6059548Ssam upaddr->updc, ((upaddr->upda)>>8)&077, 6069548Ssam (upaddr->upda)&037, 6079548Ssam upaddr->upcs2, UPCS2_BITS, 6089548Ssam upaddr->uper1, UPER1_BITS, 6099548Ssam upaddr->uper2, UPER2_BITS); 6102674Swnj bp->b_flags |= B_ERROR; 6119548Ssam } else if (upaddr->uper2 & UPER2_BSE) { 6129548Ssam if (upecc(ui, BSE)) 6139548Ssam return; 6149548Ssam else 6159548Ssam goto hard; 6162674Swnj } else { 6172674Swnj /* 6182674Swnj * Retriable error. 6192674Swnj * If a soft ecc, correct it (continuing 6202674Swnj * by returning if necessary. 6212674Swnj * Otherwise fall through and retry the transfer 6222674Swnj */ 6237183Sroot if ((upaddr->uper1&(UPER1_DCK|UPER1_ECH))==UPER1_DCK) { 6249548Ssam if (upecc(ui, ECC)) 6252629Swnj return; 6267183Sroot } else 6277183Sroot um->um_tab.b_active = 0; /* force retry */ 6282674Swnj } 6292674Swnj /* 6302674Swnj * Clear drive error and, every eight attempts, 6312674Swnj * (starting with the fourth) 6322674Swnj * recalibrate to clear the slate. 6332674Swnj */ 6342674Swnj upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 6352674Swnj needie = 0; 6363182Swnj if ((um->um_tab.b_errcnt&07) == 4 && um->um_tab.b_active == 0) { 6372674Swnj upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO; 6383160Swnj sc->sc_recal = 0; 6393160Swnj goto nextrecal; 6402674Swnj } 6412674Swnj } 6422674Swnj /* 6433160Swnj * Advance recalibration finite state machine 6443160Swnj * if recalibrate in progress, through 6453160Swnj * RECAL 6463160Swnj * SEEK 6473160Swnj * OFFSET (optional) 6483160Swnj * RETRY 6492674Swnj */ 6503160Swnj switch (sc->sc_recal) { 6513160Swnj 6523160Swnj case 1: 6533160Swnj upaddr->updc = bp->b_cylin; 6543160Swnj upaddr->upcs1 = UP_SEEK|UP_IE|UP_GO; 6553160Swnj goto nextrecal; 6563160Swnj case 2: 6573160Swnj if (um->um_tab.b_errcnt < 16 || (bp->b_flags&B_READ) == 0) 6583160Swnj goto donerecal; 6593445Sroot upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | UPOF_FMT22; 6603160Swnj upaddr->upcs1 = UP_IE|UP_OFFSET|UP_GO; 6613160Swnj goto nextrecal; 6623160Swnj nextrecal: 6633160Swnj sc->sc_recal++; 6643160Swnj um->um_tab.b_active = 1; 6653160Swnj return; 6663160Swnj donerecal: 6673160Swnj case 3: 6682674Swnj sc->sc_recal = 0; 6693160Swnj um->um_tab.b_active = 0; 6703160Swnj break; 6712674Swnj } 6722674Swnj /* 6732674Swnj * If still ``active'', then don't need any more retries. 6742674Swnj */ 6752674Swnj if (um->um_tab.b_active) { 6762674Swnj /* 6772674Swnj * If we were offset positioning, 6782674Swnj * return to centerline. 6792674Swnj */ 6802674Swnj if (um->um_tab.b_errcnt >= 16) { 6813445Sroot upaddr->upof = UPOF_FMT22; 6822674Swnj upaddr->upcs1 = UP_RTC|UP_GO|UP_IE; 6833445Sroot while (upaddr->upds & UPDS_PIP) 6842674Swnj DELAY(25); 685268Sbill needie = 0; 686264Sbill } 6872674Swnj um->um_tab.b_active = 0; 6882674Swnj um->um_tab.b_errcnt = 0; 6892674Swnj um->um_tab.b_actf = dp->b_forw; 6902674Swnj dp->b_active = 0; 6912674Swnj dp->b_errcnt = 0; 6922674Swnj dp->b_actf = bp->av_forw; 6932674Swnj bp->b_resid = (-upaddr->upwc * sizeof(short)); 6942674Swnj iodone(bp); 6952674Swnj /* 6962674Swnj * If this unit has more work to do, 6972674Swnj * then start it up right away. 6982674Swnj */ 6992674Swnj if (dp->b_actf) 7002674Swnj if (upustart(ui)) 701268Sbill needie = 0; 702264Sbill } 7032674Swnj as &= ~(1<<ui->ui_slave); 7043403Swnj /* 7053403Swnj * Release unibus resources and flush data paths. 7063403Swnj */ 7073403Swnj ubadone(um); 7082674Swnj doattn: 7092674Swnj /* 7102674Swnj * Process other units which need attention. 7112674Swnj * For each unit which needs attention, call 7122674Swnj * the unit start routine to place the slave 7132674Swnj * on the controller device queue. 7142674Swnj */ 7153160Swnj while (unit = ffs(as)) { 7163160Swnj unit--; /* was 1 origin */ 7173160Swnj as &= ~(1<<unit); 7183160Swnj upaddr->upas = 1<<unit; 7196383Swnj if (unit < UPIPUNITS && upustart(upip[sc21][unit])) 7203160Swnj needie = 0; 7213160Swnj } 7222674Swnj /* 7232674Swnj * If the controller is not transferring, but 7242674Swnj * there are devices ready to transfer, start 7252674Swnj * the controller. 7262674Swnj */ 7272395Swnj if (um->um_tab.b_actf && um->um_tab.b_active == 0) 7282395Swnj if (upstart(um)) 729268Sbill needie = 0; 730275Sbill if (needie) 7312629Swnj upaddr->upcs1 = UP_IE; 732264Sbill } 733264Sbill 7349357Ssam upread(dev, uio) 7352616Swnj dev_t dev; 7369357Ssam struct uio *uio; 737264Sbill { 7382616Swnj register int unit = minor(dev) >> 3; 7392470Swnj 7402616Swnj if (unit >= NUP) 7419357Ssam return (ENXIO); 7429357Ssam return (physio(upstrategy, &rupbuf[unit], dev, B_READ, minphys, uio)); 743264Sbill } 744264Sbill 7459357Ssam upwrite(dev, uio) 7462616Swnj dev_t dev; 7479357Ssam struct uio *uio; 748264Sbill { 7492616Swnj register int unit = minor(dev) >> 3; 7502470Swnj 7512616Swnj if (unit >= NUP) 7529357Ssam return (ENXIO); 7539357Ssam return (physio(upstrategy, &rupbuf[unit], dev, B_WRITE, minphys, uio)); 754264Sbill } 755264Sbill 756266Sbill /* 757266Sbill * Correct an ECC error, and restart the i/o to complete 758266Sbill * the transfer if necessary. This is quite complicated because 759266Sbill * the transfer may be going to an odd memory address base and/or 760266Sbill * across a page boundary. 761266Sbill */ 7629548Ssam upecc(ui, flag) 7632983Swnj register struct uba_device *ui; 7649548Ssam int flag; 765264Sbill { 7662629Swnj register struct updevice *up = (struct updevice *)ui->ui_addr; 7672395Swnj register struct buf *bp = uputab[ui->ui_unit].b_actf; 7682983Swnj register struct uba_ctlr *um = ui->ui_mi; 7692395Swnj register struct upst *st; 7702395Swnj struct uba_regs *ubp = ui->ui_hd->uh_uba; 771266Sbill register int i; 772264Sbill caddr_t addr; 773266Sbill int reg, bit, byte, npf, mask, o, cmd, ubaddr; 774264Sbill int bn, cn, tn, sn; 775264Sbill 776264Sbill /* 777266Sbill * Npf is the number of sectors transferred before the sector 778266Sbill * containing the ECC error, and reg is the UBA register 779266Sbill * mapping (the first part of) the transfer. 780266Sbill * O is offset within a memory page of the first byte transferred. 781264Sbill */ 7829548Ssam if (flag == CONT) 7839548Ssam npf = bp->b_error; 7849548Ssam else 78510858Ssam npf = btop((up->upwc * sizeof(short)) + bp->b_bcount); 7862571Swnj reg = btop(um->um_ubinfo&0x3ffff) + npf; 787264Sbill o = (int)bp->b_un.b_addr & PGOFSET; 788264Sbill mask = up->upec2; 7893445Sroot #ifdef UPECCDEBUG 7903403Swnj printf("npf %d reg %x o %d mask %o pos %d\n", npf, reg, o, mask, 7913403Swnj up->upec1); 7923445Sroot #endif 7939548Ssam bn = dkblock(bp); 7949548Ssam st = &upst[ui->ui_type]; 7959548Ssam cn = bp->b_cylin; 7969548Ssam sn = bn%st->nspc + npf; 7979548Ssam tn = sn/st->nsect; 7989548Ssam sn %= st->nsect; 7999548Ssam cn += tn/st->ntrak; 8009548Ssam tn %= st->ntrak; 8012725Swnj ubapurge(um); 8029548Ssam um->um_tab.b_active=2; 803266Sbill /* 8049548Ssam * action taken depends on the flag 805266Sbill */ 8069548Ssam switch(flag){ 8079548Ssam case ECC: 8089548Ssam npf--; 8099548Ssam reg--; 8109548Ssam mask = up->upec2; 81118317Sralph log(KERN_RECOV, "up%d%c: soft ecc sn%d\n", dkunit(bp), 8129548Ssam 'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf); 8139548Ssam /* 8149548Ssam * Flush the buffered data path, and compute the 8159548Ssam * byte and bit position of the error. The variable i 8169548Ssam * is the byte offset in the transfer, the variable byte 8179548Ssam * is the offset from a page boundary in main memory. 8189548Ssam */ 8199548Ssam i = up->upec1 - 1; /* -1 makes 0 origin */ 8209548Ssam bit = i&07; 8219548Ssam i = (i&~07)>>3; 8229548Ssam byte = i + o; 8239548Ssam /* 8249548Ssam * Correct while possible bits remain of mask. Since mask 8259548Ssam * contains 11 bits, we continue while the bit offset is > -11. 8269548Ssam * Also watch out for end of this block and the end of the whole 8279548Ssam * transfer. 8289548Ssam */ 8299548Ssam while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 83013879Ssam struct pte pte; 83113879Ssam 83213879Ssam pte = ubp->uba_map[reg + btop(byte)]; 83313879Ssam addr = ptob(pte.pg_pfnum) + (byte & PGOFSET); 8343445Sroot #ifdef UPECCDEBUG 8359548Ssam printf("addr %x map reg %x\n", 8369548Ssam addr, *(int *)(&ubp->uba_map[reg+btop(byte)])); 8379548Ssam printf("old: %x, ", getmemc(addr)); 8383445Sroot #endif 8399548Ssam putmemc(addr, getmemc(addr)^(mask<<bit)); 8403445Sroot #ifdef UPECCDEBUG 8419548Ssam printf("new: %x\n", getmemc(addr)); 8423445Sroot #endif 8439548Ssam byte++; 8449548Ssam i++; 8459580Shelge bit -= 8; 8469548Ssam } 8479548Ssam if (up->upwc == 0) 8489548Ssam return (0); 8499548Ssam npf++; 8509548Ssam reg++; 8519548Ssam break; 8529548Ssam case BSE: 8539548Ssam /* 8549548Ssam * if not in bad sector table, return 0 8559548Ssam */ 8569548Ssam if ((bn = isbad(&upbad[ui->ui_unit], cn, tn, sn)) < 0) 8579548Ssam return(0); 8589548Ssam /* 8599548Ssam * flag this one as bad 8609548Ssam */ 8619548Ssam bp->b_flags |= B_BAD; 8629548Ssam bp->b_error = npf + 1; 8639548Ssam #ifdef UPECCDEBUG 8649548Ssam printf("BSE: restart at %d\n",npf+1); 8659548Ssam #endif 8669548Ssam bn = st->ncyl * st->nspc -st->nsect - 1 - bn; 8679548Ssam cn = bn / st->nspc; 8689548Ssam sn = bn % st->nspc; 8699548Ssam tn = sn / st->nsect; 8709548Ssam sn %= st->nsect; 8719548Ssam up->upwc = -(512 / sizeof (short)); 8729548Ssam #ifdef UPECCDEBUG 8739548Ssam printf("revector to cn %d tn %d sn %d\n", cn, tn, sn); 8749548Ssam #endif 8759548Ssam break; 8769548Ssam case CONT: 8779548Ssam #ifdef UPECCDEBUG 8789548Ssam printf("upecc, CONT: bn %d cn %d tn %d sn %d\n", bn, cn, tn, sn); 8799548Ssam #endif 8809548Ssam bp->b_flags &= ~B_BAD; 8819548Ssam up->upwc = -((bp->b_bcount - (int)ptob(npf)) / sizeof(short)); 8829548Ssam if (up->upwc == 0) 8839548Ssam return(0); 8849548Ssam break; 885264Sbill } 8867183Sroot if (up->upwc == 0) { 8877183Sroot um->um_tab.b_active = 0; 888264Sbill return (0); 8897183Sroot } 890266Sbill /* 891266Sbill * Have to continue the transfer... clear the drive, 892266Sbill * and compute the position where the transfer is to continue. 893266Sbill * We have completed npf+1 sectors of the transfer already; 894266Sbill * restart at offset o of next sector (i.e. in UBA register reg+1). 895266Sbill */ 8962629Swnj #ifdef notdef 8972629Swnj up->uper1 = 0; 8982629Swnj up->upcs1 |= UP_GO; 8992629Swnj #else 9002629Swnj up->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 901264Sbill up->updc = cn; 902266Sbill up->upda = (tn << 8) | sn; 9039548Ssam ubaddr = (int)ptob(reg) + o; 904266Sbill up->upba = ubaddr; 905266Sbill cmd = (ubaddr >> 8) & 0x300; 9069548Ssam cmd |= ((bp->b_flags&B_READ)?UP_RCOM:UP_WCOM)|UP_IE|UP_GO; 9079548Ssam um->um_tab.b_errcnt = 0; 908266Sbill up->upcs1 = cmd; 9092629Swnj #endif 910264Sbill return (1); 911264Sbill } 912286Sbill 913286Sbill /* 914286Sbill * Reset driver after UBA init. 915286Sbill * Cancel software state of all pending transfers 916286Sbill * and restart all units and the controller. 917286Sbill */ 9182395Swnj upreset(uban) 9192931Swnj int uban; 920286Sbill { 9212983Swnj register struct uba_ctlr *um; 9222983Swnj register struct uba_device *ui; 9232395Swnj register sc21, unit; 924286Sbill 9252646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 9262470Swnj if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban || 9272470Swnj um->um_alive == 0) 9282395Swnj continue; 9292931Swnj printf(" sc%d", sc21); 9302395Swnj um->um_tab.b_active = 0; 9312395Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 9322931Swnj up_softc[sc21].sc_recal = 0; 9336346Swnj up_softc[sc21].sc_wticks = 0; 9342571Swnj if (um->um_ubinfo) { 9352571Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 9369357Ssam um->um_ubinfo = 0; 9372395Swnj } 9383445Sroot ((struct updevice *)(um->um_addr))->upcs2 = UPCS2_CLR; 9392395Swnj for (unit = 0; unit < NUP; unit++) { 9402395Swnj if ((ui = updinfo[unit]) == 0) 9412395Swnj continue; 9422931Swnj if (ui->ui_alive == 0 || ui->ui_mi != um) 9432395Swnj continue; 9442395Swnj uputab[unit].b_active = 0; 9452395Swnj (void) upustart(ui); 9462395Swnj } 9472395Swnj (void) upstart(um); 948286Sbill } 949286Sbill } 950313Sbill 951313Sbill /* 952313Sbill * Wake up every second and if an interrupt is pending 953313Sbill * but nothing has happened increment a counter. 9542931Swnj * If nothing happens for 20 seconds, reset the UNIBUS 955313Sbill * and begin anew. 956313Sbill */ 957313Sbill upwatch() 958313Sbill { 9592983Swnj register struct uba_ctlr *um; 9602395Swnj register sc21, unit; 9612470Swnj register struct up_softc *sc; 962313Sbill 9632759Swnj timeout(upwatch, (caddr_t)0, hz); 9642646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 9652395Swnj um = upminfo[sc21]; 9662470Swnj if (um == 0 || um->um_alive == 0) 9672470Swnj continue; 9682470Swnj sc = &up_softc[sc21]; 9692395Swnj if (um->um_tab.b_active == 0) { 9702395Swnj for (unit = 0; unit < NUP; unit++) 9712629Swnj if (uputab[unit].b_active && 9722629Swnj updinfo[unit]->ui_mi == um) 9732395Swnj goto active; 9742470Swnj sc->sc_wticks = 0; 9752395Swnj continue; 9762395Swnj } 9772931Swnj active: 9782470Swnj sc->sc_wticks++; 9792470Swnj if (sc->sc_wticks >= 20) { 9802470Swnj sc->sc_wticks = 0; 9812931Swnj printf("sc%d: lost interrupt\n", sc21); 9822646Swnj ubareset(um->um_ubanum); 9832395Swnj } 984313Sbill } 985313Sbill } 9862379Swnj 9872379Swnj #define DBSIZE 20 9882379Swnj 9892379Swnj updump(dev) 9902379Swnj dev_t dev; 9912379Swnj { 9922629Swnj struct updevice *upaddr; 9932379Swnj char *start; 9943107Swnj int num, blk, unit; 9952379Swnj struct size *sizes; 9962395Swnj register struct uba_regs *uba; 9972983Swnj register struct uba_device *ui; 9982379Swnj register short *rp; 9992395Swnj struct upst *st; 10006848Ssam register int retry; 10012379Swnj 10022395Swnj unit = minor(dev) >> 3; 10032889Swnj if (unit >= NUP) 10042889Swnj return (ENXIO); 10052470Swnj #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) 10062983Swnj ui = phys(struct uba_device *, updinfo[unit]); 10072889Swnj if (ui->ui_alive == 0) 10082889Swnj return (ENXIO); 10092395Swnj uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 10102983Swnj ubainit(uba); 10112629Swnj upaddr = (struct updevice *)ui->ui_physaddr; 10126848Ssam DELAY(5000000); 10132379Swnj num = maxfree; 10142379Swnj upaddr->upcs2 = unit; 10152983Swnj DELAY(100); 10166848Ssam upaddr->upcs1 = UP_DCLR|UP_GO; 10176848Ssam upaddr->upcs1 = UP_PRESET|UP_GO; 10186848Ssam upaddr->upof = UPOF_FMT22; 10196848Ssam retry = 0; 10206848Ssam do { 10216848Ssam DELAY(25); 10226848Ssam if (++retry > 527) 10236848Ssam break; 10246861Ssam } while ((upaddr->upds & UP_RDY) == 0); 10253445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) 10262889Swnj return (EFAULT); 10279357Ssam start = 0; 10288489Sroot st = &upst[ui->ui_type]; 10292395Swnj sizes = phys(struct size *, st->sizes); 1030*24213Sbloom if (dumplo < 0) 10312889Swnj return (EINVAL); 1032*24213Sbloom if (dumplo + num >= sizes[minor(dev)&07].nblocks) 1033*24213Sbloom num = sizes[minor(dev)&07].nblocks - dumplo; 10342379Swnj while (num > 0) { 10352379Swnj register struct pte *io; 10362379Swnj register int i; 10372379Swnj int cn, sn, tn; 10382379Swnj daddr_t bn; 10392379Swnj 10402379Swnj blk = num > DBSIZE ? DBSIZE : num; 10412395Swnj io = uba->uba_map; 10422379Swnj for (i = 0; i < blk; i++) 10432983Swnj *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV; 10442379Swnj *(int *)io = 0; 10452379Swnj bn = dumplo + btop(start); 10462607Swnj cn = bn/st->nspc + sizes[minor(dev)&07].cyloff; 10472607Swnj sn = bn%st->nspc; 10482607Swnj tn = sn/st->nsect; 10492607Swnj sn = sn%st->nsect; 10502379Swnj upaddr->updc = cn; 10512379Swnj rp = (short *) &upaddr->upda; 10522379Swnj *rp = (tn << 8) + sn; 10532379Swnj *--rp = 0; 10542379Swnj *--rp = -blk*NBPG / sizeof (short); 10552629Swnj *--rp = UP_GO|UP_WCOM; 10566848Ssam retry = 0; 10572379Swnj do { 10582379Swnj DELAY(25); 10596848Ssam if (++retry > 527) 10606848Ssam break; 10612629Swnj } while ((upaddr->upcs1 & UP_RDY) == 0); 10626848Ssam if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 10636861Ssam printf("up%d: not ready", unit); 10646848Ssam if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 10656848Ssam printf("\n"); 10666848Ssam return (EIO); 10676848Ssam } 10686848Ssam printf(" (flakey)\n"); 10696848Ssam } 10703445Sroot if (upaddr->upds&UPDS_ERR) 10712889Swnj return (EIO); 10722379Swnj start += blk*NBPG; 10732379Swnj num -= blk; 10742379Swnj } 10752379Swnj return (0); 10762379Swnj } 107712505Ssam 107812505Ssam upsize(dev) 107912505Ssam dev_t dev; 108012505Ssam { 108112505Ssam int unit = minor(dev) >> 3; 108212505Ssam struct uba_device *ui; 108312505Ssam struct upst *st; 108412505Ssam 108512505Ssam if (unit >= NUP || (ui = updinfo[unit]) == 0 || ui->ui_alive == 0) 108612505Ssam return (-1); 108712505Ssam st = &upst[ui->ui_type]; 108812505Ssam return (st->sizes[minor(dev) & 07].nblocks); 108912505Ssam } 10901902Swnj #endif 1091