OpenSolaris_b135/pkgdefs/common_files/i.scsivhciconf

#!/bin/sh
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
# ident	"%Z%%M%	%I%	%E% SMI"
#
# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#

PATH=/usr/bin:/usr/sbin:$PATH; export PATH

PREFIX=/tmp/scsi_vhci.$$
FPCONF=kernel/drv/fp.conf
#
# Add any new entries to be added to fp.conf to this file. The class action
# script for fp.conf will append the entries of this file to fp.conf.
#
NEW_FPCONF_ENTRIES=/tmp/fp.conf.new_entries

#
# Check if mpxio is enabled or disabled in the given scsi_vhci.conf file
# $1	scsi_vhci.conf file
#
# Returns 0 if disabled, 1 if enabled, 2 if can't determine.
#
is_mpxio_enabled()
{
	if egrep "^[ 	]*mpxio-disable[ 	]*=[ 	]*\"yes\"[ 	]*;" \
	    $1 > /dev/null 2>&1; then
		return 0
	fi

	if egrep "^[ 	]*mpxio-disable[ 	]*=[ 	]*\"no\"[ 	]*;" \
	    $1 > /dev/null 2>&1; then
		return 1
	fi

	return 2
}

#
# Make sed script to do most of the work of upgrading scsi_vhci.conf.
#
make_sed_script()
{
	#
	# remove mpxio-disable and forceattach properties.
	# forceattach is no longer necessary as the framework always loads
	# scsi_vhci early during boot.
	#
	cat > $SEDSCRIPT << EOF
/^# mpxio Global enable\/disable configuration$/d
/^# possible values are mpxio-disable="no" or mpxio-disable="yes"$/d
/^# mpxio global enable\/disable switch: setting mpxio-disable="no" will activate$/d
/^# I\/O multipathing; setting mpxio-disable="yes" disables this feature (do$/d
/^# not remove this property).$/d
/^[ 	]*mpxio-disable[ 	]*=/d
/^# Force load driver to support hotplug activity (do not remove this property).$/d
/^ddi-forceattach=1;$/d
EOF
	#
	# convert old 'scsi-options' oriented device-type-scsi-options-list to
	# new 'name' oriented scsi-vhci-failover-override
	#
	cat > $SEDSCRIPT << EOF
/^# For enabling MPxIO support for 3rd party symmetric device need an$/d
/^# entry similar to following in this file. Just replace the "SUN     SENA"$/d
/^# part with the Vendor ID\/Product ID for the device, exactly as reported by$/d
/^# Inquiry cmd.$/d
/^# device-type-scsi-options-list =$/d
/^# "SUN     SENA", "symmetric-option";$/d
/^# symmetric-option = 0x1000000;$/d
s/device-type-scsi-options-list/scsi-vhci-failover-override/
EOF
	# old 'symetric' scsi-options property of 1000000 -> f_sym name
	SYMMETRIC_OPTION=`grep -v '^#' $2 | grep 1000000 | \
		awk -F= '{print $1}'|awk '{print $1}'`
	if [ "$SYMMETRIC_OPTION"x != "x" ]; then
		echo "/^[ 	]*$SYMMETRIC_OPTION/d"	>> $SEDSCRIPT
		echo "s/$SYMMETRIC_OPTION/f_sym/"	>> $SEDSCRIPT
	fi

	# old 'disable' scsi-options property of 7000000 -> NONE name
	DISABLE_OPTION=`grep -v '^#' $2 | grep 7000000 | \
		awk -F= '{print $1}'|awk '{print $1}'`
	if [ "$DISABLE_OPTION"x != "x" ]; then
		echo "/^[ 	]*$DISABLE_OPTION/d"	>> $SEDSCRIPT
		echo "s/$DISABLE_OPTION/NONE/"		>> $SEDSCRIPT
	fi
}

