:
#	@(#) scsi.sh 25.5 92/10/19 
#
#	Copyright (C) 1989-1992 The Santa Cruz Operation, Inc.
#		All Rights Reserved.
#	The information in this file is provided for the exclusive use of
#	the licensees of The Santa Cruz Operation, Inc.  Such users have the
#	right to use, modify, and incorporate this code into other products
#	for purposes authorized by the license agreement provided they include
#	this notice and the associated copyright notice with any such product.
#	The information in this file is provided "AS IS" without warranty.
#
#	mkdev/.scsi - SCSI Configuration
#
# set the standard exit values
: ${OK=0} ${FAIL=1} ${STOP=10}

# set the environment variables
LANG=english_us.ascii
export LANG
PATH=/etc:/bin:/usr/bin
export PATH
umask 022

#file specifying default SCSI host adaptor type
DEFAULT=/etc/default/scsi
USE_DEF=1
UPGRADE=N
HALISTFILE=/etc/default/scsihas

#
# Standard functions
#


# Print an error message
#
# Usage: error "message"
# Argument is a quoted error message
# Notes: error always returns 1.
#
error() {
	echo "\nError: $*" >&2
	return 1
}


# Prompt with mesg, return non-zero on q
prompt() {
	while	echo "\n${mesg}or enter q to quit: \c" >&2
	do	read cmd
		case $cmd in
		+x|-x)	set $cmd					;;
		Q|q)	return $FAIL					;;
		!*)	eval `expr "$cmd" : "!\(.*\)"`			;;
		"")	# If there is an argument use it as the default
			# else loop until 'cmd' is set
			[ "$1" ] && { 
				cmd=$1
				return $OK
			}
			: continue
			;;
		*)	return $OK					;;
		esac
	done
}

# Prompt for yes or no answer - returns non-zero for no
getyn() {
	while	echo "\n$* (y/n) \c">&2
	do	read yn rest
		case $yn in
		[yY])	return $OK 			;;
		[nN])	return $FAIL			;;
		*)	echo "Please answer y or n" >&2	;;
		esac
	done
}

#
# begin mkdev scsi functions
#

settrap () {
	trap 'cleanup $FAIL' 1 2 3 15
}

unsettrap () {
	trap '' 1 2 3 15
}

cleanup ()  {
	rm -rf /tmp/scsi_* /tmp/hw

	#special exit function for -C (check), used by mkdev hd
	#output status to filedes 3: index [added]
	#index = index to be used in the minor device number to index cfg array
	#	 -1 = not configured
	#'added' indicates that device was configured during this invocation
	[ $check = 1 ] && {
		[ -n "$thisentry" ] && get_index
		echo $index $ADDED 1>&3
	}

	exit $1
}

check_link () {
	dir=`pwd`
	cd /
	if [ -f /etc/perms/extmd ]
	then
		PERM=/etc/perms/extmd
	else
		error "Cannot locate /etc/perms/extmd. This file
is needed to verify Link Kit installation."
		# or return 1
		cleanup $FAIL

	fi
	# test to see if link kit is installed
	until	fixperm -i -d LINK $PERM
	do	case $? in
		0) echo "fixperm returned 0 in Link Kit check"
 		   return 0					          ;;	
		4) echo "\nThe Link Kit is not installed." >&2	          ;;
		5) echo "\nThe Link Kit is only partially installed." >&2 ;;
		*) echo "\nError testing for Link Kit.  Exiting.">&2
		   cleanup $FAIL					  ;;
		esac

		# Not fully installed. Do so here
		getyn "Do you wish to install it now?" || {
			# answered no
			echo "
SCSI devices cannot be installed without the Link Kit.
Re-invoke this mkdev script after installing the Link Kit.">&2
			cleanup $FAIL
		}

		# answered yes, so install link kit
		/bin/sh /etc/custom -o -i LINK || {
			# custom exited unsuccessfully
			error "custom failed to install Link Kit successfully.  Please try again."
			cleanup $FAIL
		}
	done
	cd $dir
	return 0
}

