From: julian@tfs.com (Julian Elischer)
Subject: New scsi system beta3 (part 2 of       10)
Organization: TRW Financial Systems
Date: Sat, 3 Oct 1992 04:01:15 GMT

# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	scsi
#	scsi/README
#	scsi/scsiconf.h
#	scsi/scsiconf.c
#	scsi/scsi_all.h
#
echo c - scsi
mkdir scsi > /dev/null 2>&1
echo x - scsi/README
sed 's/^X//' >scsi/README << 'END-of-scsi/README'
XThis release consists of the following files 
X(relative to the base of the kernel tree)
X
Xddb/db_command.c.patch
Xkern/kern_subr.c.patch
Xi386/isa/isa.h.patch
Xi386/isa/clock.c.patch
Xi386/i386/conf.c.patch
Xi386/conf/SCSITEST
Xi386/conf/devices.i386.patch
Xi386/conf/files.i386.patch
Xi386/conf/Makefile.i386.patch
Xscsi
Xscsi/README
Xscsi/scsiconf.h
Xscsi/scsiconf.c
Xscsi/scsi_all.h
Xscsi/scsi_disk.h
Xscsi/scsi_tape.h
Xscsi/scsi_cd.h
Xscsi/st.c
Xscsi/sd.c
Xscsi/cd.c
Xi386/isa/aha1542.c
X/dev/MAKEDEV
X
XThe patch files do the following things:
X
X	ddb/db_command.c.patch
X	kern/kern_subr.c.patch
XThese move the strcmp function out of ddb to a more generic place
Xso I can use it even if ddb is not configured in.
X
X	i386/isa/isa.h.patch
Xdefine ports needed for the adaptec board.
X
X	i386/isa/clock.c.patch
Xadd a calibrated spinwait that can be used before the clock interrupts 
Xcan be used. (i.e. in boot up)
X
X	i386/i386/conf.c.patch
Xadd cdevsw and bdevsw table entries for the scsi disk and tape devices.
X
X	i386/conf/devices.i386.patch
Xdefine an sd device so I can config it for swap
X
X	i386/conf/files.i386.patch
Xdefine the files we need to compile in for this scsi system.
X
X	i386/conf/Makefile.i386.patch
XThis Makefile knows how to make the vers.c program. This should
Xbecome un-needed when the patch kit fixes this bug. 
X
X	/dev/MAKEDEV
XA replacement MAKEDEV that knows about these devices.
X
X
X----------------------------------------------------------------
XThis scsi system is designed to allow the re-use of top end drivers
Xsuch as disk and tape drivers, with different scsi adapters.
X
XAs of writing this document, There are top end drivers working for:
X----------------------------------------------------------------
Xgeneric scsi disk
Xgeneric scsi tape
Xcd-rom (tested for SUN cd-rom only)
XAEG Character recognition devices *
XCalera Character recognition devices *
XKodak IL900 scanner *
XExabyte tape changer device.**
X----------------------------------------------------------------
X
X
XThere are also working bottom end drivers for:
X----------------------------------------------------------------
Xadaptec 1542 (and 1742 in 1542 mode)
Xbustec 742a **
X----------------------------------------------------------------
X
X
XWork is proceeding on the following bottom end drivers:
X----------------------------------------------------------------
XFuture Domain (8 and 16 bit)****	hosler@tfs.com & rpr@oce.nl
XWD7000****				terry@icarus.weber.edu
Xseagate st01/st02****			overby@aspen.cray.com ?
Xadaptec 174x ***			me
XUltrastore ***				overby@aspen.cray.com & friend?
X----------------------------------------------------------------
X* drivers not made public (proprietary.. proof that the concept works though)
X** driver not yet released but working.
X*** just a dream so far.
X**** some amount more than just a dream so far.
X
X
X################## Using the scsi system ##################
X------------minor numbers---------------
XThis scsi system does not allocate minor numbers to devices depending
Xon their SCSI IDs is any way. A devices minor number is dependant
Xon the order in which it was found.
Xe.g. the first tape found will become st0 (minor number 0)
X	the second found will become st1 (minor number 16)
X	the third will become st2 (minor 32) 
X	etc.
X
XThese devices could be on the same scsi bus or different scsi busses.
XThat would not change their minor numbers.
X
XIt is possible to run two different TYPES of scsi adapters at the 
Xsame time and have st0 on one and st1 on another. (for example)
X
XThere is a scheme supported in which scsi devices can be 'wired in' even
Xif they are not present or powered on at probe time. (see scsiconf.c)
X
X--------------getting started------------
XIt should be possible to use the /dev entries for as0 as if they were 
X/dev entries for sd0 and the old as bootblocks should
Xcontinue to work if you are using an adaptec 1542b.
X
X--------------making devices------------
XA changed version of /dev/MAKEDEV is supplied that
Xcan be used to make devices sd[01234] and st[01234]
X
Xe.g. 
Xcd /dev
Xsh MAKEDEV sd0 sd1 sd2 st0 st1 cd0
X
X
XThe tape devices are as follows:
Xrst0	basic raw device, will rewind on close
Xnrst0	will not rewind on close
Xerst0	will rewind and EJECTon close
Xnerst0  will not rewind and WILL eject (some devices may rewind anyhow)
X
X------------future enhancements--------------
XSome people have indicated that they would like to have the SCSI ID
Xencoded into the minor number in some way, and
Xthis may be supported at some timein the future, using
Xminor numbers greater than 128. (or maybe a different major number)
X
XI will also be writing (probably) a generic scsi-error
Xhandling routine that will be table driven, so that the routine can
Xbe removed from each individual driver. With enough care,
Xtwo similar devices with different error codes (quite common) could run
Xthe same driver but use different error tables.
X
X--------------file layout-------------------
XOriginally I had all scsi definitions in one file: scsi.h
XI have since moved definitions of commands so that all
Xdefinitions needed for a particular type of device are
Xfound together in the include file of that name.
XThis approximatly follows the layout of their definition 
Xin the SCSI-2 spec. 
XAs such they are:
X
Xscsi_all.h   general commands for all devices --- CHAPTER 7
Xscsi-disk.h  commands relevant to disk        --- CHAPTER 8
Xscsi-tape.h  commands for scsi tapes          --- CHAPTER 9
Xscsi-cd.h    commands for cd-roms (and audio) --- CHAPTER 13
X
X-----------cd-rom-----------------
XI have only recntly added the cd-rom driver
XI have mounted disk using the iso9660 file system
Xbut have not managed to get the AUDIO commands to work (yet)
XI have only tested this code on a SUN cd-rom which uses
Xa 512 byte logical blocksize, however it has code to addapt
Xto other logical blocksizes (multiples of 512 please!)
X
END-of-scsi/README
echo x - scsi/scsiconf.h
sed 's/^X//' >scsi/scsiconf.h << 'END-of-scsi/scsiconf.h'
X/*
X * Written by Julian Elischer (julian@tfs.com)
X * for TRW Financial Systems for use under the MACH(2.5) operating system.
X *
X * TRW Financial Systems, in accordance with their agreement with Carnegie
X * Mellon University, makes this software available to CMU to distribute
X * or use in any manner that they see fit as long as this message is kept with
X * the software. For this reason TFS also grants any other persons or
X * organisations permission to use or modify this software.
X *
X * TFS supplies this software to be publicly redistributed
X * on the understanding that TFS is not responsible for the correct
X * functioning of this software in any circumstances.
X *
X */
X
X/*
X * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
X */
X
X/***********************************************\
X* these calls are called by the high-end	*
X* drivers to get services from whatever low-end	*
X* drivers they are attached to			*
X\***********************************************/
Xstruct scsi_switch
X{
X	int		(*scsi_cmd)();
X	void		(*scsi_minphys)();
X	int		(*open_target_lu)();
X	int		(*close_target_lu)();
X	long	int	(*adapter_info)(); /* see definitions below */
X	u_long	spare[3];
X};
X#define	AD_INF_MAX_CMDS		0x000000FF /* maximum number of entries
X						queuable to a device by 
X						the adapter */
X/* 24 bits of other adapter charcteristics go here */
X
X/***********************************************\
X* The scsi debug control bits			*
X\***********************************************/
Xextern	int	scsi_debug;
X#define PRINTROUTINES	0x01
X#define	TRACEOPENS	0x02
X#define	TRACEINTERRUPTS	0x04
X#define	SHOWREQUESTS	0x08
X#define	SHOWSCATGATH	0x10
X#define	SHOWINQUIRY	0x20
X#define	SHOWCOMMANDS	0x40
X
X
X/********************************/
X/* return values for scsi_cmd() */
X/********************************/
X#define SUCCESSFULLY_QUEUED	0
X#define TRY_AGAIN_LATER		1
X#define	COMPLETE		2
X#define	HAD_ERROR		3
X
Xstruct scsi_xfer
X{
X	struct	scsi_xfer *next;	/* when free */
X	int	flags;
X	u_char	adapter;
X	u_char	targ;
X	u_char	lu;
X	u_char	retries;	/* the number of times to retry */
X	long	int	timeout;	/* in miliseconds */
X	struct	scsi_generic *cmd;
X	int	cmdlen;
X	u_char	*data;		/* either the dma address OR a uio address */
X	int	datalen;	/* data len (blank if uio)    */
X	int	resid;
X	int	(*when_done)();
X	int	done_arg;
X	int	done_arg2;
X	int	error;
X	struct	buf *bp;
X	struct	scsi_sense_data	sense;
X};
X/********************************/
X/* Flag values			*/
X/********************************/
X#define	SCSI_NOSLEEP	0x01	/* Not a user... don't sleep		*/
X#define	SCSI_NOMASK	0x02	/* dont allow interrupts.. booting	*/
X#define	SCSI_NOSTART	0x04	/* left over from ancient history	*/
X#define	ITSDONE		0x10	/* the transfer is as done as it gets	*/
X#define	INUSE		0x20	/* The scsi_xfer block is in use	*/
X#define	SCSI_SILENT	0x40	/* Don't report errors to console	*/
X#define SCSI_ERR_OK	0x80	/* An error on this operation is OK.	*/
X#define	SCSI_RESET	0x100	/* Reset the device in question		*/
X#define	SCSI_DATA_UIO	0x200	/* The data address refers to a UIO	*/
X#define	SCSI_DATA_IN	0x400	/* expect data to come INTO memory	*/
X#define	SCSI_DATA_OUT	0x800	/* expect data to flow OUT of memory	*/
X/********************************/
X/* Error values			*/
X/********************************/
X#define XS_NOERROR	0x0	/* there is no error, (sense is invalid)  */
X#define XS_SENSE	0x1	/* Check the returned sense for the error */
X#define	XS_DRIVER_STUFFUP 0x2	/* Driver failed to perform operation	  */
X#define XS_TIMEOUT	0x03	/* The device timed out.. turned off?	  */
X#define XS_SWTIMEOUT	0x04	/* The Timeout reported was caught by SW  */
X#define XS_BUSY		0x08	/* The device busy, try again later?	  */
X
END-of-scsi/scsiconf.h
echo x - scsi/scsiconf.c
sed 's/^X//' >scsi/scsiconf.c << 'END-of-scsi/scsiconf.c'
X/*
X * Written by Julian Elischer (julian@tfs.com)
X * for TRW Financial Systems for use under the MACH(2.5) operating system.
X *
X * TRW Financial Systems, in accordance with their agreement with Carnegie
X * Mellon University, makes this software available to CMU to distribute
X * or use in any manner that they see fit as long as this message is kept with
X * the software. For this reason TFS also grants any other persons or
X * organisations permission to use or modify this software.
X *
X * TFS supplies this software to be publicly redistributed
X * on the understanding that TFS is not responsible for the correct
X * functioning of this software in any circumstances.
X *
X */
X
X/*
X * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
X */
X
X/*
X$Log:
X*
X*/
X#include <sys/types.h>
X#include "st.h"
X#include "sd.h"
X#include "ch.h"
X#include "cd.h"
X
X#ifdef	MACH
X#include <i386/machparam.h>
X#include <i386at/scsi_all.h>
X#include <i386at/scsiconf.h>
X#else	MACH
X#ifdef	__386BSD__
X#include <scsi/scsi_all.h>
X#include <scsi/scsiconf.h>
X#endif	__386BSD__
X#endif	MACH
X
X#if !defined(OSF) && !defined(__386BSD__)
X#include "bll.h"
X#include "cals.h"
X#endif /* !defined(OSF) && !defined(__386BSD__) */
X
X#if NSD > 0
Xextern	sdattach();
X#endif NSD
X#if NST > 0
Xextern	stattach();
X#endif NST
X#if NCH > 0
Xextern	chattach();
X#endif NCH
X#if NCD > 0
Xextern	cdattach();
X#endif NCD
X#if NBLL > 0
Xextern	bllattach();
X#endif NBLL
X#if NCALS > 0
Xextern	calsattach();
X#endif NCALS
X
X/***************************************************************\
X* The structure of pre-configured devices that might be turned	*
X* off and therefore may not show up				*
X\***************************************************************/
Xstruct	predefined
X{
X	u_char	scsibus;
X	u_char	dev;
X	u_char	lu;
X	int	(*attach_rtn)();
X	char	*devname;
X}
Xpd[] = 
X{
X#ifdef EXAMPLE_PREDEFINE
X#if NSD > 0
X	{0,0,0,sdattach,"sd"},	/* define a disk at scsibus=0 dev=0 lu=0 */
X#endif NSD
X#endif EXAMPLE_PREDEFINE
X	{0,9,9}			/*illegal dummy end entry */
X};
X
X
X/***************************************************************\
X* The structure of known drivers for autoconfiguration		*
X\***************************************************************/
Xstatic struct scsidevs 
X{
X	int type;
X	int removable;
X	char	*manufacturer;
X	char	*model;
X	char	*version;
X	int	(*attach_rtn)();
X	char	*devname;
X	char	showme;		/* 1 show my comparisons during boot(debug) */
X}
Xknowndevs[] = {
X#if NSD > 0
X	{ T_DIRECT,T_FIXED,"standard","any","any",sdattach,"sd" },
X	{ T_DIRECT,T_FIXED,"MAXTOR  ","XT-4170S        ","B5A ",sdattach,"mx1",0 },
X#endif NSD
X#if NST > 0
X	{ T_SEQUENTIAL,T_REMOV,"standard","any","any",stattach,"st" },
X#endif NST
X#if NCALS > 0
X	{ T_PROCESSOR,T_FIXED,"standard","any","any",calsattach,"cals" },
X#endif NCALS
X#if NCH > 0
X	{ T_CHANGER,T_REMOV,"standard","any","any",chattach,"ch" },
X#endif NCH
X#if NCD > 0
X	{ T_READONLY,T_REMOV,"SONY    ","CD-ROM CDU-8012 ","3.1a",cdattach,"cd" },
X#endif NCD
X#if NBLL > 0
X	{ T_PROCESSOR,T_FIXED,"AEG     ","READER          ","V1.0",bllattach,"bll" },
X#endif NBLL
X{0}
X};
X/***************************************************************\
X* Declarations							*
X\***************************************************************/
Xstruct	predefined	*scsi_get_predef();
Xstruct	scsidevs	*scsi_probedev();
Xstruct	scsidevs	*selectdev();
X
X/* controls debug level within the scsi subsystem */
X/* see scsiconf.h for values			  */
Xint	scsi_debug	=	0x0;
Xint	scsibus		=	0x0; /* This is the Nth scsibus */
X
X/***************************************************************\
X* The routine called by the adapter boards to get all their	*
X* devices configured in.					*
X\***************************************************************/
Xscsi_attachdevs( unit, scsi_addr, scsi_switch)
Xint	unit,scsi_addr;
Xstruct	scsi_switch	*scsi_switch;
X{
X	int	targ,lun;
X	struct	scsidevs	*bestmatch = (struct scsidevs *)0;
X	struct	predefined *predef;
X
X#ifdef	KODAK_SCANNER
X	printf("waiting for scsi devices to settle\n");
X	spinwait(1000 * 30);
X#endif	KODAK_SCANNER
X	targ = 0;
X	while(targ < 8)
X	{
X		if (targ == scsi_addr) 
X		{
X			targ++;
X			continue;
X		}
X		lun = 0;
X		while(lun < 8)
X		{
X			predef = scsi_get_predef(scsibus,targ,lun);
X			bestmatch = scsi_probedev(unit,targ,lun,scsi_switch);
X			if((bestmatch) && (predef)) /* both exist */
X			{
X				if(bestmatch->attach_rtn 
X				    != predef->attach_rtn)
X				{
X				    printf("Clash in found/expected devices\n");
X				    printf("will link in FOUND\n");
X				}
X				(*(bestmatch->attach_rtn))(unit,
X						targ,
X						lun,
X						scsi_switch);
X			}
X			if((bestmatch) && (!predef)) /* just FOUND */
X			{
X				(*(bestmatch->attach_rtn))(unit,
X						targ,
X						lun,
X						scsi_switch);
X			}
X			if((!bestmatch) && (predef)) /* just predef */
X			{
X				(*(predef->attach_rtn))(unit,
X						targ,
X						lun,
X						scsi_switch);
X			}
X			if((lun == 0) && (!bestmatch) && (!predef))
X			{
X				break;	/* nothing here, skip to next targ */
X			}
X			lun++;
X		}
X		targ++;
X	}
X	scsibus++;	/* next time we are on the NEXT scsi bus */
X}
X
X/***********************************************\
X* given a target and lu, check if there is a	*
X* predefined device for that address		*
X\***********************************************/
Xstruct	predefined	*scsi_get_predef(unit,target,lu)
Xint	unit,target,lu;
X{
X	int upto,numents;
X
X	numents = (sizeof(pd)/sizeof(struct predefined)) - 1;
X	
X	for(upto = 0;upto < numents;upto++)
X	{
X		if(pd[upto].scsibus != unit)
X			continue;
X		if(pd[upto].dev != target)
X			continue;
X		if(pd[upto].lu != lu)
X			continue;
X		
X		printf("  dev%d,lu%d: %s - PRECONFIGURED -\n"
X			,target
X			,lu
X			,pd[upto].devname);
X		return(&(pd[upto]));
X	}
X	return((struct predefined *)0);
X}
X
X/***********************************************\
X* given a target and lu, ask the device what	*
X* it is, and find the correct driver table	*
X* entry.					*
X\***********************************************/
Xstruct	scsidevs	*scsi_probedev(unit,target,lu,scsi_switch)
X
Xstruct	scsi_switch *scsi_switch;
Xint	unit,target,lu;
X{
X	char	*dtype,*desc;
X	struct scsi_inquiry_data	inqbuf;
X	int	len,type,remov;
X	char	manu[32];
X	char	model[32];
X	char	version[32];
X
X	bzero(&inqbuf,sizeof(inqbuf));
X	/***********************************************\
X	* Ask the device what it is			*
X	\***********************************************/
X#ifdef	DEBUG
X	if((target == 0) && (lu == 0))
X		scsi_debug = 0xfff;
X	else
X		scsi_debug = 0;
X#endif	DEBUG
X	if(scsi_ready(	unit,
X			target,
X			lu,
X			scsi_switch,
X			SCSI_NOSLEEP | SCSI_NOMASK) != COMPLETE)
X	{
X		return(struct scsidevs *)0;
X	}
X	if(scsi_inquire(unit,
X			target,
X			lu,
X			scsi_switch,
X			&inqbuf,
X			SCSI_NOSLEEP | SCSI_NOMASK) != COMPLETE)
X	{
X		return(struct scsidevs *)0;
X	}
X
X	/***********************************************\
X	* note what BASIC type of device it is		*
X	\***********************************************/
X	if(scsi_debug & SHOWINQUIRY)
X	{
X		desc=(char *)&inqbuf;
X		printf("inq: %x %x %x %x %x %x %x %x %x %x %x %x %x\n",
X		desc[0], desc[1], desc[2], desc[3],
X		desc[4], desc[5], desc[6], desc[7],
X		desc[8], desc[9], desc[10], desc[11],
X		desc[12]);
X	}
X	type = inqbuf.device_type;
X	remov = inqbuf.removable;
X	switch(type)
X	{
X		case T_DIRECT:
X			dtype="direct";
X			break;
X		case T_SEQUENTIAL:
X			dtype="sequential";
X			break;
X		case T_PRINTER:
X			dtype="printer";
X			break;
X		case T_PROCESSOR:
X			dtype="processor";
X			break;
X		case T_READONLY:
X			dtype="readonly";
X			break;
X		case T_WORM:
X			dtype="worm";
X			break;
X		case T_SCANNER:
X			dtype="scanner";
X			break;
X		case T_OPTICAL:
X			dtype="optical";
X			break;
X		case T_CHANGER:
X			dtype="changer";
X			break;
X		case T_COMM:
X			dtype="communication";
X			break;
X		default:
X			dtype="unknown";
X			break;
X	}
X	/***********************************************\
X	* Then if it's advanced enough, more detailed	*
X	* information					*
X	\***********************************************/
X	if(inqbuf.ansii_version > 0) 
X	{
X		if ((len = inqbuf.additional_length 
X				+ ( (char *)inqbuf.unused
X				  - (char *)&inqbuf))
X			> (sizeof(struct scsi_inquiry_data) - 1))
X			len = sizeof(struct scsi_inquiry_data) - 1;
X		desc=inqbuf.vendor;
X		desc[len-(desc - (char *)&inqbuf)] = 0;
X		strncpy(manu,inqbuf.vendor,8);manu[8]=0;
X		strncpy(model,inqbuf.product,16);model[16]=0;
X		strncpy(version,inqbuf.revision,4);version[4]=0;
X	}
X	else
X	/***********************************************\
X	* If not advanced enough, use default values	*
X	\***********************************************/
X	{
X		desc="early protocol device";
X		strncpy(manu,"unknown",8);
X		strncpy(model,"unknown",16);
X		strncpy(version,"????",4);
X	}
X	printf("  dev%d,lu%d: type %d(%s),%s '%s%s%s' scsi%d\n"
X		,target
X		,lu
X		,type
X		,dtype
X		,remov?"removable":"fixed"
X		,manu
X		,model
X		,version
X		,inqbuf.ansii_version
X	);
X	/***********************************************\
X	* Try make as good a match as possible with	*
X	* available sub drivers	 			*
X	\***********************************************/
X	return(selectdev(unit,target,lu,&scsi_switch,
X		type,remov,manu,model,version));
X}
X
X/***********************************************\
X* Try make as good a match as possible with	*
X* available sub drivers	 			*
X\***********************************************/
Xstruct	scsidevs	
X*selectdev(unit,target,lu,dvr_switch,type,remov,manu,model,rev)
Xint	unit,target,lu;
Xstruct	scsi_switch *dvr_switch;
Xint	type,remov;
Xchar	*manu,*model,*rev;
X{
X	int	numents = (sizeof(knowndevs)/sizeof(struct scsidevs)) - 1;
X	int	count = 0;
X	int			bestmatches;
X	struct	scsidevs	*bestmatch = (struct scsidevs *)0;
X	struct	scsidevs	*thisentry = knowndevs;
X
X	thisentry--;
X	while( count++ < numents)
X	{
X		thisentry++;
X		if(type != thisentry->type)
X		{
X			continue;
X		}
X		if(bestmatches < 1)
X		{
X			bestmatches = 1;
X			bestmatch = thisentry;
X		}
X		if(remov != thisentry->removable)
X		{
X			continue;
X		}
X		if(bestmatches < 2)
X		{
X			bestmatches = 2;
X			bestmatch = thisentry;
X		}
X		if(thisentry->showme)
X			printf("\n%s-\n%s-",thisentry->manufacturer, manu);
X		if(strcmp(thisentry->manufacturer, manu))
X		{
X			continue;
X		}
X		if(bestmatches < 3)
X		{
X			bestmatches = 3;
X			bestmatch = thisentry;
X		}
X		if(thisentry->showme)
X			printf("\n%s-\n%s-",thisentry->model, model);
X		if(strcmp(thisentry->model, model))
X		{
X			continue;
X		}
X		if(bestmatches < 4)
X		{
X			bestmatches = 4;
X			bestmatch = thisentry;
X		}
X		if(thisentry->showme)
X			printf("\n%s-\n%s-",thisentry->version, rev);
X		if(strcmp(thisentry->version, rev))
X		{
X			continue;
X		}
X		if(bestmatches < 5)
X		{
X			bestmatches = 5;
X			bestmatch = thisentry;
X			break;
X		}
X	}
X	return(bestmatch);
X}
X
Xstatic	int recurse = 0;
X/***********************************************\
X* Do a scsi operation asking a device if it is	*
X* ready. Use the scsi_cmd routine in the switch *
X* table.					*
X\***********************************************/
Xscsi_ready(unit,target,lu,scsi_switch, flags)
Xstruct	scsi_switch *scsi_switch;
X{
X	struct	scsi_test_unit_ready scsi_cmd;
X	struct	scsi_xfer scsi_xfer;
X	volatile int rval;
X	int	key;
X
X	bzero(&scsi_cmd, sizeof(scsi_cmd));
X	bzero(&scsi_xfer, sizeof(scsi_xfer));
X	scsi_cmd.op_code = TEST_UNIT_READY;
X
X	scsi_xfer.flags=flags | INUSE;
X	scsi_xfer.adapter=unit;
X	scsi_xfer.targ=target;
X	scsi_xfer.lu=lu;
X	scsi_xfer.cmd=(struct scsi_generic *)&scsi_cmd;
X	scsi_xfer.retries=8;
X	scsi_xfer.timeout=10000;
X	scsi_xfer.cmdlen=sizeof(scsi_cmd);
X	scsi_xfer.data=0;
X	scsi_xfer.datalen=0;
X	scsi_xfer.resid=0;
X	scsi_xfer.when_done=0;
X	scsi_xfer.done_arg=0;
Xretry:	scsi_xfer.error=0;
X	/*******************************************************\
X	* do not use interrupts					*
X	\*******************************************************/
X	rval = (*(scsi_switch->scsi_cmd))(&scsi_xfer);
X	if (rval != COMPLETE)
X	{
X		if(scsi_debug)
X		{
X			printf("scsi error, rval = 0x%x\n",rval);
X			printf("code from driver: 0x%x\n",scsi_xfer.error);
X		}
X		switch(scsi_xfer.error)
X		{
X		case	XS_SENSE:
X		/*******************************************************\
X		* Any sense value is illegal except UNIT ATTENTION	*
X		* In which case we need to check again to get the	*
X		* correct response.					*
X		*( especially exabytes)					*
X		\*******************************************************/
X			if(scsi_xfer.sense.error_class == 7 )
X			{
X				key = scsi_xfer.sense.ext.extended.sense_key ;
X				switch(key)
X				{ 
X				case	2:	/* not ready BUT PRESENT! */
X						return(COMPLETE);
X				case	6:
X					spinwait(1000);
X					if(scsi_xfer.retries--)
X					{
X						scsi_xfer.flags &= ~ITSDONE;
X						goto retry;
X					}
X					return(COMPLETE);
X				default:
X					if(scsi_debug)
X						printf("%d:%d,key=%x.",
X						target,lu,key);
X				}
X			}
X			return(HAD_ERROR);
X		case	XS_BUSY:
X			spinwait(1000);
X			if(scsi_xfer.retries--)
X			{
X				scsi_xfer.flags &= ~ITSDONE;
X				goto retry;
X			}
X			return(COMPLETE);	/* it's busy so it's there */
X		case	XS_TIMEOUT:
X		default:
X			return(HAD_ERROR);
X		}
X	}
X	return(COMPLETE);
X}
X/***********************************************\
X* Do a scsi operation asking a device what it is*
X* Use the scsi_cmd routine in the switch table.	*
X\***********************************************/
Xscsi_inquire(unit,target,lu,scsi_switch,inqbuf, flags)
Xstruct	scsi_switch *scsi_switch;
Xu_char	*inqbuf;
X{
X	struct	scsi_inquiry scsi_cmd;
X	struct	scsi_xfer scsi_xfer;
X	volatile int rval;
X
X	bzero(&scsi_cmd, sizeof(scsi_cmd));
X	bzero(&scsi_xfer, sizeof(scsi_xfer));
X	scsi_cmd.op_code = INQUIRY;
X	scsi_cmd.length = sizeof(struct scsi_inquiry_data);
X
X	scsi_xfer.flags=flags | SCSI_DATA_IN | INUSE;
X	scsi_xfer.adapter=unit;
X	scsi_xfer.targ=target;
X	scsi_xfer.lu=lu;
X	scsi_xfer.retries=8;
X	scsi_xfer.timeout=10000;
X	scsi_xfer.cmd=(struct scsi_generic *)&scsi_cmd;
X	scsi_xfer.cmdlen= sizeof(struct scsi_inquiry);
X	scsi_xfer.data=inqbuf;
X	scsi_xfer.datalen=sizeof(struct scsi_inquiry_data);
X	scsi_xfer.resid=sizeof(struct scsi_inquiry_data);
X	scsi_xfer.when_done=0;
X	scsi_xfer.done_arg=0;
Xretry:	scsi_xfer.error=0;
X	/*******************************************************\
X	* do not use interrupts					*
X	\*******************************************************/
X	if ((*(scsi_switch->scsi_cmd))(&scsi_xfer) != COMPLETE)
X	{
X		if(scsi_debug) printf("inquiry had error(0x%x) ",scsi_xfer.error);
X		switch(scsi_xfer.error)
X		{
X		case	XS_NOERROR:
X			break;
X		case	XS_SENSE:
X		/*******************************************************\
X		* Any sense value is illegal except UNIT ATTENTION	*
X		* In which case we need to check again to get the	*
X		* correct response.					*
X		*( especially exabytes)					*
X		\*******************************************************/
X			if((scsi_xfer.sense.error_class == 7 )
X			 && (scsi_xfer.sense.ext.extended.sense_key == 6))
X			{ /* it's changed so it's there */
X				spinwait(1000);
X				{
X					if(scsi_xfer.retries--)
X					{
X						scsi_xfer.flags &= ~ITSDONE;
X						goto retry;
X					}
X				}
X				return( COMPLETE);
X			}
X			return(HAD_ERROR);
X		case	XS_BUSY:
X			spinwait(1000);
X			if(scsi_xfer.retries--)
X			{
X				scsi_xfer.flags &= ~ITSDONE;
X				goto retry;
X			}
X			return(COMPLETE);	/* it's busy so it's there */
X		case	XS_TIMEOUT:
X		default:
X			return(HAD_ERROR);
X		}
X	}
X	return(COMPLETE);
X}
X
X
X
X
X/***********************************************\
X* Utility routines often used in SCSI stuff	*
X\***********************************************/
X
X/***********************************************\
X* convert a physical address to 3 bytes, 	*
X* MSB at the lowest address,			*
X* LSB at the highest.				*
X\***********************************************/
X
Xlto3b(val, bytes)
Xu_char *bytes;
X{
X	*bytes++ = (val&0xff0000)>>16;
X	*bytes++ = (val&0xff00)>>8;
X	*bytes = val&0xff;
X}
X
X/***********************************************\
X* The reverse of lto3b				*
X\***********************************************/
X_3btol(bytes)
Xu_char *bytes;
X{
X	int rc;
X	rc = (*bytes++ << 16);
X	rc += (*bytes++ << 8);
X	rc += *bytes;
X	return(rc);
X}
X
END-of-scsi/scsiconf.c
echo x - scsi/scsi_all.h
sed 's/^X//' >scsi/scsi_all.h << 'END-of-scsi/scsi_all.h'
X/*
X * HISTORY
X * $Log: scsi_all.h,v $
X * 
X */
X
X/*
X * SCSI general  interface description
X */
X
X
X/*
X * Largely written by Julian Elischer (julian@tfs.com)
X * for TRW Financial Systems.
X *
X * TRW Financial Systems, in accordance with their agreement with Carnegie
X * Mellon University, makes this software available to CMU to distribute
X * or use in any manner that they see fit as long as this message is kept with 
X * the software. For this reason TFS also grants any other persons or
X * organisations permission to use or modify this software.
X *
X * TFS supplies this software to be publicly redistributed
X * on the understanding that TFS is not responsible for the correct
X * functioning of this software in any circumstances.
X *
X */
X
X/*
X * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
X */
X
X/*
X * SCSI command format
X */
X
X
Xstruct scsi_generic
X{
X	u_char	opcode;
X	u_char	bytes[11];
X};
X
Xstruct scsi_test_unit_ready
X{
X	u_char	op_code;
X	u_char	:5;
X	u_char	lun:3;
X	u_char	unused[3];
X	u_char	link:1;
X	u_char	flag:4;
X	u_char	:3;
X};
X
Xstruct scsi_send_diag
X{
X	u_char	op_code;
X	u_char	uol:1;
X	u_char	dol:1;
X	u_char	selftest:1;
X	u_char	:1;
X	u_char	pf:1;
X	u_char	lun:3;
X	u_char	unused[1];
X	u_char	paramlen[2];
X	u_char	link:1;
X	u_char	flag:4;
X	u_char	:3;
X};
X
Xstruct scsi_sense
X{
X	u_char	op_code;
X	u_char	:5;
X	u_char	lun:3;	
X	u_char	unused[2];
X	u_char	length;
X	u_char	link:1;
X	u_char	flag:1;
X	u_char	:6;
X};
X
Xstruct scsi_inquiry
X{
X	u_char	op_code;
X	u_char	:5;
X	u_char	lun:3;	
X	u_char	unused[2];
X	u_char	length;
X	u_char	link:1;
X	u_char	flag:1;
X	u_char	:6;
X};
X
Xstruct scsi_mode_sense
X{
X	u_char	op_code;
X	u_char	:3;
X	u_char	dbd:1;
X	u_char	rsvd:1;
X	u_char	lun:3;	
X	u_char	page_code:6;
X	u_char	page_ctrl:2;
X	u_char	unused;
X	u_char	length;
X	u_char	link:1;
X	u_char	flag:1;
X	u_char	:6;
X};
X
Xstruct scsi_mode_sense_big
X{
X	u_char	op_code;
X	u_char	:3;
X	u_char	dbd:1;
X	u_char	rsvd:1;
X	u_char	lun:3;	
X	u_char	page_code:6;
X	u_char	page_ctrl:2;
X	u_char	unused[4];
X	u_char	length[2];
X	u_char	link:1;
X	u_char	flag:1;
X	u_char	:6;
X};
X
Xstruct scsi_mode_select
X{
X	u_char	op_code;
X	u_char	sp:1;
X	u_char	:3;
X	u_char	pf:1;
X	u_char	lun:3;	
X	u_char	unused[2];
X	u_char	length;
X	u_char	link:1;
X	u_char	flag:1;
X	u_char	:6;
X};
X
Xstruct scsi_mode_select_big
X{
X	u_char	op_code;
X	u_char	sp:1;
X	u_char	:3;
X	u_char	pf:1;
X	u_char	lun:3;	
X	u_char	unused[5];
X	u_char	length[2];
X	u_char	link:1;
X	u_char	flag:1;
X	u_char	:6;
X};
X
Xstruct scsi_reserve
X{
X	u_char	op_code;
X	u_char	:5;
X	u_char	lun:3;	
X	u_char	unused[2];
X	u_char	length;
X	u_char	link:1;
X	u_char	flag:1;
X	u_char	:6;
X};
X
Xstruct scsi_release
X{
X	u_char	op_code;
X	u_char	:5;
X	u_char	lun:3;	
X	u_char	unused[2];
X	u_char	length;
X	u_char	link:1;
X	u_char	flag:1;
X	u_char	:6;
X};
X
Xstruct scsi_prevent
X{
X	u_char	op_code;
X	u_char	:5;
X	u_char	lun:3;
X	u_char	unused[2];
X	u_char	prevent:1;
X	u_char	:7;
X	u_char	link:1;
X	u_char	flag:1;
X	u_char	:6;
X};
X#define	PR_PREVENT 1
X#define PR_ALLOW   0
X
X/*
X * Opcodes
X */
X
X#define	TEST_UNIT_READY		0x00
X#define REQUEST_SENSE		0x03
X#define INQUIRY			0x12
X#define MODE_SELECT		0x15
X#define MODE_SENSE		0x1a
X#define START_STOP		0x1b
X#define RESERVE      		0x16
X#define RELEASE      		0x17
X#define PREVENT_ALLOW		0x1e
X#define POSITION_TO_ELEMENT	0x2b
X#define	MODE_SENSE_BIG		0x54
X#define	MODE_SELECT_BIG		0x55
X#define MOVE_MEDIUM     	0xa5
X#define READ_ELEMENT_STATUS	0xb8
X
X
X/*
X * sense data format
X */
X#define T_DIRECT	0
X#define T_SEQUENTIAL	1
X#define T_PRINTER	2
X#define T_PROCESSOR	3
X#define T_WORM		4
X#define T_READONLY	5
X#define T_SCANNER 	6
X#define T_OPTICAL 	7
X#define T_CHANGER	8
X#define T_COMM		9
X
X#define T_REMOV		1
X#define	T_FIXED		0
X
Xstruct scsi_inquiry_data
X{
X	u_char	device_type:5;
X	u_char	device_qualifier:3;
X	u_char	dev_qual2:7;
X	u_char	removable:1;
X	u_char	ansii_version:3;
X	u_char	:5;
X	u_char	response_format;
X	u_char	additional_length;
X	u_char	unused[2];
X	u_char	:3;
X	u_char	can_link:1;
X	u_char	can_sync:1;
X	u_char	:3;
X	char	vendor[8];
X	char	product[16];
X	char	revision[4];
X	u_char	extra[8];
X};
X
X
Xstruct	scsi_sense_data
X{
X	u_char	error_code:4;
X	u_char	error_class:3;
X	u_char	valid:1;
X	union
X	{
X		struct
X		{
X			u_char	blockhi:5;
X			u_char	vendor:3;
X			u_char	blockmed;
X			u_char	blocklow;
X		} unextended;
X		struct
X		{
X			u_char	segment;
X			u_char	sense_key:4;
X			u_char	:1;
X			u_char	ili:1;
X			u_char	eom:1;
X			u_char	filemark:1;
X			u_char	info[4];
X			u_char	extra_len;
X			/* allocate enough room to hold new stuff
X			u_char	cmd_spec_info[4];
X			u_char	add_sense_code;
X			u_char	add_sense_code_qual;
X			u_char	fru;
X			u_char	sense_key_spec_1:7;
X			u_char	sksv:1;
X			u_char	sense_key_spec_2;
X			u_char	sense_key_spec_3;
X			( by increasing 16 to 26 below) */
X			u_char	extra_bytes[26];
X		} extended;
X	}ext;
X};
Xstruct	scsi_sense_data_new
X{
X	u_char	error_code:7;
X	u_char	valid:1;
X	union
X	{
X		struct
X		{
X			u_char	blockhi:5;
X			u_char	vendor:3;
X			u_char	blockmed;
X			u_char	blocklow;
X		} unextended;
X		struct
X		{
X			u_char	segment;
X			u_char	sense_key:4;
X			u_char	:1;
X			u_char	ili:1;
X			u_char	eom:1;
X			u_char	filemark:1;
X			u_char	info[4];
X			u_char	extra_len;
X			u_char	cmd_spec_info[4];
X			u_char	add_sense_code;
X			u_char	add_sense_code_qual;
X			u_char	fru;
X			u_char	sense_key_spec_1:7;
X			u_char	sksv:1;
X			u_char	sense_key_spec_2;
X			u_char	sense_key_spec_3;
X			u_char	extra_bytes[16];
X		} extended;
X	}ext;
X};
X
Xstruct	blk_desc
X{
X	u_char	density;
X	u_char	nblocks[3];
X	u_char	reserved;
X	u_char	blklen[3];
X};
X
Xstruct scsi_mode_header
X{
X	u_char	data_length;	/* Sense data length */
X	u_char	medium_type;
X	u_char	dev_spec;
X	u_char	blk_desc_len;
X};
X
Xstruct scsi_mode_header_big
X{
X	u_char	data_length[2];	/* Sense data length */
X	u_char	medium_type;
X	u_char	dev_spec;
X	u_char	unused[2];
X	u_char	blk_desc_len[2];
X};
X
X
X/*
X * Status Byte
X */
X#define	SCSI_OK		0x00
X#define	SCSI_CHECK		0x02
X#define	SCSI_BUSY		0x08	
X#define SCSI_INTERM		0x10
END-of-scsi/scsi_all.h
exit