#! /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 2 (of 3)."
# Contents:  disklabel.h disklabel.h.orig scsi_hi.c scsi_hi.c.orig
#   scsi_low.c.orig
# Wrapped by budd@buit2 on Fri Jun  1 18:13:08 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f disklabel.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"disklabel.h\"
else
echo shar: Extracting \"disklabel.h\" \(9322 characters\)
sed "s/^X//" >disklabel.h <<'END_OF_disklabel.h'
X/*
X * Copyright (c) 1987, 1988 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley.  The name of the
X * University may not be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *
X *	@(#)disklabel.h	7.10 (Berkeley) 6/27/88
X */
X
X/*
X * Disk description table, see disktab(5)
X */
X#define	DISKTAB		"/etc/disktab"
X
X/*
X * Each disk has a label which includes information about the hardware
X * disk geometry, filesystem partitions, and drive specific information.
X * The label is in block 0 or 1, possibly offset from the beginning
X * to leave room for a bootstrap, etc.
X */
X
X/* budd: sector/offset were 0/64 */
X#define LABELSECTOR	1			/* sector containing label */
X#define LABELOFFSET	0			/* offset of label in sector */
X#define DISKMAGIC	((u_long) 0x82564557)	/* The disk magic number */
X#ifndef MAXPARTITIONS
X#define	MAXPARTITIONS	16			/* budd: was 8 */
X						/* w/8  label is 276 bytes */
X						/* 3/16 label is 404 bytes */
X#endif
X
X
X#ifndef LOCORE
Xstruct disklabel {
X	u_long	d_magic;		/* the magic number */
X	short	d_type;			/* drive type */
X	short	d_subtype;		/* controller/d_type specific */
X	char	d_typename[16];		/* type name, e.g. "eagle" */
X	/* 
X	 * d_packname contains the pack identifier and is returned when
X	 * the disklabel is read off the disk or in-core copy.
X	 * d_boot0 and d_boot1 are the (optional) names of the
X	 * primary (block 0) and secondary (block 1-15) bootstraps
X	 * as found in /usr/mdec.  These are returned when using
X	 * getdiskbyname(3) to retrieve the values from /etc/disktab.
X	 */
X#if defined(KERNEL) || defined(STANDALONE)
X	char	d_packname[16];			/* pack identifier */ 
X#else
X	union {
X		char	un_d_packname[16];	/* pack identifier */ 
X		struct {
X			char *un_d_boot0;	/* primary bootstrap name */
X			char *un_d_boot1;	/* secondary bootstrap name */
X		} un_b; 
X	} d_un; 
X#define d_packname	d_un.un_d_packname
X#define d_boot0		d_un.un_b.un_d_boot0
X#define d_boot1		d_un.un_b.un_d_boot1
X#endif	/* ! KERNEL or STANDALONE */
X			/* disk geometry: */
X	u_long	d_secsize;		/* # of bytes per sector */
X	u_long	d_nsectors;		/* # of data sectors per track */
X	u_long	d_ntracks;		/* # of tracks per cylinder */
X	u_long	d_ncylinders;		/* # of data cylinders per unit */
X	u_long	d_secpercyl;		/* # of data sectors per cylinder */
X	u_long	d_secperunit;		/* # of data sectors per unit */
X	/*
X	 * Spares (bad sector replacements) below
X	 * are not counted in d_nsectors or d_secpercyl.
X	 * Spare sectors are assumed to be physical sectors
X	 * which occupy space at the end of each track and/or cylinder.
X	 */
X	u_short	d_sparespertrack;	/* # of spare sectors per track */
X	u_short	d_sparespercyl;		/* # of spare sectors per cylinder */
X	/*
X	 * Alternate cylinders include maintenance, replacement,
X	 * configuration description areas, etc.
X	 */
X	u_long	d_acylinders;		/* # of alt. cylinders per unit */
X
X			/* hardware characteristics: */
X	/*
X	 * d_interleave, d_trackskew and d_cylskew describe perturbations
X	 * in the media format used to compensate for a slow controller.
X	 * Interleave is physical sector interleave, set up by the formatter
X	 * or controller when formatting.  When interleaving is in use,
X	 * logically adjacent sectors are not physically contiguous,
X	 * but instead are separated by some number of sectors.
X	 * It is specified as the ratio of physical sectors traversed
X	 * per logical sector.  Thus an interleave of 1:1 implies contiguous
X	 * layout, while 2:1 implies that logical sector 0 is separated
X	 * by one sector from logical sector 1.
X	 * d_trackskew is the offset of sector 0 on track N
X	 * relative to sector 0 on track N-1 on the same cylinder.
X	 * Finally, d_cylskew is the offset of sector 0 on cylinder N
X	 * relative to sector 0 on cylinder N-1.
X	 */
X	u_short	d_rpm;			/* rotational speed */
X	u_short	d_interleave;		/* hardware sector interleave */
X	u_short	d_trackskew;		/* sector 0 skew, per track */
X	u_short	d_cylskew;		/* sector 0 skew, per cylinder */
X	u_long	d_headswitch;		/* head switch time, usec */
X	u_long	d_trkseek;		/* track-to-track seek, usec */
X	u_long	d_flags;		/* generic flags */
X#define NDDATA 5
X	u_long	d_drivedata[NDDATA];	/* drive-type specific information */
X#define NSPARE 5
X	u_long	d_spare[NSPARE];	/* reserved for future use */
X	u_long	d_magic2;		/* the magic number (again) */
X	u_short	d_checksum;		/* xor of data incl. partitions */
X
X			/* filesystem and partition information: */
X	u_short	d_npartitions;		/* number of partitions in following */
X	u_long	d_bbsize;		/* size of boot area at sn0, bytes */
X	u_long	d_sbsize;		/* max size of fs superblock, bytes */
X	struct	partition {		/* the partition table */
X		u_long	p_size;		/* number of sectors in partition */
X		u_long	p_offset;	/* starting sector */
X		u_long	p_fsize;	/* filesystem basic fragment size */
X		u_char	p_fstype;	/* filesystem type, see below */
X		u_char	p_frag;		/* filesystem fragments per block */
X		u_short	p_cpg;		/* filesystem cylinders per group */
X	} d_partitions[MAXPARTITIONS];	/* actually may be more */
X	/* budd: do not add here!! use d_extra!!! */
X};
X#else LOCORE
X	/*
X	 * offsets for asm boot files.
X	 */
X	.set	d_secsize,40
X	.set	d_nsectors,44
X	.set	d_ntracks,48
X	.set	d_ncylinders,52
X	.set	d_secpercyl,56
X	.set	d_secperunit,60
X	.set	d_end_,276		/* size of disk label */
X#endif LOCORE
X
X/* d_type values: */
X#define	DTYPE_SMD		1		/* SMD, XSMD; VAX hp/up */
X#define	DTYPE_MSCP		2		/* MSCP */
X#define	DTYPE_DEC		3		/* other DEC (rk, rl) */
X#define	DTYPE_SCSI		4		/* SCSI */
X#define	DTYPE_ESDI		5		/* ESDI interface */
X#define	DTYPE_ST506		6		/* ST506 etc. */
X#define	DTYPE_FLOPPY		10		/* floppy */
X
X#ifdef DKTYPENAMES
Xstatic char *dktypenames[] = {
X	"unknown",
X	"SMD",
X	"MSCP",
X	"old DEC",
X	"SCSI",
X	"ESDI",
X	"type 6",
X	"type 7",
X	"type 8",
X	"type 9",
X	"floppy",
X	0
X};
X#define DKMAXTYPES	(sizeof(dktypenames) / sizeof(dktypenames[0]) - 1)
X#endif
X
X/*
X * Filesystem type and version.
X * Used to interpret other filesystem-specific
X * per-partition information.
X */
X#define	FS_UNUSED	0		/* unused */
X#define	FS_SWAP		1		/* swap */
X#define	FS_V6		2		/* Sixth Edition */
X#define	FS_V7		3		/* Seventh Edition */
X#define	FS_SYSV		4		/* System V */
X#define	FS_V71K		5		/* V7 with 1K blocks (4.1, 2.9) */
X#define	FS_V8		6		/* Eighth Edition, 4K blocks */
X#define	FS_BSDFFS	7		/* 4.2BSD fast file system */
X
X#define FS_MINIX	10		/* budd: Minix FS */
X/* use p_fsize for "block" size? (usu. 1K) */
X
X#ifdef	DKTYPENAMES
Xstatic char *fstypenames[] = {
X	"unused",
X	"swap",
X	"Version 6",
X	"Version 7",
X	"System V",
X	"4.1BSD",
X	"Eighth Edition",
X	"4.2BSD",
X	"unused",			/* budd */
X	"unused",			/* budd */
X	"unused",			/* budd */
X	"Minix"				/* budd */
X	0
X};
X#define FSMAXTYPES	(sizeof(fstypenames) / sizeof(fstypenames[0]) - 1)
X#endif
X
X/*
X * flags shared by various drives:
X */
X#define		D_REMOVABLE	0x01		/* removable media */
X#define		D_ECC		0x02		/* supports ECC */
X#define		D_BADSECT	0x04		/* supports bad sector forw. */
X#define		D_RAMDISK	0x08		/* disk emulator */
X#define		D_CHAIN		0x10		/* can do back-back transfers */
X
X/*
X * Drive data for SMD.
X */
X#define	d_smdflags	d_drivedata[0]
X#define		D_SSE		0x1		/* supports skip sectoring */
X#define	d_mindist	d_drivedata[1]
X#define	d_maxdist	d_drivedata[2]
X#define	d_sdist		d_drivedata[3]
X
X/*
X * Drive data for ST506.
X */
X#define d_precompcyl	d_drivedata[0]
X#define d_gap3		d_drivedata[1]		/* used only when formatting */
X
X#ifndef LOCORE
X/*
X * Structure used to perform a format
X * or other raw operation, returning data
X * and/or register values.
X * Register identification and format
X * are device- and driver-dependent.
X */
Xstruct format_op {
X	char	*df_buf;
X	int	df_count;		/* value-result */
X	daddr_t	df_startblk;
X	int	df_reg[8];		/* result */
X};
X
X/*
X * Structure used internally to retrieve
X * information about a partition on a disk.
X */
Xstruct partinfo {
X	struct disklabel *disklab;
X	struct partition *part;
X};
X
X/*
X * Disk-specific ioctls.
X */
X		/* get and set disklabel; DIOCGPART used internally */
X#define DIOCGDINFO	_IOR('d', 101, struct disklabel)/* get */
X#define DIOCSDINFO	_IOW('d', 102, struct disklabel)/* set */
X#define DIOCWDINFO	_IOW('d', 103, struct disklabel)/* set, update disk */
X#define DIOCGPART	_IOW('d', 104, struct partinfo)	/* get partition */
X
X/* do format operation, read or write */
X#define DIOCRFORMAT	_IOWR('d', 105, struct format_op)
X#define DIOCWFORMAT	_IOWR('d', 106, struct format_op)
X
X#define DIOCSSTEP	_IOW('d', 107, int)	/* set step rate */
X#define DIOCSRETRIES	_IOW('d', 108, int)	/* set # of retries */
X#define DIOCWLABEL	_IOW('d', 109, int)	/* write en/disable label */
X
X#define DIOCSBAD	_IOW('d', 110, struct dkbad)	/* set kernel dkbad */
X
X#endif LOCORE
X
X#if !defined(KERNEL) && !defined(LOCORE)
Xstruct	disklabel *getdiskbyname();
X#endif
END_OF_disklabel.h
if test 9322 -ne `wc -c <disklabel.h`; then
    echo shar: \"disklabel.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f disklabel.h.orig -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"disklabel.h.orig\"
