-/* up.c 3.23 %G% */
+/* up.c 4.11 %G% */
+#include "up.h"
+#if NUP > 0
+#if SC11 > 0
+#include "../dev/up.c.SC11"
+#else
/*
* UNIBUS disk driver with overlapped seeks and ECC recovery.
- *
- * This driver works marginally on an Emulex SC-11B controller with rev
- * level J microcode, defining:
- * int olducode = 1;
- * to force CPU stalling delays.
- *
- * It has worked with no delays and no problems on a prototype
- * SC-21 controller. Emulex intends to upgrade all SC-11s on VAXes to SC-21s.
- * You should get a SC-21 to replace any SC-11 on a VAX.
- *
- * SC-11B Controller switch settings:
- * SW1-1 5/19 surfaces (off, 19 surfaces on Ampex 9300)
- * SW1-2 chksum enable (off, checksum disabled)
- * SW1-3 volume select (off, 815 cylinders)
- * SW1-4 sector select (on, 32 sectors)
- * SW1-5 unused (off)
- * SW1-6 port select (on, single port)
- * SW1-7 npr delay (off, disable)
- * SW1-8 ecc test mode (off, disable)
- * and top mounted switches:
- * SW2-1 extend opcodes (off=open, disable)
- * SW2-2 extend diag (off=open, disable)
- * SW2-3 4 wd dma burst (on=closed, enable)
- * SW2-4 unused (off=open)
*/
+#define DELAY(N) { register int d; d = N; while (--d > 0); }
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/uba.h"
#include "../h/vm.h"
-/*
- * Define number of drives, and range of sampling information to be used.
- *
- * Normally, DK_N .. DK_N+NUP-1 gather individual drive stats,
- * and DK_N+NUP gathers controller transferring stats.
- *
- * If DK_N+NUP > DK_NMAX, then transfer stats are divided per drive.
- * If DK_NMAX is yet smaller, some drives are not monitored.
- */
-#define DK_N 2
-#define DK_NMAX 3
-
#define ushort unsigned short
struct device
*/
int upseek;
-#define UPADDR ((struct device *)(UBA0_DEV + 0176700))
-
-#define NUP 2 /* Number of drives this installation */
-
#define NSECT 32
#define NTRAC 19
* and in the driver then we take it as it is. Otherwise we do a SEARCH
* requesting an interrupt upSDIST sectors in advance.
*/
-#define _upSDIST 6 /* 3.0 msec */
-#define _upRDIST 6 /* 3.0 msec */
+#define _upSDIST 2 /* 1.0 msec */
+#define _upRDIST 4 /* 2.0 msec */
int upSDIST = _upSDIST;
int upRDIST = _upRDIST;
* On systems with RP06'es, we normally use only 291346 blocks of the H
* area, and use DEF or G to cover the rest of the drive. The C system
* covers the whole drive and can be used for pack-pack copying.
+ *
+ * Note: sizes here are for AMPEX drives with 815 cylinders.
+ * CDC drives can make the F,G, and H areas larger as they have 823 cylinders.
*/
struct size
{
55936, 589, /* E=cyl 589 thru 680 */
81472, 681, /* F=cyl 681 thru 814 */
153824, 562, /* G=cyl 562 thru 814 */
- 445664, 82, /* H=cyl 82 thru 814 */
-/* Later, and more safely for H area...
291346, 82, /* H=cyl 82 thru 561 */
};
* +/- microinches. Note that header compare inhibit (HCI) is not
* tried (this makes sense only during read, in any case.)
*
- * NOT ALL OF THESE ARE IMPLEMENTED ON 9300!?!
+ * NB: Not all drives/controllers emulate all of these.
*/
#define P400 020
#define M400 0220
/* Bits of upcs2 */
#define CLR 040 /* Controller clear */
+#define MXF 01000
+#define NEM 04000
+
/* Bits of uper1 */
#define DCK 0100000 /* Ecc error occurred */
#define ECH 0100 /* Ecc error was unrecoverable */
#define b_cylin b_resid
int up_ubinfo; /* Information about UBA usage saved here */
-/*
- * The EMULEX controller balks if accessed quickly after
- * certain operations. With rev J delays seem to be needed only
- * when selecting a new unit, and in drive initialization type
- * like PRESET and DCLR. The following variables control the delay
- * DELAY(n) is approximately n usec.
- */
-int olducode = 1;
-int idelay = 500; /* Delay after PRESET or DCLR */
-int osdelay = 150; /* Old delay after selecting drive in upcs2 */
-int ordelay = 100; /* Old delay after SEARCH */
-int oasdel = 100; /* Old delay after clearing bit in upas */
-int nsdelay = 25;
-
-#define DELAY(N) { register int d; d = N; while (--d > 0); }
-
-int nwaitcs2; /* How many sdelay loops ? */
-int neasycs2; /* How many sdelay loops not needed ? */
int up_wticks; /* Ticks waiting for interrupt */
int upwstart; /* Have started guardian */
long sz, bn;
if (upwstart == 0) {
- timeout((caddr_t)upwatch, 0, HZ);
+ timeout(upwatch, (caddr_t)0, HZ);
upwstart++;
}
xunit = minor(bp->b_dev) & 077;
iodone(bp);
return;
}
+ if (UPDK_N+unit <= UPDK_NMAX)
+ dk_mspw[UPDK_N+unit] = .0000020345;
bp->b_cylin = bn/(NSECT*NTRAC) + up_sizes[xunit&07].cyloff;
dp = &uputab[unit];
(void) spl5();
* Other drivers tend to say something like
* upaddr->upcs1 = IE;
* upaddr->upas = 1<<unit;
- * here, but the SC-11B will cancel a command which
+ * here, but some controllers will cancel a command
* happens to be sitting in the cs1 if you clear the go
- * bit by storing there (so the first is not safe),
- * and it also does not like being bothered with operations
- * such as clearing upas when a transfer is active (as
- * it may well be.)
+ * bit by storing there (so the first is not safe).
*
* Thus we keep careful track of when we re-enable IE
* after an interrupt and do it only if we didn't issue
*/
if (unit >= NUP)
goto out;
- if (unit+DK_N <= DK_NMAX)
- dk_busy &= ~(1<<(unit+DK_N));
+ if (unit+UPDK_N <= UPDK_NMAX)
+ dk_busy &= ~(1<<(unit+UPDK_N));
dp = &uputab[unit];
if ((bp = dp->b_actf) == NULL)
goto out;
/*
- * The SC-11B doesn't start SEARCH commands when transfers are
- * in progress. In fact, it tends to get confused when given
+ * Most controllers don't start SEARCH commands when transfers are
+ * in progress. In fact, some tend to get confused when given
* SEARCH'es during transfers, generating interrupts with neither
* RDY nor a bit in the upas register. Thus we defer
* until an interrupt when a transfer is pending.
if (dp->b_active)
goto done;
dp->b_active = 1;
- if ((upaddr->upcs2 & 07) != unit) {
+ if ((upaddr->upcs2 & 07) != unit)
upaddr->upcs2 = unit;
- DELAY(olducode ? osdelay : nsdelay);
- nwaitcs2++;
- } else
- neasycs2++;
/*
* If we have changed packs or just initialized,
* then the volume will not be valid; if so, clear
*/
if ((upaddr->upds & VV) == 0) {
upaddr->upcs1 = IE|DCLR|GO;
- DELAY(idelay);
upaddr->upcs1 = IE|PRESET|GO;
- DELAY(idelay);
upaddr->upof = FMT22;
didie = 1;
}
if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL))
goto done;
+
+#if NUP > 1
/*
* Do enough of the disk address decoding to determine
* which cylinder and sector the request is on.
/*
* Mark this unit busy.
*/
- unit += DK_N;
- if (unit <= DK_NMAX && DK_N+NUP <= DK_NMAX) {
+ unit += UPDK_N;
+ if (unit <= UPDK_NMAX) {
dk_busy |= 1<<unit;
- dk_numb[unit]++;
+ dk_seek[unit]++;
}
- if (olducode)
- DELAY(ordelay);
goto out;
+#endif
done:
/*
tn = sn/NSECT;
sn %= NSECT;
upaddr = UPADDR;
- if ((upaddr->upcs2 & 07) != dn) {
+ if ((upaddr->upcs2 & 07) != dn)
upaddr->upcs2 = dn;
- /* DELAY(sdelay); Provided by ubasetup() */
- nwaitcs2++;
- } else
- neasycs2++;
- up_ubinfo = ubasetup(bp, 1); /* Providing delay */
+ up_ubinfo = ubasetup(bp, 1);
/*
* If drive is not present and on-line, then
* get rid of this with an error and loop to get
bp->b_flags |= B_ERROR;
iodone(bp);
/* A funny place to do this ... */
- ubafree(up_ubinfo), up_ubinfo = 0;
+ ubarelse(&up_ubinfo);
goto loop;
}
printf("-- came back\n");
* If this is a retry, then with the 16'th retry we
* begin to try offsetting the heads to recover the data.
*/
- if (uptab.b_errcnt >= 16 && (bp->b_flags&B_WRITE)) {
+ if (uptab.b_errcnt >= 16 && (bp->b_flags&B_READ) != 0) {
upaddr->upof = up_offset[uptab.b_errcnt & 017] | FMT22;
upaddr->upcs1 = IE|OFFSET|GO;
- DELAY(idelay);
while (upaddr->upds & PIP)
DELAY(25);
}
upaddr->upcs1 = cmd;
/*
* This is a controller busy situation.
- * Record in dk slot NUP+DK_N (after last drive)
+ * Record in dk slot NUP+UPDK_N (after last drive)
* unless there aren't that many slots reserved for
* us in which case we record this as a drive busy
* (if there is room for that).
*/
- unit = dn+DK_N;
- if (NUP+DK_N == DK_NMAX)
- unit = NUP+DK_N;
- if (unit <= DK_NMAX) {
+ unit = dn+UPDK_N;
+ if (unit <= UPDK_NMAX) {
dk_busy |= 1<<unit;
- dk_numb[unit]++;
+ dk_xfer[unit]++;
dk_wds[unit] += bp->b_bcount>>6;
}
return (1);
uputab[0].b_active, uputab[1].b_active);
}
/*
- * Mark controller or drive not busy, and check for an
+ * Mark drive not busy, and check for an
* error condition which may have resulted from the transfer.
*/
dp = uptab.b_actf;
bp = dp->b_actf;
unit = dkunit(bp);
- if (DK_N+NUP == DK_NMAX)
- dk_busy &= ~(1<<(DK_N+NUP));
- else if (DK_N+unit <= DK_NMAX)
- dk_busy &= ~(1<<(DK_N+unit));
- if ((upaddr->upcs2 & 07) != unit) {
+ if (UPDK_N+unit <= UPDK_NMAX)
+ dk_busy &= ~(1<<(UPDK_N+unit));
+ if ((upaddr->upcs2 & 07) != unit)
upaddr->upcs2 = unit;
- DELAY(olducode ? osdelay : nsdelay);
- nwaitcs2++;
- } else
- neasycs2++;
if ((upaddr->upds&ERR) || (upaddr->upcs1&TRE)) {
+ int cs2;
/*
* An error occurred, indeed. Select this unit
* to get at the drive status (a SEARCH may have
else
uptab.b_active = 0; /* To force retry */
if (uptab.b_errcnt > 27)
- deverror(bp, upaddr->upcs2, upaddr->uper1);
+ cs2 = (int)upaddr->upcs2;
+ deverror(bp, (int)upaddr->upcs2,
+ (int)upaddr->uper1);
/*
* If this was a correctible ECC error, let upecc
* do the dirty work to correct it. If upecc
* to hopefully help clear up seek positioning problems.
*/
upaddr->upcs1 = TRE|IE|DCLR|GO;
- DELAY(idelay);
needie = 0;
if ((uptab.b_errcnt&07) == 4) {
upaddr->upcs1 = RECAL|GO|IE;
- DELAY(idelay);
while(upaddr->upds & PIP)
DELAY(25);
}
+ if (uptab.b_errcnt == 28 && cs2&(NEM|MXF)) {
+ printf("FLAKEY UP ");
+ ubareset();
+ return;
+ }
}
/*
* If we are still noted as active, then no
if (uptab.b_active) {
if (uptab.b_errcnt >= 16) {
upaddr->upcs1 = RTC|GO|IE;
- DELAY(idelay);
while (upaddr->upds & PIP)
DELAY(25);
needie = 0;
}
as &= ~(1<<unit);
upsoftas &= ~(1<<unit);
- ubafree(up_ubinfo), up_ubinfo = 0;
+ ubarelse(&up_ubinfo);
} else {
- if (upaddr->upcs1 & TRE) {
+ if (upaddr->upcs1 & TRE)
upaddr->upcs1 = TRE;
- DELAY(idelay);
- }
}
/*
* If we have a unit with an outstanding SEARCH,
upsoftas = 0;
for (unit = 0; unit < NUP; unit++)
if ((as|oupsoftas) & (1<<unit)) {
- if (as & (1<<unit)) {
+ if (as & (1<<unit))
upaddr->upas = 1<<unit;
- if (olducode)
- DELAY(oasdel);
- }
if (upustart(unit))
needie = 0;
}
if (uptab.b_actf && uptab.b_active == 0)
if (upstart())
needie = 0;
-out:
if (needie)
upaddr->upcs1 = IE;
}
mask = up->upec2;
if (mask == 0) {
up->upof = FMT22; /* == RTC ???? */
- DELAY(idelay);
return (0);
}
/*
* restart at offset o of next sector (i.e. in UBA register reg+1).
*/
up->upcs1 = TRE|IE|DCLR|GO;
- DELAY(idelay);
bn = dkblock(bp);
cn = bp->b_cylin;
sn = bn%(NSECT*NTRAC) + npf + 1;
int unit;
printf(" up");
+ DELAY(15000000); /* give it time to self-test */
uptab.b_active = 0;
uptab.b_actf = uptab.b_actl = 0;
- if (DK_N+NUP == DK_NMAX)
- dk_busy &= ~(1<<(DK_N+NUP));
if (up_ubinfo) {
printf("<%d>", (up_ubinfo>>28)&0xf);
- ubafree(up_ubinfo), up_ubinfo = 0;
+ ubarelse(&up_ubinfo);
}
UPADDR->upcs2 = CLR; /* clear controller */
- DELAY(idelay);
for (unit = 0; unit < NUP; unit++) {
uputab[unit].b_active = 0;
(void) upustart(unit);
{
int i;
- timeout((caddr_t)upwatch, 0, HZ);
+ timeout(upwatch, (caddr_t)0, HZ);
if (uptab.b_active == 0) {
for (i = 0; i < NUP; i++)
if (uputab[i].b_active)
printf("\n");
}
}
+#endif
+#endif