#
# Make FAILOVER_MODULE_BLOCK file
#
make_fmbfile()
{
	#
	# Form file with new scsi_vhci FAILOVER_MODULE_BLOCK information
	#
	cat > $FMBFILE << EOF
#BEGIN: FAILOVER_MODULE_BLOCK (DO NOT MOVE OR DELETE)
#
# Declare scsi_vhci failover module paths with 'ddi-forceload' so that
# they get loaded early enough to be available for scsi_vhci root use.
#
# NOTE: Correct operation depends on the value of 'ddi-forceload', this
# value should not be changed. The ordering of entries is from
# most-specific failover modules (with a "probe" implementation that is
# completely VID/PID table based), to most generic (failover modules that
# are based on T10 standards like TPGS). By convention the last part of a
# failover module path, after "/scsi_vhci_", is called the
# "failover-module-name", which begins with "f_" (like "f_asym_sun"). The
# "failover-module-name" is also used in the override mechanism below.
ddi-forceload =
	"misc/scsi_vhci/scsi_vhci_f_asym_sun",
	"misc/scsi_vhci/scsi_vhci_f_asym_lsi",
	"misc/scsi_vhci/scsi_vhci_f_asym_emc",
	"misc/scsi_vhci/scsi_vhci_f_sym_emc",
	"misc/scsi_vhci/scsi_vhci_f_sym_hds",
	"misc/scsi_vhci/scsi_vhci_f_sym",
#	"misc/scsi_vhci/scsi_vhci_f_tpgs_tape",
#	"misc/scsi_vhci/scsi_vhci_f_tape",
	"misc/scsi_vhci/scsi_vhci_f_tpgs";

#
# For a device that has a GUID, discovered on a pHCI with mpxio enabled, vHCI
# access also depends on one of the scsi_vhci failover modules accepting the
# device.  The default way this occurs is by a failover module's "probe"
# implementation (sfo_device_probe) indicating the device is supported under
# scsi_vhci.  To override this default probe-oriented configuration in
# order to
#
#    1)	establish support for a device not currently accepted under scsi_vhci
#
# or 2)	override the module selected by "probe"
#
# or 3)	disable scsi_vhci support for a device
#
# you can add a 'scsi-vhci-failover-override' tuple, as documented in
# scsi_get_device_type_string(9F). For each tuple, the first part provides
# basic device identity information (vid/pid) and the second part selects
# the failover module by "failover-module-name". If you want to disable
# scsi_vhci support for a device, use the special failover-module-name "NONE".
# Currently, for each failover-module-name in 'scsi-vhci-failover-override'
# (except "NONE") there needs to be a
# "misc/scsi_vhci/scsi_vhci_<failover-module-name>" in 'ddi-forceload' above.
#
#	"                  111111"
#	"012345670123456789012345",	"failover-module-name" or "NONE"
#	"|-VID--||-----PID------|",
# scsi-vhci-failover-override =
#	"STK     FLEXLINE 400",		"f_asym_lsi",
#	"SUN     T4",			"f_tpgs",
#	"CME     XIRTEMMYS",		"NONE";
#
#END: FAILOVER_MODULE_BLOCK (DO NOT MOVE OR DELETE)
EOF
}

#
# Upgrade the destination scsi_vhci.conf file.
# $1	source scsi_vhci.conf file
# $2	destination scsi_vhci.conf file (the file to be upgraded)
#
# Returns 0 on success, non zero on failure.
#
update_scsi_vhci()
{
	TMPSCSIVHCI=$PREFIX.conf
	SEDSCRIPT=$PREFIX.sed
	FMBFILE=$PREFIX.fb

	# make sed script to do most of the work of upgrading
	make_sed_script $1 $2

	sed -f $SEDSCRIPT $2 > $TMPSCSIVHCI 2>/dev/null
	retval=$?
	if [ $retval -eq 0 ]; then
		cp $TMPSCSIVHCI $2
		grep "FAILOVER_MODULE_BLOCK" $2 >/dev/null 2>&1
		if [ $? -ne 0 ]; then
			make_fmbfile
			cat $FMBFILE >> $2
		fi
	fi

	rm -f $SEDSCRIPT $TMPSCSIVHCI $FMBFILE
	return $retval
}