# determine a default host adaptor type:
#	use command line parameter HATYPE
# 	else, check $DEFAULT file
# 	else, pick up the last entry from mscsi
# 	else, see what adapter shows up in the boot screen
# 	else, default to 'ad'
get_hatype () {
	if [ -n "$HATYPE" ]
	then
		hatype=$HATYPE
		return	
	fi
	#$DEFAULT file format:
	#	ADAPTER=foo
	if [ -f $DEFAULT  -a "$USE_DEF" -eq 1 ]
	then
		. $DEFAULT
		hatype=$ADAPTER
		if [ -n "$hatype" ]
		then
			[ ! -f /etc/conf/sdevice.d/$hatype ] && USE_DEF=0
			return
		fi
	fi

	grep -v "*" $mscsi | \
	while read ha attach number id lun
	do
		echo $ha >/tmp/scsi_e$$
	done

	if [ ! -f /tmp/scsi_e$$ ]
	then
		while read device base vec dma type ha id lun
		do
			case $device in
			%adapter)	echo $type | sed "s/type=//" >/tmp/scsi_e$$
					break	;;
			esac
		done < /dev/string/cfg
	fi

	if [ -f /tmp/scsi_e$$ ]
	then	hatype=`cat /tmp/scsi_e$$`
		rm /tmp/scsi_e$$
	else	hatype=ad
	fi
}

# get ID number, and LUN
get_numbers () {

    for i in 1 2 
    do
	[ -n "$ID" -a $i = 1 ] && continue
	[ -n "$LUN" -a $i = 2 ] && continue
	case $i in 
		1) thisdev="\nWhat is the Target ID for this device?\
\nSelect 0-7," ;;
	        2) thisdev="\nWhat is the LUN of this device?  Press <Return> to use the default: 0\nSelect 0-7,";;
	esac

	while :
	do   echo "$thisdev or h for help, or q to quit: \c"
	     read x
	
	     case $x in
		[0-7]) case $i in
			1) ID=$x ;;
			2) LUN=$x ;;
		       esac
		       break 			 ;;
		  q|Q) cleanup $OK		 ;;
		  h|H) scsi_help	         ;;
		    *)  if [ -z "$x" -a $i -eq 2 ]
			then
				LUN=0
				break
			fi
			echo "\nInvalid selection.  Please try again." ;;
	     esac
	done
done
}

# display current SCSI configuration
scsi_display () {
	grep -v "*" $mscsi | sed "s/hd	/Sdsk	/" > /tmp/scsi_d$$
	# old "hd" entries can just as well be "Sdsk", and it's simpler

	echo "\nThe configuration file currently has entries for the\
 following devices:\n"
	echo "Host\nAdapter		Adapter\nType	Device	Number	ID	LUN\n-----------------------------------"
	sed "s/Sdsk/disk/g" /tmp/scsi_d$$ | \
	sed "s/Stp/tape/g" | \
	sed "s/Srom/cd-rom/g"
	echo "\nPress any key to continue: \c"
	read x 
	return 0
}

# is this entry already in mscsi? 
check_dup ()  {
	if grep "^$thisentry" /tmp/scsi_a$$ > /dev/null 2>&1
	then
		[ "$action" = "add" ] && {
			case $devtype in
				Sdsk) devname=disk ;;
				 Stp) devname=tape ;;
				Srom) devname=cd-rom ;;
			esac
			echo "\nCannot add this $devname."
			echo "Another $devname is already configured at this location."
		}
		return 1
	fi
	return 0
}

# has the maximum for this device type already been reached?
check_max () {
	devcount=`grep -c $devtype /tmp/scsi_a$$`	
	case $devtype in
	       Stp) [ $devcount -eq 4 ] && {
			echo "\nError. Cannot add another tape."
			echo "\nThe maximum number of tapes -- 4 -- are \
already configured."
			return 1
                    } ;;
	       Srom) [ $devcount -eq 256 ] && {
			echo "\nError. Cannot add another cd-rom."
			echo "\nThe maximum number of cd-roms -- 256 -- are \
already configured."
			return 1
                    } ;;
	esac
	return 0
}

# issue warning if another device type is at that location
check_other () {
	checkentry="$hatype	.*	$HA	$ID	$LUN"
	if grep "^$checkentry" /tmp/scsi_a$$ > /dev/null 2>&1
	then
		# note: init.link now removes the hd entry if non-SCSI root
		if getyn "Warning! Another device is configured at\
 this location.\nDo you want to overwrite this location with the new entry?"
		then 
			grep -v "^$checkentry" /tmp/scsi_a$$ > /tmp/scsi_f$$
			mv /tmp/scsi_f$$ /tmp/scsi_a$$
			return 0
		else
			return 1
		fi
	fi
	return 0
}

