BBN-V6/dmr/hp-ecc.c

Compare this file to the similar file:
Show the results in this format:

#
/*
 * RWP06 driver
 *  modified by A. G. Nemeth - BBN - 18 May 1978
 *  ECC additions by A. G. Nemeth - BBN - 3 January 1979
 */


#include "../h/param.h"
#include "../h/buf.h"
#include "../h/conf.h"
#include "../h/systm.h"
#include "../h/user.h"
#include "../h/reg.h"

struct
{
    int     hpcs1;	   /* Control and Status register 1 */
    int     hpwc;	   /* Word count register */
    int     hpba;	   /* UNIBUS address register */
    int     hpda;	   /* Desired address register */
    int     hpcs2;	   /* Control and Status register 2 */
    int     hpds;	   /* Drive Status */
    int     hper1;	   /* Error register 1 */
    int     hpas;	   /* Attention Summary */
    int     hpla;	   /* Look ahead */
    int     hpdb;	   /* Data buffer */
    int     hpmr;	   /* Maintenance register */
    int     hpdt;	   /* Drive type */
    int     hpsn;	   /* Serial number */
    int     hpof;	   /* Offset register */
    int     hpdc;	   /* Desired Cylinder address register */
    int     hpcc;	   /* Current Cylinder */
    int     hper2;	   /* Error register 2 */
    int     hper3;	   /* Error register 3 */
    int     hpec1;	   /* Burst error bit position */
    int     hpec2;	   /* Burst error bit pattern */
    int     hpbae;	   /* Bus address extension */
    int     hpcs3;	   /* Control and status register 3 */
};

#define	HPADDR	0176700
#define	NHP	2	   /* number of HP drives */
#define NMDLOG2 4	   /* number of meta disks log 2 */
#define MASK	((1<<NMDLOG2)-1)
			   /* mask for meta disk ID */

#define SECSZ 256

struct
{
    char   *nblocks;
    int     cyloff;
}       hp_sizes[]
{
            9614, 0,       /* 0 - hpsx8 */
            9614, 23,      /* 1 - hpsx7 */
            9614, 46,      /* 2 - hpsx6 */
            9614, 69,      /* 3 - hpsx5 */
            63536, 92,     /* 4 - hplx2 */
            9614, 244,     /* 5 - hpsx4 */
            9614, 267,     /* 6 - hpsx3 */
            9614, 290,     /* 7 - hpsx2 */
            9614, 313,     /* 8 - hpsx1 */
            9614, 336,     /* 9 - hpsx0 */
            63536, 359,    /* 10 - hplx0 */
            63536, 511,    /* 11 - hplx1 */
            63536, 663,    /* 12 - hplx3 */
};


struct devtab   hptab;
struct devtab   hputab[NHP];
struct buf  hpbuf;
char    hpstatus[NHP];
int     hpsioc[NHP];
int     hpsios[NHP];

int     ghper1,
        ghper2,
        ghper3,
        ghpds,
        ghpcs2;

 /* Drive Commands */
#define	GO	01
#define	UNLOAD	02
#define	SEEK	04
#define DCLR	010
#define	RELEASE	012
#define OFFSET  014
#define	PRESET	020
#define	SEARCH	030
#define READ    070

#define	ERR	040000     /* hpds - Error */
#define	MOL	010000     /* hpds - Medium online */
#define	DRY	0200       /* hpds - drive ready */
#define VV	0100       /* hpds - volume valid */
#define SC	0100000    /* hpcs1 - Special condition */
#define	TRE	040000     /* hpcs1 - transfer error */
#define DVA	04000      /* hpcs1 - drive available */
#define	IE	0100       /* hpcs1 - interrupt enable */
#define RDY     0200       /* hpcs1 - controller ready */
#define	NED	010000     /* hpcs2 - Nonexistent drive */
#define	WLE	04000      /* hper1 - Write lock error */
#define DCK     0100000    /* hper1 - data check error */
#define ECH     0100       /* hper1 - ECC hard error */
#define FMT22	010000     /* hpof - 16 bit /word format */
#define	ECI	04000      /* hpof - ecc inhibit */

/*
 * Use av_back to save track+sector,
 * b_resid for cylinder.
 */

#define	trksec	av_back
#define	cylin	b_resid

hpstrategy (abp)
struct buf *abp;
{
    register struct buf *bp;
    register char  *p1,
                   *p2;
    struct devtab  *dp;
    int     unit;

