#!/bin/sh
#*******************************************************************************
#
# NAME:		rdacctrl
# SUMMARY:	%description%
# COMPONENT:	solsysd
# VERSION:	25
# UPDATE DATE:	%date_modified: Thu Oct 16 08:10:58 1997 %
# PROGRAMMER:	%created_by:    mgallagh %
# 
#		Copyright 1996, 1997 by Symbios Logic Inc.
#
# DESCRIPTION:
# This script performs RDAC initialization and shutdown, depending on the
# arguments ("start" or "stop").  Initializing includes automatically generating
# the necessary driver ".conf" files, loading the RDAC driver, and starting
# the RDAC daemons.  Shutdown includes stopping the RDAC daemons.
#
# NOTES:
#
# REFERENCE:
# 1.  PRD0001A.DOC, Notes on Portable RDAC Prototype
# 2.  PRD0002A.DOC, RDAC Driver-Resolution-Daemon I/O Control Message-ing
#     Interface
# 3.  PRD0003A.DOC, Notes on Portable RDAC Resolution Daemon
# 4.  PRD0004A.DOC, Productization of RDAC Prototype
# 5.  PRD0006A.DOC, Feature Enhancement:  Solaris RDAC Root/Boot
# 6.  PRD0007A.DOC, Implementation of Standard Device Name Support in Solaris
#     RDAC
#
# CODING STANDARD WAIVERS:
#
#*******************************************************************************

#*******************************************************************************
# PROCEDURE:	CleanSd
# SUMMARY:	Remove sd driver nodes corresponding to RAID devices
#
# DESCRIPTION:
# CleanSd removes sd driver nodes FOR RAID DEVICES ONLY from a device directory.
# The directory to be cleaned is given by "$1".  Both raw and block directories
# are cleaned.
#
# SYNTAX:
# CleanSd <dev dir path>
# <dev dir path> - the path to the device directory from which the nodes are to
#                  be removed (e.g., /dev/SYMsm, or just "/")
#
# NOTES:
# Other parts of rdacctrl may wish to know if this routing encountered any sd
# nodes to delete - for this reason, this routine set the flag (really a file)
# /tmp/sdDeleted.<process-id> if sd nodes are actually deleted.
#
# RETURNS:
# Nothing
#
CleanSd()
{
        $LAD 2>/dev/null |
        while read CTRL_INFO
        do
                DEV=`echo $CTRL_INFO | cut -d" " -f1`
                TARGET=`echo $DEV | cut -dt -f2 | cut -dd -f1`
                PHYS_PATH=/`ls -l $RMDEVROOT/dev/rdsk/$DEV 2>/dev/null | cut -d\> -f2 | awk -F/ '{ ORS = "/"; for (i = 4; i < NF-1; ++i) print $i; ORS="\n"; print $(NF-1) }'`/sd@$TARGET
                DEL_LIST=`ls -l  $1/dev/rdsk | grep $PHYS_PATH | tr -s " " | cut -d" " -f9`
                if [ -n "$DEL_LIST" ]
                then
                        ( if [ -d $1/dev/rdsk ]
			then
				 cd $1/dev/rdsk
                        	rm $DEL_LIST 2>/dev/null
			fi ) &
                        ( if [ -d $1/dev/dsk ]
			then
				 cd $1/dev/dsk
                        	rm $DEL_LIST 2>/dev/null
			fi ) &
                        wait
			touch /tmp/sdDeleted.$$
                fi
        done;
}

#*******************************************************************************
# PROCEDURE:	CleanRd
# SUMMARY:	Remove rdriver nodes from device directories.
#
# DESCRIPTION:
# CleanRd removes all node referring to the RDAC driver from a set of device
# directories (both dsk and rdsk).  The  directory to be cleaned is given by
# "$1".
#
# SYNTAX:
# CleanRd <dev dir path>
# <dev dir path> - the path to the device directory from which the nodes are to
#                  be removed (e.g., /dev/SYMsm, or just "/")
#
# NOTES:
#
# RETURNS:
# Nothing
#
CleanRd()
{
	DELETE_LIST=`ls -l  $1/dev/rdsk | grep $RDAC_DRIVER_NAME | tr -s " " | cut -d" " -f9`
	( if [ -d $1/dev/rdsk ]
	then
		cd $1/dev/rdsk
		rm $DELETE_LIST 2>/dev/null
	fi ) &
	( if [ -d $1/dev/dsk ]
	then
		cd $1/dev/dsk
		rm $DELETE_LIST 2>/dev/null
	fi ) &
	wait;
}

