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*24788Skarels * @(#)up.c 6.8 (Berkeley) 09/16/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 5024743Sbloom #define upunit(dev) (minor(dev) >> 3) 5124743Sbloom 522395Swnj /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 5310858Ssam struct size { 54264Sbill daddr_t nblocks; 55264Sbill int cyloff; 5611211Ssam } up9300_sizes[8] = { 57264Sbill 15884, 0, /* A=cyl 0 thru 26 */ 58264Sbill 33440, 27, /* B=cyl 27 thru 81 */ 59341Sbill 495520, 0, /* C=cyl 0 thru 814 */ 60264Sbill 15884, 562, /* D=cyl 562 thru 588 */ 61264Sbill 55936, 589, /* E=cyl 589 thru 680 */ 623730Sroot 81376, 681, /* F=cyl 681 thru 814 */ 633730Sroot 153728, 562, /* G=cyl 562 thru 814 */ 64264Sbill 291346, 82, /* H=cyl 82 thru 561 */ 6511211Ssam }, up9766_sizes[8] = { 6611211Ssam 15884, 0, /* A=cyl 0 thru 26 */ 6711211Ssam 33440, 27, /* B=cyl 27 thru 81 */ 6811211Ssam 500384, 0, /* C=cyl 0 thru 822 */ 6911211Ssam 15884, 562, /* D=cyl 562 thru 588 */ 7011211Ssam 55936, 589, /* E=cyl 589 thru 680 */ 7111211Ssam 86240, 681, /* F=cyl 681 thru 822 */ 7211211Ssam 158592, 562, /* G=cyl 562 thru 822 */ 7311211Ssam 291346, 82, /* H=cyl 82 thru 561 */ 7411211Ssam }, up160_sizes[8] = { 752395Swnj 15884, 0, /* A=cyl 0 thru 49 */ 762395Swnj 33440, 50, /* B=cyl 50 thru 154 */ 772395Swnj 263360, 0, /* C=cyl 0 thru 822 */ 7811211Ssam 15884, 155, /* D=cyl 155 thru 204 */ 7911211Ssam 55936, 205, /* E=cyl 205 thru 379 */ 8011211Ssam 141664, 380, /* F=cyl 380 thru 822 */ 8111211Ssam 213664, 155, /* G=cyl 155 thru 822 */ 822395Swnj 0, 0, 836851Ssam }, upam_sizes[8] = { 846305Sroot 15884, 0, /* A=cyl 0 thru 31 */ 856305Sroot 33440, 32, /* B=cyl 32 thru 97 */ 866305Sroot 524288, 0, /* C=cyl 0 thru 1023 */ 8711211Ssam 15884, 668, /* D=cyl 668 thru 699 */ 8811211Ssam 55936, 700, /* E=cyl 700 thru 809 */ 8911211Ssam 109472, 810, /* F=cyl 810 thru 1023 */ 9011211Ssam 182176, 668, /* G=cyl 668 thru 1023 */ 916305Sroot 291346, 98, /* H=cyl 98 thru 667 */ 9214002Ssam }, up980_sizes[8] = { 9314002Ssam 15884, 0, /* A=cyl 0 thru 99 */ 9414002Ssam 33440, 100, /* B=cyl 100 thru 308 */ 9514002Ssam 131680, 0, /* C=cyl 0 thru 822 */ 9614002Ssam 15884, 309, /* D=cyl 309 thru 408 */ 9714002Ssam 55936, 409, /* E=cyl 409 thru 758 */ 9814002Ssam 10080, 759, /* F=cyl 759 thru 822 */ 9914002Ssam 82080, 309, /* G=cyl 309 thru 822 */ 10014002Ssam 0, 0, 10121977Sbloom }, upeagle_sizes[8] = { 10221977Sbloom 15884, 0, /* A=cyl 0 thru 16 */ 10321977Sbloom 66880, 17, /* B=cyl 17 thru 86 */ 10421977Sbloom 808320, 0, /* C=cyl 0 thru 841 */ 10521977Sbloom 15884, 391, /* D=cyl 391 thru 407 */ 10621977Sbloom 307200, 408, /* E=cyl 408 thru 727 */ 10721977Sbloom 109296, 728, /* F=cyl 728 thru 841 */ 10821977Sbloom 432816, 391, /* G=cyl 391 thru 841 */ 10921977Sbloom 291346, 87, /* H=cyl 87 thru 390 */ 110264Sbill }; 1112395Swnj /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 112264Sbill 1132607Swnj int upprobe(), upslave(), upattach(), updgo(), upintr(); 1142983Swnj struct uba_ctlr *upminfo[NSC]; 1152983Swnj struct uba_device *updinfo[NUP]; 1166383Swnj #define UPIPUNITS 8 1176383Swnj struct uba_device *upip[NSC][UPIPUNITS]; /* fuji w/fixed head gives n,n+4 */ 1182395Swnj 1192607Swnj u_short upstd[] = { 0776700, 0774400, 0776300, 0 }; 1202616Swnj struct uba_driver scdriver = 1212607Swnj { upprobe, upslave, upattach, updgo, upstd, "up", updinfo, "sc", upminfo }; 1222395Swnj struct buf uputab[NUP]; 1239548Ssam char upinit[NUP]; 1242395Swnj 1252395Swnj struct upst { 12612837Ssam short nsect; /* # sectors/track */ 12712837Ssam short ntrak; /* # tracks/cylinder */ 12812837Ssam short nspc; /* # sectors/cylinder */ 12912837Ssam short ncyl; /* # cylinders */ 13012837Ssam struct size *sizes; /* partition tables */ 13112837Ssam short sdist; /* seek distance metric */ 13212837Ssam short rdist; /* rotational distance metric */ 1332395Swnj } upst[] = { 13412837Ssam { 32, 19, 32*19, 815, up9300_sizes, 3, 4 }, /* 9300 */ 13512837Ssam { 32, 19, 32*19, 823, up9766_sizes, 3, 4 }, /* 9766 */ 13612837Ssam { 32, 10, 32*10, 823, up160_sizes, 3, 4 }, /* fuji 160m */ 13712837Ssam { 32, 16, 32*16, 1024, upam_sizes, 7, 8 }, /* Capricorn */ 13814002Ssam { 32, 5, 32*5, 823, up980_sizes, 3, 4 }, /* DM980 */ 13921977Sbloom { 48, 20, 48*20, 842, upeagle_sizes, 15, 8 }, /* EAGLE */ 14012837Ssam { 0, 0, 0, 0, 0, 0, 0 } 1412395Swnj }; 1422395Swnj 1432629Swnj u_char up_offset[16] = { 1449548Ssam UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400, 1459548Ssam UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800, 1469548Ssam UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200, 1479548Ssam 0, 0, 0, 0 1482629Swnj }; 149264Sbill 1502616Swnj struct buf rupbuf[NUP]; 1519548Ssam struct buf bupbuf[NUP]; 1529548Ssam struct dkbad upbad[NUP]; 153264Sbill 154264Sbill #define b_cylin b_resid 155264Sbill 1562395Swnj int upwstart, upwatch(); /* Have started guardian */ 1572470Swnj int upseek; 1582681Swnj int upwaitdry; 1592395Swnj 1602395Swnj /*ARGSUSED*/ 1612607Swnj upprobe(reg) 1622395Swnj caddr_t reg; 1632395Swnj { 1642459Swnj register int br, cvec; 1652459Swnj 1662607Swnj #ifdef lint 16712779Ssam br = 0; cvec = br; br = cvec; upintr(0); 1682607Swnj #endif 1692629Swnj ((struct updevice *)reg)->upcs1 = UP_IE|UP_RDY; 1702607Swnj DELAY(10); 1712629Swnj ((struct updevice *)reg)->upcs1 = 0; 1729357Ssam return (sizeof (struct updevice)); 1732395Swnj } 1742395Swnj 1752607Swnj upslave(ui, reg) 1762983Swnj struct uba_device *ui; 1772395Swnj caddr_t reg; 1782395Swnj { 1792629Swnj register struct updevice *upaddr = (struct updevice *)reg; 1802395Swnj 1812395Swnj upaddr->upcs1 = 0; /* conservative */ 1822607Swnj upaddr->upcs2 = ui->ui_slave; 1836843Swnj upaddr->upcs1 = UP_NOP|UP_GO; 1843445Sroot if (upaddr->upcs2&UPCS2_NED) { 1852629Swnj upaddr->upcs1 = UP_DCLR|UP_GO; 1862395Swnj return (0); 1872395Swnj } 1882607Swnj return (1); 1892607Swnj } 1902607Swnj 1912607Swnj upattach(ui) 1922983Swnj register struct uba_device *ui; 1932607Swnj { 1942607Swnj 1952395Swnj if (upwstart == 0) { 1962759Swnj timeout(upwatch, (caddr_t)0, hz); 1972395Swnj upwstart++; 1982395Swnj } 1992571Swnj if (ui->ui_dk >= 0) 2002571Swnj dk_mspw[ui->ui_dk] = .0000020345; 2012607Swnj upip[ui->ui_ctlr][ui->ui_slave] = ui; 2022607Swnj up_softc[ui->ui_ctlr].sc_ndrive++; 20311119Ssam ui->ui_type = upmaptype(ui); 20411119Ssam } 20511119Ssam 20611119Ssam upmaptype(ui) 20711119Ssam register struct uba_device *ui; 20811119Ssam { 20911119Ssam register struct updevice *upaddr = (struct updevice *)ui->ui_addr; 21011119Ssam int type = ui->ui_type; 21111119Ssam register struct upst *st; 21211119Ssam 2132629Swnj upaddr->upcs1 = 0; 2142629Swnj upaddr->upcs2 = ui->ui_slave; 2153496Sroot upaddr->uphr = UPHR_MAXTRAK; 21611119Ssam for (st = upst; st->nsect != 0; st++) 21711119Ssam if (upaddr->uphr == st->ntrak - 1) { 21811119Ssam type = st - upst; 21911119Ssam break; 22011119Ssam } 22111119Ssam if (st->nsect == 0) 22211119Ssam printf("up%d: uphr=%x\n", ui->ui_slave, upaddr->uphr); 22311119Ssam if (type == 0) { 22411112Shelge upaddr->uphr = UPHR_MAXCYL; 22511112Shelge if (upaddr->uphr == 822) 22611119Ssam type++; 22711112Shelge } 2283496Sroot upaddr->upcs2 = UPCS2_CLR; 22911119Ssam return (type); 2302395Swnj } 231264Sbill 2329548Ssam upopen(dev) 2339548Ssam dev_t dev; 2349548Ssam { 23524743Sbloom register int unit = upunit(dev); 2369548Ssam register struct uba_device *ui; 2379548Ssam 2389548Ssam if (unit >= NUP || (ui = updinfo[unit]) == 0 || ui->ui_alive == 0) 2399548Ssam return (ENXIO); 2409548Ssam return (0); 2419548Ssam } 2429548Ssam 243264Sbill upstrategy(bp) 2442395Swnj register struct buf *bp; 245264Sbill { 2462983Swnj register struct uba_device *ui; 2472395Swnj register struct upst *st; 2482395Swnj register int unit; 2492470Swnj register struct buf *dp; 2502395Swnj int xunit = minor(bp->b_dev) & 07; 2512470Swnj long bn, sz; 25221977Sbloom int s; 253264Sbill 2542470Swnj sz = (bp->b_bcount+511) >> 9; 25524743Sbloom unit = upunit(bp->b_dev); 25624743Sbloom if (unit >= NUP) { 25724743Sbloom bp->b_error = ENXIO; 2582395Swnj goto bad; 25924743Sbloom } 2602395Swnj ui = updinfo[unit]; 26124743Sbloom if (ui == 0 || ui->ui_alive == 0) { 26224743Sbloom bp->b_error = ENXIO; 2632395Swnj goto bad; 26424743Sbloom } 2652395Swnj st = &upst[ui->ui_type]; 2662395Swnj if (bp->b_blkno < 0 || 26724743Sbloom (bn = bp->b_blkno)+sz > st->sizes[xunit].nblocks) { 268*24788Skarels if (bp->b_blkno == st->sizes[xunit].nblocks) { 269*24788Skarels bp->b_resid = bp->b_bcount; 27024743Sbloom goto done; 271*24788Skarels } 27224743Sbloom bp->b_error = EINVAL; 2732395Swnj goto bad; 27424743Sbloom } 2752395Swnj bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 27621977Sbloom s = spl5(); 2772470Swnj dp = &uputab[ui->ui_unit]; 2782470Swnj disksort(dp, bp); 2792470Swnj if (dp->b_active == 0) { 2802395Swnj (void) upustart(ui); 2812395Swnj bp = &ui->ui_mi->um_tab; 2822395Swnj if (bp->b_actf && bp->b_active == 0) 2832395Swnj (void) upstart(ui->ui_mi); 284264Sbill } 28521977Sbloom splx(s); 2862395Swnj return; 2872395Swnj 2882395Swnj bad: 2892395Swnj bp->b_flags |= B_ERROR; 29024743Sbloom done: 2912395Swnj iodone(bp); 2922395Swnj return; 293264Sbill } 294264Sbill 2952674Swnj /* 2962674Swnj * Unit start routine. 2972674Swnj * Seek the drive to be where the data is 2982674Swnj * and then generate another interrupt 2992674Swnj * to actually start the transfer. 3002674Swnj * If there is only one drive on the controller, 3012674Swnj * or we are very close to the data, don't 3022674Swnj * bother with the search. If called after 3032674Swnj * searching once, don't bother to look where 3042674Swnj * we are, just queue for transfer (to avoid 3052674Swnj * positioning forever without transferrring.) 3062674Swnj */ 3072395Swnj upustart(ui) 3082983Swnj register struct uba_device *ui; 309264Sbill { 310264Sbill register struct buf *bp, *dp; 3112983Swnj register struct uba_ctlr *um; 3122629Swnj register struct updevice *upaddr; 3132395Swnj register struct upst *st; 314264Sbill daddr_t bn; 3152674Swnj int sn, csn; 3162607Swnj /* 3172607Swnj * The SC21 cancels commands if you just say 3182629Swnj * cs1 = UP_IE 3192607Swnj * so we are cautious about handling of cs1. 3202607Swnj * Also don't bother to clear as bits other than in upintr(). 3212607Swnj */ 3222674Swnj int didie = 0; 3232674Swnj 3242674Swnj if (ui == 0) 3252674Swnj return (0); 3262983Swnj um = ui->ui_mi; 3272395Swnj dk_busy &= ~(1<<ui->ui_dk); 3282395Swnj dp = &uputab[ui->ui_unit]; 329266Sbill if ((bp = dp->b_actf) == NULL) 330268Sbill goto out; 3312674Swnj /* 3322674Swnj * If the controller is active, just remember 3332674Swnj * that this device would like to be positioned... 3342674Swnj * if we tried to position now we would confuse the SC21. 3352674Swnj */ 3362395Swnj if (um->um_tab.b_active) { 3372459Swnj up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave; 338275Sbill return (0); 339275Sbill } 3402674Swnj /* 3412674Swnj * If we have already positioned this drive, 3422674Swnj * then just put it on the ready queue. 3432674Swnj */ 344276Sbill if (dp->b_active) 345276Sbill goto done; 346276Sbill dp->b_active = 1; 3472629Swnj upaddr = (struct updevice *)um->um_addr; 3482395Swnj upaddr->upcs2 = ui->ui_slave; 3492674Swnj /* 3502674Swnj * If drive has just come up, 3512674Swnj * setup the pack. 3522674Swnj */ 3539548Ssam if ((upaddr->upds & UPDS_VV) == 0 || upinit[ui->ui_unit] == 0) { 3549548Ssam struct buf *bbp = &bupbuf[ui->ui_unit]; 35510858Ssam 3562607Swnj /* SHOULD WARN SYSTEM THAT THIS HAPPENED */ 3579548Ssam upinit[ui->ui_unit] = 1; 3582629Swnj upaddr->upcs1 = UP_IE|UP_DCLR|UP_GO; 3592629Swnj upaddr->upcs1 = UP_IE|UP_PRESET|UP_GO; 3603445Sroot upaddr->upof = UPOF_FMT22; 361268Sbill didie = 1; 3629548Ssam st = &upst[ui->ui_type]; 3639548Ssam bbp->b_flags = B_READ|B_BUSY; 3649548Ssam bbp->b_dev = bp->b_dev; 3659548Ssam bbp->b_bcount = 512; 3669548Ssam bbp->b_un.b_addr = (caddr_t)&upbad[ui->ui_unit]; 3679548Ssam bbp->b_blkno = st->ncyl * st->nspc - st->nsect; 3689548Ssam bbp->b_cylin = st->ncyl - 1; 3699548Ssam dp->b_actf = bbp; 3709548Ssam bbp->av_forw = bp; 3719548Ssam bp = bbp; 372264Sbill } 3732674Swnj /* 3742674Swnj * If drive is offline, forget about positioning. 3752674Swnj */ 3763445Sroot if ((upaddr->upds & (UPDS_DPR|UPDS_MOL)) != (UPDS_DPR|UPDS_MOL)) 377275Sbill goto done; 3782674Swnj /* 3792674Swnj * If there is only one drive, 3802674Swnj * dont bother searching. 3812674Swnj */ 3822607Swnj if (up_softc[um->um_ctlr].sc_ndrive == 1) 3832607Swnj goto done; 3842674Swnj /* 3852674Swnj * Figure out where this transfer is going to 3862674Swnj * and see if we are close enough to justify not searching. 3872674Swnj */ 3882395Swnj st = &upst[ui->ui_type]; 38924743Sbloom bn = bp->b_blkno; 3902395Swnj sn = bn%st->nspc; 39112837Ssam sn = (sn + st->nsect - st->sdist) % st->nsect; 3922674Swnj if (bp->b_cylin - upaddr->updc) 393266Sbill goto search; /* Not on-cylinder */ 394275Sbill else if (upseek) 395275Sbill goto done; /* Ok just to be on-cylinder */ 396264Sbill csn = (upaddr->upla>>6) - sn - 1; 397266Sbill if (csn < 0) 3982395Swnj csn += st->nsect; 39912837Ssam if (csn > st->nsect - st->rdist) 400264Sbill goto done; 401264Sbill search: 4022674Swnj upaddr->updc = bp->b_cylin; 4032674Swnj /* 4042674Swnj * Not on cylinder at correct position, 4052674Swnj * seek/search. 4062674Swnj */ 407275Sbill if (upseek) 4082629Swnj upaddr->upcs1 = UP_IE|UP_SEEK|UP_GO; 4092470Swnj else { 410275Sbill upaddr->upda = sn; 4112629Swnj upaddr->upcs1 = UP_IE|UP_SEARCH|UP_GO; 412275Sbill } 413268Sbill didie = 1; 4142674Swnj /* 4152674Swnj * Mark unit busy for iostat. 4162674Swnj */ 4172395Swnj if (ui->ui_dk >= 0) { 4182395Swnj dk_busy |= 1<<ui->ui_dk; 4192395Swnj dk_seek[ui->ui_dk]++; 420264Sbill } 421268Sbill goto out; 422264Sbill done: 4232674Swnj /* 4242674Swnj * Device is ready to go. 4252674Swnj * Put it on the ready queue for the controller 4262674Swnj * (unless its already there.) 4272674Swnj */ 4282629Swnj if (dp->b_active != 2) { 4292629Swnj dp->b_forw = NULL; 4302629Swnj if (um->um_tab.b_actf == NULL) 4312629Swnj um->um_tab.b_actf = dp; 4322629Swnj else 4332629Swnj um->um_tab.b_actl->b_forw = dp; 4342629Swnj um->um_tab.b_actl = dp; 4352629Swnj dp->b_active = 2; 4362629Swnj } 437268Sbill out: 438268Sbill return (didie); 439264Sbill } 440264Sbill 4412674Swnj /* 4422674Swnj * Start up a transfer on a drive. 4432674Swnj */ 4442395Swnj upstart(um) 4452983Swnj register struct uba_ctlr *um; 446264Sbill { 447264Sbill register struct buf *bp, *dp; 4482983Swnj register struct uba_device *ui; 4492629Swnj register struct updevice *upaddr; 4502470Swnj struct upst *st; 451264Sbill daddr_t bn; 4522681Swnj int dn, sn, tn, cmd, waitdry; 453264Sbill 454264Sbill loop: 4552674Swnj /* 4562674Swnj * Pull a request off the controller queue 4572674Swnj */ 4582395Swnj if ((dp = um->um_tab.b_actf) == NULL) 459268Sbill return (0); 460264Sbill if ((bp = dp->b_actf) == NULL) { 4612395Swnj um->um_tab.b_actf = dp->b_forw; 462264Sbill goto loop; 463264Sbill } 4642674Swnj /* 4652674Swnj * Mark controller busy, and 4662674Swnj * determine destination of this request. 4672674Swnj */ 4682395Swnj um->um_tab.b_active++; 46924743Sbloom ui = updinfo[upunit(bp->b_dev)]; 47024743Sbloom bn = bp->b_blkno; 4712395Swnj dn = ui->ui_slave; 4722395Swnj st = &upst[ui->ui_type]; 4732395Swnj sn = bn%st->nspc; 4742395Swnj tn = sn/st->nsect; 4752395Swnj sn %= st->nsect; 4762629Swnj upaddr = (struct updevice *)ui->ui_addr; 4772674Swnj /* 4782674Swnj * Select drive if not selected already. 4792674Swnj */ 4802674Swnj if ((upaddr->upcs2&07) != dn) 4812674Swnj upaddr->upcs2 = dn; 4822674Swnj /* 4832674Swnj * Check that it is ready and online 4842674Swnj */ 4852681Swnj waitdry = 0; 4863445Sroot while ((upaddr->upds&UPDS_DRY) == 0) { 48724743Sbloom printf("up%d: ds wait ds=%o\n",upunit(bp->b_dev),upaddr->upds); 4882681Swnj if (++waitdry > 512) 4892681Swnj break; 4902681Swnj upwaitdry++; 4912681Swnj } 4923445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 49324743Sbloom printf("up%d: not ready", upunit(bp->b_dev)); 4943445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 4952607Swnj printf("\n"); 4962395Swnj um->um_tab.b_active = 0; 4972395Swnj um->um_tab.b_errcnt = 0; 498893Sbill dp->b_actf = bp->av_forw; 499893Sbill dp->b_active = 0; 500893Sbill bp->b_flags |= B_ERROR; 501893Sbill iodone(bp); 502893Sbill goto loop; 503893Sbill } 5042674Swnj /* 5052674Swnj * Oh, well, sometimes this 5062674Swnj * happens, for reasons unknown. 5072674Swnj */ 5082629Swnj printf(" (flakey)\n"); 509264Sbill } 5102674Swnj /* 5112674Swnj * Setup for the transfer, and get in the 5122674Swnj * UNIBUS adaptor queue. 5132674Swnj */ 5142424Skre upaddr->updc = bp->b_cylin; 515264Sbill upaddr->upda = (tn << 8) + sn; 516264Sbill upaddr->upwc = -bp->b_bcount / sizeof (short); 517264Sbill if (bp->b_flags & B_READ) 5182629Swnj cmd = UP_IE|UP_RCOM|UP_GO; 519264Sbill else 5202629Swnj cmd = UP_IE|UP_WCOM|UP_GO; 5212571Swnj um->um_cmd = cmd; 5223107Swnj (void) ubago(ui); 523268Sbill return (1); 524264Sbill } 525264Sbill 5262674Swnj /* 5272674Swnj * Now all ready to go, stuff the registers. 5282674Swnj */ 5292571Swnj updgo(um) 5302983Swnj struct uba_ctlr *um; 5312395Swnj { 5322629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 5332470Swnj 5346953Swnj um->um_tab.b_active = 2; /* should now be 2 */ 5352571Swnj upaddr->upba = um->um_ubinfo; 5362571Swnj upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300); 5372395Swnj } 5382395Swnj 5392674Swnj /* 5402674Swnj * Handle a disk interrupt. 5412674Swnj */ 5422707Swnj upintr(sc21) 5432395Swnj register sc21; 544264Sbill { 545264Sbill register struct buf *bp, *dp; 5462983Swnj register struct uba_ctlr *um = upminfo[sc21]; 5472983Swnj register struct uba_device *ui; 5482629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 549264Sbill register unit; 5502470Swnj struct up_softc *sc = &up_softc[um->um_ctlr]; 5512607Swnj int as = (upaddr->upas & 0377) | sc->sc_softas; 5522681Swnj int needie = 1, waitdry; 553264Sbill 5542470Swnj sc->sc_wticks = 0; 5552607Swnj sc->sc_softas = 0; 5562674Swnj /* 5572674Swnj * If controller wasn't transferring, then this is an 5582674Swnj * interrupt for attention status on seeking drives. 5592674Swnj * Just service them. 5602674Swnj */ 5616346Swnj if (um->um_tab.b_active != 2 && !sc->sc_recal) { 5622674Swnj if (upaddr->upcs1 & UP_TRE) 5632674Swnj upaddr->upcs1 = UP_TRE; 5642674Swnj goto doattn; 5652674Swnj } 5666953Swnj um->um_tab.b_active = 1; 5672674Swnj /* 5682674Swnj * Get device and block structures, and a pointer 5692983Swnj * to the uba_device for the drive. Select the drive. 5702674Swnj */ 5712674Swnj dp = um->um_tab.b_actf; 5722674Swnj bp = dp->b_actf; 57324743Sbloom ui = updinfo[upunit(bp->b_dev)]; 5742674Swnj dk_busy &= ~(1 << ui->ui_dk); 5752674Swnj if ((upaddr->upcs2&07) != ui->ui_slave) 5762395Swnj upaddr->upcs2 = ui->ui_slave; 5779548Ssam if (bp->b_flags&B_BAD) { 5789548Ssam if (upecc(ui, CONT)) 5799548Ssam return; 5809548Ssam } 5812674Swnj /* 5822674Swnj * Check for and process errors on 5832674Swnj * either the drive or the controller. 5842674Swnj */ 5853445Sroot if ((upaddr->upds&UPDS_ERR) || (upaddr->upcs1&UP_TRE)) { 5862681Swnj waitdry = 0; 5873445Sroot while ((upaddr->upds & UPDS_DRY) == 0) { 5882681Swnj if (++waitdry > 512) 5892681Swnj break; 5902681Swnj upwaitdry++; 5912681Swnj } 5923445Sroot if (upaddr->uper1&UPER1_WLE) { 5932674Swnj /* 5942674Swnj * Give up on write locked devices 5952674Swnj * immediately. 5962674Swnj */ 59724743Sbloom printf("up%d: write locked\n", upunit(bp->b_dev)); 5982674Swnj bp->b_flags |= B_ERROR; 5992674Swnj } else if (++um->um_tab.b_errcnt > 27) { 6002674Swnj /* 6012674Swnj * After 28 retries (16 without offset, and 6022674Swnj * 12 with offset positioning) give up. 60310904Shelge * If the error was header CRC, the header is 60410904Shelge * screwed up, and the sector may in fact exist 60510904Shelge * in the bad sector table, better check... 6062674Swnj */ 60710904Shelge if (upaddr->uper1&UPER1_HCRC) { 60810904Shelge if (upecc(ui, BSE)) 60910904Shelge return; 61010904Shelge } 6119548Ssam hard: 6122931Swnj harderr(bp, "up"); 6139548Ssam printf("cn=%d tn=%d sn=%d cs2=%b er1=%b er2=%b\n", 6149548Ssam upaddr->updc, ((upaddr->upda)>>8)&077, 6159548Ssam (upaddr->upda)&037, 6169548Ssam upaddr->upcs2, UPCS2_BITS, 6179548Ssam upaddr->uper1, UPER1_BITS, 6189548Ssam upaddr->uper2, UPER2_BITS); 6192674Swnj bp->b_flags |= B_ERROR; 6209548Ssam } else if (upaddr->uper2 & UPER2_BSE) { 6219548Ssam if (upecc(ui, BSE)) 6229548Ssam return; 6239548Ssam else 6249548Ssam goto hard; 6252674Swnj } else { 6262674Swnj /* 6272674Swnj * Retriable error. 6282674Swnj * If a soft ecc, correct it (continuing 6292674Swnj * by returning if necessary. 6302674Swnj * Otherwise fall through and retry the transfer 6312674Swnj */ 6327183Sroot if ((upaddr->uper1&(UPER1_DCK|UPER1_ECH))==UPER1_DCK) { 6339548Ssam if (upecc(ui, ECC)) 6342629Swnj return; 6357183Sroot } else 6367183Sroot um->um_tab.b_active = 0; /* force retry */ 6372674Swnj } 6382674Swnj /* 6392674Swnj * Clear drive error and, every eight attempts, 6402674Swnj * (starting with the fourth) 6412674Swnj * recalibrate to clear the slate. 6422674Swnj */ 6432674Swnj upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 6442674Swnj needie = 0; 6453182Swnj if ((um->um_tab.b_errcnt&07) == 4 && um->um_tab.b_active == 0) { 6462674Swnj upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO; 6473160Swnj sc->sc_recal = 0; 6483160Swnj goto nextrecal; 6492674Swnj } 6502674Swnj } 6512674Swnj /* 6523160Swnj * Advance recalibration finite state machine 6533160Swnj * if recalibrate in progress, through 6543160Swnj * RECAL 6553160Swnj * SEEK 6563160Swnj * OFFSET (optional) 6573160Swnj * RETRY 6582674Swnj */ 6593160Swnj switch (sc->sc_recal) { 6603160Swnj 6613160Swnj case 1: 6623160Swnj upaddr->updc = bp->b_cylin; 6633160Swnj upaddr->upcs1 = UP_SEEK|UP_IE|UP_GO; 6643160Swnj goto nextrecal; 6653160Swnj case 2: 6663160Swnj if (um->um_tab.b_errcnt < 16 || (bp->b_flags&B_READ) == 0) 6673160Swnj goto donerecal; 6683445Sroot upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | UPOF_FMT22; 6693160Swnj upaddr->upcs1 = UP_IE|UP_OFFSET|UP_GO; 6703160Swnj goto nextrecal; 6713160Swnj nextrecal: 6723160Swnj sc->sc_recal++; 6733160Swnj um->um_tab.b_active = 1; 6743160Swnj return; 6753160Swnj donerecal: 6763160Swnj case 3: 6772674Swnj sc->sc_recal = 0; 6783160Swnj um->um_tab.b_active = 0; 6793160Swnj break; 6802674Swnj } 6812674Swnj /* 6822674Swnj * If still ``active'', then don't need any more retries. 6832674Swnj */ 6842674Swnj if (um->um_tab.b_active) { 6852674Swnj /* 6862674Swnj * If we were offset positioning, 6872674Swnj * return to centerline. 6882674Swnj */ 6892674Swnj if (um->um_tab.b_errcnt >= 16) { 6903445Sroot upaddr->upof = UPOF_FMT22; 6912674Swnj upaddr->upcs1 = UP_RTC|UP_GO|UP_IE; 6923445Sroot while (upaddr->upds & UPDS_PIP) 6932674Swnj DELAY(25); 694268Sbill needie = 0; 695264Sbill } 6962674Swnj um->um_tab.b_active = 0; 6972674Swnj um->um_tab.b_errcnt = 0; 6982674Swnj um->um_tab.b_actf = dp->b_forw; 6992674Swnj dp->b_active = 0; 7002674Swnj dp->b_errcnt = 0; 7012674Swnj dp->b_actf = bp->av_forw; 7022674Swnj bp->b_resid = (-upaddr->upwc * sizeof(short)); 7032674Swnj iodone(bp); 7042674Swnj /* 7052674Swnj * If this unit has more work to do, 7062674Swnj * then start it up right away. 7072674Swnj */ 7082674Swnj if (dp->b_actf) 7092674Swnj if (upustart(ui)) 710268Sbill needie = 0; 711264Sbill } 7122674Swnj as &= ~(1<<ui->ui_slave); 7133403Swnj /* 7143403Swnj * Release unibus resources and flush data paths. 7153403Swnj */ 7163403Swnj ubadone(um); 7172674Swnj doattn: 7182674Swnj /* 7192674Swnj * Process other units which need attention. 7202674Swnj * For each unit which needs attention, call 7212674Swnj * the unit start routine to place the slave 7222674Swnj * on the controller device queue. 7232674Swnj */ 7243160Swnj while (unit = ffs(as)) { 7253160Swnj unit--; /* was 1 origin */ 7263160Swnj as &= ~(1<<unit); 7273160Swnj upaddr->upas = 1<<unit; 7286383Swnj if (unit < UPIPUNITS && upustart(upip[sc21][unit])) 7293160Swnj needie = 0; 7303160Swnj } 7312674Swnj /* 7322674Swnj * If the controller is not transferring, but 7332674Swnj * there are devices ready to transfer, start 7342674Swnj * the controller. 7352674Swnj */ 7362395Swnj if (um->um_tab.b_actf && um->um_tab.b_active == 0) 7372395Swnj if (upstart(um)) 738268Sbill needie = 0; 739275Sbill if (needie) 7402629Swnj upaddr->upcs1 = UP_IE; 741264Sbill } 742264Sbill 7439357Ssam upread(dev, uio) 7442616Swnj dev_t dev; 7459357Ssam struct uio *uio; 746264Sbill { 74724743Sbloom register int unit = upunit(dev); 7482470Swnj 7492616Swnj if (unit >= NUP) 7509357Ssam return (ENXIO); 7519357Ssam return (physio(upstrategy, &rupbuf[unit], dev, B_READ, minphys, uio)); 752264Sbill } 753264Sbill 7549357Ssam upwrite(dev, uio) 7552616Swnj dev_t dev; 7569357Ssam struct uio *uio; 757264Sbill { 75824743Sbloom register int unit = upunit(dev); 7592470Swnj 7602616Swnj if (unit >= NUP) 7619357Ssam return (ENXIO); 7629357Ssam return (physio(upstrategy, &rupbuf[unit], dev, B_WRITE, minphys, uio)); 763264Sbill } 764264Sbill 765266Sbill /* 766266Sbill * Correct an ECC error, and restart the i/o to complete 767266Sbill * the transfer if necessary. This is quite complicated because 768266Sbill * the transfer may be going to an odd memory address base and/or 769266Sbill * across a page boundary. 770266Sbill */ 7719548Ssam upecc(ui, flag) 7722983Swnj register struct uba_device *ui; 7739548Ssam int flag; 774264Sbill { 7752629Swnj register struct updevice *up = (struct updevice *)ui->ui_addr; 7762395Swnj register struct buf *bp = uputab[ui->ui_unit].b_actf; 7772983Swnj register struct uba_ctlr *um = ui->ui_mi; 7782395Swnj register struct upst *st; 7792395Swnj struct uba_regs *ubp = ui->ui_hd->uh_uba; 780266Sbill register int i; 781264Sbill caddr_t addr; 782266Sbill int reg, bit, byte, npf, mask, o, cmd, ubaddr; 783264Sbill int bn, cn, tn, sn; 784264Sbill 785264Sbill /* 786266Sbill * Npf is the number of sectors transferred before the sector 787266Sbill * containing the ECC error, and reg is the UBA register 788266Sbill * mapping (the first part of) the transfer. 789266Sbill * O is offset within a memory page of the first byte transferred. 790264Sbill */ 7919548Ssam if (flag == CONT) 7929548Ssam npf = bp->b_error; 7939548Ssam else 79410858Ssam npf = btop((up->upwc * sizeof(short)) + bp->b_bcount); 7952571Swnj reg = btop(um->um_ubinfo&0x3ffff) + npf; 796264Sbill o = (int)bp->b_un.b_addr & PGOFSET; 797264Sbill mask = up->upec2; 7983445Sroot #ifdef UPECCDEBUG 7993403Swnj printf("npf %d reg %x o %d mask %o pos %d\n", npf, reg, o, mask, 8003403Swnj up->upec1); 8013445Sroot #endif 80224743Sbloom bn = bp->b_blkno; 8039548Ssam st = &upst[ui->ui_type]; 8049548Ssam cn = bp->b_cylin; 8059548Ssam sn = bn%st->nspc + npf; 8069548Ssam tn = sn/st->nsect; 8079548Ssam sn %= st->nsect; 8089548Ssam cn += tn/st->ntrak; 8099548Ssam tn %= st->ntrak; 8102725Swnj ubapurge(um); 8119548Ssam um->um_tab.b_active=2; 812266Sbill /* 8139548Ssam * action taken depends on the flag 814266Sbill */ 8159548Ssam switch(flag){ 8169548Ssam case ECC: 8179548Ssam npf--; 8189548Ssam reg--; 8199548Ssam mask = up->upec2; 82024743Sbloom log(KERN_RECOV, "up%d%c: soft ecc sn%d\n", upunit(bp->b_dev), 8219548Ssam 'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf); 8229548Ssam /* 8239548Ssam * Flush the buffered data path, and compute the 8249548Ssam * byte and bit position of the error. The variable i 8259548Ssam * is the byte offset in the transfer, the variable byte 8269548Ssam * is the offset from a page boundary in main memory. 8279548Ssam */ 8289548Ssam i = up->upec1 - 1; /* -1 makes 0 origin */ 8299548Ssam bit = i&07; 8309548Ssam i = (i&~07)>>3; 8319548Ssam byte = i + o; 8329548Ssam /* 8339548Ssam * Correct while possible bits remain of mask. Since mask 8349548Ssam * contains 11 bits, we continue while the bit offset is > -11. 8359548Ssam * Also watch out for end of this block and the end of the whole 8369548Ssam * transfer. 8379548Ssam */ 8389548Ssam while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 83913879Ssam struct pte pte; 84013879Ssam 84113879Ssam pte = ubp->uba_map[reg + btop(byte)]; 84213879Ssam addr = ptob(pte.pg_pfnum) + (byte & PGOFSET); 8433445Sroot #ifdef UPECCDEBUG 8449548Ssam printf("addr %x map reg %x\n", 8459548Ssam addr, *(int *)(&ubp->uba_map[reg+btop(byte)])); 8469548Ssam printf("old: %x, ", getmemc(addr)); 8473445Sroot #endif 8489548Ssam putmemc(addr, getmemc(addr)^(mask<<bit)); 8493445Sroot #ifdef UPECCDEBUG 8509548Ssam printf("new: %x\n", getmemc(addr)); 8513445Sroot #endif 8529548Ssam byte++; 8539548Ssam i++; 8549580Shelge bit -= 8; 8559548Ssam } 8569548Ssam if (up->upwc == 0) 8579548Ssam return (0); 8589548Ssam npf++; 8599548Ssam reg++; 8609548Ssam break; 8619548Ssam case BSE: 8629548Ssam /* 8639548Ssam * if not in bad sector table, return 0 8649548Ssam */ 8659548Ssam if ((bn = isbad(&upbad[ui->ui_unit], cn, tn, sn)) < 0) 8669548Ssam return(0); 8679548Ssam /* 8689548Ssam * flag this one as bad 8699548Ssam */ 8709548Ssam bp->b_flags |= B_BAD; 8719548Ssam bp->b_error = npf + 1; 8729548Ssam #ifdef UPECCDEBUG 8739548Ssam printf("BSE: restart at %d\n",npf+1); 8749548Ssam #endif 8759548Ssam bn = st->ncyl * st->nspc -st->nsect - 1 - bn; 8769548Ssam cn = bn / st->nspc; 8779548Ssam sn = bn % st->nspc; 8789548Ssam tn = sn / st->nsect; 8799548Ssam sn %= st->nsect; 8809548Ssam up->upwc = -(512 / sizeof (short)); 8819548Ssam #ifdef UPECCDEBUG 8829548Ssam printf("revector to cn %d tn %d sn %d\n", cn, tn, sn); 8839548Ssam #endif 8849548Ssam break; 8859548Ssam case CONT: 8869548Ssam #ifdef UPECCDEBUG 8879548Ssam printf("upecc, CONT: bn %d cn %d tn %d sn %d\n", bn, cn, tn, sn); 8889548Ssam #endif 8899548Ssam bp->b_flags &= ~B_BAD; 8909548Ssam up->upwc = -((bp->b_bcount - (int)ptob(npf)) / sizeof(short)); 8919548Ssam if (up->upwc == 0) 8929548Ssam return(0); 8939548Ssam break; 894264Sbill } 8957183Sroot if (up->upwc == 0) { 8967183Sroot um->um_tab.b_active = 0; 897264Sbill return (0); 8987183Sroot } 899266Sbill /* 900266Sbill * Have to continue the transfer... clear the drive, 901266Sbill * and compute the position where the transfer is to continue. 902266Sbill * We have completed npf+1 sectors of the transfer already; 903266Sbill * restart at offset o of next sector (i.e. in UBA register reg+1). 904266Sbill */ 9052629Swnj #ifdef notdef 9062629Swnj up->uper1 = 0; 9072629Swnj up->upcs1 |= UP_GO; 9082629Swnj #else 9092629Swnj up->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 910264Sbill up->updc = cn; 911266Sbill up->upda = (tn << 8) | sn; 9129548Ssam ubaddr = (int)ptob(reg) + o; 913266Sbill up->upba = ubaddr; 914266Sbill cmd = (ubaddr >> 8) & 0x300; 9159548Ssam cmd |= ((bp->b_flags&B_READ)?UP_RCOM:UP_WCOM)|UP_IE|UP_GO; 9169548Ssam um->um_tab.b_errcnt = 0; 917266Sbill up->upcs1 = cmd; 9182629Swnj #endif 919264Sbill return (1); 920264Sbill } 921286Sbill 922286Sbill /* 923286Sbill * Reset driver after UBA init. 924286Sbill * Cancel software state of all pending transfers 925286Sbill * and restart all units and the controller. 926286Sbill */ 9272395Swnj upreset(uban) 9282931Swnj int uban; 929286Sbill { 9302983Swnj register struct uba_ctlr *um; 9312983Swnj register struct uba_device *ui; 9322395Swnj register sc21, unit; 933286Sbill 9342646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 9352470Swnj if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban || 9362470Swnj um->um_alive == 0) 9372395Swnj continue; 9382931Swnj printf(" sc%d", sc21); 9392395Swnj um->um_tab.b_active = 0; 9402395Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 9412931Swnj up_softc[sc21].sc_recal = 0; 9426346Swnj up_softc[sc21].sc_wticks = 0; 9432571Swnj if (um->um_ubinfo) { 9442571Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 9459357Ssam um->um_ubinfo = 0; 9462395Swnj } 9473445Sroot ((struct updevice *)(um->um_addr))->upcs2 = UPCS2_CLR; 9482395Swnj for (unit = 0; unit < NUP; unit++) { 9492395Swnj if ((ui = updinfo[unit]) == 0) 9502395Swnj continue; 9512931Swnj if (ui->ui_alive == 0 || ui->ui_mi != um) 9522395Swnj continue; 9532395Swnj uputab[unit].b_active = 0; 9542395Swnj (void) upustart(ui); 9552395Swnj } 9562395Swnj (void) upstart(um); 957286Sbill } 958286Sbill } 959313Sbill 960313Sbill /* 961313Sbill * Wake up every second and if an interrupt is pending 962313Sbill * but nothing has happened increment a counter. 9632931Swnj * If nothing happens for 20 seconds, reset the UNIBUS 964313Sbill * and begin anew. 965313Sbill */ 966313Sbill upwatch() 967313Sbill { 9682983Swnj register struct uba_ctlr *um; 9692395Swnj register sc21, unit; 9702470Swnj register struct up_softc *sc; 971313Sbill 9722759Swnj timeout(upwatch, (caddr_t)0, hz); 9732646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 9742395Swnj um = upminfo[sc21]; 9752470Swnj if (um == 0 || um->um_alive == 0) 9762470Swnj continue; 9772470Swnj sc = &up_softc[sc21]; 9782395Swnj if (um->um_tab.b_active == 0) { 9792395Swnj for (unit = 0; unit < NUP; unit++) 9802629Swnj if (uputab[unit].b_active && 9812629Swnj updinfo[unit]->ui_mi == um) 9822395Swnj goto active; 9832470Swnj sc->sc_wticks = 0; 9842395Swnj continue; 9852395Swnj } 9862931Swnj active: 9872470Swnj sc->sc_wticks++; 9882470Swnj if (sc->sc_wticks >= 20) { 9892470Swnj sc->sc_wticks = 0; 9902931Swnj printf("sc%d: lost interrupt\n", sc21); 9912646Swnj ubareset(um->um_ubanum); 9922395Swnj } 993313Sbill } 994313Sbill } 9952379Swnj 9962379Swnj #define DBSIZE 20 9972379Swnj 9982379Swnj updump(dev) 9992379Swnj dev_t dev; 10002379Swnj { 10012629Swnj struct updevice *upaddr; 10022379Swnj char *start; 10033107Swnj int num, blk, unit; 10042379Swnj struct size *sizes; 10052395Swnj register struct uba_regs *uba; 10062983Swnj register struct uba_device *ui; 10072379Swnj register short *rp; 10082395Swnj struct upst *st; 10096848Ssam register int retry; 10102379Swnj 101124743Sbloom unit = upunit(dev); 10122889Swnj if (unit >= NUP) 10132889Swnj return (ENXIO); 10142470Swnj #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) 10152983Swnj ui = phys(struct uba_device *, updinfo[unit]); 10162889Swnj if (ui->ui_alive == 0) 10172889Swnj return (ENXIO); 10182395Swnj uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 10192983Swnj ubainit(uba); 10202629Swnj upaddr = (struct updevice *)ui->ui_physaddr; 10216848Ssam DELAY(5000000); 10222379Swnj num = maxfree; 10232379Swnj upaddr->upcs2 = unit; 10242983Swnj DELAY(100); 10256848Ssam upaddr->upcs1 = UP_DCLR|UP_GO; 10266848Ssam upaddr->upcs1 = UP_PRESET|UP_GO; 10276848Ssam upaddr->upof = UPOF_FMT22; 10286848Ssam retry = 0; 10296848Ssam do { 10306848Ssam DELAY(25); 10316848Ssam if (++retry > 527) 10326848Ssam break; 10336861Ssam } while ((upaddr->upds & UP_RDY) == 0); 10343445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) 10352889Swnj return (EFAULT); 10369357Ssam start = 0; 10378489Sroot st = &upst[ui->ui_type]; 10382395Swnj sizes = phys(struct size *, st->sizes); 103924213Sbloom if (dumplo < 0) 10402889Swnj return (EINVAL); 104124213Sbloom if (dumplo + num >= sizes[minor(dev)&07].nblocks) 104224213Sbloom num = sizes[minor(dev)&07].nblocks - dumplo; 10432379Swnj while (num > 0) { 10442379Swnj register struct pte *io; 10452379Swnj register int i; 10462379Swnj int cn, sn, tn; 10472379Swnj daddr_t bn; 10482379Swnj 10492379Swnj blk = num > DBSIZE ? DBSIZE : num; 10502395Swnj io = uba->uba_map; 10512379Swnj for (i = 0; i < blk; i++) 10522983Swnj *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV; 10532379Swnj *(int *)io = 0; 10542379Swnj bn = dumplo + btop(start); 10552607Swnj cn = bn/st->nspc + sizes[minor(dev)&07].cyloff; 10562607Swnj sn = bn%st->nspc; 10572607Swnj tn = sn/st->nsect; 10582607Swnj sn = sn%st->nsect; 10592379Swnj upaddr->updc = cn; 10602379Swnj rp = (short *) &upaddr->upda; 10612379Swnj *rp = (tn << 8) + sn; 10622379Swnj *--rp = 0; 10632379Swnj *--rp = -blk*NBPG / sizeof (short); 10642629Swnj *--rp = UP_GO|UP_WCOM; 10656848Ssam retry = 0; 10662379Swnj do { 10672379Swnj DELAY(25); 10686848Ssam if (++retry > 527) 10696848Ssam break; 10702629Swnj } while ((upaddr->upcs1 & UP_RDY) == 0); 10716848Ssam if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 10726861Ssam printf("up%d: not ready", unit); 10736848Ssam if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 10746848Ssam printf("\n"); 10756848Ssam return (EIO); 10766848Ssam } 10776848Ssam printf(" (flakey)\n"); 10786848Ssam } 10793445Sroot if (upaddr->upds&UPDS_ERR) 10802889Swnj return (EIO); 10812379Swnj start += blk*NBPG; 10822379Swnj num -= blk; 10832379Swnj } 10842379Swnj return (0); 10852379Swnj } 108612505Ssam 108712505Ssam upsize(dev) 108812505Ssam dev_t dev; 108912505Ssam { 109024743Sbloom int unit = upunit(dev); 109112505Ssam struct uba_device *ui; 109212505Ssam struct upst *st; 109312505Ssam 109412505Ssam if (unit >= NUP || (ui = updinfo[unit]) == 0 || ui->ui_alive == 0) 109512505Ssam return (-1); 109612505Ssam st = &upst[ui->ui_type]; 109712505Ssam return (st->sizes[minor(dev) & 07].nblocks); 109812505Ssam } 10991902Swnj #endif 1100