123355Smckusick /* 229253Smckusick * Copyright (c) 1982, 1986 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*34850Skre * @(#)up.c 7.5 (Berkeley) 06/28/88 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" 2430388Skarels #include "dkstat.h" 2517082Sbloom #include "dkbad.h" 2634525Skarels #include "ioctl.h" 2734525Skarels #include "disklabel.h" 2817082Sbloom #include "buf.h" 2917082Sbloom #include "conf.h" 3017082Sbloom #include "dir.h" 3117082Sbloom #include "user.h" 3217082Sbloom #include "map.h" 3317082Sbloom #include "vm.h" 3417082Sbloom #include "cmap.h" 3517082Sbloom #include "uio.h" 3617082Sbloom #include "kernel.h" 3718317Sralph #include "syslog.h" 38264Sbill 399357Ssam #include "../vax/cpu.h" 409357Ssam #include "../vax/nexus.h" 4117082Sbloom #include "ubavar.h" 4217082Sbloom #include "ubareg.h" 4317082Sbloom #include "upreg.h" 449357Ssam 452395Swnj struct up_softc { 462395Swnj int sc_softas; 472607Swnj int sc_ndrive; 482395Swnj int sc_wticks; 492674Swnj int sc_recal; 502646Swnj } up_softc[NSC]; 51275Sbill 5224743Sbloom #define upunit(dev) (minor(dev) >> 3) 5324743Sbloom 542395Swnj /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 5510858Ssam struct size { 56264Sbill daddr_t nblocks; 57264Sbill int cyloff; 5811211Ssam } up9300_sizes[8] = { 59264Sbill 15884, 0, /* A=cyl 0 thru 26 */ 60264Sbill 33440, 27, /* B=cyl 27 thru 81 */ 61341Sbill 495520, 0, /* C=cyl 0 thru 814 */ 62264Sbill 15884, 562, /* D=cyl 562 thru 588 */ 63264Sbill 55936, 589, /* E=cyl 589 thru 680 */ 643730Sroot 81376, 681, /* F=cyl 681 thru 814 */ 653730Sroot 153728, 562, /* G=cyl 562 thru 814 */ 66264Sbill 291346, 82, /* H=cyl 82 thru 561 */ 6711211Ssam }, up9766_sizes[8] = { 6811211Ssam 15884, 0, /* A=cyl 0 thru 26 */ 6911211Ssam 33440, 27, /* B=cyl 27 thru 81 */ 7011211Ssam 500384, 0, /* C=cyl 0 thru 822 */ 7111211Ssam 15884, 562, /* D=cyl 562 thru 588 */ 7211211Ssam 55936, 589, /* E=cyl 589 thru 680 */ 7311211Ssam 86240, 681, /* F=cyl 681 thru 822 */ 7411211Ssam 158592, 562, /* G=cyl 562 thru 822 */ 7511211Ssam 291346, 82, /* H=cyl 82 thru 561 */ 7611211Ssam }, up160_sizes[8] = { 772395Swnj 15884, 0, /* A=cyl 0 thru 49 */ 782395Swnj 33440, 50, /* B=cyl 50 thru 154 */ 792395Swnj 263360, 0, /* C=cyl 0 thru 822 */ 8011211Ssam 15884, 155, /* D=cyl 155 thru 204 */ 8111211Ssam 55936, 205, /* E=cyl 205 thru 379 */ 8211211Ssam 141664, 380, /* F=cyl 380 thru 822 */ 8311211Ssam 213664, 155, /* G=cyl 155 thru 822 */ 842395Swnj 0, 0, 856851Ssam }, upam_sizes[8] = { 866305Sroot 15884, 0, /* A=cyl 0 thru 31 */ 876305Sroot 33440, 32, /* B=cyl 32 thru 97 */ 886305Sroot 524288, 0, /* C=cyl 0 thru 1023 */ 8911211Ssam 15884, 668, /* D=cyl 668 thru 699 */ 9011211Ssam 55936, 700, /* E=cyl 700 thru 809 */ 9111211Ssam 109472, 810, /* F=cyl 810 thru 1023 */ 9211211Ssam 182176, 668, /* G=cyl 668 thru 1023 */ 936305Sroot 291346, 98, /* H=cyl 98 thru 667 */ 9414002Ssam }, up980_sizes[8] = { 9514002Ssam 15884, 0, /* A=cyl 0 thru 99 */ 9614002Ssam 33440, 100, /* B=cyl 100 thru 308 */ 9714002Ssam 131680, 0, /* C=cyl 0 thru 822 */ 9814002Ssam 15884, 309, /* D=cyl 309 thru 408 */ 9914002Ssam 55936, 409, /* E=cyl 409 thru 758 */ 10014002Ssam 10080, 759, /* F=cyl 759 thru 822 */ 10114002Ssam 82080, 309, /* G=cyl 309 thru 822 */ 10214002Ssam 0, 0, 10321977Sbloom }, upeagle_sizes[8] = { 10421977Sbloom 15884, 0, /* A=cyl 0 thru 16 */ 10521977Sbloom 66880, 17, /* B=cyl 17 thru 86 */ 10621977Sbloom 808320, 0, /* C=cyl 0 thru 841 */ 10721977Sbloom 15884, 391, /* D=cyl 391 thru 407 */ 10821977Sbloom 307200, 408, /* E=cyl 408 thru 727 */ 10921977Sbloom 109296, 728, /* F=cyl 728 thru 841 */ 11021977Sbloom 432816, 391, /* G=cyl 391 thru 841 */ 11121977Sbloom 291346, 87, /* H=cyl 87 thru 390 */ 112264Sbill }; 1132395Swnj /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 114264Sbill 1152607Swnj int upprobe(), upslave(), upattach(), updgo(), upintr(); 1162983Swnj struct uba_ctlr *upminfo[NSC]; 1172983Swnj struct uba_device *updinfo[NUP]; 1186383Swnj #define UPIPUNITS 8 1196383Swnj struct uba_device *upip[NSC][UPIPUNITS]; /* fuji w/fixed head gives n,n+4 */ 1202395Swnj 1212607Swnj u_short upstd[] = { 0776700, 0774400, 0776300, 0 }; 1222616Swnj struct uba_driver scdriver = 1232607Swnj { upprobe, upslave, upattach, updgo, upstd, "up", updinfo, "sc", upminfo }; 1242395Swnj struct buf uputab[NUP]; 1259548Ssam char upinit[NUP]; 1262395Swnj 1272395Swnj struct upst { 12812837Ssam short nsect; /* # sectors/track */ 12912837Ssam short ntrak; /* # tracks/cylinder */ 13012837Ssam short nspc; /* # sectors/cylinder */ 13112837Ssam short ncyl; /* # cylinders */ 13212837Ssam struct size *sizes; /* partition tables */ 13312837Ssam short sdist; /* seek distance metric */ 13412837Ssam short rdist; /* rotational distance metric */ 1352395Swnj } upst[] = { 13612837Ssam { 32, 19, 32*19, 815, up9300_sizes, 3, 4 }, /* 9300 */ 13712837Ssam { 32, 19, 32*19, 823, up9766_sizes, 3, 4 }, /* 9766 */ 13812837Ssam { 32, 10, 32*10, 823, up160_sizes, 3, 4 }, /* fuji 160m */ 13912837Ssam { 32, 16, 32*16, 1024, upam_sizes, 7, 8 }, /* Capricorn */ 14014002Ssam { 32, 5, 32*5, 823, up980_sizes, 3, 4 }, /* DM980 */ 14121977Sbloom { 48, 20, 48*20, 842, upeagle_sizes, 15, 8 }, /* EAGLE */ 14212837Ssam { 0, 0, 0, 0, 0, 0, 0 } 1432395Swnj }; 1442395Swnj 1452629Swnj u_char up_offset[16] = { 1469548Ssam UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400, 1479548Ssam UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800, 1489548Ssam UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200, 1499548Ssam 0, 0, 0, 0 1502629Swnj }; 151264Sbill 1529548Ssam struct buf bupbuf[NUP]; 1539548Ssam struct dkbad upbad[NUP]; 154264Sbill 155264Sbill #define b_cylin b_resid 156264Sbill 1572395Swnj int upwstart, upwatch(); /* Have started guardian */ 1582470Swnj int upseek; 1592681Swnj int upwaitdry; 1602395Swnj 1612395Swnj /*ARGSUSED*/ 1622607Swnj upprobe(reg) 1632395Swnj caddr_t reg; 1642395Swnj { 1652459Swnj register int br, cvec; 1662459Swnj 1672607Swnj #ifdef lint 16812779Ssam br = 0; cvec = br; br = cvec; upintr(0); 1692607Swnj #endif 1702629Swnj ((struct updevice *)reg)->upcs1 = UP_IE|UP_RDY; 1712607Swnj DELAY(10); 1722629Swnj ((struct updevice *)reg)->upcs1 = 0; 1739357Ssam return (sizeof (struct updevice)); 1742395Swnj } 1752395Swnj 1762607Swnj upslave(ui, reg) 1772983Swnj struct uba_device *ui; 1782395Swnj caddr_t reg; 1792395Swnj { 1802629Swnj register struct updevice *upaddr = (struct updevice *)reg; 1812395Swnj 1822395Swnj upaddr->upcs1 = 0; /* conservative */ 1832607Swnj upaddr->upcs2 = ui->ui_slave; 1846843Swnj upaddr->upcs1 = UP_NOP|UP_GO; 1853445Sroot if (upaddr->upcs2&UPCS2_NED) { 1862629Swnj upaddr->upcs1 = UP_DCLR|UP_GO; 1872395Swnj return (0); 1882395Swnj } 1892607Swnj return (1); 1902607Swnj } 1912607Swnj 1922607Swnj upattach(ui) 1932983Swnj register struct uba_device *ui; 1942607Swnj { 1952607Swnj 1962395Swnj if (upwstart == 0) { 1972759Swnj timeout(upwatch, (caddr_t)0, hz); 1982395Swnj upwstart++; 1992395Swnj } 2002571Swnj if (ui->ui_dk >= 0) 2012571Swnj dk_mspw[ui->ui_dk] = .0000020345; 2022607Swnj upip[ui->ui_ctlr][ui->ui_slave] = ui; 2032607Swnj up_softc[ui->ui_ctlr].sc_ndrive++; 20411119Ssam ui->ui_type = upmaptype(ui); 20511119Ssam } 20611119Ssam 20711119Ssam upmaptype(ui) 20811119Ssam register struct uba_device *ui; 20911119Ssam { 21011119Ssam register struct updevice *upaddr = (struct updevice *)ui->ui_addr; 21111119Ssam int type = ui->ui_type; 21211119Ssam register struct upst *st; 21311119Ssam 2142629Swnj upaddr->upcs1 = 0; 2152629Swnj upaddr->upcs2 = ui->ui_slave; 2163496Sroot upaddr->uphr = UPHR_MAXTRAK; 21711119Ssam for (st = upst; st->nsect != 0; st++) 21811119Ssam if (upaddr->uphr == st->ntrak - 1) { 21911119Ssam type = st - upst; 22011119Ssam break; 22111119Ssam } 22211119Ssam if (st->nsect == 0) 223*34850Skre printf(": uphr=%x", upaddr->uphr); 22411119Ssam if (type == 0) { 22511112Shelge upaddr->uphr = UPHR_MAXCYL; 22611112Shelge if (upaddr->uphr == 822) 22711119Ssam type++; 22811112Shelge } 2293496Sroot upaddr->upcs2 = UPCS2_CLR; 23011119Ssam return (type); 2312395Swnj } 232264Sbill 2339548Ssam upopen(dev) 2349548Ssam dev_t dev; 2359548Ssam { 23624743Sbloom register int unit = upunit(dev); 2379548Ssam register struct uba_device *ui; 2389548Ssam 2399548Ssam if (unit >= NUP || (ui = updinfo[unit]) == 0 || ui->ui_alive == 0) 2409548Ssam return (ENXIO); 2419548Ssam return (0); 2429548Ssam } 2439548Ssam 244264Sbill upstrategy(bp) 2452395Swnj register struct buf *bp; 246264Sbill { 2472983Swnj register struct uba_device *ui; 2482395Swnj register struct upst *st; 2492395Swnj register int unit; 2502470Swnj register struct buf *dp; 2512395Swnj int xunit = minor(bp->b_dev) & 07; 2522470Swnj long bn, sz; 25321977Sbloom int s; 254264Sbill 2552470Swnj sz = (bp->b_bcount+511) >> 9; 25624743Sbloom unit = upunit(bp->b_dev); 25724743Sbloom if (unit >= NUP) { 25824743Sbloom bp->b_error = ENXIO; 2592395Swnj goto bad; 26024743Sbloom } 2612395Swnj ui = updinfo[unit]; 26224743Sbloom if (ui == 0 || ui->ui_alive == 0) { 26324743Sbloom bp->b_error = ENXIO; 2642395Swnj goto bad; 26524743Sbloom } 2662395Swnj st = &upst[ui->ui_type]; 2672395Swnj if (bp->b_blkno < 0 || 26824743Sbloom (bn = bp->b_blkno)+sz > st->sizes[xunit].nblocks) { 26924788Skarels if (bp->b_blkno == st->sizes[xunit].nblocks) { 27024788Skarels bp->b_resid = bp->b_bcount; 27124743Sbloom goto done; 27224788Skarels } 27324743Sbloom bp->b_error = EINVAL; 2742395Swnj goto bad; 27524743Sbloom } 2762395Swnj bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 27721977Sbloom s = spl5(); 2782470Swnj dp = &uputab[ui->ui_unit]; 2792470Swnj disksort(dp, bp); 2802470Swnj if (dp->b_active == 0) { 2812395Swnj (void) upustart(ui); 2822395Swnj bp = &ui->ui_mi->um_tab; 2832395Swnj if (bp->b_actf && bp->b_active == 0) 2842395Swnj (void) upstart(ui->ui_mi); 285264Sbill } 28621977Sbloom splx(s); 2872395Swnj return; 2882395Swnj 2892395Swnj bad: 2902395Swnj bp->b_flags |= B_ERROR; 29124743Sbloom done: 2922395Swnj iodone(bp); 2932395Swnj return; 294264Sbill } 295264Sbill 2962674Swnj /* 2972674Swnj * Unit start routine. 2982674Swnj * Seek the drive to be where the data is 2992674Swnj * and then generate another interrupt 3002674Swnj * to actually start the transfer. 3012674Swnj * If there is only one drive on the controller, 3022674Swnj * or we are very close to the data, don't 3032674Swnj * bother with the search. If called after 3042674Swnj * searching once, don't bother to look where 3052674Swnj * we are, just queue for transfer (to avoid 3062674Swnj * positioning forever without transferrring.) 3072674Swnj */ 3082395Swnj upustart(ui) 3092983Swnj register struct uba_device *ui; 310264Sbill { 311264Sbill register struct buf *bp, *dp; 3122983Swnj register struct uba_ctlr *um; 3132629Swnj register struct updevice *upaddr; 3142395Swnj register struct upst *st; 315264Sbill daddr_t bn; 3162674Swnj int sn, csn; 3172607Swnj /* 3182607Swnj * The SC21 cancels commands if you just say 3192629Swnj * cs1 = UP_IE 3202607Swnj * so we are cautious about handling of cs1. 3212607Swnj * Also don't bother to clear as bits other than in upintr(). 3222607Swnj */ 3232674Swnj int didie = 0; 3242674Swnj 3252674Swnj if (ui == 0) 3262674Swnj return (0); 3272983Swnj um = ui->ui_mi; 3282395Swnj dk_busy &= ~(1<<ui->ui_dk); 3292395Swnj dp = &uputab[ui->ui_unit]; 330266Sbill if ((bp = dp->b_actf) == NULL) 331268Sbill goto out; 3322674Swnj /* 3332674Swnj * If the controller is active, just remember 3342674Swnj * that this device would like to be positioned... 3352674Swnj * if we tried to position now we would confuse the SC21. 3362674Swnj */ 3372395Swnj if (um->um_tab.b_active) { 3382459Swnj up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave; 339275Sbill return (0); 340275Sbill } 3412674Swnj /* 3422674Swnj * If we have already positioned this drive, 3432674Swnj * then just put it on the ready queue. 3442674Swnj */ 345276Sbill if (dp->b_active) 346276Sbill goto done; 347276Sbill dp->b_active = 1; 3482629Swnj upaddr = (struct updevice *)um->um_addr; 3492395Swnj upaddr->upcs2 = ui->ui_slave; 3502674Swnj /* 3512674Swnj * If drive has just come up, 3522674Swnj * setup the pack. 3532674Swnj */ 3549548Ssam if ((upaddr->upds & UPDS_VV) == 0 || upinit[ui->ui_unit] == 0) { 3559548Ssam struct buf *bbp = &bupbuf[ui->ui_unit]; 35610858Ssam 3572607Swnj /* SHOULD WARN SYSTEM THAT THIS HAPPENED */ 3589548Ssam upinit[ui->ui_unit] = 1; 3592629Swnj upaddr->upcs1 = UP_IE|UP_DCLR|UP_GO; 3602629Swnj upaddr->upcs1 = UP_IE|UP_PRESET|UP_GO; 3613445Sroot upaddr->upof = UPOF_FMT22; 362268Sbill didie = 1; 3639548Ssam st = &upst[ui->ui_type]; 3649548Ssam bbp->b_flags = B_READ|B_BUSY; 3659548Ssam bbp->b_dev = bp->b_dev; 3669548Ssam bbp->b_bcount = 512; 3679548Ssam bbp->b_un.b_addr = (caddr_t)&upbad[ui->ui_unit]; 3689548Ssam bbp->b_blkno = st->ncyl * st->nspc - st->nsect; 3699548Ssam bbp->b_cylin = st->ncyl - 1; 3709548Ssam dp->b_actf = bbp; 3719548Ssam bbp->av_forw = bp; 3729548Ssam bp = bbp; 373264Sbill } 3742674Swnj /* 3752674Swnj * If drive is offline, forget about positioning. 3762674Swnj */ 3773445Sroot if ((upaddr->upds & (UPDS_DPR|UPDS_MOL)) != (UPDS_DPR|UPDS_MOL)) 378275Sbill goto done; 3792674Swnj /* 3802674Swnj * If there is only one drive, 3812674Swnj * dont bother searching. 3822674Swnj */ 3832607Swnj if (up_softc[um->um_ctlr].sc_ndrive == 1) 3842607Swnj goto done; 3852674Swnj /* 3862674Swnj * Figure out where this transfer is going to 3872674Swnj * and see if we are close enough to justify not searching. 3882674Swnj */ 3892395Swnj st = &upst[ui->ui_type]; 39024743Sbloom bn = bp->b_blkno; 3912395Swnj sn = bn%st->nspc; 39212837Ssam sn = (sn + st->nsect - st->sdist) % st->nsect; 3932674Swnj if (bp->b_cylin - upaddr->updc) 394266Sbill goto search; /* Not on-cylinder */ 395275Sbill else if (upseek) 396275Sbill goto done; /* Ok just to be on-cylinder */ 397264Sbill csn = (upaddr->upla>>6) - sn - 1; 398266Sbill if (csn < 0) 3992395Swnj csn += st->nsect; 40012837Ssam if (csn > st->nsect - st->rdist) 401264Sbill goto done; 402264Sbill search: 4032674Swnj upaddr->updc = bp->b_cylin; 4042674Swnj /* 4052674Swnj * Not on cylinder at correct position, 4062674Swnj * seek/search. 4072674Swnj */ 408275Sbill if (upseek) 4092629Swnj upaddr->upcs1 = UP_IE|UP_SEEK|UP_GO; 4102470Swnj else { 411275Sbill upaddr->upda = sn; 4122629Swnj upaddr->upcs1 = UP_IE|UP_SEARCH|UP_GO; 413275Sbill } 414268Sbill didie = 1; 4152674Swnj /* 4162674Swnj * Mark unit busy for iostat. 4172674Swnj */ 4182395Swnj if (ui->ui_dk >= 0) { 4192395Swnj dk_busy |= 1<<ui->ui_dk; 4202395Swnj dk_seek[ui->ui_dk]++; 421264Sbill } 422268Sbill goto out; 423264Sbill done: 4242674Swnj /* 4252674Swnj * Device is ready to go. 4262674Swnj * Put it on the ready queue for the controller 4272674Swnj * (unless its already there.) 4282674Swnj */ 4292629Swnj if (dp->b_active != 2) { 4302629Swnj dp->b_forw = NULL; 4312629Swnj if (um->um_tab.b_actf == NULL) 4322629Swnj um->um_tab.b_actf = dp; 4332629Swnj else 4342629Swnj um->um_tab.b_actl->b_forw = dp; 4352629Swnj um->um_tab.b_actl = dp; 4362629Swnj dp->b_active = 2; 4372629Swnj } 438268Sbill out: 439268Sbill return (didie); 440264Sbill } 441264Sbill 4422674Swnj /* 4432674Swnj * Start up a transfer on a drive. 4442674Swnj */ 4452395Swnj upstart(um) 4462983Swnj register struct uba_ctlr *um; 447264Sbill { 448264Sbill register struct buf *bp, *dp; 4492983Swnj register struct uba_device *ui; 4502629Swnj register struct updevice *upaddr; 4512470Swnj struct upst *st; 452264Sbill daddr_t bn; 4532681Swnj int dn, sn, tn, cmd, waitdry; 454264Sbill 455264Sbill loop: 4562674Swnj /* 4572674Swnj * Pull a request off the controller queue 4582674Swnj */ 4592395Swnj if ((dp = um->um_tab.b_actf) == NULL) 460268Sbill return (0); 461264Sbill if ((bp = dp->b_actf) == NULL) { 4622395Swnj um->um_tab.b_actf = dp->b_forw; 463264Sbill goto loop; 464264Sbill } 4652674Swnj /* 4662674Swnj * Mark controller busy, and 4672674Swnj * determine destination of this request. 4682674Swnj */ 4692395Swnj um->um_tab.b_active++; 47024743Sbloom ui = updinfo[upunit(bp->b_dev)]; 47124743Sbloom bn = bp->b_blkno; 4722395Swnj dn = ui->ui_slave; 4732395Swnj st = &upst[ui->ui_type]; 4742395Swnj sn = bn%st->nspc; 4752395Swnj tn = sn/st->nsect; 4762395Swnj sn %= st->nsect; 4772629Swnj upaddr = (struct updevice *)ui->ui_addr; 4782674Swnj /* 4792674Swnj * Select drive if not selected already. 4802674Swnj */ 4812674Swnj if ((upaddr->upcs2&07) != dn) 4822674Swnj upaddr->upcs2 = dn; 4832674Swnj /* 4842674Swnj * Check that it is ready and online 4852674Swnj */ 4862681Swnj waitdry = 0; 4873445Sroot while ((upaddr->upds&UPDS_DRY) == 0) { 48824743Sbloom printf("up%d: ds wait ds=%o\n",upunit(bp->b_dev),upaddr->upds); 4892681Swnj if (++waitdry > 512) 4902681Swnj break; 4912681Swnj upwaitdry++; 4922681Swnj } 4933445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 49424743Sbloom printf("up%d: not ready", upunit(bp->b_dev)); 4953445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 4962607Swnj printf("\n"); 4972395Swnj um->um_tab.b_active = 0; 4982395Swnj um->um_tab.b_errcnt = 0; 499893Sbill dp->b_actf = bp->av_forw; 500893Sbill dp->b_active = 0; 501893Sbill bp->b_flags |= B_ERROR; 502893Sbill iodone(bp); 503893Sbill goto loop; 504893Sbill } 5052674Swnj /* 5062674Swnj * Oh, well, sometimes this 5072674Swnj * happens, for reasons unknown. 5082674Swnj */ 5092629Swnj printf(" (flakey)\n"); 510264Sbill } 5112674Swnj /* 5122674Swnj * Setup for the transfer, and get in the 5132674Swnj * UNIBUS adaptor queue. 5142674Swnj */ 5152424Skre upaddr->updc = bp->b_cylin; 516264Sbill upaddr->upda = (tn << 8) + sn; 517264Sbill upaddr->upwc = -bp->b_bcount / sizeof (short); 518264Sbill if (bp->b_flags & B_READ) 5192629Swnj cmd = UP_IE|UP_RCOM|UP_GO; 520264Sbill else 5212629Swnj cmd = UP_IE|UP_WCOM|UP_GO; 5222571Swnj um->um_cmd = cmd; 5233107Swnj (void) ubago(ui); 524268Sbill return (1); 525264Sbill } 526264Sbill 5272674Swnj /* 5282674Swnj * Now all ready to go, stuff the registers. 5292674Swnj */ 5302571Swnj updgo(um) 5312983Swnj struct uba_ctlr *um; 5322395Swnj { 5332629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 5342470Swnj 5356953Swnj um->um_tab.b_active = 2; /* should now be 2 */ 5362571Swnj upaddr->upba = um->um_ubinfo; 5372571Swnj upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300); 5382395Swnj } 5392395Swnj 5402674Swnj /* 5412674Swnj * Handle a disk interrupt. 5422674Swnj */ 5432707Swnj upintr(sc21) 5442395Swnj register sc21; 545264Sbill { 546264Sbill register struct buf *bp, *dp; 5472983Swnj register struct uba_ctlr *um = upminfo[sc21]; 5482983Swnj register struct uba_device *ui; 5492629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 550264Sbill register unit; 5512470Swnj struct up_softc *sc = &up_softc[um->um_ctlr]; 5522607Swnj int as = (upaddr->upas & 0377) | sc->sc_softas; 5532681Swnj int needie = 1, waitdry; 554264Sbill 5552470Swnj sc->sc_wticks = 0; 5562607Swnj sc->sc_softas = 0; 5572674Swnj /* 5582674Swnj * If controller wasn't transferring, then this is an 5592674Swnj * interrupt for attention status on seeking drives. 5602674Swnj * Just service them. 5612674Swnj */ 5626346Swnj if (um->um_tab.b_active != 2 && !sc->sc_recal) { 5632674Swnj if (upaddr->upcs1 & UP_TRE) 5642674Swnj upaddr->upcs1 = UP_TRE; 5652674Swnj goto doattn; 5662674Swnj } 5676953Swnj um->um_tab.b_active = 1; 5682674Swnj /* 5692674Swnj * Get device and block structures, and a pointer 5702983Swnj * to the uba_device for the drive. Select the drive. 5712674Swnj */ 5722674Swnj dp = um->um_tab.b_actf; 5732674Swnj bp = dp->b_actf; 57424743Sbloom ui = updinfo[upunit(bp->b_dev)]; 5752674Swnj dk_busy &= ~(1 << ui->ui_dk); 5762674Swnj if ((upaddr->upcs2&07) != ui->ui_slave) 5772395Swnj upaddr->upcs2 = ui->ui_slave; 5789548Ssam if (bp->b_flags&B_BAD) { 5799548Ssam if (upecc(ui, CONT)) 5809548Ssam return; 5819548Ssam } 5822674Swnj /* 5832674Swnj * Check for and process errors on 5842674Swnj * either the drive or the controller. 5852674Swnj */ 5863445Sroot if ((upaddr->upds&UPDS_ERR) || (upaddr->upcs1&UP_TRE)) { 5872681Swnj waitdry = 0; 5883445Sroot while ((upaddr->upds & UPDS_DRY) == 0) { 5892681Swnj if (++waitdry > 512) 5902681Swnj break; 5912681Swnj upwaitdry++; 5922681Swnj } 5933445Sroot if (upaddr->uper1&UPER1_WLE) { 5942674Swnj /* 5952674Swnj * Give up on write locked devices 5962674Swnj * immediately. 5972674Swnj */ 59824743Sbloom printf("up%d: write locked\n", upunit(bp->b_dev)); 5992674Swnj bp->b_flags |= B_ERROR; 6002674Swnj } else if (++um->um_tab.b_errcnt > 27) { 6012674Swnj /* 6022674Swnj * After 28 retries (16 without offset, and 6032674Swnj * 12 with offset positioning) give up. 60410904Shelge * If the error was header CRC, the header is 60510904Shelge * screwed up, and the sector may in fact exist 60610904Shelge * in the bad sector table, better check... 6072674Swnj */ 60810904Shelge if (upaddr->uper1&UPER1_HCRC) { 60910904Shelge if (upecc(ui, BSE)) 61010904Shelge return; 61110904Shelge } 6129548Ssam hard: 61334525Skarels diskerr(bp, "up", "hard error", LOG_PRINTF, -1, 61434525Skarels (struct disklabel *)0); 61534525Skarels printf(" cn=%d tn=%d sn=%d cs2=%b er1=%b er2=%b\n", 6169548Ssam upaddr->updc, ((upaddr->upda)>>8)&077, 6179548Ssam (upaddr->upda)&037, 6189548Ssam upaddr->upcs2, UPCS2_BITS, 6199548Ssam upaddr->uper1, UPER1_BITS, 6209548Ssam upaddr->uper2, UPER2_BITS); 6212674Swnj bp->b_flags |= B_ERROR; 6229548Ssam } else if (upaddr->uper2 & UPER2_BSE) { 6239548Ssam if (upecc(ui, BSE)) 6249548Ssam return; 6259548Ssam else 6269548Ssam goto hard; 6272674Swnj } else { 6282674Swnj /* 6292674Swnj * Retriable error. 6302674Swnj * If a soft ecc, correct it (continuing 6312674Swnj * by returning if necessary. 6322674Swnj * Otherwise fall through and retry the transfer 6332674Swnj */ 6347183Sroot if ((upaddr->uper1&(UPER1_DCK|UPER1_ECH))==UPER1_DCK) { 6359548Ssam if (upecc(ui, ECC)) 6362629Swnj return; 6377183Sroot } else 6387183Sroot um->um_tab.b_active = 0; /* force retry */ 6392674Swnj } 6402674Swnj /* 6412674Swnj * Clear drive error and, every eight attempts, 6422674Swnj * (starting with the fourth) 6432674Swnj * recalibrate to clear the slate. 6442674Swnj */ 6452674Swnj upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 6462674Swnj needie = 0; 6473182Swnj if ((um->um_tab.b_errcnt&07) == 4 && um->um_tab.b_active == 0) { 6482674Swnj upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO; 6493160Swnj sc->sc_recal = 0; 6503160Swnj goto nextrecal; 6512674Swnj } 6522674Swnj } 6532674Swnj /* 6543160Swnj * Advance recalibration finite state machine 6553160Swnj * if recalibrate in progress, through 6563160Swnj * RECAL 6573160Swnj * SEEK 6583160Swnj * OFFSET (optional) 6593160Swnj * RETRY 6602674Swnj */ 6613160Swnj switch (sc->sc_recal) { 6623160Swnj 6633160Swnj case 1: 6643160Swnj upaddr->updc = bp->b_cylin; 6653160Swnj upaddr->upcs1 = UP_SEEK|UP_IE|UP_GO; 6663160Swnj goto nextrecal; 6673160Swnj case 2: 6683160Swnj if (um->um_tab.b_errcnt < 16 || (bp->b_flags&B_READ) == 0) 6693160Swnj goto donerecal; 6703445Sroot upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | UPOF_FMT22; 6713160Swnj upaddr->upcs1 = UP_IE|UP_OFFSET|UP_GO; 6723160Swnj goto nextrecal; 6733160Swnj nextrecal: 6743160Swnj sc->sc_recal++; 6753160Swnj um->um_tab.b_active = 1; 6763160Swnj return; 6773160Swnj donerecal: 6783160Swnj case 3: 6792674Swnj sc->sc_recal = 0; 6803160Swnj um->um_tab.b_active = 0; 6813160Swnj break; 6822674Swnj } 6832674Swnj /* 6842674Swnj * If still ``active'', then don't need any more retries. 6852674Swnj */ 6862674Swnj if (um->um_tab.b_active) { 6872674Swnj /* 6882674Swnj * If we were offset positioning, 6892674Swnj * return to centerline. 6902674Swnj */ 6912674Swnj if (um->um_tab.b_errcnt >= 16) { 6923445Sroot upaddr->upof = UPOF_FMT22; 6932674Swnj upaddr->upcs1 = UP_RTC|UP_GO|UP_IE; 6943445Sroot while (upaddr->upds & UPDS_PIP) 6952674Swnj DELAY(25); 696268Sbill needie = 0; 697264Sbill } 6982674Swnj um->um_tab.b_active = 0; 6992674Swnj um->um_tab.b_errcnt = 0; 7002674Swnj um->um_tab.b_actf = dp->b_forw; 7012674Swnj dp->b_active = 0; 7022674Swnj dp->b_errcnt = 0; 7032674Swnj dp->b_actf = bp->av_forw; 7042674Swnj bp->b_resid = (-upaddr->upwc * sizeof(short)); 7052674Swnj iodone(bp); 7062674Swnj /* 7072674Swnj * If this unit has more work to do, 7082674Swnj * then start it up right away. 7092674Swnj */ 7102674Swnj if (dp->b_actf) 7112674Swnj if (upustart(ui)) 712268Sbill needie = 0; 713264Sbill } 7142674Swnj as &= ~(1<<ui->ui_slave); 7153403Swnj /* 7163403Swnj * Release unibus resources and flush data paths. 7173403Swnj */ 7183403Swnj ubadone(um); 7192674Swnj doattn: 7202674Swnj /* 7212674Swnj * Process other units which need attention. 7222674Swnj * For each unit which needs attention, call 7232674Swnj * the unit start routine to place the slave 7242674Swnj * on the controller device queue. 7252674Swnj */ 72626373Skarels while (unit = ffs((long)as)) { 7273160Swnj unit--; /* was 1 origin */ 7283160Swnj as &= ~(1<<unit); 7293160Swnj upaddr->upas = 1<<unit; 7306383Swnj if (unit < UPIPUNITS && upustart(upip[sc21][unit])) 7313160Swnj needie = 0; 7323160Swnj } 7332674Swnj /* 7342674Swnj * If the controller is not transferring, but 7352674Swnj * there are devices ready to transfer, start 7362674Swnj * the controller. 7372674Swnj */ 7382395Swnj if (um->um_tab.b_actf && um->um_tab.b_active == 0) 7392395Swnj if (upstart(um)) 740268Sbill needie = 0; 741275Sbill if (needie) 7422629Swnj upaddr->upcs1 = UP_IE; 743264Sbill } 744264Sbill 745266Sbill /* 746266Sbill * Correct an ECC error, and restart the i/o to complete 747266Sbill * the transfer if necessary. This is quite complicated because 748266Sbill * the transfer may be going to an odd memory address base and/or 749266Sbill * across a page boundary. 750266Sbill */ 7519548Ssam upecc(ui, flag) 7522983Swnj register struct uba_device *ui; 7539548Ssam int flag; 754264Sbill { 7552629Swnj register struct updevice *up = (struct updevice *)ui->ui_addr; 7562395Swnj register struct buf *bp = uputab[ui->ui_unit].b_actf; 7572983Swnj register struct uba_ctlr *um = ui->ui_mi; 7582395Swnj register struct upst *st; 7592395Swnj struct uba_regs *ubp = ui->ui_hd->uh_uba; 760266Sbill register int i; 761264Sbill caddr_t addr; 762266Sbill int reg, bit, byte, npf, mask, o, cmd, ubaddr; 763264Sbill int bn, cn, tn, sn; 764264Sbill 765264Sbill /* 766266Sbill * Npf is the number of sectors transferred before the sector 767266Sbill * containing the ECC error, and reg is the UBA register 768266Sbill * mapping (the first part of) the transfer. 769266Sbill * O is offset within a memory page of the first byte transferred. 770264Sbill */ 7719548Ssam if (flag == CONT) 7729548Ssam npf = bp->b_error; 7739548Ssam else 77427674Skarels npf = btodb(bp->b_bcount + (up->upwc * sizeof(short)) + 511); 7752571Swnj reg = btop(um->um_ubinfo&0x3ffff) + npf; 776264Sbill o = (int)bp->b_un.b_addr & PGOFSET; 777264Sbill mask = up->upec2; 7783445Sroot #ifdef UPECCDEBUG 7793403Swnj printf("npf %d reg %x o %d mask %o pos %d\n", npf, reg, o, mask, 7803403Swnj up->upec1); 7813445Sroot #endif 78224743Sbloom bn = bp->b_blkno; 7839548Ssam st = &upst[ui->ui_type]; 7849548Ssam cn = bp->b_cylin; 7859548Ssam sn = bn%st->nspc + npf; 7869548Ssam tn = sn/st->nsect; 7879548Ssam sn %= st->nsect; 7889548Ssam cn += tn/st->ntrak; 7899548Ssam tn %= st->ntrak; 7902725Swnj ubapurge(um); 7919548Ssam um->um_tab.b_active=2; 792266Sbill /* 7939548Ssam * action taken depends on the flag 794266Sbill */ 7959548Ssam switch(flag){ 7969548Ssam case ECC: 7979548Ssam npf--; 7989548Ssam reg--; 7999548Ssam mask = up->upec2; 80034525Skarels diskerr(bp, "up", "soft ecc", LOG_WARNING, npf, 80134525Skarels (struct disklabel *)0); 80234525Skarels addlog("\n"); 8039548Ssam /* 8049548Ssam * Flush the buffered data path, and compute the 8059548Ssam * byte and bit position of the error. The variable i 8069548Ssam * is the byte offset in the transfer, the variable byte 8079548Ssam * is the offset from a page boundary in main memory. 8089548Ssam */ 8099548Ssam i = up->upec1 - 1; /* -1 makes 0 origin */ 8109548Ssam bit = i&07; 8119548Ssam i = (i&~07)>>3; 8129548Ssam byte = i + o; 8139548Ssam /* 8149548Ssam * Correct while possible bits remain of mask. Since mask 8159548Ssam * contains 11 bits, we continue while the bit offset is > -11. 8169548Ssam * Also watch out for end of this block and the end of the whole 8179548Ssam * transfer. 8189548Ssam */ 81927674Skarels while (i < 512 && (int)dbtob(npf)+i < bp->b_bcount && bit > -11) { 82013879Ssam struct pte pte; 82113879Ssam 82213879Ssam pte = ubp->uba_map[reg + btop(byte)]; 82313879Ssam addr = ptob(pte.pg_pfnum) + (byte & PGOFSET); 8243445Sroot #ifdef UPECCDEBUG 8259548Ssam printf("addr %x map reg %x\n", 8269548Ssam addr, *(int *)(&ubp->uba_map[reg+btop(byte)])); 8279548Ssam printf("old: %x, ", getmemc(addr)); 8283445Sroot #endif 8299548Ssam putmemc(addr, getmemc(addr)^(mask<<bit)); 8303445Sroot #ifdef UPECCDEBUG 8319548Ssam printf("new: %x\n", getmemc(addr)); 8323445Sroot #endif 8339548Ssam byte++; 8349548Ssam i++; 8359580Shelge bit -= 8; 8369548Ssam } 8379548Ssam if (up->upwc == 0) 8389548Ssam return (0); 8399548Ssam npf++; 8409548Ssam reg++; 8419548Ssam break; 8429548Ssam case BSE: 8439548Ssam /* 8449548Ssam * if not in bad sector table, return 0 8459548Ssam */ 8469548Ssam if ((bn = isbad(&upbad[ui->ui_unit], cn, tn, sn)) < 0) 8479548Ssam return(0); 8489548Ssam /* 8499548Ssam * flag this one as bad 8509548Ssam */ 8519548Ssam bp->b_flags |= B_BAD; 8529548Ssam bp->b_error = npf + 1; 8539548Ssam #ifdef UPECCDEBUG 8549548Ssam printf("BSE: restart at %d\n",npf+1); 8559548Ssam #endif 8569548Ssam bn = st->ncyl * st->nspc -st->nsect - 1 - bn; 8579548Ssam cn = bn / st->nspc; 8589548Ssam sn = bn % st->nspc; 8599548Ssam tn = sn / st->nsect; 8609548Ssam sn %= st->nsect; 8619548Ssam up->upwc = -(512 / sizeof (short)); 8629548Ssam #ifdef UPECCDEBUG 8639548Ssam printf("revector to cn %d tn %d sn %d\n", cn, tn, sn); 8649548Ssam #endif 8659548Ssam break; 8669548Ssam case CONT: 8679548Ssam #ifdef UPECCDEBUG 8689548Ssam printf("upecc, CONT: bn %d cn %d tn %d sn %d\n", bn, cn, tn, sn); 8699548Ssam #endif 8709548Ssam bp->b_flags &= ~B_BAD; 87127674Skarels if ((int)dbtob(npf) >= bp->b_bcount) 87227674Skarels return (0); 87327674Skarels up->upwc = -((bp->b_bcount - (int)dbtob(npf)) / sizeof(short)); 8749548Ssam break; 875264Sbill } 8767183Sroot if (up->upwc == 0) { 8777183Sroot um->um_tab.b_active = 0; 878264Sbill return (0); 8797183Sroot } 880266Sbill /* 881266Sbill * Have to continue the transfer... clear the drive, 882266Sbill * and compute the position where the transfer is to continue. 883266Sbill * We have completed npf+1 sectors of the transfer already; 884266Sbill * restart at offset o of next sector (i.e. in UBA register reg+1). 885266Sbill */ 8862629Swnj #ifdef notdef 8872629Swnj up->uper1 = 0; 8882629Swnj up->upcs1 |= UP_GO; 8892629Swnj #else 8902629Swnj up->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 891264Sbill up->updc = cn; 892266Sbill up->upda = (tn << 8) | sn; 8939548Ssam ubaddr = (int)ptob(reg) + o; 894266Sbill up->upba = ubaddr; 895266Sbill cmd = (ubaddr >> 8) & 0x300; 8969548Ssam cmd |= ((bp->b_flags&B_READ)?UP_RCOM:UP_WCOM)|UP_IE|UP_GO; 8979548Ssam um->um_tab.b_errcnt = 0; 898266Sbill up->upcs1 = cmd; 8992629Swnj #endif 900264Sbill return (1); 901264Sbill } 902286Sbill 903286Sbill /* 904286Sbill * Reset driver after UBA init. 905286Sbill * Cancel software state of all pending transfers 906286Sbill * and restart all units and the controller. 907286Sbill */ 9082395Swnj upreset(uban) 9092931Swnj int uban; 910286Sbill { 9112983Swnj register struct uba_ctlr *um; 9122983Swnj register struct uba_device *ui; 9132395Swnj register sc21, unit; 914286Sbill 9152646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 9162470Swnj if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban || 9172470Swnj um->um_alive == 0) 9182395Swnj continue; 9192931Swnj printf(" sc%d", sc21); 9202395Swnj um->um_tab.b_active = 0; 9212395Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 9222931Swnj up_softc[sc21].sc_recal = 0; 9236346Swnj up_softc[sc21].sc_wticks = 0; 9242571Swnj if (um->um_ubinfo) { 9252571Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 9269357Ssam um->um_ubinfo = 0; 9272395Swnj } 9283445Sroot ((struct updevice *)(um->um_addr))->upcs2 = UPCS2_CLR; 9292395Swnj for (unit = 0; unit < NUP; unit++) { 9302395Swnj if ((ui = updinfo[unit]) == 0) 9312395Swnj continue; 9322931Swnj if (ui->ui_alive == 0 || ui->ui_mi != um) 9332395Swnj continue; 9342395Swnj uputab[unit].b_active = 0; 9352395Swnj (void) upustart(ui); 9362395Swnj } 9372395Swnj (void) upstart(um); 938286Sbill } 939286Sbill } 940313Sbill 941313Sbill /* 942313Sbill * Wake up every second and if an interrupt is pending 943313Sbill * but nothing has happened increment a counter. 9442931Swnj * If nothing happens for 20 seconds, reset the UNIBUS 945313Sbill * and begin anew. 946313Sbill */ 947313Sbill upwatch() 948313Sbill { 9492983Swnj register struct uba_ctlr *um; 9502395Swnj register sc21, unit; 9512470Swnj register struct up_softc *sc; 952313Sbill 9532759Swnj timeout(upwatch, (caddr_t)0, hz); 9542646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 9552395Swnj um = upminfo[sc21]; 9562470Swnj if (um == 0 || um->um_alive == 0) 9572470Swnj continue; 9582470Swnj sc = &up_softc[sc21]; 9592395Swnj if (um->um_tab.b_active == 0) { 9602395Swnj for (unit = 0; unit < NUP; unit++) 9612629Swnj if (uputab[unit].b_active && 9622629Swnj updinfo[unit]->ui_mi == um) 9632395Swnj goto active; 9642470Swnj sc->sc_wticks = 0; 9652395Swnj continue; 9662395Swnj } 9672931Swnj active: 9682470Swnj sc->sc_wticks++; 9692470Swnj if (sc->sc_wticks >= 20) { 9702470Swnj sc->sc_wticks = 0; 9712931Swnj printf("sc%d: lost interrupt\n", sc21); 9722646Swnj ubareset(um->um_ubanum); 9732395Swnj } 974313Sbill } 975313Sbill } 9762379Swnj 9772379Swnj #define DBSIZE 20 9782379Swnj 9792379Swnj updump(dev) 9802379Swnj dev_t dev; 9812379Swnj { 9822629Swnj struct updevice *upaddr; 9832379Swnj char *start; 9843107Swnj int num, blk, unit; 9852379Swnj struct size *sizes; 9862395Swnj register struct uba_regs *uba; 9872983Swnj register struct uba_device *ui; 9882379Swnj register short *rp; 9892395Swnj struct upst *st; 9906848Ssam register int retry; 9912379Swnj 99224743Sbloom unit = upunit(dev); 9932889Swnj if (unit >= NUP) 9942889Swnj return (ENXIO); 9952470Swnj #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) 9962983Swnj ui = phys(struct uba_device *, updinfo[unit]); 9972889Swnj if (ui->ui_alive == 0) 9982889Swnj return (ENXIO); 9992395Swnj uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 10002983Swnj ubainit(uba); 10012629Swnj upaddr = (struct updevice *)ui->ui_physaddr; 10026848Ssam DELAY(5000000); 10032379Swnj num = maxfree; 10042379Swnj upaddr->upcs2 = unit; 10052983Swnj DELAY(100); 10066848Ssam upaddr->upcs1 = UP_DCLR|UP_GO; 10076848Ssam upaddr->upcs1 = UP_PRESET|UP_GO; 10086848Ssam upaddr->upof = UPOF_FMT22; 10096848Ssam retry = 0; 10106848Ssam do { 10116848Ssam DELAY(25); 10126848Ssam if (++retry > 527) 10136848Ssam break; 10146861Ssam } while ((upaddr->upds & UP_RDY) == 0); 10153445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) 10162889Swnj return (EFAULT); 10179357Ssam start = 0; 10188489Sroot st = &upst[ui->ui_type]; 10192395Swnj sizes = phys(struct size *, st->sizes); 102024213Sbloom if (dumplo < 0) 10212889Swnj return (EINVAL); 102224213Sbloom if (dumplo + num >= sizes[minor(dev)&07].nblocks) 102324213Sbloom num = sizes[minor(dev)&07].nblocks - dumplo; 10242379Swnj while (num > 0) { 10252379Swnj register struct pte *io; 10262379Swnj register int i; 10272379Swnj int cn, sn, tn; 10282379Swnj daddr_t bn; 10292379Swnj 10302379Swnj blk = num > DBSIZE ? DBSIZE : num; 10312395Swnj io = uba->uba_map; 10322379Swnj for (i = 0; i < blk; i++) 10332983Swnj *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV; 10342379Swnj *(int *)io = 0; 10352379Swnj bn = dumplo + btop(start); 10362607Swnj cn = bn/st->nspc + sizes[minor(dev)&07].cyloff; 10372607Swnj sn = bn%st->nspc; 10382607Swnj tn = sn/st->nsect; 10392607Swnj sn = sn%st->nsect; 10402379Swnj upaddr->updc = cn; 10412379Swnj rp = (short *) &upaddr->upda; 10422379Swnj *rp = (tn << 8) + sn; 10432379Swnj *--rp = 0; 10442379Swnj *--rp = -blk*NBPG / sizeof (short); 10452629Swnj *--rp = UP_GO|UP_WCOM; 10466848Ssam retry = 0; 10472379Swnj do { 10482379Swnj DELAY(25); 10496848Ssam if (++retry > 527) 10506848Ssam break; 10512629Swnj } while ((upaddr->upcs1 & UP_RDY) == 0); 10526848Ssam if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 10536861Ssam printf("up%d: not ready", unit); 10546848Ssam if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 10556848Ssam printf("\n"); 10566848Ssam return (EIO); 10576848Ssam } 10586848Ssam printf(" (flakey)\n"); 10596848Ssam } 10603445Sroot if (upaddr->upds&UPDS_ERR) 10612889Swnj return (EIO); 10622379Swnj start += blk*NBPG; 10632379Swnj num -= blk; 10642379Swnj } 10652379Swnj return (0); 10662379Swnj } 106712505Ssam 106812505Ssam upsize(dev) 106912505Ssam dev_t dev; 107012505Ssam { 107124743Sbloom int unit = upunit(dev); 107212505Ssam struct uba_device *ui; 107312505Ssam struct upst *st; 107412505Ssam 107512505Ssam if (unit >= NUP || (ui = updinfo[unit]) == 0 || ui->ui_alive == 0) 107612505Ssam return (-1); 107712505Ssam st = &upst[ui->ui_type]; 107812505Ssam return (st->sizes[minor(dev) & 07].nblocks); 107912505Ssam } 10801902Swnj #endif 1081