# make sure that adapter and Sdevice are configured in
configure_in () {
	for dev in $hatype $devtype
	do
		sdev=/etc/conf/sdevice.d/$dev
		if grep -s N $sdev >/dev/null
		then	# configure in: change N to Y in sdevice.d file
			sed "s/N/Y/" $sdev >$sdev.new
			mv $sdev.new $sdev
		fi
	done

	# If this was an upgrade from ad to eiad on the same adapter (174X)
 	# and there are no longer any 'ad' entries in mscsi, then set
	# sdevice.d entry to N.

	grep "^ad" /tmp/scsi_a$$ > /dev/null 2>&1
	res=$?
	[ "$UPGRADE" = "Y" -a $res -ne 0 ] && {
		sed "s,Y,N," /etc/conf/sdevice.d/ad > /tmp/scsi_ad$$
		mv /tmp/scsi_ad$$ /etc/conf/sdevice.d/ad 
	}
}

# add entry to mscsi, after appropriate error checking
add_mscsi ()  {
	check_dup || return 1
	check_max || return 1
	check_other || return 1

	# If this is a 174X being configured to run in enhanced mode,
	# we must use the existing 'ad' entries in mscsi instead of
	# adding new ones.

	if [ "$UPGRADE" = "N" ]
	then
		echo "$thisentry" >> /tmp/scsi_a$$
	else
		cat /tmp/scsi_a$$ | 
		sed "s%^\(ad\)\([ 	]*[a-zA-Z]*[ 	]*$HA\)%eiad\2%"\
		> /tmp/scsi_a1$$
		mv /tmp/scsi_a1$$ /tmp/scsi_a$$
	fi

	index=`expr \`grep -c $devtype /tmp/scsi_a$$\`	- 1`
	configure_in
	ADDED=added
	return 0
}

rem_mscsi () {
	check_dup || {
		sed "/^$thisentry/d" /tmp/scsi_a$$ > /tmp/scsi_b$$ 
		mv /tmp/scsi_b$$ /tmp/scsi_a$$
		return 0
	}
	echo "\nError.  Cannot remove this device."
	echo "This type of device is not configured at this location."
	return 1
}

# edit mscsi to add or remove this device; return 0 if mscsi modified, 1 if not
edit_mscsi () {
	# split mscsi into commented lines and real entries	
	grep "*" $mscsi > /tmp/scsi_c$$
	grep -v "*" $mscsi | sed "s/hd	/Sdsk	/" > /tmp/scsi_a$$
	# old "hd" entries can just as well be "Sdsk", and it's simpler
	
	case $action in
		   add) add_mscsi || return 1 ;;
		remove) rem_mscsi || return 1 ;;
	esac

	cat /tmp/scsi_a$$ >> /tmp/scsi_c$$
	unsettrap
	mv /tmp/scsi_c$$ $mscsi
	settrap
}


#get SCSI index of device listed in $thisentry
get_index () {
	index=-1
	grep -v "*" $mscsi | sed "s/hd	/Sdsk	/" | grep $devtype > /tmp/scsi_a$$
	line=`grep -n "^$thisentry" /tmp/scsi_a$$`
	[ -z "$line" ] && return
	index=`expr \`expr "$line" : '\([0-9][0-9]*\)'\` - 1`
	rm -f /tmp/scsi_a$$
}