#*******************************************************************************
# PROCEDURE:	GenRdriverConf	
# SUMMARY:	Generate the "rdriver.conf" file
#
# DESCRIPTION:
# GenRdriverConf calls symconf to generate the rdriver.conf file.  In
# addition, it has certain special provisions:  (1) it tries to cope with the
# fact that Solaris's bus numbering skips over busses that have no targets
# on them - it does this via an intermediate stage where it generates all
# LUNs for both controllers regardless of LUN ownership, then runs "disks",
# forcing Solaris to see the bus and number it then regenerates rdriver.conf
# with the true configuration, and the next time disks is run, the non-exist-
# ent nodes go away and the nodes that are left have the right names.  (2) The
# other special provision of this routine is to revert to installing rdriver
# as a pseudo driver for the case where there are no arrays on the system.
# (If this is not done, unexpected results occur on boot -r with no arrays
# attached.)
#
# SYNTAX:
# GenRdriverConf <mode>
# <mode> - if set to "VERBOSE", display "regenerating" message, otherwise work
#          silently
#
# NOTES:
# "ROOT" is an environment variable defined for testing purposes - it should
# normally be set to NULL.
#
# RETURNS:
# Nothing
#
GenRdriverConf()
{
	if [ "$1" = "VERBOSE" ]
	then
		echo "Re-generating rdriver.conf file ..."
	fi
	if [ ! -f /tmp/rdriver.conf.orig ]
	then
		mv /kernel/drv/rdriver.conf /tmp/rdriver.conf.orig
	fi
	if [ -z "`modinfo | grep rdriver`" ]
	then
		cd /kernel/drv
		modload rdriver
	fi
	MODNUM=`modinfo | grep rdriver | cut -c1-3`
	$RM_BOOT_HOME/symconf -c /tmp/rdriver.conf.orig >/tmp/rdriver.conf 2> /dev/null
	SYMCONF_STATUS=$?
	diff /tmp/rdriver.conf /tmp/rdriver.conf.orig >/dev/null 2>/dev/null
	DIFF_STATUS=$?  
	if [ "$SYMCONF_STATUS" != 0 ]
	then
		$LOGGER -p user.err "Warning: rdriver.conf re-generation failed"
	fi
	if [ "$SYMCONF_STATUS" = 0 -a -s /tmp/rdriver.conf -a "$DIFF_STATUS" != 0 ]
	then
		mv /tmp/rdriver.conf  /kernel/drv/rdriver.conf

		chmod 644 /kernel/drv/rdriver.conf
		chown root /kernel/drv/rdriver.conf
		chgrp sys  /kernel/drv/rdriver.conf

		rm /tmp/rdriver.conf.orig 2>/dev/null
	else
#
#	test below is a special case:  if we produced a 0-length rdriver.conf,
#	let's revert back to installing rdriver as a pseudo driver
#
		if [ -f /tmp/rdriver.conf -a ! -s /tmp/rdriver.conf ]
		then
			echo name=\"rdriver\" parent=\"pseudo\" instance=0\; >/kernel/drv/rdriver.conf
		else
			mv /tmp/rdriver.conf.orig /kernel/drv/rdriver.conf
		fi
	fi

	# now ready to re-load the RDAC driver
	modunload -i $MODNUM >/dev/null 2>&1;
}

#*******************************************************************************
# PROCEDURE:	MakeRmdevroot	
# SUMMARY:	Create the private device directory for SYMplicity storage
#		manager
#
# DESCRIPTION:
# MakeRmdevroot creates a dev directory for the private use of SYMplicity
# storage manager.
#
# SYNTAX:
# MakeRmdevroot
#
# NOTES:
#
# RETURNS:
# Nothing
#
MakeRmdevroot()
{
	echo "Setting up RAID device access ..."
	mkdir $RMDEVROOT > /dev/null 2>&1
	chmod 775 $RMDEVROOT
	chgrp sys $RMDEVROOT
	ln -s /devices $RMDEVROOT/devices >/dev/null 2>&1
	find /dev/rdsk /dev/dsk -print | cpio -pdum $RMDEVROOT >/dev/null 2>&1;
}

