123355Smckusick /*
229253Smckusick * Copyright (c) 1982, 1986 Regents of the University of California.
323355Smckusick * All rights reserved. The Berkeley software License Agreement
423355Smckusick * specifies the terms and conditions for redistribution.
523355Smckusick *
6*45809Sbostic * @(#)up.c 7.10 (Berkeley) 12/16/90
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 */
20*45809Sbostic #include "../include/pte.h"
21264Sbill
22*45809Sbostic #include "sys/param.h"
23*45809Sbostic #include "sys/systm.h"
24*45809Sbostic #include "sys/dkstat.h"
25*45809Sbostic #include "sys/dkbad.h"
26*45809Sbostic #include "sys/ioctl.h"
27*45809Sbostic #include "sys/disklabel.h"
28*45809Sbostic #include "sys/buf.h"
29*45809Sbostic #include "sys/conf.h"
30*45809Sbostic #include "sys/user.h"
31*45809Sbostic #include "sys/map.h"
32*45809Sbostic #include "sys/vm.h"
33*45809Sbostic #include "sys/cmap.h"
34*45809Sbostic #include "sys/uio.h"
35*45809Sbostic #include "sys/kernel.h"
36*45809Sbostic #include "sys/syslog.h"
37264Sbill
38*45809Sbostic #include "../include/cpu.h"
399357Ssam #include "../vax/nexus.h"
4017082Sbloom #include "ubavar.h"
4117082Sbloom #include "ubareg.h"
4217082Sbloom #include "upreg.h"
439357Ssam
442395Swnj struct up_softc {
452395Swnj int sc_softas;
462607Swnj int sc_ndrive;
472395Swnj int sc_wticks;
482674Swnj int sc_recal;
492646Swnj } up_softc[NSC];
50275Sbill
5124743Sbloom #define upunit(dev) (minor(dev) >> 3)
5224743Sbloom
532395Swnj /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */
5410858Ssam struct size {
55264Sbill daddr_t nblocks;
56264Sbill int cyloff;
5711211Ssam } up9300_sizes[8] = {
58264Sbill 15884, 0, /* A=cyl 0 thru 26 */
59264Sbill 33440, 27, /* B=cyl 27 thru 81 */
60341Sbill 495520, 0, /* C=cyl 0 thru 814 */
61264Sbill 15884, 562, /* D=cyl 562 thru 588 */
62264Sbill 55936, 589, /* E=cyl 589 thru 680 */
633730Sroot 81376, 681, /* F=cyl 681 thru 814 */
643730Sroot 153728, 562, /* G=cyl 562 thru 814 */
65264Sbill 291346, 82, /* H=cyl 82 thru 561 */
6611211Ssam }, up9766_sizes[8] = {
6711211Ssam 15884, 0, /* A=cyl 0 thru 26 */
6811211Ssam 33440, 27, /* B=cyl 27 thru 81 */
6911211Ssam 500384, 0, /* C=cyl 0 thru 822 */
7011211Ssam 15884, 562, /* D=cyl 562 thru 588 */
7111211Ssam 55936, 589, /* E=cyl 589 thru 680 */
7211211Ssam 86240, 681, /* F=cyl 681 thru 822 */
7311211Ssam 158592, 562, /* G=cyl 562 thru 822 */
7411211Ssam 291346, 82, /* H=cyl 82 thru 561 */
7511211Ssam }, up160_sizes[8] = {
762395Swnj 15884, 0, /* A=cyl 0 thru 49 */
772395Swnj 33440, 50, /* B=cyl 50 thru 154 */
782395Swnj 263360, 0, /* C=cyl 0 thru 822 */
7911211Ssam 15884, 155, /* D=cyl 155 thru 204 */
8011211Ssam 55936, 205, /* E=cyl 205 thru 379 */
8111211Ssam 141664, 380, /* F=cyl 380 thru 822 */
8211211Ssam 213664, 155, /* G=cyl 155 thru 822 */
832395Swnj 0, 0,
846851Ssam }, upam_sizes[8] = {
856305Sroot 15884, 0, /* A=cyl 0 thru 31 */
866305Sroot 33440, 32, /* B=cyl 32 thru 97 */
876305Sroot 524288, 0, /* C=cyl 0 thru 1023 */
8811211Ssam 15884, 668, /* D=cyl 668 thru 699 */
8911211Ssam 55936, 700, /* E=cyl 700 thru 809 */
9011211Ssam 109472, 810, /* F=cyl 810 thru 1023 */
9111211Ssam 182176, 668, /* G=cyl 668 thru 1023 */
926305Sroot 291346, 98, /* H=cyl 98 thru 667 */
9314002Ssam }, up980_sizes[8] = {
9414002Ssam 15884, 0, /* A=cyl 0 thru 99 */
9514002Ssam 33440, 100, /* B=cyl 100 thru 308 */
9614002Ssam 131680, 0, /* C=cyl 0 thru 822 */
9714002Ssam 15884, 309, /* D=cyl 309 thru 408 */
9814002Ssam 55936, 409, /* E=cyl 409 thru 758 */
9914002Ssam 10080, 759, /* F=cyl 759 thru 822 */
10014002Ssam 82080, 309, /* G=cyl 309 thru 822 */
10114002Ssam 0, 0,
10221977Sbloom }, upeagle_sizes[8] = {
10321977Sbloom 15884, 0, /* A=cyl 0 thru 16 */
10421977Sbloom 66880, 17, /* B=cyl 17 thru 86 */
10521977Sbloom 808320, 0, /* C=cyl 0 thru 841 */
10621977Sbloom 15884, 391, /* D=cyl 391 thru 407 */
10721977Sbloom 307200, 408, /* E=cyl 408 thru 727 */
10821977Sbloom 109296, 728, /* F=cyl 728 thru 841 */
10921977Sbloom 432816, 391, /* G=cyl 391 thru 841 */
11021977Sbloom 291346, 87, /* H=cyl 87 thru 390 */
111264Sbill };
1122395Swnj /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */
113264Sbill
1142607Swnj int upprobe(), upslave(), upattach(), updgo(), upintr();
1152983Swnj struct uba_ctlr *upminfo[NSC];
1162983Swnj struct uba_device *updinfo[NUP];
1176383Swnj #define UPIPUNITS 8
1186383Swnj struct uba_device *upip[NSC][UPIPUNITS]; /* fuji w/fixed head gives n,n+4 */
1192395Swnj
1202607Swnj u_short upstd[] = { 0776700, 0774400, 0776300, 0 };
1212616Swnj struct uba_driver scdriver =
1222607Swnj { upprobe, upslave, upattach, updgo, upstd, "up", updinfo, "sc", upminfo };
1232395Swnj struct buf uputab[NUP];
1249548Ssam char upinit[NUP];
1252395Swnj
1262395Swnj struct upst {
12712837Ssam short nsect; /* # sectors/track */
12812837Ssam short ntrak; /* # tracks/cylinder */
12912837Ssam short nspc; /* # sectors/cylinder */
13012837Ssam short ncyl; /* # cylinders */
13112837Ssam struct size *sizes; /* partition tables */
13212837Ssam short sdist; /* seek distance metric */
13312837Ssam short rdist; /* rotational distance metric */
1342395Swnj } upst[] = {
13512837Ssam { 32, 19, 32*19, 815, up9300_sizes, 3, 4 }, /* 9300 */
13612837Ssam { 32, 19, 32*19, 823, up9766_sizes, 3, 4 }, /* 9766 */
13712837Ssam { 32, 10, 32*10, 823, up160_sizes, 3, 4 }, /* fuji 160m */
13812837Ssam { 32, 16, 32*16, 1024, upam_sizes, 7, 8 }, /* Capricorn */
13914002Ssam { 32, 5, 32*5, 823, up980_sizes, 3, 4 }, /* DM980 */
14021977Sbloom { 48, 20, 48*20, 842, upeagle_sizes, 15, 8 }, /* EAGLE */
14112837Ssam { 0, 0, 0, 0, 0, 0, 0 }
1422395Swnj };
1432395Swnj
1442629Swnj u_char up_offset[16] = {
1459548Ssam UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400,
1469548Ssam UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800,
1479548Ssam UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200,
1489548Ssam 0, 0, 0, 0
1492629Swnj };
150264Sbill
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*/
upprobe(reg)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
upattach(ui)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)
20038177Smckusick dk_wpms[ui->ui_dk] = 491521;
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
upmaptype(ui)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)
22234850Skre printf(": uphr=%x", 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
upopen(dev)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
upstrategy(bp)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) {
26824788Skarels if (bp->b_blkno == st->sizes[xunit].nblocks) {
26924788Skarels bp->b_resid = bp->b_bcount;
27024743Sbloom goto done;
27124788Skarels }
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 */
upustart(ui)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 */
upstart(um)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 */
upintr(sc21)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:
61234525Skarels diskerr(bp, "up", "hard error", LOG_PRINTF, -1,
61334525Skarels (struct disklabel *)0);
61434525Skarels printf(" cn=%d tn=%d sn=%d cs2=%b er1=%b er2=%b\n",
6159548Ssam upaddr->updc, ((upaddr->upda)>>8)&077,
6169548Ssam (upaddr->upda)&037,
6179548Ssam upaddr->upcs2, UPCS2_BITS,
6189548Ssam upaddr->uper1, UPER1_BITS,
6199548Ssam upaddr->uper2, UPER2_BITS);
6202674Swnj bp->b_flags |= B_ERROR;
6219548Ssam } else if (upaddr->uper2 & UPER2_BSE) {
6229548Ssam if (upecc(ui, BSE))
6239548Ssam return;
6249548Ssam else
6259548Ssam goto hard;
6262674Swnj } else {
6272674Swnj /*
6282674Swnj * Retriable error.
6292674Swnj * If a soft ecc, correct it (continuing
6302674Swnj * by returning if necessary.
6312674Swnj * Otherwise fall through and retry the transfer
6322674Swnj */
6337183Sroot if ((upaddr->uper1&(UPER1_DCK|UPER1_ECH))==UPER1_DCK) {
6349548Ssam if (upecc(ui, ECC))
6352629Swnj return;
6367183Sroot } else
6377183Sroot um->um_tab.b_active = 0; /* force retry */
6382674Swnj }
6392674Swnj /*
6402674Swnj * Clear drive error and, every eight attempts,
6412674Swnj * (starting with the fourth)
6422674Swnj * recalibrate to clear the slate.
6432674Swnj */
6442674Swnj upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO;
6452674Swnj needie = 0;
6463182Swnj if ((um->um_tab.b_errcnt&07) == 4 && um->um_tab.b_active == 0) {
6472674Swnj upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO;
6483160Swnj sc->sc_recal = 0;
6493160Swnj goto nextrecal;
6502674Swnj }
6512674Swnj }
6522674Swnj /*
6533160Swnj * Advance recalibration finite state machine
6543160Swnj * if recalibrate in progress, through
6553160Swnj * RECAL
6563160Swnj * SEEK
6573160Swnj * OFFSET (optional)
6583160Swnj * RETRY
6592674Swnj */
6603160Swnj switch (sc->sc_recal) {
6613160Swnj
6623160Swnj case 1:
6633160Swnj upaddr->updc = bp->b_cylin;
6643160Swnj upaddr->upcs1 = UP_SEEK|UP_IE|UP_GO;
6653160Swnj goto nextrecal;
6663160Swnj case 2:
6673160Swnj if (um->um_tab.b_errcnt < 16 || (bp->b_flags&B_READ) == 0)
6683160Swnj goto donerecal;
6693445Sroot upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | UPOF_FMT22;
6703160Swnj upaddr->upcs1 = UP_IE|UP_OFFSET|UP_GO;
6713160Swnj goto nextrecal;
6723160Swnj nextrecal:
6733160Swnj sc->sc_recal++;
6743160Swnj um->um_tab.b_active = 1;
6753160Swnj return;
6763160Swnj donerecal:
6773160Swnj case 3:
6782674Swnj sc->sc_recal = 0;
6793160Swnj um->um_tab.b_active = 0;
6803160Swnj break;
6812674Swnj }
6822674Swnj /*
6832674Swnj * If still ``active'', then don't need any more retries.
6842674Swnj */
6852674Swnj if (um->um_tab.b_active) {
6862674Swnj /*
6872674Swnj * If we were offset positioning,
6882674Swnj * return to centerline.
6892674Swnj */
6902674Swnj if (um->um_tab.b_errcnt >= 16) {
6913445Sroot upaddr->upof = UPOF_FMT22;
6922674Swnj upaddr->upcs1 = UP_RTC|UP_GO|UP_IE;
6933445Sroot while (upaddr->upds & UPDS_PIP)
6942674Swnj DELAY(25);
695268Sbill needie = 0;
696264Sbill }
6972674Swnj um->um_tab.b_active = 0;
6982674Swnj um->um_tab.b_errcnt = 0;
6992674Swnj um->um_tab.b_actf = dp->b_forw;
7002674Swnj dp->b_active = 0;
7012674Swnj dp->b_errcnt = 0;
7022674Swnj dp->b_actf = bp->av_forw;
7032674Swnj bp->b_resid = (-upaddr->upwc * sizeof(short));
7042674Swnj iodone(bp);
7052674Swnj /*
7062674Swnj * If this unit has more work to do,
7072674Swnj * then start it up right away.
7082674Swnj */
7092674Swnj if (dp->b_actf)
7102674Swnj if (upustart(ui))
711268Sbill needie = 0;
712264Sbill }
7132674Swnj as &= ~(1<<ui->ui_slave);
7143403Swnj /*
7153403Swnj * Release unibus resources and flush data paths.
7163403Swnj */
7173403Swnj ubadone(um);
7182674Swnj doattn:
7192674Swnj /*
7202674Swnj * Process other units which need attention.
7212674Swnj * For each unit which needs attention, call
7222674Swnj * the unit start routine to place the slave
7232674Swnj * on the controller device queue.
7242674Swnj */
72526373Skarels while (unit = ffs((long)as)) {
7263160Swnj unit--; /* was 1 origin */
7273160Swnj as &= ~(1<<unit);
7283160Swnj upaddr->upas = 1<<unit;
7296383Swnj if (unit < UPIPUNITS && upustart(upip[sc21][unit]))
7303160Swnj needie = 0;
7313160Swnj }
7322674Swnj /*
7332674Swnj * If the controller is not transferring, but
7342674Swnj * there are devices ready to transfer, start
7352674Swnj * the controller.
7362674Swnj */
7372395Swnj if (um->um_tab.b_actf && um->um_tab.b_active == 0)
7382395Swnj if (upstart(um))
739268Sbill needie = 0;
740275Sbill if (needie)
7412629Swnj upaddr->upcs1 = UP_IE;
742264Sbill }
743264Sbill
744266Sbill /*
745266Sbill * Correct an ECC error, and restart the i/o to complete
746266Sbill * the transfer if necessary. This is quite complicated because
747266Sbill * the transfer may be going to an odd memory address base and/or
748266Sbill * across a page boundary.
749266Sbill */
upecc(ui,flag)7509548Ssam upecc(ui, flag)
7512983Swnj register struct uba_device *ui;
7529548Ssam int flag;
753264Sbill {
7542629Swnj register struct updevice *up = (struct updevice *)ui->ui_addr;
7552395Swnj register struct buf *bp = uputab[ui->ui_unit].b_actf;
7562983Swnj register struct uba_ctlr *um = ui->ui_mi;
7572395Swnj register struct upst *st;
7582395Swnj struct uba_regs *ubp = ui->ui_hd->uh_uba;
759266Sbill register int i;
760264Sbill caddr_t addr;
761266Sbill int reg, bit, byte, npf, mask, o, cmd, ubaddr;
762264Sbill int bn, cn, tn, sn;
763264Sbill
764264Sbill /*
765266Sbill * Npf is the number of sectors transferred before the sector
766266Sbill * containing the ECC error, and reg is the UBA register
767266Sbill * mapping (the first part of) the transfer.
768266Sbill * O is offset within a memory page of the first byte transferred.
769264Sbill */
7709548Ssam if (flag == CONT)
7719548Ssam npf = bp->b_error;
7729548Ssam else
77327674Skarels npf = btodb(bp->b_bcount + (up->upwc * sizeof(short)) + 511);
77436037Skarels reg = btop(UBAI_ADDR(um->um_ubinfo)) + npf;
775264Sbill o = (int)bp->b_un.b_addr & PGOFSET;
776264Sbill mask = up->upec2;
7773445Sroot #ifdef UPECCDEBUG
7783403Swnj printf("npf %d reg %x o %d mask %o pos %d\n", npf, reg, o, mask,
7793403Swnj up->upec1);
7803445Sroot #endif
78124743Sbloom bn = bp->b_blkno;
7829548Ssam st = &upst[ui->ui_type];
7839548Ssam cn = bp->b_cylin;
7849548Ssam sn = bn%st->nspc + npf;
7859548Ssam tn = sn/st->nsect;
7869548Ssam sn %= st->nsect;
7879548Ssam cn += tn/st->ntrak;
7889548Ssam tn %= st->ntrak;
7892725Swnj ubapurge(um);
7909548Ssam um->um_tab.b_active=2;
791266Sbill /*
7929548Ssam * action taken depends on the flag
793266Sbill */
7949548Ssam switch(flag){
7959548Ssam case ECC:
7969548Ssam npf--;
7979548Ssam reg--;
7989548Ssam mask = up->upec2;
79934525Skarels diskerr(bp, "up", "soft ecc", LOG_WARNING, npf,
80034525Skarels (struct disklabel *)0);
80134525Skarels addlog("\n");
8029548Ssam /*
8039548Ssam * Flush the buffered data path, and compute the
8049548Ssam * byte and bit position of the error. The variable i
8059548Ssam * is the byte offset in the transfer, the variable byte
8069548Ssam * is the offset from a page boundary in main memory.
8079548Ssam */
8089548Ssam i = up->upec1 - 1; /* -1 makes 0 origin */
8099548Ssam bit = i&07;
8109548Ssam i = (i&~07)>>3;
8119548Ssam byte = i + o;
8129548Ssam /*
8139548Ssam * Correct while possible bits remain of mask. Since mask
8149548Ssam * contains 11 bits, we continue while the bit offset is > -11.
8159548Ssam * Also watch out for end of this block and the end of the whole
8169548Ssam * transfer.
8179548Ssam */
81827674Skarels while (i < 512 && (int)dbtob(npf)+i < bp->b_bcount && bit > -11) {
81913879Ssam struct pte pte;
82013879Ssam
82113879Ssam pte = ubp->uba_map[reg + btop(byte)];
82213879Ssam addr = ptob(pte.pg_pfnum) + (byte & PGOFSET);
8233445Sroot #ifdef UPECCDEBUG
8249548Ssam printf("addr %x map reg %x\n",
8259548Ssam addr, *(int *)(&ubp->uba_map[reg+btop(byte)]));
8269548Ssam printf("old: %x, ", getmemc(addr));
8273445Sroot #endif
8289548Ssam putmemc(addr, getmemc(addr)^(mask<<bit));
8293445Sroot #ifdef UPECCDEBUG
8309548Ssam printf("new: %x\n", getmemc(addr));
8313445Sroot #endif
8329548Ssam byte++;
8339548Ssam i++;
8349580Shelge bit -= 8;
8359548Ssam }
8369548Ssam if (up->upwc == 0)
8379548Ssam return (0);
8389548Ssam npf++;
8399548Ssam reg++;
8409548Ssam break;
8419548Ssam case BSE:
8429548Ssam /*
8439548Ssam * if not in bad sector table, return 0
8449548Ssam */
8459548Ssam if ((bn = isbad(&upbad[ui->ui_unit], cn, tn, sn)) < 0)
8469548Ssam return(0);
8479548Ssam /*
8489548Ssam * flag this one as bad
8499548Ssam */
8509548Ssam bp->b_flags |= B_BAD;
8519548Ssam bp->b_error = npf + 1;
8529548Ssam #ifdef UPECCDEBUG
8539548Ssam printf("BSE: restart at %d\n",npf+1);
8549548Ssam #endif
8559548Ssam bn = st->ncyl * st->nspc -st->nsect - 1 - bn;
8569548Ssam cn = bn / st->nspc;
8579548Ssam sn = bn % st->nspc;
8589548Ssam tn = sn / st->nsect;
8599548Ssam sn %= st->nsect;
8609548Ssam up->upwc = -(512 / sizeof (short));
8619548Ssam #ifdef UPECCDEBUG
8629548Ssam printf("revector to cn %d tn %d sn %d\n", cn, tn, sn);
8639548Ssam #endif
8649548Ssam break;
8659548Ssam case CONT:
8669548Ssam #ifdef UPECCDEBUG
8679548Ssam printf("upecc, CONT: bn %d cn %d tn %d sn %d\n", bn, cn, tn, sn);
8689548Ssam #endif
8699548Ssam bp->b_flags &= ~B_BAD;
87027674Skarels if ((int)dbtob(npf) >= bp->b_bcount)
87127674Skarels return (0);
87227674Skarels up->upwc = -((bp->b_bcount - (int)dbtob(npf)) / sizeof(short));
8739548Ssam break;
874264Sbill }
8757183Sroot if (up->upwc == 0) {
8767183Sroot um->um_tab.b_active = 0;
877264Sbill return (0);
8787183Sroot }
879266Sbill /*
880266Sbill * Have to continue the transfer... clear the drive,
881266Sbill * and compute the position where the transfer is to continue.
882266Sbill * We have completed npf+1 sectors of the transfer already;
883266Sbill * restart at offset o of next sector (i.e. in UBA register reg+1).
884266Sbill */
8852629Swnj #ifdef notdef
8862629Swnj up->uper1 = 0;
8872629Swnj up->upcs1 |= UP_GO;
8882629Swnj #else
8892629Swnj up->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO;
890264Sbill up->updc = cn;
891266Sbill up->upda = (tn << 8) | sn;
8929548Ssam ubaddr = (int)ptob(reg) + o;
893266Sbill up->upba = ubaddr;
894266Sbill cmd = (ubaddr >> 8) & 0x300;
8959548Ssam cmd |= ((bp->b_flags&B_READ)?UP_RCOM:UP_WCOM)|UP_IE|UP_GO;
8969548Ssam um->um_tab.b_errcnt = 0;
897266Sbill up->upcs1 = cmd;
8982629Swnj #endif
899264Sbill return (1);
900264Sbill }
901286Sbill
902286Sbill /*
903286Sbill * Reset driver after UBA init.
904286Sbill * Cancel software state of all pending transfers
905286Sbill * and restart all units and the controller.
906286Sbill */
upreset(uban)9072395Swnj upreset(uban)
9082931Swnj int uban;
909286Sbill {
9102983Swnj register struct uba_ctlr *um;
9112983Swnj register struct uba_device *ui;
9122395Swnj register sc21, unit;
913286Sbill
9142646Swnj for (sc21 = 0; sc21 < NSC; sc21++) {
9152470Swnj if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban ||
9162470Swnj um->um_alive == 0)
9172395Swnj continue;
9182931Swnj printf(" sc%d", sc21);
9192395Swnj um->um_tab.b_active = 0;
9202395Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0;
9212931Swnj up_softc[sc21].sc_recal = 0;
9226346Swnj up_softc[sc21].sc_wticks = 0;
9232571Swnj if (um->um_ubinfo) {
9242571Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf);
9259357Ssam um->um_ubinfo = 0;
9262395Swnj }
9273445Sroot ((struct updevice *)(um->um_addr))->upcs2 = UPCS2_CLR;
9282395Swnj for (unit = 0; unit < NUP; unit++) {
9292395Swnj if ((ui = updinfo[unit]) == 0)
9302395Swnj continue;
9312931Swnj if (ui->ui_alive == 0 || ui->ui_mi != um)
9322395Swnj continue;
9332395Swnj uputab[unit].b_active = 0;
9342395Swnj (void) upustart(ui);
9352395Swnj }
9362395Swnj (void) upstart(um);
937286Sbill }
938286Sbill }
939313Sbill
940313Sbill /*
941313Sbill * Wake up every second and if an interrupt is pending
942313Sbill * but nothing has happened increment a counter.
9432931Swnj * If nothing happens for 20 seconds, reset the UNIBUS
944313Sbill * and begin anew.
945313Sbill */
upwatch()946313Sbill upwatch()
947313Sbill {
9482983Swnj register struct uba_ctlr *um;
9492395Swnj register sc21, unit;
9502470Swnj register struct up_softc *sc;
951313Sbill
9522759Swnj timeout(upwatch, (caddr_t)0, hz);
9532646Swnj for (sc21 = 0; sc21 < NSC; sc21++) {
9542395Swnj um = upminfo[sc21];
9552470Swnj if (um == 0 || um->um_alive == 0)
9562470Swnj continue;
9572470Swnj sc = &up_softc[sc21];
9582395Swnj if (um->um_tab.b_active == 0) {
9592395Swnj for (unit = 0; unit < NUP; unit++)
9602629Swnj if (uputab[unit].b_active &&
9612629Swnj updinfo[unit]->ui_mi == um)
9622395Swnj goto active;
9632470Swnj sc->sc_wticks = 0;
9642395Swnj continue;
9652395Swnj }
9662931Swnj active:
9672470Swnj sc->sc_wticks++;
9682470Swnj if (sc->sc_wticks >= 20) {
9692470Swnj sc->sc_wticks = 0;
9702931Swnj printf("sc%d: lost interrupt\n", sc21);
9712646Swnj ubareset(um->um_ubanum);
9722395Swnj }
973313Sbill }
974313Sbill }
9752379Swnj
9762379Swnj #define DBSIZE 20
9772379Swnj
updump(dev)9782379Swnj updump(dev)
9792379Swnj dev_t dev;
9802379Swnj {
9812629Swnj struct updevice *upaddr;
9822379Swnj char *start;
9833107Swnj int num, blk, unit;
9842379Swnj struct size *sizes;
9852395Swnj register struct uba_regs *uba;
9862983Swnj register struct uba_device *ui;
9872379Swnj register short *rp;
9882395Swnj struct upst *st;
9896848Ssam register int retry;
9902379Swnj
99124743Sbloom unit = upunit(dev);
9922889Swnj if (unit >= NUP)
9932889Swnj return (ENXIO);
9942470Swnj #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff))
9952983Swnj ui = phys(struct uba_device *, updinfo[unit]);
9962889Swnj if (ui->ui_alive == 0)
9972889Swnj return (ENXIO);
9982395Swnj uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba;
9992983Swnj ubainit(uba);
10002629Swnj upaddr = (struct updevice *)ui->ui_physaddr;
10016848Ssam DELAY(5000000);
10022379Swnj num = maxfree;
10032379Swnj upaddr->upcs2 = unit;
10042983Swnj DELAY(100);
10056848Ssam upaddr->upcs1 = UP_DCLR|UP_GO;
10066848Ssam upaddr->upcs1 = UP_PRESET|UP_GO;
10076848Ssam upaddr->upof = UPOF_FMT22;
10086848Ssam retry = 0;
10096848Ssam do {
10106848Ssam DELAY(25);
10116848Ssam if (++retry > 527)
10126848Ssam break;
10136861Ssam } while ((upaddr->upds & UP_RDY) == 0);
10143445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY)
10152889Swnj return (EFAULT);
10169357Ssam start = 0;
10178489Sroot st = &upst[ui->ui_type];
10182395Swnj sizes = phys(struct size *, st->sizes);
101924213Sbloom if (dumplo < 0)
10202889Swnj return (EINVAL);
102124213Sbloom if (dumplo + num >= sizes[minor(dev)&07].nblocks)
102224213Sbloom num = sizes[minor(dev)&07].nblocks - dumplo;
10232379Swnj while (num > 0) {
10242379Swnj register struct pte *io;
10252379Swnj register int i;
10262379Swnj int cn, sn, tn;
10272379Swnj daddr_t bn;
10282379Swnj
10292379Swnj blk = num > DBSIZE ? DBSIZE : num;
10302395Swnj io = uba->uba_map;
10312379Swnj for (i = 0; i < blk; i++)
10322983Swnj *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV;
10332379Swnj *(int *)io = 0;
10342379Swnj bn = dumplo + btop(start);
10352607Swnj cn = bn/st->nspc + sizes[minor(dev)&07].cyloff;
10362607Swnj sn = bn%st->nspc;
10372607Swnj tn = sn/st->nsect;
10382607Swnj sn = sn%st->nsect;
10392379Swnj upaddr->updc = cn;
10402379Swnj rp = (short *) &upaddr->upda;
10412379Swnj *rp = (tn << 8) + sn;
10422379Swnj *--rp = 0;
10432379Swnj *--rp = -blk*NBPG / sizeof (short);
10442629Swnj *--rp = UP_GO|UP_WCOM;
10456848Ssam retry = 0;
10462379Swnj do {
10472379Swnj DELAY(25);
10486848Ssam if (++retry > 527)
10496848Ssam break;
10502629Swnj } while ((upaddr->upcs1 & UP_RDY) == 0);
10516848Ssam if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) {
10526861Ssam printf("up%d: not ready", unit);
10536848Ssam if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) {
10546848Ssam printf("\n");
10556848Ssam return (EIO);
10566848Ssam }
10576848Ssam printf(" (flakey)\n");
10586848Ssam }
10593445Sroot if (upaddr->upds&UPDS_ERR)
10602889Swnj return (EIO);
10612379Swnj start += blk*NBPG;
10622379Swnj num -= blk;
10632379Swnj }
10642379Swnj return (0);
10652379Swnj }
106612505Ssam
upsize(dev)106712505Ssam upsize(dev)
106812505Ssam dev_t dev;
106912505Ssam {
107024743Sbloom int unit = upunit(dev);
107112505Ssam struct uba_device *ui;
107212505Ssam struct upst *st;
107312505Ssam
107412505Ssam if (unit >= NUP || (ui = updinfo[unit]) == 0 || ui->ui_alive == 0)
107512505Ssam return (-1);
107612505Ssam st = &upst[ui->ui_type];
107712505Ssam return (st->sizes[minor(dev) & 07].nblocks);
107812505Ssam }
10791902Swnj #endif
1080