scsi_help () {
	echo "\
\nSCSI Help Message --
\nInstallation of a SCSI device requires reconfiguration of the kernel.\
\nThe SCSI configuration file must be updated with the location of the new\
\ndevice.  The kernel must be rebuilt and rebooted to access the new\
\ndevice.\
\n\
\nTo specify the location of the device to be added or removed,\
\nyou need to know three pieces of information: The host adapter number,\
\nthe ID number of the controller, and the logical unit number (LUN)\
\nof the device.\
\n\nHost Adapter Number --\
\n\nA host adapter is a card that plugs into a slot on the motherboard.\
\nIt supports a SCSI bus.  Several host adapters may be installed on\
\na system.  The first host adapter is SCSI-0.  The second is SCSI-1.\
\nThe nth host adapter is SCSI-n.  This numbering is unique for each \
\ntype of host adapter on the system." 

echo "\nPress return to continue: \c"
read x

echo "\
\nSCSI Controller ID number -- \
\n\nUp to 7 controllers may be put on a SCSI bus.  Each controller has \
\na unique ID number.  This number is determined by jumper settings \
\non the controller.  The valid range of ID numbers is 0-7.\
\n\nSCSI Logical Unit Number (LUN) --\n\
\nMost SCSI devices are manufactured with a controller embedded in the \
\nsame physical unit as the device.  These controllers support one device \
\nonly. In this case, the LUN of the device is 0.\
\nNon-embedded controllers may support up to 8 SCSI devices.\
\nIn this case, LUN numbers are determined by jumper settings on\
\neach device. The valid range of LUN numbers is 0-7."

echo "\nPress return to continue: \c"
read x

}

check_vec ()
{
	[ `expr "$1" : '[0-9][0-9]*'` -eq `expr "$1" : '.*'` ] && return $OK
	echo "\nInvalid choice.  Please try again."
	return $FAIL
}

check_io()
{
	[ `expr "$1" : '[a-fA-F0-9][a-fA-F0-9]*'` -eq `expr "$1" : '.*'` ] && return $OK
	echo "\nInvalid choice.  Please try again." 
	return $FAIL
}

check_cma()
{
	check_io $1
	return $?
}

#To configure next host adapter in sdevice.d file
add_ha_num() {
   sdev=$1
   while :
   do
	getyn "'$hatype' SCSI host adapter $HA is not configured.\
\nWould you like to update the link-kit?"
	[ $? -eq $FAIL ] && { 
		echo "\n'$hatype' SCSI host adapter $HA must be configured in order for\nthe kernel to successfully re-link"
		return $OK
	} 
	#use parameters from last entry
	set -- `grep -v "\*" $sdev | tail -1`
	name=$1
	unit=$3
	ipl=$4
	vectype=$5
	vec=$6
	sio=$7
	eio=$8
	scma=$9
	shift 1
	ecma=$9

	pmes="\\\nThe following parameters will be used to configure '$hatype' SCSI host adapter $HA:\\\n\\\n"

	#[ "$vectype" -ne 0 -a "$vec" -ne 0 ] && parms="1 $parms"
	[ "$vec" -ne 0 ] && parms="1 $parms"
	[ "$sio" -ne 0 ] && parms="$parms 2 3"
	[ "$scma" -ne 0 ] && parms="$parms 4 5"
	#get irq, sio and eio
	for i in $parms 
	do
		case $i in 
		1) thisdev="\nWhat is the interrupt vector for this adapter?"
		   pmes="$pmes\\\tInterrupt vector\\\t\$vec\\\n";;
	        2) thisdev="\nWhat is the start IO address (hex) for this adapter?"
		   pmes="$pmes\\\tStart I/O address\\\t0x\$sio\\\n";;
	        3) thisdev="\nWhat is the end IO address (hex) for this adapter?"
		   pmes="$pmes\\\tEnd I/O address\\\t\\\t0x\$eio\\\n";;
	        4) thisdev="\nWhat is the start controller memory address (hex) for this adapter?"
		   pmes="$pmes\\\tStart controller memory address\\\t0x\$scma\\\n";;
	        5) thisdev="\nWhat is the end controller memory address (hex) for this adapter?"
		   pmes="$pmes\\\tEnd controller memory address\\\t0x\$ecma\\\n";;
		esac

		while :
		do   
		     echo "$thisdev\nenter number, or q to quit: \c"
		     read x
		
		     case $x in
			*[a-fA-F0-9]*) case $i in
				1) vec=$x 
				   check_vec $vec || continue ;;
				2) sio=$x
				   check_io $sio || continue ;;
				3) eio=$x
				   check_io $eio || continue ;;
			 	4) scma=$x
				   check_cma $scma || continue ;;
			 	5) ecma=$x
				   check_cma $ecma || continue ;;
			       esac
			       break 			 ;;
			  q|Q) return $FAIL		 ;;
			    *) echo "\nInvalid choice.  Please try again." ;;
		     esac
		done
	done
	[ -z "$parms" ] && break

	eval echo "$pmes"
	
	getyn "Update the link-kit?"
	[ $? -eq $OK ] && break
   done
   echo "$name\tY\t$unit\t$ipl\t$vectype\t$vec\t$sio\t$eio\t$scma\t$ecma">>$sdev
   return $OK
}

