#!/bin/sh
#
# Copyright(c) 2009 Intel Corporation. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms and conditions of the GNU General Public License,
# version 2, as published by the Free Software Foundation.
#
# This program is distributed in the hope it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
#
# chkconfig: - 21 80
#
# Maintained at www.Open-FCoE.org

### BEGIN INIT INFO
# Provides: fcoe
# Required-Start: network
# Required-Stop:
# Default-Start:
# Default-Stop:
# Short-Description: Open-FCoE SAN Setup
# Description: Open-FCoE SAN Setup
### END INIT INFO

CONFIG_DIR=/etc/fcoe
CONFIG_SCRIPT=$CONFIG_DIR/scripts/fcoeplumb
PID_FILE="/var/run/fcoemon.pid"
LOG_FILE="/var/log/fcoemon.log"
FCOEMON=/usr/sbin/fcoemon
FCOEADM=/usr/sbin/fcoeadm
DCBD=dcbd
LOGGER="logger -t fcoe -s"

. /etc/init.d/functions

varify_yesno_values()
{
	value=$1

	case $value in
		"yes" | "YES" ) return 1 ;;
		"no" | "NO" ) return 2 ;;
		*) return 0 ;;
	esac
}

verify_configuration()
{
	. $CONFIG_DIR/config
	varify_yesno_values $USE_SYSLOG
	if [ $? -eq 0 ]; then
		echo "Invalid USE_SYSLOG in $CONFIG_DIR/config"
		return 1
	fi
	varify_yesno_values $DEBUG
	if [ $? -eq 0 ]; then
		echo "Invalid DEBUG in $CONFIG_DIR/config"
		return 1
	fi

	for ifcfg_file in `ls $CONFIG_DIR/cfg-eth*`
	do
		. $ifcfg_file
		varify_yesno_values $FCOE_ENABLE
		if [ $? -eq 0 ]; then
			echo "Invalid FCOE_ENABLE in $ifcfg_file"
			return 1
		fi
		varify_yesno_values $DCB_REQUIRED
		if [ $? -eq 0 ]; then
			echo "Invalid DCB_REQUIRED in $ifcfg_file"
			return 1
		fi
	done
	return 0
}

verify_configuration
if [ $? -ne 0 ]; then
    failure
fi

if [ "$USE_SYSLOG" != "yes" ] && [ "$USE_SYSLOG" != "YES" ]; then
	LOGGER="echo"
fi

if [ "$DEBUG" = "yes" ] || [ "$DEBUG" = "YES" ]; then
	DEBUG="yes"
fi

test -x $CONFIG_SCRIPT || {
	$LOGGER "$CONFIG_SCRIPT not installed";
	if [ "$1" = "stop" ]; then exit 0;
	else
	    failure
	fi
}

test -x $FCOEADM || {
	$LOGGER "$FCOEADM not installed";
	if [ "$1" = "stop" ]; then exit 0;
	else
	    failure
	fi
}

validate_link_flow_control()
{
	ifname=$1

	retry_count=1
	while true
	do
		TX_STATUS=`ethtool -a $ifname 2>&1 | awk '/TX:/{print $2}'`
		RX_STATUS=`ethtool -a $ifname 2>&1 | awk '/RX:/{print $2}'`

		if [ "$TX_STATUS" = "on" ] && [ "$RX_STATUS" = "on" ]; then
			return 0
		fi

		ethtool -A $ifname rx on tx on
		[ $retry_count -eq 0 ] && return 0
		retry_count=$(($retry_count-1))
		usleep 500000
	done
	$LOGGER "Warning: Failed to bring up link flow control of $ifname."
	return 1
}

service_start()
{
	rm -f /var/run/fcoemon.*

	modprobe -q libfc
	modprobe -q fcoe

	HAS_DCB_IF="false"
	for ifcfg_file in `ls $CONFIG_DIR/cfg-eth*`
	do
		ifname=`basename $ifcfg_file | cut -d"-" -f2`
		. $ifcfg_file
		[ "$FCOE_ENABLE" != "yes" ] &&
		[ "$FCOE_ENABLE" != "YES" ] && continue

		if [ "$DCB_REQUIRED" != "yes" ] &&
		   [ "$DCB_REQUIRED" != "YES" ]; then
			#
			# DCB is not required, we nee to validate the
			# link flow control of the Ethernet port
			#
			validate_link_flow_control $ifname
			[ $? -ne 0 ] && continue
			#
			# Create the FCoE interface
			#
			$FCOEADM -c $ifname
		else
			#
			# Configure the DCB for the Ethernet
			# port if DCB is required
			#
			HAS_DCB_IF="true"
		fi
	done

	#
	# If DCB-required Ethernet port exists, then start the fcoemon
	# daemon to create the FCoE interfaces for these ports.
	#
	if [ "$HAS_DCB_IF" = "true" -a -x $FCOEMON ]; then
	    daemon --pidfile ${PID_FILE} ${FCOEMON}
	fi

  echo 
  touch /var/lock/subsys/fcoe

	return
}

service_stop()
{
	pidof $FCOEMON
	[ $? -eq 0 ] && kill -TERM `pidof $FCOEMON`

	for ifcfg_file in `ls $CONFIG_DIR/cfg-eth*`
	do
		ifname=`basename $ifcfg_file | cut -d"-" -f2`
		. $ifcfg_file
		[ "$FCOE_ENABLE" != "yes" ] &&
		[ "$FCOE_ENABLE" != "YES" ] && continue
		if [ "$DCB_REQUIRED" != "yes" ] &&
		   [ "$DCB_REQUIRED" != "YES" ]; then
			STATUS=`$FCOEADM -i $ifname 2>&1 | \
				awk '/Interface Name:/{print $3}'`
			if [ "$STATUS" = "$ifname" ]; then
				$FCOEADM -d $ifname
			fi
		fi
	done

	retry_count=5
	while true
	do
		[ $retry_count -eq 0 ] && break
		ps | grep -q fcoeplumb
		[ $? -ne 0 ] && [ ! -f $PID_FILE ] && break
		sleep 1
		retry_count=$(($retry_count-1))
	done
	rm -f /var/run/fcoemon.*
	rm -f /tmp/fcoemon.dcbd.*
  rm -f /var/lock/subsys/fcoe
}

service_status()
{
	pidof $FCOEMON
	if [ $? -eq 0 ]; then
		echo "$FCOEMON -- RUNNING, pid=`cat $PID_FILE`"
	else
		echo "$FCOEMON -- UNUSED"
	fi
	IF_LIST=`$FCOEADM -i 2>&1 | \
		awk '/Interface Name:/{print $3}' | \
		sort | awk '{printf("%s ", $1)}'`
	if [ -z "$IF_LIST" ]; then
		echo "No interfaces created."
	else
		echo "Created interfaces: $IF_LIST"
	fi
	test -f /var/lock/subsys/fcoe
	return $@
}

case "$1" in
	start)
		$LOGGER "Service starting up"
		service_start
		;;
	stop)
		$LOGGER "Service shutting down"
		service_stop
		;;
	try-restart|condrestart)
		if test "$1" = "condrestart"; then
			$LOGGER "${attn} Use try-restart ${done}(LSB)${attn} " \
				"rather than condrestart ${warn}(RH)${norm}"
		fi
		$0 status
		if test $? = 0; then
			$0 restart
		else
			failure
		fi

		;;
	restart)
		$0 stop
		$0 start

		;;
	force-reload)
		$0 try-restart

		;;
	reload)
		$LOGGER "Service reloading"
		failure
		;;
	status)
		service_status
		exit $?
		;;
	*)
		echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload}"
		exit 1
		;;
esac