#*******************************************************************************
# PROCEDURE:	RebuildRmdevroot	
# SUMMARY:	Ggenerate the device nodes for SYMplicity storage manager
#		underneath its private device directory.
#
# DESCRIPTION:
# RebuildRmdevroot USED TO performs five basic steps:  (1) delete
# everything from $RMDEVROOT; (2) copy nodes over from "/"; (3) remove sd
# nodes corresponding arrays; (4) remove all rdriver nodes; and (5) run
# disks (actually "symdisks").  Now, all it does is clean out RDAC nodes
# and run symdisks.
#
# SYNTAX:
# RebuildRmdevroot
#
# NOTES:
#
# RETURNS:
# Nothing
#
RebuildRmdevroot()
{
	CleanRd $RMDEVROOT
	$SYMDISKS -r $RMDEVROOT;
}

#*******************************************************************************
# PROCEDURE:	PrimeDisks
# SUMMARY:	"Prime" the disks utility to make the desired device names.
#
# DESCRIPTION:
# PrimeDisks determines what rdriver devices are configured and creates
# "placeholder" symlinks in /dev, so as to force disks to create the expected
# device name.  Without this sort of action, device name links generated by
# disks during parallel LUN creation is unpredictable.
#
# SYNTAX:
# PrimeDisks
#
# NOTES:
#
# RETURNS:
# Nothing
#

PrimeDisks()
{
	grep -v "^#" ${RD_CONF} | grep "dev_" |
	while read RD_CONF_ENTRY
	do
		UNIT=`echo "${RD_CONF_ENTRY}" | cut -d= -f4 | cut -d" " -f1`
		UNIT_HEX=`echo ${UNIT} | awk '{printf("%x", $0)}'`
		TARG=`echo "${RD_CONF_ENTRY}" | cut -d= -f5 | cut -d" " -f1`
		TARG_HEX=`echo ${TARG} | awk '{printf("%x", $0)}'`
		CTRL=`echo "${RD_CONF_ENTRY}" | cut -d@ -f2 | cut -d\" -f1`
		PHYS_NAME=../../devices/pseudo/rdnexus@${CTRL}/rdriver@${TARG_HEX},${UNIT_HEX}:a
		DEV_NAME=c${CTRL}t${TARG}d${UNIT}s0

		SD_DEVS=`ls -l ${ROOT}/dev/dsk/c${CTRL}t* 2>/dev/null | grep -v rdriver | tr -s " " | cut -d" " -f9`
		if [ -n "${SD_DEVS}" ]
		then
			if [ -z "${BUS_WARNING_FLAG}" ]
			then
				echo $WARNING_BUS
				BUS_WARNING_FLAG="TRUE"
			fi
			rm ${SD_DEVS}
		fi

		SD_DEVS=`ls -l ${ROOT}/dev/rdsk/c${CTRL}t* 2>/dev/null | grep -v rdriver | tr -s " " | cut -d" " -f9`
		if [ -n "${SD_DEVS}" ]
		then
			if [ -z "${BUS_WARNING_FLAG}" ]
			then
				echo $WARNING_BUS
				BUS_WARNING_FLAG="TRUE"
			fi
			rm ${SD_DEVS}
		fi	
	
		if [ ! -h ${ROOT}/dev/rdsk/${DEV_NAME} ]
		then
			ln -s ${PHYS_NAME} ${ROOT}/dev/dsk/${DEV_NAME} >/dev/null 2>&1
			ln -s ${PHYS_NAME},raw ${ROOT}/dev/rdsk/${DEV_NAME} >/dev/null 2>&1
		fi
	done;
}

#*******************************************************************************
# PROCEDURE:	rdacctrl (main)
# SUMMARY:	Control RDAC startup/shutdown operations
#
# DESCRIPTION:
# rdacctrl conforms to the standard rc script "start/stop" interface.  The
# "start" processing carries out the steps needed to initialize RDAC; the
# "stop processing carries out the steps needed to shut down RDAC.  rdacctrl
# handles two main situations in different ways:  (1) when RDAC is NOT the
# root device, and (2) when RDAC IS controlling the root device.  For the
# non-root case, RDAC reconfiguration occurs as part of "start" processing;
# for the root case, reconfiguration is done as part of "stop" processing, since
# since there is no opportunity in the root case to present a new configuration
# to the RDAC driver via reloading it during bootup.
#
# SYNTAX:
# rdacctrl <action>
# <action> = start | stop | config
# start -> initialize RDAC
# stop -> shutdonw RDAC
# config -> regenerate RDAC config files
#
# NOTES:
# There is also "vendor-unique" argument, "config" which can be used
# (e.g., "rdacctrl config") to regenerate the rdriver .conf file.
#
# RETURNS:
# Nothing