#
# Preprocess a driver.conf file. The output is written to out file.
# $1	driver.conf file
# $2	out file
#
preprocess()
{
	TMPPREPROCESS=$PREFIX.preprocess

	# strip comments, blank lines, leading and trailing spaces
	sed -e "/^[ 	]*#/d"	\
	    -e "/^[ 	]*$/d"	\
	    -e "s/^[ 	]*//"	\
	    -e "s/[ 	]*$//" $1 > $TMPPREPROCESS

	# combine entries that spawn more than one line
	sed -e "/;$/p"		\
	    -e "/;$/d"		\
	    -e ":rdnext"	\
	    -e "N"		\
	    -e "s/\n/ /"	\
	    -e "/;$/p"		\
	    -e "/;$/d"		\
	    -e "b rdnext" $TMPPREPROCESS > $2

	rm -f $TMPPREPROCESS
}

#
# Disable mpxio on all fp ports.
# $1	fp.conf file
#
# Returns 0 on success, non zero on failure.
#
disable_mpxio_globally()
{
	TMPFP1=$PREFIX.fp1
	TMPFP2=$PREFIX.fp2

	if [ ! -f $1 ]; then
		echo "mpxio-disable=\"yes\";" > $NEW_FPCONF_ENTRIES
		return 0
	fi

	#
	# change all occurrences of mpxio-disable (including per port) value
	# from "no" to "yes" except in comments.
	#
	sed -e "/^[ 	]*#/p" -e "/^[ 	]*#/d"	\
	  -e "s/mpxio-disable[ 	]*=[ 	]*\"no\"/mpxio-disable=\"yes\"/g"\
	    $1 > $TMPFP1 2>/dev/null

	retval=$?
	if [ $retval -eq 0 ]; then
		preprocess $TMPFP1 $TMPFP2
		# add global mpxio-disable if not already present
		egrep "^mpxio-disable[ 	]*=[ 	]*\"yes\"[ 	]*;" \
		    $TMPFP2 >/dev/null 2>&1
		if [ $? -ne 0 ]; then
			echo "mpxio-disable=\"yes\";" > $NEW_FPCONF_ENTRIES
		fi
		cp $TMPFP1 $1
		rm -f $TMPFP2
	fi

	rm -f $TMPFP1
	return $retval
}

#
# Check if mpxio-disable entry is present in fp.conf file for the specified
# controller and port.
#
# $1	fp.conf file
# $2	controller name
# $3	port number
#
# Returns 1 if the entry is present, 0 if not.
#
check_mpxio()
{
	TMPFILE=$PREFIX.check

	preprocess $1 $TMPFILE
	if egrep "parent[ 	]*=[ 	]*\"$2\"" $TMPFILE \
	    2>/dev/null | egrep "port[ 	]*=[ 	]*$3" 2>/dev/null | \
	    egrep "mpxio-disable[ 	]*=[ 	]*\".*\"" >/dev/null 2>&1; then
		rm -f $TMPFILE
		return 1
	fi

	rm -f $TMPFILE
	return 0
}

#
# Reads vfstab entry fields corresponding to the specified mount point.
# This function assumes that stdin is already set to vfstab.
#
# $1	mount point
#
readvfstab()
{
	while read special fsckdev mountp fstype fsckpass automnt mntopts; do
		case "$special" in
		'#'* | '')	#  Ignore comments, empty lines
				continue ;;
		'-')		#  Ignore no-action lines
				continue
		esac

		[ "x$mountp" = "x$1" ] && break
	done
}