#
list_haprefixes()
{
	echo "\n\nPrefix\t\tSCSI Host Adapter Type\n"
	sed '/^#/d
/^[ 	]*$/d' $HALISTFILE | while read line
	do
		set -- $line
		echo "$1\t\t\c"
		shift
		echo $*
	done
}

# Get adapter type (supply a default) and number
get_adapter () {

	get_hatype
	while :
	do
	mesg="\
Enter the prefix of the SCSI host adapter that supports this device
or press <Return> for the default: '$hatype'\nEnter h for a list of host adapters "

		#skip first prompt if hatype given on command line
		cmd=$hatype
		if [ -z "$HATYPE" -o -z "$hatype" ]
		then
			# changed below to cleanup $FAIL from cleanup $OK
			prompt $hatype || cleanup $FAIL

			case "$cmd" in
			h|H)	list_haprefixes
				continue;;
			esac
		fi
		HATYPE=

		sdev=/etc/conf/sdevice.d/$cmd
		[ ! -f $sdev ] && {
			echo "\nMissing 'sdevice.d' file for host adapter driver '$cmd'"
			get_hatype
			continue
		}
		hatype=$cmd
		hamax=`grep -v "\*" $sdev | wc -l | sed 's/[ 	]//g' `
		[ "$hamax" -gt 0 ] && break
		echo "\nIncomplete 'sdevice.d' file for host adapter driver '$cmd'"
		
		get_hatype
	done
	[ -z "$HA" -o \( "$HA" -gt $hamax -o "$HA" -lt 0 \) ] && {
		mesg="Which '$hatype' SCSI host adapter supports this device?\
\nSelect 0-${hamax}, " 
		while :
		do
			prompt || return $FAIL
			case $cmd in
			[0-$hamax])	HA=$cmd; break;;
			*) echo "\nInvalid selection.  Please try again." ;;
			esac
		done
	} 

	if [ $HA -eq $hamax ]  
	then
		while :
		do
			add_ha_num $sdev && return $OK 
		done
	fi
	return $OK
}

get_device () {
while
   	quit=" or enter q to quit:"
	mesg="What type of device do you want to $action?

	1. Hard Disk
	2. Tape
	3. CD-ROM
	4. Other

Select an option "

do
	prompt || cleanup $OK
	devcmd=$cmd
	case $devcmd in
		1) devtype=Sdsk
		   break  ;;	
		2) devtype=Stp
		   break ;;
		3) devtype=Srom
		   break ;;
		4) echo "\nNo other devices are supported yet." ;;
		*) echo "\nPlease enter 1 2 3 4 or q to quit." 	;;
	esac
done
}
	
just_relink () {

	( cd /etc/conf/cf.d; ./link_unix )
	
}

ask_relink () {
	getyn "A new kernel must be built, to reflect the changes\n\
to the SCSI configuration. Do you want to do this now?"
	case $? in
		0) dir=`pwd`
		   cd /etc/conf/cf.d
		   ./link_unix  
		   case $? in
			0) cd $dir     
			   return 0  ;;
			1) cd $dir
			   return 1  ;;
		   esac 		;;
		1) return 1		;;
	esac
}

get_action () {

while
   	quit=" or enter q to quit:"
	mesg="\tSCSI Device Configuration\n
	1. Add a SCSI device
	2. Remove a SCSI device
	3. Display current SCSI configuration 
	4. Display SCSI help message

Select an option "

do
	prompt || cleanup $OK
	maincmd=$cmd
	case $maincmd in
		1) action=add    
		   break ;;
		2) action=remove
		   break  ;;
		3) scsi_display  ;;  	 
		4) scsi_help     ;;
		*) echo "\nPlease select 1,2,3, or 4" ;;
	esac
done
}