    bp = abp;
    p1 = &hp_sizes[bp -> b_dev.d_minor & MASK];
    unit = bp -> b_dev.d_minor >> NMDLOG2;
    if (unit >= NHP || hpstatus[unit] ||
	    bp -> b_blkno >= p1 -> nblocks)
    {
	bp -> b_flags =| B_ERROR;
	iodone (bp);
	return;
    }
    bp -> av_forw = 0;
    bp -> cylin = p1 -> cyloff;
    p1 = bp -> b_blkno;
    p2 = lrem (p1, 22);
    p1 = ldiv (p1, 22);
    bp -> trksec = (p1 % 19) << 8 | p2;
    bp -> cylin =+ p1 / 19;
    spl5 ();
    dp = &hputab[unit];
    hpsioc[unit]++;
    if ((p1 = dp -> d_actf) == 0)
	dp -> d_actf = bp;
    else
    {
	for (; p2 = p1 -> av_forw; p1 = p2)
	{
	    if (p1 -> cylin <= bp -> cylin
		    && bp -> cylin < p2 -> cylin
		    || p1 -> cylin >= bp -> cylin
		    && bp -> cylin > p2 -> cylin)
		break;
	}
	bp -> av_forw = p2;
	p1 -> av_forw = bp;
    }
    if (dp -> d_active == 0)
	hpustart (unit);
    spl0 ();
}

hpustart (dev)
{
    register struct buf *bp;
    register struct devtab *dp;
    register    unit;
    int     search;
    int     i;

    unit = dev;
    dp = &hputab[unit];
    HPADDR -> hpcs2.lobyte = unit;
    HPADDR -> hpas = 1 << unit;
			   /* hpstatus[unit] = 0 was here, moved lower */
    if ((HPADDR -> hpcs1 & DVA) == 0)
    {
			   /* either NED or dual-port not avail */
	printf ("NED ");
	goto abort;
    }
    if ((HPADDR -> hpds & MOL) == 0)
    {
	if (hpstatus[unit] == 0)
			   /* check added to prevent */
	    printf ("MOL ");
			   /* multiple printfs: 9/25/77:mob */
	goto abort;
    }
			   /* check on dp->d_actf was here: moved for error
			      handling 9/23/77:mob */
    hpstatus[unit] = 0;    /* moved from above 9/25/77:mob */
    if (HPADDR -> hpds & ERR)
    {
	printf ("SE %d %o\n", unit, HPADDR -> hper1);
	HPADDR -> hpcs1.lobyte = IE | DCLR | GO;
	if (++dp -> d_errcnt > 16)
	{
	    printf ("Unit %d unloaded\n", unit);
	    HPADDR -> hpcs1.lobyte = IE | UNLOAD | GO;
	    goto abort;
	}
	if (dp -> d_actf)  /* error handling 9/23/77:mob */
	    dp -> d_active--;
    }
    if ((HPADDR -> hpds & VV) == 0)
    {
	HPADDR -> hpcs1.lobyte = IE | PRESET | GO;
	HPADDR -> hpof = FMT22;
    }
    if ((bp = dp -> d_actf) == 0)
			   /* error handling (moved) 9/23/77:mob */
	return;		   /*              "               */
    dp -> d_active++;
    i = bp -> cylin - HPADDR -> hpcc;
/*      systm[11] =+ (i > 0 ? i : -i);  /* monitoring 9/22/77:rsk */
    HPADDR -> hpdc = bp -> cylin;
    search = bp -> trksec.lobyte - (HPADDR -> hpla >> 6) - 1;
    if (search < 0)
	search =+ 22;
    if ((bp -> cylin != HPADDR -> hpcc || search > 6) &&
	    dp -> d_active < 3)
    {
	search = bp -> trksec;
	search.lobyte =- 4;
	if (search.lobyte < 0)
	    search.lobyte =+ 22;
	hpsios[unit]++;
	HPADDR -> hpda = search;
	HPADDR -> hpcs1.lobyte = IE | SEARCH | GO;
    }
    else
    {
	dp -> b_forw = 0;
	if (hptab.d_actf == 0)
	    hptab.d_actf = dp;
	else
	    hptab.d_actl -> b_forw = dp;
	hptab.d_actl = dp;
	if (hptab.d_active == 0)
	    hpstart (0);
    }
    return;
abort: 
    if (hpstatus[unit] == 0)
    {			   /* check must be here since we want, * in all,
			      cases, to free pending blocks */
	printf ("er1 %o, er2 %o, er3 %o, ds %o, cs1 %o, cs2 %o\n",
		HPADDR -> hper1, HPADDR -> hper2, HPADDR -> hper3, HPADDR -> hpds,
		HPADDR -> hpcs1, HPADDR -> hpcs2);
			   /* helpful debugging info: 9/21/77:mob */
	HPADDR -> hpcs1.lobyte = IE | DCLR | GO;
			   /* error handling: 9/23/77:mob */
    }
    hpstatus[unit]++;
    while (bp = dp -> d_actf)
    {
	bp -> b_flags =| B_ERROR;
	dp -> d_actf = bp -> av_forw;
	iodone (bp);
    }
    dp -> d_active = 0;
    dp -> d_errcnt = 0;
    HPADDR -> hpcs1 = IE | DCLR | GO;
    printf ("RP06 drive %d offline\n", unit);
}

hpstart (off)
int     off;
{
    register struct buf *bp;
    register struct devtab *dp;

    if ((dp = hptab.d_actf) == 0)
	return;
    bp = dp -> d_actf;
    HPADDR -> hpcs2.lobyte = bp -> b_dev.d_minor >> NMDLOG2;
    hptab.d_active++;
    HPADDR -> hpdc = bp -> cylin;
    rhstart (bp, &HPADDR -> hpda, bp -> trksec, &HPADDR -> hpbae, off);
}