#
# Disable mpxio on the specified controller if the controller had mpxio
# disabled (implicitly) before the upgrade.
#
# $1	directory on which the root filesystem of the OS image being
#	upgraded is mounted.
# $2	/dev link or /devices name of the root slice whose controller needs
#	to have mpxio disabled.
#
disable_mpxio()
{
	if echo "$2" | grep "/devices/" >/dev/null 2>&1; then
		physpath=`echo "$2" | sed "s/^.*\/devices\//\//" 2>/dev/null`
	elif echo "$2" | grep "/dev/" >/dev/null 2>&1; then
		# it is /dev link
		physpath=`ls -l $1/$2 | sed "s/^.*\/devices\//\//" 2>/dev/null`
	else
		return
	fi

	if echo "$physpath" | grep "/fp@" >/dev/null 2>&1; then
		# extract controller and port number
		controller=`echo "$physpath" | sed "s/\/fp@.*$//" 2>/dev/null`
		port=`echo "$physpath" | sed -e "s/^.*\/fp@//" 2>/dev/null \
		    -e "s/,0\/.*$//" 2>/dev/null`

		#
		# add an entry to fp.conf to disable mpxio only if not already
		# present.
		#
		check_mpxio $1/$FPCONF $controller $port
		if [ $? -eq 0 ]; then
			echo "name=\"fp\" parent=\"$controller\" port=$port \
mpxio-disable=\"yes\";" >> $NEW_FPCONF_ENTRIES
		fi
	fi
}

#
# Disable mpxio on the root controller if it was implicitly disabled before
# the upgrade.
#
# Note that s8 and s9 didn't have mpxio support on the root controller.
# So root controller always had mpxio disabled. But Network Storage supplies a
# patch to enable mpxio on the root controller.
#
# $1	directory on which the root filesystem of the OS image being
#	upgraded is mounted.
#
disable_mpxio_on_root()
{
	rel=`uname -r | cut -f 2 -d .`
	if [ $rel -lt 10 ]; then
		# live upgrade
		root=/
	else
		root=$1
	fi

	#
	# if the root is a metadevice disable mpxio on each of the component
	# controllers if the component controller had mpxio disabled before.
	#
	if mount | grep "^$root on /dev/md/dsk/" >/dev/null 2>&1; then
		metadev=`mount | grep "^$root on /dev/md/dsk/" | \
		    cut -f3 -d " " | cut -f5 -d "/"`
		devlist=`metastat -p $metadev | grep " 1 1 " | \
		    sed -e "s/^.* 1 1 //" | cut -f1 -d " "`
		if [ "x$devlist" = x ]; then
			return
		fi
		for d in $devlist
		do
			disable_mpxio $1 /dev/dsk/$d
		done
	else
		exec < ${root}/etc/vfstab; readvfstab "/"
		disable_mpxio $1 $special
	fi
	
}

if read src dest; then
	# first delete if a stale version of this file exists
	rm -f $NEW_FPCONF_ENTRIES

	if [ ! -f $dest ]; then
		cp $src $dest
		#
		# If we are upgrading from s7 or s8, scsi_vhci.conf file
		# won't exist and mpxio needs to be globally disabled.
		#
		# XXX Install doesn't provide a way to distinguish between
		# fresh install and upgrade. In this hack we assume that if
		# the system's vfstab already contains an entry for the root
		# it must be an upgrade.
		#
		if [ -s $PKG_INSTALL_ROOT/etc/vfstab ]; then
			exec < $PKG_INSTALL_ROOT/etc/vfstab; readvfstab "/"
			if [ "x$mountp" = x/ ]; then
				disable_mpxio_globally $PKG_INSTALL_ROOT/$FPCONF
				if [ $? -ne 0 ]; then
					exit 1
				fi
			fi
		fi
		exit 0
	fi

	is_mpxio_enabled $dest
	mpxio_on=$?
	update_scsi_vhci $src $dest
	if [ $? -ne 0 ]; then
		exit 1
	fi

	if [ $mpxio_on -eq 0 ]; then
		disable_mpxio_globally $PKG_INSTALL_ROOT/$FPCONF
		if [ $? -ne 0 ]; then
			exit 1
		fi
	elif [ $mpxio_on -eq 1 ]; then
		if [ "x$PKG_INSTALL_ROOT" != x ]; then
			disable_mpxio_on_root $PKG_INSTALL_ROOT
		else
			disable_mpxio_on_root /
		fi 
	fi
fi

exit 0