1*21977Sbloom /* up.c 6.4 85/06/04 */ 2264Sbill 31937Swnj #include "up.h" 42646Swnj #if NSC > 0 5264Sbill /* 69548Ssam * UNIBUS disk driver with: 79548Ssam * overlapped seeks, 89548Ssam * ECC recovery, and 99548Ssam * bad sector forwarding. 102889Swnj * 112889Swnj * TODO: 123445Sroot * Check that offset recovery code works 13264Sbill */ 149782Ssam #include "../machine/pte.h" 15264Sbill 1617082Sbloom #include "param.h" 1717082Sbloom #include "systm.h" 1817082Sbloom #include "dk.h" 1917082Sbloom #include "dkbad.h" 2017082Sbloom #include "buf.h" 2117082Sbloom #include "conf.h" 2217082Sbloom #include "dir.h" 2317082Sbloom #include "user.h" 2417082Sbloom #include "map.h" 2517082Sbloom #include "vm.h" 2617082Sbloom #include "cmap.h" 2717082Sbloom #include "uio.h" 2817082Sbloom #include "kernel.h" 2918317Sralph #include "syslog.h" 30264Sbill 319357Ssam #include "../vax/cpu.h" 329357Ssam #include "../vax/nexus.h" 3317082Sbloom #include "ubavar.h" 3417082Sbloom #include "ubareg.h" 3517082Sbloom #include "upreg.h" 369357Ssam 372395Swnj struct up_softc { 382395Swnj int sc_softas; 392607Swnj int sc_ndrive; 402395Swnj int sc_wticks; 412674Swnj int sc_recal; 422646Swnj } up_softc[NSC]; 43275Sbill 442395Swnj /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 4510858Ssam struct size { 46264Sbill daddr_t nblocks; 47264Sbill int cyloff; 4811211Ssam } up9300_sizes[8] = { 49264Sbill 15884, 0, /* A=cyl 0 thru 26 */ 50264Sbill 33440, 27, /* B=cyl 27 thru 81 */ 51341Sbill 495520, 0, /* C=cyl 0 thru 814 */ 52264Sbill 15884, 562, /* D=cyl 562 thru 588 */ 53264Sbill 55936, 589, /* E=cyl 589 thru 680 */ 543730Sroot 81376, 681, /* F=cyl 681 thru 814 */ 553730Sroot 153728, 562, /* G=cyl 562 thru 814 */ 56264Sbill 291346, 82, /* H=cyl 82 thru 561 */ 5711211Ssam }, up9766_sizes[8] = { 5811211Ssam 15884, 0, /* A=cyl 0 thru 26 */ 5911211Ssam 33440, 27, /* B=cyl 27 thru 81 */ 6011211Ssam 500384, 0, /* C=cyl 0 thru 822 */ 6111211Ssam 15884, 562, /* D=cyl 562 thru 588 */ 6211211Ssam 55936, 589, /* E=cyl 589 thru 680 */ 6311211Ssam 86240, 681, /* F=cyl 681 thru 822 */ 6411211Ssam 158592, 562, /* G=cyl 562 thru 822 */ 6511211Ssam 291346, 82, /* H=cyl 82 thru 561 */ 6611211Ssam }, up160_sizes[8] = { 672395Swnj 15884, 0, /* A=cyl 0 thru 49 */ 682395Swnj 33440, 50, /* B=cyl 50 thru 154 */ 692395Swnj 263360, 0, /* C=cyl 0 thru 822 */ 7011211Ssam 15884, 155, /* D=cyl 155 thru 204 */ 7111211Ssam 55936, 205, /* E=cyl 205 thru 379 */ 7211211Ssam 141664, 380, /* F=cyl 380 thru 822 */ 7311211Ssam 213664, 155, /* G=cyl 155 thru 822 */ 742395Swnj 0, 0, 756851Ssam }, upam_sizes[8] = { 766305Sroot 15884, 0, /* A=cyl 0 thru 31 */ 776305Sroot 33440, 32, /* B=cyl 32 thru 97 */ 786305Sroot 524288, 0, /* C=cyl 0 thru 1023 */ 7911211Ssam 15884, 668, /* D=cyl 668 thru 699 */ 8011211Ssam 55936, 700, /* E=cyl 700 thru 809 */ 8111211Ssam 109472, 810, /* F=cyl 810 thru 1023 */ 8211211Ssam 182176, 668, /* G=cyl 668 thru 1023 */ 836305Sroot 291346, 98, /* H=cyl 98 thru 667 */ 8414002Ssam }, up980_sizes[8] = { 8514002Ssam 15884, 0, /* A=cyl 0 thru 99 */ 8614002Ssam 33440, 100, /* B=cyl 100 thru 308 */ 8714002Ssam 131680, 0, /* C=cyl 0 thru 822 */ 8814002Ssam 15884, 309, /* D=cyl 309 thru 408 */ 8914002Ssam 55936, 409, /* E=cyl 409 thru 758 */ 9014002Ssam 10080, 759, /* F=cyl 759 thru 822 */ 9114002Ssam 82080, 309, /* G=cyl 309 thru 822 */ 9214002Ssam 0, 0, 93*21977Sbloom }, upeagle_sizes[8] = { 94*21977Sbloom 15884, 0, /* A=cyl 0 thru 16 */ 95*21977Sbloom 66880, 17, /* B=cyl 17 thru 86 */ 96*21977Sbloom 808320, 0, /* C=cyl 0 thru 841 */ 97*21977Sbloom 15884, 391, /* D=cyl 391 thru 407 */ 98*21977Sbloom 307200, 408, /* E=cyl 408 thru 727 */ 99*21977Sbloom 109296, 728, /* F=cyl 728 thru 841 */ 100*21977Sbloom 432816, 391, /* G=cyl 391 thru 841 */ 101*21977Sbloom 291346, 87, /* H=cyl 87 thru 390 */ 102264Sbill }; 1032395Swnj /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 104264Sbill 1052607Swnj int upprobe(), upslave(), upattach(), updgo(), upintr(); 1062983Swnj struct uba_ctlr *upminfo[NSC]; 1072983Swnj struct uba_device *updinfo[NUP]; 1086383Swnj #define UPIPUNITS 8 1096383Swnj struct uba_device *upip[NSC][UPIPUNITS]; /* fuji w/fixed head gives n,n+4 */ 1102395Swnj 1112607Swnj u_short upstd[] = { 0776700, 0774400, 0776300, 0 }; 1122616Swnj struct uba_driver scdriver = 1132607Swnj { upprobe, upslave, upattach, updgo, upstd, "up", updinfo, "sc", upminfo }; 1142395Swnj struct buf uputab[NUP]; 1159548Ssam char upinit[NUP]; 1162395Swnj 1172395Swnj struct upst { 11812837Ssam short nsect; /* # sectors/track */ 11912837Ssam short ntrak; /* # tracks/cylinder */ 12012837Ssam short nspc; /* # sectors/cylinder */ 12112837Ssam short ncyl; /* # cylinders */ 12212837Ssam struct size *sizes; /* partition tables */ 12312837Ssam short sdist; /* seek distance metric */ 12412837Ssam short rdist; /* rotational distance metric */ 1252395Swnj } upst[] = { 12612837Ssam { 32, 19, 32*19, 815, up9300_sizes, 3, 4 }, /* 9300 */ 12712837Ssam { 32, 19, 32*19, 823, up9766_sizes, 3, 4 }, /* 9766 */ 12812837Ssam { 32, 10, 32*10, 823, up160_sizes, 3, 4 }, /* fuji 160m */ 12912837Ssam { 32, 16, 32*16, 1024, upam_sizes, 7, 8 }, /* Capricorn */ 13014002Ssam { 32, 5, 32*5, 823, up980_sizes, 3, 4 }, /* DM980 */ 131*21977Sbloom { 48, 20, 48*20, 842, upeagle_sizes, 15, 8 }, /* EAGLE */ 13212837Ssam { 0, 0, 0, 0, 0, 0, 0 } 1332395Swnj }; 1342395Swnj 1352629Swnj u_char up_offset[16] = { 1369548Ssam UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400, 1379548Ssam UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800, 1389548Ssam UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200, 1399548Ssam 0, 0, 0, 0 1402629Swnj }; 141264Sbill 1422616Swnj struct buf rupbuf[NUP]; 1439548Ssam struct buf bupbuf[NUP]; 1449548Ssam struct dkbad upbad[NUP]; 145264Sbill 146264Sbill #define b_cylin b_resid 147264Sbill 148264Sbill #ifdef INTRLVE 149264Sbill daddr_t dkblock(); 150264Sbill #endif 1512395Swnj 1522395Swnj int upwstart, upwatch(); /* Have started guardian */ 1532470Swnj int upseek; 1542681Swnj int upwaitdry; 1552395Swnj 1562395Swnj /*ARGSUSED*/ 1572607Swnj upprobe(reg) 1582395Swnj caddr_t reg; 1592395Swnj { 1602459Swnj register int br, cvec; 1612459Swnj 1622607Swnj #ifdef lint 16312779Ssam br = 0; cvec = br; br = cvec; upintr(0); 1642607Swnj #endif 1652629Swnj ((struct updevice *)reg)->upcs1 = UP_IE|UP_RDY; 1662607Swnj DELAY(10); 1672629Swnj ((struct updevice *)reg)->upcs1 = 0; 1689357Ssam return (sizeof (struct updevice)); 1692395Swnj } 1702395Swnj 1712607Swnj upslave(ui, reg) 1722983Swnj struct uba_device *ui; 1732395Swnj caddr_t reg; 1742395Swnj { 1752629Swnj register struct updevice *upaddr = (struct updevice *)reg; 1762395Swnj 1772395Swnj upaddr->upcs1 = 0; /* conservative */ 1782607Swnj upaddr->upcs2 = ui->ui_slave; 1796843Swnj upaddr->upcs1 = UP_NOP|UP_GO; 1803445Sroot if (upaddr->upcs2&UPCS2_NED) { 1812629Swnj upaddr->upcs1 = UP_DCLR|UP_GO; 1822395Swnj return (0); 1832395Swnj } 1842607Swnj return (1); 1852607Swnj } 1862607Swnj 1872607Swnj upattach(ui) 1882983Swnj register struct uba_device *ui; 1892607Swnj { 1902607Swnj 1912395Swnj if (upwstart == 0) { 1922759Swnj timeout(upwatch, (caddr_t)0, hz); 1932395Swnj upwstart++; 1942395Swnj } 1952571Swnj if (ui->ui_dk >= 0) 1962571Swnj dk_mspw[ui->ui_dk] = .0000020345; 1972607Swnj upip[ui->ui_ctlr][ui->ui_slave] = ui; 1982607Swnj up_softc[ui->ui_ctlr].sc_ndrive++; 19911119Ssam ui->ui_type = upmaptype(ui); 20011119Ssam } 20111119Ssam 20211119Ssam upmaptype(ui) 20311119Ssam register struct uba_device *ui; 20411119Ssam { 20511119Ssam register struct updevice *upaddr = (struct updevice *)ui->ui_addr; 20611119Ssam int type = ui->ui_type; 20711119Ssam register struct upst *st; 20811119Ssam 2092629Swnj upaddr->upcs1 = 0; 2102629Swnj upaddr->upcs2 = ui->ui_slave; 2113496Sroot upaddr->uphr = UPHR_MAXTRAK; 21211119Ssam for (st = upst; st->nsect != 0; st++) 21311119Ssam if (upaddr->uphr == st->ntrak - 1) { 21411119Ssam type = st - upst; 21511119Ssam break; 21611119Ssam } 21711119Ssam if (st->nsect == 0) 21811119Ssam printf("up%d: uphr=%x\n", ui->ui_slave, upaddr->uphr); 21911119Ssam if (type == 0) { 22011112Shelge upaddr->uphr = UPHR_MAXCYL; 22111112Shelge if (upaddr->uphr == 822) 22211119Ssam type++; 22311112Shelge } 2243496Sroot upaddr->upcs2 = UPCS2_CLR; 22511119Ssam return (type); 2262395Swnj } 227264Sbill 2289548Ssam upopen(dev) 2299548Ssam dev_t dev; 2309548Ssam { 2319548Ssam register int unit = minor(dev) >> 3; 2329548Ssam register struct uba_device *ui; 2339548Ssam 2349548Ssam if (unit >= NUP || (ui = updinfo[unit]) == 0 || ui->ui_alive == 0) 2359548Ssam return (ENXIO); 2369548Ssam return (0); 2379548Ssam } 2389548Ssam 239264Sbill upstrategy(bp) 2402395Swnj register struct buf *bp; 241264Sbill { 2422983Swnj register struct uba_device *ui; 2432395Swnj register struct upst *st; 2442395Swnj register int unit; 2452470Swnj register struct buf *dp; 2462395Swnj int xunit = minor(bp->b_dev) & 07; 2472470Swnj long bn, sz; 248*21977Sbloom int s; 249264Sbill 2502470Swnj sz = (bp->b_bcount+511) >> 9; 251264Sbill unit = dkunit(bp); 2522395Swnj if (unit >= NUP) 2532395Swnj goto bad; 2542395Swnj ui = updinfo[unit]; 2552395Swnj if (ui == 0 || ui->ui_alive == 0) 2562395Swnj goto bad; 2572395Swnj st = &upst[ui->ui_type]; 2582395Swnj if (bp->b_blkno < 0 || 2592395Swnj (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) 2602395Swnj goto bad; 2612395Swnj bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 262*21977Sbloom s = spl5(); 2632470Swnj dp = &uputab[ui->ui_unit]; 2642470Swnj disksort(dp, bp); 2652470Swnj if (dp->b_active == 0) { 2662395Swnj (void) upustart(ui); 2672395Swnj bp = &ui->ui_mi->um_tab; 2682395Swnj if (bp->b_actf && bp->b_active == 0) 2692395Swnj (void) upstart(ui->ui_mi); 270264Sbill } 271*21977Sbloom splx(s); 2722395Swnj return; 2732395Swnj 2742395Swnj bad: 2752395Swnj bp->b_flags |= B_ERROR; 2762395Swnj iodone(bp); 2772395Swnj return; 278264Sbill } 279264Sbill 2802674Swnj /* 2812674Swnj * Unit start routine. 2822674Swnj * Seek the drive to be where the data is 2832674Swnj * and then generate another interrupt 2842674Swnj * to actually start the transfer. 2852674Swnj * If there is only one drive on the controller, 2862674Swnj * or we are very close to the data, don't 2872674Swnj * bother with the search. If called after 2882674Swnj * searching once, don't bother to look where 2892674Swnj * we are, just queue for transfer (to avoid 2902674Swnj * positioning forever without transferrring.) 2912674Swnj */ 2922395Swnj upustart(ui) 2932983Swnj register struct uba_device *ui; 294264Sbill { 295264Sbill register struct buf *bp, *dp; 2962983Swnj register struct uba_ctlr *um; 2972629Swnj register struct updevice *upaddr; 2982395Swnj register struct upst *st; 299264Sbill daddr_t bn; 3002674Swnj int sn, csn; 3012607Swnj /* 3022607Swnj * The SC21 cancels commands if you just say 3032629Swnj * cs1 = UP_IE 3042607Swnj * so we are cautious about handling of cs1. 3052607Swnj * Also don't bother to clear as bits other than in upintr(). 3062607Swnj */ 3072674Swnj int didie = 0; 3082674Swnj 3092674Swnj if (ui == 0) 3102674Swnj return (0); 3112983Swnj um = ui->ui_mi; 3122395Swnj dk_busy &= ~(1<<ui->ui_dk); 3132395Swnj dp = &uputab[ui->ui_unit]; 314266Sbill if ((bp = dp->b_actf) == NULL) 315268Sbill goto out; 3162674Swnj /* 3172674Swnj * If the controller is active, just remember 3182674Swnj * that this device would like to be positioned... 3192674Swnj * if we tried to position now we would confuse the SC21. 3202674Swnj */ 3212395Swnj if (um->um_tab.b_active) { 3222459Swnj up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave; 323275Sbill return (0); 324275Sbill } 3252674Swnj /* 3262674Swnj * If we have already positioned this drive, 3272674Swnj * then just put it on the ready queue. 3282674Swnj */ 329276Sbill if (dp->b_active) 330276Sbill goto done; 331276Sbill dp->b_active = 1; 3322629Swnj upaddr = (struct updevice *)um->um_addr; 3332395Swnj upaddr->upcs2 = ui->ui_slave; 3342674Swnj /* 3352674Swnj * If drive has just come up, 3362674Swnj * setup the pack. 3372674Swnj */ 3389548Ssam if ((upaddr->upds & UPDS_VV) == 0 || upinit[ui->ui_unit] == 0) { 3399548Ssam struct buf *bbp = &bupbuf[ui->ui_unit]; 34010858Ssam 3412607Swnj /* SHOULD WARN SYSTEM THAT THIS HAPPENED */ 3429548Ssam upinit[ui->ui_unit] = 1; 3432629Swnj upaddr->upcs1 = UP_IE|UP_DCLR|UP_GO; 3442629Swnj upaddr->upcs1 = UP_IE|UP_PRESET|UP_GO; 3453445Sroot upaddr->upof = UPOF_FMT22; 346268Sbill didie = 1; 3479548Ssam st = &upst[ui->ui_type]; 3489548Ssam bbp->b_flags = B_READ|B_BUSY; 3499548Ssam bbp->b_dev = bp->b_dev; 3509548Ssam bbp->b_bcount = 512; 3519548Ssam bbp->b_un.b_addr = (caddr_t)&upbad[ui->ui_unit]; 3529548Ssam bbp->b_blkno = st->ncyl * st->nspc - st->nsect; 3539548Ssam bbp->b_cylin = st->ncyl - 1; 3549548Ssam dp->b_actf = bbp; 3559548Ssam bbp->av_forw = bp; 3569548Ssam bp = bbp; 357264Sbill } 3582674Swnj /* 3592674Swnj * If drive is offline, forget about positioning. 3602674Swnj */ 3613445Sroot if ((upaddr->upds & (UPDS_DPR|UPDS_MOL)) != (UPDS_DPR|UPDS_MOL)) 362275Sbill goto done; 3632674Swnj /* 3642674Swnj * If there is only one drive, 3652674Swnj * dont bother searching. 3662674Swnj */ 3672607Swnj if (up_softc[um->um_ctlr].sc_ndrive == 1) 3682607Swnj goto done; 3692674Swnj /* 3702674Swnj * Figure out where this transfer is going to 3712674Swnj * and see if we are close enough to justify not searching. 3722674Swnj */ 3732395Swnj st = &upst[ui->ui_type]; 374264Sbill bn = dkblock(bp); 3752395Swnj sn = bn%st->nspc; 37612837Ssam sn = (sn + st->nsect - st->sdist) % st->nsect; 3772674Swnj if (bp->b_cylin - upaddr->updc) 378266Sbill goto search; /* Not on-cylinder */ 379275Sbill else if (upseek) 380275Sbill goto done; /* Ok just to be on-cylinder */ 381264Sbill csn = (upaddr->upla>>6) - sn - 1; 382266Sbill if (csn < 0) 3832395Swnj csn += st->nsect; 38412837Ssam if (csn > st->nsect - st->rdist) 385264Sbill goto done; 386264Sbill search: 3872674Swnj upaddr->updc = bp->b_cylin; 3882674Swnj /* 3892674Swnj * Not on cylinder at correct position, 3902674Swnj * seek/search. 3912674Swnj */ 392275Sbill if (upseek) 3932629Swnj upaddr->upcs1 = UP_IE|UP_SEEK|UP_GO; 3942470Swnj else { 395275Sbill upaddr->upda = sn; 3962629Swnj upaddr->upcs1 = UP_IE|UP_SEARCH|UP_GO; 397275Sbill } 398268Sbill didie = 1; 3992674Swnj /* 4002674Swnj * Mark unit busy for iostat. 4012674Swnj */ 4022395Swnj if (ui->ui_dk >= 0) { 4032395Swnj dk_busy |= 1<<ui->ui_dk; 4042395Swnj dk_seek[ui->ui_dk]++; 405264Sbill } 406268Sbill goto out; 407264Sbill done: 4082674Swnj /* 4092674Swnj * Device is ready to go. 4102674Swnj * Put it on the ready queue for the controller 4112674Swnj * (unless its already there.) 4122674Swnj */ 4132629Swnj if (dp->b_active != 2) { 4142629Swnj dp->b_forw = NULL; 4152629Swnj if (um->um_tab.b_actf == NULL) 4162629Swnj um->um_tab.b_actf = dp; 4172629Swnj else 4182629Swnj um->um_tab.b_actl->b_forw = dp; 4192629Swnj um->um_tab.b_actl = dp; 4202629Swnj dp->b_active = 2; 4212629Swnj } 422268Sbill out: 423268Sbill return (didie); 424264Sbill } 425264Sbill 4262674Swnj /* 4272674Swnj * Start up a transfer on a drive. 4282674Swnj */ 4292395Swnj upstart(um) 4302983Swnj register struct uba_ctlr *um; 431264Sbill { 432264Sbill register struct buf *bp, *dp; 4332983Swnj register struct uba_device *ui; 4342629Swnj register struct updevice *upaddr; 4352470Swnj struct upst *st; 436264Sbill daddr_t bn; 4372681Swnj int dn, sn, tn, cmd, waitdry; 438264Sbill 439264Sbill loop: 4402674Swnj /* 4412674Swnj * Pull a request off the controller queue 4422674Swnj */ 4432395Swnj if ((dp = um->um_tab.b_actf) == NULL) 444268Sbill return (0); 445264Sbill if ((bp = dp->b_actf) == NULL) { 4462395Swnj um->um_tab.b_actf = dp->b_forw; 447264Sbill goto loop; 448264Sbill } 4492674Swnj /* 4502674Swnj * Mark controller busy, and 4512674Swnj * determine destination of this request. 4522674Swnj */ 4532395Swnj um->um_tab.b_active++; 4542395Swnj ui = updinfo[dkunit(bp)]; 455264Sbill bn = dkblock(bp); 4562395Swnj dn = ui->ui_slave; 4572395Swnj st = &upst[ui->ui_type]; 4582395Swnj sn = bn%st->nspc; 4592395Swnj tn = sn/st->nsect; 4602395Swnj sn %= st->nsect; 4612629Swnj upaddr = (struct updevice *)ui->ui_addr; 4622674Swnj /* 4632674Swnj * Select drive if not selected already. 4642674Swnj */ 4652674Swnj if ((upaddr->upcs2&07) != dn) 4662674Swnj upaddr->upcs2 = dn; 4672674Swnj /* 4682674Swnj * Check that it is ready and online 4692674Swnj */ 4702681Swnj waitdry = 0; 4713445Sroot while ((upaddr->upds&UPDS_DRY) == 0) { 4727036Swnj printf("up%d: ds wait ds=%o\n",dkunit(bp),upaddr->upds); 4732681Swnj if (++waitdry > 512) 4742681Swnj break; 4752681Swnj upwaitdry++; 4762681Swnj } 4773445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 4782931Swnj printf("up%d: not ready", dkunit(bp)); 4793445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 4802607Swnj printf("\n"); 4812395Swnj um->um_tab.b_active = 0; 4822395Swnj um->um_tab.b_errcnt = 0; 483893Sbill dp->b_actf = bp->av_forw; 484893Sbill dp->b_active = 0; 485893Sbill bp->b_flags |= B_ERROR; 486893Sbill iodone(bp); 487893Sbill goto loop; 488893Sbill } 4892674Swnj /* 4902674Swnj * Oh, well, sometimes this 4912674Swnj * happens, for reasons unknown. 4922674Swnj */ 4932629Swnj printf(" (flakey)\n"); 494264Sbill } 4952674Swnj /* 4962674Swnj * Setup for the transfer, and get in the 4972674Swnj * UNIBUS adaptor queue. 4982674Swnj */ 4992424Skre upaddr->updc = bp->b_cylin; 500264Sbill upaddr->upda = (tn << 8) + sn; 501264Sbill upaddr->upwc = -bp->b_bcount / sizeof (short); 502264Sbill if (bp->b_flags & B_READ) 5032629Swnj cmd = UP_IE|UP_RCOM|UP_GO; 504264Sbill else 5052629Swnj cmd = UP_IE|UP_WCOM|UP_GO; 5062571Swnj um->um_cmd = cmd; 5073107Swnj (void) ubago(ui); 508268Sbill return (1); 509264Sbill } 510264Sbill 5112674Swnj /* 5122674Swnj * Now all ready to go, stuff the registers. 5132674Swnj */ 5142571Swnj updgo(um) 5152983Swnj struct uba_ctlr *um; 5162395Swnj { 5172629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 5182470Swnj 5196953Swnj um->um_tab.b_active = 2; /* should now be 2 */ 5202571Swnj upaddr->upba = um->um_ubinfo; 5212571Swnj upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300); 5222395Swnj } 5232395Swnj 5242674Swnj /* 5252674Swnj * Handle a disk interrupt. 5262674Swnj */ 5272707Swnj upintr(sc21) 5282395Swnj register sc21; 529264Sbill { 530264Sbill register struct buf *bp, *dp; 5312983Swnj register struct uba_ctlr *um = upminfo[sc21]; 5322983Swnj register struct uba_device *ui; 5332629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 534264Sbill register unit; 5352470Swnj struct up_softc *sc = &up_softc[um->um_ctlr]; 5362607Swnj int as = (upaddr->upas & 0377) | sc->sc_softas; 5372681Swnj int needie = 1, waitdry; 538264Sbill 5392470Swnj sc->sc_wticks = 0; 5402607Swnj sc->sc_softas = 0; 5412674Swnj /* 5422674Swnj * If controller wasn't transferring, then this is an 5432674Swnj * interrupt for attention status on seeking drives. 5442674Swnj * Just service them. 5452674Swnj */ 5466346Swnj if (um->um_tab.b_active != 2 && !sc->sc_recal) { 5472674Swnj if (upaddr->upcs1 & UP_TRE) 5482674Swnj upaddr->upcs1 = UP_TRE; 5492674Swnj goto doattn; 5502674Swnj } 5516953Swnj um->um_tab.b_active = 1; 5522674Swnj /* 5532674Swnj * Get device and block structures, and a pointer 5542983Swnj * to the uba_device for the drive. Select the drive. 5552674Swnj */ 5562674Swnj dp = um->um_tab.b_actf; 5572674Swnj bp = dp->b_actf; 5582674Swnj ui = updinfo[dkunit(bp)]; 5592674Swnj dk_busy &= ~(1 << ui->ui_dk); 5602674Swnj if ((upaddr->upcs2&07) != ui->ui_slave) 5612395Swnj upaddr->upcs2 = ui->ui_slave; 5629548Ssam if (bp->b_flags&B_BAD) { 5639548Ssam if (upecc(ui, CONT)) 5649548Ssam return; 5659548Ssam } 5662674Swnj /* 5672674Swnj * Check for and process errors on 5682674Swnj * either the drive or the controller. 5692674Swnj */ 5703445Sroot if ((upaddr->upds&UPDS_ERR) || (upaddr->upcs1&UP_TRE)) { 5712681Swnj waitdry = 0; 5723445Sroot while ((upaddr->upds & UPDS_DRY) == 0) { 5732681Swnj if (++waitdry > 512) 5742681Swnj break; 5752681Swnj upwaitdry++; 5762681Swnj } 5773445Sroot if (upaddr->uper1&UPER1_WLE) { 5782674Swnj /* 5792674Swnj * Give up on write locked devices 5802674Swnj * immediately. 5812674Swnj */ 5822931Swnj printf("up%d: write locked\n", dkunit(bp)); 5832674Swnj bp->b_flags |= B_ERROR; 5842674Swnj } else if (++um->um_tab.b_errcnt > 27) { 5852674Swnj /* 5862674Swnj * After 28 retries (16 without offset, and 5872674Swnj * 12 with offset positioning) give up. 58810904Shelge * If the error was header CRC, the header is 58910904Shelge * screwed up, and the sector may in fact exist 59010904Shelge * in the bad sector table, better check... 5912674Swnj */ 59210904Shelge if (upaddr->uper1&UPER1_HCRC) { 59310904Shelge if (upecc(ui, BSE)) 59410904Shelge return; 59510904Shelge } 5969548Ssam hard: 5972931Swnj harderr(bp, "up"); 5989548Ssam printf("cn=%d tn=%d sn=%d cs2=%b er1=%b er2=%b\n", 5999548Ssam upaddr->updc, ((upaddr->upda)>>8)&077, 6009548Ssam (upaddr->upda)&037, 6019548Ssam upaddr->upcs2, UPCS2_BITS, 6029548Ssam upaddr->uper1, UPER1_BITS, 6039548Ssam upaddr->uper2, UPER2_BITS); 6042674Swnj bp->b_flags |= B_ERROR; 6059548Ssam } else if (upaddr->uper2 & UPER2_BSE) { 6069548Ssam if (upecc(ui, BSE)) 6079548Ssam return; 6089548Ssam else 6099548Ssam goto hard; 6102674Swnj } else { 6112674Swnj /* 6122674Swnj * Retriable error. 6132674Swnj * If a soft ecc, correct it (continuing 6142674Swnj * by returning if necessary. 6152674Swnj * Otherwise fall through and retry the transfer 6162674Swnj */ 6177183Sroot if ((upaddr->uper1&(UPER1_DCK|UPER1_ECH))==UPER1_DCK) { 6189548Ssam if (upecc(ui, ECC)) 6192629Swnj return; 6207183Sroot } else 6217183Sroot um->um_tab.b_active = 0; /* force retry */ 6222674Swnj } 6232674Swnj /* 6242674Swnj * Clear drive error and, every eight attempts, 6252674Swnj * (starting with the fourth) 6262674Swnj * recalibrate to clear the slate. 6272674Swnj */ 6282674Swnj upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 6292674Swnj needie = 0; 6303182Swnj if ((um->um_tab.b_errcnt&07) == 4 && um->um_tab.b_active == 0) { 6312674Swnj upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO; 6323160Swnj sc->sc_recal = 0; 6333160Swnj goto nextrecal; 6342674Swnj } 6352674Swnj } 6362674Swnj /* 6373160Swnj * Advance recalibration finite state machine 6383160Swnj * if recalibrate in progress, through 6393160Swnj * RECAL 6403160Swnj * SEEK 6413160Swnj * OFFSET (optional) 6423160Swnj * RETRY 6432674Swnj */ 6443160Swnj switch (sc->sc_recal) { 6453160Swnj 6463160Swnj case 1: 6473160Swnj upaddr->updc = bp->b_cylin; 6483160Swnj upaddr->upcs1 = UP_SEEK|UP_IE|UP_GO; 6493160Swnj goto nextrecal; 6503160Swnj case 2: 6513160Swnj if (um->um_tab.b_errcnt < 16 || (bp->b_flags&B_READ) == 0) 6523160Swnj goto donerecal; 6533445Sroot upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | UPOF_FMT22; 6543160Swnj upaddr->upcs1 = UP_IE|UP_OFFSET|UP_GO; 6553160Swnj goto nextrecal; 6563160Swnj nextrecal: 6573160Swnj sc->sc_recal++; 6583160Swnj um->um_tab.b_active = 1; 6593160Swnj return; 6603160Swnj donerecal: 6613160Swnj case 3: 6622674Swnj sc->sc_recal = 0; 6633160Swnj um->um_tab.b_active = 0; 6643160Swnj break; 6652674Swnj } 6662674Swnj /* 6672674Swnj * If still ``active'', then don't need any more retries. 6682674Swnj */ 6692674Swnj if (um->um_tab.b_active) { 6702674Swnj /* 6712674Swnj * If we were offset positioning, 6722674Swnj * return to centerline. 6732674Swnj */ 6742674Swnj if (um->um_tab.b_errcnt >= 16) { 6753445Sroot upaddr->upof = UPOF_FMT22; 6762674Swnj upaddr->upcs1 = UP_RTC|UP_GO|UP_IE; 6773445Sroot while (upaddr->upds & UPDS_PIP) 6782674Swnj DELAY(25); 679268Sbill needie = 0; 680264Sbill } 6812674Swnj um->um_tab.b_active = 0; 6822674Swnj um->um_tab.b_errcnt = 0; 6832674Swnj um->um_tab.b_actf = dp->b_forw; 6842674Swnj dp->b_active = 0; 6852674Swnj dp->b_errcnt = 0; 6862674Swnj dp->b_actf = bp->av_forw; 6872674Swnj bp->b_resid = (-upaddr->upwc * sizeof(short)); 6882674Swnj iodone(bp); 6892674Swnj /* 6902674Swnj * If this unit has more work to do, 6912674Swnj * then start it up right away. 6922674Swnj */ 6932674Swnj if (dp->b_actf) 6942674Swnj if (upustart(ui)) 695268Sbill needie = 0; 696264Sbill } 6972674Swnj as &= ~(1<<ui->ui_slave); 6983403Swnj /* 6993403Swnj * Release unibus resources and flush data paths. 7003403Swnj */ 7013403Swnj ubadone(um); 7022674Swnj doattn: 7032674Swnj /* 7042674Swnj * Process other units which need attention. 7052674Swnj * For each unit which needs attention, call 7062674Swnj * the unit start routine to place the slave 7072674Swnj * on the controller device queue. 7082674Swnj */ 7093160Swnj while (unit = ffs(as)) { 7103160Swnj unit--; /* was 1 origin */ 7113160Swnj as &= ~(1<<unit); 7123160Swnj upaddr->upas = 1<<unit; 7136383Swnj if (unit < UPIPUNITS && upustart(upip[sc21][unit])) 7143160Swnj needie = 0; 7153160Swnj } 7162674Swnj /* 7172674Swnj * If the controller is not transferring, but 7182674Swnj * there are devices ready to transfer, start 7192674Swnj * the controller. 7202674Swnj */ 7212395Swnj if (um->um_tab.b_actf && um->um_tab.b_active == 0) 7222395Swnj if (upstart(um)) 723268Sbill needie = 0; 724275Sbill if (needie) 7252629Swnj upaddr->upcs1 = UP_IE; 726264Sbill } 727264Sbill 7289357Ssam upread(dev, uio) 7292616Swnj dev_t dev; 7309357Ssam struct uio *uio; 731264Sbill { 7322616Swnj register int unit = minor(dev) >> 3; 7332470Swnj 7342616Swnj if (unit >= NUP) 7359357Ssam return (ENXIO); 7369357Ssam return (physio(upstrategy, &rupbuf[unit], dev, B_READ, minphys, uio)); 737264Sbill } 738264Sbill 7399357Ssam upwrite(dev, uio) 7402616Swnj dev_t dev; 7419357Ssam struct uio *uio; 742264Sbill { 7432616Swnj register int unit = minor(dev) >> 3; 7442470Swnj 7452616Swnj if (unit >= NUP) 7469357Ssam return (ENXIO); 7479357Ssam return (physio(upstrategy, &rupbuf[unit], dev, B_WRITE, minphys, uio)); 748264Sbill } 749264Sbill 750266Sbill /* 751266Sbill * Correct an ECC error, and restart the i/o to complete 752266Sbill * the transfer if necessary. This is quite complicated because 753266Sbill * the transfer may be going to an odd memory address base and/or 754266Sbill * across a page boundary. 755266Sbill */ 7569548Ssam upecc(ui, flag) 7572983Swnj register struct uba_device *ui; 7589548Ssam int flag; 759264Sbill { 7602629Swnj register struct updevice *up = (struct updevice *)ui->ui_addr; 7612395Swnj register struct buf *bp = uputab[ui->ui_unit].b_actf; 7622983Swnj register struct uba_ctlr *um = ui->ui_mi; 7632395Swnj register struct upst *st; 7642395Swnj struct uba_regs *ubp = ui->ui_hd->uh_uba; 765266Sbill register int i; 766264Sbill caddr_t addr; 767266Sbill int reg, bit, byte, npf, mask, o, cmd, ubaddr; 768264Sbill int bn, cn, tn, sn; 769264Sbill 770264Sbill /* 771266Sbill * Npf is the number of sectors transferred before the sector 772266Sbill * containing the ECC error, and reg is the UBA register 773266Sbill * mapping (the first part of) the transfer. 774266Sbill * O is offset within a memory page of the first byte transferred. 775264Sbill */ 7769548Ssam if (flag == CONT) 7779548Ssam npf = bp->b_error; 7789548Ssam else 77910858Ssam npf = btop((up->upwc * sizeof(short)) + bp->b_bcount); 7802571Swnj reg = btop(um->um_ubinfo&0x3ffff) + npf; 781264Sbill o = (int)bp->b_un.b_addr & PGOFSET; 782264Sbill mask = up->upec2; 7833445Sroot #ifdef UPECCDEBUG 7843403Swnj printf("npf %d reg %x o %d mask %o pos %d\n", npf, reg, o, mask, 7853403Swnj up->upec1); 7863445Sroot #endif 7879548Ssam bn = dkblock(bp); 7889548Ssam st = &upst[ui->ui_type]; 7899548Ssam cn = bp->b_cylin; 7909548Ssam sn = bn%st->nspc + npf; 7919548Ssam tn = sn/st->nsect; 7929548Ssam sn %= st->nsect; 7939548Ssam cn += tn/st->ntrak; 7949548Ssam tn %= st->ntrak; 7952725Swnj ubapurge(um); 7969548Ssam um->um_tab.b_active=2; 797266Sbill /* 7989548Ssam * action taken depends on the flag 799266Sbill */ 8009548Ssam switch(flag){ 8019548Ssam case ECC: 8029548Ssam npf--; 8039548Ssam reg--; 8049548Ssam mask = up->upec2; 80518317Sralph log(KERN_RECOV, "up%d%c: soft ecc sn%d\n", dkunit(bp), 8069548Ssam 'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf); 8079548Ssam /* 8089548Ssam * Flush the buffered data path, and compute the 8099548Ssam * byte and bit position of the error. The variable i 8109548Ssam * is the byte offset in the transfer, the variable byte 8119548Ssam * is the offset from a page boundary in main memory. 8129548Ssam */ 8139548Ssam i = up->upec1 - 1; /* -1 makes 0 origin */ 8149548Ssam bit = i&07; 8159548Ssam i = (i&~07)>>3; 8169548Ssam byte = i + o; 8179548Ssam /* 8189548Ssam * Correct while possible bits remain of mask. Since mask 8199548Ssam * contains 11 bits, we continue while the bit offset is > -11. 8209548Ssam * Also watch out for end of this block and the end of the whole 8219548Ssam * transfer. 8229548Ssam */ 8239548Ssam while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 82413879Ssam struct pte pte; 82513879Ssam 82613879Ssam pte = ubp->uba_map[reg + btop(byte)]; 82713879Ssam addr = ptob(pte.pg_pfnum) + (byte & PGOFSET); 8283445Sroot #ifdef UPECCDEBUG 8299548Ssam printf("addr %x map reg %x\n", 8309548Ssam addr, *(int *)(&ubp->uba_map[reg+btop(byte)])); 8319548Ssam printf("old: %x, ", getmemc(addr)); 8323445Sroot #endif 8339548Ssam putmemc(addr, getmemc(addr)^(mask<<bit)); 8343445Sroot #ifdef UPECCDEBUG 8359548Ssam printf("new: %x\n", getmemc(addr)); 8363445Sroot #endif 8379548Ssam byte++; 8389548Ssam i++; 8399580Shelge bit -= 8; 8409548Ssam } 8419548Ssam if (up->upwc == 0) 8429548Ssam return (0); 8439548Ssam npf++; 8449548Ssam reg++; 8459548Ssam break; 8469548Ssam case BSE: 8479548Ssam /* 8489548Ssam * if not in bad sector table, return 0 8499548Ssam */ 8509548Ssam if ((bn = isbad(&upbad[ui->ui_unit], cn, tn, sn)) < 0) 8519548Ssam return(0); 8529548Ssam /* 8539548Ssam * flag this one as bad 8549548Ssam */ 8559548Ssam bp->b_flags |= B_BAD; 8569548Ssam bp->b_error = npf + 1; 8579548Ssam #ifdef UPECCDEBUG 8589548Ssam printf("BSE: restart at %d\n",npf+1); 8599548Ssam #endif 8609548Ssam bn = st->ncyl * st->nspc -st->nsect - 1 - bn; 8619548Ssam cn = bn / st->nspc; 8629548Ssam sn = bn % st->nspc; 8639548Ssam tn = sn / st->nsect; 8649548Ssam sn %= st->nsect; 8659548Ssam up->upwc = -(512 / sizeof (short)); 8669548Ssam #ifdef UPECCDEBUG 8679548Ssam printf("revector to cn %d tn %d sn %d\n", cn, tn, sn); 8689548Ssam #endif 8699548Ssam break; 8709548Ssam case CONT: 8719548Ssam #ifdef UPECCDEBUG 8729548Ssam printf("upecc, CONT: bn %d cn %d tn %d sn %d\n", bn, cn, tn, sn); 8739548Ssam #endif 8749548Ssam bp->b_flags &= ~B_BAD; 8759548Ssam up->upwc = -((bp->b_bcount - (int)ptob(npf)) / sizeof(short)); 8769548Ssam if (up->upwc == 0) 8779548Ssam return(0); 8789548Ssam break; 879264Sbill } 8807183Sroot if (up->upwc == 0) { 8817183Sroot um->um_tab.b_active = 0; 882264Sbill return (0); 8837183Sroot } 884266Sbill /* 885266Sbill * Have to continue the transfer... clear the drive, 886266Sbill * and compute the position where the transfer is to continue. 887266Sbill * We have completed npf+1 sectors of the transfer already; 888266Sbill * restart at offset o of next sector (i.e. in UBA register reg+1). 889266Sbill */ 8902629Swnj #ifdef notdef 8912629Swnj up->uper1 = 0; 8922629Swnj up->upcs1 |= UP_GO; 8932629Swnj #else 8942629Swnj up->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 895264Sbill up->updc = cn; 896266Sbill up->upda = (tn << 8) | sn; 8979548Ssam ubaddr = (int)ptob(reg) + o; 898266Sbill up->upba = ubaddr; 899266Sbill cmd = (ubaddr >> 8) & 0x300; 9009548Ssam cmd |= ((bp->b_flags&B_READ)?UP_RCOM:UP_WCOM)|UP_IE|UP_GO; 9019548Ssam um->um_tab.b_errcnt = 0; 902266Sbill up->upcs1 = cmd; 9032629Swnj #endif 904264Sbill return (1); 905264Sbill } 906286Sbill 907286Sbill /* 908286Sbill * Reset driver after UBA init. 909286Sbill * Cancel software state of all pending transfers 910286Sbill * and restart all units and the controller. 911286Sbill */ 9122395Swnj upreset(uban) 9132931Swnj int uban; 914286Sbill { 9152983Swnj register struct uba_ctlr *um; 9162983Swnj register struct uba_device *ui; 9172395Swnj register sc21, unit; 918286Sbill 9192646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 9202470Swnj if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban || 9212470Swnj um->um_alive == 0) 9222395Swnj continue; 9232931Swnj printf(" sc%d", sc21); 9242395Swnj um->um_tab.b_active = 0; 9252395Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 9262931Swnj up_softc[sc21].sc_recal = 0; 9276346Swnj up_softc[sc21].sc_wticks = 0; 9282571Swnj if (um->um_ubinfo) { 9292571Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 9309357Ssam um->um_ubinfo = 0; 9312395Swnj } 9323445Sroot ((struct updevice *)(um->um_addr))->upcs2 = UPCS2_CLR; 9332395Swnj for (unit = 0; unit < NUP; unit++) { 9342395Swnj if ((ui = updinfo[unit]) == 0) 9352395Swnj continue; 9362931Swnj if (ui->ui_alive == 0 || ui->ui_mi != um) 9372395Swnj continue; 9382395Swnj uputab[unit].b_active = 0; 9392395Swnj (void) upustart(ui); 9402395Swnj } 9412395Swnj (void) upstart(um); 942286Sbill } 943286Sbill } 944313Sbill 945313Sbill /* 946313Sbill * Wake up every second and if an interrupt is pending 947313Sbill * but nothing has happened increment a counter. 9482931Swnj * If nothing happens for 20 seconds, reset the UNIBUS 949313Sbill * and begin anew. 950313Sbill */ 951313Sbill upwatch() 952313Sbill { 9532983Swnj register struct uba_ctlr *um; 9542395Swnj register sc21, unit; 9552470Swnj register struct up_softc *sc; 956313Sbill 9572759Swnj timeout(upwatch, (caddr_t)0, hz); 9582646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 9592395Swnj um = upminfo[sc21]; 9602470Swnj if (um == 0 || um->um_alive == 0) 9612470Swnj continue; 9622470Swnj sc = &up_softc[sc21]; 9632395Swnj if (um->um_tab.b_active == 0) { 9642395Swnj for (unit = 0; unit < NUP; unit++) 9652629Swnj if (uputab[unit].b_active && 9662629Swnj updinfo[unit]->ui_mi == um) 9672395Swnj goto active; 9682470Swnj sc->sc_wticks = 0; 9692395Swnj continue; 9702395Swnj } 9712931Swnj active: 9722470Swnj sc->sc_wticks++; 9732470Swnj if (sc->sc_wticks >= 20) { 9742470Swnj sc->sc_wticks = 0; 9752931Swnj printf("sc%d: lost interrupt\n", sc21); 9762646Swnj ubareset(um->um_ubanum); 9772395Swnj } 978313Sbill } 979313Sbill } 9802379Swnj 9812379Swnj #define DBSIZE 20 9822379Swnj 9832379Swnj updump(dev) 9842379Swnj dev_t dev; 9852379Swnj { 9862629Swnj struct updevice *upaddr; 9872379Swnj char *start; 9883107Swnj int num, blk, unit; 9892379Swnj struct size *sizes; 9902395Swnj register struct uba_regs *uba; 9912983Swnj register struct uba_device *ui; 9922379Swnj register short *rp; 9932395Swnj struct upst *st; 9946848Ssam register int retry; 9952379Swnj 9962395Swnj unit = minor(dev) >> 3; 9972889Swnj if (unit >= NUP) 9982889Swnj return (ENXIO); 9992470Swnj #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) 10002983Swnj ui = phys(struct uba_device *, updinfo[unit]); 10012889Swnj if (ui->ui_alive == 0) 10022889Swnj return (ENXIO); 10032395Swnj uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 10042983Swnj ubainit(uba); 10052629Swnj upaddr = (struct updevice *)ui->ui_physaddr; 10066848Ssam DELAY(5000000); 10072379Swnj num = maxfree; 10082379Swnj upaddr->upcs2 = unit; 10092983Swnj DELAY(100); 10106848Ssam upaddr->upcs1 = UP_DCLR|UP_GO; 10116848Ssam upaddr->upcs1 = UP_PRESET|UP_GO; 10126848Ssam upaddr->upof = UPOF_FMT22; 10136848Ssam retry = 0; 10146848Ssam do { 10156848Ssam DELAY(25); 10166848Ssam if (++retry > 527) 10176848Ssam break; 10186861Ssam } while ((upaddr->upds & UP_RDY) == 0); 10193445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) 10202889Swnj return (EFAULT); 10219357Ssam start = 0; 10228489Sroot st = &upst[ui->ui_type]; 10232395Swnj sizes = phys(struct size *, st->sizes); 10242889Swnj if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) 10252889Swnj return (EINVAL); 10262379Swnj while (num > 0) { 10272379Swnj register struct pte *io; 10282379Swnj register int i; 10292379Swnj int cn, sn, tn; 10302379Swnj daddr_t bn; 10312379Swnj 10322379Swnj blk = num > DBSIZE ? DBSIZE : num; 10332395Swnj io = uba->uba_map; 10342379Swnj for (i = 0; i < blk; i++) 10352983Swnj *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV; 10362379Swnj *(int *)io = 0; 10372379Swnj bn = dumplo + btop(start); 10382607Swnj cn = bn/st->nspc + sizes[minor(dev)&07].cyloff; 10392607Swnj sn = bn%st->nspc; 10402607Swnj tn = sn/st->nsect; 10412607Swnj sn = sn%st->nsect; 10422379Swnj upaddr->updc = cn; 10432379Swnj rp = (short *) &upaddr->upda; 10442379Swnj *rp = (tn << 8) + sn; 10452379Swnj *--rp = 0; 10462379Swnj *--rp = -blk*NBPG / sizeof (short); 10472629Swnj *--rp = UP_GO|UP_WCOM; 10486848Ssam retry = 0; 10492379Swnj do { 10502379Swnj DELAY(25); 10516848Ssam if (++retry > 527) 10526848Ssam break; 10532629Swnj } while ((upaddr->upcs1 & UP_RDY) == 0); 10546848Ssam if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 10556861Ssam printf("up%d: not ready", unit); 10566848Ssam if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 10576848Ssam printf("\n"); 10586848Ssam return (EIO); 10596848Ssam } 10606848Ssam printf(" (flakey)\n"); 10616848Ssam } 10623445Sroot if (upaddr->upds&UPDS_ERR) 10632889Swnj return (EIO); 10642379Swnj start += blk*NBPG; 10652379Swnj num -= blk; 10662379Swnj } 10672379Swnj return (0); 10682379Swnj } 106912505Ssam 107012505Ssam upsize(dev) 107112505Ssam dev_t dev; 107212505Ssam { 107312505Ssam int unit = minor(dev) >> 3; 107412505Ssam struct uba_device *ui; 107512505Ssam struct upst *st; 107612505Ssam 107712505Ssam if (unit >= NUP || (ui = updinfo[unit]) == 0 || ui->ui_alive == 0) 107812505Ssam return (-1); 107912505Ssam st = &upst[ui->ui_type]; 108012505Ssam return (st->sizes[minor(dev) & 07].nblocks); 108112505Ssam } 10821902Swnj #endif 1083