# R D A C C T R L   M A I N   P R O C E D U R E
#
PATH=/sbin:/usr/sbin:/bin:/usr/bin

WARNING="\nWARNING:  It is possible that VxVM is not bound to the RDAC device nodes.You\nneed to reboot or reset the configuration daemon (vxconfigd -k -r reset) to\nensure proper binding.\n"
WARNING_BUS="\nWARNING:  Reconfiguration boot (rdacctrl) has discovered non-array devices on array buses\n"
BUS_WARNING_FLAG=""

RUNNING_DRVCONFIG_MSG="\nCreating /devices entries for the arrays - this is necessary in order to load\nRDAC early and may take up to a few minutes.\n"

UNLOAD_FAILED_ADVISORY="\n(Note:  any messages about the RDAC driver failing to unload are not serious and\nmay be ignored.)\n"

RMPARAMS_FILE=/etc/raid/rmparams
LUNLOCKS=`grep -v "^#" $RMPARAMS_FILE | grep System_LunlocksDirPath | cut -d= -f2`
RM_BOOT_HOME=`grep -v "^#" $RMPARAMS_FILE | grep System_RmBootHomeDirectory | cut -d= -f2`

RMDEVROOT=`grep -v "^#" $RMPARAMS_FILE | grep "System_AltDevDirRoot" | cut -d= -f2 | awk -F/ '{ ORS = "/"; for (i = NF; i > 1; --i) print $i; ORS = "\n"; print $1 }' | cut -d"/" -f3-32 |  awk -F/ '{ ORS = "/"; for (i = NF; i > 1; --i) print $i; ORS = "\n"; print $1 }'`

LAD=$RM_BOOT_HOME/lad
SYMDISKS=$RM_BOOT_HOME/symdisks
RDAC_DRIVER_NAME=rdriver
RD_CONF=/kernel/drv/rdriver.conf

if grep -v "^#" $RMPARAMS_FILE | grep "Rdac_SupportDisabled.*=.*TRUE" >/dev/null 2>&1
then
	RDAC_DISABLED=TRUE
fi

if grep -v "^#" $RMPARAMS_FILE | grep "Rdac_NoReconfig.*=.*TRUE" >/dev/null 2>&1
then
	RDAC_NO_RECONFIG=TRUE
else
	RDAC_NO_RECONFIG=""
fi

if [ ! -d $RMDEVROOT/dev ]
then
	FRESH_INSTALL=TRUE
fi

#
# set up access to "logger" program
#
if [ -x "/usr/ucb/logger" ]
then
	LOGGER=/usr/ucb/logger
elif [ -x "/usr/bin/logger" ]
then
	LOGGER=/usr/bin/logger
else
	LOGGER=/bin/echo
fi

umask 0002
case $1 in


