#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 3 (of 3)."
# Contents:  minix.c scsi_low.c
# Wrapped by budd@buit2 on Fri Jun  1 18:13:09 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f minix.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"minix.c\"
else
echo shar: Extracting \"minix.c\" \(16046 characters\)
sed "s/^X//" >minix.c <<'END_OF_minix.c'
X# ifdef MINIX
X/*
X * Read (only for now) Minix file systems
X * for PC532 stand alone i/o system
X * Phil Budne, May 1990
X *
X * this was written reading only the text in the book
X * (not the code!)
X *
X * some work for write (under MINIX_WRITE) in place. work needed
X * in namei, minixwrite call, zone cache (per super), fz2fsz
X */
X
X# ifdef TEST
X# define dskopen testopen
X# endif
X
X# include "satypes.h"
X# include "saerrno.h"
X# include "safile.h"
X# include "stdlib.h"
X# include "disklabel.h"
X
X# define NULL 0
X
Xtypedef u_char bool;
X# define TRUE 1
X# define FALSE 0
X
X/*
X * FIXME: should be zero!! else each partition has 1K for
X * boot and disklabel!!!
X */
X# define SUPERB 1			/* block number of super block */
X					/* in BLOCKSIZE units. */
X
X# define BLOCKSIZE 1024			/* 1K */
X# define BLOCKSHFT 10			/* LOG2(BLOCKSIZE) */
X
X# define MAGIC 011577			/* determined using od */
X
Xtypedef u_short inum_t;			/* i number in dirent */
Xtypedef u_short zone_t;			/* zone number in inode */
X
Xtypedef u_long bmap;
X# define BMAPSIZE (sizeof(bmap)*8)
X# define BIT(n)   (1<<(BMAPSIZE-(n)))
X# define INDEX(n) (n/BMAPSIZE)
X
X# define TSTBIT(map,bit) (map[INDEX(bit)] &   BIT(bit))
X# define CLRBIT(map,bit) (map[INDEX(bit)] &= ~BIT(bit))
X# define SETBIT(map,bit) (map[INDEX(bit)] |=  BIT(bit))
X
Xstruct super {				/* fix 5-31, p301 */
X    inum_t  ninodes;			/* number of inodes */
X    u_short nzones;			/* number of zones */
X    u_short nimblks;			/* number of inode bitmap blocks */
X    u_short nzmblks;			/* number of zone bitmap blocks */
X    u_short firstdata;			/* first data zone */
X    u_short zoneshift;			/* log2(zonesize/blksize) */
X    u_long  maxfile;			/* max filesize in bytes */
X    u_short magic;			/* magic number */
X
X    /* in core only */
X    int refcount;			/* reference count */
X    u_long zonemask, zonesize, zoneshft; /* save time */
X    zone_t izone;			/* first inode zone */
X    dev_t device;			/* convenient (c.f. fp->device) */
X    struct file *fp;			/* open raw file */
X# ifdef MINIX_WRITE
X    bmap *imap, *zmap;			/* inode and zone bitmaps */
X    bool dirty;				/* flags?? */
X# endif
X};
X
X# define NDIR 7
X
X/* disk inode exactly 32 bytes */
Xstruct dinode {				/* fig 5-32, p304 */
X    u_short mode;			/* file type and mode */
X    u_short uid;			/* owner */
X    u_long  size;			/* file size */
X    u_long  time;			/* file time (yuk! just one) */
X    /* NOTE! diagram in book is little endian layout! */
X    u_char  gid;			/* group (yuk! only 8 bits) */
X    u_char  links;			/* link count (yuk! only 8 bits) */
X    zone_t  zones[NDIR];		/* direct block pointers */
X    zone_t  indir;			/* indirect block pointer */
X    zone_t  dindir;			/* double indirect block pointer */
X};
X
Xstruct iinode {				/* incore inode */
X    struct dinode i;
X    struct super *super;
X    int refcount;
X    inum_t inum;
X# ifdef MINIX_WRITE
X    bool dirty;
X# endif
X};
X
X# define FMTSHFT 12			/* mode shift to get type */
X# define FMTDIR 4			/* directory file */
X# define FMTREG 8			/* regular file */
X
X/* guess... */
X
X# define BADI	 ((inum_t)0)
X# define BADZONE ((zone_t)0)
X
X# define NAMELEN 14			/* 16-sizeof(inum_t) */
X/* 16 bytes */
Xstruct dirent {
X    inum_t  inum;			/* i numbber (or BADI) */
X    u_char  name[NAMELEN];		/* filename (if not BADI) */
X};
X
X# define ROOTINUM 1			/* inode of root */
X
X# define MASK(n) ((1<<(n))-1)		/* assume 2's complement! */
X
X/* used for dinode and dirent which are .le. 32 bytes */
X# define LOG2(n) \
X    ((n) <=  1 ? 0 : \
X     ((n) <=  2 ? 1 : \
X      ((n) <=  4 ? 2 : \
X       ((n) <=  8 ? 3 : \
X	((n) <= 16 ? 4 : \
X	 ((n) <= 32 ? 5 : \
X	  ((n) <= 64 ? 6 : \
X	   ((n) <= 128 ? 7 : \
X	    ((n) <= 256 ? 8 : \
X	     (9))))))))))
X
X# define _ZONESIZE(sp)	(BLOCKSIZE<<((sp)->zoneshift))
X# define _ZONESHFT(sp)	(BLOCKSHFT<<((sp)->zoneshift))
X# define _ZONEMASK(sp)	MASK(ZONESHFT(sp))
X
X# define ZONESIZE(sp)	((sp)->zonesize)
X# define ZONESHFT(sp)	((sp)->zoneshft)
X# define ZONEMASK(sp)	((sp)->zonemask)
X
X/* zone pointers per zone (for indirect blocks) */
X# define PPZONE(sp)	(ZONESIZE(sp)/sizeof(zone_t)) /* >>LOG2()? */
X# define PPZONESHFT(sp) (ZONESHFT(sp)-LOG2(sizeof(zone_t)))
X# define PPZONEMASK(sp) MASK(PPZONESHFT(sp))
X
X/* dirents per zone (for directory files) */
X# define DPZONE(sp)	(ZONESIZE(sp)/sizeof(struct dirent)) /* >>LOG2? */
X# define DPZONESHFT(sp) (ZONESHFT(sp)-LOG2(sizeof(struct dirent))
X# define DPZONEMASK(sp) MASK(DPZONESHFT(sp))
X
X/* inodes per zone */
X# define IPZONE(sp)	(ZONESIZE(sp)/sizeof(struct dinode)) /* >>LOG2? */
X# define IPZONESHFT(sp) (ZONESHFT(sp)-LOG2(sizeof(struct dinode)))
X# define IPZONEMASK(sp) MASK(IPZONESHFT(sp))
X
Xenum nameop { OLD, NEW, KILL };		/* ops for namei -- only OLD for now */
X
Xextern struct file *newfile(void);
Xextern int ioerr(), ionull();
X
X/* forward */
Xstatic struct iinode *namei( struct super *, u_char *, enum nameop );
Xstatic u_char *getfilezone( struct iinode *, zone_t );
Xstatic void irel( struct iinode * );
X
Xint minixopen();
Xstatic int minixread(), minixclose();
X# ifdef MINIX_WRITE
Xstatic int minixwrite();
X# else
X# define minixwrite ioerr
X# endif
X
Xstatic struct devsw minixdev =
X    { "minix", minixopen, minixclose, minixread, minixwrite, ioerr };
X
X# define MAXSUPER 5
Xstatic struct super supers[MAXSUPER];	/* should be a doubly linked list */
X
X# define MAXINODE 10
Xstatic struct iinode inodes[MAXINODE];	/* should be a list */
X
Xstatic bool
Xdiskread( struct file *fp, off_t pos, u_char *buf, int size ) {
X    int cc;
X
X    fp->pos = pos;
X    cc = (fp->devsw->read)( fp, buf, size );
X    return( cc == size );
X}
X
Xstatic struct super *
Xfindsuper( struct file **fpp ) {
X    struct file *fp;
X    struct super *sp, *fsp;
X    int i;
X
X    /* search for superblock... */
X    fsp = NULL;
X    for( i = 0, sp = supers; i < MAXSUPER; i++, sp++ )
X	if( sp->refcount > 0 ) {
X	    if( (*fpp)->device == sp->device )
X		break;
X	}
X	else if( fsp == NULL )
X	    fsp = sp;
X
X    if( i == MAXSUPER ) {		/* search failed */
X	sp = fsp;
X	if( sp == NULL ) {
X	    errno = EMFILE;		/* too many super blocks in core */
X	    return( NULL );
X	}
X
X	fp = newfile();			/* new fp for raw disk */
X	*fp = **fpp;			/* copy all fields!! */
X					/* use old one and swap? */
X
X	if( dskopen( &fp, NULL ) < 0 ) { /* open raw disk (recurse!) */
X	    freefile( fp );
X	    return( NULL );
X	}
X
X	if( !diskread( fp, SUPERB * BLOCKSIZE,
X		      (u_char *)sp, sizeof( struct super ) ) ||
X	   sp->magic != MAGIC ) {	/* or bad magic in superblock */
X	    (fp->devsw->close)( fp );
X	    return( NULL );
X	}
X	sp->device = (*fpp)->device;	/* save device in superblock */
X	sp->fp = fp;			/* save file in superblock */
X	sp->zonesize = _ZONESIZE(sp);
X	sp->zoneshft = _ZONESHFT(sp);
X	sp->zonemask = _ZONEMASK(sp);
X	sp->izone =
X	    ((SUPERB + sp->nimblks + sp->nzmblks + 1)
X	     * BLOCKSIZE + ZONESIZE(sp) - 1) >> ZONESHFT(sp);
X# ifdef MINIX_WRITE
X	i = sp->ninodes / 8;
X	sp->imap = (bmap *) malloc( i ); /* FIX */
X	diskread( *fpp, (SUPERB+1)*BLOCKSIZE, sp->imap, i ); /* FIX */
X
X	i = sp->nzones / 8;
X	sp->zmap = (bmap *) malloc( i ); /* CHECK! */
X	diskread( *fpp, (SUPERB+1+sp->nimblks)*BLOCKSIZE, sp->zmap, i );
X
X	sp->dirty = FALSE;
X# endif
X    }
X    sp->refcount++;			/* bump superblock ref count */
X    return( sp );
X}
X
Xstatic int
Xrelsuper( struct super *sp ) {
X    sp->refcount--;			/* start race */
X    if( sp->refcount < 1 ) {
X	/* flush cache?! */
X	sp->refcount = 0;
X	return( (sp->fp->devsw->close)( sp->fp ) );
X    }
X    return( 0 );
X}
X
X/* global */ int
Xminixopen( struct file **fpp, u_char *name, struct partition *pp ) {
X    struct super *sp;
X    struct iinode *ip;
X
X# ifndef MINIX_WRITE
X    if( !((*fpp)->flags & FREAD) )	/* read only for now... */
X       ERR(EACCES);
X# endif
X
X    sp = findsuper( fpp );
X    if( sp == NULL )
X	return( -1 );
X
X    (*fpp)->data = ip = namei( sp, name, OLD );
X    if( ip == NULL ) {
X	/* if FWRITE try again with op = NEW */
X	relsuper( sp );
X	return( -1 );
X    }
X    (*fpp)->devsw = &minixdev;		/* use minix operations */
X    (*fpp)->end = ip->i.size;		/* eof */
X    return( 0 );
X}
X
Xstatic int
Xminixclose( struct file *fp ) {
X
X    if( fp->data != NULL )
X	irel( fp->data );
X    fp->data = NULL;
X    return( 0 );
X}
X
Xstatic int
Xminixread( struct file *fp, u_char *buf, int count ) {
X    u_char *data, *bp;
X    struct iinode *ip;
X    int z, off, cc, rem, zs;
X
X    ip  = fp->data;
X    cc  = 0;
X
X    if( fp->pos > ip->i.size )		/* past EOF */
X	return( -1 );			/* well then.. */
X
X    zs = ZONESIZE(ip->super);
X    z   = fp->pos >> ZONESHFT(ip->super); /* figure initial logical zone */
X    off = fp->pos &  ZONEMASK(ip->super); /* and offset into it */
X
X    if( count + fp->pos > ip->i.size )	/* past EOF? */
X	count = ip->i.size - fp->pos;	/* limit count */
X
X    bp = buf;
X    rem = count;
X    while( rem > 0 ) {
X	cc = rem;			/* try for it all */
X	if( cc + off > zs )		/* more than a zone */
X	    cc = zs - off;		/* never ear anything larger than */
X					/* yer head */
X
X	data = getfilezone( ip, z );	/* read next logical zone */
X	if( data == NULL )		/* unallocated (or read failed?) */
X	    memset( bp, EOS, cc );	/* zero it */
X	else
X	    memcpy( bp, data+off, cc );	/* else copy in */
X	bp += cc;			/* update pointer */
X	rem -= cc;			/* amount remaining */
X	off = 0;			/* no more offset */
X    }
X
X    cc = count - rem;			/* how much we actually read */
X    fp->pos += cc;			/* updatefile pointer */
X    return( cc );			/* return it too */
X}
X
Xu_char *
Xgetzone( struct super *sp, zone_t zone ) {
X    int zs;
X
X    /* allocate a buffer */
X    static u_char buf[ BLOCKSIZE * 2 ];	/* UGH! FIXME */
X
X    if( zone < sp->izone )
X	return( NULL );
X
X    zs = ZONESIZE(sp);
X    if( !diskread( sp->fp, zs * zone, buf, zs ) )
X	return( NULL );
X    return( buf );
X}
X
X/* convert file zone number to fs zone number */
Xdaddr_t
Xfz2fsz( zone_t zone, struct iinode *ip, int writing ) {
X    if( zone < NDIR )			/* in a direct zone? */
X	zone = ip->i.zones[zone];	/* yes. */
X    else {				/* not direct... */
X	zone_t *ind;			/* indirect zone pointer */
X
X	zone -= NDIR;
X	if( zone < PPZONE(ip->super) )	/* single indirect? */
X	    ind = (zone_t *) getzone( ip->super, ip->i.indir ); /* yes */
X	else {
X# ifdef SMALL
X	    ind = NULL;
X# else
X	    zone -= PPZONE(ip->super);
X	    /* get level 2 indirect block */
X	    ind = (zone_t *) getzone( ip->super, ip->i.dindir );
X	    if( ind == NULL )		/* failed? */
X		return( BADZONE );
X
X	    /* get level 1 indirect block */
X	    ind = (zone_t *) getzone( ip->super,
X				     ind[ zone >> PPZONESHFT(ip->super) ] );
X	    zone &= PPZONEMASK(ip->super);
X# endif
X	}
X	if( ind == NULL )
X	    return( BADZONE );
X	zone = ind[ zone ];
X    } /* not direct */
X    return( zone );			/* for better or worse */
X}
X
Xstatic struct iinode *
Xiget( struct super *sp, inum_t inum ) {
X    struct iinode *ip, *fip;
X    int i;
X
X    if( inum < 1 || inum >= sp->ninodes )
X	return( NULL );			/* bad inum */
X
X    /* UGH... */
X    fip = NULL;
X    for( i = 0, ip = inodes; i < MAXINODE; i++, ip++ )
X	if( ip->refcount > 0 ) {
X	    if( sp == ip->super && inum == ip->inum )
X		break;
X	}
X	else if( fip == NULL )
X	    fip = ip;
X
X    if( i == MAXINODE ) {		/* search failed */
X	struct dinode *dp;
X
X	ip = fip;
X	if( ip == NULL ) {		/* no free slots */
X	    errno = EMFILE;		/* too many super blocks in core */
X	    return( NULL );
X	}
X
X	dp = ((struct dinode *) getzone( sp, sp->izone +
X					((inum-1) >> IPZONESHFT(sp))) );
X	if( dp == NULL )		/* hmm! */
X	    return( NULL );		/* can directories have zero blocks? */
X
X	memcpy( (u_char *) (&ip->i),
X	       (u_char *) (dp + ((inum-1) & IPZONEMASK(sp))),
X	       sizeof( struct dinode ) );
X	ip->super = sp;
X	ip->inum = inum;
X# ifdef MINIX_WRITE
X	ip->dirty = FALSE;
X# endif
X    }
X    /* ...UGH */
X    sp->refcount++;
X    ip->refcount++;
X    return( ip );
X}
X
Xstatic void
Xirel( struct iinode *ip ) {		/* release in core inode */
X    ip->refcount--;			/* start race */
X    if( ip->refcount < 1 ) {
X	relsuper( ip->super );
X	ip->refcount = 0;
X    }
X}
X
X/* get a zone from a file */
Xu_char *
Xgetfilezone( struct iinode *ip, zone_t zone ) {
X    return( getzone( ip->super, fz2fsz( zone, ip, FALSE ) ) );
X}
X
Xstatic struct dirent *
Xdirsearch( struct iinode *ip, u_char *name ) {
X    int n, dpz, z;
X    struct dirent *dp;
X
X# ifdef DEBUG
X    printf("searching %d for %s\n", ip->inum, name );
X# endif
X
X    dpz = DPZONE(ip->super);
X    n = ip->i.size / sizeof( struct dirent );
X    for( z = 0; n > 0; z++ ) {
X	int i, j;
X
X	j = n;				/* remaining dirents */
X	if( j > dpz )			/* more than a zone? */
X	    j = dpz;			/* look at just one zone's worth */
X
X	dp = (struct dirent *) getfilezone( ip, z ); /* get zone */
X	if( dp == NULL )		/* failed. */
X	    break;
X
X	for( i = 0; i < j; i++, n--, dp++ ) { /* for each dirent in zone */
X	    if( dp->inum == 0 )
X		continue;		/* just op == OLD for now.. */
X
X# ifdef DEBUG
X	    printf(" %s %d\n", dp->name, dp->inum );
X# endif
X	    if( memcmp( dp->name, name, NAMELEN ) == 0 )
X		return( dp );
X	}
X    }
X    return( NULL );
X}
X
X/* convert path to inode */
Xstruct iinode *
Xnamei( struct super *sp, u_char *name, enum nameop op ) {
X    struct iinode *ip;
X    u_char buf[ 512 ], *bp;
X
X    ip = iget( sp, ROOTINUM );		/* always start at root */
X    while( *name ) {
X	struct dirent *dp;
X
X	while( *name && *name == '/' )	/* consume leading slashes */
X	    name++;
X
X	if( *name == EOS )		/* no more? */
X	    break;			/* all done */
X
X	memset( buf, EOS, NAMELEN );	/* clear buffer */
X	bp = buf;			/* reset buf pointer */
X	while( *name && *name != '/' )	/* copy until slash */
X	    *bp++ = *name++;
X
X	/* search dir for name in buf */
X	dp = dirsearch( ip, buf );
X	if( dp == NULL ) {
X	    /* just op == OLD for now */
X	    irel( ip );			/* release old inode */
X	    errno = ENOENT;
X	    return( NULL );
X	}
X	irel( ip );			/* release old inode */
X	ip = iget( sp, dp->inum );	/* get the new inode */
X
X	if( *name == EOS ) {		/* reached end? */
X	    /* just op == OLD for now */
X	    break;			/* yes! */
X	}
X
X	/* ie; open("foo/") yields NOTDIR if foo is regular! */
X	if( (ip->i.mode>>FMTSHFT) != FMTDIR ) {
X	    errno = ENOTDIR;
X	    irel( ip );
X	    return( NULL );
X	}
X	/* check for execute permission? as who? */
X	if( !(ip->i.mode & 0111) ) {	/* why not */
X	    errno = EACCES;
X	    irel( ip );
X	    return( NULL );
X	}
X    }
X
X    switch( ip->i.mode >> FMTSHFT ) {
X    case FMTREG:
X	return( ip );
X
X    case FMTDIR:			/* for now... */
X	errno = EISDIR;			/* don't read dirs!! */
X	break;
X
X    default:
X	errno = EIO;			/* must be special, FIFO */
X	break;				/* or some other junk! */
X    }
X    irel( ip );
X    return( NULL );
X}
X# ifdef MINIX_WRITE
X
X/* find first free bit in map */
Xstatic int
Xbitalloc( bmap *map, int size ) {
X    int i, n, j;
X
X    n = (size+BMAPSIZE-1) / BMAPSIZE;
X    for( i = 0; i < n; i++ )
X	if( map[i] != 0 )
X	    break;
X
X    if( i == n )
X	return( -1 );			/* no mo */
X
X    /* find first (highest order) bit set in this element */
X    j = 0;
X    while( (map[i] & BIT(j)) == 0 )
X	j++;
X
X    map[i] ^= BIT(j);			/* clear it */
X    return( i * BMAPSIZE + j );
X}
X
Xstatic int
Xzalloc( struct super *sp ) {
X    return( bitalloc( sp->zmap, sp->nzones ) );
X}
X
Xstatic int
Xialloc( struct super *sp ) {
X    return( bitalloc( sp->imap, sp->ninodes ) );
X}
X
Xstatic void
Xzfree( struct super *sp, zone_t z ) {
X    SETBIT( sp->zmap, z );
X}
X
Xstatic void
Xifree( struct super *sp, inode_t i ) {
X    SETBIT( sp->imap, i );
X}
X
Xstatic int
Xminixwrite( struct file *fp, u_char buf, int count ) {
X    u_char *data, *bp;
X    struct iinode *ip;
X    struct super *sp;
X    int z, off, cc, rem, zs;
X
X    ip = fp->data;
X    sp = ip->super;
X
X    if( fp->pos > sp->maxfile )		/* past legal limit? */
X	ERR(EIO);			/* ?! */
X
X    if( fp->pos + count > sp->maxfile ) /* would run past limit? */
X	count = sp->maxfile - fp->pos;	/* make write return short */
X
X    cc  = 0;
X
X    zs  = ZONESIZE(sp);
X    z   = fp->pos >> ZONESHFT(sp);	/* figure initial logical zone */
X    off = fp->pos &  ZONEMASK(sp);	/* and offset into it */
X
X    if( off != 0 ) {
X	u_char *dp;
X
X	dp = getfilezone( ip, z );
X	if( dp == BADZONE )		/* none there? */
X	    dp = newzone();		/* allocate one, with zeroed buffer */
X
X	/* copy in first partial block */
X    }
X
X    return( -1 );
X}
X# endif /* MINIX_WRITE */
X# endif /* MINIX */
END_OF_minix.c
if test 16046 -ne `wc -c <minix.c`; then
    echo shar: \"minix.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f scsi_low.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"scsi_low.c\"
