diff --git a/provisioning_scripts/fibre_channel/vfio.sh b/provisioning_scripts/fibre_channel/vfio.sh new file mode 100755 index 0000000..329892f --- /dev/null +++ b/provisioning_scripts/fibre_channel/vfio.sh @@ -0,0 +1,175 @@ +#!/bin/bash + +# Copyright 2016 IBM Corp. +# +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# +# This script manage binding\unbinding a pci device with vfio driver +# The script gets a string in form of Domain:Bus:Device.Function +# and perform requested operation according to the command line argument: +# +# -h Display help message and exit +# -l List devices binded to vfio-pci kernel driver +# -r Force a rescan of pci devices +# -u PCI_DEVICE Unbind vfio-pci and remove. PCI_DEVICE is Domain:Bus:Device string of the form "0000:00:00.0" +# -b PCI_DEVICE Bind vfio-pci. PCI_DEVICE is Domain:Bus:Device string of the form "0000:00:00.0" + +function iommu_group_devs { + INPUT_PCI_DEV=$1 + INPUT_PCI_DEV_SYSFS_PATH="/sys/bus/pci/devices/$INPUT_PCI_DEV" + if [[ ! -d $INPUT_PCI_DEV_SYSFS_PATH ]]; then + echo "There is no device: $INPUT_PCI_DEV" 1>&2 + exit 1 + fi + + if [[ ! -d "$INPUT_PCI_DEV_SYSFS_PATH/iommu/" ]]; then + echo "Check IOMMU definition." 1>&2 + echo "Use intel_iommu=on or iommu=pt iommu=1" 1>&2 + exit 1 + fi + + for pcid in $INPUT_PCI_DEV_SYSFS_PATH/iommu_group/devices/* + do + dbdf=${pcid##*/} + if [[ $(( 0x$(setpci -s $dbdf 0e.b) & 0x7f )) -eq 0 ]]; then + dev_sysfs_paths+=( ${pcid##*/} ) + fi + done + echo "${dev_sysfs_paths[@]}" +} + +function vfio_unbind { + DEV=$1 + echo "Trying to unbind: $DEV" + if [ -e /sys/bus/pci/drivers/vfio-pci/$DEV/remove ]; then + echo "Removing device: $DEV" 1>&2 + echo 1 > /sys/bus/pci/drivers/vfio-pci/$DEV/remove + else + echo "Device: $DEV not found" 1>&2 + return 1 + fi + return 0 +} + +function vfio_bind { + DEV=$1 + echo "Trying to bind: $DEV" + #/sys/bus/pci/devices/0000:20:00.0/iommu_group/devices/0000:20:00.0 + dpath="/sys/bus/pci/devices/$DEV" + echo "vfio-pci" > "$dpath/driver_override" + + if [[ -d $dpath ]]; then + curr_driver=$(readlink $dpath/driver) + curr_driver=${curr_driver##*/} + + if [[ $curr_driver == "vfio-pci" ]]; then + echo "$DEV already bound to vfio-pci" 1>&2 + continue + else + echo $DEV > "$dpath/driver/unbind" + echo "Unbound $DEV from $curr_driver" 1>&2 + fi + fi + + echo $DEV > /sys/bus/pci/drivers_probe +} + +# Usage info +show_help() { +cat << EOF +Usage: ${0##*/} [-h] [-u PCI_DEVICE] PCI_DEVICE... +This script enble binding/unbinding pci devices to vfio-pci driver + + -h Display this help and exit + -l List devices bind to vfio-pci kernel driver + -r Force a rescan of pci devices + -u PCI_DEVICE Unbind vfio-pci. PCI_DEVICE is Domain:Bus:Device string of the form "0000:00:00.0" + -b PCI_DEVICE Bind vfio-pci. PCI_DEVICE is Domain:Bus:Device string of the form "0000:00:00.0" +EOF +} + + +if [ "$#" -lt 1 ];then + echo "illegal number of arguments: $#" + show_help + exit 1 +fi + +OPTIND=1 +while getopts "hlru:b:" opt; do + options_found=1 + case "$opt" in + h) + show_help + exit 0 + ;; + l) + lspci -k | grep -i vfio-pci -B2 | grep -i fib | awk '{print $1}' + exit 0 + ;; + r) echo "Run PCI rescan" + echo 1 > /sys/bus/pci/rescan + exit $? + ;; + u) device=$OPTARG + devs="$(iommu_group_devs $device)" + if [[ -n $devs ]]; then + for dpci in $devs + do + echo "Remove device: $dpci" + vfio_unbind $dpci + if [[ $? -ne 0 ]]; then + echo "Unbind Devices error" 1>&2 + exit 1 + fi + done + exit 0 + fi + exit 1 + ;; + b) device=$OPTARG + modprobe -i vfio-pci + if [[ $? -ne 0 ]]; then + echo "Error probing vfio-pci" 1>&2 + exit 1 + fi + devs="$(iommu_group_devs $device)" + if [[ -n $devs ]]; then + for dpci in $devs + do + echo "Binding device: $dpci" + vfio_bind $dpci + if [[ $? -ne 0 ]]; then + echo "Device binding error: $dpci" + exit 1 + fi + done + exit 0 + fi + exit 1 + ;; + \?) + show_help >&2 + exit 1 + ;; + esac +done +shift "$((OPTIND-1))" # Shift off the options and optional --. + +if ((!options_found)); then + echo "no options found" + show_help +fi