1*266Sbill int cs1del; 2264Sbill int printsw; 3*266Sbill /* 10/14/12 3.2 06/18/80 */ 4264Sbill 5264Sbill /* 6264Sbill * Emulex UNIBUS disk driver with overlapped seeks and ECC recovery. 7264Sbill * 8*266Sbill * NB: This device is very sensitive: be aware that the code is the way 9*266Sbill * it is for good reason and that there are delay loops here which may 10*266Sbill * have to be lengthened if your processor is faster and which should 11*266Sbill * probably be shortened if your processor is slower. 12*266Sbill * 13264Sbill * This driver has been tested on a SC-11B Controller, configured 14264Sbill * with the following internal switch settings: 15264Sbill * SW1-1 5/19 surfaces (off, 19 surfaces on Ampex 9300) 16264Sbill * SW1-2 chksum enable (off, checksum disabled) 17264Sbill * SW1-3 volume select (off, 815 cylinders) 18264Sbill * SW1-4 sector select (on, 32 sectors) 19264Sbill * SW1-5 unused (off) 20264Sbill * SW1-6 port select (on, single port) 21264Sbill * SW1-7 npr delay (off, disable) 22264Sbill * SW1-8 ecc test mode (off, disable) 23264Sbill * and top mounted switches: 24264Sbill * SW2-1 extend opcodes (off=open, disable) 25264Sbill * SW2-2 extend diag (off=open, disable) 26264Sbill * SW2-3 4 wd dma burst (off=open, disable) 27264Sbill * SW2-4 unused (off=open) 28264Sbill * 29264Sbill * The controller transfers data much more rapidly with SW2-3 set, 30264Sbill * but we have previously experienced problems with it set this way. 31264Sbill * We intend to try this again in the near future. 32264Sbill * 33264Sbill * wnj June 14, 1980 34264Sbill */ 35264Sbill 36264Sbill #include "../h/param.h" 37264Sbill #include "../h/systm.h" 38264Sbill #include "../h/buf.h" 39264Sbill #include "../h/conf.h" 40264Sbill #include "../h/dir.h" 41264Sbill #include "../h/user.h" 42264Sbill #include "../h/map.h" 43264Sbill #include "../h/mba.h" 44264Sbill #include "../h/mtpr.h" 45264Sbill #include "../h/pte.h" 46264Sbill #include "../h/uba.h" 47264Sbill #include "../h/vm.h" 48264Sbill 49264Sbill /* 50264Sbill * Define number of drives, and range of sampling information to be used. 51264Sbill * 52264Sbill * Normally, DK_N .. DK_N+NUP-1 gather individual drive stats, 53264Sbill * and DK_N+NUP gathers controller transferring stats. 54264Sbill * 55264Sbill * If DK_N+NUP > DK_NMAX, then transfer stats are divided per drive. 56264Sbill * If DK_NMAX is yet smaller, some drives are not monitored. 57264Sbill */ 58264Sbill #define DK_N 1 59264Sbill #define DK_NMAX 2 60264Sbill 61264Sbill #define ushort unsigned short 62264Sbill 63264Sbill struct device 64264Sbill { 65264Sbill ushort upcs1; /* control and status register 1 */ 66264Sbill short upwc; /* word count register */ 67264Sbill ushort upba; /* UNIBUS address register */ 68264Sbill ushort upda; /* desired address register */ 69264Sbill ushort upcs2; /* control and status register 2 */ 70264Sbill ushort upds; /* drive Status */ 71264Sbill ushort uper1; /* error register 1 */ 72264Sbill ushort upas; /* attention summary */ 73264Sbill ushort upla; /* look ahead */ 74264Sbill ushort updb; /* data buffer */ 75264Sbill ushort upmr; /* maintenance */ 76264Sbill ushort updt; /* drive type */ 77264Sbill ushort upsn; /* serial number */ 78264Sbill ushort upof; /* offset register */ 79264Sbill ushort updc; /* desired cylinder address register */ 80264Sbill ushort upcc; /* current cylinder */ 81264Sbill ushort uper2; /* error register 2 */ 82264Sbill ushort uper3; /* error register 3 */ 83264Sbill ushort upec1; /* burst error bit position */ 84264Sbill ushort upec2; /* burst error bit pattern */ 85264Sbill }; 86264Sbill 87264Sbill #define UPADDR ((struct device *)(UBA0_DEV + 0176700)) 88264Sbill 89264Sbill #define NUP 2 /* Number of drives this installation */ 90264Sbill 91264Sbill #define NSECT 32 92264Sbill #define NTRAC 19 93264Sbill 94264Sbill /* 95264Sbill * Constants controlling on-cylinder SEARCH usage. 96264Sbill * 97264Sbill * We assume that it takes SDIST sectors of time to set up a transfer. 98264Sbill * If a drive is on-cylinder, and between SDIST and SDIST+RDIST sectors 99264Sbill * from the first sector to be transferred, then we just perform the 100264Sbill * transfer. SDIST represents interrupt latency, RDIST the amount 101264Sbill * of rotation which is tolerable to avoid another interrupt. 102264Sbill */ 103*266Sbill #define SDIST 3 /* 2-3 sectors 1-1.5 msec */ 104*266Sbill #define RDIST 6 /* 5-6 sectors 2.5-3 msec */ 105264Sbill 106264Sbill /* 107264Sbill * To fill a 300M drive: 108264Sbill * A is designed to be used as a root. 109264Sbill * B is suitable for a swap area. 110264Sbill * H is the primary storage area. 111264Sbill * On systems with RP06'es, we normally use only 291346 blocks of the H 112264Sbill * area, and use DEF or G to cover the rest of the drive. The C system 113264Sbill * covers the whole drive and can be used for pack-pack copying. 114264Sbill */ 115264Sbill struct size 116264Sbill { 117264Sbill daddr_t nblocks; 118264Sbill int cyloff; 119264Sbill } up_sizes[8] = { 120264Sbill 15884, 0, /* A=cyl 0 thru 26 */ 121264Sbill 33440, 27, /* B=cyl 27 thru 81 */ 122264Sbill 494912, 0, /* C=cyl 0 thru 814 */ 123264Sbill 15884, 562, /* D=cyl 562 thru 588 */ 124264Sbill 55936, 589, /* E=cyl 589 thru 680 */ 125264Sbill 81472, 681, /* F=cyl 681 thru 814 */ 126264Sbill 153824, 562, /* G=cyl 562 thru 814 */ 127264Sbill 445664, 82, /* H=cyl 82 thru 814 */ 128264Sbill /* Later, and more safely for H area... 129264Sbill 291346, 82, /* H=cyl 82 thru 561 */ 130264Sbill }; 131264Sbill 132264Sbill /* 133264Sbill * The following defines are used in offset positioning 134264Sbill * when trying to recover disk errors, with the constants being 135264Sbill * +/- microinches. Note that header compare inhibit (HCI) is not 136264Sbill * tried (this makes sense only during read, in any case.) 137264Sbill * 138264Sbill * ARE ALL THESE IMPLEMENTED ON 9300? 139264Sbill */ 140264Sbill #define P400 020 141264Sbill #define M400 0220 142264Sbill #define P800 040 143264Sbill #define M800 0240 144264Sbill #define P1200 060 145264Sbill #define M1200 0260 146264Sbill #define HCI 020000 147264Sbill 148264Sbill int up_offset[16] = 149264Sbill { 150264Sbill P400, M400, P400, M400, 151264Sbill P800, M800, P800, M800, 152264Sbill P1200, M1200, P1200, M1200, 153264Sbill 0, 0, 0, 0, 154264Sbill }; 155264Sbill 156264Sbill /* 157264Sbill * Each drive has a table uputab[i]. On this table are sorted the 158264Sbill * pending requests implementing an elevator algorithm (see dsort.c.) 159264Sbill * In the upustart() routine, each drive is independently advanced 160264Sbill * until it is on the desired cylinder for the next transfer and near 161264Sbill * the desired sector. The drive is then chained onto the uptab 162264Sbill * table, and the transfer is initiated by the upstart() routine. 163264Sbill * When the transfer is completed the driver reinvokes the upustart() 164264Sbill * routine to set up the next transfer. 165264Sbill */ 166264Sbill struct buf uptab; 167264Sbill struct buf uputab[NUP]; 168264Sbill 169264Sbill struct buf rupbuf; /* Buffer for raw i/o */ 170264Sbill 171264Sbill /* Drive commands, placed in upcs1 */ 172264Sbill #define GO 01 /* Go bit, set in all commands */ 173264Sbill #define PRESET 020 /* Preset drive at init or after errors */ 174264Sbill #define OFFSET 014 /* Offset heads to try to recover error */ 175264Sbill #define RTC 016 /* Return to center-line after OFFSET */ 176264Sbill #define SEARCH 030 /* Search for cylinder+sector */ 177264Sbill #define RECAL 06 /* Recalibrate, needed after seek error */ 178264Sbill #define DCLR 010 /* Drive clear, after error */ 179264Sbill #define WCOM 060 /* Write */ 180264Sbill #define RCOM 070 /* Read */ 181264Sbill 182264Sbill /* Other bits of upcs1 */ 183264Sbill #define IE 0100 /* Controller wide interrupt enable */ 184264Sbill #define TRE 040000 /* Transfer error */ 185*266Sbill #define RDY 020 /* Transfer terminated */ 186264Sbill 187264Sbill /* Drive status bits of upds */ 188264Sbill #define PIP 020000 /* Positioning in progress */ 189264Sbill #define ERR 040000 /* Error has occurred, DCLR necessary */ 190264Sbill #define VV 0100 /* Volume is valid, set by PRESET */ 191264Sbill #define DPR 0400 /* Drive has been preset */ 192264Sbill #define MOL 010000 /* Drive is online, heads loaded, etc */ 193264Sbill #define DRY 0200 /* Drive ready */ 194264Sbill 195264Sbill /* Bits of uper1 */ 196264Sbill #define DCK 0100000 /* Ecc error occurred */ 197264Sbill #define ECH 0100 /* Ecc error was unrecoverable */ 198264Sbill #define WLE 04000 /* Attempt to write read-only drive */ 199264Sbill 200264Sbill /* Bits of upof; the offset bits above are also in this register */ 201264Sbill #define FMT22 010000 /* 16 bits/word, must be always set */ 202264Sbill 203264Sbill #define b_cylin b_resid 204264Sbill 205264Sbill int up_ubinfo; /* Information about UBA usage saved here */ 206264Sbill /* 207264Sbill * The EMULEX controller balks if accessed quickly after 208264Sbill * certain operations. The exact timing has not yet been 209264Sbill * determined, but delays are known to be needed when changing 210264Sbill * the selected drive (by writing in upcs2), and thought to be 211264Sbill * needed after operations like PRESET and DCLR. The following 212264Sbill * variables control the delay, DELAY(n) is approximately n usec. 213264Sbill */ 214264Sbill int idelay = 500; /* Delay after PRESET or DCLR */ 215264Sbill int sdelay = 500; /* Delay after selecting drive in upcs2 */ 216*266Sbill int iedel1 = 500; 217*266Sbill int iedel2 = 500; 218*266Sbill int iedel3 = 0; 219*266Sbill int iedel4 = 500; 220264Sbill 221264Sbill #define DELAY(N) { register int d; d = N; while (--d > 0); } 222264Sbill 223264Sbill int nwaitcs2; /* How many sdelay loops ? */ 224264Sbill int neasycs2; /* How many sdelay loops not needed ? */ 225264Sbill 226264Sbill #ifdef INTRLVE 227264Sbill daddr_t dkblock(); 228264Sbill #endif 229264Sbill 230264Sbill /* 231264Sbill * Queue an i/o request for a drive, checking first that it is in range. 232264Sbill * 233264Sbill * A unit start is issued if the drive is inactive, causing 234264Sbill * a SEARCH for the correct cylinder/sector. If the drive is 235264Sbill * already nearly on the money and the controller is not transferring 236264Sbill * we kick it to start the transfer. 237264Sbill */ 238264Sbill upstrategy(bp) 239264Sbill register struct buf *bp; 240264Sbill { 241264Sbill register struct buf *dp; 242264Sbill register unit, xunit; 243264Sbill long sz, bn; 244264Sbill 245264Sbill xunit = minor(bp->b_dev) & 077; 246264Sbill sz = bp->b_bcount; 247264Sbill sz = (sz+511) >> 9; /* transfer size in 512 byte sectors */ 248264Sbill unit = dkunit(bp); 249264Sbill if (unit >= NUP || 250264Sbill bp->b_blkno < 0 || 251264Sbill (bn = dkblock(bp))+sz > up_sizes[xunit&07].nblocks) { 252264Sbill bp->b_flags |= B_ERROR; 253264Sbill iodone(bp); 254264Sbill return; 255264Sbill } 256264Sbill bp->b_cylin = bn/(NSECT*NTRAC) + up_sizes[xunit&07].cyloff; 257264Sbill dp = &uputab[unit]; 258264Sbill (void) spl5(); 259264Sbill disksort(dp, bp); 260264Sbill if (dp->b_active == 0) { 261264Sbill upustart(unit); 262264Sbill if (uptab.b_actf && uptab.b_active == 0) 263264Sbill upstart(); 264264Sbill } 265264Sbill (void) spl0(); 266264Sbill } 267264Sbill 268264Sbill /* 269264Sbill * Start activity on specified drive; called when drive is inactive 270264Sbill * and new transfer request arrives and also when upas indicates that 271264Sbill * a SEARCH command is complete. 272264Sbill */ 273264Sbill upustart(unit) 274264Sbill register unit; 275264Sbill { 276264Sbill register struct buf *bp, *dp; 277264Sbill register struct device *upaddr = UPADDR; 278264Sbill daddr_t bn; 279264Sbill int sn, cn, csn; 280264Sbill 281264Sbill if (printsw&1) printf("upustart\n"); 282*266Sbill if (unit >= NUP) 283264Sbill return; 284*266Sbill /* 285*266Sbill * Whether or not it was before, this unit is no longer busy. 286*266Sbill * Check to see if there is (still or now) a request in this 287*266Sbill * drives queue, and if there is, select this unit. 288*266Sbill */ 289264Sbill if (unit+DK_N <= DK_NMAX) 290264Sbill dk_busy &= ~(1<<(unit+DK_N)); 291264Sbill dp = &uputab[unit]; 292*266Sbill if ((bp = dp->b_actf) == NULL) 293264Sbill return; 294264Sbill if ((upaddr->upcs2 & 07) != unit) { 295264Sbill upaddr->upcs2 = unit; 296264Sbill DELAY(sdelay); 297264Sbill nwaitcs2++; 298264Sbill } else 299264Sbill neasycs2++; 300*266Sbill /* 301*266Sbill * If we have changed packs or just initialized, 302*266Sbill * the the volume will not be valid; if so, clear 303*266Sbill * the drive, preset it and put in 16bit/word mode. 304*266Sbill */ 305*266Sbill if ((upaddr->upds & VV) == 0) { 306*266Sbill upaddr->upcs1 = IE|DCLR|GO; 307*266Sbill DELAY(idelay); 308264Sbill upaddr->upcs1 = IE|PRESET|GO; 309264Sbill DELAY(idelay); 310264Sbill upaddr->upof = FMT22; 311264Sbill } 312264Sbill /* 313*266Sbill * We are called from upstrategy when a new request arrives 314*266Sbill * if we are not already active (with dp->b_active == 0), 315*266Sbill * and we then set dp->b_active to 1 if we are to SEARCH 316*266Sbill * for the desired cylinder, or 2 if we are on-cylinder. 317*266Sbill * If we SEARCH then we will later be called from upintr() 318*266Sbill * when the search is complete, and will link this disk onto 319*266Sbill * the uptab. We then set dp->b_active to 2 so that upintr() 320*266Sbill * will not call us again. 321*266Sbill * 322*266Sbill * NB: Other drives clear the bit in the attention status 323*266Sbill * (i.e. upas) register corresponding to the drive when they 324*266Sbill * place the drive on the ready (i.e. uptab) queue. This does 325*266Sbill * not work with the Emulex, as the controller hangs the UBA 326*266Sbill * of the VAX shortly after the upas register is set, for 327*266Sbill * reasons unknown. This only occurs in multi-spindle configurations, 328*266Sbill * but to avoid the problem we use the fact that dp->b_active is 329*266Sbill * 2 to replace the clearing of the upas bit. 330264Sbill */ 331*266Sbill if (dp->b_active) 332264Sbill goto done; 333*266Sbill dp->b_active = 1; 334264Sbill if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) 335*266Sbill goto done; /* Will redetect error in upstart() soon */ 336264Sbill 337*266Sbill /* 338*266Sbill * Do enough of the disk address decoding to determine 339*266Sbill * which cylinder and sector the request is on. 340*266Sbill * Then compute the number of the sector SDIST sectors before 341*266Sbill * the one where the transfer is to start, this being the 342*266Sbill * point where we wish to attempt to begin the transfer, 343*266Sbill * allowing approximately SDIST/2 msec for interrupt latency 344*266Sbill * and preparation of the request. 345*266Sbill * 346*266Sbill * If we are on the correct cylinder and the desired sector 347*266Sbill * lies between SDIST and SDIST+RDIST sectors ahead of us, then 348*266Sbill * we don't bother to SEARCH but just begin the transfer asap. 349*266Sbill */ 350264Sbill bn = dkblock(bp); 351264Sbill cn = bp->b_cylin; 352264Sbill sn = bn%(NSECT*NTRAC); 353264Sbill sn = (sn+NSECT-SDIST)%NSECT; 354264Sbill 355*266Sbill if (cn - upaddr->updc) 356*266Sbill goto search; /* Not on-cylinder */ 357264Sbill csn = (upaddr->upla>>6) - sn - 1; 358*266Sbill if (csn < 0) 359264Sbill csn += NSECT; 360*266Sbill if (csn > NSECT-RDIST) 361264Sbill goto done; 362264Sbill 363264Sbill search: 364264Sbill upaddr->updc = cn; 365264Sbill upaddr->upda = sn; 366*266Sbill if (cs1del&8) DELAY(500); 367264Sbill upaddr->upcs1 = IE|SEARCH|GO; 368*266Sbill if (cs1del&8) DELAY(500); 369*266Sbill /* 370*266Sbill * Mark this unit busy. 371*266Sbill */ 372264Sbill unit += DK_N; 373264Sbill if (unit <= DK_NMAX) { 374264Sbill dk_busy |= 1<<unit; 375264Sbill dk_numb[unit]++; 376264Sbill } 377264Sbill return; 378264Sbill 379264Sbill done: 380*266Sbill /* 381*266Sbill * This unit is ready to go. Make active == 2 so 382*266Sbill * we won't get called again (by upintr() because upas&(1<<unit)) 383*266Sbill * and link us onto the chain of ready disks. 384*266Sbill */ 385*266Sbill dp->b_active = 2; 386264Sbill dp->b_forw = NULL; 387*266Sbill if (uptab.b_actf == NULL) 388264Sbill uptab.b_actf = dp; 389264Sbill else 390264Sbill uptab.b_actl->b_forw = dp; 391264Sbill uptab.b_actl = dp; 392264Sbill } 393264Sbill 394264Sbill /* 395264Sbill * Start a transfer; call from top level at spl5() or on interrupt. 396264Sbill */ 397264Sbill upstart() 398264Sbill { 399264Sbill register struct buf *bp, *dp; 400264Sbill register unit; 401264Sbill register struct device *upaddr; 402264Sbill daddr_t bn; 403*266Sbill int dn, sn, tn, cn, cmd; 404264Sbill 405264Sbill if (printsw&2) printf("upstart\n"); 406264Sbill loop: 407*266Sbill /* 408*266Sbill * Pick a drive off the queue of ready drives, and 409*266Sbill * perform the first transfer on its queue. 410*266Sbill * 411*266Sbill * Looping here is completely for the sake of drives which 412*266Sbill * are not present and on-line, for which we completely clear the 413*266Sbill * request queue. 414*266Sbill */ 415264Sbill if ((dp = uptab.b_actf) == NULL) 416264Sbill return; 417264Sbill if ((bp = dp->b_actf) == NULL) { 418264Sbill uptab.b_actf = dp->b_forw; 419264Sbill goto loop; 420264Sbill } 421*266Sbill /* 422*266Sbill * Mark the controller busy, and multi-part disk address. 423*266Sbill * Select the unit on which the i/o is to take place. 424*266Sbill */ 425264Sbill uptab.b_active++; 426264Sbill unit = minor(bp->b_dev) & 077; 427264Sbill dn = dkunit(bp); 428264Sbill bn = dkblock(bp); 429264Sbill cn = up_sizes[unit&07].cyloff; 430264Sbill cn += bn/(NSECT*NTRAC); 431264Sbill sn = bn%(NSECT*NTRAC); 432264Sbill tn = sn/NSECT; 433*266Sbill sn %= NSECT; 434264Sbill upaddr = UPADDR; 435264Sbill if ((upaddr->upcs2 & 07) != dn) { 436264Sbill upaddr->upcs2 = dn; 437264Sbill DELAY(sdelay); 438264Sbill nwaitcs2++; 439264Sbill } else 440264Sbill neasycs2++; 441*266Sbill up_ubinfo = ubasetup(bp, 1); /* In a funny place for delay... */ 442*266Sbill /* 443*266Sbill * If drive is not present and on-line, then 444*266Sbill * get rid of this with an error and loop to get 445*266Sbill * rid of the rest of its queued requests. 446*266Sbill * (Then on to any other ready drives.) 447*266Sbill */ 448264Sbill if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) { 449264Sbill uptab.b_active = 0; 450264Sbill uptab.b_errcnt = 0; 451264Sbill dp->b_actf = bp->av_forw; 452*266Sbill dp->b_active = 0; 453264Sbill bp->b_flags |= B_ERROR; 454264Sbill iodone(bp); 455*266Sbill ubafree(up_ubinfo), up_ubinfo = 0; /* A funny place ... */ 456264Sbill goto loop; 457264Sbill } 458*266Sbill /* 459*266Sbill * If this is a retry, then with the 16'th retry we 460*266Sbill * begin to try offsetting the heads to recover the data. 461*266Sbill */ 462*266Sbill if (uptab.b_errcnt >= 16) { 463264Sbill upaddr->upof = up_offset[uptab.b_errcnt & 017] | FMT22; 464*266Sbill upaddr->upcs1 = IE|OFFSET|GO; 465264Sbill DELAY(idelay); 466*266Sbill while (upaddr->upds & PIP) 467264Sbill DELAY(25); 468264Sbill } 469*266Sbill /* 470*266Sbill * Now set up the transfer, retrieving the high 471*266Sbill * 2 bits of the UNIBUS address from the information 472*266Sbill * returned by ubasetup() for the cs1 register bits 8 and 9. 473*266Sbill */ 474264Sbill upaddr->updc = cn; 475264Sbill upaddr->upda = (tn << 8) + sn; 476264Sbill upaddr->upba = up_ubinfo; 477*266Sbill if (cs1del&1) DELAY(500); 478264Sbill upaddr->upwc = -bp->b_bcount / sizeof (short); 479*266Sbill cmd = (up_ubinfo >> 8) & 0x300; 480264Sbill if (bp->b_flags & B_READ) 481*266Sbill cmd |= IE|RCOM|GO; 482264Sbill else 483*266Sbill cmd |= IE|WCOM|GO; 484*266Sbill if (cs1del&1) DELAY(500); 485*266Sbill upaddr->upcs1 = cmd; 486*266Sbill if (cs1del&1) DELAY(500); 487*266Sbill /* 488*266Sbill * This is a controller busy situation. 489*266Sbill * Record in dk slot NUP+DK_N (after last drive) 490*266Sbill * unless there aren't that many slots reserved for 491*266Sbill * us in which case we record this as a drive busy 492*266Sbill * (if there is room for that). 493*266Sbill */ 494264Sbill unit = dn+DK_N; 495264Sbill if (NUP+DK_N == DK_NMAX) 496264Sbill unit = NUP+DK_N; 497264Sbill if (unit <= DK_NMAX) { 498264Sbill dk_busy |= 1<<unit; 499264Sbill dk_numb[unit]++; 500264Sbill dk_wds[unit] += bp->b_bcount>>6; 501264Sbill } 502264Sbill } 503264Sbill 504264Sbill /* 505264Sbill * Handle a device interrupt. 506264Sbill * 507264Sbill * If the transferring drive needs attention, service it 508264Sbill * retrying on error or beginning next transfer. 509264Sbill * Service all other ready drives, calling ustart to transfer 510264Sbill * their blocks to the ready queue in uptab, and then restart 511264Sbill * the controller if there is anything to do. 512264Sbill */ 513264Sbill upintr() 514264Sbill { 515264Sbill register struct buf *bp, *dp; 516264Sbill register unit; 517264Sbill register struct device *upaddr = UPADDR; 518264Sbill int as = upaddr->upas & 0377; 519264Sbill 520*266Sbill if (printsw&4) printf("upintr as=%d act %d %d %d\n", as, uptab.b_active, uputab[0].b_active, uputab[1].b_active); 521*266Sbill if (uptab.b_active) { 522*266Sbill /* 523*266Sbill * The drive is transferring, thus the hardware 524*266Sbill * (say the designers) will only interrupt when the transfer 525*266Sbill * completes; check for it anyways. 526*266Sbill */ 527*266Sbill if ((upaddr->upcs1 & RDY) == 0) { 528*266Sbill printf("upintr b_active && !RDY\n"); 529*266Sbill goto out; 530*266Sbill } 531*266Sbill /* 532*266Sbill * Mark controller or drive not busy, and check for an 533*266Sbill * error condition which may have resulted from the transfer. 534*266Sbill */ 535264Sbill dp = uptab.b_actf; 536264Sbill bp = dp->b_actf; 537264Sbill unit = dkunit(bp); 538264Sbill if (DK_N+NUP == DK_NMAX) 539264Sbill dk_busy &= ~(1<<(DK_N+NUP)); 540264Sbill else if (DK_N+unit <= DK_NMAX) 541264Sbill dk_busy &= ~(1<<(DK_N+unit)); 542264Sbill if (upaddr->upcs1 & TRE) { 543*266Sbill /* 544*266Sbill * An error occurred, indeed. Select this unit 545*266Sbill * to get at the drive status (a SEARCH may have 546*266Sbill * intervened to change the selected unit), and 547*266Sbill * wait for the command which caused the interrupt 548*266Sbill * to complete (DRY). 549*266Sbill * 550*266Sbill * WHY IS THE WAIT NECESSARY? 551*266Sbill */ 552264Sbill if ((upaddr->upcs2 & 07) != unit) { 553264Sbill upaddr->upcs2 = unit; 554264Sbill DELAY(sdelay); 555264Sbill nwaitcs2++; 556264Sbill } else 557264Sbill neasycs2++; 558*266Sbill while ((upaddr->upds & DRY) == 0) 559264Sbill DELAY(25); 560*266Sbill /* 561*266Sbill * After 28 retries (16 w/o servo offsets, and then 562*266Sbill * 12 with servo offsets), or if we encountered 563*266Sbill * an error because the drive is write-protected, 564*266Sbill * give up. Print an error message on the last 2 565*266Sbill * retries before a hard failure. 566*266Sbill */ 567*266Sbill if (++uptab.b_errcnt > 28 || upaddr->uper1&WLE) 568264Sbill bp->b_flags |= B_ERROR; 569264Sbill else 570*266Sbill uptab.b_active = 0; /* To force retry */ 571*266Sbill if (uptab.b_errcnt > 27) 572264Sbill deverror(bp, upaddr->upcs2, upaddr->uper1); 573*266Sbill /* 574*266Sbill * If this was a correctible ECC error, let upecc 575*266Sbill * do the dirty work to correct it. If upecc 576*266Sbill * starts another READ for the rest of the data 577*266Sbill * then it returns 1 (having set uptab.b_active). 578*266Sbill * Otherwise we are done and fall through to 579*266Sbill * finish up. 580*266Sbill */ 581*266Sbill if ((upaddr->uper1&(DCK|ECH))==DCK && upecc(upaddr, bp)) 582*266Sbill return; 583*266Sbill /* 584*266Sbill * Clear the drive and, every 4 retries, recalibrate 585*266Sbill * to hopefully help clear up seek positioning problems. 586*266Sbill */ 587264Sbill upaddr->upcs1 = TRE|IE|DCLR|GO; 588264Sbill DELAY(idelay); 589*266Sbill if ((uptab.b_errcnt&07) == 4) { 590264Sbill upaddr->upcs1 = RECAL|GO|IE; 591264Sbill DELAY(idelay); 592264Sbill while(upaddr->upds & PIP) 593264Sbill DELAY(25); 594264Sbill } 595264Sbill } 596*266Sbill /* 597*266Sbill * If we are still noted as active, then no 598*266Sbill * (further) retries are necessary. 599*266Sbill * 600*266Sbill * Make sure the correct unit is selected, 601*266Sbill * return it to centerline if necessary, and mark 602*266Sbill * this i/o complete, starting the next transfer 603*266Sbill * on this drive with the upustart routine (if any). 604*266Sbill */ 605*266Sbill if (uptab.b_active) { 606*266Sbill if ((upaddr->upcs2 & 07) != unit) { 607*266Sbill upaddr->upcs2 = unit; 608*266Sbill DELAY(sdelay); 609*266Sbill nwaitcs2++; 610*266Sbill } else 611*266Sbill neasycs2++; 612*266Sbill if (uptab.b_errcnt >= 16) { 613*266Sbill upaddr->upcs1 = RTC|GO|IE; 614264Sbill DELAY(idelay); 615*266Sbill while (upaddr->upds & PIP) 616264Sbill DELAY(25); 617264Sbill } 618264Sbill uptab.b_active = 0; 619264Sbill uptab.b_errcnt = 0; 620264Sbill uptab.b_actf = dp->b_forw; 621264Sbill dp->b_active = 0; 622264Sbill dp->b_errcnt = 0; 623264Sbill dp->b_actf = bp->av_forw; 624*266Sbill bp->b_resid = (-upaddr->upwc * sizeof(short)); 625*266Sbill if (cs1del&2) DELAY(500); 626*266Sbill upaddr->upcs1 = IE; 627*266Sbill if (cs1del&2) DELAY(500); 628264Sbill iodone(bp); 629264Sbill if(dp->b_actf) 630264Sbill upustart(unit); 631264Sbill } 632264Sbill as &= ~(1<<unit); 633264Sbill ubafree(up_ubinfo), up_ubinfo = 0; 634*266Sbill } 635*266Sbill #ifndef notdef 636*266Sbill else { 637*266Sbill if (printsw&64) printf("cs1 %o\n", upaddr->upcs1); 638264Sbill if (upaddr->upcs1 & TRE) { 639264Sbill upaddr->upcs1 = TRE; 640264Sbill DELAY(idelay); 641*266Sbill if (printsw&64) printf("after TRE cs1 %o\n", upaddr->upcs1); 642264Sbill } 643264Sbill } 644*266Sbill #endif 645*266Sbill /* 646*266Sbill * If we have a unit with an outstanding SEARCH, 647*266Sbill * and the hardware indicates the unit requires attention, 648*266Sbill * the bring the drive to the ready queue. 649*266Sbill * Finally, if the controller is not transferring 650*266Sbill * start it if any drives are now ready to transfer. 651*266Sbill */ 652*266Sbill for (unit = 0; unit < NUP; unit++) 653*266Sbill if (as & (1<<unit)) 654*266Sbill if (uputab[unit].b_active == 1) 655*266Sbill upustart(unit); 656*266Sbill else { 657*266Sbill upaddr->upas = 1<<unit; 658*266Sbill DELAY(1000); 659*266Sbill } 660*266Sbill if (uptab.b_actf && uptab.b_active == 0) 661*266Sbill upstart(); 662*266Sbill out: 663*266Sbill if (cs1del&4) DELAY(500); 664*266Sbill if ((upaddr->upcs1&IE) == 0) 665*266Sbill upaddr->upcs1 = IE; 666*266Sbill if (cs1del&4) DELAY(500); 667*266Sbill if (printsw&128) printf("exit cs1 %o\n", upaddr->upcs1); 668264Sbill } 669264Sbill 670264Sbill upread(dev) 671264Sbill { 672264Sbill 673264Sbill physio(upstrategy, &rupbuf, dev, B_READ, minphys); 674264Sbill } 675264Sbill 676264Sbill upwrite(dev) 677264Sbill { 678264Sbill 679264Sbill physio(upstrategy, &rupbuf, dev, B_WRITE, minphys); 680264Sbill } 681264Sbill 682*266Sbill /* 683*266Sbill * Correct an ECC error, and restart the i/o to complete 684*266Sbill * the transfer if necessary. This is quite complicated because 685*266Sbill * the transfer may be going to an odd memory address base and/or 686*266Sbill * across a page boundary. 687*266Sbill */ 688264Sbill upecc(up, bp) 689264Sbill register struct device *up; 690264Sbill register struct buf *bp; 691264Sbill { 692264Sbill struct uba_regs *ubp = (struct uba_regs *)UBA0; 693*266Sbill register int i; 694264Sbill caddr_t addr; 695*266Sbill int reg, bit, byte, npf, mask, o, cmd, ubaddr; 696264Sbill int bn, cn, tn, sn; 697264Sbill 698264Sbill if (printsw&8) printf("upecc\n"); 699264Sbill /* 700*266Sbill * Npf is the number of sectors transferred before the sector 701*266Sbill * containing the ECC error, and reg is the UBA register 702*266Sbill * mapping (the first part of) the transfer. 703*266Sbill * O is offset within a memory page of the first byte transferred. 704264Sbill */ 705*266Sbill npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1; 706*266Sbill reg = btop(up_ubinfo&0x3ffff) + npf; 707264Sbill o = (int)bp->b_un.b_addr & PGOFSET; 708264Sbill printf("%D ", bp->b_blkno+npf); 709264Sbill prdev("ECC", bp->b_dev); 710264Sbill mask = up->upec2; 711264Sbill if (mask == 0) { 712*266Sbill up->upof = FMT22; /* == RTC ???? */ 713264Sbill DELAY(idelay); 714264Sbill return (0); 715264Sbill } 716*266Sbill /* 717*266Sbill * Flush the buffered data path, and compute the 718*266Sbill * byte and bit position of the error. The variable i 719*266Sbill * is the byte offset in the transfer, the variable byte 720*266Sbill * is the offset from a page boundary in main memory. 721*266Sbill */ 722*266Sbill ubp->uba_dpr[(up_ubinfo>>28)&0x0f] |= BNE; 723*266Sbill i = up->upec1 - 1; /* -1 makes 0 origin */ 724*266Sbill bit = i&07; 725*266Sbill i = (i&~07)>>3; 726264Sbill byte = i + o; 727*266Sbill /* 728*266Sbill * Correct while possible bits remain of mask. Since mask 729*266Sbill * contains 11 bits, we continue while the bit offset is > -11. 730*266Sbill * Also watch out for end of this block and the end of the whole 731*266Sbill * transfer. 732*266Sbill */ 733*266Sbill while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 734*266Sbill addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ 735*266Sbill (byte & PGOFSET); 736*266Sbill putmemc(addr, getmemc(addr)^(mask<<bit)); 737*266Sbill byte++; 738*266Sbill i++; 739*266Sbill bit -= 8; 740264Sbill } 741*266Sbill uptab.b_active++; /* Either complete or continuing... */ 742264Sbill if (up->upwc == 0) 743264Sbill return (0); 744*266Sbill /* 745*266Sbill * Have to continue the transfer... clear the drive, 746*266Sbill * and compute the position where the transfer is to continue. 747*266Sbill * We have completed npf+1 sectors of the transfer already; 748*266Sbill * restart at offset o of next sector (i.e. in UBA register reg+1). 749*266Sbill */ 750*266Sbill up->upcs1 = TRE|IE|DCLR|GO; 751264Sbill DELAY(idelay); 752264Sbill bn = dkblock(bp); 753264Sbill cn = bp->b_cylin; 754*266Sbill sn = bn%(NSECT*NTRAC) + npf + 1; 755264Sbill tn = sn/NSECT; 756264Sbill sn %= NSECT; 757*266Sbill cn += tn/NTRAC; 758*266Sbill tn %= NTRAC; 759264Sbill up->updc = cn; 760*266Sbill up->upda = (tn << 8) | sn; 761*266Sbill ubaddr = (int)ptob(reg+1) + o; 762*266Sbill up->upba = ubaddr; 763*266Sbill cmd = (ubaddr >> 8) & 0x300; 764*266Sbill cmd |= IE|GO|RCOM; 765*266Sbill up->upcs1 = cmd; 766264Sbill return (1); 767264Sbill } 768