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*24743Sbloom * @(#)up.c 6.7 (Berkeley) 09/14/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 50*24743Sbloom #define upunit(dev) (minor(dev) >> 3) 51*24743Sbloom 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 { 235*24743Sbloom 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; 255*24743Sbloom unit = upunit(bp->b_dev); 256*24743Sbloom if (unit >= NUP) { 257*24743Sbloom bp->b_error = ENXIO; 2582395Swnj goto bad; 259*24743Sbloom } 2602395Swnj ui = updinfo[unit]; 261*24743Sbloom if (ui == 0 || ui->ui_alive == 0) { 262*24743Sbloom bp->b_error = ENXIO; 2632395Swnj goto bad; 264*24743Sbloom } 2652395Swnj st = &upst[ui->ui_type]; 2662395Swnj if (bp->b_blkno < 0 || 267*24743Sbloom (bn = bp->b_blkno)+sz > st->sizes[xunit].nblocks) { 268*24743Sbloom if (bp->b_blkno == st->sizes[xunit].nblocks + 1) 269*24743Sbloom goto done; 270*24743Sbloom bp->b_error = EINVAL; 2712395Swnj goto bad; 272*24743Sbloom } 2732395Swnj bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 27421977Sbloom s = spl5(); 2752470Swnj dp = &uputab[ui->ui_unit]; 2762470Swnj disksort(dp, bp); 2772470Swnj if (dp->b_active == 0) { 2782395Swnj (void) upustart(ui); 2792395Swnj bp = &ui->ui_mi->um_tab; 2802395Swnj if (bp->b_actf && bp->b_active == 0) 2812395Swnj (void) upstart(ui->ui_mi); 282264Sbill } 28321977Sbloom splx(s); 2842395Swnj return; 2852395Swnj 2862395Swnj bad: 2872395Swnj bp->b_flags |= B_ERROR; 288*24743Sbloom done: 2892395Swnj iodone(bp); 2902395Swnj return; 291264Sbill } 292264Sbill 2932674Swnj /* 2942674Swnj * Unit start routine. 2952674Swnj * Seek the drive to be where the data is 2962674Swnj * and then generate another interrupt 2972674Swnj * to actually start the transfer. 2982674Swnj * If there is only one drive on the controller, 2992674Swnj * or we are very close to the data, don't 3002674Swnj * bother with the search. If called after 3012674Swnj * searching once, don't bother to look where 3022674Swnj * we are, just queue for transfer (to avoid 3032674Swnj * positioning forever without transferrring.) 3042674Swnj */ 3052395Swnj upustart(ui) 3062983Swnj register struct uba_device *ui; 307264Sbill { 308264Sbill register struct buf *bp, *dp; 3092983Swnj register struct uba_ctlr *um; 3102629Swnj register struct updevice *upaddr; 3112395Swnj register struct upst *st; 312264Sbill daddr_t bn; 3132674Swnj int sn, csn; 3142607Swnj /* 3152607Swnj * The SC21 cancels commands if you just say 3162629Swnj * cs1 = UP_IE 3172607Swnj * so we are cautious about handling of cs1. 3182607Swnj * Also don't bother to clear as bits other than in upintr(). 3192607Swnj */ 3202674Swnj int didie = 0; 3212674Swnj 3222674Swnj if (ui == 0) 3232674Swnj return (0); 3242983Swnj um = ui->ui_mi; 3252395Swnj dk_busy &= ~(1<<ui->ui_dk); 3262395Swnj dp = &uputab[ui->ui_unit]; 327266Sbill if ((bp = dp->b_actf) == NULL) 328268Sbill goto out; 3292674Swnj /* 3302674Swnj * If the controller is active, just remember 3312674Swnj * that this device would like to be positioned... 3322674Swnj * if we tried to position now we would confuse the SC21. 3332674Swnj */ 3342395Swnj if (um->um_tab.b_active) { 3352459Swnj up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave; 336275Sbill return (0); 337275Sbill } 3382674Swnj /* 3392674Swnj * If we have already positioned this drive, 3402674Swnj * then just put it on the ready queue. 3412674Swnj */ 342276Sbill if (dp->b_active) 343276Sbill goto done; 344276Sbill dp->b_active = 1; 3452629Swnj upaddr = (struct updevice *)um->um_addr; 3462395Swnj upaddr->upcs2 = ui->ui_slave; 3472674Swnj /* 3482674Swnj * If drive has just come up, 3492674Swnj * setup the pack. 3502674Swnj */ 3519548Ssam if ((upaddr->upds & UPDS_VV) == 0 || upinit[ui->ui_unit] == 0) { 3529548Ssam struct buf *bbp = &bupbuf[ui->ui_unit]; 35310858Ssam 3542607Swnj /* SHOULD WARN SYSTEM THAT THIS HAPPENED */ 3559548Ssam upinit[ui->ui_unit] = 1; 3562629Swnj upaddr->upcs1 = UP_IE|UP_DCLR|UP_GO; 3572629Swnj upaddr->upcs1 = UP_IE|UP_PRESET|UP_GO; 3583445Sroot upaddr->upof = UPOF_FMT22; 359268Sbill didie = 1; 3609548Ssam st = &upst[ui->ui_type]; 3619548Ssam bbp->b_flags = B_READ|B_BUSY; 3629548Ssam bbp->b_dev = bp->b_dev; 3639548Ssam bbp->b_bcount = 512; 3649548Ssam bbp->b_un.b_addr = (caddr_t)&upbad[ui->ui_unit]; 3659548Ssam bbp->b_blkno = st->ncyl * st->nspc - st->nsect; 3669548Ssam bbp->b_cylin = st->ncyl - 1; 3679548Ssam dp->b_actf = bbp; 3689548Ssam bbp->av_forw = bp; 3699548Ssam bp = bbp; 370264Sbill } 3712674Swnj /* 3722674Swnj * If drive is offline, forget about positioning. 3732674Swnj */ 3743445Sroot if ((upaddr->upds & (UPDS_DPR|UPDS_MOL)) != (UPDS_DPR|UPDS_MOL)) 375275Sbill goto done; 3762674Swnj /* 3772674Swnj * If there is only one drive, 3782674Swnj * dont bother searching. 3792674Swnj */ 3802607Swnj if (up_softc[um->um_ctlr].sc_ndrive == 1) 3812607Swnj goto done; 3822674Swnj /* 3832674Swnj * Figure out where this transfer is going to 3842674Swnj * and see if we are close enough to justify not searching. 3852674Swnj */ 3862395Swnj st = &upst[ui->ui_type]; 387*24743Sbloom bn = bp->b_blkno; 3882395Swnj sn = bn%st->nspc; 38912837Ssam sn = (sn + st->nsect - st->sdist) % st->nsect; 3902674Swnj if (bp->b_cylin - upaddr->updc) 391266Sbill goto search; /* Not on-cylinder */ 392275Sbill else if (upseek) 393275Sbill goto done; /* Ok just to be on-cylinder */ 394264Sbill csn = (upaddr->upla>>6) - sn - 1; 395266Sbill if (csn < 0) 3962395Swnj csn += st->nsect; 39712837Ssam if (csn > st->nsect - st->rdist) 398264Sbill goto done; 399264Sbill search: 4002674Swnj upaddr->updc = bp->b_cylin; 4012674Swnj /* 4022674Swnj * Not on cylinder at correct position, 4032674Swnj * seek/search. 4042674Swnj */ 405275Sbill if (upseek) 4062629Swnj upaddr->upcs1 = UP_IE|UP_SEEK|UP_GO; 4072470Swnj else { 408275Sbill upaddr->upda = sn; 4092629Swnj upaddr->upcs1 = UP_IE|UP_SEARCH|UP_GO; 410275Sbill } 411268Sbill didie = 1; 4122674Swnj /* 4132674Swnj * Mark unit busy for iostat. 4142674Swnj */ 4152395Swnj if (ui->ui_dk >= 0) { 4162395Swnj dk_busy |= 1<<ui->ui_dk; 4172395Swnj dk_seek[ui->ui_dk]++; 418264Sbill } 419268Sbill goto out; 420264Sbill done: 4212674Swnj /* 4222674Swnj * Device is ready to go. 4232674Swnj * Put it on the ready queue for the controller 4242674Swnj * (unless its already there.) 4252674Swnj */ 4262629Swnj if (dp->b_active != 2) { 4272629Swnj dp->b_forw = NULL; 4282629Swnj if (um->um_tab.b_actf == NULL) 4292629Swnj um->um_tab.b_actf = dp; 4302629Swnj else 4312629Swnj um->um_tab.b_actl->b_forw = dp; 4322629Swnj um->um_tab.b_actl = dp; 4332629Swnj dp->b_active = 2; 4342629Swnj } 435268Sbill out: 436268Sbill return (didie); 437264Sbill } 438264Sbill 4392674Swnj /* 4402674Swnj * Start up a transfer on a drive. 4412674Swnj */ 4422395Swnj upstart(um) 4432983Swnj register struct uba_ctlr *um; 444264Sbill { 445264Sbill register struct buf *bp, *dp; 4462983Swnj register struct uba_device *ui; 4472629Swnj register struct updevice *upaddr; 4482470Swnj struct upst *st; 449264Sbill daddr_t bn; 4502681Swnj int dn, sn, tn, cmd, waitdry; 451264Sbill 452264Sbill loop: 4532674Swnj /* 4542674Swnj * Pull a request off the controller queue 4552674Swnj */ 4562395Swnj if ((dp = um->um_tab.b_actf) == NULL) 457268Sbill return (0); 458264Sbill if ((bp = dp->b_actf) == NULL) { 4592395Swnj um->um_tab.b_actf = dp->b_forw; 460264Sbill goto loop; 461264Sbill } 4622674Swnj /* 4632674Swnj * Mark controller busy, and 4642674Swnj * determine destination of this request. 4652674Swnj */ 4662395Swnj um->um_tab.b_active++; 467*24743Sbloom ui = updinfo[upunit(bp->b_dev)]; 468*24743Sbloom bn = bp->b_blkno; 4692395Swnj dn = ui->ui_slave; 4702395Swnj st = &upst[ui->ui_type]; 4712395Swnj sn = bn%st->nspc; 4722395Swnj tn = sn/st->nsect; 4732395Swnj sn %= st->nsect; 4742629Swnj upaddr = (struct updevice *)ui->ui_addr; 4752674Swnj /* 4762674Swnj * Select drive if not selected already. 4772674Swnj */ 4782674Swnj if ((upaddr->upcs2&07) != dn) 4792674Swnj upaddr->upcs2 = dn; 4802674Swnj /* 4812674Swnj * Check that it is ready and online 4822674Swnj */ 4832681Swnj waitdry = 0; 4843445Sroot while ((upaddr->upds&UPDS_DRY) == 0) { 485*24743Sbloom printf("up%d: ds wait ds=%o\n",upunit(bp->b_dev),upaddr->upds); 4862681Swnj if (++waitdry > 512) 4872681Swnj break; 4882681Swnj upwaitdry++; 4892681Swnj } 4903445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 491*24743Sbloom printf("up%d: not ready", upunit(bp->b_dev)); 4923445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 4932607Swnj printf("\n"); 4942395Swnj um->um_tab.b_active = 0; 4952395Swnj um->um_tab.b_errcnt = 0; 496893Sbill dp->b_actf = bp->av_forw; 497893Sbill dp->b_active = 0; 498893Sbill bp->b_flags |= B_ERROR; 499893Sbill iodone(bp); 500893Sbill goto loop; 501893Sbill } 5022674Swnj /* 5032674Swnj * Oh, well, sometimes this 5042674Swnj * happens, for reasons unknown. 5052674Swnj */ 5062629Swnj printf(" (flakey)\n"); 507264Sbill } 5082674Swnj /* 5092674Swnj * Setup for the transfer, and get in the 5102674Swnj * UNIBUS adaptor queue. 5112674Swnj */ 5122424Skre upaddr->updc = bp->b_cylin; 513264Sbill upaddr->upda = (tn << 8) + sn; 514264Sbill upaddr->upwc = -bp->b_bcount / sizeof (short); 515264Sbill if (bp->b_flags & B_READ) 5162629Swnj cmd = UP_IE|UP_RCOM|UP_GO; 517264Sbill else 5182629Swnj cmd = UP_IE|UP_WCOM|UP_GO; 5192571Swnj um->um_cmd = cmd; 5203107Swnj (void) ubago(ui); 521268Sbill return (1); 522264Sbill } 523264Sbill 5242674Swnj /* 5252674Swnj * Now all ready to go, stuff the registers. 5262674Swnj */ 5272571Swnj updgo(um) 5282983Swnj struct uba_ctlr *um; 5292395Swnj { 5302629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 5312470Swnj 5326953Swnj um->um_tab.b_active = 2; /* should now be 2 */ 5332571Swnj upaddr->upba = um->um_ubinfo; 5342571Swnj upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300); 5352395Swnj } 5362395Swnj 5372674Swnj /* 5382674Swnj * Handle a disk interrupt. 5392674Swnj */ 5402707Swnj upintr(sc21) 5412395Swnj register sc21; 542264Sbill { 543264Sbill register struct buf *bp, *dp; 5442983Swnj register struct uba_ctlr *um = upminfo[sc21]; 5452983Swnj register struct uba_device *ui; 5462629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 547264Sbill register unit; 5482470Swnj struct up_softc *sc = &up_softc[um->um_ctlr]; 5492607Swnj int as = (upaddr->upas & 0377) | sc->sc_softas; 5502681Swnj int needie = 1, waitdry; 551264Sbill 5522470Swnj sc->sc_wticks = 0; 5532607Swnj sc->sc_softas = 0; 5542674Swnj /* 5552674Swnj * If controller wasn't transferring, then this is an 5562674Swnj * interrupt for attention status on seeking drives. 5572674Swnj * Just service them. 5582674Swnj */ 5596346Swnj if (um->um_tab.b_active != 2 && !sc->sc_recal) { 5602674Swnj if (upaddr->upcs1 & UP_TRE) 5612674Swnj upaddr->upcs1 = UP_TRE; 5622674Swnj goto doattn; 5632674Swnj } 5646953Swnj um->um_tab.b_active = 1; 5652674Swnj /* 5662674Swnj * Get device and block structures, and a pointer 5672983Swnj * to the uba_device for the drive. Select the drive. 5682674Swnj */ 5692674Swnj dp = um->um_tab.b_actf; 5702674Swnj bp = dp->b_actf; 571*24743Sbloom ui = updinfo[upunit(bp->b_dev)]; 5722674Swnj dk_busy &= ~(1 << ui->ui_dk); 5732674Swnj if ((upaddr->upcs2&07) != ui->ui_slave) 5742395Swnj upaddr->upcs2 = ui->ui_slave; 5759548Ssam if (bp->b_flags&B_BAD) { 5769548Ssam if (upecc(ui, CONT)) 5779548Ssam return; 5789548Ssam } 5792674Swnj /* 5802674Swnj * Check for and process errors on 5812674Swnj * either the drive or the controller. 5822674Swnj */ 5833445Sroot if ((upaddr->upds&UPDS_ERR) || (upaddr->upcs1&UP_TRE)) { 5842681Swnj waitdry = 0; 5853445Sroot while ((upaddr->upds & UPDS_DRY) == 0) { 5862681Swnj if (++waitdry > 512) 5872681Swnj break; 5882681Swnj upwaitdry++; 5892681Swnj } 5903445Sroot if (upaddr->uper1&UPER1_WLE) { 5912674Swnj /* 5922674Swnj * Give up on write locked devices 5932674Swnj * immediately. 5942674Swnj */ 595*24743Sbloom printf("up%d: write locked\n", upunit(bp->b_dev)); 5962674Swnj bp->b_flags |= B_ERROR; 5972674Swnj } else if (++um->um_tab.b_errcnt > 27) { 5982674Swnj /* 5992674Swnj * After 28 retries (16 without offset, and 6002674Swnj * 12 with offset positioning) give up. 60110904Shelge * If the error was header CRC, the header is 60210904Shelge * screwed up, and the sector may in fact exist 60310904Shelge * in the bad sector table, better check... 6042674Swnj */ 60510904Shelge if (upaddr->uper1&UPER1_HCRC) { 60610904Shelge if (upecc(ui, BSE)) 60710904Shelge return; 60810904Shelge } 6099548Ssam hard: 6102931Swnj harderr(bp, "up"); 6119548Ssam printf("cn=%d tn=%d sn=%d cs2=%b er1=%b er2=%b\n", 6129548Ssam upaddr->updc, ((upaddr->upda)>>8)&077, 6139548Ssam (upaddr->upda)&037, 6149548Ssam upaddr->upcs2, UPCS2_BITS, 6159548Ssam upaddr->uper1, UPER1_BITS, 6169548Ssam upaddr->uper2, UPER2_BITS); 6172674Swnj bp->b_flags |= B_ERROR; 6189548Ssam } else if (upaddr->uper2 & UPER2_BSE) { 6199548Ssam if (upecc(ui, BSE)) 6209548Ssam return; 6219548Ssam else 6229548Ssam goto hard; 6232674Swnj } else { 6242674Swnj /* 6252674Swnj * Retriable error. 6262674Swnj * If a soft ecc, correct it (continuing 6272674Swnj * by returning if necessary. 6282674Swnj * Otherwise fall through and retry the transfer 6292674Swnj */ 6307183Sroot if ((upaddr->uper1&(UPER1_DCK|UPER1_ECH))==UPER1_DCK) { 6319548Ssam if (upecc(ui, ECC)) 6322629Swnj return; 6337183Sroot } else 6347183Sroot um->um_tab.b_active = 0; /* force retry */ 6352674Swnj } 6362674Swnj /* 6372674Swnj * Clear drive error and, every eight attempts, 6382674Swnj * (starting with the fourth) 6392674Swnj * recalibrate to clear the slate. 6402674Swnj */ 6412674Swnj upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 6422674Swnj needie = 0; 6433182Swnj if ((um->um_tab.b_errcnt&07) == 4 && um->um_tab.b_active == 0) { 6442674Swnj upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO; 6453160Swnj sc->sc_recal = 0; 6463160Swnj goto nextrecal; 6472674Swnj } 6482674Swnj } 6492674Swnj /* 6503160Swnj * Advance recalibration finite state machine 6513160Swnj * if recalibrate in progress, through 6523160Swnj * RECAL 6533160Swnj * SEEK 6543160Swnj * OFFSET (optional) 6553160Swnj * RETRY 6562674Swnj */ 6573160Swnj switch (sc->sc_recal) { 6583160Swnj 6593160Swnj case 1: 6603160Swnj upaddr->updc = bp->b_cylin; 6613160Swnj upaddr->upcs1 = UP_SEEK|UP_IE|UP_GO; 6623160Swnj goto nextrecal; 6633160Swnj case 2: 6643160Swnj if (um->um_tab.b_errcnt < 16 || (bp->b_flags&B_READ) == 0) 6653160Swnj goto donerecal; 6663445Sroot upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | UPOF_FMT22; 6673160Swnj upaddr->upcs1 = UP_IE|UP_OFFSET|UP_GO; 6683160Swnj goto nextrecal; 6693160Swnj nextrecal: 6703160Swnj sc->sc_recal++; 6713160Swnj um->um_tab.b_active = 1; 6723160Swnj return; 6733160Swnj donerecal: 6743160Swnj case 3: 6752674Swnj sc->sc_recal = 0; 6763160Swnj um->um_tab.b_active = 0; 6773160Swnj break; 6782674Swnj } 6792674Swnj /* 6802674Swnj * If still ``active'', then don't need any more retries. 6812674Swnj */ 6822674Swnj if (um->um_tab.b_active) { 6832674Swnj /* 6842674Swnj * If we were offset positioning, 6852674Swnj * return to centerline. 6862674Swnj */ 6872674Swnj if (um->um_tab.b_errcnt >= 16) { 6883445Sroot upaddr->upof = UPOF_FMT22; 6892674Swnj upaddr->upcs1 = UP_RTC|UP_GO|UP_IE; 6903445Sroot while (upaddr->upds & UPDS_PIP) 6912674Swnj DELAY(25); 692268Sbill needie = 0; 693264Sbill } 6942674Swnj um->um_tab.b_active = 0; 6952674Swnj um->um_tab.b_errcnt = 0; 6962674Swnj um->um_tab.b_actf = dp->b_forw; 6972674Swnj dp->b_active = 0; 6982674Swnj dp->b_errcnt = 0; 6992674Swnj dp->b_actf = bp->av_forw; 7002674Swnj bp->b_resid = (-upaddr->upwc * sizeof(short)); 7012674Swnj iodone(bp); 7022674Swnj /* 7032674Swnj * If this unit has more work to do, 7042674Swnj * then start it up right away. 7052674Swnj */ 7062674Swnj if (dp->b_actf) 7072674Swnj if (upustart(ui)) 708268Sbill needie = 0; 709264Sbill } 7102674Swnj as &= ~(1<<ui->ui_slave); 7113403Swnj /* 7123403Swnj * Release unibus resources and flush data paths. 7133403Swnj */ 7143403Swnj ubadone(um); 7152674Swnj doattn: 7162674Swnj /* 7172674Swnj * Process other units which need attention. 7182674Swnj * For each unit which needs attention, call 7192674Swnj * the unit start routine to place the slave 7202674Swnj * on the controller device queue. 7212674Swnj */ 7223160Swnj while (unit = ffs(as)) { 7233160Swnj unit--; /* was 1 origin */ 7243160Swnj as &= ~(1<<unit); 7253160Swnj upaddr->upas = 1<<unit; 7266383Swnj if (unit < UPIPUNITS && upustart(upip[sc21][unit])) 7273160Swnj needie = 0; 7283160Swnj } 7292674Swnj /* 7302674Swnj * If the controller is not transferring, but 7312674Swnj * there are devices ready to transfer, start 7322674Swnj * the controller. 7332674Swnj */ 7342395Swnj if (um->um_tab.b_actf && um->um_tab.b_active == 0) 7352395Swnj if (upstart(um)) 736268Sbill needie = 0; 737275Sbill if (needie) 7382629Swnj upaddr->upcs1 = UP_IE; 739264Sbill } 740264Sbill 7419357Ssam upread(dev, uio) 7422616Swnj dev_t dev; 7439357Ssam struct uio *uio; 744264Sbill { 745*24743Sbloom register int unit = upunit(dev); 7462470Swnj 7472616Swnj if (unit >= NUP) 7489357Ssam return (ENXIO); 7499357Ssam return (physio(upstrategy, &rupbuf[unit], dev, B_READ, minphys, uio)); 750264Sbill } 751264Sbill 7529357Ssam upwrite(dev, uio) 7532616Swnj dev_t dev; 7549357Ssam struct uio *uio; 755264Sbill { 756*24743Sbloom register int unit = upunit(dev); 7572470Swnj 7582616Swnj if (unit >= NUP) 7599357Ssam return (ENXIO); 7609357Ssam return (physio(upstrategy, &rupbuf[unit], dev, B_WRITE, minphys, uio)); 761264Sbill } 762264Sbill 763266Sbill /* 764266Sbill * Correct an ECC error, and restart the i/o to complete 765266Sbill * the transfer if necessary. This is quite complicated because 766266Sbill * the transfer may be going to an odd memory address base and/or 767266Sbill * across a page boundary. 768266Sbill */ 7699548Ssam upecc(ui, flag) 7702983Swnj register struct uba_device *ui; 7719548Ssam int flag; 772264Sbill { 7732629Swnj register struct updevice *up = (struct updevice *)ui->ui_addr; 7742395Swnj register struct buf *bp = uputab[ui->ui_unit].b_actf; 7752983Swnj register struct uba_ctlr *um = ui->ui_mi; 7762395Swnj register struct upst *st; 7772395Swnj struct uba_regs *ubp = ui->ui_hd->uh_uba; 778266Sbill register int i; 779264Sbill caddr_t addr; 780266Sbill int reg, bit, byte, npf, mask, o, cmd, ubaddr; 781264Sbill int bn, cn, tn, sn; 782264Sbill 783264Sbill /* 784266Sbill * Npf is the number of sectors transferred before the sector 785266Sbill * containing the ECC error, and reg is the UBA register 786266Sbill * mapping (the first part of) the transfer. 787266Sbill * O is offset within a memory page of the first byte transferred. 788264Sbill */ 7899548Ssam if (flag == CONT) 7909548Ssam npf = bp->b_error; 7919548Ssam else 79210858Ssam npf = btop((up->upwc * sizeof(short)) + bp->b_bcount); 7932571Swnj reg = btop(um->um_ubinfo&0x3ffff) + npf; 794264Sbill o = (int)bp->b_un.b_addr & PGOFSET; 795264Sbill mask = up->upec2; 7963445Sroot #ifdef UPECCDEBUG 7973403Swnj printf("npf %d reg %x o %d mask %o pos %d\n", npf, reg, o, mask, 7983403Swnj up->upec1); 7993445Sroot #endif 800*24743Sbloom bn = bp->b_blkno; 8019548Ssam st = &upst[ui->ui_type]; 8029548Ssam cn = bp->b_cylin; 8039548Ssam sn = bn%st->nspc + npf; 8049548Ssam tn = sn/st->nsect; 8059548Ssam sn %= st->nsect; 8069548Ssam cn += tn/st->ntrak; 8079548Ssam tn %= st->ntrak; 8082725Swnj ubapurge(um); 8099548Ssam um->um_tab.b_active=2; 810266Sbill /* 8119548Ssam * action taken depends on the flag 812266Sbill */ 8139548Ssam switch(flag){ 8149548Ssam case ECC: 8159548Ssam npf--; 8169548Ssam reg--; 8179548Ssam mask = up->upec2; 818*24743Sbloom log(KERN_RECOV, "up%d%c: soft ecc sn%d\n", upunit(bp->b_dev), 8199548Ssam 'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf); 8209548Ssam /* 8219548Ssam * Flush the buffered data path, and compute the 8229548Ssam * byte and bit position of the error. The variable i 8239548Ssam * is the byte offset in the transfer, the variable byte 8249548Ssam * is the offset from a page boundary in main memory. 8259548Ssam */ 8269548Ssam i = up->upec1 - 1; /* -1 makes 0 origin */ 8279548Ssam bit = i&07; 8289548Ssam i = (i&~07)>>3; 8299548Ssam byte = i + o; 8309548Ssam /* 8319548Ssam * Correct while possible bits remain of mask. Since mask 8329548Ssam * contains 11 bits, we continue while the bit offset is > -11. 8339548Ssam * Also watch out for end of this block and the end of the whole 8349548Ssam * transfer. 8359548Ssam */ 8369548Ssam while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 83713879Ssam struct pte pte; 83813879Ssam 83913879Ssam pte = ubp->uba_map[reg + btop(byte)]; 84013879Ssam addr = ptob(pte.pg_pfnum) + (byte & PGOFSET); 8413445Sroot #ifdef UPECCDEBUG 8429548Ssam printf("addr %x map reg %x\n", 8439548Ssam addr, *(int *)(&ubp->uba_map[reg+btop(byte)])); 8449548Ssam printf("old: %x, ", getmemc(addr)); 8453445Sroot #endif 8469548Ssam putmemc(addr, getmemc(addr)^(mask<<bit)); 8473445Sroot #ifdef UPECCDEBUG 8489548Ssam printf("new: %x\n", getmemc(addr)); 8493445Sroot #endif 8509548Ssam byte++; 8519548Ssam i++; 8529580Shelge bit -= 8; 8539548Ssam } 8549548Ssam if (up->upwc == 0) 8559548Ssam return (0); 8569548Ssam npf++; 8579548Ssam reg++; 8589548Ssam break; 8599548Ssam case BSE: 8609548Ssam /* 8619548Ssam * if not in bad sector table, return 0 8629548Ssam */ 8639548Ssam if ((bn = isbad(&upbad[ui->ui_unit], cn, tn, sn)) < 0) 8649548Ssam return(0); 8659548Ssam /* 8669548Ssam * flag this one as bad 8679548Ssam */ 8689548Ssam bp->b_flags |= B_BAD; 8699548Ssam bp->b_error = npf + 1; 8709548Ssam #ifdef UPECCDEBUG 8719548Ssam printf("BSE: restart at %d\n",npf+1); 8729548Ssam #endif 8739548Ssam bn = st->ncyl * st->nspc -st->nsect - 1 - bn; 8749548Ssam cn = bn / st->nspc; 8759548Ssam sn = bn % st->nspc; 8769548Ssam tn = sn / st->nsect; 8779548Ssam sn %= st->nsect; 8789548Ssam up->upwc = -(512 / sizeof (short)); 8799548Ssam #ifdef UPECCDEBUG 8809548Ssam printf("revector to cn %d tn %d sn %d\n", cn, tn, sn); 8819548Ssam #endif 8829548Ssam break; 8839548Ssam case CONT: 8849548Ssam #ifdef UPECCDEBUG 8859548Ssam printf("upecc, CONT: bn %d cn %d tn %d sn %d\n", bn, cn, tn, sn); 8869548Ssam #endif 8879548Ssam bp->b_flags &= ~B_BAD; 8889548Ssam up->upwc = -((bp->b_bcount - (int)ptob(npf)) / sizeof(short)); 8899548Ssam if (up->upwc == 0) 8909548Ssam return(0); 8919548Ssam break; 892264Sbill } 8937183Sroot if (up->upwc == 0) { 8947183Sroot um->um_tab.b_active = 0; 895264Sbill return (0); 8967183Sroot } 897266Sbill /* 898266Sbill * Have to continue the transfer... clear the drive, 899266Sbill * and compute the position where the transfer is to continue. 900266Sbill * We have completed npf+1 sectors of the transfer already; 901266Sbill * restart at offset o of next sector (i.e. in UBA register reg+1). 902266Sbill */ 9032629Swnj #ifdef notdef 9042629Swnj up->uper1 = 0; 9052629Swnj up->upcs1 |= UP_GO; 9062629Swnj #else 9072629Swnj up->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 908264Sbill up->updc = cn; 909266Sbill up->upda = (tn << 8) | sn; 9109548Ssam ubaddr = (int)ptob(reg) + o; 911266Sbill up->upba = ubaddr; 912266Sbill cmd = (ubaddr >> 8) & 0x300; 9139548Ssam cmd |= ((bp->b_flags&B_READ)?UP_RCOM:UP_WCOM)|UP_IE|UP_GO; 9149548Ssam um->um_tab.b_errcnt = 0; 915266Sbill up->upcs1 = cmd; 9162629Swnj #endif 917264Sbill return (1); 918264Sbill } 919286Sbill 920286Sbill /* 921286Sbill * Reset driver after UBA init. 922286Sbill * Cancel software state of all pending transfers 923286Sbill * and restart all units and the controller. 924286Sbill */ 9252395Swnj upreset(uban) 9262931Swnj int uban; 927286Sbill { 9282983Swnj register struct uba_ctlr *um; 9292983Swnj register struct uba_device *ui; 9302395Swnj register sc21, unit; 931286Sbill 9322646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 9332470Swnj if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban || 9342470Swnj um->um_alive == 0) 9352395Swnj continue; 9362931Swnj printf(" sc%d", sc21); 9372395Swnj um->um_tab.b_active = 0; 9382395Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 9392931Swnj up_softc[sc21].sc_recal = 0; 9406346Swnj up_softc[sc21].sc_wticks = 0; 9412571Swnj if (um->um_ubinfo) { 9422571Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 9439357Ssam um->um_ubinfo = 0; 9442395Swnj } 9453445Sroot ((struct updevice *)(um->um_addr))->upcs2 = UPCS2_CLR; 9462395Swnj for (unit = 0; unit < NUP; unit++) { 9472395Swnj if ((ui = updinfo[unit]) == 0) 9482395Swnj continue; 9492931Swnj if (ui->ui_alive == 0 || ui->ui_mi != um) 9502395Swnj continue; 9512395Swnj uputab[unit].b_active = 0; 9522395Swnj (void) upustart(ui); 9532395Swnj } 9542395Swnj (void) upstart(um); 955286Sbill } 956286Sbill } 957313Sbill 958313Sbill /* 959313Sbill * Wake up every second and if an interrupt is pending 960313Sbill * but nothing has happened increment a counter. 9612931Swnj * If nothing happens for 20 seconds, reset the UNIBUS 962313Sbill * and begin anew. 963313Sbill */ 964313Sbill upwatch() 965313Sbill { 9662983Swnj register struct uba_ctlr *um; 9672395Swnj register sc21, unit; 9682470Swnj register struct up_softc *sc; 969313Sbill 9702759Swnj timeout(upwatch, (caddr_t)0, hz); 9712646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 9722395Swnj um = upminfo[sc21]; 9732470Swnj if (um == 0 || um->um_alive == 0) 9742470Swnj continue; 9752470Swnj sc = &up_softc[sc21]; 9762395Swnj if (um->um_tab.b_active == 0) { 9772395Swnj for (unit = 0; unit < NUP; unit++) 9782629Swnj if (uputab[unit].b_active && 9792629Swnj updinfo[unit]->ui_mi == um) 9802395Swnj goto active; 9812470Swnj sc->sc_wticks = 0; 9822395Swnj continue; 9832395Swnj } 9842931Swnj active: 9852470Swnj sc->sc_wticks++; 9862470Swnj if (sc->sc_wticks >= 20) { 9872470Swnj sc->sc_wticks = 0; 9882931Swnj printf("sc%d: lost interrupt\n", sc21); 9892646Swnj ubareset(um->um_ubanum); 9902395Swnj } 991313Sbill } 992313Sbill } 9932379Swnj 9942379Swnj #define DBSIZE 20 9952379Swnj 9962379Swnj updump(dev) 9972379Swnj dev_t dev; 9982379Swnj { 9992629Swnj struct updevice *upaddr; 10002379Swnj char *start; 10013107Swnj int num, blk, unit; 10022379Swnj struct size *sizes; 10032395Swnj register struct uba_regs *uba; 10042983Swnj register struct uba_device *ui; 10052379Swnj register short *rp; 10062395Swnj struct upst *st; 10076848Ssam register int retry; 10082379Swnj 1009*24743Sbloom unit = upunit(dev); 10102889Swnj if (unit >= NUP) 10112889Swnj return (ENXIO); 10122470Swnj #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) 10132983Swnj ui = phys(struct uba_device *, updinfo[unit]); 10142889Swnj if (ui->ui_alive == 0) 10152889Swnj return (ENXIO); 10162395Swnj uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 10172983Swnj ubainit(uba); 10182629Swnj upaddr = (struct updevice *)ui->ui_physaddr; 10196848Ssam DELAY(5000000); 10202379Swnj num = maxfree; 10212379Swnj upaddr->upcs2 = unit; 10222983Swnj DELAY(100); 10236848Ssam upaddr->upcs1 = UP_DCLR|UP_GO; 10246848Ssam upaddr->upcs1 = UP_PRESET|UP_GO; 10256848Ssam upaddr->upof = UPOF_FMT22; 10266848Ssam retry = 0; 10276848Ssam do { 10286848Ssam DELAY(25); 10296848Ssam if (++retry > 527) 10306848Ssam break; 10316861Ssam } while ((upaddr->upds & UP_RDY) == 0); 10323445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) 10332889Swnj return (EFAULT); 10349357Ssam start = 0; 10358489Sroot st = &upst[ui->ui_type]; 10362395Swnj sizes = phys(struct size *, st->sizes); 103724213Sbloom if (dumplo < 0) 10382889Swnj return (EINVAL); 103924213Sbloom if (dumplo + num >= sizes[minor(dev)&07].nblocks) 104024213Sbloom num = sizes[minor(dev)&07].nblocks - dumplo; 10412379Swnj while (num > 0) { 10422379Swnj register struct pte *io; 10432379Swnj register int i; 10442379Swnj int cn, sn, tn; 10452379Swnj daddr_t bn; 10462379Swnj 10472379Swnj blk = num > DBSIZE ? DBSIZE : num; 10482395Swnj io = uba->uba_map; 10492379Swnj for (i = 0; i < blk; i++) 10502983Swnj *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV; 10512379Swnj *(int *)io = 0; 10522379Swnj bn = dumplo + btop(start); 10532607Swnj cn = bn/st->nspc + sizes[minor(dev)&07].cyloff; 10542607Swnj sn = bn%st->nspc; 10552607Swnj tn = sn/st->nsect; 10562607Swnj sn = sn%st->nsect; 10572379Swnj upaddr->updc = cn; 10582379Swnj rp = (short *) &upaddr->upda; 10592379Swnj *rp = (tn << 8) + sn; 10602379Swnj *--rp = 0; 10612379Swnj *--rp = -blk*NBPG / sizeof (short); 10622629Swnj *--rp = UP_GO|UP_WCOM; 10636848Ssam retry = 0; 10642379Swnj do { 10652379Swnj DELAY(25); 10666848Ssam if (++retry > 527) 10676848Ssam break; 10682629Swnj } while ((upaddr->upcs1 & UP_RDY) == 0); 10696848Ssam if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 10706861Ssam printf("up%d: not ready", unit); 10716848Ssam if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 10726848Ssam printf("\n"); 10736848Ssam return (EIO); 10746848Ssam } 10756848Ssam printf(" (flakey)\n"); 10766848Ssam } 10773445Sroot if (upaddr->upds&UPDS_ERR) 10782889Swnj return (EIO); 10792379Swnj start += blk*NBPG; 10802379Swnj num -= blk; 10812379Swnj } 10822379Swnj return (0); 10832379Swnj } 108412505Ssam 108512505Ssam upsize(dev) 108612505Ssam dev_t dev; 108712505Ssam { 1088*24743Sbloom int unit = upunit(dev); 108912505Ssam struct uba_device *ui; 109012505Ssam struct upst *st; 109112505Ssam 109212505Ssam if (unit >= NUP || (ui = updinfo[unit]) == 0 || ui->ui_alive == 0) 109312505Ssam return (-1); 109412505Ssam st = &upst[ui->ui_type]; 109512505Ssam return (st->sizes[minor(dev) & 07].nblocks); 109612505Ssam } 10971902Swnj #endif 1098