else
echo shar: Extracting \"disklabel.h.orig\" \(8964 characters\)
sed "s/^X//" >disklabel.h.orig <<'END_OF_disklabel.h.orig'
X/*
X * Copyright (c) 1987, 1988 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley.  The name of the
X * University may not be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *
X *	@(#)disklabel.h	7.10 (Berkeley) 6/27/88
X */
X
X/*
X * Disk description table, see disktab(5)
X */
X#define	DISKTAB		"/etc/disktab"
X
X/*
X * Each disk has a label which includes information about the hardware
X * disk geometry, filesystem partitions, and drive specific information.
X * The label is in block 0 or 1, possibly offset from the beginning
X * to leave room for a bootstrap, etc.
X */
X
X#define LABELSECTOR	0			/* sector containing label */
X#define LABELOFFSET	64			/* offset of label in sector */
X#define DISKMAGIC	((u_long) 0x82564557)	/* The disk magic number */
X#ifndef MAXPARTITIONS
X#define	MAXPARTITIONS	8
X#endif
X
X
X#ifndef LOCORE
Xstruct disklabel {
X	u_long	d_magic;		/* the magic number */
X	short	d_type;			/* drive type */
X	short	d_subtype;		/* controller/d_type specific */
X	char	d_typename[16];		/* type name, e.g. "eagle" */
X	/* 
X	 * d_packname contains the pack identifier and is returned when
X	 * the disklabel is read off the disk or in-core copy.
X	 * d_boot0 and d_boot1 are the (optional) names of the
X	 * primary (block 0) and secondary (block 1-15) bootstraps
X	 * as found in /usr/mdec.  These are returned when using
X	 * getdiskbyname(3) to retrieve the values from /etc/disktab.
X	 */
X#if defined(KERNEL) || defined(STANDALONE)
X	char	d_packname[16];			/* pack identifier */ 
X#else
X	union {
X		char	un_d_packname[16];	/* pack identifier */ 
X		struct {
X			char *un_d_boot0;	/* primary bootstrap name */
X			char *un_d_boot1;	/* secondary bootstrap name */
X		} un_b; 
X	} d_un; 
X#define d_packname	d_un.un_d_packname
X#define d_boot0		d_un.un_b.un_d_boot0
X#define d_boot1		d_un.un_b.un_d_boot1
X#endif	/* ! KERNEL or STANDALONE */
X			/* disk geometry: */
X	u_long	d_secsize;		/* # of bytes per sector */
X	u_long	d_nsectors;		/* # of data sectors per track */
X	u_long	d_ntracks;		/* # of tracks per cylinder */
X	u_long	d_ncylinders;		/* # of data cylinders per unit */
X	u_long	d_secpercyl;		/* # of data sectors per cylinder */
X	u_long	d_secperunit;		/* # of data sectors per unit */
X	/*
X	 * Spares (bad sector replacements) below
X	 * are not counted in d_nsectors or d_secpercyl.
X	 * Spare sectors are assumed to be physical sectors
X	 * which occupy space at the end of each track and/or cylinder.
X	 */
X	u_short	d_sparespertrack;	/* # of spare sectors per track */
X	u_short	d_sparespercyl;		/* # of spare sectors per cylinder */
X	/*
X	 * Alternate cylinders include maintenance, replacement,
X	 * configuration description areas, etc.
X	 */
X	u_long	d_acylinders;		/* # of alt. cylinders per unit */
X
X			/* hardware characteristics: */
X	/*
X	 * d_interleave, d_trackskew and d_cylskew describe perturbations
X	 * in the media format used to compensate for a slow controller.
X	 * Interleave is physical sector interleave, set up by the formatter
X	 * or controller when formatting.  When interleaving is in use,
X	 * logically adjacent sectors are not physically contiguous,
X	 * but instead are separated by some number of sectors.
X	 * It is specified as the ratio of physical sectors traversed
X	 * per logical sector.  Thus an interleave of 1:1 implies contiguous
X	 * layout, while 2:1 implies that logical sector 0 is separated
X	 * by one sector from logical sector 1.
X	 * d_trackskew is the offset of sector 0 on track N
X	 * relative to sector 0 on track N-1 on the same cylinder.
X	 * Finally, d_cylskew is the offset of sector 0 on cylinder N
X	 * relative to sector 0 on cylinder N-1.
X	 */
X	u_short	d_rpm;			/* rotational speed */
X	u_short	d_interleave;		/* hardware sector interleave */
X	u_short	d_trackskew;		/* sector 0 skew, per track */
X	u_short	d_cylskew;		/* sector 0 skew, per cylinder */
X	u_long	d_headswitch;		/* head switch time, usec */
X	u_long	d_trkseek;		/* track-to-track seek, usec */
X	u_long	d_flags;		/* generic flags */
X#define NDDATA 5
X	u_long	d_drivedata[NDDATA];	/* drive-type specific information */
X#define NSPARE 5
X	u_long	d_spare[NSPARE];	/* reserved for future use */
X	u_long	d_magic2;		/* the magic number (again) */
X	u_short	d_checksum;		/* xor of data incl. partitions */
X
X			/* filesystem and partition information: */
X	u_short	d_npartitions;		/* number of partitions in following */
X	u_long	d_bbsize;		/* size of boot area at sn0, bytes */
X	u_long	d_sbsize;		/* max size of fs superblock, bytes */
X	struct	partition {		/* the partition table */
X		u_long	p_size;		/* number of sectors in partition */
X		u_long	p_offset;	/* starting sector */
X		u_long	p_fsize;	/* filesystem basic fragment size */
X		u_char	p_fstype;	/* filesystem type, see below */
X		u_char	p_frag;		/* filesystem fragments per block */
X		u_short	p_cpg;		/* filesystem cylinders per group */
X	} d_partitions[MAXPARTITIONS];	/* actually may be more */
X};
X#else LOCORE
X	/*
X	 * offsets for asm boot files.
X	 */
X	.set	d_secsize,40
X	.set	d_nsectors,44
X	.set	d_ntracks,48
X	.set	d_ncylinders,52
X	.set	d_secpercyl,56
X	.set	d_secperunit,60
X	.set	d_end_,276		/* size of disk label */
X#endif LOCORE
X
X/* d_type values: */
X#define	DTYPE_SMD		1		/* SMD, XSMD; VAX hp/up */
X#define	DTYPE_MSCP		2		/* MSCP */
X#define	DTYPE_DEC		3		/* other DEC (rk, rl) */
X#define	DTYPE_SCSI		4		/* SCSI */
X#define	DTYPE_ESDI		5		/* ESDI interface */
X#define	DTYPE_ST506		6		/* ST506 etc. */
X#define	DTYPE_FLOPPY		10		/* floppy */
X
X#ifdef DKTYPENAMES
Xstatic char *dktypenames[] = {
X	"unknown",
X	"SMD",
X	"MSCP",
X	"old DEC",
X	"SCSI",
X	"ESDI",
X	"type 6",
X	"type 7",
X	"type 8",
X	"type 9",
X	"floppy",
X	0
X};
X#define DKMAXTYPES	(sizeof(dktypenames) / sizeof(dktypenames[0]) - 1)
X#endif
X
X/*
X * Filesystem type and version.
X * Used to interpret other filesystem-specific
X * per-partition information.
X */
X#define	FS_UNUSED	0		/* unused */
X#define	FS_SWAP		1		/* swap */
X#define	FS_V6		2		/* Sixth Edition */
X#define	FS_V7		3		/* Seventh Edition */
X#define	FS_SYSV		4		/* System V */
X#define	FS_V71K		5		/* V7 with 1K blocks (4.1, 2.9) */
X#define	FS_V8		6		/* Eighth Edition, 4K blocks */
X#define	FS_BSDFFS	7		/* 4.2BSD fast file system */
X
X#ifdef	DKTYPENAMES
Xstatic char *fstypenames[] = {
X	"unused",
X	"swap",
X	"Version 6",
X	"Version 7",
X	"System V",
X	"4.1BSD",
X	"Eighth Edition",
X	"4.2BSD",
X	0
X};
X#define FSMAXTYPES	(sizeof(fstypenames) / sizeof(fstypenames[0]) - 1)
X#endif
X
X/*
X * flags shared by various drives:
X */
X#define		D_REMOVABLE	0x01		/* removable media */
X#define		D_ECC		0x02		/* supports ECC */
X#define		D_BADSECT	0x04		/* supports bad sector forw. */
X#define		D_RAMDISK	0x08		/* disk emulator */
X#define		D_CHAIN		0x10		/* can do back-back transfers */
X
X/*
X * Drive data for SMD.
X */
X#define	d_smdflags	d_drivedata[0]
X#define		D_SSE		0x1		/* supports skip sectoring */
X#define	d_mindist	d_drivedata[1]
X#define	d_maxdist	d_drivedata[2]
X#define	d_sdist		d_drivedata[3]
X
X/*
X * Drive data for ST506.
X */
X#define d_precompcyl	d_drivedata[0]
X#define d_gap3		d_drivedata[1]		/* used only when formatting */
X
X#ifndef LOCORE
X/*
X * Structure used to perform a format
X * or other raw operation, returning data
X * and/or register values.
X * Register identification and format
X * are device- and driver-dependent.
X */
Xstruct format_op {
X	char	*df_buf;
X	int	df_count;		/* value-result */
X	daddr_t	df_startblk;
X	int	df_reg[8];		/* result */
X};
X
X/*
X * Structure used internally to retrieve
X * information about a partition on a disk.
X */
Xstruct partinfo {
X	struct disklabel *disklab;
X	struct partition *part;
X};
X
X/*
X * Disk-specific ioctls.
X */
X		/* get and set disklabel; DIOCGPART used internally */
X#define DIOCGDINFO	_IOR('d', 101, struct disklabel)/* get */
X#define DIOCSDINFO	_IOW('d', 102, struct disklabel)/* set */
X#define DIOCWDINFO	_IOW('d', 103, struct disklabel)/* set, update disk */
X#define DIOCGPART	_IOW('d', 104, struct partinfo)	/* get partition */
X
X/* do format operation, read or write */
X#define DIOCRFORMAT	_IOWR('d', 105, struct format_op)
X#define DIOCWFORMAT	_IOWR('d', 106, struct format_op)
X
X#define DIOCSSTEP	_IOW('d', 107, int)	/* set step rate */
X#define DIOCSRETRIES	_IOW('d', 108, int)	/* set # of retries */
X#define DIOCWLABEL	_IOW('d', 109, int)	/* write en/disable label */
X
X#define DIOCSBAD	_IOW('d', 110, struct dkbad)	/* set kernel dkbad */
X
X#endif LOCORE
X
X#if !defined(KERNEL) && !defined(LOCORE)
Xstruct	disklabel *getdiskbyname();
X#endif
END_OF_disklabel.h.orig
if test 8964 -ne `wc -c <disklabel.h.orig`; then
    echo shar: \"disklabel.h.orig\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f scsi_hi.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"scsi_hi.c\"