char   *oldbk;
int     lecc;
int     off
{
    0
};
hpintr ()
{
    struct { int high; int low;};
    long    secloc,mask;
    int     wd,ct,errpos;
    register struct buf *bp;
    register struct devtab *dp;
    register unit;

    if (hptab.d_active)
    {			   /* data transfer underway */
	off = 0;
	dp = hptab.d_actf;
	bp = dp -> d_actf;
	unit = bp -> b_dev.d_minor >> NMDLOG2;
	HPADDR -> hpcs2.lobyte = unit;
	if (HPADDR -> hpcs1 & TRE)
	{		   /* error bit */
	    oldbk = bp -> b_blkno;
	    ghper1 = HPADDR -> hper1;
	    ghper2 = HPADDR -> hper2;
	    ghper3 = HPADDR -> hper3;
	    ghpds = HPADDR -> hpds;
	    ghpcs2 = HPADDR -> hpcs2;
/*
 * use ecc only if not hard error (rsk:12/20/77)
 */
	     /**/ printf ("** ERR%o %o **\n", ghper1, ghper2);
	    if ((!(ghper1 & ECH)) && (ghper1 & DCK))
	    {

		 /**/ printf ("Entered ECC ");
		 /**/ printf ("EA%o BA%o WL%d WT%d POS%d MSK%o\n", HPADDR -> hpbae, HPADDR -> hpba,
			 /**/ HPADDR -> hpwc, -bp -> b_wcount, HPADDR -> hpec1, HPADDR -> hpec2);

		ct = HPADDR->hpwc;
		ct =- bp->b_wcount;     /* number of words xfered */
		errpos = HPADDR->hpec1; /* position of error */
		if (errpos-- == 0)
		  { printf ("ECC position zero\n");
		    goto notecc;
		  }
		secloc.high = bp->b_xmem;
		secloc.low = bp->b_addr;
		wd = 2*((ct & (~ (SECSZ-1)))+errpos/16); /* convenient temp */
		secloc =+ wd;   /* start of sector + word of error */
		ct = ct%SECSZ;      /* amount of last sector xfer'ed */
		ct = (ct == 0)? SECSZ:ct;
		mask.high = 0;
		mask.low = HPADDR->hpec2;
		mask =<< (errpos&017);
		if (errpos/16 < ct) pphys(secloc,mask.low^gphys(secloc));
		if ((errpos+11)/16 < ct)
		  { secloc++;
		    pphys(secloc,mask.high^gphys(secloc));
		  }
		if (HPADDR->hpwc != 0)  /*more to xfer ? */
		  { HPADDR->hpcs1 = IE|READ|GO; /* just continue on to read
						   more */
		    return;
		  }
	      }
notecc:
	    HPADDR -> hpcs1 = TRE | IE | DCLR | GO;
	    if (++hptab.d_errcnt > 16 || ghper1 & WLE)
		bp -> b_flags =| B_ERROR;
	    else
		hptab.d_active = 0;
	}
/*
 * check not only for data transfer but also be sure this is
 * really the interrupt for it and not some seek interrupt.
 */
	if (hptab.d_active && (HPADDR -> hpcs1 & RDY))
	{		   /* mob:10/07/77 */
	    hptab.d_active = 0;
	    hptab.d_errcnt = 0;
	    hptab.d_actf = dp -> b_forw;
	    dp -> d_active = 0;
	    dp -> d_errcnt = 0;
	    dp -> d_actf = bp -> av_forw;
	    bp -> b_resid = HPADDR -> hpwc;
	    iodone (bp);
	    HPADDR -> hpcs1 = IE | RELEASE | GO;
	    hpustart (unit);
	}
	if (hptab.d_active == 0)
	    hpstart (); /* start I/O */
    }
    else
	HPADDR -> hpcs1.hibyte = TRE >> 8;
    for (unit = 0; unit < NHP; unit++)
    {
	if (HPADDR -> hpas & (1 << unit))
	    hpustart (unit);
    }
    if ((HPADDR -> hpcs1 & IE) == 0)
    {
	HPADDR -> hpcs1 = IE;
	if (HPADDR -> hpcs1 & TRE)
	    HPADDR -> hpcs1.hibyte = TRE >> 8;
    }
}

hpread (dev)
{

    if (hpphys (dev))
	physio (hpstrategy, &hpbuf, dev, B_READ);
}

hpwrite (dev)
{

    if (hpphys (dev))
	physio (hpstrategy, &hpbuf, dev, B_WRITE);
}

hpphys (dev)
{
    register    c;

    c = lshift (u.u_offset, -9);
    c =+ ldiv (u.u_count + 511, 512);
    if (c > hp_sizes[dev.d_minor & MASK].nblocks)
    {
	u.u_error = ENXIO;
	return (0);
    }
    return (1);
}