1*275Sbill /* 10/14/12 3.11 06/20/80 */ 2264Sbill 3264Sbill /* 4264Sbill * Emulex UNIBUS disk driver with overlapped seeks and ECC recovery. 5264Sbill * 6266Sbill * NB: This device is very sensitive: be aware that the code is the way 7266Sbill * it is for good reason and that there are delay loops here which may 8266Sbill * have to be lengthened if your processor is faster and which should 9266Sbill * probably be shortened if your processor is slower. 10266Sbill * 11264Sbill * This driver has been tested on a SC-11B Controller, configured 12264Sbill * with the following internal switch settings: 13264Sbill * SW1-1 5/19 surfaces (off, 19 surfaces on Ampex 9300) 14264Sbill * SW1-2 chksum enable (off, checksum disabled) 15264Sbill * SW1-3 volume select (off, 815 cylinders) 16264Sbill * SW1-4 sector select (on, 32 sectors) 17264Sbill * SW1-5 unused (off) 18264Sbill * SW1-6 port select (on, single port) 19264Sbill * SW1-7 npr delay (off, disable) 20264Sbill * SW1-8 ecc test mode (off, disable) 21264Sbill * and top mounted switches: 22264Sbill * SW2-1 extend opcodes (off=open, disable) 23264Sbill * SW2-2 extend diag (off=open, disable) 24264Sbill * SW2-3 4 wd dma burst (off=open, disable) 25264Sbill * SW2-4 unused (off=open) 26264Sbill * 27264Sbill * The controller transfers data much more rapidly with SW2-3 set, 28264Sbill * but we have previously experienced problems with it set this way. 29264Sbill * We intend to try this again in the near future. 30264Sbill * 31264Sbill * wnj June 14, 1980 32264Sbill */ 33264Sbill 34264Sbill #include "../h/param.h" 35264Sbill #include "../h/systm.h" 36264Sbill #include "../h/buf.h" 37264Sbill #include "../h/conf.h" 38264Sbill #include "../h/dir.h" 39264Sbill #include "../h/user.h" 40264Sbill #include "../h/map.h" 41264Sbill #include "../h/mba.h" 42264Sbill #include "../h/mtpr.h" 43264Sbill #include "../h/pte.h" 44264Sbill #include "../h/uba.h" 45264Sbill #include "../h/vm.h" 46264Sbill 47264Sbill /* 48264Sbill * Define number of drives, and range of sampling information to be used. 49264Sbill * 50264Sbill * Normally, DK_N .. DK_N+NUP-1 gather individual drive stats, 51264Sbill * and DK_N+NUP gathers controller transferring stats. 52264Sbill * 53264Sbill * If DK_N+NUP > DK_NMAX, then transfer stats are divided per drive. 54264Sbill * If DK_NMAX is yet smaller, some drives are not monitored. 55264Sbill */ 56264Sbill #define DK_N 1 57264Sbill #define DK_NMAX 2 58264Sbill 59264Sbill #define ushort unsigned short 60264Sbill 61264Sbill struct device 62264Sbill { 63264Sbill ushort upcs1; /* control and status register 1 */ 64264Sbill short upwc; /* word count register */ 65264Sbill ushort upba; /* UNIBUS address register */ 66264Sbill ushort upda; /* desired address register */ 67264Sbill ushort upcs2; /* control and status register 2 */ 68264Sbill ushort upds; /* drive Status */ 69264Sbill ushort uper1; /* error register 1 */ 70264Sbill ushort upas; /* attention summary */ 71264Sbill ushort upla; /* look ahead */ 72264Sbill ushort updb; /* data buffer */ 73264Sbill ushort upmr; /* maintenance */ 74264Sbill ushort updt; /* drive type */ 75264Sbill ushort upsn; /* serial number */ 76264Sbill ushort upof; /* offset register */ 77264Sbill ushort updc; /* desired cylinder address register */ 78264Sbill ushort upcc; /* current cylinder */ 79264Sbill ushort uper2; /* error register 2 */ 80264Sbill ushort uper3; /* error register 3 */ 81264Sbill ushort upec1; /* burst error bit position */ 82264Sbill ushort upec2; /* burst error bit pattern */ 83264Sbill }; 84264Sbill 85*275Sbill /* 86*275Sbill * Software extension to the upas register, so we can 87*275Sbill * postpone starting SEARCH commands until the controller 88*275Sbill * is not transferring. 89*275Sbill */ 90*275Sbill int softas; 91*275Sbill 92*275Sbill /* 93*275Sbill * If upseek then we don't issue SEARCH commands but rather just 94*275Sbill * settle for a SEEK to the correct cylinder. 95*275Sbill */ 96*275Sbill int upseek; 97*275Sbill 98264Sbill #define UPADDR ((struct device *)(UBA0_DEV + 0176700)) 99264Sbill 100264Sbill #define NUP 2 /* Number of drives this installation */ 101264Sbill 102264Sbill #define NSECT 32 103264Sbill #define NTRAC 19 104264Sbill 105264Sbill /* 106264Sbill * Constants controlling on-cylinder SEARCH usage. 107264Sbill * 108*275Sbill * SDIST/2 msec time needed to start transfer 109*275Sbill * IDIST/2 msec slop for interrupt latency 110*275Sbill * RDIST/2 msec tolerable rotational latency when on-cylinder 111*275Sbill * 112*275Sbill * If we are no closer than SDIST sectors and no further than SDIST+RDIST 113*275Sbill * and in the driver then we take it as it is. Otherwise we do a SEARCH 114*275Sbill * requesting an interrupt SDIST+IDIST sectors in advance. 115264Sbill */ 116*275Sbill #define _SDIST 6 /* 3.0 msec */ 117*275Sbill #define _RDIST 6 /* 2.5 msec */ 118*275Sbill #define _IDIST 1 /* 0.5 msec */ 119264Sbill 120*275Sbill int SDIST = _SDIST; 121*275Sbill int RDIST = _RDIST; 122*275Sbill int IDIST = _IDIST; 123*275Sbill 124264Sbill /* 125264Sbill * To fill a 300M drive: 126264Sbill * A is designed to be used as a root. 127264Sbill * B is suitable for a swap area. 128264Sbill * H is the primary storage area. 129264Sbill * On systems with RP06'es, we normally use only 291346 blocks of the H 130264Sbill * area, and use DEF or G to cover the rest of the drive. The C system 131264Sbill * covers the whole drive and can be used for pack-pack copying. 132264Sbill */ 133264Sbill struct size 134264Sbill { 135264Sbill daddr_t nblocks; 136264Sbill int cyloff; 137264Sbill } up_sizes[8] = { 138264Sbill 15884, 0, /* A=cyl 0 thru 26 */ 139264Sbill 33440, 27, /* B=cyl 27 thru 81 */ 140264Sbill 494912, 0, /* C=cyl 0 thru 814 */ 141264Sbill 15884, 562, /* D=cyl 562 thru 588 */ 142264Sbill 55936, 589, /* E=cyl 589 thru 680 */ 143264Sbill 81472, 681, /* F=cyl 681 thru 814 */ 144264Sbill 153824, 562, /* G=cyl 562 thru 814 */ 145264Sbill 445664, 82, /* H=cyl 82 thru 814 */ 146264Sbill /* Later, and more safely for H area... 147264Sbill 291346, 82, /* H=cyl 82 thru 561 */ 148264Sbill }; 149264Sbill 150264Sbill /* 151264Sbill * The following defines are used in offset positioning 152264Sbill * when trying to recover disk errors, with the constants being 153264Sbill * +/- microinches. Note that header compare inhibit (HCI) is not 154264Sbill * tried (this makes sense only during read, in any case.) 155264Sbill * 156264Sbill * ARE ALL THESE IMPLEMENTED ON 9300? 157264Sbill */ 158264Sbill #define P400 020 159264Sbill #define M400 0220 160264Sbill #define P800 040 161264Sbill #define M800 0240 162264Sbill #define P1200 060 163264Sbill #define M1200 0260 164264Sbill #define HCI 020000 165264Sbill 166264Sbill int up_offset[16] = 167264Sbill { 168264Sbill P400, M400, P400, M400, 169264Sbill P800, M800, P800, M800, 170264Sbill P1200, M1200, P1200, M1200, 171264Sbill 0, 0, 0, 0, 172264Sbill }; 173264Sbill 174264Sbill /* 175264Sbill * Each drive has a table uputab[i]. On this table are sorted the 176264Sbill * pending requests implementing an elevator algorithm (see dsort.c.) 177264Sbill * In the upustart() routine, each drive is independently advanced 178264Sbill * until it is on the desired cylinder for the next transfer and near 179264Sbill * the desired sector. The drive is then chained onto the uptab 180264Sbill * table, and the transfer is initiated by the upstart() routine. 181264Sbill * When the transfer is completed the driver reinvokes the upustart() 182264Sbill * routine to set up the next transfer. 183264Sbill */ 184264Sbill struct buf uptab; 185264Sbill struct buf uputab[NUP]; 186264Sbill 187264Sbill struct buf rupbuf; /* Buffer for raw i/o */ 188264Sbill 189264Sbill /* Drive commands, placed in upcs1 */ 190264Sbill #define GO 01 /* Go bit, set in all commands */ 191264Sbill #define PRESET 020 /* Preset drive at init or after errors */ 192264Sbill #define OFFSET 014 /* Offset heads to try to recover error */ 193264Sbill #define RTC 016 /* Return to center-line after OFFSET */ 194264Sbill #define SEARCH 030 /* Search for cylinder+sector */ 195*275Sbill #define SEEK 04 /* Seek to cylinder */ 196264Sbill #define RECAL 06 /* Recalibrate, needed after seek error */ 197264Sbill #define DCLR 010 /* Drive clear, after error */ 198264Sbill #define WCOM 060 /* Write */ 199264Sbill #define RCOM 070 /* Read */ 200264Sbill 201264Sbill /* Other bits of upcs1 */ 202264Sbill #define IE 0100 /* Controller wide interrupt enable */ 203264Sbill #define TRE 040000 /* Transfer error */ 204266Sbill #define RDY 020 /* Transfer terminated */ 205264Sbill 206264Sbill /* Drive status bits of upds */ 207264Sbill #define PIP 020000 /* Positioning in progress */ 208264Sbill #define ERR 040000 /* Error has occurred, DCLR necessary */ 209264Sbill #define VV 0100 /* Volume is valid, set by PRESET */ 210264Sbill #define DPR 0400 /* Drive has been preset */ 211264Sbill #define MOL 010000 /* Drive is online, heads loaded, etc */ 212264Sbill #define DRY 0200 /* Drive ready */ 213264Sbill 214264Sbill /* Bits of uper1 */ 215264Sbill #define DCK 0100000 /* Ecc error occurred */ 216264Sbill #define ECH 0100 /* Ecc error was unrecoverable */ 217264Sbill #define WLE 04000 /* Attempt to write read-only drive */ 218264Sbill 219264Sbill /* Bits of upof; the offset bits above are also in this register */ 220264Sbill #define FMT22 010000 /* 16 bits/word, must be always set */ 221264Sbill 222264Sbill #define b_cylin b_resid 223264Sbill 224264Sbill int up_ubinfo; /* Information about UBA usage saved here */ 225264Sbill /* 226264Sbill * The EMULEX controller balks if accessed quickly after 227264Sbill * certain operations. The exact timing has not yet been 228264Sbill * determined, but delays are known to be needed when changing 229264Sbill * the selected drive (by writing in upcs2), and thought to be 230264Sbill * needed after operations like PRESET and DCLR. The following 231264Sbill * variables control the delay, DELAY(n) is approximately n usec. 232264Sbill */ 233264Sbill int idelay = 500; /* Delay after PRESET or DCLR */ 234268Sbill int sdelay = 150; /* Delay after selecting drive in upcs2 */ 235*275Sbill int rdelay = 100; /* Delay after SEARCH */ 236*275Sbill int asdel = 100; /* Delay after clearing bit in upas */ 237264Sbill 238*275Sbill int csdel2 = 0; /* ??? Delay in upstart ??? */ 239*275Sbill 240264Sbill #define DELAY(N) { register int d; d = N; while (--d > 0); } 241264Sbill 242264Sbill int nwaitcs2; /* How many sdelay loops ? */ 243264Sbill int neasycs2; /* How many sdelay loops not needed ? */ 244264Sbill 245264Sbill #ifdef INTRLVE 246264Sbill daddr_t dkblock(); 247264Sbill #endif 248264Sbill 249264Sbill /* 250264Sbill * Queue an i/o request for a drive, checking first that it is in range. 251264Sbill * 252264Sbill * A unit start is issued if the drive is inactive, causing 253264Sbill * a SEARCH for the correct cylinder/sector. If the drive is 254264Sbill * already nearly on the money and the controller is not transferring 255264Sbill * we kick it to start the transfer. 256264Sbill */ 257264Sbill upstrategy(bp) 258264Sbill register struct buf *bp; 259264Sbill { 260264Sbill register struct buf *dp; 261264Sbill register unit, xunit; 262264Sbill long sz, bn; 263264Sbill 264264Sbill xunit = minor(bp->b_dev) & 077; 265264Sbill sz = bp->b_bcount; 266264Sbill sz = (sz+511) >> 9; /* transfer size in 512 byte sectors */ 267264Sbill unit = dkunit(bp); 268264Sbill if (unit >= NUP || 269264Sbill bp->b_blkno < 0 || 270264Sbill (bn = dkblock(bp))+sz > up_sizes[xunit&07].nblocks) { 271264Sbill bp->b_flags |= B_ERROR; 272264Sbill iodone(bp); 273264Sbill return; 274264Sbill } 275264Sbill bp->b_cylin = bn/(NSECT*NTRAC) + up_sizes[xunit&07].cyloff; 276264Sbill dp = &uputab[unit]; 277264Sbill (void) spl5(); 278264Sbill disksort(dp, bp); 279264Sbill if (dp->b_active == 0) { 280268Sbill (void) upustart(unit); 281264Sbill if (uptab.b_actf && uptab.b_active == 0) 282268Sbill (void) upstart(); 283264Sbill } 284264Sbill (void) spl0(); 285264Sbill } 286264Sbill 287264Sbill /* 288264Sbill * Start activity on specified drive; called when drive is inactive 289264Sbill * and new transfer request arrives and also when upas indicates that 290264Sbill * a SEARCH command is complete. 291264Sbill */ 292264Sbill upustart(unit) 293264Sbill register unit; 294264Sbill { 295264Sbill register struct buf *bp, *dp; 296264Sbill register struct device *upaddr = UPADDR; 297264Sbill daddr_t bn; 298264Sbill int sn, cn, csn; 299268Sbill int didie = 0; 300264Sbill 301*275Sbill /* 302*275Sbill * Other drivers tend to say something like 303*275Sbill * upaddr->upcs1 = IE; 304*275Sbill * upaddr->upas = 1<<unit; 305*275Sbill * here, but the SC-11B will cancel a command which 306*275Sbill * happens to be sitting in the cs1 if you clear the go 307*275Sbill * bit by storing there (so the first is not safe), 308*275Sbill * and it also does not like being bothered with operations 309*275Sbill * such as clearing upas when a transfer is active (as 310*275Sbill * it may well be.) 311*275Sbill * 312*275Sbill * Thus we keep careful track of when we re-enable IE 313*275Sbill * after an interrupt and do it only if we didn't issue 314*275Sbill * a command which re-enabled it as a matter of course. 315*275Sbill * We clear bits in upas in the interrupt routine, when 316*275Sbill * no transfers are active. 317*275Sbill */ 318266Sbill if (unit >= NUP) 319268Sbill goto out; 320264Sbill if (unit+DK_N <= DK_NMAX) 321264Sbill dk_busy &= ~(1<<(unit+DK_N)); 322264Sbill dp = &uputab[unit]; 323266Sbill if ((bp = dp->b_actf) == NULL) 324268Sbill goto out; 325*275Sbill /* 326*275Sbill * The SC-11B doesn't start SEARCH commands when transfers are 327*275Sbill * in progress. In fact, it tends to get confused when given 328*275Sbill * SEARCH'es during transfers, generating interrupts with neither 329*275Sbill * RDY nor a bit in the upas register. Thus we defer 330*275Sbill * until an interrupt when a transfer is pending. 331*275Sbill */ 332*275Sbill if (uptab.b_active) { 333*275Sbill softas |= 1<<unit; 334*275Sbill return (0); 335*275Sbill } 336264Sbill if ((upaddr->upcs2 & 07) != unit) { 337264Sbill upaddr->upcs2 = unit; 338264Sbill DELAY(sdelay); 339264Sbill nwaitcs2++; 340264Sbill } else 341264Sbill neasycs2++; 342266Sbill /* 343266Sbill * If we have changed packs or just initialized, 344*275Sbill * then the volume will not be valid; if so, clear 345266Sbill * the drive, preset it and put in 16bit/word mode. 346266Sbill */ 347266Sbill if ((upaddr->upds & VV) == 0) { 348266Sbill upaddr->upcs1 = IE|DCLR|GO; 349266Sbill DELAY(idelay); 350264Sbill upaddr->upcs1 = IE|PRESET|GO; 351264Sbill DELAY(idelay); 352264Sbill upaddr->upof = FMT22; 353*275Sbill printf("VV done ds %o, er? %o %o %o\n", upaddr->upds, upaddr->uper1, upaddr->uper2, upaddr->uper3); 354268Sbill didie = 1; 355264Sbill } 356266Sbill if (dp->b_active) 357264Sbill goto done; 358266Sbill dp->b_active = 1; 359264Sbill if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) 360*275Sbill goto done; 361266Sbill /* 362266Sbill * Do enough of the disk address decoding to determine 363266Sbill * which cylinder and sector the request is on. 364266Sbill * If we are on the correct cylinder and the desired sector 365266Sbill * lies between SDIST and SDIST+RDIST sectors ahead of us, then 366266Sbill * we don't bother to SEARCH but just begin the transfer asap. 367*275Sbill * Otherwise ask for a interrupt SDIST+IDIST sectors ahead. 368266Sbill */ 369264Sbill bn = dkblock(bp); 370264Sbill cn = bp->b_cylin; 371264Sbill sn = bn%(NSECT*NTRAC); 372264Sbill sn = (sn+NSECT-SDIST)%NSECT; 373264Sbill 374266Sbill if (cn - upaddr->updc) 375266Sbill goto search; /* Not on-cylinder */ 376*275Sbill else if (upseek) 377*275Sbill goto done; /* Ok just to be on-cylinder */ 378264Sbill csn = (upaddr->upla>>6) - sn - 1; 379266Sbill if (csn < 0) 380264Sbill csn += NSECT; 381266Sbill if (csn > NSECT-RDIST) 382264Sbill goto done; 383264Sbill 384264Sbill search: 385264Sbill upaddr->updc = cn; 386*275Sbill if (upseek) 387*275Sbill upaddr->upcs1 = IE|SEEK|GO; 388*275Sbill else { 389*275Sbill upaddr->upda = sn; 390*275Sbill upaddr->upcs1 = IE|SEARCH|GO; 391*275Sbill } 392268Sbill didie = 1; 393266Sbill /* 394266Sbill * Mark this unit busy. 395266Sbill */ 396264Sbill unit += DK_N; 397264Sbill if (unit <= DK_NMAX) { 398264Sbill dk_busy |= 1<<unit; 399264Sbill dk_numb[unit]++; 400264Sbill } 401*275Sbill DELAY(rdelay); 402268Sbill goto out; 403264Sbill 404264Sbill done: 405266Sbill /* 406*275Sbill * This unit is ready to go so 407*275Sbill * link it onto the chain of ready disks. 408266Sbill */ 409264Sbill dp->b_forw = NULL; 410266Sbill if (uptab.b_actf == NULL) 411264Sbill uptab.b_actf = dp; 412264Sbill else 413264Sbill uptab.b_actl->b_forw = dp; 414264Sbill uptab.b_actl = dp; 415268Sbill 416268Sbill out: 417268Sbill return (didie); 418264Sbill } 419264Sbill 420264Sbill /* 421264Sbill * Start a transfer; call from top level at spl5() or on interrupt. 422264Sbill */ 423264Sbill upstart() 424264Sbill { 425264Sbill register struct buf *bp, *dp; 426264Sbill register unit; 427264Sbill register struct device *upaddr; 428264Sbill daddr_t bn; 429266Sbill int dn, sn, tn, cn, cmd; 430264Sbill 431264Sbill loop: 432272Sbill if (csdel2) DELAY(csdel2); 433266Sbill /* 434266Sbill * Pick a drive off the queue of ready drives, and 435266Sbill * perform the first transfer on its queue. 436266Sbill * 437266Sbill * Looping here is completely for the sake of drives which 438266Sbill * are not present and on-line, for which we completely clear the 439266Sbill * request queue. 440266Sbill */ 441273Sbill if ((dp = uptab.b_actf) == NULL) 442268Sbill return (0); 443264Sbill if ((bp = dp->b_actf) == NULL) { 444264Sbill uptab.b_actf = dp->b_forw; 445264Sbill goto loop; 446264Sbill } 447266Sbill /* 448266Sbill * Mark the controller busy, and multi-part disk address. 449266Sbill * Select the unit on which the i/o is to take place. 450266Sbill */ 451264Sbill uptab.b_active++; 452264Sbill unit = minor(bp->b_dev) & 077; 453264Sbill dn = dkunit(bp); 454264Sbill bn = dkblock(bp); 455264Sbill cn = up_sizes[unit&07].cyloff; 456264Sbill cn += bn/(NSECT*NTRAC); 457264Sbill sn = bn%(NSECT*NTRAC); 458264Sbill tn = sn/NSECT; 459266Sbill sn %= NSECT; 460264Sbill upaddr = UPADDR; 461264Sbill if ((upaddr->upcs2 & 07) != dn) { 462264Sbill upaddr->upcs2 = dn; 463*275Sbill /* DELAY(sdelay); Provided by ubasetup() */ 464264Sbill nwaitcs2++; 465264Sbill } else 466264Sbill neasycs2++; 467*275Sbill up_ubinfo = ubasetup(bp, 1); /* Providing delay */ 468266Sbill /* 469266Sbill * If drive is not present and on-line, then 470266Sbill * get rid of this with an error and loop to get 471266Sbill * rid of the rest of its queued requests. 472266Sbill * (Then on to any other ready drives.) 473266Sbill */ 474264Sbill if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) { 475*275Sbill printf("!DPR || !MOL, unit %d, ds %o\n", dn, upaddr->upds); 476264Sbill uptab.b_active = 0; 477264Sbill uptab.b_errcnt = 0; 478264Sbill dp->b_actf = bp->av_forw; 479266Sbill dp->b_active = 0; 480264Sbill bp->b_flags |= B_ERROR; 481264Sbill iodone(bp); 482266Sbill ubafree(up_ubinfo), up_ubinfo = 0; /* A funny place ... */ 483264Sbill goto loop; 484264Sbill } 485266Sbill /* 486266Sbill * If this is a retry, then with the 16'th retry we 487266Sbill * begin to try offsetting the heads to recover the data. 488266Sbill */ 489266Sbill if (uptab.b_errcnt >= 16) { 490264Sbill upaddr->upof = up_offset[uptab.b_errcnt & 017] | FMT22; 491266Sbill upaddr->upcs1 = IE|OFFSET|GO; 492264Sbill DELAY(idelay); 493266Sbill while (upaddr->upds & PIP) 494264Sbill DELAY(25); 495264Sbill } 496266Sbill /* 497266Sbill * Now set up the transfer, retrieving the high 498266Sbill * 2 bits of the UNIBUS address from the information 499266Sbill * returned by ubasetup() for the cs1 register bits 8 and 9. 500266Sbill */ 501264Sbill upaddr->updc = cn; 502264Sbill upaddr->upda = (tn << 8) + sn; 503264Sbill upaddr->upba = up_ubinfo; 504264Sbill upaddr->upwc = -bp->b_bcount / sizeof (short); 505266Sbill cmd = (up_ubinfo >> 8) & 0x300; 506264Sbill if (bp->b_flags & B_READ) 507266Sbill cmd |= IE|RCOM|GO; 508264Sbill else 509266Sbill cmd |= IE|WCOM|GO; 510266Sbill upaddr->upcs1 = cmd; 511266Sbill /* 512266Sbill * This is a controller busy situation. 513266Sbill * Record in dk slot NUP+DK_N (after last drive) 514266Sbill * unless there aren't that many slots reserved for 515266Sbill * us in which case we record this as a drive busy 516266Sbill * (if there is room for that). 517266Sbill */ 518264Sbill unit = dn+DK_N; 519264Sbill if (NUP+DK_N == DK_NMAX) 520264Sbill unit = NUP+DK_N; 521264Sbill if (unit <= DK_NMAX) { 522264Sbill dk_busy |= 1<<unit; 523264Sbill dk_numb[unit]++; 524264Sbill dk_wds[unit] += bp->b_bcount>>6; 525264Sbill } 526268Sbill return (1); 527264Sbill } 528264Sbill 529264Sbill /* 530264Sbill * Handle a device interrupt. 531264Sbill * 532264Sbill * If the transferring drive needs attention, service it 533264Sbill * retrying on error or beginning next transfer. 534264Sbill * Service all other ready drives, calling ustart to transfer 535264Sbill * their blocks to the ready queue in uptab, and then restart 536264Sbill * the controller if there is anything to do. 537264Sbill */ 538264Sbill upintr() 539264Sbill { 540264Sbill register struct buf *bp, *dp; 541264Sbill register unit; 542264Sbill register struct device *upaddr = UPADDR; 543264Sbill int as = upaddr->upas & 0377; 544272Sbill int osoftas; 545268Sbill int needie = 1; 546264Sbill 547266Sbill if (uptab.b_active) { 548266Sbill /* 549266Sbill * The drive is transferring, thus the hardware 550266Sbill * (say the designers) will only interrupt when the transfer 551266Sbill * completes; check for it anyways. 552266Sbill */ 553266Sbill if ((upaddr->upcs1 & RDY) == 0) { 554272Sbill printf("!RDY: cs1 %o, ds %o, wc %d\n", upaddr->upcs1, 555272Sbill upaddr->upds, upaddr->upwc); 556267Sbill printf("as=%d act %d %d %d\n", as, uptab.b_active, uputab[0].b_active, uputab[1].b_active); 557269Sbill } 558266Sbill /* 559266Sbill * Mark controller or drive not busy, and check for an 560266Sbill * error condition which may have resulted from the transfer. 561266Sbill */ 562264Sbill dp = uptab.b_actf; 563264Sbill bp = dp->b_actf; 564264Sbill unit = dkunit(bp); 565264Sbill if (DK_N+NUP == DK_NMAX) 566264Sbill dk_busy &= ~(1<<(DK_N+NUP)); 567264Sbill else if (DK_N+unit <= DK_NMAX) 568264Sbill dk_busy &= ~(1<<(DK_N+unit)); 569*275Sbill if ((upaddr->upcs2 & 07) != unit) { 570*275Sbill upaddr->upcs2 = unit; 571*275Sbill DELAY(sdelay); 572*275Sbill nwaitcs2++; 573*275Sbill } else 574*275Sbill neasycs2++; 575*275Sbill if (upaddr->upds & ERR) { 576266Sbill /* 577266Sbill * An error occurred, indeed. Select this unit 578266Sbill * to get at the drive status (a SEARCH may have 579266Sbill * intervened to change the selected unit), and 580266Sbill * wait for the command which caused the interrupt 581266Sbill * to complete (DRY). 582266Sbill */ 583266Sbill while ((upaddr->upds & DRY) == 0) 584264Sbill DELAY(25); 585266Sbill /* 586266Sbill * After 28 retries (16 w/o servo offsets, and then 587266Sbill * 12 with servo offsets), or if we encountered 588266Sbill * an error because the drive is write-protected, 589266Sbill * give up. Print an error message on the last 2 590266Sbill * retries before a hard failure. 591266Sbill */ 592266Sbill if (++uptab.b_errcnt > 28 || upaddr->uper1&WLE) 593264Sbill bp->b_flags |= B_ERROR; 594264Sbill else 595266Sbill uptab.b_active = 0; /* To force retry */ 596266Sbill if (uptab.b_errcnt > 27) 597264Sbill deverror(bp, upaddr->upcs2, upaddr->uper1); 598266Sbill /* 599266Sbill * If this was a correctible ECC error, let upecc 600266Sbill * do the dirty work to correct it. If upecc 601266Sbill * starts another READ for the rest of the data 602266Sbill * then it returns 1 (having set uptab.b_active). 603266Sbill * Otherwise we are done and fall through to 604266Sbill * finish up. 605266Sbill */ 606266Sbill if ((upaddr->uper1&(DCK|ECH))==DCK && upecc(upaddr, bp)) 607266Sbill return; 608266Sbill /* 609266Sbill * Clear the drive and, every 4 retries, recalibrate 610266Sbill * to hopefully help clear up seek positioning problems. 611266Sbill */ 612264Sbill upaddr->upcs1 = TRE|IE|DCLR|GO; 613264Sbill DELAY(idelay); 614268Sbill needie = 0; 615266Sbill if ((uptab.b_errcnt&07) == 4) { 616264Sbill upaddr->upcs1 = RECAL|GO|IE; 617264Sbill DELAY(idelay); 618264Sbill while(upaddr->upds & PIP) 619264Sbill DELAY(25); 620264Sbill } 621264Sbill } 622266Sbill /* 623266Sbill * If we are still noted as active, then no 624266Sbill * (further) retries are necessary. 625266Sbill * 626266Sbill * Make sure the correct unit is selected, 627266Sbill * return it to centerline if necessary, and mark 628266Sbill * this i/o complete, starting the next transfer 629266Sbill * on this drive with the upustart routine (if any). 630266Sbill */ 631266Sbill if (uptab.b_active) { 632266Sbill if ((upaddr->upcs2 & 07) != unit) { 633266Sbill upaddr->upcs2 = unit; 634266Sbill DELAY(sdelay); 635266Sbill nwaitcs2++; 636266Sbill } else 637266Sbill neasycs2++; 638266Sbill if (uptab.b_errcnt >= 16) { 639266Sbill upaddr->upcs1 = RTC|GO|IE; 640264Sbill DELAY(idelay); 641266Sbill while (upaddr->upds & PIP) 642264Sbill DELAY(25); 643268Sbill needie = 0; 644264Sbill } 645264Sbill uptab.b_active = 0; 646264Sbill uptab.b_errcnt = 0; 647264Sbill uptab.b_actf = dp->b_forw; 648264Sbill dp->b_active = 0; 649264Sbill dp->b_errcnt = 0; 650264Sbill dp->b_actf = bp->av_forw; 651266Sbill bp->b_resid = (-upaddr->upwc * sizeof(short)); 652*275Sbill if (bp->b_resid) 653*275Sbill printf("resid %d ds %o er? %o %o %o\n", bp->b_resid, upaddr->upds, 654*275Sbill upaddr->uper1, upaddr->uper2, upaddr->uper3); 655264Sbill iodone(bp); 656264Sbill if(dp->b_actf) 657268Sbill if (upustart(unit)) 658268Sbill needie = 0; 659264Sbill } 660264Sbill as &= ~(1<<unit); 661272Sbill softas &= ~(1<<unit); 662264Sbill ubafree(up_ubinfo), up_ubinfo = 0; 663273Sbill } else { 664264Sbill if (upaddr->upcs1 & TRE) { 665264Sbill upaddr->upcs1 = TRE; 666264Sbill DELAY(idelay); 667264Sbill } 668264Sbill } 669266Sbill /* 670266Sbill * If we have a unit with an outstanding SEARCH, 671266Sbill * and the hardware indicates the unit requires attention, 672266Sbill * the bring the drive to the ready queue. 673266Sbill * Finally, if the controller is not transferring 674266Sbill * start it if any drives are now ready to transfer. 675266Sbill */ 676272Sbill as |= softas; 677272Sbill osoftas = softas; 678272Sbill softas = 0; 679266Sbill for (unit = 0; unit < NUP; unit++) 680273Sbill if ((as|osoftas) & (1<<unit)) { 681273Sbill if (as & (1<<unit)) { 682267Sbill upaddr->upas = 1<<unit; 683268Sbill if (asdel) DELAY(asdel); 684272Sbill } 685273Sbill if (upustart(unit)) 686273Sbill needie = 0; 687273Sbill } 688266Sbill if (uptab.b_actf && uptab.b_active == 0) 689268Sbill if (upstart()) 690268Sbill needie = 0; 691266Sbill out: 692*275Sbill if (needie) 693266Sbill upaddr->upcs1 = IE; 694264Sbill } 695264Sbill 696264Sbill upread(dev) 697264Sbill { 698264Sbill 699264Sbill physio(upstrategy, &rupbuf, dev, B_READ, minphys); 700264Sbill } 701264Sbill 702264Sbill upwrite(dev) 703264Sbill { 704264Sbill 705264Sbill physio(upstrategy, &rupbuf, dev, B_WRITE, minphys); 706264Sbill } 707264Sbill 708266Sbill /* 709266Sbill * Correct an ECC error, and restart the i/o to complete 710266Sbill * the transfer if necessary. This is quite complicated because 711266Sbill * the transfer may be going to an odd memory address base and/or 712266Sbill * across a page boundary. 713266Sbill */ 714264Sbill upecc(up, bp) 715264Sbill register struct device *up; 716264Sbill register struct buf *bp; 717264Sbill { 718264Sbill struct uba_regs *ubp = (struct uba_regs *)UBA0; 719266Sbill register int i; 720264Sbill caddr_t addr; 721266Sbill int reg, bit, byte, npf, mask, o, cmd, ubaddr; 722264Sbill int bn, cn, tn, sn; 723264Sbill 724264Sbill /* 725266Sbill * Npf is the number of sectors transferred before the sector 726266Sbill * containing the ECC error, and reg is the UBA register 727266Sbill * mapping (the first part of) the transfer. 728266Sbill * O is offset within a memory page of the first byte transferred. 729264Sbill */ 730266Sbill npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1; 731266Sbill reg = btop(up_ubinfo&0x3ffff) + npf; 732264Sbill o = (int)bp->b_un.b_addr & PGOFSET; 733264Sbill printf("%D ", bp->b_blkno+npf); 734264Sbill prdev("ECC", bp->b_dev); 735264Sbill mask = up->upec2; 736264Sbill if (mask == 0) { 737266Sbill up->upof = FMT22; /* == RTC ???? */ 738264Sbill DELAY(idelay); 739264Sbill return (0); 740264Sbill } 741266Sbill /* 742266Sbill * Flush the buffered data path, and compute the 743266Sbill * byte and bit position of the error. The variable i 744266Sbill * is the byte offset in the transfer, the variable byte 745266Sbill * is the offset from a page boundary in main memory. 746266Sbill */ 747266Sbill ubp->uba_dpr[(up_ubinfo>>28)&0x0f] |= BNE; 748266Sbill i = up->upec1 - 1; /* -1 makes 0 origin */ 749266Sbill bit = i&07; 750266Sbill i = (i&~07)>>3; 751264Sbill byte = i + o; 752266Sbill /* 753266Sbill * Correct while possible bits remain of mask. Since mask 754266Sbill * contains 11 bits, we continue while the bit offset is > -11. 755266Sbill * Also watch out for end of this block and the end of the whole 756266Sbill * transfer. 757266Sbill */ 758266Sbill while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 759266Sbill addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ 760266Sbill (byte & PGOFSET); 761266Sbill putmemc(addr, getmemc(addr)^(mask<<bit)); 762266Sbill byte++; 763266Sbill i++; 764266Sbill bit -= 8; 765264Sbill } 766266Sbill uptab.b_active++; /* Either complete or continuing... */ 767264Sbill if (up->upwc == 0) 768264Sbill return (0); 769266Sbill /* 770266Sbill * Have to continue the transfer... clear the drive, 771266Sbill * and compute the position where the transfer is to continue. 772266Sbill * We have completed npf+1 sectors of the transfer already; 773266Sbill * restart at offset o of next sector (i.e. in UBA register reg+1). 774266Sbill */ 775266Sbill up->upcs1 = TRE|IE|DCLR|GO; 776264Sbill DELAY(idelay); 777264Sbill bn = dkblock(bp); 778264Sbill cn = bp->b_cylin; 779266Sbill sn = bn%(NSECT*NTRAC) + npf + 1; 780264Sbill tn = sn/NSECT; 781264Sbill sn %= NSECT; 782266Sbill cn += tn/NTRAC; 783266Sbill tn %= NTRAC; 784264Sbill up->updc = cn; 785266Sbill up->upda = (tn << 8) | sn; 786266Sbill ubaddr = (int)ptob(reg+1) + o; 787266Sbill up->upba = ubaddr; 788266Sbill cmd = (ubaddr >> 8) & 0x300; 789266Sbill cmd |= IE|GO|RCOM; 790266Sbill up->upcs1 = cmd; 791264Sbill return (1); 792264Sbill } 793