2007-06-19 00:21:15 +02:00
|
|
|
#!/bin/bash
|
|
|
|
|
|
|
|
# Usage: block-npiv [add npiv | remove dev]
|
|
|
|
|
|
|
|
dir=$(dirname "$0")
|
|
|
|
. "$dir/block-common.sh"
|
|
|
|
|
|
|
|
#set -x
|
|
|
|
#command=$1
|
|
|
|
|
2009-09-27 00:20:06 +02:00
|
|
|
# Look for the NPIV vport with the WWPN
|
|
|
|
# $1 contains the WWPN (assumes it does not contain a leading "0x")
|
|
|
|
find_vhost()
|
|
|
|
{
|
|
|
|
unset vhost
|
|
|
|
|
|
|
|
# look in upstream locations
|
|
|
|
for fchost in /sys/class/fc_vports/* ; do
|
|
|
|
if test -e $fchost/port_name ; then
|
|
|
|
wwpn=`cat $fchost/port_name | sed -e s/^0x//`
|
|
|
|
if test $wwpn = $1 ; then
|
|
|
|
# Note: makes the assumption the vport will always have an scsi_host child
|
|
|
|
vhost=`ls -d $fchost/device/host*`
|
|
|
|
vhost=`basename $vhost`
|
|
|
|
return
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
|
|
|
|
# look in vendor-specific locations
|
|
|
|
|
|
|
|
# Emulex - just looks like another scsi_host - so look at fc_hosts...
|
|
|
|
for fchost in /sys/class/fc_host/* ; do
|
|
|
|
if test -e $fchost/port_name ; then
|
|
|
|
wwpn=`cat $fchost/port_name | sed -e s/^0x//`
|
|
|
|
if test $wwpn = $1 ; then
|
|
|
|
# Note: makes the assumption the vport will always have an scsi_host child
|
|
|
|
vhost=`basename $fchost`
|
|
|
|
return
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Create a NPIV vport on the fabric w/ FABRICNM, with WWPN,WWNN
|
|
|
|
# $1 contains FABRICNM
|
|
|
|
# $2 contains the VPORT WWPN
|
|
|
|
# $3 contains the VPORT WWNN
|
|
|
|
# (assumes no name contains a leading "0x")
|
|
|
|
create_vport()
|
|
|
|
{
|
|
|
|
# find a base adapter with npiv support that is on the right fabric
|
|
|
|
|
|
|
|
# Look via upstream interfaces
|
|
|
|
for fchost in /sys/class/fc_host/* ; do
|
|
|
|
if test -e $fchost/vport_create ; then
|
|
|
|
# is the link up, w/ NPIV support ?
|
|
|
|
pstate=`cat $fchost/port_state`
|
|
|
|
ptype=`cat $fchost/port_type | cut -c 1-5`
|
|
|
|
fname=`cat $fchost/fabric_name | sed -e s/^0x//`
|
|
|
|
if [ $pstate = "Online" -a $ptype = "NPort" -a $fname = $1 ] ; then
|
|
|
|
vmax=`cat $fchost/max_npiv_vports`
|
|
|
|
vinuse=`cat $fchost/npiv_vports_inuse`
|
|
|
|
avail=`expr $vmax - $vinuse`
|
|
|
|
if [ $avail -gt 0 ] ; then
|
|
|
|
# create the vport
|
|
|
|
echo $2":"$3 > $fchost/vport_create
|
|
|
|
if [ $? -eq 0 ] ; then
|
|
|
|
return 0
|
|
|
|
fi
|
|
|
|
# failed - so we'll just look for the next adapter
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
|
|
|
|
# Look in vendor-specific locations
|
|
|
|
|
|
|
|
# Emulex: interfaces mirror upstream, but are under adapter scsi_host
|
|
|
|
for shost in /sys/class/scsi_host/* ; do
|
|
|
|
if [ -e $shost/vport_create ] ; then
|
|
|
|
fchost=`ls -d $shost/device/fc_host*`
|
|
|
|
# is the link up, w/ NPIV support ?
|
|
|
|
pstate=`cat $fchost/port_state`
|
|
|
|
ptype=`cat $fchost/port_type | cut -c 1-5`
|
|
|
|
fname=`cat $fchost/fabric_name | sed -e s/^0x//`
|
|
|
|
if [ $pstate = "Online" -a $ptype = "NPort" -a $fname = $1 ] ; then
|
|
|
|
vmax=`cat $shost/max_npiv_vports`
|
|
|
|
vinuse=`cat $shost/npiv_vports_inuse`
|
|
|
|
avail=`expr $vmax - $vinuse`
|
|
|
|
if [ $avail -gt 0 ] ; then
|
|
|
|
# create the vport
|
|
|
|
echo $2":"$3 > $shost/vport_create
|
|
|
|
if [ $? -eq 0 ] ; then
|
|
|
|
return 0
|
|
|
|
fi
|
|
|
|
# failed - so we'll just look for the next adapter
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Look for the LUN on the indicated scsi_host (which is an NPIV vport)
|
|
|
|
# $1 is the scsi_host name (normalized to simply the hostX name)
|
|
|
|
# $2 is the WWPN of the tgt port the lun is on
|
|
|
|
# Note: this implies we don't support a multipath'd lun, or we
|
|
|
|
# are explicitly identifying a "path"
|
|
|
|
# $3 is the LUN number of the scsi device
|
|
|
|
find_sdev()
|
|
|
|
{
|
|
|
|
unset dev
|
|
|
|
hostno=${1/*host/}
|
|
|
|
for sdev in /sys/class/scsi_device/${hostno}:*:$3 ; do
|
|
|
|
if test -e $sdev/device/../fc_trans*/port_name ; then
|
|
|
|
tgtwwpn=`cat $sdev/device/../fc_trans*/port_name | sed -e s/^0x//`
|
|
|
|
if test $tgtwwpn = $2 ; then
|
|
|
|
if test -e $sdev/device/block* ; then
|
|
|
|
dev=`readlink $sdev/device/block*`
|
|
|
|
dev=${dev##*/}
|
|
|
|
return
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Look for the NPIV vhost based on a scsi "sdX" name
|
|
|
|
# $1 is the "sdX" name
|
|
|
|
find_vhost_from_dev()
|
|
|
|
{
|
|
|
|
unset vhost
|
|
|
|
hostno=`readlink /sys/block/$1/device`
|
|
|
|
hostno=${hostno##*/}
|
|
|
|
hostno=${hostno%%:*}
|
|
|
|
if test -z "$hostno" ; then return; fi
|
|
|
|
vhost="host"$hostno
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# We're about to terminate a vhost based on a scsi device
|
|
|
|
# Flush all nodes on that vhost as they are about to go away
|
|
|
|
# $1 is the vhost
|
|
|
|
flush_nodes_on_vhost()
|
|
|
|
{
|
|
|
|
if test ! -x /sbin/blockdev ; then return; fi
|
|
|
|
hostno=${1/*host/}
|
|
|
|
for sdev in /sys/class/scsi_device/${hostno}:* ; do
|
|
|
|
if test -e $sdev/device/block* ; then
|
|
|
|
dev=`readlink $sdev/device/block*`
|
|
|
|
dev=${dev##*/}
|
|
|
|
dev="/dev/"$dev
|
|
|
|
if test -n "$dev"; then
|
|
|
|
blockdev --flushbufs $dev
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Terminate a NPIV vhost
|
|
|
|
# $1 is vhost
|
|
|
|
delete_vhost()
|
|
|
|
{
|
|
|
|
# use upstream interface
|
|
|
|
for vport in /sys/class/fc_vports/* ; do
|
|
|
|
if test -e $vport/device/$1 ; then
|
|
|
|
if test -e $vport/vport_delete ; then
|
|
|
|
echo "1" > $vport/vport_delete
|
|
|
|
if test $? -ne 0 ; then exit 6; fi
|
|
|
|
sleep 4
|
|
|
|
return
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
|
|
|
|
# use vendor specific interface
|
|
|
|
|
|
|
|
# Emulex
|
|
|
|
if test -e /sys/class/fc_host/$1/device/../scsi_host*/lpfc_drvr_version ; then
|
|
|
|
shost=`ls -1d /sys/class/fc_host/$1/device/../scsi_host* | sed s/.*scsi_host://`
|
|
|
|
vportwwpn=`cat /sys/class/fc_host/$1/port_name | sed s/^0x//`
|
|
|
|
vportwwnn=`cat /sys/class/fc_host/$1/node_name | sed s/^0x//`
|
|
|
|
echo "$vportwwpn:$vportwwnn" > /sys/class/scsi_host/$shost/vport_delete
|
|
|
|
if test $? -ne 0 ; then exit 6; fi
|
|
|
|
sleep 4
|
|
|
|
return
|
|
|
|
fi
|
|
|
|
|
|
|
|
# Qlogic
|
|
|
|
if test -e /sys/class/fc_host/$1/device/../scsi_host*/driver_version ; then
|
|
|
|
shost=`ls -1d /sys/class/fc_host/$1/device/../scsi_host* | sed s/.*scsi_host://`
|
|
|
|
vportwwpn=`cat /sys/class/fc_host/$1/port_name | sed s/^0x//`
|
|
|
|
vportwwnn=`cat /sys/class/fc_host/$1/node_name | sed s/^0x//`
|
|
|
|
echo "$vportwwpn:$vportwwnn" > /sys/class/scsi_host/$shost/vport_delete
|
|
|
|
if test $? -ne 0 ; then exit 6; fi
|
|
|
|
sleep 4
|
|
|
|
return
|
|
|
|
fi
|
|
|
|
|
|
|
|
exit 6
|
|
|
|
}
|
|
|
|
|
2007-06-19 00:21:15 +02:00
|
|
|
case "$command" in
|
|
|
|
add)
|
2008-02-02 01:58:27 +01:00
|
|
|
# Params is one big arg, with fields separated by hyphens:
|
|
|
|
# FABRIC-VPWWPN-VPWWNN-TGTWWPN-LUN#
|
|
|
|
# arg 2 - Fabric Name
|
|
|
|
# arg 3 - VPORT's WWPN
|
|
|
|
# arg 4 - VPORT's WWNN
|
|
|
|
# arg 5 - Target's WWPN
|
|
|
|
# arg 6 - LUN # on Target
|
|
|
|
# no wwn contains a leading 0x - it is a 16 character hex value
|
|
|
|
# You may want to optionally pick a specific adapter ?
|
2007-06-19 00:21:15 +02:00
|
|
|
par=`xenstore-read $XENBUS_PATH/params` || true
|
|
|
|
#par=$2
|
2008-02-02 01:58:27 +01:00
|
|
|
NPIVARGS=$par;
|
|
|
|
LUN=${NPIVARGS##*-*-*-*-}; NPIVARGS=${NPIVARGS%-*}
|
|
|
|
if test $LUN = $NPIVARGS ; then exit 1; fi
|
|
|
|
TGTWWPN=${NPIVARGS##*-*-*-}; NPIVARGS=${NPIVARGS%-*}
|
|
|
|
if test $TGTWWPN = $NPIVARGS ; then exit 1; fi
|
|
|
|
VPORTWWNN=${NPIVARGS##*-*-}; NPIVARGS=${NPIVARGS%-*}
|
|
|
|
if test $VPORTWWNN = $NPIVARGS ; then exit 1; fi
|
|
|
|
VPORTWWPN=${NPIVARGS##*-}; NPIVARGS=${NPIVARGS%-*}
|
|
|
|
if test $VPORTWWPN = $NPIVARGS ; then exit 1; fi
|
|
|
|
FABRICNM=$NPIVARGS
|
|
|
|
|
|
|
|
# Ensure we compare everything using lower-case hex characters
|
|
|
|
TGTWWPN=`echo $TGTWWPN | tr A-Z a-z`
|
|
|
|
VPORTWWPN=`echo $VPORTWWPN | tr A-Z a-z`
|
|
|
|
VPORTWWNN=`echo $VPORTWWNN | tr A-Z a-z`
|
|
|
|
FABRICNM=`echo $FABRICNM | tr A-Z a-z`
|
|
|
|
|
|
|
|
find_vhost $VPORTWWPN
|
|
|
|
if test -z "$vhost" ; then
|
|
|
|
create_vport $FABRICNM $VPORTWWPN $VPORTWWNN
|
|
|
|
if [ $? -ne 0 ] ; then exit 2; fi
|
2007-06-19 00:21:15 +02:00
|
|
|
sleep 8
|
2008-02-02 01:58:27 +01:00
|
|
|
find_vhost $VPORTWWPN
|
|
|
|
if test -z "$vhost" ; then exit 3; fi
|
|
|
|
fi
|
|
|
|
find_sdev $vhost $TGTWWPN $LUN
|
|
|
|
if test -z "$dev"; then
|
|
|
|
echo "- - -" > /sys/class/scsi_host/$vhost/scan
|
|
|
|
sleep 2
|
|
|
|
find_sdev $vhost $TGTWWPN $LUN
|
|
|
|
fi
|
|
|
|
if test ! -z "$dev"; then
|
2007-06-19 00:21:15 +02:00
|
|
|
xenstore-write $XENBUS_PATH/node /dev/$dev
|
|
|
|
write_dev /dev/$dev
|
|
|
|
exit 0
|
|
|
|
fi
|
2008-02-02 01:58:27 +01:00
|
|
|
|
|
|
|
exit 4
|
2007-06-19 00:21:15 +02:00
|
|
|
;;
|
2008-02-02 01:58:27 +01:00
|
|
|
|
2007-06-19 00:21:15 +02:00
|
|
|
remove)
|
|
|
|
node=`xenstore-read $XENBUS_PATH/node` || true
|
|
|
|
#node=$2
|
|
|
|
dev=$node; dev=${dev#/dev/}
|
2008-02-02 01:58:27 +01:00
|
|
|
# this is really screwy. the first delete of a lun will
|
|
|
|
# terminate the entire vport (all luns)
|
|
|
|
find_vhost_from_dev $dev
|
|
|
|
if test -z "$vhost" ; then exit 5; fi
|
|
|
|
flush_nodes_on_vhost $vhost
|
|
|
|
delete_vhost $vhost
|
2007-06-19 00:21:15 +02:00
|
|
|
exit 0
|
|
|
|
;;
|
|
|
|
esac
|