else
echo shar: Extracting \"scsi_low.c\" \(13400 characters\)
sed "s/^X//" >scsi_low.c <<'END_OF_scsi_low.c'
X/****************************************************************************
X * NS32K Monitor SCSI low-level driver
X * Bruce Culbertson
X * 8 March 1990
X *
X * Adapted from Minix SCSI driver.  Do not use DMA -- makes 32016 and pc532
X * versions compatible.  Do not use interrupts -- makes it harder for the
X * user code to bomb this code.
X ****************************************************************************/
X#include "so.h"
X#include "stdlib.h"			/* budd */
X/*
X#define OK 		0
X#define NOT_OK		OK+1
X*/
X#define	PRIVATE		static
X#define PUBLIC
X#define WR_ADR(adr,val)	(*((volatile unsigned char *)(adr))=(val))
X#define RD_ADR(adr)	(*((volatile unsigned char *)(adr)))
X#define AIC6250		0
X#define DP8490		1
X#define MAX_CACHE	0x10000
X
X/* SCSI bus phases
X */
X#define PH_ODATA	0
X#define PH_IDATA	1
X#define PH_CMD		2
X#define PH_STAT		3
X#define PH_IMSG		7
X#define PH_NONE		8
X#define PH_IN(phase)	((phase) & 1)
X
X/* NCR5380 SCSI controller registers
X */
X#define SC_CTL		0x30000000	/* base for control registers */
X#define SC_DMA		0x38000000	/* base for data registers */
X#define SC_CURDATA	SC_CTL+0
X#define SC_OUTDATA	SC_CTL+0
X#define SC_ICMD		SC_CTL+1
X#define SC_MODE		SC_CTL+2
X#define SC_TCMD		SC_CTL+3
X#define SC_STAT1	SC_CTL+4
X#define SC_STAT2	SC_CTL+5
X#define SC_START_SEND	SC_CTL+5
X#define SC_INDATA	SC_CTL+6
X#define SC_RESETIP	SC_CTL+7
X#define SC_START_RCV	SC_CTL+7
X
X/* Bits in NCR5380 registers
X */
X#define SC_A_RST	0x80
X#define SC_A_SEL	0x04
X#define SC_S_SEL	0x02
X#define SC_S_REQ	0x20
X#define SC_S_BSY	0x40
X#define SC_S_BSYERR	0x04
X#define SC_S_PHASE	0x08
X#define SC_S_IRQ	0x10
X#define SC_S_DRQ	0x40
X#define SC_M_DMA	0x02
X#define SC_M_BSY	0x04
X#define SC_ENABLE_DB	0x01
X
X/* Status of interrupt routine, returned in m1_i1 field of message.
X */
X#define ISR_NOTDONE	0
X#define ISR_OK		1
X#define ISR_BSYERR	2
X#define ISR_RSTERR	3
X#define ISR_BADPHASE	4
X#define ISR_TIMEOUT	5
X
X#define ICU_ADR		0xfffffe00
X#define ICU_IO		(ICU_ADR+20)
X#define ICU_DIR		(ICU_ADR+21)
X#define ICU_DATA	(ICU_ADR+19)
X#define ICU_SCSI_BIT	0x80
X
X/* Miscellaneous
X */
X#define MAX_WAIT	2000000
X#define SC_LOG_LEN	32
X
X/* budd: forwards; */
XPRIVATE void sc_reset(), scCtlrSelect(), sc_dma_setup();
XPRIVATE int sc_wait_bus_free(), sc_select(), sc_receive();
X
XPRIVATE struct scsi_args	*sc_ptrs;
XPRIVATE char			sc_cur_phase,
X				sc_reset_done,
X				sc_have_msg,
X				sc_accept_int,
X				sc_dma_dir;
X
Xlong	sc_dma_port = SC_DMA,
X	sc_dma_adr;
X
X#ifdef DEBUG
Xstruct sc_log {
X  unsigned char stat1, stat2;
X}				sc_log [SC_LOG_LEN],
X				*sc_log_head = sc_log;
Xint				sc_spurious_int;
X#endif
Xunsigned char
X	sc_watchdog_error;		/* watch dog error */
X
X/* error messages */
Xchar *scsi_errors[] = {
X  0,					/* ISR_NOTDONE */
X  0,					/* ISR_OK */
X  "busy error",				/* ISR_BSYERR */
X  "reset error",			/* ISR_RSTERR */
X  "NULL pointer for current phase",	/* ISR_BADPHASE */
X  "timeout",				/* ISR_TIMEOUT */
X};
X
X/*===========================================================================*
X *				exec_scsi_low				     * 
X *===========================================================================*/
X/* Execute a generic SCSI command.  Passed pointers to eight buffers:
X * data-out, data-in, command, status, dummy, dummy, message-out, message-in.
X */
XPUBLIC
Xint
Xexec_scsi_low (args, scsi_adr)
Xstruct scsi_args *args;
Xlong scsi_adr;
X{
X  int ret;
X
X  sc_ptrs = args;			/* make pointers globally accessible */
X  scCtlrSelect (DP8490);
X  if (!sc_reset_done) sc_reset();
X  /* TCMD has some undocumented behavior in initiator mode.  I think the
X   * data bus cannot be enabled if i/o is asserted.
X   */
X  WR_ADR (SC_TCMD, 0);
X  if (OK != sc_wait_bus_free ()) {	/* bus-free phase */
X    printf("SCSI: bus not free\n");
X    return NOT_OK;
X  }
X  sc_cur_phase = PH_NONE;
X  sc_have_msg = 0;
X  if (OK != sc_select (scsi_adr))	/* select phase */
X    return NOT_OK;
X  sc_watchdog_error = 0;
X  ret = sc_receive ();			/* isr does the rest */
X  if (ret == ISR_OK) return OK;
X  else {
X    sc_reset();
X    printf("SCSI: %s\n", scsi_errors[ret]);
X    return NOT_OK;
X  }
X}
X
X/*===========================================================================*
X *				sc_reset				     * 
X *===========================================================================*/
X/*
X * Reset SCSI bus.
X */
XPRIVATE void
Xsc_reset()
X{
X  volatile int i;
X
X  WR_ADR (SC_MODE, 0);			/* get into harmless state */
X  WR_ADR (SC_OUTDATA, 0);
X  WR_ADR (SC_ICMD, SC_A_RST);		/* assert RST on SCSI bus */
X  i = 200;				/* wait 25 usec */
X  while (i--);
X  WR_ADR (SC_ICMD, 0);			/* deassert RST, get off bus */
X  sc_reset_done = 1;
X}
X
X/*===========================================================================*
X *				sc_wait_bus_free			     * 
X *===========================================================================*/
XPRIVATE int
Xsc_wait_bus_free()
X{
X  int i = MAX_WAIT;
X  volatile int j;
X
X  while (i--) {
X    /* Must be clear for 2 usec, so read twice */
X    if (RD_ADR (SC_STAT1) & (SC_S_BSY | SC_S_SEL)) continue;
X    for (j = 0; j < 25; ++j);
X    if (RD_ADR (SC_STAT1) & (SC_S_BSY | SC_S_SEL)) continue;
X    return OK;
X  }
X  sc_reset_done = 0;
X  return NOT_OK;
X}
X
X/*===========================================================================*
X *				sc_select				     * 
X *===========================================================================*/
X/* This duplicates much of the work that the interrupt routine would do on a
X * phase mismatch and, in fact, the original plan was to just do the select,
X * let a phase mismatch occur, and let the interrupt routine do the rest.
X * That didn't work because the 5380 did not reliably generate the phase
X * mismatch interrupt after selection.
X */
XPRIVATE int
Xsc_select(adr)
Xlong adr;
X{
X  int i, stat1;
X  long new_ptr;
X
X  WR_ADR (SC_OUTDATA, adr);		/* SCSI bus address */
X  WR_ADR (SC_ICMD, SC_A_SEL | SC_ENABLE_DB);
X  for (i = 0;; ++i) {			/* wait for target to assert SEL */
X    stat1 = RD_ADR (SC_STAT1);
X    if (stat1 & SC_S_BSY) break;	/* select successful */
X    if (i > MAX_WAIT) {			/* timeout */
X      printf("SCSI: SELECT timeout\n");
X      sc_reset();
X      return NOT_OK;
X    }
X  }
X  WR_ADR (SC_ICMD, 0);			/* clear SEL, disable data out */
X  WR_ADR (SC_OUTDATA, 0);
X  for (i = 0;; ++i) {			/* wait for target to assert REQ */
X    if (stat1 & SC_S_REQ) break;	/* target requesting transfer */
X    if (i > MAX_WAIT) {			/* timeout */
X      printf("SCSI: REQ timeout\n");
X      sc_reset();
X      return NOT_OK;
X    }
X    stat1 = RD_ADR (SC_STAT1);
X  }
X  sc_cur_phase = (stat1 >> 2) & 7;	/* get new phase from controller */
X  if (sc_cur_phase != PH_CMD) {
X    printf("SCSI: bad phase = %d\n", sc_cur_phase);
X    sc_reset();
X    return NOT_OK;
X  }
X  new_ptr = sc_ptrs->ptr[PH_CMD];
X  if (new_ptr == 0) {
X    printf("SCSI: NULL command pointer\n");
X    sc_reset();
X    return NOT_OK;
X  }
X  sc_accept_int = 1;
X  sc_dma_setup (DISK_WRITE, new_ptr);
X  WR_ADR (SC_TCMD, PH_CMD);
X  WR_ADR (SC_ICMD, SC_ENABLE_DB);
X  WR_ADR (SC_MODE, SC_M_BSY | SC_M_DMA);
X  WR_ADR (SC_START_SEND, 0);
X  return OK;
X}
X
X/*===========================================================================*
X *				scsi_interrupt				     *
X *===========================================================================*/
X/* SCSI interrupt handler.
X */
XPUBLIC
Xint
Xscsi_interrupt()
X{
X  unsigned char stat2, dummy;
X  long new_ptr;
X  int ret = ISR_NOTDONE;
X
X  stat2 = RD_ADR (SC_STAT2);		/* get status before clearing request */
X
X# ifdef DEBUG				/* debugging log of interrupts */
X  sc_log_head->stat1 = RD_ADR (SC_STAT1);
X  sc_log_head->stat2 = stat2;
X  if (++sc_log_head >= sc_log + SC_LOG_LEN) sc_log_head = sc_log;
X  sc_log_head->stat1 = sc_log_head->stat2 = 0xff;
X# endif
X
X  for (;;) {
X    dummy = RD_ADR (SC_RESETIP);	/* clear interrupt request */
X    if (!sc_accept_int ||		/* return if spurious interrupt */
X        (!sc_watchdog_error &&
X         (stat2 & SC_S_BSYERR) == 0 && (stat2 & SC_S_PHASE) == 1))
X    {
X#     ifdef DEBUG
X        ++sc_spurious_int;
X#     endif
X      return ret;
X    }
X    RD_ADR (SC_MODE) &= ~SC_M_DMA;	/* clear DMA mode */
X    WR_ADR (SC_ICMD, 0);		/* disable data bus */
X    if (sc_cur_phase != PH_NONE) {	/* if did DMA, save the new pointer */
X      new_ptr = sc_dma_adr;		/* fetch new pointer from DMA cntlr */
X      if (sc_cur_phase == PH_IMSG &&	/* have message? */
X        new_ptr != sc_ptrs->ptr[PH_IMSG]) sc_have_msg = 1;
X      sc_ptrs->ptr[sc_cur_phase] =	/* save pointer */
X        new_ptr;
X    }
X    if (sc_watchdog_error) ret = ISR_TIMEOUT;
X    else if (stat2 & SC_S_BSYERR) {	/* target deasserted BSY? */
X      if (sc_have_msg) ret = ISR_OK;
X      else ret = ISR_BSYERR;
X    } else if (!(stat2 & SC_S_PHASE)) {	/* if phase mismatch, setup new phase */
X      sc_cur_phase = 			/* get new phase from controller */
X        (RD_ADR (SC_STAT1) >> 2) & 7;
X      new_ptr = sc_ptrs->ptr[sc_cur_phase];
X      if (new_ptr == 0) ret = ISR_BADPHASE;
X      else {
X        WR_ADR (SC_TCMD, sc_cur_phase);	/* write new phase into TCMD */
X        if (PH_IN (sc_cur_phase)) {	/* set DMA controller */
X          sc_dma_setup (DISK_READ, new_ptr);
X          RD_ADR (SC_MODE) |= SC_M_DMA;
X          WR_ADR (SC_START_RCV, 0);	/* tell SCSI to start DMA */
X	} else {
X          sc_dma_setup (DISK_WRITE, new_ptr);
X	  RD_ADR (SC_MODE) |= SC_M_DMA;
X	  WR_ADR (SC_ICMD, SC_ENABLE_DB);
X	  WR_ADR (SC_START_SEND, 0);
X	}
X      }
X    } else ret = ISR_RSTERR;
X    if (ret != ISR_NOTDONE) {		/* if done, send message to task */
X      sc_watchdog_error = 0;
X      sc_accept_int = 0;
X      WR_ADR (SC_MODE, 0);		/* clear monbsy, dma */
X      break;				/* reti re-enables ints */
X    }
X    if (0 == ((stat2 =			/* check for another interrupt */
X      RD_ADR (SC_STAT2)) & SC_S_IRQ)) 
X    {
X      break;
X    }
X  }
X  return ret;
X}
X
X/*===========================================================================*
X *				sc_dma_setup				     *
X *===========================================================================*/
X/* Fake DMA setup.  Just store pointers and direction in global variables.
X *
X * The pseudo-DMA is subtler than it looks because of the cache.
X *
X * 1)	When accessing I/O devices through a cache, some mechanism is
X *	necessary to ensure you access the device rather than the cache.
X *	On the 32532, the IODEC signal is supposed to be asserted for I/O
X *	addresses to accomplish this.  However, a bug makes this much
X *	slower than necessary and severely hurts pseudo-DMA performance.
X *	Hence, IODEC is not asserted for the SCSI DMA port.
X *
X * 2)	Because of (1), we must devise our own method of forcing the
X *	SCSI DMA port to be read.  0x8000000 addresses have been decoded
X *	to all access this port.  By always using new addresses to access
X *	the DMA port (wrapping only after reading MAX_CACHE bytes), we
X *	force cache misses and, hence, device reads.  Since the cache
X *	is write-through, we do not need to worry about writes.
X *
X * 3)	It is possible to miss the last few bytes of a transfer if
X *	bus transfer size is not considered.  The loop in sc_receive()
X *	transfers data until the interrupt signal is asserted.  If
X *	bytes are transferred, the attempt to move the first byte of a
X *	double word causes the whole word to be read into the cache.
X *	Then the byte is transferred.  If reading the double word
X *	completed the SCSI transfer, then the loop exits since
X *	interrupt is asserted.  However, the last few bytes have only
X *	been moved into the cache -- they have not been moved to the
X *	DMA destination.
X *
X * 4)	It is also possible to miss the first few bytes of a transfer.
X *	If the address used to access pseudo-dma port is not double word
X *	aligned, the whole double word is read into the cache, and then
X *	data is moved from the middle of the word (i.e. something other
X *	than the first bytes read from the SCSI controller) by the
X *	pseudo-dma loop in sc_receive().
X */
XPRIVATE void
Xsc_dma_setup (dir, adr)
Xint dir;
Xlong adr;
X{
X  if (sc_dma_port > SC_DMA + MAX_CACHE) sc_dma_port = SC_DMA;
X  sc_dma_dir = dir;
X  sc_dma_adr = adr;
X}
X
X/*===========================================================================*
X *				sc_receive				     *
X *===========================================================================*/
X/* Replacement for Minix receive(), which waits for a message.  This code
X * spins, waiting for data to transfer or interrupt requests to handle.
X * See sc_dma_setup for details.
X */
Xint
Xsc_receive()
X{
X  int stat2, isr_ret;
X
X  for (;;) {
X    stat2 = RD_ADR (SC_STAT2);
X    if (stat2 & SC_S_IRQ) {
X      if (ISR_NOTDONE != (isr_ret = scsi_interrupt())) break;
X    } else if (stat2 & SC_S_DRQ) {	/* test really not necessary on pc532 */
X      if (sc_dma_dir == DISK_READ)
X	*((long *)sc_dma_adr)++ = *((volatile long *)sc_dma_port)++;
X      else *((volatile long *)sc_dma_port)++ = *((long *)sc_dma_adr)++;
X    }
X  }
X  return isr_ret;
X}
X
X/*===========================================================================*
X *				scCtlrSelect
X *===========================================================================*/
X/* Select a SCSI device.
X */
XPRIVATE void
XscCtlrSelect (ctlr)
Xint ctlr;
X{
X  static current = -1;			/* budd */
X
X  if( ctlr == current )			/* budd */
X      return;				/* budd */
X
X  RD_ADR (ICU_IO) &= ~ICU_SCSI_BIT;	/* i/o, not port */
X  RD_ADR (ICU_DIR) &= ~ICU_SCSI_BIT;	/* output */
X  if (ctlr == DP8490)
X    RD_ADR (ICU_DATA) &= ~ICU_SCSI_BIT;	/* select = 0 for 8490 */
X  else
X    RD_ADR (ICU_DATA) |= ICU_SCSI_BIT;	/* select = 1 for AIC6250 */
X  current = ctlr;			/* budd */
X}
END_OF_scsi_low.c
if test 13400 -ne `wc -c <scsi_low.c`; then
    echo shar: \"scsi_low.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 3 \(of 3\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 3 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