'start')
	if [ -z "`modinfo | grep sd | grep SCSI`" ]
	then
		drvconfig -i sd 2>/dev/null
		if [ $? != 0 ]
		then
			exit 1
		fi
	fi
	# get rid of any lurking lun locks and semaphores
	rm $LUNLOCKS 2>/dev/null
	rm /etc/raid/locks/* 2>/dev/null
	rm /tmp/mutex.add_disk /tmp/mutex.add_rdac /tmp/mutex.symdisks 2>/dev/null

	grep "^#!noauto_config" /kernel/drv/rdriver.conf >/dev/null 2>&1
	if [ $? -ne 0 -a -z "${RDAC_NO_RECONFIG}" ]
	then
		AUTO_CONFIG_ENABLED=TRUE
	fi

	# try to unload the RDAC driver
	modunload -i `modinfo | grep rdriver | cut -c1-3` 2>/dev/null
	if [ "$?" != 0 ]
	then
		UNLOAD_FAILED=TRUE
	fi

	if [ -n "${_INIT_RECONFIG}" ]
	then
		if [ -n "${FRESH_INSTALL}" ]
		then
			MakeRmdevroot
		fi
		RebuildRmdevroot
		if [ -z "`modinfo | grep rdriver`" ]
		then
			CleanRd /
		fi
		mv /kernel/drv/rdriver.conf /tmp/rdriver.conf.orig
		echo name=\"rdriver\" parent=\"pseudo\" instance=0\; >/kernel/drv/rdriver.conf
		if [ -z "${RDAC_DISABLED}" ]
		then
			rm /tmp/sdDeleted.$$ 2>/dev/null
			CleanSd /
		fi
	fi

	if [ -n "${RDAC_DISABLED}" ]
	then
		echo "RDAC support disabled"
		rm /tmp/rdriver.conf.orig 2>/dev/null

		# make sure rdriver.conf attributes are as they should be
		chmod 644 /kernel/drv/rdriver.conf
		chown root /kernel/drv/rdriver.conf
		chgrp sys  /kernel/drv/rdriver.conf

		exit
	fi

	#
	# Proceeding with RDAC initialization
	#

	if [ -n "${_INIT_RECONFIG}" ]
	then
		# generate new rdriver.conf

		if [ -n "${AUTO_CONFIG_ENABLED}" ]
		then
			GenRdriverConf VERBOSE
			DRVCONFIG_NEEDED=TRUE
		else
			# auto-config disabled - put original back!
			mv /tmp/rdriver.conf.orig /kernel/drv/rdriver.conf
		fi
		PrimeDisks	# Make sure we get right nodes out of impending disks run
	fi

	if [ -z "`modinfo | grep rdriver`" ]
	then
		cd /kernel/drv
		modload rdriver
		DRVCONFIG_NEEDED=TRUE
		echo "RDAC driver re-loaded"
	fi

	if [ -n "${DRVCONFIG_NEEDED}" ]
	then
		drvconfig -i rdriver
	fi

        VXCONFIGD_ALIVE=`ps -ef | grep vxconfigd 2>/dev/null | grep -v grep 2>/dev/null`
	if [ -n "${VXCONFIGD_ALIVE}" ]
	then
		VX_BOOTED=`vxdctl mode 2>/dev/null | grep booted`
		if [ -n "${VX_BOOTED}" -a \( -n "${FRESH_INSTALL}" -o -f /tmp/sdDeleted.$$ \) ]
		then
			echo $WARNING
			sleep 3
		fi
	fi

	# clean up after ourselves
	rm /tmp/sdDeleted.$$ /tmp/rdriver.conf /tmp/rdriver.conf.orig /tmp/rdriver.conf.all 2>/dev/null

	# make sure rdriver.conf attributes are as they should be
	chmod 644 /kernel/drv/rdriver.conf
	chown root /kernel/drv/rdriver.conf
	chgrp sys  /kernel/drv/rdriver.conf

	if [ -n "${UNLOAD_FAILED}" ]
	then
		echo $UNLOAD_FAILED_ADVISORY
	fi

	;;


'stop')

	# nothing to do here, really
	;;


'config')

	if [ -n "${RDAC_DISABLED}" ]
	then
		echo "RDAC disabled - NOT configuring"
		exit
	fi
	if [ -n "${FRESH_INSTALL}" ]
	then
		MakeRmdevroot
	fi
	RebuildRmdevroot
	DEVS_EXIST=`$LAD | wc -l`
	if [ "${DEVS_EXIST}" = 0 ]
	then
		echo $RUNNING_DRVCONFIG_MSG
		drvconfig -i sd
		RebuildRmdevroot
	fi
	CleanSd /
	/etc/init.d/amdemon stop	# stop SYMsm daemons
	GenRdriverConf VERBOSE
	if [ -n "`modinfo | grep rdriver`" ]
	then
		echo "Unable to unload RDAC driver - reboot to make new configuration take effect"
	else
		CleanRd /
		cd /kernel/drv
		modload rdriver
		$SYMDISKS -r /"${ROOT}" -d rdriver
	fi
	/etc/init.d/amdemon start	# restart SYMsm daemons

	# make sure rdriver.conf attributes are as they should be
	chmod 644 /kernel/drv/rdriver.conf
	chown root /kernel/drv/rdriver.conf
	chgrp sys  /kernel/drv/rdriver.conf

	;;

*)
	echo "usage: rdacctrl {start|stop|config}"
	;;
esac
