1*313Sbill /* 10/14/12 3.15 06/26/80 */ 2264Sbill 3308Sbill #define spl5 spl6 /* block clock, for delay loop's sake */ 4264Sbill /* 5264Sbill * Emulex UNIBUS disk driver with overlapped seeks and ECC recovery. 6264Sbill * 7266Sbill * NB: This device is very sensitive: be aware that the code is the way 8266Sbill * it is for good reason and that there are delay loops here which may 9266Sbill * have to be lengthened if your processor is faster and which should 10266Sbill * probably be shortened if your processor is slower. 11266Sbill * 12264Sbill * This driver has been tested on a SC-11B Controller, configured 13264Sbill * with the following internal switch settings: 14264Sbill * SW1-1 5/19 surfaces (off, 19 surfaces on Ampex 9300) 15264Sbill * SW1-2 chksum enable (off, checksum disabled) 16264Sbill * SW1-3 volume select (off, 815 cylinders) 17264Sbill * SW1-4 sector select (on, 32 sectors) 18264Sbill * SW1-5 unused (off) 19264Sbill * SW1-6 port select (on, single port) 20264Sbill * SW1-7 npr delay (off, disable) 21264Sbill * SW1-8 ecc test mode (off, disable) 22264Sbill * and top mounted switches: 23264Sbill * SW2-1 extend opcodes (off=open, disable) 24264Sbill * SW2-2 extend diag (off=open, disable) 25264Sbill * SW2-3 4 wd dma burst (off=open, disable) 26264Sbill * SW2-4 unused (off=open) 27264Sbill * 28264Sbill * The controller transfers data much more rapidly with SW2-3 set, 29264Sbill * but we have previously experienced problems with it set this way. 30264Sbill * We intend to try this again in the near future. 31264Sbill * 32308Sbill * NB: OUR SYSTEM CURRENTLY GETS UBA ERRORS WHEN RUNNING THIS DRIVER 33308Sbill * AND THE BUS OCCASIONALLY HANGS, NECESSITATING THE DEVIE RESET 34308Sbill * CODE WHICH RE-INITS THE UNIBUS. YECHHH. 35264Sbill */ 36264Sbill 37264Sbill #include "../h/param.h" 38264Sbill #include "../h/systm.h" 39308Sbill #include "../h/dk.h" 40264Sbill #include "../h/buf.h" 41264Sbill #include "../h/conf.h" 42264Sbill #include "../h/dir.h" 43264Sbill #include "../h/user.h" 44264Sbill #include "../h/map.h" 45264Sbill #include "../h/mba.h" 46264Sbill #include "../h/mtpr.h" 47264Sbill #include "../h/pte.h" 48264Sbill #include "../h/uba.h" 49264Sbill #include "../h/vm.h" 50264Sbill 51264Sbill /* 52264Sbill * Define number of drives, and range of sampling information to be used. 53264Sbill * 54264Sbill * Normally, DK_N .. DK_N+NUP-1 gather individual drive stats, 55264Sbill * and DK_N+NUP gathers controller transferring stats. 56264Sbill * 57264Sbill * If DK_N+NUP > DK_NMAX, then transfer stats are divided per drive. 58264Sbill * If DK_NMAX is yet smaller, some drives are not monitored. 59264Sbill */ 60308Sbill #define DK_N 2 61308Sbill #define DK_NMAX 3 62264Sbill 63264Sbill #define ushort unsigned short 64264Sbill 65264Sbill struct device 66264Sbill { 67264Sbill ushort upcs1; /* control and status register 1 */ 68264Sbill short upwc; /* word count register */ 69264Sbill ushort upba; /* UNIBUS address register */ 70264Sbill ushort upda; /* desired address register */ 71264Sbill ushort upcs2; /* control and status register 2 */ 72264Sbill ushort upds; /* drive Status */ 73264Sbill ushort uper1; /* error register 1 */ 74264Sbill ushort upas; /* attention summary */ 75264Sbill ushort upla; /* look ahead */ 76264Sbill ushort updb; /* data buffer */ 77264Sbill ushort upmr; /* maintenance */ 78264Sbill ushort updt; /* drive type */ 79264Sbill ushort upsn; /* serial number */ 80264Sbill ushort upof; /* offset register */ 81264Sbill ushort updc; /* desired cylinder address register */ 82264Sbill ushort upcc; /* current cylinder */ 83264Sbill ushort uper2; /* error register 2 */ 84264Sbill ushort uper3; /* error register 3 */ 85264Sbill ushort upec1; /* burst error bit position */ 86264Sbill ushort upec2; /* burst error bit pattern */ 87264Sbill }; 88264Sbill 89275Sbill /* 90275Sbill * Software extension to the upas register, so we can 91275Sbill * postpone starting SEARCH commands until the controller 92275Sbill * is not transferring. 93275Sbill */ 94275Sbill int softas; 95275Sbill 96275Sbill /* 97275Sbill * If upseek then we don't issue SEARCH commands but rather just 98275Sbill * settle for a SEEK to the correct cylinder. 99275Sbill */ 100275Sbill int upseek; 101275Sbill 102264Sbill #define UPADDR ((struct device *)(UBA0_DEV + 0176700)) 103264Sbill 104264Sbill #define NUP 2 /* Number of drives this installation */ 105264Sbill 106264Sbill #define NSECT 32 107264Sbill #define NTRAC 19 108264Sbill 109264Sbill /* 110264Sbill * Constants controlling on-cylinder SEARCH usage. 111264Sbill * 112308Sbill * upSDIST/2 msec time needed to start transfer 113308Sbill * upRDIST/2 msec tolerable rotational latency when on-cylinder 114275Sbill * 115308Sbill * If we are no closer than upSDIST sectors and no further than upSDIST+upRDIST 116275Sbill * and in the driver then we take it as it is. Otherwise we do a SEARCH 117308Sbill * requesting an interrupt upSDIST sectors in advance. 118264Sbill */ 119308Sbill #define _upSDIST 6 /* 3.0 msec */ 120308Sbill #define _upRDIST 6 /* 3.0 msec */ 121264Sbill 122308Sbill int upSDIST = _upSDIST; 123308Sbill int upRDIST = _upRDIST; 124275Sbill 125264Sbill /* 126264Sbill * To fill a 300M drive: 127264Sbill * A is designed to be used as a root. 128264Sbill * B is suitable for a swap area. 129264Sbill * H is the primary storage area. 130264Sbill * On systems with RP06'es, we normally use only 291346 blocks of the H 131264Sbill * area, and use DEF or G to cover the rest of the drive. The C system 132264Sbill * covers the whole drive and can be used for pack-pack copying. 133264Sbill */ 134264Sbill struct size 135264Sbill { 136264Sbill daddr_t nblocks; 137264Sbill int cyloff; 138264Sbill } up_sizes[8] = { 139264Sbill 15884, 0, /* A=cyl 0 thru 26 */ 140264Sbill 33440, 27, /* B=cyl 27 thru 81 */ 141264Sbill 494912, 0, /* C=cyl 0 thru 814 */ 142264Sbill 15884, 562, /* D=cyl 562 thru 588 */ 143264Sbill 55936, 589, /* E=cyl 589 thru 680 */ 144264Sbill 81472, 681, /* F=cyl 681 thru 814 */ 145264Sbill 153824, 562, /* G=cyl 562 thru 814 */ 146264Sbill 445664, 82, /* H=cyl 82 thru 814 */ 147264Sbill /* Later, and more safely for H area... 148264Sbill 291346, 82, /* H=cyl 82 thru 561 */ 149264Sbill }; 150264Sbill 151264Sbill /* 152264Sbill * The following defines are used in offset positioning 153264Sbill * when trying to recover disk errors, with the constants being 154264Sbill * +/- microinches. Note that header compare inhibit (HCI) is not 155264Sbill * tried (this makes sense only during read, in any case.) 156264Sbill * 157264Sbill * ARE ALL THESE IMPLEMENTED ON 9300? 158264Sbill */ 159264Sbill #define P400 020 160264Sbill #define M400 0220 161264Sbill #define P800 040 162264Sbill #define M800 0240 163264Sbill #define P1200 060 164264Sbill #define M1200 0260 165264Sbill #define HCI 020000 166264Sbill 167264Sbill int up_offset[16] = 168264Sbill { 169264Sbill P400, M400, P400, M400, 170264Sbill P800, M800, P800, M800, 171264Sbill P1200, M1200, P1200, M1200, 172264Sbill 0, 0, 0, 0, 173264Sbill }; 174264Sbill 175264Sbill /* 176264Sbill * Each drive has a table uputab[i]. On this table are sorted the 177264Sbill * pending requests implementing an elevator algorithm (see dsort.c.) 178264Sbill * In the upustart() routine, each drive is independently advanced 179264Sbill * until it is on the desired cylinder for the next transfer and near 180264Sbill * the desired sector. The drive is then chained onto the uptab 181264Sbill * table, and the transfer is initiated by the upstart() routine. 182264Sbill * When the transfer is completed the driver reinvokes the upustart() 183264Sbill * routine to set up the next transfer. 184264Sbill */ 185264Sbill struct buf uptab; 186264Sbill struct buf uputab[NUP]; 187264Sbill 188264Sbill struct buf rupbuf; /* Buffer for raw i/o */ 189264Sbill 190264Sbill /* Drive commands, placed in upcs1 */ 191264Sbill #define GO 01 /* Go bit, set in all commands */ 192264Sbill #define PRESET 020 /* Preset drive at init or after errors */ 193264Sbill #define OFFSET 014 /* Offset heads to try to recover error */ 194264Sbill #define RTC 016 /* Return to center-line after OFFSET */ 195264Sbill #define SEARCH 030 /* Search for cylinder+sector */ 196275Sbill #define SEEK 04 /* Seek to cylinder */ 197264Sbill #define RECAL 06 /* Recalibrate, needed after seek error */ 198264Sbill #define DCLR 010 /* Drive clear, after error */ 199264Sbill #define WCOM 060 /* Write */ 200264Sbill #define RCOM 070 /* Read */ 201264Sbill 202264Sbill /* Other bits of upcs1 */ 203264Sbill #define IE 0100 /* Controller wide interrupt enable */ 204264Sbill #define TRE 040000 /* Transfer error */ 205266Sbill #define RDY 020 /* Transfer terminated */ 206264Sbill 207264Sbill /* Drive status bits of upds */ 208264Sbill #define PIP 020000 /* Positioning in progress */ 209264Sbill #define ERR 040000 /* Error has occurred, DCLR necessary */ 210264Sbill #define VV 0100 /* Volume is valid, set by PRESET */ 211264Sbill #define DPR 0400 /* Drive has been preset */ 212264Sbill #define MOL 010000 /* Drive is online, heads loaded, etc */ 213264Sbill #define DRY 0200 /* Drive ready */ 214264Sbill 215*313Sbill /* Bits of upcs2 */ 216*313Sbill #define CLR 040 /* Controller clear */ 217264Sbill /* Bits of uper1 */ 218264Sbill #define DCK 0100000 /* Ecc error occurred */ 219264Sbill #define ECH 0100 /* Ecc error was unrecoverable */ 220264Sbill #define WLE 04000 /* Attempt to write read-only drive */ 221264Sbill 222264Sbill /* Bits of upof; the offset bits above are also in this register */ 223264Sbill #define FMT22 010000 /* 16 bits/word, must be always set */ 224264Sbill 225264Sbill #define b_cylin b_resid 226264Sbill 227264Sbill int up_ubinfo; /* Information about UBA usage saved here */ 228264Sbill /* 229264Sbill * The EMULEX controller balks if accessed quickly after 230264Sbill * certain operations. The exact timing has not yet been 231264Sbill * determined, but delays are known to be needed when changing 232264Sbill * the selected drive (by writing in upcs2), and thought to be 233264Sbill * needed after operations like PRESET and DCLR. The following 234264Sbill * variables control the delay, DELAY(n) is approximately n usec. 235264Sbill */ 236264Sbill int idelay = 500; /* Delay after PRESET or DCLR */ 237268Sbill int sdelay = 150; /* Delay after selecting drive in upcs2 */ 238275Sbill int rdelay = 100; /* Delay after SEARCH */ 239275Sbill int asdel = 100; /* Delay after clearing bit in upas */ 240264Sbill 241275Sbill int csdel2 = 0; /* ??? Delay in upstart ??? */ 242275Sbill 243264Sbill #define DELAY(N) { register int d; d = N; while (--d > 0); } 244264Sbill 245264Sbill int nwaitcs2; /* How many sdelay loops ? */ 246264Sbill int neasycs2; /* How many sdelay loops not needed ? */ 247264Sbill 248*313Sbill int up_wticks; /* Ticks waiting for interrupt */ 249*313Sbill int upwstart; /* Have started guardian */ 250*313Sbill int upwatch(); 251*313Sbill 252264Sbill #ifdef INTRLVE 253264Sbill daddr_t dkblock(); 254264Sbill #endif 255264Sbill 256264Sbill /* 257264Sbill * Queue an i/o request for a drive, checking first that it is in range. 258264Sbill * 259264Sbill * A unit start is issued if the drive is inactive, causing 260264Sbill * a SEARCH for the correct cylinder/sector. If the drive is 261264Sbill * already nearly on the money and the controller is not transferring 262264Sbill * we kick it to start the transfer. 263264Sbill */ 264264Sbill upstrategy(bp) 265264Sbill register struct buf *bp; 266264Sbill { 267264Sbill register struct buf *dp; 268264Sbill register unit, xunit; 269264Sbill long sz, bn; 270264Sbill 271*313Sbill if (upwstart == 0) { 272*313Sbill timeout((caddr_t)upwatch, 0, HZ); 273*313Sbill upwstart++; 274*313Sbill } 275264Sbill xunit = minor(bp->b_dev) & 077; 276264Sbill sz = bp->b_bcount; 277264Sbill sz = (sz+511) >> 9; /* transfer size in 512 byte sectors */ 278264Sbill unit = dkunit(bp); 279264Sbill if (unit >= NUP || 280264Sbill bp->b_blkno < 0 || 281264Sbill (bn = dkblock(bp))+sz > up_sizes[xunit&07].nblocks) { 282264Sbill bp->b_flags |= B_ERROR; 283264Sbill iodone(bp); 284264Sbill return; 285264Sbill } 286264Sbill bp->b_cylin = bn/(NSECT*NTRAC) + up_sizes[xunit&07].cyloff; 287264Sbill dp = &uputab[unit]; 288264Sbill (void) spl5(); 289264Sbill disksort(dp, bp); 290264Sbill if (dp->b_active == 0) { 291268Sbill (void) upustart(unit); 292264Sbill if (uptab.b_actf && uptab.b_active == 0) 293268Sbill (void) upstart(); 294264Sbill } 295264Sbill (void) spl0(); 296264Sbill } 297264Sbill 298264Sbill /* 299264Sbill * Start activity on specified drive; called when drive is inactive 300264Sbill * and new transfer request arrives and also when upas indicates that 301264Sbill * a SEARCH command is complete. 302264Sbill */ 303264Sbill upustart(unit) 304264Sbill register unit; 305264Sbill { 306264Sbill register struct buf *bp, *dp; 307264Sbill register struct device *upaddr = UPADDR; 308264Sbill daddr_t bn; 309264Sbill int sn, cn, csn; 310268Sbill int didie = 0; 311264Sbill 312275Sbill /* 313275Sbill * Other drivers tend to say something like 314275Sbill * upaddr->upcs1 = IE; 315275Sbill * upaddr->upas = 1<<unit; 316275Sbill * here, but the SC-11B will cancel a command which 317275Sbill * happens to be sitting in the cs1 if you clear the go 318275Sbill * bit by storing there (so the first is not safe), 319275Sbill * and it also does not like being bothered with operations 320275Sbill * such as clearing upas when a transfer is active (as 321275Sbill * it may well be.) 322275Sbill * 323275Sbill * Thus we keep careful track of when we re-enable IE 324275Sbill * after an interrupt and do it only if we didn't issue 325275Sbill * a command which re-enabled it as a matter of course. 326275Sbill * We clear bits in upas in the interrupt routine, when 327275Sbill * no transfers are active. 328275Sbill */ 329266Sbill if (unit >= NUP) 330268Sbill goto out; 331264Sbill if (unit+DK_N <= DK_NMAX) 332264Sbill dk_busy &= ~(1<<(unit+DK_N)); 333264Sbill dp = &uputab[unit]; 334266Sbill if ((bp = dp->b_actf) == NULL) 335268Sbill goto out; 336275Sbill /* 337275Sbill * The SC-11B doesn't start SEARCH commands when transfers are 338275Sbill * in progress. In fact, it tends to get confused when given 339275Sbill * SEARCH'es during transfers, generating interrupts with neither 340275Sbill * RDY nor a bit in the upas register. Thus we defer 341275Sbill * until an interrupt when a transfer is pending. 342275Sbill */ 343275Sbill if (uptab.b_active) { 344275Sbill softas |= 1<<unit; 345275Sbill return (0); 346275Sbill } 347276Sbill if (dp->b_active) 348276Sbill goto done; 349276Sbill dp->b_active = 1; 350264Sbill if ((upaddr->upcs2 & 07) != unit) { 351264Sbill upaddr->upcs2 = unit; 352264Sbill DELAY(sdelay); 353264Sbill nwaitcs2++; 354264Sbill } else 355264Sbill neasycs2++; 356266Sbill /* 357266Sbill * If we have changed packs or just initialized, 358275Sbill * then the volume will not be valid; if so, clear 359266Sbill * the drive, preset it and put in 16bit/word mode. 360266Sbill */ 361266Sbill if ((upaddr->upds & VV) == 0) { 362266Sbill upaddr->upcs1 = IE|DCLR|GO; 363266Sbill DELAY(idelay); 364264Sbill upaddr->upcs1 = IE|PRESET|GO; 365264Sbill DELAY(idelay); 366264Sbill upaddr->upof = FMT22; 367275Sbill printf("VV done ds %o, er? %o %o %o\n", upaddr->upds, upaddr->uper1, upaddr->uper2, upaddr->uper3); 368268Sbill didie = 1; 369264Sbill } 370264Sbill if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) 371275Sbill goto done; 372266Sbill /* 373266Sbill * Do enough of the disk address decoding to determine 374266Sbill * which cylinder and sector the request is on. 375266Sbill * If we are on the correct cylinder and the desired sector 376308Sbill * lies between upSDIST and upSDIST+upRDIST sectors ahead of us, then 377266Sbill * we don't bother to SEARCH but just begin the transfer asap. 378308Sbill * Otherwise ask for a interrupt upSDIST sectors ahead. 379266Sbill */ 380264Sbill bn = dkblock(bp); 381264Sbill cn = bp->b_cylin; 382264Sbill sn = bn%(NSECT*NTRAC); 383308Sbill sn = (sn+NSECT-upSDIST)%NSECT; 384264Sbill 385266Sbill if (cn - upaddr->updc) 386266Sbill goto search; /* Not on-cylinder */ 387275Sbill else if (upseek) 388275Sbill goto done; /* Ok just to be on-cylinder */ 389264Sbill csn = (upaddr->upla>>6) - sn - 1; 390266Sbill if (csn < 0) 391264Sbill csn += NSECT; 392308Sbill if (csn > NSECT-upRDIST) 393264Sbill goto done; 394264Sbill 395264Sbill search: 396264Sbill upaddr->updc = cn; 397275Sbill if (upseek) 398275Sbill upaddr->upcs1 = IE|SEEK|GO; 399275Sbill else { 400275Sbill upaddr->upda = sn; 401275Sbill upaddr->upcs1 = IE|SEARCH|GO; 402275Sbill } 403268Sbill didie = 1; 404266Sbill /* 405266Sbill * Mark this unit busy. 406266Sbill */ 407264Sbill unit += DK_N; 408264Sbill if (unit <= DK_NMAX) { 409264Sbill dk_busy |= 1<<unit; 410264Sbill dk_numb[unit]++; 411264Sbill } 412275Sbill DELAY(rdelay); 413268Sbill goto out; 414264Sbill 415264Sbill done: 416266Sbill /* 417275Sbill * This unit is ready to go so 418275Sbill * link it onto the chain of ready disks. 419266Sbill */ 420264Sbill dp->b_forw = NULL; 421266Sbill if (uptab.b_actf == NULL) 422264Sbill uptab.b_actf = dp; 423264Sbill else 424264Sbill uptab.b_actl->b_forw = dp; 425264Sbill uptab.b_actl = dp; 426268Sbill 427268Sbill out: 428268Sbill return (didie); 429264Sbill } 430264Sbill 431264Sbill /* 432264Sbill * Start a transfer; call from top level at spl5() or on interrupt. 433264Sbill */ 434264Sbill upstart() 435264Sbill { 436264Sbill register struct buf *bp, *dp; 437264Sbill register unit; 438264Sbill register struct device *upaddr; 439264Sbill daddr_t bn; 440266Sbill int dn, sn, tn, cn, cmd; 441264Sbill 442264Sbill loop: 443272Sbill if (csdel2) DELAY(csdel2); 444266Sbill /* 445266Sbill * Pick a drive off the queue of ready drives, and 446266Sbill * perform the first transfer on its queue. 447266Sbill * 448266Sbill * Looping here is completely for the sake of drives which 449266Sbill * are not present and on-line, for which we completely clear the 450266Sbill * request queue. 451266Sbill */ 452273Sbill if ((dp = uptab.b_actf) == NULL) 453268Sbill return (0); 454264Sbill if ((bp = dp->b_actf) == NULL) { 455264Sbill uptab.b_actf = dp->b_forw; 456264Sbill goto loop; 457264Sbill } 458266Sbill /* 459266Sbill * Mark the controller busy, and multi-part disk address. 460266Sbill * Select the unit on which the i/o is to take place. 461266Sbill */ 462264Sbill uptab.b_active++; 463264Sbill unit = minor(bp->b_dev) & 077; 464264Sbill dn = dkunit(bp); 465264Sbill bn = dkblock(bp); 466264Sbill cn = up_sizes[unit&07].cyloff; 467264Sbill cn += bn/(NSECT*NTRAC); 468264Sbill sn = bn%(NSECT*NTRAC); 469264Sbill tn = sn/NSECT; 470266Sbill sn %= NSECT; 471264Sbill upaddr = UPADDR; 472264Sbill if ((upaddr->upcs2 & 07) != dn) { 473264Sbill upaddr->upcs2 = dn; 474275Sbill /* DELAY(sdelay); Provided by ubasetup() */ 475264Sbill nwaitcs2++; 476264Sbill } else 477264Sbill neasycs2++; 478275Sbill up_ubinfo = ubasetup(bp, 1); /* Providing delay */ 479266Sbill /* 480266Sbill * If drive is not present and on-line, then 481266Sbill * get rid of this with an error and loop to get 482266Sbill * rid of the rest of its queued requests. 483266Sbill * (Then on to any other ready drives.) 484266Sbill */ 485264Sbill if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) { 486275Sbill printf("!DPR || !MOL, unit %d, ds %o\n", dn, upaddr->upds); 487264Sbill uptab.b_active = 0; 488264Sbill uptab.b_errcnt = 0; 489264Sbill dp->b_actf = bp->av_forw; 490266Sbill dp->b_active = 0; 491264Sbill bp->b_flags |= B_ERROR; 492264Sbill iodone(bp); 493266Sbill ubafree(up_ubinfo), up_ubinfo = 0; /* A funny place ... */ 494264Sbill goto loop; 495264Sbill } 496266Sbill /* 497266Sbill * If this is a retry, then with the 16'th retry we 498266Sbill * begin to try offsetting the heads to recover the data. 499266Sbill */ 500266Sbill if (uptab.b_errcnt >= 16) { 501264Sbill upaddr->upof = up_offset[uptab.b_errcnt & 017] | FMT22; 502266Sbill upaddr->upcs1 = IE|OFFSET|GO; 503264Sbill DELAY(idelay); 504266Sbill while (upaddr->upds & PIP) 505264Sbill DELAY(25); 506264Sbill } 507266Sbill /* 508266Sbill * Now set up the transfer, retrieving the high 509266Sbill * 2 bits of the UNIBUS address from the information 510266Sbill * returned by ubasetup() for the cs1 register bits 8 and 9. 511266Sbill */ 512264Sbill upaddr->updc = cn; 513264Sbill upaddr->upda = (tn << 8) + sn; 514264Sbill upaddr->upba = up_ubinfo; 515264Sbill upaddr->upwc = -bp->b_bcount / sizeof (short); 516266Sbill cmd = (up_ubinfo >> 8) & 0x300; 517264Sbill if (bp->b_flags & B_READ) 518266Sbill cmd |= IE|RCOM|GO; 519264Sbill else 520266Sbill cmd |= IE|WCOM|GO; 521266Sbill upaddr->upcs1 = cmd; 522266Sbill /* 523266Sbill * This is a controller busy situation. 524266Sbill * Record in dk slot NUP+DK_N (after last drive) 525266Sbill * unless there aren't that many slots reserved for 526266Sbill * us in which case we record this as a drive busy 527266Sbill * (if there is room for that). 528266Sbill */ 529264Sbill unit = dn+DK_N; 530264Sbill if (NUP+DK_N == DK_NMAX) 531264Sbill unit = NUP+DK_N; 532264Sbill if (unit <= DK_NMAX) { 533264Sbill dk_busy |= 1<<unit; 534264Sbill dk_numb[unit]++; 535264Sbill dk_wds[unit] += bp->b_bcount>>6; 536264Sbill } 537268Sbill return (1); 538264Sbill } 539264Sbill 540264Sbill /* 541264Sbill * Handle a device interrupt. 542264Sbill * 543264Sbill * If the transferring drive needs attention, service it 544264Sbill * retrying on error or beginning next transfer. 545264Sbill * Service all other ready drives, calling ustart to transfer 546264Sbill * their blocks to the ready queue in uptab, and then restart 547264Sbill * the controller if there is anything to do. 548264Sbill */ 549264Sbill upintr() 550264Sbill { 551264Sbill register struct buf *bp, *dp; 552264Sbill register unit; 553264Sbill register struct device *upaddr = UPADDR; 554264Sbill int as = upaddr->upas & 0377; 555272Sbill int osoftas; 556268Sbill int needie = 1; 557264Sbill 558276Sbill (void) spl6(); 559*313Sbill up_wticks = 0; 560266Sbill if (uptab.b_active) { 561266Sbill /* 562266Sbill * The drive is transferring, thus the hardware 563266Sbill * (say the designers) will only interrupt when the transfer 564266Sbill * completes; check for it anyways. 565266Sbill */ 566266Sbill if ((upaddr->upcs1 & RDY) == 0) { 567272Sbill printf("!RDY: cs1 %o, ds %o, wc %d\n", upaddr->upcs1, 568272Sbill upaddr->upds, upaddr->upwc); 569267Sbill printf("as=%d act %d %d %d\n", as, uptab.b_active, uputab[0].b_active, uputab[1].b_active); 570269Sbill } 571266Sbill /* 572266Sbill * Mark controller or drive not busy, and check for an 573266Sbill * error condition which may have resulted from the transfer. 574266Sbill */ 575264Sbill dp = uptab.b_actf; 576264Sbill bp = dp->b_actf; 577264Sbill unit = dkunit(bp); 578264Sbill if (DK_N+NUP == DK_NMAX) 579264Sbill dk_busy &= ~(1<<(DK_N+NUP)); 580264Sbill else if (DK_N+unit <= DK_NMAX) 581264Sbill dk_busy &= ~(1<<(DK_N+unit)); 582275Sbill if ((upaddr->upcs2 & 07) != unit) { 583275Sbill upaddr->upcs2 = unit; 584275Sbill DELAY(sdelay); 585275Sbill nwaitcs2++; 586275Sbill } else 587275Sbill neasycs2++; 588275Sbill if (upaddr->upds & ERR) { 589266Sbill /* 590266Sbill * An error occurred, indeed. Select this unit 591266Sbill * to get at the drive status (a SEARCH may have 592266Sbill * intervened to change the selected unit), and 593266Sbill * wait for the command which caused the interrupt 594266Sbill * to complete (DRY). 595266Sbill */ 596266Sbill while ((upaddr->upds & DRY) == 0) 597264Sbill DELAY(25); 598266Sbill /* 599266Sbill * After 28 retries (16 w/o servo offsets, and then 600266Sbill * 12 with servo offsets), or if we encountered 601266Sbill * an error because the drive is write-protected, 602266Sbill * give up. Print an error message on the last 2 603266Sbill * retries before a hard failure. 604266Sbill */ 605266Sbill if (++uptab.b_errcnt > 28 || upaddr->uper1&WLE) 606264Sbill bp->b_flags |= B_ERROR; 607264Sbill else 608266Sbill uptab.b_active = 0; /* To force retry */ 609266Sbill if (uptab.b_errcnt > 27) 610264Sbill deverror(bp, upaddr->upcs2, upaddr->uper1); 611266Sbill /* 612266Sbill * If this was a correctible ECC error, let upecc 613266Sbill * do the dirty work to correct it. If upecc 614266Sbill * starts another READ for the rest of the data 615266Sbill * then it returns 1 (having set uptab.b_active). 616266Sbill * Otherwise we are done and fall through to 617266Sbill * finish up. 618266Sbill */ 619266Sbill if ((upaddr->uper1&(DCK|ECH))==DCK && upecc(upaddr, bp)) 620266Sbill return; 621266Sbill /* 622266Sbill * Clear the drive and, every 4 retries, recalibrate 623266Sbill * to hopefully help clear up seek positioning problems. 624266Sbill */ 625264Sbill upaddr->upcs1 = TRE|IE|DCLR|GO; 626264Sbill DELAY(idelay); 627268Sbill needie = 0; 628266Sbill if ((uptab.b_errcnt&07) == 4) { 629264Sbill upaddr->upcs1 = RECAL|GO|IE; 630264Sbill DELAY(idelay); 631264Sbill while(upaddr->upds & PIP) 632264Sbill DELAY(25); 633264Sbill } 634264Sbill } 635266Sbill /* 636266Sbill * If we are still noted as active, then no 637266Sbill * (further) retries are necessary. 638266Sbill * 639266Sbill * Make sure the correct unit is selected, 640266Sbill * return it to centerline if necessary, and mark 641266Sbill * this i/o complete, starting the next transfer 642266Sbill * on this drive with the upustart routine (if any). 643266Sbill */ 644266Sbill if (uptab.b_active) { 645266Sbill if (uptab.b_errcnt >= 16) { 646266Sbill upaddr->upcs1 = RTC|GO|IE; 647264Sbill DELAY(idelay); 648266Sbill while (upaddr->upds & PIP) 649264Sbill DELAY(25); 650268Sbill needie = 0; 651264Sbill } 652264Sbill uptab.b_active = 0; 653264Sbill uptab.b_errcnt = 0; 654264Sbill uptab.b_actf = dp->b_forw; 655264Sbill dp->b_active = 0; 656264Sbill dp->b_errcnt = 0; 657264Sbill dp->b_actf = bp->av_forw; 658266Sbill bp->b_resid = (-upaddr->upwc * sizeof(short)); 659275Sbill if (bp->b_resid) 660275Sbill printf("resid %d ds %o er? %o %o %o\n", bp->b_resid, upaddr->upds, 661275Sbill upaddr->uper1, upaddr->uper2, upaddr->uper3); 662264Sbill iodone(bp); 663264Sbill if(dp->b_actf) 664268Sbill if (upustart(unit)) 665268Sbill needie = 0; 666264Sbill } 667264Sbill as &= ~(1<<unit); 668272Sbill softas &= ~(1<<unit); 669264Sbill ubafree(up_ubinfo), up_ubinfo = 0; 670273Sbill } else { 671264Sbill if (upaddr->upcs1 & TRE) { 672264Sbill upaddr->upcs1 = TRE; 673264Sbill DELAY(idelay); 674264Sbill } 675264Sbill } 676266Sbill /* 677266Sbill * If we have a unit with an outstanding SEARCH, 678266Sbill * and the hardware indicates the unit requires attention, 679266Sbill * the bring the drive to the ready queue. 680266Sbill * Finally, if the controller is not transferring 681266Sbill * start it if any drives are now ready to transfer. 682266Sbill */ 683272Sbill as |= softas; 684272Sbill osoftas = softas; 685272Sbill softas = 0; 686266Sbill for (unit = 0; unit < NUP; unit++) 687273Sbill if ((as|osoftas) & (1<<unit)) { 688273Sbill if (as & (1<<unit)) { 689267Sbill upaddr->upas = 1<<unit; 690268Sbill if (asdel) DELAY(asdel); 691272Sbill } 692273Sbill if (upustart(unit)) 693273Sbill needie = 0; 694273Sbill } 695266Sbill if (uptab.b_actf && uptab.b_active == 0) 696268Sbill if (upstart()) 697268Sbill needie = 0; 698266Sbill out: 699275Sbill if (needie) 700266Sbill upaddr->upcs1 = IE; 701264Sbill } 702264Sbill 703264Sbill upread(dev) 704264Sbill { 705264Sbill 706264Sbill physio(upstrategy, &rupbuf, dev, B_READ, minphys); 707264Sbill } 708264Sbill 709264Sbill upwrite(dev) 710264Sbill { 711264Sbill 712264Sbill physio(upstrategy, &rupbuf, dev, B_WRITE, minphys); 713264Sbill } 714264Sbill 715266Sbill /* 716266Sbill * Correct an ECC error, and restart the i/o to complete 717266Sbill * the transfer if necessary. This is quite complicated because 718266Sbill * the transfer may be going to an odd memory address base and/or 719266Sbill * across a page boundary. 720266Sbill */ 721264Sbill upecc(up, bp) 722264Sbill register struct device *up; 723264Sbill register struct buf *bp; 724264Sbill { 725264Sbill struct uba_regs *ubp = (struct uba_regs *)UBA0; 726266Sbill register int i; 727264Sbill caddr_t addr; 728266Sbill int reg, bit, byte, npf, mask, o, cmd, ubaddr; 729264Sbill int bn, cn, tn, sn; 730264Sbill 731264Sbill /* 732266Sbill * Npf is the number of sectors transferred before the sector 733266Sbill * containing the ECC error, and reg is the UBA register 734266Sbill * mapping (the first part of) the transfer. 735266Sbill * O is offset within a memory page of the first byte transferred. 736264Sbill */ 737266Sbill npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1; 738266Sbill reg = btop(up_ubinfo&0x3ffff) + npf; 739264Sbill o = (int)bp->b_un.b_addr & PGOFSET; 740264Sbill printf("%D ", bp->b_blkno+npf); 741264Sbill prdev("ECC", bp->b_dev); 742264Sbill mask = up->upec2; 743264Sbill if (mask == 0) { 744266Sbill up->upof = FMT22; /* == RTC ???? */ 745264Sbill DELAY(idelay); 746264Sbill return (0); 747264Sbill } 748266Sbill /* 749266Sbill * Flush the buffered data path, and compute the 750266Sbill * byte and bit position of the error. The variable i 751266Sbill * is the byte offset in the transfer, the variable byte 752266Sbill * is the offset from a page boundary in main memory. 753266Sbill */ 754266Sbill ubp->uba_dpr[(up_ubinfo>>28)&0x0f] |= BNE; 755266Sbill i = up->upec1 - 1; /* -1 makes 0 origin */ 756266Sbill bit = i&07; 757266Sbill i = (i&~07)>>3; 758264Sbill byte = i + o; 759266Sbill /* 760266Sbill * Correct while possible bits remain of mask. Since mask 761266Sbill * contains 11 bits, we continue while the bit offset is > -11. 762266Sbill * Also watch out for end of this block and the end of the whole 763266Sbill * transfer. 764266Sbill */ 765266Sbill while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 766266Sbill addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ 767266Sbill (byte & PGOFSET); 768266Sbill putmemc(addr, getmemc(addr)^(mask<<bit)); 769266Sbill byte++; 770266Sbill i++; 771266Sbill bit -= 8; 772264Sbill } 773266Sbill uptab.b_active++; /* Either complete or continuing... */ 774264Sbill if (up->upwc == 0) 775264Sbill return (0); 776266Sbill /* 777266Sbill * Have to continue the transfer... clear the drive, 778266Sbill * and compute the position where the transfer is to continue. 779266Sbill * We have completed npf+1 sectors of the transfer already; 780266Sbill * restart at offset o of next sector (i.e. in UBA register reg+1). 781266Sbill */ 782266Sbill up->upcs1 = TRE|IE|DCLR|GO; 783264Sbill DELAY(idelay); 784264Sbill bn = dkblock(bp); 785264Sbill cn = bp->b_cylin; 786266Sbill sn = bn%(NSECT*NTRAC) + npf + 1; 787264Sbill tn = sn/NSECT; 788264Sbill sn %= NSECT; 789266Sbill cn += tn/NTRAC; 790266Sbill tn %= NTRAC; 791264Sbill up->updc = cn; 792266Sbill up->upda = (tn << 8) | sn; 793266Sbill ubaddr = (int)ptob(reg+1) + o; 794266Sbill up->upba = ubaddr; 795266Sbill cmd = (ubaddr >> 8) & 0x300; 796266Sbill cmd |= IE|GO|RCOM; 797266Sbill up->upcs1 = cmd; 798264Sbill return (1); 799264Sbill } 800286Sbill 801286Sbill /* 802286Sbill * Reset driver after UBA init. 803286Sbill * Cancel software state of all pending transfers 804286Sbill * and restart all units and the controller. 805286Sbill */ 806286Sbill upreset() 807286Sbill { 808286Sbill int unit; 809286Sbill 810286Sbill printf(" up"); 811286Sbill uptab.b_active = 0; 812286Sbill uptab.b_actf = uptab.b_actl = 0; 813286Sbill if (DK_N+NUP == DK_NMAX) 814286Sbill dk_busy &= ~(1<<(DK_N+NUP)); 815286Sbill if (up_ubinfo) { 816286Sbill printf("<%d>", (up_ubinfo>>28)&0xf); 817286Sbill ubafree(up_ubinfo), up_ubinfo = 0; 818286Sbill } 819*313Sbill UPADDR->upcs2 = CLR; /* clear controller */ 820*313Sbill DELAY(idelay); 821286Sbill for (unit = 0; unit < NUP; unit++) { 822286Sbill uputab[unit].b_active = 0; 823286Sbill (void) upustart(unit); 824286Sbill } 825286Sbill (void) upstart(); 826286Sbill } 827*313Sbill 828*313Sbill /* 829*313Sbill * Wake up every second and if an interrupt is pending 830*313Sbill * but nothing has happened increment a counter. 831*313Sbill * If nothing happens for 20 seconds, reset the controller 832*313Sbill * and begin anew. 833*313Sbill */ 834*313Sbill upwatch() 835*313Sbill { 836*313Sbill int i; 837*313Sbill 838*313Sbill timeout((caddr_t)upwatch, 0, HZ); 839*313Sbill if (uptab.b_active == 0) { 840*313Sbill for (i = 0; i < NUP; i++) 841*313Sbill if (uputab[i].b_active) 842*313Sbill goto active; 843*313Sbill up_wticks = 0; /* idling */ 844*313Sbill return; 845*313Sbill } 846*313Sbill active: 847*313Sbill up_wticks++; 848*313Sbill if (up_wticks >= 20) { 849*313Sbill up_wticks = 0; 850*313Sbill printf("LOST INTERRUPT RESET"); 851*313Sbill upreset(); 852*313Sbill printf("\n"); 853*313Sbill } 854*313Sbill } 855