#!/bin/bash
#
# Configures a ccw interface.
# $Id: hwup-ccw 1124 2004-11-24 13:52:11Z hare $
#
# Detects all ccw devices as per modules.ccwmap
# (current as of 2.6.5)
#
# Should be called from /sbin/hwup with the
# hardware configuration as argument
#
# The hardware configuration should look like
# <type>-bus-<bus>-<id>
# e.g.
# 'hwup-ccw dasd-bus-ccw-0.0.0190'
# 
# Programs called from this script:
#  echo
#  expr
#  test
#

SCRIPTNAME=${0##*/}
CONFIG=$1
HWDESC=$2

# Read in common functions
. ./scripts/functions
test -r ./config && . ./config

if test -z "$SYSFS"; then
    message "sysfs not mounted, aborting."
    exit 1
fi

# Read in the configuration file
. ./hwcfg-${CONFIG}

# Set defaults
if [ -z "$HWD_DEVICEPATH" ]; then
    HWD_DEVICEPATH=${SYSFS}/bus/ccw/devices/${HWD_BUSID}
fi

if [ ! -d "$HWD_DEVICEPATH" ]; then
    message "No hardware devicepath given, cannot configure"
    exit 1
fi

# Check for the attached control unit and device type
read _cu_type < $HWD_DEVICEPATH/cutype
read _dev_type < $HWD_DEVICEPATH/devtype

#
# This checks for all known control units and device types.
# Information is from /lib/modules/<kversion>/modules.ccwmap
#
if [ -z "$CCW_CHAN_NAME" ] ; then
    CCW_CHAN_GROUP=
    CCW_CHAN_NUM=
    case "$_cu_type" in
	3088/01)
	    # P/390 network adapter (Not tested)
	    CCW_CHAN_NAME="cu3088"
	    CCW_CHAN_GROUP="p390"
	    CCW_CHAN_NUM=2
	    ;;
	3088/08)
	    # Channel To Channel
	    CCW_CHAN_NAME="cu3088"
	    CCW_CHAN_GROUP="ctc"
	    CCW_CHAN_NUM=2
	    ;;
	3088/1e)
	    # FICON adapter (Not tested)
	    CCW_CHAN_NAME="cu3088"
	    CCW_CHAN_GROUP="ficon"
	    CCW_CHAN_NUM=2
	    ;;
	3088/1f)
	    # ESCON adapter (I.e. hardware CTC device)
	    CCW_CHAN_NAME="cu3088"
	    CCW_CHAN_GROUP="ctc"
	    CCW_CHAN_NUM=2
	    ;;
	3088/60)
	    # Lan Control Station
	    CCW_CHAN_NAME="cu3088"
	    CCW_CHAN_GROUP="lcs"
	    CCW_CHAN_NUM=2
	    ;;
	1731/01|1731/05)
	    # OSA/Express or Guest LAN
	    CCW_CHAN_NAME="qeth"
	    CCW_CHAN_NUM=3
	    ;;
	1731/03)
	    # zFCP adapter
	    if [ "$_dev_type" == "1732/03" -o "$_dev_type" == "1732/04" ]; then
		CCW_CHAN_NAME="zfcp"
	    else
		CCW_CHAN_NAME=
	    fi
	    ;;
	3480/*|3490/*)
	    # IBM 3480/3490 tape driver
	    if [ "$_dev_type" == "$_cu_type" ]; then
		CCW_CHAN_NAME="tape-34xx"
	    else
		CCW_CHAN_NAME=
	    fi
	    ;;
	3990/*|2105/*|9343/*)
	    # DASD (ECKD mode)
	    CCW_CHAN_NAME="dasd-eckd"
	    ;;
	6310/*)
	    # DASD (FBA mode)
	    CCW_CHAN_NAME="dasd-fba"
	    ;;
	3880/*)
	    case "$_dev_type" in
		3390/*)
	            # DASD (ECKD mode)
		    CCW_CHAN_NAME="dasd-eckd"
		    ;;
		3370/*)
	            # DASD (FBA mode)
		    CCW_CHAN_NAME="dasd-fba"
		    ;;
		*)
		    CCW_CHAN_NAME=
		    ;;
	    esac
	    ;;
	*)
	    CCW_CHAN_NAME=
	    ;;
    esac
fi

# Unknown device
if [ -z "$CCW_CHAN_NAME" ]; then
    message "Invalid device type (cu ${_cu_type} dev ${_dev_type}"
    exit 1
fi

# Set defaults
if test -z "$CCW_CHAN_GROUP"; then
    CCW_CHAN_GROUP="$CCW_CHAN_NAME"
fi
if test -z "$CCW_CHAN_NUM"; then
    CCW_CHAN_NUM="1"
fi
if test -z "$CCW_CHAN_IDS"; then
    CCW_CHAN_IDS="$HWD_BUSID"
fi
CCW_USE_DIAG=0
if test "$CCW_CHAN_NAME" = "dasd-eckd" -o "$CCW_CHAN_NAME" = "dasd-fba"; then
    if test "$DASD_USE_DIAG" && test "$DASD_USE_DIAG" -eq 1 ; then
	CCW_USE_DIAG=1
    fi
fi

# Set sysfs paths
_ccw_dir=${SYSFS}/bus/ccw/drivers/${CCW_CHAN_NAME}
_ccwgroup_dir=${SYSFS}/bus/ccwgroup/drivers/${CCW_CHAN_GROUP}

if [ -z "$CCW_CHAN_IDS" ] ; then
    message "no channel IDs given"
    exit 1
fi

# Checking channel availability

# Check whether we need to configure the channel group
if test "$CCW_CHAN_NUM" -gt 1 ; then
    set -- $CCW_CHAN_IDS
    CCW_CHAN_GROUPID=$1
    
    if test -d "$_ccwgroup_dir/$CCW_CHAN_GROUPID" ; then
	# Device group already configured
	debug "Device group $CCW_CHAN_GROUPID already configured!"
    else
	debug "Checking group ${CCW_CHAN_GROUPID}"
	
        # Check whether all channels for this device are accessible
	num=0
	for _ccw_file in $CCW_CHAN_IDS; do
	    if test ! -d "${_ccw_dir}/${_ccw_file}" ; then
		_ccw_group_lst=
		break;
	    fi
	    _ccw_group_lst="${_ccw_group_lst:-${_ccw_file}}${_ccw_group_lst:+,${_ccw_file}}"
	    num=$(expr $num + 1)
	done
	
        # Configure the channel group
	# Note that the non-existence of channels is not a failure;
	# if we were called during start-up it might well be that
	# not all channels are available yet.
	if test "$num" -lt "$CCW_CHAN_NUM" ; then 
	    if test -z "$_ccw_group_lst" ; then
		message "Device group ${CCW_CHAN_GROUPID} not (yet) available!"
	    else
		message "Not enough channels for this device!"
	    fi
	else
	    message "Configuring group ${CCW_CHAN_GROUPID}"
	    echo $_ccw_group_lst > $_ccwgroup_dir/group
	fi
    fi
else
    message_n "Configuring device ${CCW_CHAN_IDS}: "
    _ccw_status_dir="$_ccw_dir/$CCW_CHAN_IDS"
    # Set the device online
    if test -d "$_ccw_status_dir" ; then
	read _ccw_dev_online < $_ccw_status_dir/online
	if [ "$_ccw_dev_online" -eq 0 ]; then
	    if [ "$CCW_USE_DIAG" -eq 1 ]; then
                # DIAG access for DASDs
                # Need to be done prior to activation
		debug "Activating DIAG access mode"
		echo 1 > $_ccw_status_dir/use_diag
	    fi
	    # Set the device online
	    debug "Setting device online"
	    echo "1" > $_ccw_status_dir/online

            # Re-read device status
	    read _ccw_dev_status < $_ccw_status_dir/online

	    if [ "$CCW_USE_DIAG" -eq 1 ]; then
		# Special handling for DIAG devices:
		# The availability of DIAG access can only be
		# established if the device could be activated.
		# If this fails, we fall back to normal access
		# and ignore any DIAG parameter.
		if [ "$_ccw_dev_status" -eq 0 ]; then
		    # Failed to activate device
		    message_n "(DIAG not available) "
		    echo 0 > $_ccw_status_dir/use_diag
	             # Set the device online
		    debug "Setting device online w/o DIAG access"
		    echo "1" > $_ccw_status_dir/online
                    # Re-read device status
		    read _ccw_dev_status < $_ccw_status_dir/online
		else
		    message_n "(DIAG) "
		fi
	    fi
	    # Special handling for zfcp: might be online but 
	    # status might indicate that something went wrong
	    if [ -r $_ccw_status_dir/failed ]; then
		read _ccw_dev_status < $_ccw_status_dir/failed
		# Invert the sense
		let _ccw_dev_status^=1
	    fi

	    # Check for success
	    if [ "$_ccw_dev_status" -eq 0 ]; then
		# Failed to activate device
		message "failed."
	    else
		message "ok."
	    fi
	else
	    debug "Device already activated"
	fi
    else
	message "not available."
    fi
fi
