1*1783Sbill /* up.c 4.2 11/09/80 */ 2264Sbill 31563Sbill #include "../conf/up.h" 4264Sbill /* 5885Sbill * UNIBUS disk driver with overlapped seeks and ECC recovery. 6264Sbill */ 71756Sbill #define DELAY(N) { register int d; d = N; while (--d > 0); } 8264Sbill 9264Sbill #include "../h/param.h" 10264Sbill #include "../h/systm.h" 11308Sbill #include "../h/dk.h" 12264Sbill #include "../h/buf.h" 13264Sbill #include "../h/conf.h" 14264Sbill #include "../h/dir.h" 15264Sbill #include "../h/user.h" 16264Sbill #include "../h/map.h" 17420Sbill #include "../h/pte.h" 18264Sbill #include "../h/mba.h" 19264Sbill #include "../h/mtpr.h" 20264Sbill #include "../h/uba.h" 21264Sbill #include "../h/vm.h" 22264Sbill 23264Sbill #define ushort unsigned short 24264Sbill 25264Sbill struct device 26264Sbill { 27264Sbill ushort upcs1; /* control and status register 1 */ 28264Sbill short upwc; /* word count register */ 29264Sbill ushort upba; /* UNIBUS address register */ 30264Sbill ushort upda; /* desired address register */ 31264Sbill ushort upcs2; /* control and status register 2 */ 32264Sbill ushort upds; /* drive Status */ 33264Sbill ushort uper1; /* error register 1 */ 34264Sbill ushort upas; /* attention summary */ 35264Sbill ushort upla; /* look ahead */ 36264Sbill ushort updb; /* data buffer */ 37264Sbill ushort upmr; /* maintenance */ 38264Sbill ushort updt; /* drive type */ 39264Sbill ushort upsn; /* serial number */ 40264Sbill ushort upof; /* offset register */ 41264Sbill ushort updc; /* desired cylinder address register */ 42264Sbill ushort upcc; /* current cylinder */ 43264Sbill ushort uper2; /* error register 2 */ 44264Sbill ushort uper3; /* error register 3 */ 45264Sbill ushort upec1; /* burst error bit position */ 46264Sbill ushort upec2; /* burst error bit pattern */ 47264Sbill }; 48264Sbill 49275Sbill /* 50275Sbill * Software extension to the upas register, so we can 51275Sbill * postpone starting SEARCH commands until the controller 52275Sbill * is not transferring. 53275Sbill */ 54341Sbill int upsoftas; 55275Sbill 56275Sbill /* 57275Sbill * If upseek then we don't issue SEARCH commands but rather just 58275Sbill * settle for a SEEK to the correct cylinder. 59275Sbill */ 60275Sbill int upseek; 61275Sbill 62264Sbill #define NSECT 32 63264Sbill #define NTRAC 19 64264Sbill 65264Sbill /* 66264Sbill * Constants controlling on-cylinder SEARCH usage. 67264Sbill * 68308Sbill * upSDIST/2 msec time needed to start transfer 69308Sbill * upRDIST/2 msec tolerable rotational latency when on-cylinder 70275Sbill * 71308Sbill * If we are no closer than upSDIST sectors and no further than upSDIST+upRDIST 72275Sbill * and in the driver then we take it as it is. Otherwise we do a SEARCH 73308Sbill * requesting an interrupt upSDIST sectors in advance. 74264Sbill */ 751592Sbill #define _upSDIST 2 /* 1.0 msec */ 761592Sbill #define _upRDIST 4 /* 2.0 msec */ 77264Sbill 78308Sbill int upSDIST = _upSDIST; 79308Sbill int upRDIST = _upRDIST; 80275Sbill 81264Sbill /* 82264Sbill * To fill a 300M drive: 83264Sbill * A is designed to be used as a root. 84264Sbill * B is suitable for a swap area. 85264Sbill * H is the primary storage area. 86264Sbill * On systems with RP06'es, we normally use only 291346 blocks of the H 87264Sbill * area, and use DEF or G to cover the rest of the drive. The C system 88264Sbill * covers the whole drive and can be used for pack-pack copying. 891756Sbill * 901756Sbill * Note: sizes here are for AMPEX drives with 815 cylinders. 911756Sbill * CDC drives can make the F,G, and H areas larger as they have 823 cylinders. 92264Sbill */ 93264Sbill struct size 94264Sbill { 95264Sbill daddr_t nblocks; 96264Sbill int cyloff; 97264Sbill } up_sizes[8] = { 98264Sbill 15884, 0, /* A=cyl 0 thru 26 */ 99264Sbill 33440, 27, /* B=cyl 27 thru 81 */ 100341Sbill 495520, 0, /* C=cyl 0 thru 814 */ 101264Sbill 15884, 562, /* D=cyl 562 thru 588 */ 102264Sbill 55936, 589, /* E=cyl 589 thru 680 */ 103264Sbill 81472, 681, /* F=cyl 681 thru 814 */ 104264Sbill 153824, 562, /* G=cyl 562 thru 814 */ 105264Sbill 291346, 82, /* H=cyl 82 thru 561 */ 106264Sbill }; 107264Sbill 108264Sbill /* 109264Sbill * The following defines are used in offset positioning 110264Sbill * when trying to recover disk errors, with the constants being 111264Sbill * +/- microinches. Note that header compare inhibit (HCI) is not 112264Sbill * tried (this makes sense only during read, in any case.) 113264Sbill * 1141756Sbill * NB: Not all drives/controllers emulate all of these. 115264Sbill */ 116264Sbill #define P400 020 117264Sbill #define M400 0220 118264Sbill #define P800 040 119264Sbill #define M800 0240 120264Sbill #define P1200 060 121264Sbill #define M1200 0260 122264Sbill #define HCI 020000 123264Sbill 124264Sbill int up_offset[16] = 125264Sbill { 126264Sbill P400, M400, P400, M400, 127264Sbill P800, M800, P800, M800, 128264Sbill P1200, M1200, P1200, M1200, 129264Sbill 0, 0, 0, 0, 130264Sbill }; 131264Sbill 132264Sbill /* 133264Sbill * Each drive has a table uputab[i]. On this table are sorted the 134264Sbill * pending requests implementing an elevator algorithm (see dsort.c.) 135264Sbill * In the upustart() routine, each drive is independently advanced 136264Sbill * until it is on the desired cylinder for the next transfer and near 137264Sbill * the desired sector. The drive is then chained onto the uptab 138264Sbill * table, and the transfer is initiated by the upstart() routine. 139264Sbill * When the transfer is completed the driver reinvokes the upustart() 140264Sbill * routine to set up the next transfer. 141264Sbill */ 142264Sbill struct buf uptab; 143264Sbill struct buf uputab[NUP]; 144264Sbill 145264Sbill struct buf rupbuf; /* Buffer for raw i/o */ 146264Sbill 147264Sbill /* Drive commands, placed in upcs1 */ 148264Sbill #define GO 01 /* Go bit, set in all commands */ 149264Sbill #define PRESET 020 /* Preset drive at init or after errors */ 150264Sbill #define OFFSET 014 /* Offset heads to try to recover error */ 151264Sbill #define RTC 016 /* Return to center-line after OFFSET */ 152264Sbill #define SEARCH 030 /* Search for cylinder+sector */ 153275Sbill #define SEEK 04 /* Seek to cylinder */ 154264Sbill #define RECAL 06 /* Recalibrate, needed after seek error */ 155264Sbill #define DCLR 010 /* Drive clear, after error */ 156264Sbill #define WCOM 060 /* Write */ 157264Sbill #define RCOM 070 /* Read */ 158264Sbill 159264Sbill /* Other bits of upcs1 */ 160264Sbill #define IE 0100 /* Controller wide interrupt enable */ 161264Sbill #define TRE 040000 /* Transfer error */ 162345Sbill #define RDY 0200 /* Transfer terminated */ 163264Sbill 164264Sbill /* Drive status bits of upds */ 165264Sbill #define PIP 020000 /* Positioning in progress */ 166264Sbill #define ERR 040000 /* Error has occurred, DCLR necessary */ 167264Sbill #define VV 0100 /* Volume is valid, set by PRESET */ 168264Sbill #define DPR 0400 /* Drive has been preset */ 169264Sbill #define MOL 010000 /* Drive is online, heads loaded, etc */ 170264Sbill #define DRY 0200 /* Drive ready */ 171264Sbill 172313Sbill /* Bits of upcs2 */ 173313Sbill #define CLR 040 /* Controller clear */ 174264Sbill /* Bits of uper1 */ 175264Sbill #define DCK 0100000 /* Ecc error occurred */ 176264Sbill #define ECH 0100 /* Ecc error was unrecoverable */ 177264Sbill #define WLE 04000 /* Attempt to write read-only drive */ 178264Sbill 179264Sbill /* Bits of upof; the offset bits above are also in this register */ 180264Sbill #define FMT22 010000 /* 16 bits/word, must be always set */ 181264Sbill 182264Sbill #define b_cylin b_resid 183264Sbill 184264Sbill int up_ubinfo; /* Information about UBA usage saved here */ 185264Sbill 186313Sbill int up_wticks; /* Ticks waiting for interrupt */ 187313Sbill int upwstart; /* Have started guardian */ 188313Sbill int upwatch(); 189313Sbill 190264Sbill #ifdef INTRLVE 191264Sbill daddr_t dkblock(); 192264Sbill #endif 193264Sbill 194264Sbill /* 195264Sbill * Queue an i/o request for a drive, checking first that it is in range. 196264Sbill * 197264Sbill * A unit start is issued if the drive is inactive, causing 198264Sbill * a SEARCH for the correct cylinder/sector. If the drive is 199264Sbill * already nearly on the money and the controller is not transferring 200264Sbill * we kick it to start the transfer. 201264Sbill */ 202264Sbill upstrategy(bp) 203264Sbill register struct buf *bp; 204264Sbill { 205264Sbill register struct buf *dp; 206264Sbill register unit, xunit; 207264Sbill long sz, bn; 208264Sbill 209313Sbill if (upwstart == 0) { 210*1783Sbill timeout(upwatch, (caddr_t)0, HZ); 211313Sbill upwstart++; 212313Sbill } 213264Sbill xunit = minor(bp->b_dev) & 077; 214264Sbill sz = bp->b_bcount; 215264Sbill sz = (sz+511) >> 9; /* transfer size in 512 byte sectors */ 216264Sbill unit = dkunit(bp); 217264Sbill if (unit >= NUP || 218264Sbill bp->b_blkno < 0 || 219264Sbill (bn = dkblock(bp))+sz > up_sizes[xunit&07].nblocks) { 220264Sbill bp->b_flags |= B_ERROR; 221264Sbill iodone(bp); 222264Sbill return; 223264Sbill } 2241412Sbill if (DK_N+unit <= DK_NMAX) 2251412Sbill dk_mspw[DK_N+unit] = .0000020345; 226264Sbill bp->b_cylin = bn/(NSECT*NTRAC) + up_sizes[xunit&07].cyloff; 227264Sbill dp = &uputab[unit]; 228264Sbill (void) spl5(); 229264Sbill disksort(dp, bp); 230264Sbill if (dp->b_active == 0) { 231268Sbill (void) upustart(unit); 232264Sbill if (uptab.b_actf && uptab.b_active == 0) 233268Sbill (void) upstart(); 234264Sbill } 235264Sbill (void) spl0(); 236264Sbill } 237264Sbill 238264Sbill /* 239264Sbill * Start activity on specified drive; called when drive is inactive 240264Sbill * and new transfer request arrives and also when upas indicates that 241264Sbill * a SEARCH command is complete. 242264Sbill */ 243264Sbill upustart(unit) 244264Sbill register unit; 245264Sbill { 246264Sbill register struct buf *bp, *dp; 247264Sbill register struct device *upaddr = UPADDR; 248264Sbill daddr_t bn; 249264Sbill int sn, cn, csn; 250268Sbill int didie = 0; 251264Sbill 252275Sbill /* 253275Sbill * Other drivers tend to say something like 254275Sbill * upaddr->upcs1 = IE; 255275Sbill * upaddr->upas = 1<<unit; 2561756Sbill * here, but some controllers will cancel a command 257275Sbill * happens to be sitting in the cs1 if you clear the go 2581756Sbill * bit by storing there (so the first is not safe). 259275Sbill * 260275Sbill * Thus we keep careful track of when we re-enable IE 261275Sbill * after an interrupt and do it only if we didn't issue 262275Sbill * a command which re-enabled it as a matter of course. 263275Sbill * We clear bits in upas in the interrupt routine, when 264275Sbill * no transfers are active. 265275Sbill */ 266266Sbill if (unit >= NUP) 267268Sbill goto out; 268264Sbill if (unit+DK_N <= DK_NMAX) 269264Sbill dk_busy &= ~(1<<(unit+DK_N)); 270264Sbill dp = &uputab[unit]; 271266Sbill if ((bp = dp->b_actf) == NULL) 272268Sbill goto out; 273275Sbill /* 2741756Sbill * Most controllers don't start SEARCH commands when transfers are 2751756Sbill * in progress. In fact, some tend to get confused when given 276275Sbill * SEARCH'es during transfers, generating interrupts with neither 277275Sbill * RDY nor a bit in the upas register. Thus we defer 278275Sbill * until an interrupt when a transfer is pending. 279275Sbill */ 280275Sbill if (uptab.b_active) { 281341Sbill upsoftas |= 1<<unit; 282275Sbill return (0); 283275Sbill } 284276Sbill if (dp->b_active) 285276Sbill goto done; 286276Sbill dp->b_active = 1; 2871756Sbill if ((upaddr->upcs2 & 07) != unit) 288264Sbill upaddr->upcs2 = unit; 289266Sbill /* 290266Sbill * If we have changed packs or just initialized, 291275Sbill * then the volume will not be valid; if so, clear 292266Sbill * the drive, preset it and put in 16bit/word mode. 293266Sbill */ 294266Sbill if ((upaddr->upds & VV) == 0) { 295266Sbill upaddr->upcs1 = IE|DCLR|GO; 296264Sbill upaddr->upcs1 = IE|PRESET|GO; 297264Sbill upaddr->upof = FMT22; 298268Sbill didie = 1; 299264Sbill } 300264Sbill if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) 301275Sbill goto done; 302266Sbill /* 303266Sbill * Do enough of the disk address decoding to determine 304266Sbill * which cylinder and sector the request is on. 305266Sbill * If we are on the correct cylinder and the desired sector 306308Sbill * lies between upSDIST and upSDIST+upRDIST sectors ahead of us, then 307266Sbill * we don't bother to SEARCH but just begin the transfer asap. 308308Sbill * Otherwise ask for a interrupt upSDIST sectors ahead. 309266Sbill */ 310264Sbill bn = dkblock(bp); 311264Sbill cn = bp->b_cylin; 312264Sbill sn = bn%(NSECT*NTRAC); 313308Sbill sn = (sn+NSECT-upSDIST)%NSECT; 314264Sbill 315266Sbill if (cn - upaddr->updc) 316266Sbill goto search; /* Not on-cylinder */ 317275Sbill else if (upseek) 318275Sbill goto done; /* Ok just to be on-cylinder */ 319264Sbill csn = (upaddr->upla>>6) - sn - 1; 320266Sbill if (csn < 0) 321264Sbill csn += NSECT; 322308Sbill if (csn > NSECT-upRDIST) 323264Sbill goto done; 324264Sbill 325264Sbill search: 326264Sbill upaddr->updc = cn; 327275Sbill if (upseek) 328275Sbill upaddr->upcs1 = IE|SEEK|GO; 329275Sbill else { 330275Sbill upaddr->upda = sn; 331275Sbill upaddr->upcs1 = IE|SEARCH|GO; 332275Sbill } 333268Sbill didie = 1; 334266Sbill /* 335266Sbill * Mark this unit busy. 336266Sbill */ 337264Sbill unit += DK_N; 3381412Sbill if (unit <= DK_NMAX) { 339264Sbill dk_busy |= 1<<unit; 3401412Sbill dk_seek[unit]++; 341264Sbill } 342268Sbill goto out; 343264Sbill 344264Sbill done: 345266Sbill /* 346275Sbill * This unit is ready to go so 347275Sbill * link it onto the chain of ready disks. 348266Sbill */ 349264Sbill dp->b_forw = NULL; 350266Sbill if (uptab.b_actf == NULL) 351264Sbill uptab.b_actf = dp; 352264Sbill else 353264Sbill uptab.b_actl->b_forw = dp; 354264Sbill uptab.b_actl = dp; 355268Sbill 356268Sbill out: 357268Sbill return (didie); 358264Sbill } 359264Sbill 360264Sbill /* 361264Sbill * Start a transfer; call from top level at spl5() or on interrupt. 362264Sbill */ 363264Sbill upstart() 364264Sbill { 365264Sbill register struct buf *bp, *dp; 366264Sbill register unit; 367264Sbill register struct device *upaddr; 368264Sbill daddr_t bn; 369266Sbill int dn, sn, tn, cn, cmd; 370264Sbill 371264Sbill loop: 372266Sbill /* 373266Sbill * Pick a drive off the queue of ready drives, and 374266Sbill * perform the first transfer on its queue. 375266Sbill * 376266Sbill * Looping here is completely for the sake of drives which 377266Sbill * are not present and on-line, for which we completely clear the 378266Sbill * request queue. 379266Sbill */ 380273Sbill if ((dp = uptab.b_actf) == NULL) 381268Sbill return (0); 382264Sbill if ((bp = dp->b_actf) == NULL) { 383264Sbill uptab.b_actf = dp->b_forw; 384264Sbill goto loop; 385264Sbill } 386266Sbill /* 387266Sbill * Mark the controller busy, and multi-part disk address. 388266Sbill * Select the unit on which the i/o is to take place. 389266Sbill */ 390264Sbill uptab.b_active++; 391264Sbill unit = minor(bp->b_dev) & 077; 392264Sbill dn = dkunit(bp); 393264Sbill bn = dkblock(bp); 394264Sbill cn = up_sizes[unit&07].cyloff; 395264Sbill cn += bn/(NSECT*NTRAC); 396264Sbill sn = bn%(NSECT*NTRAC); 397264Sbill tn = sn/NSECT; 398266Sbill sn %= NSECT; 399264Sbill upaddr = UPADDR; 4001756Sbill if ((upaddr->upcs2 & 07) != dn) 401264Sbill upaddr->upcs2 = dn; 4021756Sbill up_ubinfo = ubasetup(bp, 1); 403266Sbill /* 404266Sbill * If drive is not present and on-line, then 405266Sbill * get rid of this with an error and loop to get 406266Sbill * rid of the rest of its queued requests. 407266Sbill * (Then on to any other ready drives.) 408266Sbill */ 409264Sbill if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) { 410893Sbill printf("!DPR || !MOL, unit %d, ds %o", dn, upaddr->upds); 411893Sbill if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) { 412893Sbill printf("-- hard\n"); 413893Sbill uptab.b_active = 0; 414893Sbill uptab.b_errcnt = 0; 415893Sbill dp->b_actf = bp->av_forw; 416893Sbill dp->b_active = 0; 417893Sbill bp->b_flags |= B_ERROR; 418893Sbill iodone(bp); 419893Sbill /* A funny place to do this ... */ 420893Sbill ubafree(up_ubinfo), up_ubinfo = 0; 421893Sbill goto loop; 422893Sbill } 423893Sbill printf("-- came back\n"); 424264Sbill } 425266Sbill /* 426266Sbill * If this is a retry, then with the 16'th retry we 427266Sbill * begin to try offsetting the heads to recover the data. 428266Sbill */ 429924Sbill if (uptab.b_errcnt >= 16 && (bp->b_flags&B_WRITE) == 0) { 430264Sbill upaddr->upof = up_offset[uptab.b_errcnt & 017] | FMT22; 431266Sbill upaddr->upcs1 = IE|OFFSET|GO; 432266Sbill while (upaddr->upds & PIP) 433264Sbill DELAY(25); 434264Sbill } 435266Sbill /* 436266Sbill * Now set up the transfer, retrieving the high 437266Sbill * 2 bits of the UNIBUS address from the information 438266Sbill * returned by ubasetup() for the cs1 register bits 8 and 9. 439266Sbill */ 440264Sbill upaddr->updc = cn; 441264Sbill upaddr->upda = (tn << 8) + sn; 442264Sbill upaddr->upba = up_ubinfo; 443264Sbill upaddr->upwc = -bp->b_bcount / sizeof (short); 444266Sbill cmd = (up_ubinfo >> 8) & 0x300; 445264Sbill if (bp->b_flags & B_READ) 446266Sbill cmd |= IE|RCOM|GO; 447264Sbill else 448266Sbill cmd |= IE|WCOM|GO; 449266Sbill upaddr->upcs1 = cmd; 450266Sbill /* 451266Sbill * This is a controller busy situation. 452266Sbill * Record in dk slot NUP+DK_N (after last drive) 453266Sbill * unless there aren't that many slots reserved for 454266Sbill * us in which case we record this as a drive busy 455266Sbill * (if there is room for that). 456266Sbill */ 457264Sbill unit = dn+DK_N; 458264Sbill if (unit <= DK_NMAX) { 459264Sbill dk_busy |= 1<<unit; 4601412Sbill dk_xfer[unit]++; 461264Sbill dk_wds[unit] += bp->b_bcount>>6; 462264Sbill } 463268Sbill return (1); 464264Sbill } 465264Sbill 466264Sbill /* 467264Sbill * Handle a device interrupt. 468264Sbill * 469264Sbill * If the transferring drive needs attention, service it 470264Sbill * retrying on error or beginning next transfer. 471264Sbill * Service all other ready drives, calling ustart to transfer 472264Sbill * their blocks to the ready queue in uptab, and then restart 473264Sbill * the controller if there is anything to do. 474264Sbill */ 475264Sbill upintr() 476264Sbill { 477264Sbill register struct buf *bp, *dp; 478264Sbill register unit; 479264Sbill register struct device *upaddr = UPADDR; 480264Sbill int as = upaddr->upas & 0377; 481341Sbill int oupsoftas; 482268Sbill int needie = 1; 483264Sbill 484276Sbill (void) spl6(); 485313Sbill up_wticks = 0; 486266Sbill if (uptab.b_active) { 487266Sbill /* 488266Sbill * The drive is transferring, thus the hardware 489266Sbill * (say the designers) will only interrupt when the transfer 490266Sbill * completes; check for it anyways. 491266Sbill */ 492266Sbill if ((upaddr->upcs1 & RDY) == 0) { 493272Sbill printf("!RDY: cs1 %o, ds %o, wc %d\n", upaddr->upcs1, 494272Sbill upaddr->upds, upaddr->upwc); 495341Sbill printf("as=%d act %d %d %d\n", as, uptab.b_active, 496341Sbill uputab[0].b_active, uputab[1].b_active); 497269Sbill } 498266Sbill /* 4991412Sbill * Mark drive not busy, and check for an 500266Sbill * error condition which may have resulted from the transfer. 501266Sbill */ 502264Sbill dp = uptab.b_actf; 503264Sbill bp = dp->b_actf; 504264Sbill unit = dkunit(bp); 5051412Sbill if (DK_N+unit <= DK_NMAX) 506264Sbill dk_busy &= ~(1<<(DK_N+unit)); 5071756Sbill if ((upaddr->upcs2 & 07) != unit) 508275Sbill upaddr->upcs2 = unit; 509885Sbill if ((upaddr->upds&ERR) || (upaddr->upcs1&TRE)) { 510266Sbill /* 511266Sbill * An error occurred, indeed. Select this unit 512266Sbill * to get at the drive status (a SEARCH may have 513266Sbill * intervened to change the selected unit), and 514266Sbill * wait for the command which caused the interrupt 515266Sbill * to complete (DRY). 516266Sbill */ 517266Sbill while ((upaddr->upds & DRY) == 0) 518264Sbill DELAY(25); 519266Sbill /* 520266Sbill * After 28 retries (16 w/o servo offsets, and then 521266Sbill * 12 with servo offsets), or if we encountered 522266Sbill * an error because the drive is write-protected, 523266Sbill * give up. Print an error message on the last 2 524266Sbill * retries before a hard failure. 525266Sbill */ 526266Sbill if (++uptab.b_errcnt > 28 || upaddr->uper1&WLE) 527264Sbill bp->b_flags |= B_ERROR; 528264Sbill else 529266Sbill uptab.b_active = 0; /* To force retry */ 530266Sbill if (uptab.b_errcnt > 27) 531*1783Sbill deverror(bp, (int)upaddr->upcs2, 532*1783Sbill (int)upaddr->uper1); 533266Sbill /* 534266Sbill * If this was a correctible ECC error, let upecc 535266Sbill * do the dirty work to correct it. If upecc 536266Sbill * starts another READ for the rest of the data 537266Sbill * then it returns 1 (having set uptab.b_active). 538266Sbill * Otherwise we are done and fall through to 539266Sbill * finish up. 540266Sbill */ 541266Sbill if ((upaddr->uper1&(DCK|ECH))==DCK && upecc(upaddr, bp)) 542266Sbill return; 543266Sbill /* 544266Sbill * Clear the drive and, every 4 retries, recalibrate 545266Sbill * to hopefully help clear up seek positioning problems. 546266Sbill */ 547264Sbill upaddr->upcs1 = TRE|IE|DCLR|GO; 548268Sbill needie = 0; 549266Sbill if ((uptab.b_errcnt&07) == 4) { 550264Sbill upaddr->upcs1 = RECAL|GO|IE; 551264Sbill while(upaddr->upds & PIP) 552264Sbill DELAY(25); 553264Sbill } 554264Sbill } 555266Sbill /* 556266Sbill * If we are still noted as active, then no 557266Sbill * (further) retries are necessary. 558266Sbill * 559266Sbill * Make sure the correct unit is selected, 560266Sbill * return it to centerline if necessary, and mark 561266Sbill * this i/o complete, starting the next transfer 562266Sbill * on this drive with the upustart routine (if any). 563266Sbill */ 564266Sbill if (uptab.b_active) { 565266Sbill if (uptab.b_errcnt >= 16) { 566266Sbill upaddr->upcs1 = RTC|GO|IE; 567266Sbill while (upaddr->upds & PIP) 568264Sbill DELAY(25); 569268Sbill needie = 0; 570264Sbill } 571264Sbill uptab.b_active = 0; 572264Sbill uptab.b_errcnt = 0; 573264Sbill uptab.b_actf = dp->b_forw; 574264Sbill dp->b_active = 0; 575264Sbill dp->b_errcnt = 0; 576264Sbill dp->b_actf = bp->av_forw; 577266Sbill bp->b_resid = (-upaddr->upwc * sizeof(short)); 578275Sbill if (bp->b_resid) 579341Sbill printf("resid %d ds %o er? %o %o %o\n", 580341Sbill bp->b_resid, upaddr->upds, 581275Sbill upaddr->uper1, upaddr->uper2, upaddr->uper3); 582264Sbill iodone(bp); 583264Sbill if(dp->b_actf) 584268Sbill if (upustart(unit)) 585268Sbill needie = 0; 586264Sbill } 587264Sbill as &= ~(1<<unit); 588341Sbill upsoftas &= ~(1<<unit); 589264Sbill ubafree(up_ubinfo), up_ubinfo = 0; 590273Sbill } else { 5911756Sbill if (upaddr->upcs1 & TRE) 592264Sbill upaddr->upcs1 = TRE; 593264Sbill } 594266Sbill /* 595266Sbill * If we have a unit with an outstanding SEARCH, 596266Sbill * and the hardware indicates the unit requires attention, 597266Sbill * the bring the drive to the ready queue. 598266Sbill * Finally, if the controller is not transferring 599266Sbill * start it if any drives are now ready to transfer. 600266Sbill */ 601341Sbill as |= upsoftas; 602341Sbill oupsoftas = upsoftas; 603341Sbill upsoftas = 0; 604266Sbill for (unit = 0; unit < NUP; unit++) 605341Sbill if ((as|oupsoftas) & (1<<unit)) { 6061756Sbill if (as & (1<<unit)) 607267Sbill upaddr->upas = 1<<unit; 608273Sbill if (upustart(unit)) 609273Sbill needie = 0; 610273Sbill } 611266Sbill if (uptab.b_actf && uptab.b_active == 0) 612268Sbill if (upstart()) 613268Sbill needie = 0; 614275Sbill if (needie) 615266Sbill upaddr->upcs1 = IE; 616264Sbill } 617264Sbill 618264Sbill upread(dev) 619264Sbill { 620264Sbill 621264Sbill physio(upstrategy, &rupbuf, dev, B_READ, minphys); 622264Sbill } 623264Sbill 624264Sbill upwrite(dev) 625264Sbill { 626264Sbill 627264Sbill physio(upstrategy, &rupbuf, dev, B_WRITE, minphys); 628264Sbill } 629264Sbill 630266Sbill /* 631266Sbill * Correct an ECC error, and restart the i/o to complete 632266Sbill * the transfer if necessary. This is quite complicated because 633266Sbill * the transfer may be going to an odd memory address base and/or 634266Sbill * across a page boundary. 635266Sbill */ 636264Sbill upecc(up, bp) 637264Sbill register struct device *up; 638264Sbill register struct buf *bp; 639264Sbill { 640264Sbill struct uba_regs *ubp = (struct uba_regs *)UBA0; 641266Sbill register int i; 642264Sbill caddr_t addr; 643266Sbill int reg, bit, byte, npf, mask, o, cmd, ubaddr; 644264Sbill int bn, cn, tn, sn; 645264Sbill 646264Sbill /* 647266Sbill * Npf is the number of sectors transferred before the sector 648266Sbill * containing the ECC error, and reg is the UBA register 649266Sbill * mapping (the first part of) the transfer. 650266Sbill * O is offset within a memory page of the first byte transferred. 651264Sbill */ 652266Sbill npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1; 653266Sbill reg = btop(up_ubinfo&0x3ffff) + npf; 654264Sbill o = (int)bp->b_un.b_addr & PGOFSET; 655264Sbill printf("%D ", bp->b_blkno+npf); 656264Sbill prdev("ECC", bp->b_dev); 657264Sbill mask = up->upec2; 658264Sbill if (mask == 0) { 659266Sbill up->upof = FMT22; /* == RTC ???? */ 660264Sbill return (0); 661264Sbill } 662266Sbill /* 663266Sbill * Flush the buffered data path, and compute the 664266Sbill * byte and bit position of the error. The variable i 665266Sbill * is the byte offset in the transfer, the variable byte 666266Sbill * is the offset from a page boundary in main memory. 667266Sbill */ 668266Sbill ubp->uba_dpr[(up_ubinfo>>28)&0x0f] |= BNE; 669266Sbill i = up->upec1 - 1; /* -1 makes 0 origin */ 670266Sbill bit = i&07; 671266Sbill i = (i&~07)>>3; 672264Sbill byte = i + o; 673266Sbill /* 674266Sbill * Correct while possible bits remain of mask. Since mask 675266Sbill * contains 11 bits, we continue while the bit offset is > -11. 676266Sbill * Also watch out for end of this block and the end of the whole 677266Sbill * transfer. 678266Sbill */ 679266Sbill while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 680266Sbill addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ 681266Sbill (byte & PGOFSET); 682266Sbill putmemc(addr, getmemc(addr)^(mask<<bit)); 683266Sbill byte++; 684266Sbill i++; 685266Sbill bit -= 8; 686264Sbill } 687266Sbill uptab.b_active++; /* Either complete or continuing... */ 688264Sbill if (up->upwc == 0) 689264Sbill return (0); 690266Sbill /* 691266Sbill * Have to continue the transfer... clear the drive, 692266Sbill * and compute the position where the transfer is to continue. 693266Sbill * We have completed npf+1 sectors of the transfer already; 694266Sbill * restart at offset o of next sector (i.e. in UBA register reg+1). 695266Sbill */ 696266Sbill up->upcs1 = TRE|IE|DCLR|GO; 697264Sbill bn = dkblock(bp); 698264Sbill cn = bp->b_cylin; 699266Sbill sn = bn%(NSECT*NTRAC) + npf + 1; 700264Sbill tn = sn/NSECT; 701264Sbill sn %= NSECT; 702266Sbill cn += tn/NTRAC; 703266Sbill tn %= NTRAC; 704264Sbill up->updc = cn; 705266Sbill up->upda = (tn << 8) | sn; 706266Sbill ubaddr = (int)ptob(reg+1) + o; 707266Sbill up->upba = ubaddr; 708266Sbill cmd = (ubaddr >> 8) & 0x300; 709266Sbill cmd |= IE|GO|RCOM; 710266Sbill up->upcs1 = cmd; 711264Sbill return (1); 712264Sbill } 713286Sbill 714286Sbill /* 715286Sbill * Reset driver after UBA init. 716286Sbill * Cancel software state of all pending transfers 717286Sbill * and restart all units and the controller. 718286Sbill */ 719286Sbill upreset() 720286Sbill { 721286Sbill int unit; 722286Sbill 723286Sbill printf(" up"); 724286Sbill uptab.b_active = 0; 725286Sbill uptab.b_actf = uptab.b_actl = 0; 726286Sbill if (up_ubinfo) { 727286Sbill printf("<%d>", (up_ubinfo>>28)&0xf); 728286Sbill ubafree(up_ubinfo), up_ubinfo = 0; 729286Sbill } 730313Sbill UPADDR->upcs2 = CLR; /* clear controller */ 731286Sbill for (unit = 0; unit < NUP; unit++) { 732286Sbill uputab[unit].b_active = 0; 733286Sbill (void) upustart(unit); 734286Sbill } 735286Sbill (void) upstart(); 736286Sbill } 737313Sbill 738313Sbill /* 739313Sbill * Wake up every second and if an interrupt is pending 740313Sbill * but nothing has happened increment a counter. 741313Sbill * If nothing happens for 20 seconds, reset the controller 742313Sbill * and begin anew. 743313Sbill */ 744313Sbill upwatch() 745313Sbill { 746313Sbill int i; 747313Sbill 748*1783Sbill timeout(upwatch, (caddr_t)0, HZ); 749313Sbill if (uptab.b_active == 0) { 750313Sbill for (i = 0; i < NUP; i++) 751313Sbill if (uputab[i].b_active) 752313Sbill goto active; 753313Sbill up_wticks = 0; /* idling */ 754313Sbill return; 755313Sbill } 756313Sbill active: 757313Sbill up_wticks++; 758313Sbill if (up_wticks >= 20) { 759313Sbill up_wticks = 0; 760313Sbill printf("LOST INTERRUPT RESET"); 761313Sbill upreset(); 762313Sbill printf("\n"); 763313Sbill } 764313Sbill } 765