else
echo shar: Extracting \"scsi_hi.c\" \(10324 characters\)
sed "s/^X//" >scsi_hi.c <<'END_OF_scsi_hi.c'
X/****************************************************************************
X * NS32K Monitor SCSI high-level driver
X * Bruce Culbertson
X * 8 March 1990
X *
X * There are three monitor SCSI commands.  "Read" and "write" I think are
X * fairly self explanatory once you read the help messages.  They, in fact,
X * execute the "extended read", "extended write", and "request sense"
X * commands from the SCSI standard.
X * 
X * "Raw" lets you execute any SCSI command but you need a SCSI reference to
X * know what the commands are and what their formats are.  The SCSI
X * standard specifies that there are six buffers which, for example, hold a
X * SCSI command or are the source or destination for data.  You provide
X * "raw" with an array of pointers to the six buffers.  Using "edit", you
X * can enter a SCSI command somewhere in memory and you can create the
X * array of pointers.  The array must actually be eight entries long; two
X * entries are not used.  By typing "raw <array address>", the SCSI command
X * is executed.
X * 
X * By the way, "read", "write", and "raw" talk only to the DP8490 SCSI
X * controller.  I have not had time to read the Adaptec data sheet and
X * write a driver for it.
X ****************************************************************************/
X#include "so.h"
X#include "stdlib.h"
X
X/*
X#define OK 			0
X#define NOT_OK			OK+1
X*/
X#define	PRIVATE			static
X#define PUBLIC
X#define U8			unsigned char
X
X/* budd: forward */
XPRIVATE int exec_scsi_hi(), get_sense();
XPRIVATE int sc_initialize();
X
Xextern int exec_scsi_low();		/* budd */
X
Xstruct cmd_desc {			/* SCSI command description */
X  const U8	*cmd;			/* command string */
X  const U8	*odata;			/* data to output, if any */
X  const struct cmd_desc *chain;		/* next command */
X};
X
Xstruct drive {				/* SCSI drive description */
X  U8	adr, lun;			/* SCSI address and LUN */
X  U8	flags;				/* drive characteristics */
X  U8	stat;				/* drive state */
X  const struct cmd_desc *init;		/* list of initialize commands */
X};
X/* for drive.flags */
X#define EXTENDED_RDWR		1	/* device does extended read, write */
X#define EXTENDED_SENSE		2	/* device does extended sense */
X/* for drive.stat */
X#define INITIALIZED		1	/* device is initialized */
X
X#ifdef OMTI
X/* These SCSI commands initialize a OMTI 5200 SCSI controller with a 360K
X * floppy at LUN=1 and an ST-225 at LUN=0.
X */
Xconst U8 floppy_parms_cmd[] =	{0xc2, 0x20, 0, 0, 0, 0};
Xconst U8 floppy_parms_data[] =	{0, 3, 0x27, 0xa, 0, 0, 0, 0x80, 1, 0};
Xconst U8 floppy_format_cmd[] =	{0xc0, 0x20, 0, 0, 9, 0x8b};
Xconst U8 floppy_recal_cmd[] =	{1, 0x20, 0, 0, 0, 0};
Xconst U8 wini_parms_cmd[] =	{0xc2, 0, 0, 0, 0, 0};
Xconst U8 wini_parms_data[] =	{0, 0, 0, 3, 2, 0x63, 0, 1, 0x10, 0};
Xconst U8 wini_recal_cmd[] =	{1, 0, 0, 0, 0, 0};
Xconst struct cmd_desc floppy_init2 =
X	{floppy_recal_cmd, 0, 0};
Xconst struct cmd_desc floppy_init1 =
X	{floppy_format_cmd, 0, &floppy_init2};
Xconst struct cmd_desc floppy_init0 =
X	{floppy_parms_cmd, floppy_parms_data, &floppy_init1};
Xconst struct cmd_desc wini_init1 =
X	{wini_recal_cmd, 0, 0};
Xconst struct cmd_desc wini_init0 =
X	{wini_parms_cmd, wini_parms_data, &wini_init1};
X#endif
X
XPRIVATE struct drive drive_tbl[] = {
X#ifdef OMTI
X  {1, 0, 0, 0, &wini_init0},
X  {1, 1, 0, 0, &floppy_init0},
X#endif
X  {0, 0, EXTENDED_RDWR | EXTENDED_SENSE, 1, 0},
X};
X#define DRV_TBL_SZ (sizeof (drive_tbl) / sizeof (struct drive))
X
X/* Round up to multiple of four since SCSI transfers are always multiples
X * of four bytes.
X */
X#define CMD_LEN		12		/* longest SCSI command */
X#define SENSE_LEN 	24		/* extended sense length */
X#define MSG_LEN		4
X#define STAT_LEN	4
X
X#define MAX_SCSI_RETRIES	6
X#define CMD_IX		2
X#define CMD_SENSE	0x03
X#define CMD_READ	0x08
X#define CMD_WRITE	0x0a
X#define CMD_XREAD	0x28
X#define CMD_XWRITE	0x2a
XPRIVATE U8		cmd_buf[CMD_LEN];
X
X#define SENSE_KEY	2
X#define NO_SENSE	0
X#define RECOVERY_ERR	1
X#define UNIT_ATTN	6
X#define ADD_SENSE_CODE	12
X#define SENSE_RST	0x29
XPRIVATE	U8		sense_buf[SENSE_LEN];
X
X#define CHECK_CONDITION	2
X#define STAT_IX		3
X#define STAT_MASK	0x1f
XPRIVATE U8		stat_buf[STAT_LEN];
X#define IMSG_IX		7
XPRIVATE U8		msg_buf[MSG_LEN];
X
X#define ODATA_IX	0
X#define IDATA_IX	1
XPRIVATE struct scsi_args scsi_args;
X
X/*===========================================================================*
X *				sc_rdwt					     * 
X *===========================================================================*/
X/* Carry out a read or write request for the SCSI disk. */
XPUBLIC int
Xsc_rdwt(op, block, ram_adr, len, sc_adr, lun)
Xint op;
Xlong block, ram_adr, len, sc_adr, lun;
X{
X  int retries, ret;
X  U8 *p;
X  struct drive *dp;
X
X  /* get drive characteristics */
X  for (dp = drive_tbl; dp < drive_tbl + DRV_TBL_SZ - 1; ++dp)
X    if (dp->adr == sc_adr && dp->lun == lun) break;
X  if (dp == drive_tbl + DRV_TBL_SZ - 1) {
X    dp->adr = sc_adr;			/* have default, set adr, lun */
X    dp->lun = lun;
X  }
X  for (retries = 0; retries < MAX_SCSI_RETRIES; ++retries) {
X    if (dp->init && !(dp->stat & INITIALIZED))
X      if (OK != sc_initialize (dp)) {
X	printf("SCSI cannot initialize device\n");
X	return NOT_OK;
X      }
X    p = cmd_buf;			/* build SCSI command */
X    if (dp->flags & EXTENDED_RDWR) {	/* use extended commands */
X      *p++ = (op == DISK_READ)? CMD_XREAD: CMD_XWRITE;
X      *p++ = lun << 5;
X      *p++ = (block >> 24) & 0xff;
X      *p++ = (block >> 16) & 0xff;
X      *p++ = (block >> 8) & 0xff;
X      *p++ = (block >> 0) & 0xff;
X      *p++ = 0;
X      *p++ = (len >> 8) & 0xff;
X      *p++ = (len >> 0) & 0xff;
X      *p = 0;
X    } else {				/* use short (SASI) commands */
X      *p++ = (op == DISK_READ)? CMD_READ: CMD_WRITE;
X      *p++ = (lun << 5) | ((block >> 16) & 0x1f);
X      *p++ = (block >> 8) & 0xff;
X      *p++ = (block >> 0) & 0xff;
X      *p++ = len;
X      *p = 0;
X    }
X    if (op == DISK_READ)
X      ret = exec_scsi_hi (cmd_buf, (U8 *)ram_adr, (U8 *)0, dp);
X    else
X      ret = exec_scsi_hi (cmd_buf, (U8 *)0, (U8 *)ram_adr, dp);
X    if (OK == ret) return OK;
X    dp->stat &= ~INITIALIZED;
X  }
X  printf("SCSI %s, block %d failed even after retries\n",
X    op == DISK_READ? "READ": "WRITE", block);
X  return NOT_OK;
X}
X
X/*===========================================================================*
X *				sc_initialize				     *
X *===========================================================================*/
X/* Execute the list of initialization commands for the given drive.
X */
XPRIVATE int
Xsc_initialize (dp)
Xstruct drive *dp;
X{
X  const struct cmd_desc *cp;
X
X  for (cp = dp->init; cp != 0; cp = cp->chain)
X    if (OK != exec_scsi_hi (cp->cmd, 0, cp->odata, dp)) {
X      dp->stat &= ~INITIALIZED;
X      return NOT_OK;
X    }
X  dp->stat |= INITIALIZED;
X  return OK;
X}
X
X/*===========================================================================*
X *				exec_scsi_hi				     * 
X *===========================================================================*/
X/* Execute a "high-level" SCSI command.  This means execute a low level
X * command and, if it fails, execute a request sense to find out why.
X */
XPRIVATE int
Xexec_scsi_hi(cmd, data_in, data_out, dp)
XU8 *cmd, *data_out, *data_in;
Xstruct drive *dp;
X{
X  scsi_args.ptr[CMD_IX] = (long)cmd;
X  scsi_args.ptr[STAT_IX] = (long)stat_buf;
X  scsi_args.ptr[IMSG_IX] = (long)msg_buf;
X  scsi_args.ptr[IDATA_IX] = (long)data_in;
X  scsi_args.ptr[ODATA_IX] = (long)data_out;
X  if (OK != exec_scsi_low (&scsi_args, dp->adr))
X    return NOT_OK;
X  *stat_buf &= STAT_MASK;		/* strip off lun */
X  if (*stat_buf == 0)
X    /* Success -- this should be the usual case */
X    return OK;
X  if (*stat_buf != CHECK_CONDITION) {
X    /* do not know how to handle this so return error */
X    printf("SCSI device returned unknown status: %d\n", *stat_buf);
X    return NOT_OK;
X  }
X  /* Something funny happened, need to execute request-sense command
X   * to learn more.
X   */
X  if (OK == get_sense(dp))
X    /* Something funny happened, but the device recovered from it and
X     * the command succeeded.
X     */
X    return OK;
X  return NOT_OK;
X}
X
X/*===========================================================================*
X *				get_sense				     * 
X *===========================================================================*/
X/* Execute a "request sense" SCSI command and check results.  When a SCSI
X * command returns CHECK_CONDITION, a request-sense command must be executed.
X * A request-sense command provides information about the original command.
X * The original command might have succeeded, in which case it does not
X * need to be retried and OK is returned.  Examples: read error corrected
X * with error correction code, or error corrected by retries performed by
X * the SCSI device.  The original command also could have failed, in
X * which case NOT_OK is returned.
X */
X#define XLOGICAL_ADR	\
X  (sense_buf[3]<<24 | sense_buf[4]<<16 | sense_buf[5]<<8 | sense_buf[6])
X#define LOGICAL_ADR	\
X  (sense_buf[1]<<16 | sense_buf[2]<<8 | sense_buf[3])
X
XPRIVATE int
Xget_sense (dp)
Xstruct drive *dp;
X{
X  U8 *p;
X
X  p = cmd_buf;				/* build SCSI command */
X  *p++ = CMD_SENSE;
X  *p++ = dp->lun << 5;
X  *p++ = 0;
X  *p++ = 0;
X  *p++ = (dp->flags & EXTENDED_SENSE)? SENSE_LEN: 0;
X  *p = 0;
X  scsi_args.ptr[IDATA_IX] = (long)sense_buf;
X  scsi_args.ptr[ODATA_IX] = 0;
X  scsi_args.ptr[CMD_IX] = (long)cmd_buf;
X  scsi_args.ptr[STAT_IX] = (long)stat_buf;
X  scsi_args.ptr[IMSG_IX] = (long)msg_buf;
X  if (OK != exec_scsi_low (&scsi_args, dp->adr)) {
X    printf("SCSI SENSE command failed\n");
X    return NOT_OK;
X  }
X  if ((*stat_buf & STAT_MASK) != 0) {
X    printf("SCSI SENSE returned wrong status %d\n", *stat_buf);
X    return NOT_OK;
X  }
X  if (0 == (dp->flags & EXTENDED_SENSE)) {
X    printf("SCSI request sense, code 0x%x, log_adr 0x%x\n",
X      sense_buf[0], LOGICAL_ADR);
X    return NOT_OK;
X  }
X  switch (sense_buf[SENSE_KEY] & 0xf) {
X    case NO_SENSE:
X    case UNIT_ATTN:			/* reset */
X      return NOT_OK;			/* must retry command */
X    case RECOVERY_ERR:
X      /* eventually, we probably do not want to hear about these. */
X      printf("SCSI ok with recovery, code 0x%x, logical address 0x%x\n",
X	     sense_buf[ADD_SENSE_CODE], XLOGICAL_ADR);
X      return OK;			/* orig command was ok with recovery */
X    default:
X      printf("SCSI failure: key 0x%x code 0x%x log adr 0x%x sense buf 0x%x\n",
X	     sense_buf[SENSE_KEY], sense_buf[ADD_SENSE_CODE],
X	XLOGICAL_ADR, sense_buf);
X      return NOT_OK;			/* orig command failed */
X  }
X}
END_OF_scsi_hi.c
if test 10324 -ne `wc -c <scsi_hi.c`; then
    echo shar: \"scsi_hi.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f scsi_hi.c.orig -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"scsi_hi.c.orig\"