usage () {
echo "\n\
Usage: /usr/lib/mkdev/.scsi [ -artdcnhuC ] [ha [id [lun [hatype] ] ] ]\n\n\
	-a	    add SCSI device\n\
	-r	    remove SCSI device\n\
	-t	    device is a tape\n\
	-d	    device is a disk\n\
	-c	    device is a cd-rom\n\
	-n	    do not reconfigure & relink the kernel\n\
	-h	    display SCSI help message\n\
	-u	    display this usage message\n\
	-C	    check if device is configured\n\
	 
\n	All arguments are optional"

exit $OK
}

# begin main
mscsi=/etc/conf/cf.d/mscsi
devtype=
action=
relink= 
check=0
index=-1


settrap

# arg processing
[ $# != 0 ] &&  {
	set -- `getopt artdcnhuC $*` || usage

	for i in $* 
	do
		case $i in
			-a) action=add	  ;;
			-r) action=remove ;;
			-t) devtype=Stp	  ;;
			-d) devtype=Sdsk  ;;
			-c) devtype=Srom  ;;
			-n) relink=no	  ;;
			-h) scsi_help
		    	    exit $OK      ;;
			-u) usage         ;;
			-C) check=1;      ;;
			--) shift; break  ;;
			*) break;;
		esac
	shift
	done

	HA=$1
	ID=$2
	LUN=$3
	HATYPE=$4
}


# verify that link kit is installed
check_link

# determine a default host adaptor type
# get_hatype

while :
do
[ ! "$action"  -a $check != 1 ]   &&  get_action
[ ! "$devtype" ]  &&  get_device
get_adapter || cleanup $OK
[ ! "$HA" -o ! "$ID" -o ! "$LUN" ] && get_numbers
thisentry="$hatype	$devtype	$HA	$ID	$LUN"

# If hatype is 'eiad' and there is already an 'ad' entry with
# the same HA number in mscsi, then its quite likely that the
# user is configuring a 174X running in 154X emulation mode, to
# run in enhanced mode. Handle this by replacing ad instances of
# the given HA number, with 'eiad'.

if [ "$hatype" = "eiad" ]
then
     grep -v "\*" $mscsi > /tmp/scsi_a$$
     line=`grep -n "^ad[ 	]*[a-zA-Z]*[ 	]*$HA" /tmp/scsi_a$$`

     if [ -n "$line" ]
     then
          getyn "Are you reconfiguring a 174X adapter which is currently\
 running in 154X\nemulation mode, to run in enhanced mode ?"
	  case $? in 
	  	0) UPGRADE=Y ;;
	  	1) ;;
	  esac
      fi
fi

#once thisentry is set, check only (no action) can exit
[ $check = 1 ] && {
	[ -z "$action" ] && cleanup $OK
	get_index
 	[ "$action" = "add" -a $index -ne -1 ] && cleanup $OK
	[ "$action" = "remove" -a $index -eq -1 ] && cleanup $OK
}

# Give user a last chance to back out, else edit mscsi file
echo "\nYou are about to $action the following SCSI device:\n"
echo "Host\nAdapter		Adapter\nType   Device	Number	ID	LUN\n-----------------------------------"
echo "$hatype\t$devtype\t$HA\t$ID\t$LUN"
getyn "Update SCSI configuration?" && edit_mscsi

case $? in
	0) echo "\nThe SCSI configuration file has been updated."
	   # if -n flag given on command line, don't prompt for relink
	   [ "$relink" = "no" ] && cleanup $OK

	   if [ "$_RELINK" -o "$_NOPROMPT" ]
	   then
		just_relink
		cleanup $OK
	   fi

           if ask_relink 
	   then
		cleanup $OK 
	   else
		echo "\nThe kernel will not be rebuilt now."
		[ "$action" = "add" ] &&  { 
		echo "\nNote: Any device that \
has been added to the SCSI configuration\nwill not be usable until the \
kernel is rebuilt & rebooted."
		}
		cleanup $FAIL 
	   fi ;;
	1) echo "\nSCSI configuration files not updated."
	   getyn "Would you like to try again?"
	   case $? in
		0) HA=
		   ID=
		   LUN=
		   continue     ;;
		1) echo "\nSCSI Configuration script exiting."
		   cleanup $FAIL  ;;
	   esac	;;
esac
done