else
echo shar: Extracting \"scsi_hi.c.orig\" \(10232 characters\)
sed "s/^X//" >scsi_hi.c.orig <<'END_OF_scsi_hi.c.orig'
X/****************************************************************************
X * NS32K Monitor SCSI high-level driver
X * Bruce Culbertson
X * 8 March 1990
X *
X * There are three monitor SCSI commands.  "Read" and "write" I think are
X * fairly self explanatory once you read the help messages.  They, in fact,
X * execute the "extended read", "extended write", and "request sense"
X * commands from the SCSI standard.
X * 
X * "Raw" lets you execute any SCSI command but you need a SCSI reference to
X * know what the commands are and what their formats are.  The SCSI
X * standard specifies that there are six buffers which, for example, hold a
X * SCSI command or are the source or destination for data.  You provide
X * "raw" with an array of pointers to the six buffers.  Using "edit", you
X * can enter a SCSI command somewhere in memory and you can create the
X * array of pointers.  The array must actually be eight entries long; two
X * entries are not used.  By typing "raw <array address>", the SCSI command
X * is executed.
X * 
X * By the way, "read", "write", and "raw" talk only to the DP8490 SCSI
X * controller.  I have not had time to read the Adaptec data sheet and
X * write a driver for it.
X ****************************************************************************/
X#include "so.h"
X
X#define OK 			0
X#define NOT_OK			OK+1
X#define	PRIVATE
X#define PUBLIC
X#define U8			unsigned char
X
Xlong	scsiAdr = DEFAULT_SCSI_ADR,	/* default SCSI address */
X	scsiLun = DEFAULT_SCSI_LUN;
X
Xstruct cmd_desc {			/* SCSI command description */
X  const U8	*cmd;			/* command string */
X  const U8	*odata;			/* data to output, if any */
X  const struct cmd_desc *chain;		/* next command */
X};
X
Xstruct drive {				/* SCSI drive description */
X  U8	adr, lun;			/* SCSI address and LUN */
X  U8	flags;				/* drive characteristics */
X  U8	stat;				/* drive state */
X  const struct cmd_desc *init;		/* list of initialize commands */
X};
X/* for drive.flags */
X#define EXTENDED_RDWR		1	/* device does extended read, write */
X#define EXTENDED_SENSE		2	/* device does extended sense */
X/* for drive.stat */
X#define INITIALIZED		1	/* device is initialized */
X
X#ifdef OMTI
X/* These SCSI commands initialize a OMTI 5200 SCSI controller with a 360K
X * floppy at LUN=1 and an ST-225 at LUN=0.
X */
Xconst U8 floppy_parms_cmd[] =	{0xc2, 0x20, 0, 0, 0, 0};
Xconst U8 floppy_parms_data[] =	{0, 3, 0x27, 0xa, 0, 0, 0, 0x80, 1, 0};
Xconst U8 floppy_format_cmd[] =	{0xc0, 0x20, 0, 0, 9, 0x8b};
Xconst U8 floppy_recal_cmd[] =	{1, 0x20, 0, 0, 0, 0};
Xconst U8 wini_parms_cmd[] =	{0xc2, 0, 0, 0, 0, 0};
Xconst U8 wini_parms_data[] =	{0, 0, 0, 3, 2, 0x63, 0, 1, 0x10, 0};
Xconst U8 wini_recal_cmd[] =	{1, 0, 0, 0, 0, 0};
Xconst struct cmd_desc floppy_init2 =
X	{floppy_recal_cmd, 0, 0};
Xconst struct cmd_desc floppy_init1 =
X	{floppy_format_cmd, 0, &floppy_init2};
Xconst struct cmd_desc floppy_init0 =
X	{floppy_parms_cmd, floppy_parms_data, &floppy_init1};
Xconst struct cmd_desc wini_init1 =
X	{wini_recal_cmd, 0, 0};
Xconst struct cmd_desc wini_init0 =
X	{wini_parms_cmd, wini_parms_data, &wini_init1};
X#endif
X
XPRIVATE struct drive drive_tbl[] = {
X#ifdef OMTI
X  {1, 0, 0, 0, &wini_init0},
X  {1, 1, 0, 0, &floppy_init0},
X#endif
X  {0, 0, EXTENDED_RDWR | EXTENDED_SENSE, 1, 0},
X};
X#define DRV_TBL_SZ (sizeof (drive_tbl) / sizeof (struct drive))
X
X/* Round up to multiple of four since SCSI transfers are always multiples
X * of four bytes.
X */
X#define CMD_LEN		12		/* longest SCSI command */
X#define SENSE_LEN 	24		/* extended sense length */
X#define MSG_LEN		4
X#define STAT_LEN	4
X
X#define MAX_SCSI_RETRIES	6
X#define CMD_IX		2
X#define CMD_SENSE	0x03
X#define CMD_READ	0x08
X#define CMD_WRITE	0x0a
X#define CMD_XREAD	0x28
X#define CMD_XWRITE	0x2a
XPRIVATE U8		cmd_buf[CMD_LEN];
X
X#define SENSE_KEY	2
X#define NO_SENSE	0
X#define RECOVERY_ERR	1
X#define UNIT_ATTN	6
X#define ADD_SENSE_CODE	12
X#define SENSE_RST	0x29
XPRIVATE	U8		sense_buf[SENSE_LEN];
X
X#define CHECK_CONDITION	2
X#define STAT_IX		3
X#define STAT_MASK	0x1f
XPRIVATE U8		stat_buf[STAT_LEN];
X#define IMSG_IX		7
XPRIVATE U8		msg_buf[MSG_LEN];
X
X#define ODATA_IX	0
X#define IDATA_IX	1
XPRIVATE struct scsi_args scsi_args;
X
X/*===========================================================================*
X *				sc_rdwt					     * 
X *===========================================================================*/
X/* Carry out a read or write request for the SCSI disk. */
XPRIVATE int
Xsc_rdwt(op, block, ram_adr, len, sc_adr, lun)
Xlong block, ram_adr, len, sc_adr, lun;
X{
X  int retries, ret;
X  U8 *p;
X  struct drive *dp;
X
X  /* get drive characteristics */
X  for (dp = drive_tbl; dp < drive_tbl + DRV_TBL_SZ - 1; ++dp)
X    if (dp->adr == sc_adr && dp->lun == lun) break;
X  if (dp == drive_tbl + DRV_TBL_SZ - 1) {
X    dp->adr = sc_adr;			/* have default, set adr, lun */
X    dp->lun = lun;
X  }
X  for (retries = 0; retries < MAX_SCSI_RETRIES; ++retries) {
X    if (dp->init && !(dp->stat & INITIALIZED))
X      if (OK != sc_initialize (dp)) {
X	printf("SCSI cannot initialize device\n");
X	return NOT_OK;
X      }
X    p = cmd_buf;			/* build SCSI command */
X    if (dp->flags & EXTENDED_RDWR) {	/* use extended commands */
X      *p++ = (op == DISK_READ)? CMD_XREAD: CMD_XWRITE;
X      *p++ = lun << 5;
X      *p++ = (block >> 24) & 0xff;
X      *p++ = (block >> 16) & 0xff;
X      *p++ = (block >> 8) & 0xff;
X      *p++ = (block >> 0) & 0xff;
X      *p++ = 0;
X      *p++ = (len >> 8) & 0xff;
X      *p++ = (len >> 0) & 0xff;
X      *p = 0;
X    } else {				/* use short (SASI) commands */
X      *p++ = (op == DISK_READ)? CMD_READ: CMD_WRITE;
X      *p++ = (lun << 5) | ((block >> 16) & 0x1f);
X      *p++ = (block >> 8) & 0xff;
X      *p++ = (block >> 0) & 0xff;
X      *p++ = len;
X      *p = 0;
X    }
X    if (op == DISK_READ)
X      ret = exec_scsi_hi (cmd_buf, (U8 *)ram_adr, (U8 *)0, dp);
X    else
X      ret = exec_scsi_hi (cmd_buf, (U8 *)0, (U8 *)ram_adr, dp);
X    if (OK == ret) return OK;
X    dp->stat &= ~INITIALIZED;
X  }
X  printf("SCSI %s, block %d failed even after retries\n",
X    op == DISK_READ? "READ": "WRITE", block);
X  return NOT_OK;
X}
X
X/*===========================================================================*
X *				sc_initialize				     *
X *===========================================================================*/
X/* Execute the list of initialization commands for the given drive.
X */
Xint
Xsc_initialize (dp)
Xstruct drive *dp;
X{
X  const struct cmd_desc *cp;
X
X  for (cp = dp->init; cp != 0; cp = cp->chain)
X    if (OK != exec_scsi_hi (cp->cmd, 0, cp->odata, dp)) {
X      dp->stat &= ~INITIALIZED;
X      return NOT_OK;
X    }
X  dp->stat |= INITIALIZED;
X  return OK;
X}
X
X/*===========================================================================*
X *				exec_scsi_hi				     * 
X *===========================================================================*/
X/* Execute a "high-level" SCSI command.  This means execute a low level
X * command and, if it fails, execute a request sense to find out why.
X */
XPRIVATE int
Xexec_scsi_hi(cmd, data_in, data_out, dp)
XU8 *cmd, *data_out, *data_in;
Xstruct drive *dp;
X{
X  scsi_args.ptr[CMD_IX] = (long)cmd;
X  scsi_args.ptr[STAT_IX] = (long)stat_buf;
X  scsi_args.ptr[IMSG_IX] = (long)msg_buf;
X  scsi_args.ptr[IDATA_IX] = (long)data_in;
X  scsi_args.ptr[ODATA_IX] = (long)data_out;
X  if (OK != exec_scsi_low (&scsi_args, dp->adr))
X    return NOT_OK;
X  *stat_buf &= STAT_MASK;		/* strip off lun */
X  if (*stat_buf == 0)
X    /* Success -- this should be the usual case */
X    return OK;
X  if (*stat_buf != CHECK_CONDITION) {
X    /* do not know how to handle this so return error */
X    printf("SCSI device returned unknown status: %d\n", *stat_buf);
X    return NOT_OK;
X  }
X  /* Something funny happened, need to execute request-sense command
X   * to learn more.
X   */
X  if (OK == get_sense(dp))
X    /* Something funny happened, but the device recovered from it and
X     * the command succeeded.
X     */
X    return OK;
X  return NOT_OK;
X}
X
X/*===========================================================================*
X *				get_sense				     * 
X *===========================================================================*/
X/* Execute a "request sense" SCSI command and check results.  When a SCSI
X * command returns CHECK_CONDITION, a request-sense command must be executed.
X * A request-sense command provides information about the original command.
X * The original command might have succeeded, in which case it does not
X * need to be retried and OK is returned.  Examples: read error corrected
X * with error correction code, or error corrected by retries performed by
X * the SCSI device.  The original command also could have failed, in
X * which case NOT_OK is returned.
X */
X#define XLOGICAL_ADR	\
X  (sense_buf[3]<<24 | sense_buf[4]<<16 | sense_buf[5]<<8 | sense_buf[6])
X#define LOGICAL_ADR	\
X  (sense_buf[1]<<16 | sense_buf[2]<<8 | sense_buf[3])
X
XPRIVATE int
Xget_sense (dp)
Xstruct drive *dp;
X{
X  U8 *p;
X
X  p = cmd_buf;				/* build SCSI command */
X  *p++ = CMD_SENSE;
X  *p++ = dp->lun << 5;
X  *p++ = 0;
X  *p++ = 0;
X  *p++ = (dp->flags & EXTENDED_SENSE)? SENSE_LEN: 0;
X  *p = 0;
X  scsi_args.ptr[IDATA_IX] = (long)sense_buf;
X  scsi_args.ptr[ODATA_IX] = 0;
X  scsi_args.ptr[CMD_IX] = (long)cmd_buf;
X  scsi_args.ptr[STAT_IX] = (long)stat_buf;
X  scsi_args.ptr[IMSG_IX] = (long)msg_buf;
X  if (OK != exec_scsi_low (&scsi_args, dp->adr)) {
X    printf("SCSI SENSE command failed\n");
X    return NOT_OK;
X  }
X  if ((*stat_buf & STAT_MASK) != 0) {
X    printf("SCSI SENSE returned wrong status %d\n", *stat_buf);
X    return NOT_OK;
X  }
X  if (0 == (dp->flags & EXTENDED_SENSE)) {
X    printf("SCSI request sense, code 0x%x, log_adr 0x%x\n",
X      sense_buf[0], LOGICAL_ADR);
X    return NOT_OK;
X  }
X  switch (sense_buf[SENSE_KEY] & 0xf) {
X    case NO_SENSE:
X    case UNIT_ATTN:			/* reset */
X      return NOT_OK;			/* must retry command */
X    case RECOVERY_ERR:
X      /* eventually, we probably do not want to hear about these. */
X      printf("SCSI ok with recovery, code 0x%x, logical address 0x%x\n",
X	     sense_buf[ADD_SENSE_CODE], XLOGICAL_ADR);
X      return OK;			/* orig command was ok with recovery */
X    default:
X      printf("SCSI failure: key 0x%x code 0x%x log adr 0x%x sense buf 0x%x\n",
X	     sense_buf[SENSE_KEY], sense_buf[ADD_SENSE_CODE],
X	XLOGICAL_ADR, sense_buf);
X      return NOT_OK;			/* orig command failed */
X  }
X}
END_OF_scsi_hi.c.orig
if test 10232 -ne `wc -c <scsi_hi.c.orig`; then
    echo shar: \"scsi_hi.c.orig\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f scsi_low.c.orig -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"scsi_low.c.orig\"
else
echo shar: Extracting \"scsi_low.c.orig\" \(13050 characters\)
sed "s/^X//" >scsi_low.c.orig <<'END_OF_scsi_low.c.orig'
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
X#define OK 		0
X#define NOT_OK		OK+1
X#define	PRIVATE
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
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
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 */
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 */
XscCtlrSelect (ctlr)
Xint ctlr;
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}
END_OF_scsi_low.c.orig
if test 13050 -ne `wc -c <scsi_low.c.orig`; then
    echo shar: \"scsi_low.c.orig\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 2 \(of 3\).
cp /dev/null ark2isdone
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
