From a8b31d7218749ba197e45dfa1b45e3d043f8c759 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Tue, 6 Aug 2019 14:58:26 -0400 Subject: [PATCH] import s390utils-2.6.0-15.el8 --- .gitignore | 3 + .s390utils.metadata | 3 + SOURCES/00-zipl-prepare.install | 9 + SOURCES/20-zipl-kernel.install | 175 + SOURCES/52-zipl-rescue.install | 48 + SOURCES/91-zipl.install | 15 + SOURCES/ccw.udev | 13 + SOURCES/ccw_init | 176 + SOURCES/cmsfs-1.1.8-kernel26.patch | 12 + ...filesystem-block-size-on-FBA-devices.patch | 31 + SOURCES/cmsfs-1.1.8-warnings.patch | 11 + SOURCES/dasd.udev | 16 + SOURCES/dasdconf.sh | 94 + SOURCES/device_cio_free | 313 + SOURCES/device_cio_free.service | 13 + SOURCES/normalize_dasd_arg | 120 + SOURCES/s390-tools-rhel.patch | 8406 +++++++++++++++++ SOURCES/s390-tools-zipl-fiemap.patch | 106 + ...390-tools-zipl-invert-script-options.patch | 84 + SOURCES/s390-tools-zipl-sort-like-rpm.patch | 148 + .../s390-tools-zipl-title-section-name.patch | 50 + SOURCES/zfcp.udev | 1 + SOURCES/zfcpconf.sh | 56 + SPECS/s390utils.spec | 1742 ++++ 24 files changed, 11645 insertions(+) create mode 100644 .gitignore create mode 100644 .s390utils.metadata create mode 100755 SOURCES/00-zipl-prepare.install create mode 100755 SOURCES/20-zipl-kernel.install create mode 100755 SOURCES/52-zipl-rescue.install create mode 100755 SOURCES/91-zipl.install create mode 100644 SOURCES/ccw.udev create mode 100644 SOURCES/ccw_init create mode 100644 SOURCES/cmsfs-1.1.8-kernel26.patch create mode 100644 SOURCES/cmsfs-1.1.8-use-detected-filesystem-block-size-on-FBA-devices.patch create mode 100644 SOURCES/cmsfs-1.1.8-warnings.patch create mode 100644 SOURCES/dasd.udev create mode 100644 SOURCES/dasdconf.sh create mode 100644 SOURCES/device_cio_free create mode 100644 SOURCES/device_cio_free.service create mode 100644 SOURCES/normalize_dasd_arg create mode 100644 SOURCES/s390-tools-rhel.patch create mode 100644 SOURCES/s390-tools-zipl-fiemap.patch create mode 100644 SOURCES/s390-tools-zipl-invert-script-options.patch create mode 100644 SOURCES/s390-tools-zipl-sort-like-rpm.patch create mode 100644 SOURCES/s390-tools-zipl-title-section-name.patch create mode 100644 SOURCES/zfcp.udev create mode 100644 SOURCES/zfcpconf.sh create mode 100644 SPECS/s390utils.spec diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9776127 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +SOURCES/cmsfs-1.1.8c.tar.gz +SOURCES/s390-tools-2.6.0.tar.gz +SOURCES/src_vipa-2.1.0.tar.gz diff --git a/.s390utils.metadata b/.s390utils.metadata new file mode 100644 index 0000000..cba2a76 --- /dev/null +++ b/.s390utils.metadata @@ -0,0 +1,3 @@ +9c9a4e89bddb2b4e6e09ef6fc7c2e6f2ad6316de SOURCES/cmsfs-1.1.8c.tar.gz +46a09493030c3c80987b7710e34a33462e4b90f4 SOURCES/s390-tools-2.6.0.tar.gz +8ed8592a0a9370ce8422df9231ccb17f6cf49bed SOURCES/src_vipa-2.1.0.tar.gz diff --git a/SOURCES/00-zipl-prepare.install b/SOURCES/00-zipl-prepare.install new file mode 100755 index 0000000..315b2f9 --- /dev/null +++ b/SOURCES/00-zipl-prepare.install @@ -0,0 +1,9 @@ +#!/bin/bash + +COMMAND="$1" +KERNEL_VERSION="$2" +BOOT_DIR_ABS="$3" +KERNEL_IMAGE="$4" + +# Remove it, since for zipl the images are always installed in /boot +rm -rf "${BOOT_DIR_ABS%/*}" diff --git a/SOURCES/20-zipl-kernel.install b/SOURCES/20-zipl-kernel.install new file mode 100755 index 0000000..1978b11 --- /dev/null +++ b/SOURCES/20-zipl-kernel.install @@ -0,0 +1,175 @@ +#!/bin/bash + +[[ -f /etc/sysconfig/kernel ]] && . /etc/sysconfig/kernel + +COMMAND="$1" +KERNEL_VERSION="$2" +BOOT_DIR_ABS="$3" +KERNEL_IMAGE="$4" + +KERNEL_DIR="${KERNEL_IMAGE%/*}" + +MACHINE_ID=$KERNEL_INSTALL_MACHINE_ID + +BLS_DIR="/boot/loader/entries" +ZIPLCFG="/etc/zipl.conf" +CMDLINE_LINUX_DEBUG=" systemd.log_level=debug systemd.log_target=kmsg" +LINUX_DEBUG_VERSION_POSTFIX="_with_debugging" +LINUX_DEBUG_TITLE_POSTFIX=" with debugging" + +mkbls() { + local kernelver=$1 && shift + local datetime=$1 && shift + local kernelopts=$1 && shift + + local debugname="" + local flavor="" + + if [[ "$kernelver" == *\+* ]] ; then + local flavor=-"${kernelver##*+}" + if [[ "${flavor}" == "-debug" ]]; then + local debugname=" with debugging" + local debugid="-debug" + fi + fi + + cat </dev/null && \ + restorecon -R "/boot/${i##*/}-${KERNEL_VERSION}" + done + # hmac is .vmlinuz-.hmac so needs a special treatment + i="$KERNEL_DIR/.${KERNEL_IMAGE##*/}.hmac" + if [[ -e "$i" ]]; then + cp -a "$i" "/boot/.${KERNEL_IMAGE##*/}-${KERNEL_VERSION}.hmac" + command -v restorecon &>/dev/null && \ + restorecon "/boot/.${KERNEL_IMAGE##*/}-${KERNEL_VERSION}.hmac" + fi + fi + + if [[ ! -f /sbin/new-kernel-pkg ]]; then + declare -a BOOT_OPTIONS + if [[ -f /etc/kernel/cmdline ]]; then + read -r -d '' -a BOOT_OPTIONS < /etc/kernel/cmdline + fi + + if ! [[ ${BOOT_OPTIONS[*]} ]]; then + read -r -d '' -a line < /proc/cmdline + for i in "${line[@]}"; do + [[ "${i#initrd=*}" != "$i" ]] && continue + BOOT_OPTIONS+=("$i") + done + fi + + if ! [[ ${BOOT_OPTIONS[*]} ]]; then + echo "Could not determine the kernel command line parameters." >&2 + echo "Please specify the kernel command line in /etc/kernel/cmdline!" >&2 + exit 1 + fi + + [[ -d "$BLS_DIR" ]] || mkdir -m 0700 -p "$BLS_DIR" + BLS_TARGET="${BLS_DIR}/${MACHINE_ID}-${KERNEL_VERSION}.conf" + if [[ -f "${KERNEL_DIR}/bls.conf" ]]; then + cp -aT "${KERNEL_DIR}/bls.conf" "${BLS_TARGET}" || exit $? + sed -i -e "s,^linux.*,linux /boot/vmlinuz-${KERNEL_VERSION},g" "${BLS_TARGET}" + sed -i -e "s,^initrd.*,initrd /boot/initramfs-${KERNEL_VERSION}.img,g" "${BLS_TARGET}" + sed -i -e "s#^options.*#options ${BOOT_OPTIONS[*]}#g" "${BLS_TARGET}" + else + mkbls "${KERNEL_VERSION}" \ + "$(date -u +%Y%m%d%H%M%S -d "$(stat -c '%y' "${KERNEL_DIR}")")" \ + "${BOOT_OPTIONS[*]}" >"${BLS_TARGET}" + fi + + if [[ "$KERNEL_VERSION" == *\+* ]] && [ "x$DEFAULTDEBUG" != "xyes" ]; then + UPDATEDEFAULT="no" + fi + + if [[ "x$UPDATEDEFAULT" = "xyes" ]]; then + TITLE="$(grep '^title[ \t]' "${BLS_TARGET}" | sed -e 's/^title[ \t]*//')" + NEWDEFAULT="${TITLE}" + fi + + if [ "x${MAKEDEBUG}" = "xyes" ]; then + BLS_DEBUG="$(echo ${BLS_TARGET} | sed -e "s/${KERNEL_VERSION}/${KERNEL_VERSION}~debug/")" + cp -aT "${BLS_TARGET}" "${BLS_DEBUG}" + TITLE="$(grep '^title[ \t]' "${BLS_DEBUG}" | sed -e 's/^title[ \t]*//')" + VERSION="$(grep '^version[ \t]' "${BLS_DEBUG}" | sed -e 's/^version[ \t]*//')" + BLSID="$(grep '^id[ \t]' "${BLS_DEBUG}" | sed -e "s/${KERNEL_VERSION}/${KERNEL_VERSION}~debug/")" + sed -i -e "s/^title.*/title ${TITLE}${LINUX_DEBUG_TITLE_POSTFIX}/" "${BLS_DEBUG}" + sed -i -e "s/^version.*/version ${VERSION}${LINUX_DEBUG_VERSION_POSTFIX}/" "${BLS_DEBUG}" + sed -i -e "s/^id.*/${BLSID}/" "${BLS_DEBUG}" + sed -i -e "s#^options.*#options ${BOOT_OPTIONS[*]}${CMDLINE_LINUX_DEBUG}#" "${BLS_DEBUG}" + if [ -n "$NEWDEFAULT" -a "x$DEFAULTDEBUG" = "xyes" ]; then + TITLE="$(grep '^title[ \t]' "${BLS_DEBUG}" | sed -e 's/^title[ \t]*//')" + NEWDEFAULT="${TITLE}" + fi + fi + + if [ -n "$NEWDEFAULT" ]; then + sed -i -e "s,^default=.*,default=${NEWDEFAULT}," "${ZIPLCFG}" + fi + + exit 0 + fi + + /sbin/new-kernel-pkg --package "kernel${flavor}" --install "$KERNEL_VERSION" || exit $? + /sbin/new-kernel-pkg --package "kernel${flavor}" --mkinitrd --dracut --depmod --update "$KERNEL_VERSION" || exit $? + /sbin/new-kernel-pkg --package "kernel${flavor}" --rpmposttrans "$KERNEL_VERSION" || exit $? + # If grubby is used there's no need to run other installation plugins + exit 77 + ;; + remove) + if [[ ! -f /sbin/new-kernel-pkg ]]; then + ARCH="$(uname -m)" + BLS_TARGET="${BLS_DIR}/${MACHINE_ID}-${KERNEL_VERSION}.conf" + BLS_DEBUG="$(echo ${BLS_TARGET} | sed -e "s/${KERNEL_VERSION}/${KERNEL_VERSION}~debug/")" + + TITLE="$(grep '^title[ \t]' "${BLS_TARGET}" | sed -e 's/^title[ \t]*//')" + sed -i -e "/^default=${TITLE}/d" "${ZIPLCFG}" + + if [[ -f "${BLS_DEBUG}" ]]; then + TITLE="$(grep '^title[ \t]' "${BLS_DEBUG}" | sed -e 's/^title[ \t]*//')" + sed -i -e "/^default=${TITLE}/d" "${ZIPLCFG}" + fi + + rm -f "${BLS_TARGET}" "${BLS_DEBUG}" + + for i in vmlinuz System.map config zImage.stub dtb; do + rm -rf "/boot/${i}-${KERNEL_VERSION}" + done + # hmac is .vmlinuz-.hmac so needs a special treatment + rm -f "/boot/.vmlinuz-${KERNEL_VERSION}.hmac" + + exit 0 + fi + + /sbin/new-kernel-pkg --package "kernel${flavor+-$flavor}" --rminitrd --rmmoddep --remove "$KERNEL_VERSION" || exit $? + # If grubby is used there's no need to run other installation plugins + exit 77 + ;; + *) + ;; +esac diff --git a/SOURCES/52-zipl-rescue.install b/SOURCES/52-zipl-rescue.install new file mode 100755 index 0000000..a2945f7 --- /dev/null +++ b/SOURCES/52-zipl-rescue.install @@ -0,0 +1,48 @@ +#!/bin/bash + +[[ -f /etc/os-release ]] && . /etc/os-release +[[ -f /etc/sysconfig/kernel ]] && . /etc/sysconfig/kernel + +COMMAND="$1" +KERNEL_VERSION="$2" +BOOT_DIR_ABS="$3" +KERNEL_IMAGE="$4" + +MACHINE_ID=$KERNEL_INSTALL_MACHINE_ID + +BLS_DIR="/boot/loader/entries" + +[[ "$KERNEL_VERSION" == *\+* ]] && flavor=-"${KERNEL_VERSION##*+}" +case "$COMMAND" in + add) + if [[ ! -f /sbin/new-kernel-pkg ]]; then + declare -a BOOT_OPTIONS + if [[ -f /etc/kernel/cmdline ]]; then + read -r -d '' -a BOOT_OPTIONS < /etc/kernel/cmdline + fi + + if ! [[ ${BOOT_OPTIONS[*]} ]]; then + read -r -d '' -a line < /proc/cmdline + for i in "${line[@]}"; do + [[ "${i#initrd=*}" != "$i" ]] && continue + BOOT_OPTIONS+=("$i") + done + fi + + if ! [[ ${BOOT_OPTIONS[*]} ]]; then + echo "Could not determine the kernel command line parameters." >&2 + echo "Please specify the kernel command line in /etc/kernel/cmdline!" >&2 + exit 1 + fi + + BLS_RESCUE="${BLS_DIR}/${MACHINE_ID}-0-rescue.conf" + if [[ -f "${BLS_RESCUE}" ]] && grep -q '^options.*$kernelopts' "${BLS_RESCUE}"; then + sed -i -e "s,^linux.*,linux /boot/vmlinuz-0-rescue-${MACHINE_ID},g" "${BLS_RESCUE}" + sed -i -e "s,^initrd.*,initrd /boot/initramfs-0-rescue-${MACHINE_ID}.img,g" "${BLS_RESCUE}" + sed -i -e "s#^options.*#options ${BOOT_OPTIONS[*]}#g" "${BLS_RESCUE}" + fi + fi + ;; + *) + ;; +esac diff --git a/SOURCES/91-zipl.install b/SOURCES/91-zipl.install new file mode 100755 index 0000000..6205638 --- /dev/null +++ b/SOURCES/91-zipl.install @@ -0,0 +1,15 @@ +#!/bin/bash + +if [[ ! -f /etc/zipl.conf ]]; then + exit 0 +fi + +COMMAND="$1" + +case "$COMMAND" in + add|remove) + zipl > /dev/null + ;; + *) + ;; +esac diff --git a/SOURCES/ccw.udev b/SOURCES/ccw.udev new file mode 100644 index 0000000..a12ad05 --- /dev/null +++ b/SOURCES/ccw.udev @@ -0,0 +1,13 @@ +ACTION!="add|change", GOTO="ccw_end" +SUBSYSTEM!="ccw", GOTO="ccw_end" +ATTRS{cutype}=="1731/01", RUN+="ccw_init" +ATTRS{cutype}=="1731/02", RUN+="ccw_init" +ATTRS{cutype}=="1731/05", RUN+="ccw_init" +ATTRS{cutype}=="1731/06", RUN+="ccw_init" +ATTRS{cutype}=="3088/01", RUN+="ccw_init" +ATTRS{cutype}=="3088/08", RUN+="ccw_init" +ATTRS{cutype}=="3088/60", RUN+="ccw_init" +ATTRS{cutype}=="3088/61", RUN+="ccw_init" +ATTRS{cutype}=="3088/1e", RUN+="ccw_init" +ATTRS{cutype}=="3088/1f", RUN+="ccw_init" +LABEL="ccw_end" diff --git a/SOURCES/ccw_init b/SOURCES/ccw_init new file mode 100644 index 0000000..a691ae0 --- /dev/null +++ b/SOURCES/ccw_init @@ -0,0 +1,176 @@ +#! /bin/sh + +[ -z "$DEVPATH" ] && exit 0 +[ "$SUBSYSTEM" != "ccw" ] && exit 0 + +[ -e /etc/ccw.conf ] && MODE="dracut" || MODE="normal" +OLD_IFS="$IFS" + +get_config_line_by_subchannel() +{ + local CHANNEL + CHANNEL="$1" + while read line; do + IFS="," + set $line + IFS="$OLD_IFS" + for i in $@; do + if [ "$CHANNEL" = "$i" ]; then + echo $line + return 0 + fi + done + done < /etc/ccw.conf + return 1 +} + +CHANNEL=${DEVPATH##*/} + +if [ $MODE = "dracut" ]; then + CONFIG_LINE=$(get_config_line_by_subchannel $CHANNEL) + + [ $? -ne 0 -o -z "$CONFIG_LINE" ] && break + + IFS="," + set $CONFIG_LINE + IFS="$OLD_IFS" + NETTYPE=$1 + shift + SUBCHANNELS="$1" + OPTIONS="" + shift + while [ $# -gt 0 ]; do + case $1 in + *=*) OPTIONS="$OPTIONS $1";; + [0-9]*) SUBCHANNELS="$SUBCHANNELS,$1";; + esac + shift + done +elif [ $MODE = "normal" ]; then + NOLOCALE="yes" + + . /etc/sysconfig/network-scripts/network-functions + + CONFIG_FILE=$(get_config_by_subchannel $CHANNEL) + + if [ -n "$CONFIG_FILE" ]; then + . $CONFIG_FILE + else + exit 1 + fi +else + echo "Unknown mode=$MODE" + exit 1 +fi + + +# now we have extracted these variables from the config files: +# SUBCHANNELS +# OPTIONS + +# put LAYER2 option into its own variable +set $OPTIONS +OPTIONS="" +while [ $# -gt 0 ]; do + case $1 in + layer2=*) LAYER2=${1##layer2=};; + *=*) OPTIONS="$OPTIONS $1";; + esac + shift +done + +# translate variables from the interface config files to OPTIONS +if [ -n "$PORTNAME" ]; then + if [ "$NETTYPE" = "lcs" ]; then + OPTIONS="$OPTIONS portno=$PORTNAME" + else + OPTIONS="$OPTIONS portname=$PORTNAME" + fi +fi +if [ "$NETTYPE" = "ctc" -a -n "$CTCPROT" ]; then + OPTIONS="$OPTIONS protocol=$CTCPROT" +fi + +# SUBCHANNELS is only set on mainframe ccwgroup devices +[ -z "$SUBCHANNELS" -o -z "$NETTYPE" ] && exit 0 +if [ "$NETTYPE" = "ctc" ]; then + DIR="/sys/bus/ccwgroup/drivers/ctcm" +else + DIR="/sys/bus/ccwgroup/drivers/$NETTYPE" +fi + +i=0 +while [ $i -lt 20 ]; do + [ -e $DIR ] && break + sleep 0.1 + i=$(($i+1)) +done + +# driver missing or not loaded +[ ! -e $DIR ] && exit 0 + +IFS="," +set $SUBCHANNELS +IFS="$OLD_IFS" +CHANNEL1=$1 +CHANNEL2=$2 +SYSDIR="$DIR/$CHANNEL1" + +[ -e $SYSDIR ] && exit 0 + +# check if the interface is already online +if [ -e $SYSDIR/online ]; then + read on <$SYSDIR/online + [ "$on" = "1" ] && exit 0 +fi + +DRIVER=$(readlink $DEVPATH/driver) +DRIVER=${DRIVER##*/} +if [ "$DRIVER" = "lcs" -a "$NETTYPE" = "ctc" ]; then + echo "$CHANNEL" > /sys/bus/ccw/drivers/lcs/unbind + echo "$CHANNEL" > /sys/bus/ccw/drivers/ctcm/bind + echo "$CHANNEL2" > /sys/bus/ccw/drivers/lcs/unbind + echo "$CHANNEL2" > /sys/bus/ccw/drivers/ctcm/bind +fi +if [ "$DRIVER" = "ctcm" -a "$NETTYPE" = "lcs" ]; then + echo "$CHANNEL" > /sys/bus/ccw/drivers/ctcm/unbind + echo "$CHANNEL" > /sys/bus/ccw/drivers/lcs/bind + echo "$CHANNEL2" > /sys/bus/ccw/drivers/ctcm/unbind + echo "$CHANNEL2" > /sys/bus/ccw/drivers/lcs/bind +fi + +if [ ! -e $SYSDIR ]; then + echo "$SUBCHANNELS" > $DIR/group + i=0 + while [ $i -lt 20 ]; do + [ -e $SYSDIR ] && break + sleep 0.1 + i=$(($i+1)) + done + + [ ! -e $SYSDIR ] && exit 1 +fi + +# check if the interface is already online +if [ -e $SYSDIR/online ]; then + read on <$SYSDIR/online + [ "$on" = "1" ] && exit 0 +fi + +# first set layer2, other options may depend on it +[ -n "$LAYER2" ] && echo $LAYER2 > $SYSDIR/layer2 + +if [ -n "$OPTIONS" ]; then + for i in $OPTIONS; do + OPT=${i%%=*} + VAL=${i##*=} + if [ -e "$SYSDIR/$OPT" ]; then + echo "$VAL" > "$SYSDIR/$OPT" || \ + echo "Could not set value \"$VAL\" for OPTION \"$OPT\" with SUBCHANNELS \"$SUBCHANNELS\"" + else + echo "OPTION \"$OPT\" does not exist for SUBCHANNELS \"$SUBCHANNELS\"" + fi + done +fi + +[ -e $SYSDIR/online ] && echo 1 > $SYSDIR/online diff --git a/SOURCES/cmsfs-1.1.8-kernel26.patch b/SOURCES/cmsfs-1.1.8-kernel26.patch new file mode 100644 index 0000000..c045827 --- /dev/null +++ b/SOURCES/cmsfs-1.1.8-kernel26.patch @@ -0,0 +1,12 @@ +diff -urN cmsfs-1.1.8/cmsfssed.sh cmsfs-1.1.8_/cmsfssed.sh +--- cmsfs-1.1.8/cmsfssed.sh 2003-02-28 17:52:59.000000000 -0500 ++++ cmsfs-1.1.8_/cmsfssed.sh 2004-05-28 16:36:22.000000000 -0400 +@@ -85,7 +85,7 @@ + DRIVER_SOURCE="cmsfs22x.c" + MODULES_DIRECTORY="/lib/modules/`uname -r`/fs" + ;; +- 2.4*|2.5*) ++ 2.4*|2.5*|2.6*|3.*|4.*) + LINUX_RELEASE="2.4" + # ln -s cmsfs24x.c cmsfsvfs.c + INCLUDES="-I/lib/modules/`uname -r`/build/include" diff --git a/SOURCES/cmsfs-1.1.8-use-detected-filesystem-block-size-on-FBA-devices.patch b/SOURCES/cmsfs-1.1.8-use-detected-filesystem-block-size-on-FBA-devices.patch new file mode 100644 index 0000000..275d371 --- /dev/null +++ b/SOURCES/cmsfs-1.1.8-use-detected-filesystem-block-size-on-FBA-devices.patch @@ -0,0 +1,31 @@ +From 25442f958a12b428b7d063b927ac48965dcd8164 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Dan=20Hor=C3=A1k?= +Date: Fri, 28 Jan 2011 16:11:19 +0100 +Subject: [PATCH] use detected filesystem block size on FBA devices + +If a FBA device is not properly formated, then the CMS file system can +have a different block size. The cmsfs tools were able to detect the file +system block size, but in fact they still used default 512 instead. And +using the default was causing crashes. Now the detected value is used. + +https://bugzilla.redhat.com/show_bug.cgi?id=651012 +--- + cmsfsany.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/cmsfsany.c b/cmsfsany.c +index 55bcfdc..18efffb 100644 +--- a/cmsfsany.c ++++ b/cmsfsany.c +@@ -102,7 +102,7 @@ int cmsfs_find_label(struct CMSSUPER *vol,struct CMSFSADT *adt) + cmsfs_error(cmsfs_ermsg); + } + vol->flags = CMSFSFBA; +- vol->blksz = 512; ++ vol->blksz = blksz; + return vol->blksz; + } } + +-- +1.7.3.5 + diff --git a/SOURCES/cmsfs-1.1.8-warnings.patch b/SOURCES/cmsfs-1.1.8-warnings.patch new file mode 100644 index 0000000..cb1501d --- /dev/null +++ b/SOURCES/cmsfs-1.1.8-warnings.patch @@ -0,0 +1,11 @@ +--- cmsfs-1.1.8/cmsfsvol.c.warnings 2003-07-18 01:38:57.000000000 +0200 ++++ cmsfs-1.1.8/cmsfsvol.c 2005-09-06 16:57:15.000000000 +0200 +@@ -52,7 +52,7 @@ + + /* print a header; looks like CMS */ + (void) printf("LABEL VDEV M STAT CYL TYPE \ +-BLKSZ FILES BLKS USED-(%) BLKS LEFT BLK TOTAL\n"); ++BLKSZ FILES BLKS USED-(%%) BLKS LEFT BLK TOTAL\n"); + + for ( ; i < argc ; i++) + { diff --git a/SOURCES/dasd.udev b/SOURCES/dasd.udev new file mode 100644 index 0000000..5364935 --- /dev/null +++ b/SOURCES/dasd.udev @@ -0,0 +1,16 @@ +ACTION=="add", SUBSYSTEM=="drivers", KERNEL=="dasd-eckd", RUN+="/sbin/dasdconf.sh" +ACTION=="add", SUBSYSTEM=="drivers", KERNEL=="dasd-fba", RUN+="/sbin/dasdconf.sh" + +# This list should be autogenerated with "modinfo dasd_{eckd,fba}_mod" +ACTION=="add", SUBSYSTEM=="ccw", ATTR{modalias}=="ccw:t1750m*dt3380dm*", RUN+="/sbin/dasdconf.sh" +ACTION=="add", SUBSYSTEM=="ccw", ATTR{modalias}=="ccw:t1750m*dt3390dm*", RUN+="/sbin/dasdconf.sh" +ACTION=="add", SUBSYSTEM=="ccw", ATTR{modalias}=="ccw:t2107m*dt3380dm*", RUN+="/sbin/dasdconf.sh" +ACTION=="add", SUBSYSTEM=="ccw", ATTR{modalias}=="ccw:t2107m*dt3390dm*", RUN+="/sbin/dasdconf.sh" +ACTION=="add", SUBSYSTEM=="ccw", ATTR{modalias}=="ccw:t9343m*dt9345dm*", RUN+="/sbin/dasdconf.sh" +ACTION=="add", SUBSYSTEM=="ccw", ATTR{modalias}=="ccw:t2105m*dt3380dm*", RUN+="/sbin/dasdconf.sh" +ACTION=="add", SUBSYSTEM=="ccw", ATTR{modalias}=="ccw:t3990m*dt3380dm*", RUN+="/sbin/dasdconf.sh" +ACTION=="add", SUBSYSTEM=="ccw", ATTR{modalias}=="ccw:t3880m*dt3390dm*", RUN+="/sbin/dasdconf.sh" +ACTION=="add", SUBSYSTEM=="ccw", ATTR{modalias}=="ccw:t2105m*dt3390dm*", RUN+="/sbin/dasdconf.sh" +ACTION=="add", SUBSYSTEM=="ccw", ATTR{modalias}=="ccw:t3990m*dt3390dm*", RUN+="/sbin/dasdconf.sh" +ACTION=="add", SUBSYSTEM=="ccw", ATTR{modalias}=="ccw:t3880m*dt3370dm*", RUN+="/sbin/dasdconf.sh" +ACTION=="add", SUBSYSTEM=="ccw", ATTR{modalias}=="ccw:t6310m*dt9336dm*", RUN+="/sbin/dasdconf.sh" diff --git a/SOURCES/dasdconf.sh b/SOURCES/dasdconf.sh new file mode 100644 index 0000000..2be5276 --- /dev/null +++ b/SOURCES/dasdconf.sh @@ -0,0 +1,94 @@ +#!/bin/sh + +# config file syntax: +# deviceno sysfs_opts... +# +# Examples: +# 0.0.0203 readonly=1 failfast=1 +# 0.0.0204 +# 0.0.0205 erplog=1 + +[ -z "$DEVPATH" ] && exit 0 +[ "$ACTION" != "add" ] && exit 0 + +CHANNEL=${DEVPATH##*/} + +CONFIG=/etc/dasd.conf +PATH=/sbin:/bin +export PATH + +warn() { + [ -e /dev/kmsg ] && echo "<4>dasdconf.sh Warning: $@" > /dev/kmsg + echo "dasdconf.sh Warning: $@" >&2 +} + +if [ -f "$CONFIG" ]; then + if [ ! -d /sys/bus/ccw/drivers/dasd-eckd ] && [ ! -d /sys/bus/ccw/drivers/dasd-fba ]; then + #warn "No dasd-eckd or dasd-eckd loaded" + exit 0 + fi + sed 'y/ABCDEF/abcdef/' < $CONFIG | while read line; do + case $line in + \#*) ;; + *) + [ -z "$line" ] && continue + set $line + + # if we are in single add mode, only add the new CHANNEL + [ "$SUBSYSTEM" = "ccw" ] && [ "$1" != "$CHANNEL" ] && continue + + DEVICE=$1 + SYSFSPATH= + + if [ -r "/sys/bus/ccw/drivers/dasd-eckd/$DEVICE" ]; then + SYSFSPATH="/sys/bus/ccw/drivers/dasd-eckd/$DEVICE" + elif [ -r "/sys/bus/ccw/drivers/dasd-fba/$DEVICE" ]; then + SYSFSPATH="/sys/bus/ccw/drivers/dasd-fba/$DEVICE" + else + # if we are in single add mode, this is a failure! + [ "$SUBSYSTEM" = "ccw" ] && warn "Could not find $DEVICE in sysfs" + continue + fi + + # skip already onlined devices + if [ "$(cat $SYSFSPATH/online)" = "1" ]; then + if [ "$SUBSYSTEM" = "ccw" ]; then + # if we are in single add mode, we should not touch the device + warn "$DEVICE is already online, not configuring" + exit 0 + fi + continue + fi + + shift + while [ -n "$1" ]; do + ( + attribute="$1" + IFS="=" + set $attribute + + if [ "$1" = "use_diag" ]; then + # this module better only returns after + # all sysfs entries have the "use_diag" file + modprobe dasd_diag_mod + fi + + if [ -r "$SYSFSPATH/$1" ]; then + echo $2 > $SYSFSPATH/$1 || warn "Could not set $1=$2 for $DEVICE" + else + warn "$1 does not exist for $DEVICE" + fi + ) + shift + done + + # Now, put the device online + echo 1 > $SYSFSPATH/online || echo "Could not activate $DEVICE" + + # if we are in single add mode, we are done + [ "$SUBSYSTEM" = "ccw" ] && exit 0 + ;; + esac + done +fi +exit 0 diff --git a/SOURCES/device_cio_free b/SOURCES/device_cio_free new file mode 100644 index 0000000..cd2b21f --- /dev/null +++ b/SOURCES/device_cio_free @@ -0,0 +1,313 @@ +#!/bin/sh +# +# Copyright 2009, 2010 Red Hat, Inc. +# License: GPLv2 +# Author: Dan Horák +# +# unblock devices listed in various config files and wait until they are ready +# +# it uses dasd and zfcp config file +# config file syntax: +# deviceno options +# or +# deviceno WWPN FCPLUN +# +# also processes the system ccw config file and network interface configurations +# +# requires: echo, sleep, modprobe, grep, printf, sed. +# +# it is used in +# anaconda +# dracut generated initramfs +# normal system startup driven by upstart +# + +DASDCONFIG=/etc/dasd.conf +ZFCPCONFIG=/etc/zfcp.conf +ZNETCONFIG=/etc/ccw.conf +BLACKLIST=/proc/cio_ignore +CIO_SETTLE=/proc/cio_settle +VERBOSE= +PATH=/bin:/sbin +DEVICE= # list of devices given on command line +ALL_DEVICES= # list of all unblocked devices +WAITING_TIMEOUT=60 # maximum time to wait for all devices to appear +WAITING_TOTAL=0 # actual time spent waiting for devices + +usage() +{ + echo "Usage: $CMD [-h|--help] [-V|--verbose] [-d|--device ]" + echo " -h|--help print this message" + echo " -V|--verbose be verbose" + echo " -d|--device unblock and wait for specified device" + exit 1 +} + +# accepts single device, comma-separated lists and dash separated ranges and their combinations +# the comma separated list is split so we minimize the effect of unsuccessful freeing +free_device() +{ + local DEV DEV_LIST + + [ -z "$1" ] && return + + DEV_LIST=$(echo "$1" | sed 'y/ABCDEF/abcdef/' | sed 's/,/ /g') + + for DEV in $DEV_LIST; do + [ $VERBOSE ] && echo "Freeing device(s) $DEV" + if ! echo "free $DEV" > $BLACKLIST 2> /dev/null ; then + echo "Error: can't free device(s) $DEV" + else + if [ -z $ALL_DEVICES ]; then + ALL_DEVICES="$DEV" + else + ALL_DEVICES="$ALL_DEVICES,$DEV" + fi + fi + done +} + +# wait until a device appears on the ccw bus +wait_on_single_device() +{ + local DEVICE_ONLINE DEV + + [ -z "$1" ] && return + + DEV="$1" + DEVICE_ONLINE="/sys/bus/ccw/devices/$DEV/online" + + [ $VERBOSE ] && echo "Waiting on device $DEV" + [ -f "$DEVICE_ONLINE" ] && return + + for t in 1 2 3 4 5 + do + if [ $WAITING_TOTAL -ge $WAITING_TIMEOUT ]; then + [ $VERBOSE ] && echo "Waiting timeout of $WAITING_TIMEOUT seconds reached" + break + fi + WAITING_TOTAL=$(($WAITING_TOTAL + $t)) + [ $VERBOSE ] && echo "Waiting additional $t second(s) and $WAITING_TOTAL second(s) in total" + sleep $t + [ -f "$DEVICE_ONLINE" ] && return + done + echo "Error: device $DEV still not ready" +} + +# wait until recently unblocked devices are ready +# at this point we know the content of ALL_DEVICES is syntacticly correct +wait_on_devices() +{ + if [ -w $CIO_SETTLE ]; then + [ $VERBOSE ] && echo "Waiting until all pending CIO requests are processed" + echo 1 > $CIO_SETTLE + return + fi + + OLD_IFS=$IFS + IFS="," + set $ALL_DEVICES + for DEV in $* + do + IFS="." + + # get the lower bound for range or get the single device + LOWER=${DEV%%-*} + set $LOWER + if [ $# -eq 1 ]; then + L0=0 + L1=0 + L2=$(printf "%d" "0x$1") + else + L0=$(printf "%d" "0x$1") + L1=$(printf "%d" "0x$2") + L2=$(printf "%d" "0x$3") + fi + + # get the upper bound for range or get the single device + UPPER=${DEV##*-} + set $UPPER + if [ $# -eq 1 ]; then + U0=0 + U1=0 + U2=$(printf "%d" "0x$1") + else + U0=$(printf "%d" "0x$1") + U1=$(printf "%d" "0x$2") + U2=$(printf "%d" "0x$3") + fi + + IFS=$OLD_IFS + + # iterate thru all devices + i=$L0 + while [ $i -le $U0 ]; do + [ $i -eq $L0 ] && LJ=$L1 || LJ=0 + [ $i -eq $U0 ] && UJ=$U1 || UJ=3 + + j=$LJ + while [ $j -le $UJ ]; do + [ $i -eq $L0 -a $j -eq $L1 ] && LK=$L2 || LK=0 + [ $i -eq $U0 -a $j -eq $U1 ] && UK=$U2 || UK=65535 + + k=$LK + while [ $k -le $UK ]; do + wait_on_single_device "$(printf %x.%x.%04x $i $j $k)" + k=$(($k + 1)) + done + j=$(($j + 1)) + done + i=$(($i + 1)) + done + done +} + +process_config_file() +{ + local CONFIG + + [ -z "$1" ] && return + + CONFIG="$1" + if [ -f "$CONFIG" ]; then + while read line; do + case $line in + \#*) ;; + *) + [ -z "$line" ] && continue + set $line + free_device $1 + ;; + esac + done < "$CONFIG" + fi +} + +# check how we were called +CMD=${0##*/} +DIR=${0%/*} +ARGS=$@ +case $CMD in + "dasd_cio_free") + MODE_DASD="yes" + ;; + "zfcp_cio_free") + MODE_ZFCP="yes" + ;; + "znet_cio_free") + MODE_ZNET="yes" + ;; + "device_cio_free") + MODE_DASD="yes" + MODE_ZFCP="yes" + MODE_ZNET="yes" + ;; + *) + echo "Error: unknown alias '$CMD'." + echo "Supported aliases are dasd_cio_free, zfcp_cio_free and znet_cio_free." + exit 1 + ;; +esac + +# process command line options +while [ $# -gt 0 ]; do + case $1 in + -V|--verbose) + VERBOSE=yes + ;; + -h|--help) + usage + ;; + -d|--device) + shift + if [ "$1" ]; then + if [ "$DEVICE" ]; then + DEVICE="$DEVICE,$1" + else + DEVICE=$1 + fi + else + echo "Error: no device given" + usage + fi + ;; + *) + echo "Error: unknown option $1" + usage + ;; + esac + shift +done + +if [ ! -f $BLACKLIST ]; then + echo "Error: $BLACKLIST kernel interface doesn't exist" + exit 2 +fi + +if [ "$DEVICE" ]; then + [ $VERBOSE ] && echo "Freeing specific devices" + free_device $DEVICE + wait_on_devices + udevadm settle + exit 0 +fi + +if [ $VERBOSE ]; then + echo -n "Freeing devices:" + [ $MODE_DASD ] && echo -n " dasd" + [ $MODE_ZFCP ] && echo -n " zfcp" + [ $MODE_ZNET ] && echo -n " znet" + echo +fi + +[ $MODE_DASD ] && process_config_file $DASDCONFIG +[ $MODE_ZFCP ] && process_config_file $ZFCPCONFIG + +if [ $MODE_DASD ]; then + # process the device list defined as option for the dasd module + DEVICES=$(modprobe --showconfig | LANG=C grep "options[[:space:]]\+dasd_mod" | \ + sed -e 's/.*[[:space:]]dasd=\([^[:space:]]*\).*/\1/' -e 's/([^)]*)//g' \ + -e 's/nopav\|nofcx\|autodetect\|probeonly//g' -e 's/,,/,/g' -e 's/^,//' -e 's/,$//') + + for DEVRANGE in $(echo $DEVICES | sed 's/,/ /g'); do + free_device $DEVRANGE + done +fi + +if [ $MODE_ZNET ]; then + # process the config file + if [ -f "$ZNETCONFIG" ]; then + while read line; do + case $line in + \#*) ;; + *) + [ -z "$line" ] && continue + # grep 2 or 3 channels from each ",," line + DEVICES=$(echo $line | LANG=C grep -E -i -o "([0-9]\.[0-9]\.[a-f0-9]+,){1,2}([0-9]\.[0-9]\.[a-f0-9]+)") + free_device $DEVICES + ;; + esac + done < "$ZNETCONFIG" + fi + # process channels from network interface configurations + if [ -z "$__sed_discard_ignored_files" ]; then + if [ -f /etc/init.d/functions ]; then + . /etc/init.d/functions + else + # default value copied from initscripts 9.03.10 + __sed_discard_ignored_files='/\(~\|\.bak\|\.orig\|\.rpmnew\|\.rpmorig\|\.rpmsave\)$/d' + fi + fi + for line in $(LANG=C grep -E -i -h \ + "^[[:space:]]*SUBCHANNELS=['\"]?([0-9]\.[0-9]\.[a-f0-9]+,){1,2}([0-9]\.[0-9]\.[a-f0-9]+)['\"]?([[:space:]]+#|[[:space:]]*$)" \ + $( (ls /etc/sysconfig/network-scripts/ifcfg-* 2> /dev/null || echo "__no_config_file") | \ + LC_ALL=C sed -e "$__sed_discard_ignored_files") 2> /dev/null) + do + eval "$line" + free_device $SUBCHANNELS + done +fi + +[ -z "$ALL_DEVICES" ] && exit 0 + +wait_on_devices diff --git a/SOURCES/device_cio_free.service b/SOURCES/device_cio_free.service new file mode 100644 index 0000000..07a57f5 --- /dev/null +++ b/SOURCES/device_cio_free.service @@ -0,0 +1,13 @@ +[Unit] +Description=Free all devices on startup +DefaultDependencies=no +Before=sysinit.target + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/sbin/device_cio_free +StandardOutput=syslog + +[Install] +WantedBy=sysinit.target diff --git a/SOURCES/normalize_dasd_arg b/SOURCES/normalize_dasd_arg new file mode 100644 index 0000000..3e7afa6 --- /dev/null +++ b/SOURCES/normalize_dasd_arg @@ -0,0 +1,120 @@ +#!/bin/sh +# +# Copyright 2012 Red Hat, Inc. +# License: GPLv2 +# Author: Jesse Keating +# +# Normalize DASD data into valid dasd.conf format +# +# Standard input should be the DASD argument +# Standard otuput is the properly formatted content +# +# it is used in +# dracut generated initramfs +# +# Much of this code was salvaged from linuxrc.s390 from Anaconda: +# +# License GPLv2+ +# +# Copyright (C) 2000-2004 by +# Bernhard Rosenkraenzer +# Oliver Paukstadt +# Karsten Hopp +# Florian La Roche +# Nils Philippsen +# Helge Deller +# David Sainty +# Copyright (C) IBM Corp. 2008,2009 +# Author: Steffen Maier + + +function canonicalize_devno() +{ + case ${#1} in + 3) echo "0.0.0${1}" ;; + 4) echo "0.0.${1}" ;; + *) echo "${1}" ;; + esac + return 0 +} + +read DASD +# See if we've gotten a format like ,feature or ,, +[[ "$DASD" =~ (\,*=[[:digit:]]) ]] +case $? in + # case of 0 is features, just turn the comma into a space + 0) echo $DASD |sed 's/,/ /g';; + *) # We've got no features, do things normally + for dasditem in $(echo $DASD |sed 's/,/ /g') + do + unset range features lo hi attrs devno lodevno hidevno devbusid sys + case $dasditem in + autodetect|probeonly|nopav|nofcx|"") continue ;; # these don't gen a config + *) + IFS='(' + read range features <<< "$dasditem" + unset IFS + lo=${range%%-*} + [[ "$lo" =~ (^[[:xdigit:]]+\.[0-3]\.[[:xdigit:]]{4}$)|(^[[:xdigit:]]{3,4}$) ]] + case $? in + 0) # string matched the pattern + lo=$(canonicalize_devno $lo) ;; + 1) # string did not match the pattern + echo $"Incorrect format for lower bound of DASD range $range: $lo" 1>&2 + exit 1 + ;; + 2) echo "l.$LINENO: syntax error in regex of match operator =~, code needs to be fixed" 1>&2 ;; + *) echo "l.$LINENO: unexpected return code of regex match operator =~, code needs to be fixed" 1>&2 ;; + esac + if [ "${range//*-*/}" = "" ]; then + hi=${range##*-} + [[ "$hi" =~ (^[[:xdigit:]]+\.[0-3]\.[[:xdigit:]]{4}$)|(^[[:xdigit:]]{3,4}$) ]] + case $? in + 0) # string matched the pattern + hi=$(canonicalize_devno $hi) + if [ "${lo%.*}" != "${hi%.*}" ]; then + echo $"Prefixes of DASD range $range do not match: ${lo%.*} != ${hi%.*}" 1>&2 + exit 1 + fi + ;; + 1) # string did not match the pattern + echo $"Incorrect format for upper bound of DASD range $range: $hi" 1>&2 + exit 1 + ;; + 2) echo "l.$LINENO: syntax error in regex of match operator =~, code needs to be fixed" 1>&2 ;; + *) echo "l.$LINENO: unexpected return code of regex match operator =~, code needs to be fixed" 1>&2 ;; + esac + fi + if [ "${features//*)/}" != "" ]; then + echo $"Missing closing parenthesis at features of DASD range $range: ($features" 1>&2 + exit 1 + fi + if [ -n "$features" ]; then + attrs="" + features="${features%)}" + for feature in $(echo $features |sed 's/:/\n/g'); do + case $feature in + ro) attrs=$attrs" readonly" ;; + diag) attrs=$attrs" use_diag" ;; + erplog|failfast) attrs=$attrs" "$feature ;; + *) echo $"Unknown DASD feature for device range $range: $feature" 1>&2 + exit 1 + ;; + esac + done + fi + [ -z "$hi" ] && hi=$lo + lodevno=$((0x${lo##*.})) + hidevno=$((0x${hi##*.})) + for ((devno=$lodevno; $devno <= $hidevno; ++devno)); do + devbusid=$(printf "%s.%04x" ${lo%.*} $devno) + echo -n "$devbusid" + for attr in $attrs; do + echo -n " $attr=1" + done + echo + done + esac + done + ;; +esac diff --git a/SOURCES/s390-tools-rhel.patch b/SOURCES/s390-tools-rhel.patch new file mode 100644 index 0000000..b95ceef --- /dev/null +++ b/SOURCES/s390-tools-rhel.patch @@ -0,0 +1,8406 @@ +From ab2402c95f031ad97544a86e4418cb765313eee8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Dan=20Hor=C3=A1k?= +Date: Fri, 31 Aug 2018 10:07:35 +0200 +Subject: [PATCH 01/21] drop LOADLIBES variable +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Remove depreciated LOADLIBES variable from the Makefile rules, LDLIBS serves +the same purpose these days. + +Signed-off-by: Dan Horák +--- + common.mak | 2 +- + cpuplugd/Makefile | 2 +- + ipl_tools/Makefile | 2 +- + vmconvert/Makefile | 2 +- + vmur/Makefile | 2 +- + ziomon/Makefile | 10 +++++----- + 6 files changed, 10 insertions(+), 10 deletions(-) + +diff --git a/common.mak b/common.mak +index 571fb30..6f0990e 100644 +--- a/common.mak ++++ b/common.mak +@@ -239,7 +239,7 @@ endif + $(CXX) $(ALL_CPPFLAGS) $(ALL_CXXFLAGS) -c $< -o $@ + + %: %.o +- $(LINK) $(ALL_LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@ ++ $(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@ + + %.a: + $(AR) rcs $@ $^ +diff --git a/cpuplugd/Makefile b/cpuplugd/Makefile +index a9a49ab..916638d 100644 +--- a/cpuplugd/Makefile ++++ b/cpuplugd/Makefile +@@ -7,7 +7,7 @@ LDLIBS += -lm + OBJECTS = daemon.o cpu.o info.o terms.o config.o main.o getopt.o mem.o + + cpuplugd: $(OBJECTS) +- $(LINK) $(ALL_LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@ ++ $(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@ + + clean: + rm -f cpuplugd $(OBJECTS) +diff --git a/ipl_tools/Makefile b/ipl_tools/Makefile +index 128ec3e..506d5cd 100644 +--- a/ipl_tools/Makefile ++++ b/ipl_tools/Makefile +@@ -6,7 +6,7 @@ objects = main.o ccw.o fcp.o system.o shutdown.o \ + cmd_lsshut.o cmd_chshut.o cmd_lsreipl.o cmd_chreipl.o proc.o + + chreipl: $(objects) +- $(LINK) $(ALL_LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@ ++ $(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@ + + lsreipl: + ln -sf chreipl lsreipl +diff --git a/vmconvert/Makefile b/vmconvert/Makefile +index 4d0216c..380eb19 100644 +--- a/vmconvert/Makefile ++++ b/vmconvert/Makefile +@@ -9,7 +9,7 @@ libs = $(rootdir)/libvmdump/libvmdump.a + objects = vmconvert.o + + vmconvert: $(objects) $(libs) +- $(LINKXX) $(ALL_LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@ ++ $(LINKXX) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@ + + install: all + $(INSTALL) -d -m 755 $(DESTDIR)$(USRBINDIR) $(DESTDIR)$(MANDIR)/man1 +diff --git a/vmur/Makefile b/vmur/Makefile +index 1a6bddc..2c1c2d5 100644 +--- a/vmur/Makefile ++++ b/vmur/Makefile +@@ -11,7 +11,7 @@ libs = $(rootdir)/libvmdump/libvmdump.a \ + objects = vmur.o + + vmur: $(objects) $(libs) +- $(LINKXX) $(ALL_LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@ ++ $(LINKXX) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@ + + install: all + $(INSTALL) -d -m 755 $(DESTDIR)$(USRSBINDIR) $(DESTDIR)$(MANDIR)/man8 +diff --git a/ziomon/Makefile b/ziomon/Makefile +index 778401b..61c2399 100644 +--- a/ziomon/Makefile ++++ b/ziomon/Makefile +@@ -12,33 +12,33 @@ ziomon_mgr_main.o: ziomon_mgr.c + ziomon_mgr: LDLIBS += -lm + ziomon_mgr: ziomon_dacc.o ziomon_util.o ziomon_mgr_main.o ziomon_tools.o \ + ziomon_zfcpdd.o ziomon_msg_tools.o +- $(LINK) $(ALL_LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@ ++ $(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@ + + ziomon_util_main.o: ziomon_util.c ziomon_util.h + $(CC) -DWITH_MAIN $(ALL_CFLAGS) $(ALL_CPPFLAGS) -c $< -o $@ + ziomon_util: LDLIBS += -lm + ziomon_util: ziomon_util_main.o ziomon_tools.o +- $(LINK) $(ALL_LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@ ++ $(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@ + + ziomon_zfcpdd_main.o: ziomon_zfcpdd.c ziomon_zfcpdd.h + $(CC) -DWITH_MAIN $(ALL_CFLAGS) $(ALL_CPPFLAGS) -c $< -o $@ + ziomon_zfcpdd: LDLIBS += -lm -lrt -lpthread + ziomon_zfcpdd: ziomon_zfcpdd_main.o ziomon_tools.o +- $(LINK) $(ALL_LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@ ++ $(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@ + + ziorep_traffic: ziorep_traffic.o ziorep_framer.o ziorep_frameset.o \ + ziorep_printers.o ziomon_dacc.o ziomon_util.o \ + ziomon_msg_tools.o ziomon_tools.o ziomon_zfcpdd.o \ + ziorep_cfgreader.o ziorep_collapser.o ziorep_utils.o \ + ziorep_filters.o +- $(LINKXX) $(ALL_LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@ ++ $(LINKXX) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@ + + ziorep_utilization: ziorep_utilization.o ziorep_framer.o ziorep_frameset.o \ + ziorep_printers.o ziomon_dacc.o ziomon_util.o \ + ziomon_msg_tools.o ziomon_tools.o ziomon_zfcpdd.o \ + ziorep_cfgreader.o ziorep_collapser.o ziorep_utils.o \ + ziorep_filters.o +- $(LINKXX) $(ALL_LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@ ++ $(LINKXX) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@ + + install: all + $(SED) -e 's/%S390_TOOLS_VERSION%/$(S390_TOOLS_RELEASE)/' \ +-- +2.21.0 + + +From ed7cf76fd149a9fed3ce9f728e072bccc44997cb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Dan=20Hor=C3=A1k?= +Date: Fri, 31 Aug 2018 10:13:38 +0200 +Subject: [PATCH 02/21] zkey: Drop redundant include +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Dan Horák +--- + zkey/Makefile | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/zkey/Makefile b/zkey/Makefile +index 68f35cf..725cb3b 100644 +--- a/zkey/Makefile ++++ b/zkey/Makefile +@@ -22,7 +22,6 @@ else + INSTALL_TARGETS += zkey-cryptsetup-skip-cryptsetup2 + endif + +-CPPFLAGS += -I../include + LIBS = $(rootdir)/libutil/libutil.a + + detect-libcryptsetup.h: +-- +2.21.0 + + +From 3a354d9d8e83a36edb9ce68fb85b3cc4afd19991 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Dan=20Hor=C3=A1k?= +Date: Fri, 31 Aug 2018 10:17:07 +0200 +Subject: [PATCH 03/21] zkey: Be consistent when refering to libutil.a +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Dan Horák +--- + zkey/Makefile | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/zkey/Makefile b/zkey/Makefile +index 725cb3b..7e2047a 100644 +--- a/zkey/Makefile ++++ b/zkey/Makefile +@@ -22,7 +22,7 @@ else + INSTALL_TARGETS += zkey-cryptsetup-skip-cryptsetup2 + endif + +-LIBS = $(rootdir)/libutil/libutil.a ++libs = $(rootdir)/libutil/libutil.a + + detect-libcryptsetup.h: + echo "#include " > detect-libcryptsetup.h +@@ -69,10 +69,10 @@ keystore.o: keystore.c keystore.h properties.h + zkey-cryptsetup.o: check-dep-zkey-cryptsetup zkey-cryptsetup.c pkey.h misc.h + + zkey: LDLIBS = -ldl -lcrypto +-zkey: zkey.o pkey.o properties.o keystore.o $(LIBS) ++zkey: zkey.o pkey.o properties.o keystore.o $(libs) + + zkey-cryptsetup: LDLIBS = -ldl -lcryptsetup -ljson-c +-zkey-cryptsetup: zkey-cryptsetup.o pkey.o $(LIBS) ++zkey-cryptsetup: zkey-cryptsetup.o pkey.o $(libs) + + install-common: + $(INSTALL) -d -m 755 $(DESTDIR)$(USRBINDIR) +-- +2.21.0 + + +From 913721b06be3b4662593c3f1a344256c46ce841a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Dan=20Hor=C3=A1k?= +Date: Fri, 31 Aug 2018 04:29:39 -0400 +Subject: [PATCH 04/21] zkey: Be explicit about linking the tools +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +I've met cases when the make's default rule for linking was used instead omitting +the ALL_LDFLAGS variable. The linking rule from common.mak is defined for linking +*.o files only, here we have libutil.a too. + +Signed-off-by: Dan Horák +--- + zkey/Makefile | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/zkey/Makefile b/zkey/Makefile +index 7e2047a..901ddd4 100644 +--- a/zkey/Makefile ++++ b/zkey/Makefile +@@ -70,9 +70,11 @@ zkey-cryptsetup.o: check-dep-zkey-cryptsetup zkey-cryptsetup.c pkey.h misc.h + + zkey: LDLIBS = -ldl -lcrypto + zkey: zkey.o pkey.o properties.o keystore.o $(libs) ++ $(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@ + + zkey-cryptsetup: LDLIBS = -ldl -lcryptsetup -ljson-c + zkey-cryptsetup: zkey-cryptsetup.o pkey.o $(libs) ++ $(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@ + + install-common: + $(INSTALL) -d -m 755 $(DESTDIR)$(USRBINDIR) +-- +2.21.0 + + +From 6a3da6ec34a0947bd14cd0a36ab08b607236a414 Mon Sep 17 00:00:00 2001 +From: Ingo Franzki +Date: Wed, 17 Oct 2018 13:52:48 +0200 +Subject: [PATCH 05/21] zkey: Makefile: Avoid relink of modules during 'make + install' +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Because targets check-dep-zkey and check-dep-zkey-cryptsetup +do not produce any file, any targets that have a pre-req on those +targets are rebuilt during 'make install'. + +Also correct .PHONY targets. + +Fixes: https://github.com/ibm-s390-tools/s390-tools/issues/46 +Signed-off-by: Ingo Franzki +Signed-off-by: Jan Höppner +--- + zkey/Makefile | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/zkey/Makefile b/zkey/Makefile +index 901ddd4..bc7bc33 100644 +--- a/zkey/Makefile ++++ b/zkey/Makefile +@@ -37,6 +37,7 @@ check-dep-zkey: + "openssl/evp.h", \ + "openssl-devel", \ + "HAVE_OPENSSL=0") ++ touch check-dep-zkey + + check-dep-zkey-cryptsetup: detect-libcryptsetup.h + $(call check_dep, \ +@@ -50,6 +51,7 @@ check-dep-zkey-cryptsetup: detect-libcryptsetup.h + "json-c/json.h", \ + "json-c-devel", \ + "HAVE_JSONC=0") ++ touch check-dep-zkey-cryptsetup + + zkey-skip: + echo " SKIP zkey due to HAVE_OPENSSL=0" +@@ -93,6 +95,9 @@ install-zkey-cryptsetup: + install: all install-common $(INSTALL_TARGETS) + + clean: +- rm -f *.o zkey zkey-cryptsetup detect-libcryptsetup.h ++ rm -f *.o zkey zkey-cryptsetup detect-libcryptsetup.h \ ++ check-dep-zkey check-dep-zkey-cryptsetup + +-.PHONY: all install clean ++.PHONY: all install clean zkey-skip zkey-cryptsetup-skip-cryptsetup2 \ ++ zkey-cryptsetup-skip-jsonc install-common install-zkey \ ++ install-zkey-cryptsetup +-- +2.21.0 + + +From e7b59a9f7cc5d049ef68331855a881beb85a1347 Mon Sep 17 00:00:00 2001 +From: Ingo Franzki +Date: Thu, 25 Oct 2018 12:57:29 +0200 +Subject: [PATCH 06/21] zkey: Makefile: Don't rebuild .o.d files on 'make + install' +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The .o.d make targets in common.mak do not expect that +header files are generated by a make target. When a new header +file is generated, the .o.d targets will be rebuilt on the +next make invocation, because that new header file is then +detected, and is then treated as a new dependency of all .o.d +targets. + +Signed-off-by: Ingo Franzki +Signed-off-by: Jan Höppner +--- + zkey/Makefile | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/zkey/Makefile b/zkey/Makefile +index bc7bc33..a44b14b 100644 +--- a/zkey/Makefile ++++ b/zkey/Makefile +@@ -24,12 +24,12 @@ endif + + libs = $(rootdir)/libutil/libutil.a + +-detect-libcryptsetup.h: +- echo "#include " > detect-libcryptsetup.h +- echo "#ifndef CRYPT_LUKS2" >> detect-libcryptsetup.h +- echo " #error libcryptsetup version 2.0.3 is required" >> detect-libcryptsetup.h +- echo "#endif" >> detect-libcryptsetup.h +- echo "int i = CRYPT_SLOT_UNBOUND;" >> detect-libcryptsetup.h ++detect-libcryptsetup.dep: ++ echo "#include " > detect-libcryptsetup.dep ++ echo "#ifndef CRYPT_LUKS2" >> detect-libcryptsetup.dep ++ echo " #error libcryptsetup version 2.0.3 is required" >> detect-libcryptsetup.dep ++ echo "#endif" >> detect-libcryptsetup.dep ++ echo "int i = CRYPT_SLOT_UNBOUND;" >> detect-libcryptsetup.dep + + check-dep-zkey: + $(call check_dep, \ +@@ -39,10 +39,10 @@ check-dep-zkey: + "HAVE_OPENSSL=0") + touch check-dep-zkey + +-check-dep-zkey-cryptsetup: detect-libcryptsetup.h ++check-dep-zkey-cryptsetup: detect-libcryptsetup.dep + $(call check_dep, \ + "zkey-cryptsetup", \ +- "detect-libcryptsetup.h", \ ++ "detect-libcryptsetup.dep", \ + "cryptsetup-devel version 2.0.3", \ + "HAVE_CRYPTSETUP2=0", \ + "-I.") +@@ -95,7 +95,7 @@ install-zkey-cryptsetup: + install: all install-common $(INSTALL_TARGETS) + + clean: +- rm -f *.o zkey zkey-cryptsetup detect-libcryptsetup.h \ ++ rm -f *.o zkey zkey-cryptsetup detect-libcryptsetup.dep \ + check-dep-zkey check-dep-zkey-cryptsetup + + .PHONY: all install clean zkey-skip zkey-cryptsetup-skip-cryptsetup2 \ +-- +2.21.0 + + +From dc92c4ce7963dcf5018c3ef3672b6d217f29842f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Dan=20Hor=C3=A1k?= +Date: Mon, 19 Nov 2018 11:26:40 +0100 +Subject: [PATCH 07/21] zpcictl: Add tool to manage PCI devices (#1525409) + +Summary: zpcictl: Add tool to manage PCI devices +Description: Use the zpcictl tool to manage PCI devices on the IBM Z + platform. Initial functions include generating firmware + error logs, resetting PCI devices, and preparing a device + for further repair actions. +--- + .gitignore | 1 + + Makefile | 2 +- + zpcictl/Makefile | 18 +++ + zpcictl/zpcictl.8 | 80 ++++++++++ + zpcictl/zpcictl.c | 379 ++++++++++++++++++++++++++++++++++++++++++++++ + zpcictl/zpcictl.h | 60 ++++++++ + 6 files changed, 539 insertions(+), 1 deletion(-) + create mode 100644 zpcictl/Makefile + create mode 100644 zpcictl/zpcictl.8 + create mode 100644 zpcictl/zpcictl.c + create mode 100644 zpcictl/zpcictl.h + +diff --git a/.gitignore b/.gitignore +index 41feaf6..042233f 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -89,3 +89,4 @@ zipl/src/chreipl_helper.device-mapper + zipl/src/zipl + zipl/src/zipl_helper.device-mapper + zkey/zkey ++zpcictl/zpcictl +diff --git a/Makefile b/Makefile +index adc92b6..bb2b900 100644 +--- a/Makefile ++++ b/Makefile +@@ -8,7 +8,7 @@ TOOL_DIRS = zipl zdump fdasd dasdfmt dasdview tunedasd \ + tape390 osasnmpd qetharp ip_watcher qethconf scripts zconf \ + vmconvert vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \ + ziomon iucvterm hyptop cmsfs-fuse qethqoat zfcpdump zdsfs cpumf \ +- systemd hmcdrvfs cpacfstats zdev dump2tar zkey netboot etc ++ systemd hmcdrvfs cpacfstats zdev dump2tar zkey netboot etc zpcictl + SUB_DIRS = $(LIB_DIRS) $(TOOL_DIRS) + + all: $(TOOL_DIRS) +diff --git a/zpcictl/Makefile b/zpcictl/Makefile +new file mode 100644 +index 0000000..2b315c5 +--- /dev/null ++++ b/zpcictl/Makefile +@@ -0,0 +1,18 @@ ++include ../common.mak ++ ++all: zpcictl ++ ++libs = $(rootdir)/libutil/libutil.a ++ ++zpcictl: zpcictl.o $(libs) ++ ++install: all ++ $(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man8 ++ $(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 zpcictl $(DESTDIR)$(BINDIR) ++ $(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 zpcictl.8 \ ++ $(DESTDIR)$(MANDIR)/man8 ++ ++clean: ++ rm -f *.o *~ zpcictl core ++ ++.PHONY: all install clean +diff --git a/zpcictl/zpcictl.8 b/zpcictl/zpcictl.8 +new file mode 100644 +index 0000000..4f8fcd8 +--- /dev/null ++++ b/zpcictl/zpcictl.8 +@@ -0,0 +1,80 @@ ++.\" Copyright 2017 IBM Corp. ++.\" s390-tools is free software; you can redistribute it and/or modify ++.\" it under the terms of the MIT license. See LICENSE for details. ++.\" ++.\" Macro for inserting an option description prologue. ++.\" .OD [] [args] ++.de OD ++. ds args " ++. if !'\\$3'' .as args \fI\\$3\fP ++. if !'\\$4'' .as args \\$4 ++. if !'\\$5'' .as args \fI\\$5\fP ++. if !'\\$6'' .as args \\$6 ++. if !'\\$7'' .as args \fI\\$7\fP ++. PD 0 ++. if !'\\$2'' .IP "\fB\-\\$2\fP \\*[args]" 4 ++. if !'\\$1'' .IP "\fB\-\-\\$1\fP \\*[args]" 4 ++. PD ++.. ++. ++.TH zpcictl 8 "Oct 2018" s390-tools zpcictl ++. ++.SH NAME ++zpcictl - Manage PCI devices on z Systems ++. ++. ++.SH SYNOPSIS ++.B "zpcictl" ++.I "OPTIONS" ++.I "DEVICE" ++. ++. ++.SH DESCRIPTION ++.B zpcictl ++is a tool for managing PCI devices on the IBM z Systems platform. It is ++especially used for reporting errorneous PCI devices to the service element. ++ ++.B Note: ++For NVMe devices additional data (such as S.M.A.R.T. data) is collected and sent ++with any error handling action. The smartmontools are required to be installed ++for this to work. ++.PP ++. ++. ++.SH DEVICE ++.B DEVICE ++can be either the PCI slot address (e.g. 0000:00:00.0) or the main device node ++of an NVMe device (e.g. /dev/nvme0). ++. ++. ++.SH OPTIONS ++.SS Error Handling ++.OD reset "" "DEVICE" ++Reset ++.I DEVICE ++and initiate a re-initialisation of the adapter. ++.PP ++. ++.OD deconfigure "" "DEVICE" ++De-configure ++.I DEVICE ++and prepare for any repair action. This action will move the ++PCI device from a configured to a reserved state. ++.PP ++. ++.OD report-error "" "DEVICE" ++Report any device error for ++.IR DEVICE . ++The ++.I DEVICE ++is marked as erroneous and no further action is initiated on it. ++.PP ++. ++.SS Misc ++.OD help "h" "" ++Print usage information, then exit. ++.PP ++. ++.OD version "v" "" ++Print version information, then exit. ++.PP +diff --git a/zpcictl/zpcictl.c b/zpcictl/zpcictl.c +new file mode 100644 +index 0000000..5f63b17 +--- /dev/null ++++ b/zpcictl/zpcictl.c +@@ -0,0 +1,379 @@ ++/* ++ * zpcictl - Manage PCI devices on z Systems ++ * ++ * Copyright IBM Corp. 2018 ++ * ++ * s390-tools is free software; you can redistribute it and/or modify ++ * it under the terms of the MIT license. See LICENSE for details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "lib/util_base.h" ++#include "lib/util_libc.h" ++#include "lib/util_opt.h" ++#include "lib/util_path.h" ++#include "lib/util_prg.h" ++#include "lib/util_proc.h" ++#include "lib/util_rec.h" ++#include "lib/util_scandir.h" ++ ++#include "zpcictl.h" ++ ++#define SMARTCTL_CMDLINE "smartctl -x %s 2>/dev/null" ++ ++static const struct util_prg prg = { ++ .desc = "Use zpcictl to manage PCI devices on s390\n" ++ "DEVICE is the slot id or node of the device (e.g. /dev/nvme0)", ++ .args = "DEVICE", ++ .copyright_vec = { ++ { ++ .owner = "IBM Corp.", ++ .pub_first = 2018, ++ .pub_last = 2018, ++ }, ++ UTIL_PRG_COPYRIGHT_END ++ } ++}; ++ ++/* Defines for options with no short command */ ++#define OPT_RESET 128 ++#define OPT_DECONF 129 ++#define OPT_REPORT_ERR 130 ++ ++static struct util_opt opt_vec[] = { ++ UTIL_OPT_SECTION("ERROR HANDLING"), ++ { ++ .option = { "reset", no_argument, NULL, OPT_RESET }, ++ .desc = "Reset device", ++ .flags = UTIL_OPT_FLAG_NOSHORT, ++ }, ++ { ++ .option = { "deconfigure", no_argument, NULL, OPT_DECONF }, ++ .desc = "De-configure device and prepare for any repair action", ++ .flags = UTIL_OPT_FLAG_NOSHORT, ++ }, ++ { ++ .option = { "report-error", no_argument, NULL, OPT_REPORT_ERR }, ++ .desc = "Report device error to service element (SE)", ++ .flags = UTIL_OPT_FLAG_NOSHORT, ++ }, ++ UTIL_OPT_SECTION("MISC"), ++ UTIL_OPT_HELP, ++ UTIL_OPT_VERSION, ++ UTIL_OPT_END ++}; ++ ++static int is_char_dev(const char *dev) ++{ ++ struct stat s; ++ ++ if (stat(dev, &s)) ++ return 0; ++ ++ return S_ISCHR(s.st_mode); ++} ++ ++static int is_blk_dev(const char *dev) ++{ ++ struct stat s; ++ ++ if (stat(dev, &s)) ++ return 0; ++ ++ return S_ISBLK(s.st_mode); ++} ++ ++static void fopen_err(char *path) ++{ ++ warnx("Could not open file %s: %s", path, strerror(errno)); ++ free(path); ++ exit(EXIT_FAILURE); ++} ++ ++#define READ_CHUNK_SIZE 512 ++ ++static char *collect_smart_data(struct zpci_device *pdev) ++{ ++ char *buffer = NULL; ++ size_t count = 0; ++ char *cmd; ++ FILE *fd; ++ ++ util_asprintf(&cmd, SMARTCTL_CMDLINE, pdev->device); ++ fd = popen(cmd, "r"); ++ if (!fd) ++ goto out; ++ ++ while (!feof(fd)) { ++ buffer = realloc(buffer, count + READ_CHUNK_SIZE); ++ if (!buffer) { ++ warnx("Could not collect S.M.A.R.T. data"); ++ goto out; ++ } ++ count += fread(&buffer[count], 1, READ_CHUNK_SIZE, fd); ++ if (ferror(fd)) { ++ free(buffer); ++ buffer = NULL; ++ goto out; ++ } ++ } ++ ++ buffer = realloc(buffer, count); ++ if (!buffer && count > 0) ++ warnx("Could not collect S.M.A.R.T. data"); ++ if (buffer) ++ buffer[count] = '\0'; ++ ++out: ++ pclose(fd); ++ free(cmd); ++ ++ return buffer; ++} ++ ++static unsigned int sysfs_read_value(struct zpci_device *pdev, const char *attr) ++{ ++ unsigned int val; ++ char *path; ++ FILE *fp; ++ ++ path = util_path_sysfs("bus/pci/devices/%s/%s", pdev->slot, attr); ++ fp = fopen(path, "r"); ++ if (!fp) ++ fopen_err(path); ++ fscanf(fp, "%x", &val); ++ fclose(fp); ++ free(path); ++ ++ return val; ++} ++ ++static void sysfs_write_data(struct zpci_report_error *report, char *slot) ++{ ++ char *path; ++ int fd, rc; ++ ++ path = util_path_sysfs("bus/pci/devices/%s/report_error", slot); ++ fd = open(path, O_WRONLY); ++ if (!fd) ++ fopen_err(path); ++ rc = write(fd, report, sizeof(*report)); ++ if (rc == -1) ++ warnx("Could not write to file: %s: %s", path, strerror(errno)); ++ if (close(fd)) ++ warnx("Could not close file: %s: %s", path, strerror(errno)); ++ free(path); ++} ++ ++static void sysfs_get_slot_addr(const char *dev, char *slot) ++{ ++ unsigned int major, minor; ++ struct stat dev_stat; ++ char addr[13]; ++ char *path; ++ FILE *fp; ++ ++ if (stat(dev, &dev_stat) != 0) { ++ errx(EXIT_FAILURE, "Could not get stat information for %s: %s", ++ dev, strerror(errno)); ++ } ++ major = major(dev_stat.st_rdev); ++ minor = minor(dev_stat.st_rdev); ++ ++ path = util_path_sysfs("dev/char/%u:%u/address", major, minor); ++ fp = fopen(path, "r"); ++ if (!fp) ++ fopen_err(path); ++ fscanf(fp, "%s", addr); ++ fclose(fp); ++ free(path); ++ ++ strcpy(slot, addr); ++} ++ ++static void get_device_node(struct zpci_device *pdev) ++{ ++ struct dirent **de_vec; ++ char *path, *dev; ++ char slot[13]; ++ int count, i; ++ ++ path = util_path_sysfs("bus/pci/devices/%s/nvme", pdev->slot); ++ count = util_scandir(&de_vec, alphasort, path, "nvme*"); ++ if (count == -1) { ++ warnx("Could not read directory %s: %s", path, strerror(errno)); ++ free(path); ++ exit(EXIT_FAILURE); ++ } ++ ++ for (i = 0; i < count; i++) { ++ util_asprintf(&dev, "/dev/%s", de_vec[i]->d_name); ++ sysfs_get_slot_addr(dev, slot); ++ if (strcmp(slot, pdev->slot) == 0) { ++ pdev->device = dev; ++ break; ++ } ++ } ++ ++ util_scandir_free(de_vec, count); ++ free(path); ++} ++ ++static int device_exists(char *dev) ++{ ++ char *path; ++ int rc = 0; ++ ++ path = util_path_sysfs("bus/pci/devices/%s", dev); ++ if (util_path_exists(path) || util_path_exists(dev)) ++ rc = 1; ++ free(path); ++ ++ return rc; ++} ++ ++static void get_device_info(struct zpci_device *pdev, char *dev) ++{ ++ if (!device_exists(dev)) ++ errx(EXIT_FAILURE, "Device %s not found", dev); ++ if (is_blk_dev(dev)) ++ errx(EXIT_FAILURE, "Unsupported device type %s", dev); ++ if (is_char_dev(dev)) { ++ sysfs_get_slot_addr(dev, pdev->slot); ++ pdev->device = dev; ++ } else { ++ strcpy(pdev->slot, dev); ++ } ++ ++ pdev->class = sysfs_read_value(pdev, "class"); ++ pdev->fid = sysfs_read_value(pdev, "function_id"); ++ pdev->pchid = sysfs_read_value(pdev, "pchid"); ++ ++ /* In case a slot address was specified, we still need to figure out ++ * the device node for NVMe devices. Otherwise we won't be able to ++ * collect S.M.A.R.T. data at a later point. ++ */ ++ if (!pdev->device && pdev->class == PCI_CLASS_NVME) ++ get_device_node(pdev); ++} ++ ++/* ++ * Issue an SCLP Adapter Error Notification event with a specific action ++ * qualifier. ++ * ++ * Collect additional information when possible (e.g. S.M.A.R.T. data for NVMe ++ * devices). ++ */ ++static void sclp_issue_action(struct zpci_device *pdev, int action) ++{ ++ struct zpci_report_error report = { ++ .header = { 0 }, ++ .data = { 0 } ++ }; ++ char *sdata = NULL; ++ ++ report.header.version = 1; ++ report.header.action = action; ++ report.header.length = sizeof(report.data); ++ report.data.timestamp = (__u64)time(NULL); ++ report.data.err_log_id = 0x4713; ++ ++ if (pdev->class == PCI_CLASS_NVME) ++ sdata = collect_smart_data(pdev); ++ if (sdata) { ++ strncpy(report.data.log_data, sdata, sizeof(report.data.log_data)); ++ free(sdata); ++ } ++ sysfs_write_data(&report, pdev->slot); ++} ++ ++/* ++ * Reset the PCI device and initiate a re-initialization. ++ */ ++static void sclp_reset_device(struct zpci_device *pdev) ++{ ++ sclp_issue_action(pdev, SCLP_ERRNOTIFY_AQ_RESET); ++} ++ ++/* ++ * De-Configure/repair PCI device. Moves the device from configured ++ * to reserved state. ++ */ ++static void sclp_deconfigure(struct zpci_device *pdev) ++{ ++ sclp_issue_action(pdev, SCLP_ERRNOTIFY_AQ_DECONF); ++} ++ ++/* ++ * Report an error to the SE. ++ */ ++static void sclp_report_error(struct zpci_device *pdev) ++{ ++ sclp_issue_action(pdev, SCLP_ERRNOTIFY_AQ_REPORT_ERR); ++} ++ ++static void parse_cmdline(int argc, char *argv[], struct options *opts) ++{ ++ int cmd; ++ ++ util_prg_init(&prg); ++ util_opt_init(opt_vec, NULL); ++ ++ do { ++ cmd = util_opt_getopt_long(argc, argv); ++ ++ switch (cmd) { ++ case OPT_RESET: ++ opts->reset = 1; ++ break; ++ case OPT_DECONF: ++ opts->deconfigure = 1; ++ break; ++ case OPT_REPORT_ERR: ++ opts->report = 1; ++ break; ++ case 'h': ++ util_prg_print_help(); ++ util_opt_print_help(); ++ exit(EXIT_SUCCESS); ++ case 'v': ++ util_prg_print_version(); ++ exit(EXIT_SUCCESS); ++ case -1: ++ /* End of options string */ ++ if (argc == 1) { ++ errx(EXIT_FAILURE, ++ "Use '%s --help' for more information", ++ argv[0]); ++ } ++ break; ++ } ++ } while (cmd != -1); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ struct zpci_device pdev = { 0 }; ++ struct options opts = { 0 }; ++ ++ parse_cmdline(argc, argv, &opts); ++ ++ if (optind >= argc) ++ errx(EXIT_FAILURE, "No device specified"); ++ ++ get_device_info(&pdev, argv[optind]); ++ ++ if (opts.reset) ++ sclp_reset_device(&pdev); ++ else if (opts.deconfigure) ++ sclp_deconfigure(&pdev); ++ else if (opts.report) ++ sclp_report_error(&pdev); ++ ++ return 0; ++} +diff --git a/zpcictl/zpcictl.h b/zpcictl/zpcictl.h +new file mode 100644 +index 0000000..5187e7c +--- /dev/null ++++ b/zpcictl/zpcictl.h +@@ -0,0 +1,60 @@ ++/* ++ * zpcictl - Manage PCI devices on z Systems ++ * ++ * Copyright IBM Corp. 2018 ++ * ++ * s390-tools is free software; you can redistribute it and/or modify ++ * it under the terms of the MIT license. See LICENSE for details. ++ */ ++ ++#ifndef ZPCICTL_H ++#define ZPCICTL_H ++ ++#include ++#include "lib/zt_common.h" ++ ++#define SCLP_ERRNOTIFY_AQ_RESET 0 ++#define SCLP_ERRNOTIFY_AQ_DECONF 1 ++#define SCLP_ERRNOTIFY_AQ_REPORT_ERR 2 ++ ++#define PCI_CLASS_UNCLASSIFIED 0x000000U ++#define PCI_CLASS_NVME 0x010802U ++#define PCI_CLASS_NETWORK 0x020000U ++ ++struct options { ++ unsigned int reset; ++ unsigned int deconfigure; ++ unsigned int report; ++}; ++ ++struct zpci_device { ++ u16 fid; ++ u16 pchid; ++ u32 class; ++ char slot[13]; ++ char *device; ++}; ++ ++struct zpci_report_error_header { ++ __u8 version; /* Interface version byte */ ++ __u8 action; /* Action qualifier byte ++ * 0: Adapter Reset Request ++ * 1: Deconfigure and repair action requested ++ * 2: Informational Report ++ */ ++ __u16 length; /* Length of Subsequent Data (up to 4K – SCLP header) */ ++ __u8 data[0]; /* Subsequent Data passed verbatim to SCLP ET 24 */ ++}; ++ ++struct zpci_report_error_data { ++ __u64 timestamp; ++ __u64 err_log_id; ++ char log_data[4054]; /* We cannot exceed a total of 4074 bytes (header + data) */ ++}; ++ ++struct zpci_report_error { ++ struct zpci_report_error_header header; ++ struct zpci_report_error_data data; ++} __packed; ++ ++#endif /* ZPCICTL_H */ +-- +2.21.0 + + +From c17b203ee85a63c812654e937f0c5cb3da6229e3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Dan=20Hor=C3=A1k?= +Date: Mon, 19 Nov 2018 11:35:09 +0100 +Subject: [PATCH 08/21] zpcictl: Read device link to obtain device address + (#1639220) + +Description: zpcictl: Read device link to obtain device address +Symptom: Issuing zpcictl --report-error /dev/nvme0 leads to: + zpcictl: Could not open file /sys/dev/char/249:0/address: + No such file or directory +Problem: The sysfs attribute 'address' in /sys/dev/char/x:x/ is not + present on all kernel versions. +Solution: Read the device link using readlink() to obtain the device + address instead. +Reproduction: For example, run zpcictl --report-error /dev/nvme0 before + kernel 4.8. +--- + zpcictl/zpcictl.8 | 13 +++++---- + zpcictl/zpcictl.c | 72 +++++++++++++++++++++++++++++++---------------- + 2 files changed, 55 insertions(+), 30 deletions(-) + +diff --git a/zpcictl/zpcictl.8 b/zpcictl/zpcictl.8 +index 4f8fcd8..41fab9a 100644 +--- a/zpcictl/zpcictl.8 ++++ b/zpcictl/zpcictl.8 +@@ -1,4 +1,4 @@ +-.\" Copyright 2017 IBM Corp. ++.\" Copyright IBM Corp. 2018 + .\" s390-tools is free software; you can redistribute it and/or modify + .\" it under the terms of the MIT license. See LICENSE for details. + .\" +@@ -30,9 +30,10 @@ zpcictl - Manage PCI devices on z Systems + . + . + .SH DESCRIPTION ++With + .B zpcictl +-is a tool for managing PCI devices on the IBM z Systems platform. It is +-especially used for reporting errorneous PCI devices to the service element. ++, you can manage PCI devices on the IBM z Systems platform. It is especially ++used for reporting erroneous PCI devices to the service element. + + .B Note: + For NVMe devices additional data (such as S.M.A.R.T. data) is collected and sent +@@ -44,7 +45,9 @@ for this to work. + .SH DEVICE + .B DEVICE + can be either the PCI slot address (e.g. 0000:00:00.0) or the main device node +-of an NVMe device (e.g. /dev/nvme0). ++of an NVMe device (e.g. ++.I /dev/nvme0 ++). + . + . + .SH OPTIONS +@@ -52,7 +55,7 @@ of an NVMe device (e.g. /dev/nvme0). + .OD reset "" "DEVICE" + Reset + .I DEVICE +-and initiate a re-initialisation of the adapter. ++and initiate a re-initialization of the PCI device. + .PP + . + .OD deconfigure "" "DEVICE" +diff --git a/zpcictl/zpcictl.c b/zpcictl/zpcictl.c +index 5f63b17..a9e38fb 100644 +--- a/zpcictl/zpcictl.c ++++ b/zpcictl/zpcictl.c +@@ -104,6 +104,9 @@ static char *collect_smart_data(struct zpci_device *pdev) + char *cmd; + FILE *fd; + ++ if (!pdev->device) ++ return NULL; ++ + util_asprintf(&cmd, SMARTCTL_CMDLINE, pdev->device); + fd = popen(cmd, "r"); + if (!fd) +@@ -155,45 +158,60 @@ static unsigned int sysfs_read_value(struct zpci_device *pdev, const char *attr) + + static void sysfs_write_data(struct zpci_report_error *report, char *slot) + { ++ size_t r_size; + char *path; +- int fd, rc; ++ FILE *fp; ++ ++ r_size = sizeof(*report); + + path = util_path_sysfs("bus/pci/devices/%s/report_error", slot); +- fd = open(path, O_WRONLY); +- if (!fd) ++ fp = fopen(path, "w"); ++ if (!fp) + fopen_err(path); +- rc = write(fd, report, sizeof(*report)); +- if (rc == -1) ++ if (fwrite(report, 1, r_size, fp) != r_size) + warnx("Could not write to file: %s: %s", path, strerror(errno)); +- if (close(fd)) ++ if (fclose(fp)) + warnx("Could not close file: %s: %s", path, strerror(errno)); + free(path); + } + +-static void sysfs_get_slot_addr(const char *dev, char *slot) ++/* lstat() doesn't work for sysfs files, so we have to work with a fixed size */ ++#define READLINK_SIZE 256 ++ ++static int sysfs_get_slot_addr(const char *dev, char *slot) + { ++ char device[READLINK_SIZE], *result; + unsigned int major, minor; + struct stat dev_stat; +- char addr[13]; ++ ssize_t len; + char *path; +- FILE *fp; + + if (stat(dev, &dev_stat) != 0) { +- errx(EXIT_FAILURE, "Could not get stat information for %s: %s", +- dev, strerror(errno)); ++ warnx("Could not get stat information for %s: %s", ++ dev, strerror(errno)); ++ return 0; + } + major = major(dev_stat.st_rdev); + minor = minor(dev_stat.st_rdev); + +- path = util_path_sysfs("dev/char/%u:%u/address", major, minor); +- fp = fopen(path, "r"); +- if (!fp) +- fopen_err(path); +- fscanf(fp, "%s", addr); +- fclose(fp); ++ path = util_path_sysfs("dev/char/%u:%u/device", major, minor); ++ len = readlink(path, device, READLINK_SIZE - 1); + free(path); ++ if (len != -1) { ++ device[len] = '\0'; ++ } else { ++ warnx("Could not read device link for %s", dev); ++ return 0; ++ } ++ ++ result = strrchr(device, '/'); ++ if (result) ++ result++; ++ else ++ result = device; ++ strcpy(slot, result); + +- strcpy(slot, addr); ++ return 1; + } + + static void get_device_node(struct zpci_device *pdev) +@@ -208,12 +226,13 @@ static void get_device_node(struct zpci_device *pdev) + if (count == -1) { + warnx("Could not read directory %s: %s", path, strerror(errno)); + free(path); +- exit(EXIT_FAILURE); ++ return; + } + + for (i = 0; i < count; i++) { + util_asprintf(&dev, "/dev/%s", de_vec[i]->d_name); +- sysfs_get_slot_addr(dev, slot); ++ if (!sysfs_get_slot_addr(dev, slot)) ++ continue; + if (strcmp(slot, pdev->slot) == 0) { + pdev->device = dev; + break; +@@ -240,11 +259,13 @@ static int device_exists(char *dev) + static void get_device_info(struct zpci_device *pdev, char *dev) + { + if (!device_exists(dev)) +- errx(EXIT_FAILURE, "Device %s not found", dev); ++ errx(EXIT_FAILURE, "Could not find device %s", dev); + if (is_blk_dev(dev)) + errx(EXIT_FAILURE, "Unsupported device type %s", dev); + if (is_char_dev(dev)) { +- sysfs_get_slot_addr(dev, pdev->slot); ++ if (!sysfs_get_slot_addr(dev, pdev->slot)) ++ errx(EXIT_FAILURE, ++ "Could not determine slot address for %s", dev); + pdev->device = dev; + } else { + strcpy(pdev->slot, dev); +@@ -254,9 +275,10 @@ static void get_device_info(struct zpci_device *pdev, char *dev) + pdev->fid = sysfs_read_value(pdev, "function_id"); + pdev->pchid = sysfs_read_value(pdev, "pchid"); + +- /* In case a slot address was specified, we still need to figure out +- * the device node for NVMe devices. Otherwise we won't be able to +- * collect S.M.A.R.T. data at a later point. ++ /* ++ * In case a slot address was specified, the device node for NVMe ++ * devices is still needed. Otherwise it won't be possible to collect ++ * S.M.A.R.T. data at a later point. + */ + if (!pdev->device && pdev->class == PCI_CLASS_NVME) + get_device_node(pdev); +-- +2.21.0 + + +From 8d8e0a970dbde0ca4486192aed806d837f080370 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Dan=20Hor=C3=A1k?= +Date: Mon, 19 Nov 2018 11:36:36 +0100 +Subject: [PATCH 09/21] zpcictl: Change wording of man-page and help output + (#1643451) + +Description: zpcictl: Change wording of man-page and help output +Symptom: - +Problem: Wording not clear enough and platform description is wrong. +Solution: Change wording and use the correct platform description. +Reproduction: - +Upstream-ID: aaaebb2030c80151ecac528f22cb9a52752b868c +--- + zpcictl/zpcictl.8 | 38 +++++++++++++++----------------------- + zpcictl/zpcictl.c | 15 ++++++++------- + 2 files changed, 23 insertions(+), 30 deletions(-) + +diff --git a/zpcictl/zpcictl.8 b/zpcictl/zpcictl.8 +index 41fab9a..38aa344 100644 +--- a/zpcictl/zpcictl.8 ++++ b/zpcictl/zpcictl.8 +@@ -20,7 +20,7 @@ + .TH zpcictl 8 "Oct 2018" s390-tools zpcictl + . + .SH NAME +-zpcictl - Manage PCI devices on z Systems ++zpcictl - Manage PCI devices on IBM Z + . + . + .SH SYNOPSIS +@@ -30,50 +30,42 @@ zpcictl - Manage PCI devices on z Systems + . + . + .SH DESCRIPTION +-With ++Use + .B zpcictl +-, you can manage PCI devices on the IBM z Systems platform. It is especially +-used for reporting erroneous PCI devices to the service element. ++to manage PCI devices on the IBM Z platform. In particular, ++use this command to report defective PCI devices to the service element. + + .B Note: + For NVMe devices additional data (such as S.M.A.R.T. data) is collected and sent +-with any error handling action. The smartmontools are required to be installed +-for this to work. ++with any error handling action. For this extendend data collection, the ++smartmontools must be installed. + .PP + . + . + .SH DEVICE +-.B DEVICE +-can be either the PCI slot address (e.g. 0000:00:00.0) or the main device node +-of an NVMe device (e.g. ++A PCI slot address (e.g. 0000:00:00.0) or the main device node of an NVMe ++device (e.g. + .I /dev/nvme0 + ). + . + . + .SH OPTIONS +-.SS Error Handling ++.SS Error Handling Options + .OD reset "" "DEVICE" +-Reset +-.I DEVICE +-and initiate a re-initialization of the PCI device. ++Reset and re-initialize the PCI device. + .PP + . + .OD deconfigure "" "DEVICE" +-De-configure +-.I DEVICE +-and prepare for any repair action. This action will move the +-PCI device from a configured to a reserved state. ++Deconfigure the PCI device and prepare for any repair action. This action ++changes the status of the PCI device from configured to reserved. + .PP + . + .OD report-error "" "DEVICE" +-Report any device error for +-.IR DEVICE . +-The +-.I DEVICE +-is marked as erroneous and no further action is initiated on it. ++Report any device error for the PCI device. ++The device is marked as defective but no further action is taken. + .PP + . +-.SS Misc ++.SS General Options + .OD help "h" "" + Print usage information, then exit. + .PP +diff --git a/zpcictl/zpcictl.c b/zpcictl/zpcictl.c +index a9e38fb..7cfa0d3 100644 +--- a/zpcictl/zpcictl.c ++++ b/zpcictl/zpcictl.c +@@ -27,8 +27,9 @@ + #define SMARTCTL_CMDLINE "smartctl -x %s 2>/dev/null" + + static const struct util_prg prg = { +- .desc = "Use zpcictl to manage PCI devices on s390\n" +- "DEVICE is the slot id or node of the device (e.g. /dev/nvme0)", ++ .desc = "Use zpcictl to manage PCI devices on IBM Z\n" ++ "DEVICE is the slot ID or node of the device " ++ "(e.g. 0000:00:00.0 or /dev/nvme0)", + .args = "DEVICE", + .copyright_vec = { + { +@@ -46,23 +47,23 @@ static const struct util_prg prg = { + #define OPT_REPORT_ERR 130 + + static struct util_opt opt_vec[] = { +- UTIL_OPT_SECTION("ERROR HANDLING"), ++ UTIL_OPT_SECTION("ERROR HANDLING OPTIONS"), + { + .option = { "reset", no_argument, NULL, OPT_RESET }, +- .desc = "Reset device", ++ .desc = "Reset the device", + .flags = UTIL_OPT_FLAG_NOSHORT, + }, + { + .option = { "deconfigure", no_argument, NULL, OPT_DECONF }, +- .desc = "De-configure device and prepare for any repair action", ++ .desc = "Deconfigure the device to prepare for any repair action", + .flags = UTIL_OPT_FLAG_NOSHORT, + }, + { + .option = { "report-error", no_argument, NULL, OPT_REPORT_ERR }, +- .desc = "Report device error to service element (SE)", ++ .desc = "Report a device error to the service element (SE)", + .flags = UTIL_OPT_FLAG_NOSHORT, + }, +- UTIL_OPT_SECTION("MISC"), ++ UTIL_OPT_SECTION("GENERAL OPTIONS"), + UTIL_OPT_HELP, + UTIL_OPT_VERSION, + UTIL_OPT_END +-- +2.21.0 + + +From 916022e17d4cb189c0d83028ed09d3f4600046dd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Dan=20Hor=C3=A1k?= +Date: Mon, 19 Nov 2018 11:37:34 +0100 +Subject: [PATCH 10/21] zdev: qeth BridgePort and VNICC attribute conflict + (#1643452) + +Description: zdev: qeth BridgePort and VNICC attribute conflict +Symptom: chzdev cannot set VNICC attributes due to a conflict with + BridgePort attributes. +Problem: Existing conflict checking always assumes a BridgePort and a + VNICC attribute are active. +Solution: Introduce a function that determines if BridgePort or VNICC + attributes are active and use only active attributes for conflict + checking. +Reproduction: Set VNICC attribute with chzdev w/o active BridgePort attributes. +Upstream-ID: ffe91d1b3082730905caee75b6ec8b05e3cf46a3 +--- + zdev/src/qeth.c | 33 +++++++++++++++++++++++++++++++++ + 1 file changed, 33 insertions(+) + +diff --git a/zdev/src/qeth.c b/zdev/src/qeth.c +index 46bc23d..6191ad1 100644 +--- a/zdev/src/qeth.c ++++ b/zdev/src/qeth.c +@@ -1171,6 +1171,37 @@ static exit_code_t check_ineffective_settings(struct setting_list *list, + return rc; + } + ++/* Check if a possibly conflicting setting is active in the configuration */ ++static bool conflict_setting_active(struct setting *s) ++{ ++ enum qeth_attr_group_type t; ++ ++ t = get_attr_group_type(s); ++ if (t != group_bridge && t != group_vnicc) { ++ /* Check BridgePort and VNICC attributes only */ ++ return false; ++ } ++ if (s->specified) { ++ /* Specified on the command line: We are strict here and do not ++ * allow to specify VNICC and BridgePort attributes in the same ++ * command to avoid issues when attributes are enabled/disabled ++ * in the wrong order. Example: disable VNICC and enable ++ * BridgePort in the same command would result in an error ++ * because BridgePort attributes are set first. ++ */ ++ return true; ++ } ++ if (attrib_match_default(s->attrib, s->value)) { ++ /* Not active if set to default value */ ++ return false; ++ } ++ if (s->actual_value && strncmp(s->actual_value, "n/a", 3) == 0) { ++ /* Not active if in n/a state (conflicting attribute set) */ ++ return false; ++ } ++ return true; ++} ++ + /* Check if there are conflicting attribute settings */ + static exit_code_t check_conflicting_settings(struct setting_list *list) + { +@@ -1182,6 +1213,8 @@ static exit_code_t check_conflicting_settings(struct setting_list *list) + util_list_iterate(&list->list, s) { + if (s->removed) + continue; ++ if (!conflict_setting_active(s)) ++ continue; + t = get_attr_group_type(s); + if (t == group_bridge && (!bridge || !bridge->specified)) + bridge = s; +-- +2.21.0 + + +From e2916bdb493e9565d74b0334fa45f17c6f0f730c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Dan=20Hor=C3=A1k?= +Date: Mon, 19 Nov 2018 11:38:30 +0100 +Subject: [PATCH 11/21] qethqoat: add OSA-Express7S support (#1644384) + +Description: qethqoat: add OSA-Express7S support +Symptom: qethqoat fails to report HW generation and link speed for + OSA-Express7S network card. +Problem: Missing identifiers for new values in the QUERY OAT data. +Solution: Add identifiers for card generation and link speed. +Reproduction: Run qethqoat on an OSA-Express7S, check the output for + 'OSA Generation' and 'Port speed/mode'. +Upstream-ID: 20145b6d06debd47944bff0a471d17e5eba07010 +--- + qethqoat/qethqoat.c | 6 ++++++ + qethqoat/qethqoat.h | 2 ++ + 2 files changed, 8 insertions(+) + +diff --git a/qethqoat/qethqoat.c b/qethqoat/qethqoat.c +index 6a30d1d..7110c28 100644 +--- a/qethqoat/qethqoat.c ++++ b/qethqoat/qethqoat.c +@@ -208,6 +208,9 @@ static void print_physical(struct qeth_qoat_physical *phdr) + case OAT_OSA_GEN_OSAE6S: + osagen = "OSA-Express6S"; + break; ++ case OAT_OSA_GEN_OSAE7S: ++ osagen = "OSA-Express7S"; ++ break; + default: + sprintf(tmp, "unknown (0x%x)", phdr->osa_gen); + osagen = tmp; +@@ -239,6 +242,9 @@ static void print_physical(struct qeth_qoat_physical *phdr) + case OAT_PORT_SPEED_10gbs_full: + speed = "10 Gb/s / full duplex"; + break; ++ case OAT_PORT_SPEED_25gbs_full: ++ speed = "25 Gb/s / full duplex"; ++ break; + case OAT_PORT_SPEED_UNKNOWN: + speed = "unknown / unknown"; + break; +diff --git a/qethqoat/qethqoat.h b/qethqoat/qethqoat.h +index dd7e992..e692937 100644 +--- a/qethqoat/qethqoat.h ++++ b/qethqoat/qethqoat.h +@@ -58,6 +58,7 @@ struct qeth_qoat_physical { + #define OAT_OSA_GEN_OSAE4S 0x02 + #define OAT_OSA_GEN_OSAE5S 0x03 + #define OAT_OSA_GEN_OSAE6S 0x04 ++#define OAT_OSA_GEN_OSAE7S 0x05 + __u8 osa_gen; + #define OAT_PORT_SPEED_UNKNOWN 0x00 + #define OAT_PORT_SPEED_10mbs_half 0x01 +@@ -68,6 +69,7 @@ struct qeth_qoat_physical { + #define OAT_PORT_SPEED_1000mbs_full 0x06 + #define OAT_PORT_SPEED_NA 0x07 + #define OAT_PORT_SPEED_10gbs_full 0x08 ++#define OAT_PORT_SPEED_25gbs_full 0x0A + __u8 port_speed; + #define OAT_PORT_MEDIA_COPPER 0x01 + #define OAT_PORT_MEDIA_MULTI_MODE 0x02 +-- +2.21.0 + + +From ba7eb5cd9d858f2ff8bd29e0b610337896587b94 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Dan=20Hor=C3=A1k?= +Date: Mon, 19 Nov 2018 11:39:35 +0100 +Subject: [PATCH 12/21] zcryptctl: add zcryptctl to manage multiple zcrypt + nodes (#1646354) + +Summary: zcryptctl: add zcryptctl to manage multiple zcrypt nodes +Description: There is a new zcrypt kernel feature which provides + multiple customizable device nodes for the zcrypt + device driver. Here is the userspace part of this + which adds a new application zcryptctl for user + friendly management of this feature. +Upstream-ID: f05f7d656b13c3904f0c55e86ebe9e9b19fcd222 +--- + zconf/zcrypt/Makefile | 7 +- + zconf/zcrypt/zcryptctl.8 | 147 ++++++ + zconf/zcrypt/zcryptctl.c | 1030 ++++++++++++++++++++++++++++++++++++++ + 3 files changed, 1182 insertions(+), 2 deletions(-) + create mode 100644 zconf/zcrypt/zcryptctl.8 + create mode 100644 zconf/zcrypt/zcryptctl.c + +diff --git a/zconf/zcrypt/Makefile b/zconf/zcrypt/Makefile +index 698e148..d075f34 100644 +--- a/zconf/zcrypt/Makefile ++++ b/zconf/zcrypt/Makefile +@@ -1,21 +1,24 @@ + include ../../common.mak + +-all: chzcrypt lszcrypt ++all: chzcrypt lszcrypt zcryptctl + + libs = $(rootdir)/libutil/libutil.a + + chzcrypt: chzcrypt.o misc.o $(libs) + lszcrypt: lszcrypt.o misc.o $(libs) ++zcryptctl: zcryptctl.o misc.o $(libs) + + install: all + $(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR) + $(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 chzcrypt $(DESTDIR)$(BINDIR) + $(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 lszcrypt $(DESTDIR)$(BINDIR) ++ $(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 zcryptctl $(DESTDIR)$(BINDIR) + $(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man8 + $(INSTALL) -m 644 -c chzcrypt.8 $(DESTDIR)$(MANDIR)/man8 + $(INSTALL) -m 644 -c lszcrypt.8 $(DESTDIR)$(MANDIR)/man8 ++ $(INSTALL) -m 644 -c zcryptctl.8 $(DESTDIR)$(MANDIR)/man8 + + clean: +- rm -f *.o chzcrypt lszcrypt ++ rm -f *.o chzcrypt lszcrypt zcryptctl + + .PHONY: all install clean +diff --git a/zconf/zcrypt/zcryptctl.8 b/zconf/zcrypt/zcryptctl.8 +new file mode 100644 +index 0000000..5d098da +--- /dev/null ++++ b/zconf/zcrypt/zcryptctl.8 +@@ -0,0 +1,147 @@ ++.\" zcryptctl.8 ++.\" ++.\" Copyright 2018 IBM Corp. ++.\" s390-tools is free software; you can redistribute it and/or modify ++.\" it under the terms of the MIT license. See LICENSE for details. ++.\" ++.\" use ++.\" groff -man -Tutf8 zcryptctl.8 ++.\" or ++.\" nroff -man zcryptctl.8 ++.\" to process this source ++.\" ++.TH ZCRYPTCTL 8 "AUG 2018" "s390-tools" ++.SH NAME ++zcryptctl \- display information and administrate zcrypt multiple device nodes ++.SH SYNOPSIS ++.TP 8 ++.B zcryptctl list ++.TP ++.B zcryptctl create ++.R [ ++.I node-name ++.R ] ++.TP ++.B zcryptctl destroy ++.I node-name ++.TP ++.B zcryptctl addap ++.R | ++.B delap ++.I node-name adapter-nr ++.TP ++.B zcryptctl adddom ++.R | ++.B deldom ++.I node-name domain-nr ++.TP ++.B zcryptctl addioctl ++.R | ++.B delioctl ++.I node-name ioctl-term ++.TP ++.B zcryptctl config ++.I config-file ++.TP ++.B zcryptctl listconfig ++.SH DESCRIPTION ++The ++.B zcryptctl ++command displays information and maintains the multi device node ++extension for the zcrypt device driver. ++.P ++With the multi device node extension you can create and configure ++additional zcrypt device nodes which can be used as alternate device ++nodes to access the crypto hardware provided by the zcrypt device ++driver. Each zcrypt device node can be restricted in terms of crypto ++cards, domains, and available ioctls. Such a device node can be used ++as a base for container solutions like Docker to control and restrict ++the access to crypto resources. ++.SH COMMANDS ++.TP 8 ++.B zcryptctl list ++Show all the additional device nodes that are currently active. ++.TP ++.B zcryptctl create ++.R [ ++.I node-name ++.R ] ++Create a new zcrypt device node. The \fInode-name\fP might be given ++and needs to be unique and not in use. If there is no node name ++provided, the zcrypt device driver will create a new one with pattern ++zcrypt_\fIx\fP, with \fIx\fP being the next free number. Up to 256 ++additional device nodes can be created. The newly created additional ++device node appears in /dev and has read and write permissions enabled ++only for root. By default all adapters, domains and ioctls are ++initially disabled on this new device node. ++.TP ++.B zcryptctl destroy ++.I node-name ++Destroy an additional zcrypt device node. The device node is only ++marked for disposal and destroyed when it is no longer used. ++.TP ++.B zcryptctl addap ++.R | ++.B delap ++.I node-name adapter-nr ++Update the filter for the specified zcrypt device node and add or ++delete a crypto adapter to be accessible via this node. The symbol ++\fBALL\fP can be used to enable or disable all adapters. ++.TP ++.B zcryptctl adddom ++.R | ++.B deldom ++.I node-name domain-nr ++Update the filter for the specified zcrypt device node and add or ++delete a domain to be accessible through this node. The symbol ++\fBALL\fP can be used to enable or disable all domains. ++.TP ++.B zcryptctl addioctl ++.R | ++.B delioctl ++.I node-name ioctl-term ++Update the filter for the specified zcrypt device node and add or ++delete an ioctl. The ioctl might be specified as symbolic string (one ++of \fBICARSAMODEXPO\fP, \fBICARSACRT\fP, \fBZSECSENDCPRB\fP, ++\fBZSENDEP11CPRB\fP, \fBZCRYPT_DEVICE_STATUS\fP, ++\fBZCRYPT_STATUS_MASK\fP, \fBZCRYPT_QDEPTH_MASK\fP, ++\fBZCRYPT_PERDEV_REQCNT\fP) or numeric value in the range 0-255 and ++the symbol \fBALL\fP can be used to include all ioctls. ++.TP ++.B zcryptctl config ++.I config-file ++Process a config file. The given configuration file is read line by ++line and the settings are applied. Syntax is simple: ++.RS ++.IP "node=" ++.IP "aps=" ++.IP "doms=" ++.IP "ioctls=" ++.LP ++Empty lines are ignored and the '#' marks the rest of the ++line as comment. ++.LP ++The \fBnode=\fP line creates a new zcrypt device node, the \fBaps=\fP, ++\fBdoms=\fP and \fBioctls=\fP lines customize the previously created ++node. The symbol \fBALL\fP is also recognized for aps, doms, and ++ioctls. ++.LP ++Each action must fit into one line, spreading over multiple lines is ++not supported. But you can use more than one \fBaps=\fP, \fBdoms=\fP ++and \fBioctls=\fP lines to customize the very same node. ++.LP ++Processing stops when a line cannot be parsed or the current action ++fails. In this case the exit status is non zero but the successful ++actions until the failure occurs are not rolled back. ++.RE ++.TP ++.B zcryptctl listconfig ++List the current configuration in a form suitable for input to the ++\fBzcryptctl config\fP command. ++.LP ++.SH EXIT STATUS ++On successful completion of the command the exit status is 0. A non ++zero return code (and some kind of failure message) is emitted if the ++processing could not complete successful. ++.SH SEE ALSO ++\fBlszcrypt\fR(8) +diff --git a/zconf/zcrypt/zcryptctl.c b/zconf/zcrypt/zcryptctl.c +new file mode 100644 +index 0000000..8326a08 +--- /dev/null ++++ b/zconf/zcrypt/zcryptctl.c +@@ -0,0 +1,1030 @@ ++/* ++ * zcryptctl - Maintain zcrypt multi device nodes. ++ * ++ * by Harald Freudenberger ++ * Copyright IBM Corp. 2018 ++ * ++ * s390-tools is free software; you can redistribute it and/or modify ++ * it under the terms of the MIT license. See LICENSE for details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "lib/util_base.h" ++#include "lib/util_file.h" ++#include "lib/util_opt.h" ++#include "lib/util_panic.h" ++#include "lib/util_path.h" ++#include "lib/util_prg.h" ++#include "lib/util_proc.h" ++#include "lib/util_rec.h" ++#include "lib/util_scandir.h" ++#include "lib/zt_common.h" ++ ++#define MAX_ZDEV_IOCTLS 256 ++#define ZCRYPT_NAME "zcrypt" ++#define MAX_ZDEV_CARDIDS_EXT 256 ++#define MAX_ZDEV_DOMAINS_EXT 256 ++#define ZCRYPTDEVICE "/dev/z90crypt" ++#define _UNUSED_ __attribute__((unused)) ++ ++/* ++ * Currently known commands ++ */ ++#define CMD_LIST 0x0001 ++#define CMD_CREATE 0x0002 ++#define CMD_DESTROY 0x0003 ++#define CMD_ADD_AP 0x0004 ++#define CMD_DEL_AP 0x0005 ++#define CMD_ADD_DOM 0x0006 ++#define CMD_DEL_DOM 0x0007 ++#define CMD_ADD_IOCTL 0x0008 ++#define CMD_DEL_IOCTL 0x0009 ++#define CMD_CONFIG 0x000A ++#define CMD_LISTCONFIG 0x000B ++ ++/* ++ * Program configuration ++ */ ++static const struct util_prg prg = { ++ .args = "", ++ .command_args = "COMMAND [COMMAND-PARAMS]", ++ .desc = "Display and administrate zcrypt multiple device nodes.", ++ .copyright_vec = { ++ { ++ .owner = "IBM Corp.", ++ .pub_first = 2018, ++ .pub_last = 2018, ++ }, ++ UTIL_PRG_COPYRIGHT_END ++ } ++}; ++ ++static struct util_opt opt_vec[] = { ++ UTIL_OPT_HELP, ++ UTIL_OPT_VERSION, ++ UTIL_OPT_END ++}; ++ ++/* ++ * List of currently known and supported ioctls ++ */ ++static struct zcryptctl_ioctls_s { ++ int nr; ++ const char *name; ++} zcryptctl_ioctls[] = { ++ { ++ .name = "ICARSAMODEXPO", ++ .nr = 0x05, ++ }, ++ { ++ .name = "ICARSACRT", ++ .nr = 0x06, ++ }, ++ { ++ .name = "ZSECSENDCPRB", ++ .nr = 0x81, ++ }, ++ { ++ .name = "ZSENDEP11CPRB", ++ .nr = 0x04, ++ }, ++ { ++ .name = "ZCRYPT_DEVICE_STATUS", ++ .nr = 0x5f, ++ }, ++ { ++ .name = "ZCRYPT_STATUS_MASK", ++ .nr = 0x58, ++ }, ++ { ++ .name = "ZCRYPT_QDEPTH_MASK", ++ .nr = 0x59, ++ }, ++ { ++ .name = "ZCRYPT_PERDEV_REQCNT", ++ .nr = 0x5a, ++ }, ++ { ++ .name = NULL, ++ .nr = 0, ++ }, ++}; ++ ++static int ioctlstr2value(const char *str) ++{ ++ int i; ++ ++ for (i = 0; zcryptctl_ioctls[i].name; i++) ++ if (strcasecmp(str, zcryptctl_ioctls[i].name) == 0) ++ return zcryptctl_ioctls[i].nr; ++ ++ return -1; ++} ++ ++static const char *value2ioctlstr(int value) ++{ ++ int i; ++ ++ for (i = 0; zcryptctl_ioctls[i].name; i++) ++ if (value == zcryptctl_ioctls[i].nr) ++ return zcryptctl_ioctls[i].name; ++ ++ return NULL; ++} ++ ++static int check_nodename(const char *nodename) ++{ ++ struct stat sb; ++ const char *node; ++ char pathname[PATH_MAX]; ++ ++ node = strrchr(nodename, '/'); ++ node = node ? node + 1 : nodename; ++ snprintf(pathname, sizeof(pathname), "/dev/%s", node); ++ pathname[sizeof(pathname) - 1] = '\0'; ++ if (stat(pathname, &sb) != 0) ++ return -1; ++ if (!S_ISCHR(sb.st_mode)) ++ return -2; ++ ++ return 0; ++} ++ ++static int check_zcrypt_class_dir(void) ++{ ++ int rc = 0; ++ char *afile; ++ ++ afile = util_path_sysfs("class/%s", ZCRYPT_NAME); ++ if (!util_path_is_dir(afile)) ++ rc = -1; ++ ++ free(afile); ++ return rc; ++} ++ ++static int fetch_major_minor(const char *nodename, int *major, int *minor) ++{ ++ FILE *f; ++ int rc = 0; ++ char *afile; ++ const char *node; ++ ++ node = strrchr(nodename, '/'); ++ node = node ? node + 1 : nodename; ++ afile = util_path_sysfs("class/%s/%s/dev", ZCRYPT_NAME, node); ++ f = fopen(afile, "r"); ++ if (!f) { ++ rc = -1; ++ goto out; ++ } ++ if (fscanf(f, "%i:%i", major, minor) != 2) { ++ fclose(f); ++ rc = -2; ++ goto out; ++ } ++ fclose(f); ++ ++out: ++ free(afile); ++ return rc; ++} ++ ++static int write_dn_attr(const char *nodename, const char *attr, ++ const char *value) ++{ ++ FILE *f; ++ int rc = 0; ++ char *afile; ++ const char *node; ++ ++ if (nodename) { ++ node = strrchr(nodename, '/'); ++ node = node ? node + 1 : nodename; ++ afile = util_path_sysfs("class/%s/%s/%s", ++ ZCRYPT_NAME, node, attr); ++ } else ++ afile = util_path_sysfs("class/%s/%s", ZCRYPT_NAME, attr); ++ f = fopen(afile, "w"); ++ if (!f) { ++ rc = -1; ++ goto out; ++ } ++ if (fprintf(f, "%s\n", value) < 0) { ++ fclose(f); ++ rc = -2; ++ goto out; ++ } ++ fflush(f); ++ if (ferror(f)) { ++ fclose(f); ++ rc = -2; ++ goto out; ++ } ++ ++ fclose(f); ++ ++out: ++ free(afile); ++ return rc; ++} ++ ++static int read_dn_attr(const char *nodename, const char *attr, ++ char *value, int valuelen) ++{ ++ int rc; ++ FILE *f; ++ char *afile; ++ const char *node; ++ ++ node = strrchr(nodename, '/'); ++ node = node ? node + 1 : nodename; ++ afile = util_path_sysfs("class/%s/%s/%s", ZCRYPT_NAME, node, attr); ++ f = fopen(afile, "r"); ++ if (!f) { ++ rc = -1; ++ goto out; ++ } ++ value = fgets(value, valuelen, f); ++ fclose(f); ++ rc = value ? 0 : -2; ++ ++out: ++ free(afile); ++ return rc; ++} ++ ++static int test_bit(int n, const char *hexbytestr) ++{ ++ char c; ++ int v, i = 0; ++ ++ if (strncmp(hexbytestr, "0x", 2) == 0) ++ i += 2; ++ c = hexbytestr[i + n / 4]; ++ if (c >= '0' && c <= '9') ++ v = c - '0'; ++ else if (c >= 'a' && c <= 'f') ++ v = 10 + c - 'a'; ++ else if (c >= 'A' && c <= 'F') ++ v = 10 + c - 'A'; ++ else ++ errx(EXIT_FAILURE, ++ "Could not parse hex digit '%c'", c); ++ ++ return v & (1 << (3 - (n % 4))); ++} ++ ++static int cmd_list(int cmd, ++ const char *node _UNUSED_, ++ const char *arg _UNUSED_) ++{ ++ DIR *dir; ++ char *dirname; ++ const char *p; ++ struct dirent *de; ++ int i, n, major, minor, count = 0; ++ char buf[80], tab = (cmd == CMD_LISTCONFIG ? ' ' : '\t'); ++ ++ dirname = util_path_sysfs("class/%s", ZCRYPT_NAME); ++ dir = opendir(dirname); ++ if (!dir) ++ errx(EXIT_FAILURE, ++ "Could not read directory '%s' errno=%d (%s)", ++ dirname, errno, strerror(errno)); ++ while ((de = readdir(dir)) != NULL) { ++ if (de->d_name[0] == '.' || de->d_type == DT_REG) ++ continue; ++ if (fetch_major_minor(de->d_name, &major, &minor) != 0) ++ errx(EXIT_FAILURE, ++ "Could not fetch major/minor from sysfs for zcrypt node '%s'", ++ de->d_name); ++ if (cmd == CMD_LISTCONFIG) { ++ printf("node = %s\n", de->d_name); ++ printf(" aps ="); ++ } else { ++ printf("zcrypt node name:\t%s\n", de->d_name); ++ printf(" device node:\t/dev/%s\n", de->d_name); ++ printf(" major:minor:\t%d:%d\n", major, minor); ++ printf(" adapter:"); ++ } ++ if (read_dn_attr(de->d_name, "apmask", buf, sizeof(buf)) != 0) ++ errx(EXIT_FAILURE, ++ "Could not fetch apmask attribute from sysfs for zcrypt node '%s'", ++ de->d_name); ++ for (i = n = 0; i < MAX_ZDEV_CARDIDS_EXT; i++) ++ if (test_bit(i, buf)) ++ printf("%c%d", n++ == 0 ? tab : ',', i); ++ putchar('\n'); ++ if (cmd == CMD_LISTCONFIG) ++ printf(" doms ="); ++ else ++ printf(" domains:"); ++ if (read_dn_attr(de->d_name, "aqmask", buf, sizeof(buf)) != 0) ++ errx(EXIT_FAILURE, ++ "Could not fetch aqmask attribute from sysfs for zcrypt node '%s'", ++ de->d_name); ++ for (i = n = 0; i < MAX_ZDEV_DOMAINS_EXT; i++) ++ if (test_bit(i, buf)) ++ printf("%c%d", n++ == 0 ? tab : ',', i); ++ putchar('\n'); ++ if (cmd == CMD_LISTCONFIG) ++ printf(" ioctls ="); ++ else ++ printf(" ioctls:"); ++ if (read_dn_attr(de->d_name, "ioctlmask", ++ buf, sizeof(buf)) != 0) ++ errx(EXIT_FAILURE, ++ "Could not fetch ioctlmask attribute from sysfs for zcrypt node '%s'", ++ de->d_name); ++ for (i = n = 0; i < MAX_ZDEV_IOCTLS; i++) { ++ if (test_bit(i, buf)) { ++ p = value2ioctlstr(i); ++ if (p) ++ printf("%c%s", ++ n++ == 0 ? tab : ',', p); ++ else ++ printf("%c%d", ++ n++ == 0 ? tab : ',', i); ++ } ++ } ++ putchar('\n'); ++ count++; ++ } ++ closedir(dir); ++ ++ if (count == 0) ++ printf("No additional zcrypt device nodes defined\n"); ++ ++ return 0; ++} ++ ++static int cmd_create(int cmd _UNUSED_, ++ const char *nodename, ++ const char *arg _UNUSED_) ++{ ++ int rc; ++ const char *node; ++ char buf[PATH_MAX]; ++ ++ if (nodename) { ++ node = strrchr(nodename, '/'); ++ node = node ? node + 1 : nodename; ++ strncpy(buf, node, sizeof(buf) - 1); ++ } else ++ strncpy(buf, "\n", sizeof(buf) - 1); ++ buf[sizeof(buf) - 1] = 0; ++ ++ rc = write_dn_attr(NULL, "create", buf); ++ if (rc != 0) ++ errx(EXIT_FAILURE, ++ "Could not write into sysfs entry to create zdev node"); ++ ++ printf("Device node created\n"); ++ ++ return 0; ++} ++ ++static int cmd_destroy(int cmd _UNUSED_, ++ const char *nodename, ++ const char *arg _UNUSED_) ++{ ++ int rc; ++ struct stat sb; ++ const char *node; ++ char pathname[PATH_MAX]; ++ ++ node = strrchr(nodename, '/'); ++ node = node ? node + 1 : nodename; ++ snprintf(pathname, sizeof(pathname), "/dev/%s", node); ++ pathname[sizeof(pathname) - 1] = '\0'; ++ rc = stat(pathname, &sb); ++ if (rc != 0) ++ errx(EXIT_FAILURE, ++ "Could not check status for '%s'", pathname); ++ if (!S_ISCHR(sb.st_mode)) ++ errx(EXIT_FAILURE, ++ "File '%s' is not a character device node", pathname); ++ ++ rc = write_dn_attr(NULL, "destroy", node); ++ if (rc != 0) ++ errx(EXIT_FAILURE, ++ "Could not write into sysfs entry to destroy zdev node '%s'", ++ node); ++ ++ printf("Device node '%s' marked for destruction\n", node); ++ ++ return 0; ++} ++ ++static void add_del_ap(int cmd, const char *node, int ap) ++{ ++ int rc; ++ char buf[PATH_MAX]; ++ ++ if (cmd == CMD_ADD_AP) ++ sprintf(buf, "+%d", ap); ++ else ++ sprintf(buf, "-%d", ap); ++ rc = write_dn_attr(node, "apmask", buf); ++ if (rc != 0) ++ errx(EXIT_FAILURE, ++ "Could not write into sysfs entry to %s adapter %d for zdev node '%s'", ++ cmd == CMD_ADD_AP ? "add" : "remove", ap, node); ++} ++ ++static int cmd_add_del_ap(int cmd, const char *node, const char *arg) ++{ ++ int ap, all = 0; ++ ++ if (strcasecmp(arg, "ALL") == 0) { ++ all = 1; ++ } else { ++ if (sscanf(arg, "%i", &ap) != 1) ++ errx(EXIT_FAILURE, ++ "Invalid adapter argument '%s'", arg); ++ if (ap < 0 || ap >= MAX_ZDEV_CARDIDS_EXT) ++ errx(EXIT_FAILURE, ++ "Adapter argument '%s' out of range [0..%d]", ++ arg, MAX_ZDEV_CARDIDS_EXT - 1); ++ } ++ ++ if (!all) { ++ add_del_ap(cmd, node, ap); ++ printf("Adapter %d %s\n", ap, ++ (cmd == CMD_ADD_AP ? "added" : "removed")); ++ } else { ++ for (ap = 0; ap < MAX_ZDEV_CARDIDS_EXT; ap++) ++ add_del_ap(cmd, node, ap); ++ printf("All adapters %s\n", ++ (cmd == CMD_ADD_AP ? "added" : "removed")); ++ } ++ ++ return 0; ++} ++ ++static void add_del_dom(int cmd, const char *node, int dom) ++{ ++ int rc; ++ char buf[PATH_MAX]; ++ ++ if (cmd == CMD_ADD_DOM) ++ sprintf(buf, "+%d", dom); ++ else ++ sprintf(buf, "-%d", dom); ++ rc = write_dn_attr(node, "aqmask", buf); ++ if (rc != 0) ++ errx(EXIT_FAILURE, ++ "Could not write into sysfs entry to %s domain %d for zdev node '%s'", ++ cmd == CMD_ADD_DOM ? "add" : "remove", dom, node); ++} ++ ++static int cmd_add_del_dom(int cmd, const char *node, const char *arg) ++{ ++ int dom, all = 0; ++ ++ if (strcasecmp(arg, "ALL") == 0) { ++ all = 1; ++ } else { ++ if (sscanf(arg, "%i", &dom) != 1) ++ errx(EXIT_FAILURE, ++ "Invalid domain argument '%s'", arg); ++ if (dom < 0 || dom >= MAX_ZDEV_DOMAINS_EXT) ++ errx(EXIT_FAILURE, ++ "Domain argument '%s' out of range [0..%d]", ++ arg, MAX_ZDEV_DOMAINS_EXT - 1); ++ } ++ ++ if (!all) { ++ add_del_dom(cmd, node, dom); ++ printf("Domain %d %s\n", dom, ++ (cmd == CMD_ADD_DOM ? "added" : "removed")); ++ } else { ++ for (dom = 0; dom < MAX_ZDEV_DOMAINS_EXT; dom++) ++ add_del_dom(cmd, node, dom); ++ printf("All domains %s\n", ++ (cmd == CMD_ADD_DOM ? "added" : "removed")); ++ } ++ ++ return 0; ++} ++ ++static void add_del_ioctl(int cmd, const char *node, int ioctlnr) ++{ ++ int rc; ++ char buf[PATH_MAX]; ++ ++ if (cmd == CMD_ADD_IOCTL) ++ sprintf(buf, "+%d", ioctlnr); ++ else ++ sprintf(buf, "-%d", ioctlnr); ++ rc = write_dn_attr(node, "ioctlmask", buf); ++ if (rc != 0) ++ errx(EXIT_FAILURE, ++ "Could not write into sysfs entry to %s ioctl %d for zdev node '%s'", ++ cmd == CMD_ADD_IOCTL ? "add" : "remove", ioctlnr, node); ++} ++ ++static int cmd_add_del_ioctl(int cmd, const char *node, const char *arg) ++{ ++ int ioctlnr, all = 0; ++ ++ if (strcasecmp(arg, "ALL") == 0) { ++ all = 1; ++ } else { ++ ioctlnr = ioctlstr2value(arg); ++ if (ioctlnr < 0) ++ if (sscanf(arg, "%i", &ioctlnr) != 1) ++ errx(EXIT_FAILURE, ++ "Invalid ioctl argument '%s'", arg); ++ if (ioctlnr < 0 || ioctlnr >= MAX_ZDEV_IOCTLS) ++ errx(EXIT_FAILURE, ++ "Ioctl argument '%s' out of range [0..%d]", ++ arg, MAX_ZDEV_IOCTLS - 1); ++ } ++ ++ if (!all) { ++ add_del_ioctl(cmd, node, ioctlnr); ++ printf("Ioctl %s %s\n", arg, ++ (cmd == CMD_ADD_IOCTL ? "added" : "removed")); ++ } else { ++ for (ioctlnr = 0; ioctlnr < MAX_ZDEV_IOCTLS; ioctlnr++) ++ add_del_ioctl(cmd, node, ioctlnr); ++ printf("All Ioctls %s\n", ++ (cmd == CMD_ADD_IOCTL ? "added" : "removed")); ++ } ++ ++ return 0; ++} ++ ++static int _match_keyword(char **p, const char *keyword) ++{ ++ int n = strlen(keyword); ++ ++ if (strncmp(*p, keyword, n) == 0) { ++ *p += n; ++ return n; ++ } ++ ++ return 0; ++} ++ ++static int _match_character(char **p, char c) ++{ ++ char *q = *p; ++ ++ while (isblank(*q)) ++ q++; ++ if (*q != c) ++ return 0; ++ q++; ++ while (isblank(*q)) ++ q++; ++ *p = q; ++ ++ return 1; ++} ++ ++static int _match_string(char **p, char *buf) ++{ ++ int n = 0; ++ char *q = *p; ++ ++ while (isblank(*q)) ++ q++; ++ while (*q && *q != ',' && !isspace(*q)) { ++ buf[n++] = *q; ++ q++; ++ } ++ while (isblank(*q)) ++ q++; ++ ++ if (n > 0) { ++ buf[n] = '\0'; ++ *p = q; ++ } ++ ++ return n; ++} ++ ++static int cmd_config(int cmd _UNUSED_, ++ const char *nodename _UNUSED_, ++ const char *arg) ++{ ++ ssize_t n; ++ size_t linesize = 0; ++ int nr = 0, havenode = 0; ++ FILE *f = fopen(arg, "r"); ++ char *p, *line = NULL, node[128], buf[128]; ++ ++ if (!f) ++ errx(EXIT_FAILURE, ++ "Could not open file '%s'", arg); ++ ++ while ((n = getline(&line, &linesize, f)) != -1) { ++ nr++; ++ p = line; ++ while (isspace(*p)) ++ p++; ++ if (*p == '\0' || *p == '#') ++ continue; ++ if (_match_keyword(&p, "node")) { ++ if (!_match_character(&p, '=')) ++ errx(EXIT_FAILURE, ++ "Missing '=' at '%-8.8s...' in line %d '%s'", ++ p, nr, line); ++ if (!_match_string(&p, node)) ++ errx(EXIT_FAILURE, ++ "Missing node name at '%-8.8s...' in line %d '%s'", ++ p, nr, line); ++ cmd_create(CMD_CREATE, node, NULL); ++ havenode = 1; ++ } else if (_match_keyword(&p, "aps")) { ++ if (!havenode) ++ errx(EXIT_FAILURE, ++ "Missing node=... before processing any aps=... statements in line %d '%s'", ++ nr, line); ++ if (!_match_character(&p, '=')) ++ errx(EXIT_FAILURE, ++ "Missing '=' at '%-8.8s...' in line %d '%s'", ++ p, nr, line); ++ while (1) { ++ while (isspace(*p)) ++ p++; ++ if (*p == '\0' || *p == '#') ++ break; ++ if (!_match_string(&p, buf)) ++ errx(EXIT_FAILURE, ++ "Missing argument(s) for aps=... at '%-8.8s...' in line %d '%s'", ++ p, nr, line); ++ cmd_add_del_ap(CMD_ADD_AP, node, buf); ++ while (isblank(*p) || *p == ',') ++ p++; ++ } ++ } else if (_match_keyword(&p, "doms")) { ++ if (!havenode) ++ errx(EXIT_FAILURE, ++ "Missing node=... before processing any doms=... statements in line %d '%s'", ++ nr, line); ++ if (!_match_character(&p, '=')) ++ errx(EXIT_FAILURE, ++ "Missing '=' at '%-8.8s...' in line %d '%s'", ++ p, nr, line); ++ while (1) { ++ while (isspace(*p)) ++ p++; ++ if (*p == '\0' || *p == '#') ++ break; ++ if (!_match_string(&p, buf)) ++ errx(EXIT_FAILURE, ++ "Missing argument(s) for aps=... at '%-8.8s...' in line %d '%s'", ++ p, nr, line); ++ cmd_add_del_dom(CMD_ADD_DOM, node, buf); ++ while (isblank(*p) || *p == ',') ++ p++; ++ } ++ } else if (_match_keyword(&p, "ioctls")) { ++ if (!havenode) ++ errx(EXIT_FAILURE, ++ "Missing node=... before processing any ioctls=... statements in line %d '%s'", ++ nr, line); ++ if (!_match_character(&p, '=')) ++ errx(EXIT_FAILURE, ++ "Missing '=' at '%-8.8s...' in line %d '%s'", ++ p, nr, line); ++ while (1) { ++ while (isspace(*p)) ++ p++; ++ if (*p == '\0' || *p == '#') ++ break; ++ if (!_match_string(&p, buf)) ++ errx(EXIT_FAILURE, ++ "Missing argument(s) for aps=... at '%-8.8s...' in line %d '%s'", ++ p, nr, line); ++ cmd_add_del_ioctl(CMD_ADD_IOCTL, node, buf); ++ while (isblank(*p) || *p == ',') ++ p++; ++ } ++ } else ++ errx(EXIT_FAILURE, ++ "Unknown keyword '%-8.8s...' in line %d '%s'", ++ p, nr, line); ++ } ++ ++ free(line); ++ fclose(f); ++ ++ return 0; ++} ++ ++static struct zcryptctl_cmds_s { ++ int cmd; ++ const char *usage; ++ const char *command; ++ const char *description; ++ int (*function)(int cmd, const char *node, const char *arg); ++} zcryptctl_cmds[] = { ++ { ++ .cmd = CMD_LIST, ++ .command = "list", ++ .function = cmd_list, ++ .usage = "zcryptctl list", ++ .description = ++ "List all currently known additional zcrypt device nodes.", ++ }, ++ { ++ .cmd = CMD_CREATE, ++ .command = "create", ++ .function = cmd_create, ++ .usage = "zcryptctl create [nodename]", ++ .description = ++ "Create a new zcrypt device node.\n" ++ "The node-name might be given and needs to be unique and not\n" ++ "in use. If there is no node name provided, the zcrypt device\n" ++ "driver will create a new one with pattern zcrypt_\n" ++ "with being the next free number. By default all\n" ++ "adapters, domains and ioctls are initially disabled on this\n" ++ "new device node." ++ }, ++ { ++ .cmd = CMD_DESTROY, ++ .command = "destroy", ++ .function = cmd_destroy, ++ .usage = "zcryptctl destroy ", ++ .description = ++ "Destroy an additional zcrypt device node.\n" ++ "Mark the given zcrypt device node as disposable. The removal\n" ++ "will take place when it is no longer used.", ++ }, ++ { ++ .cmd = CMD_ADD_AP, ++ .command = "addap", ++ .function = cmd_add_del_ap, ++ .usage = "zcryptctl addap ", ++ .description = ++ "Update the filter for the specified zcrypt device node and\n" ++ "add an crypto adapter to be accessible via this node. The\n" ++ "adapter argument may be a number in the range 0-255 or the\n" ++ "symbol ALL.", ++ }, ++ { ++ .cmd = CMD_DEL_AP, ++ .command = "delap", ++ .function = cmd_add_del_ap, ++ .usage = "zcryptctl delap ", ++ .description = ++ "Update the filter for the specified zcrypt device node and\n" ++ "remove a crypto adapter from the allowed adapters list. The\n" ++ "adapter argument may be a number in the range 0-255 or the\n" ++ "symbol ALL.", ++ }, ++ { ++ .cmd = CMD_ADD_DOM, ++ .command = "adddom", ++ .function = cmd_add_del_dom, ++ .usage = "zcryptctl adddom ", ++ .description = ++ "Update the filter for the specified zcrypt device node and\n" ++ "add a crypto domain to be accessible via this node. The\n" ++ "domain argument may be a number in the range 0-255 or the\n" ++ "symbol ALL.", ++ }, ++ { ++ .cmd = CMD_DEL_DOM, ++ .command = "deldom", ++ .function = cmd_add_del_dom, ++ .usage = "zcryptctl deldom ", ++ .description = ++ "Update the filter for the specified zcrypt device node and\n" ++ "remove a crypto domain from the allowed domains list. The\n" ++ "domain argument may be a number in the range 0-255 or the\n" ++ "symbol ALL.", ++ }, ++ { ++ .cmd = CMD_ADD_IOCTL, ++ .command = "addioctl", ++ .function = cmd_add_del_ioctl, ++ .usage = "zcryptctl addioctl ", ++ .description = ++ "Update the filter for the specified zcrypt device node and\n" ++ "add an ioctl number to be accessible via this node. The\n" ++ "ioctlexp argument may be one of symbols ICARSAMODEXPO,\n" ++ "ICARSACRT, ZSECSENDCPRB, ZSENDEP11CPRB, ZCRYPT_DEVICE_STATUS\n" ++ "ZCRYPT_STATUS_MASK, ZCRYPT_QDEPTH_MASK, ZCRYPT_PERDEV_REQCNT\n" ++ "or a number in the range 0-255 or the symbol ALL.", ++ }, ++ { ++ .cmd = CMD_DEL_IOCTL, ++ .command = "delioctl", ++ .function = cmd_add_del_ioctl, ++ .usage = "zcryptctl delioctl ", ++ .description = ++ "Update the filter for the specified zcrypt device node and\n" ++ "remove an ioctl number from the allowed ioctls list. The\n" ++ "ioctlexp argument may be one of symbols ICARSAMODEXPO,\n" ++ "ICARSACRT, ZSECSENDCPRB, ZSENDEP11CPRB, ZCRYPT_DEVICE_STATUS\n" ++ "ZCRYPT_STATUS_MASK, ZCRYPT_QDEPTH_MASK, ZCRYPT_PERDEV_REQCNT\n" ++ "or a number in the range 0-255 or the symbol ALL.", ++ }, ++ { ++ .cmd = CMD_CONFIG, ++ .command = "config", ++ .function = cmd_config, ++ .usage = "zcryptctl config ", ++ .description = ++ "Process a config file. The given config file is read line by\n" ++ "line and the settings are applied. Syntax is simple:\n" ++ " node=\n" ++ " aps=\n" ++ " doms=\n" ++ " ioctls=\n" ++ "Empty lines are ignored and the '#' marks the rest of the\n" ++ "line as comment.\n" ++ "The node= line creates a new zcrypt device node, the\n" ++ "aps=, doms= and ioctls= lines customize the previously\n" ++ "created node. The symbol ALL is also recognized for aps,\n" ++ "doms, and ioctls.\n" ++ "Each action must fit into one line, spreading over multiple\n" ++ "lines is not supported. But you can use more than one\n" ++ "aps=, doms= and ioctls= lines to customize the very same\n" ++ "node.\n" ++ "Processing stops when a line cannot be parsed or the\n" ++ "current action fails. When the config file has been\n" ++ "processed successful, the zcryptctl return code is 0. A non\n" ++ "zero return code (and some kind of failure message) is\n" ++ "emitted on partial completion.", ++ }, ++ { ++ .cmd = CMD_LISTCONFIG, ++ .command = "listconfig", ++ .function = cmd_list, ++ .usage = "zcryptctl listconfig", ++ .description = ++ "List all currently known additional zcrypt device nodes\n" ++ "in a format suitable for the 'config' command.", ++ }, ++ { ++ .command = NULL, ++ .cmd = 0, ++ } ++}; ++ ++static int get_command_index(const char *cmdstr) ++{ ++ int i; ++ ++ for (i = 0; zcryptctl_cmds[i].command; i++) ++ if (!strcmp(zcryptctl_cmds[i].command, cmdstr)) ++ return i; ++ ++ return -1; ++} ++ ++static void commands_print_help(void) ++{ ++ int i; ++ ++ for (i = 0; zcryptctl_cmds[i].command; i++) ++ if (zcryptctl_cmds[i].usage) ++ printf(" %s\n", zcryptctl_cmds[i].usage); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ int c, cmdindex = -1; ++ int rc = EXIT_SUCCESS; ++ ++ util_prg_init(&prg); ++ util_opt_init(opt_vec, NULL); ++ ++ for (c = 1; c < argc; c++) { ++ cmdindex = get_command_index(argv[c]); ++ if (cmdindex >= 0) ++ break; ++ } ++ ++ while (1) { ++ c = util_opt_getopt_long(argc, argv); ++ if (c == -1) ++ break; ++ switch (c) { ++ case 'h': ++ if (cmdindex < 0) { ++ util_prg_print_help(); ++ commands_print_help(); ++ util_opt_print_help(); ++ } else { ++ printf("Usage: %s\n", ++ zcryptctl_cmds[cmdindex].usage); ++ printf("%s\n", ++ zcryptctl_cmds[cmdindex].description); ++ } ++ return EXIT_SUCCESS; ++ case 'v': ++ util_prg_print_version(); ++ return EXIT_SUCCESS; ++ default: ++ util_opt_print_parse_error(c, argv); ++ return EXIT_FAILURE; ++ } ++ } ++ ++ if (cmdindex < 0) ++ errx(EXIT_FAILURE, "Missing or invalid command argument"); ++ ++ if (check_zcrypt_class_dir() != 0) ++ errx(EXIT_FAILURE, ++ "Directory class/%s is missing in sysfs.\n" ++ "Multiple zcrypt node support is not available", ++ ZCRYPT_NAME); ++ ++ c = zcryptctl_cmds[cmdindex].cmd; ++ switch (c) { ++ case CMD_LIST: ++ case CMD_LISTCONFIG: ++ rc = zcryptctl_cmds[cmdindex].function(c, NULL, NULL); ++ break; ++ case CMD_CREATE: ++ rc = zcryptctl_cmds[cmdindex].function(c, ++ optind + 1 < argc ? ++ argv[optind + 1] : NULL, ++ NULL); ++ break; ++ case CMD_DESTROY: ++ if (optind + 1 >= argc) ++ errx(EXIT_FAILURE, "Missing node name argument"); ++ if (check_nodename(argv[optind + 1]) != 0) ++ errx(EXIT_FAILURE, "Invalid or unknown nodename '%s'", ++ argv[optind + 1]); ++ rc = zcryptctl_cmds[cmdindex].function(c, ++ argv[optind + 1], NULL); ++ break; ++ case CMD_ADD_AP: ++ case CMD_DEL_AP: ++ if (optind + 1 >= argc) ++ errx(EXIT_FAILURE, "Missing node name argument"); ++ if (optind + 2 >= argc) ++ errx(EXIT_FAILURE, "Missing adapter argument"); ++ if (check_nodename(argv[optind + 1]) != 0) ++ errx(EXIT_FAILURE, "Invalid or unknown nodename '%s'", ++ argv[optind + 1]); ++ rc = zcryptctl_cmds[cmdindex].function(c, ++ argv[optind + 1], ++ argv[optind + 2]); ++ break; ++ case CMD_ADD_DOM: ++ case CMD_DEL_DOM: ++ if (optind + 1 >= argc) ++ errx(EXIT_FAILURE, "Missing node name argument"); ++ if (optind + 2 >= argc) ++ errx(EXIT_FAILURE, "Missing domain argument"); ++ if (check_nodename(argv[optind + 1]) != 0) ++ errx(EXIT_FAILURE, "Invalid or unknown nodename '%s'", ++ argv[optind + 1]); ++ rc = zcryptctl_cmds[cmdindex].function(c, ++ argv[optind + 1], ++ argv[optind + 2]); ++ break; ++ case CMD_ADD_IOCTL: ++ case CMD_DEL_IOCTL: ++ if (optind + 1 >= argc) ++ errx(EXIT_FAILURE, "Missing node name argument"); ++ if (optind + 2 >= argc) ++ errx(EXIT_FAILURE, "Missing ioctl argument"); ++ if (check_nodename(argv[optind + 1]) != 0) ++ errx(EXIT_FAILURE, "Invalid or unknown nodename '%s'", ++ argv[optind + 1]); ++ rc = zcryptctl_cmds[cmdindex].function(c, ++ argv[optind + 1], ++ argv[optind + 2]); ++ break; ++ case CMD_CONFIG: ++ if (optind + 1 >= argc) ++ errx(EXIT_FAILURE, "Missing filename argument"); ++ rc = zcryptctl_cmds[cmdindex].function(c, NULL, ++ argv[optind + 1]); ++ break; ++ default: ++ errx(EXIT_FAILURE, "Unknown command %d", c); ++ } ++ ++ return rc; ++} +-- +2.21.0 + + +From d5aab30ab6dd79a47d821b39e9f803d4afe8ed7b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Dan=20Hor=C3=A1k?= +Date: Mon, 19 Nov 2018 11:40:35 +0100 +Subject: [PATCH 13/21] lszcrypt: support for alternate zcrypt device drivers + (#1646355) + +Summary: lszcrypt: support for alternate zcrypt device drivers +Description: With kernel 4.19 there comes an extension to the + existing AP bus which supports alternate zcrypt + drivers. For details about this see kernel patch + "s390/zcrypt: AP bus support for alternate + driver(s)". So now lszcrypt displays the driver name + in verbose mode. As some of the information + displayed by lszcrypt was based on sysfs attributes, + which are only available when the default zcrypt + driver is bound to the device, this also needed some + rework. If a sysfs attribute is not available + because of an alternate driver binding (or no + driver) a question mark is printed into the field. +Upstream-ID: 0a0b4c382693cded5652404e8fa2c0e483aa33df +--- + zconf/zcrypt/lszcrypt.8 | 4 +- + zconf/zcrypt/lszcrypt.c | 163 +++++++++++++++++++++++++++------------- + 2 files changed, 112 insertions(+), 55 deletions(-) + +diff --git a/zconf/zcrypt/lszcrypt.8 b/zconf/zcrypt/lszcrypt.8 +index 7196806..826e109 100644 +--- a/zconf/zcrypt/lszcrypt.8 ++++ b/zconf/zcrypt/lszcrypt.8 +@@ -54,8 +54,8 @@ status. + .B -V, --verbose + The verbose level for cryptographic device information. + With this verbose level additional information like hardware card type, +-hardware queue depth, pending request queue count, outstanding +-request queue count, and installed function facilities are displayed. ++hardware queue depth, pending requests count, installed function ++facilities and driver binding is displayed. + .TP 8 + .B + Specifies a cryptographic device to display. A cryptographic device can be +diff --git a/zconf/zcrypt/lszcrypt.c b/zconf/zcrypt/lszcrypt.c +index eb3cd6e..580407f 100644 +--- a/zconf/zcrypt/lszcrypt.c ++++ b/zconf/zcrypt/lszcrypt.c +@@ -1,7 +1,7 @@ + /** + * lszcrypt - Display zcrypt devices and configuration settings + * +- * Copyright IBM Corp. 2008, 2017 ++ * Copyright IBM Corp. 2008, 2018 + * + * s390-tools is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. +@@ -56,6 +56,25 @@ struct lszcrypt_l *lszcrypt_l = &l; + #define MASK_CLASS_STATELESS 0x00400000 + #define CLASS_STATELESS "restricted function set" + ++/* ++ * facility bits ++ */ ++#define MAX_FAC_BITS 9 ++static struct fac_bits_s { ++ int mask; ++ char c; ++} fac_bits[MAX_FAC_BITS] = { ++ { 0x80000000, 'S' }, ++ { 0x40000000, 'M' }, ++ { 0x20000000, 'C' }, ++ { 0x10000000, 'D' }, ++ { 0x08000000, 'A' }, ++ { 0x04000000, 'X' }, ++ { 0x02000000, 'N' }, ++ { 0x00800000, 'F' }, ++ { 0x00400000, 'R' }, ++}; ++ + /* + * Program configuration + */ +@@ -66,7 +85,7 @@ const struct util_prg prg = { + { + .owner = "IBM Corp.", + .pub_first = 2008, +- .pub_last = 2017, ++ .pub_last = 2018, + }, + UTIL_PRG_COPYRIGHT_END + } +@@ -255,7 +274,8 @@ static void show_capability(const char *id_str) + /* Skip devices, which are not supported by zcrypt layer */ + if (!util_path_is_readable("%s/type", dev) || + !util_path_is_readable("%s/online", dev)) { +- printf("Detailed capability information for %s (hardware type %ld) is not available.\n", card, hwtype); ++ printf("Detailed capability information for %s (hardware type %ld) is not available.\n", ++ card, hwtype); + return; + } + cbuf[0] = '\0'; +@@ -299,11 +319,13 @@ static void show_capability(const char *id_str) + } else if (func_val & MASK_EP11) { + printf("%s", CAP_EP11); + } else { +- printf("Detailed capability information for %s (hardware type %ld) is not available.", card, hwtype); ++ printf("Detailed capability information for %s (hardware type %ld) is not available.", ++ card, hwtype); + } + break; + default: +- printf("Detailed capability information for %s (hardware type %ld) is not available.", card, hwtype); ++ printf("Detailed capability information for %s (hardware type %ld) is not available.", ++ card, hwtype); + break; + } + printf("\n"); +@@ -315,17 +337,22 @@ static void show_capability(const char *id_str) + static void read_subdev_rec_default(struct util_rec *rec, const char *grp_dev, + const char *sub_dev) + { +- unsigned long facility; + char buf[256]; ++ unsigned long facility; + +- util_file_read_line(buf, sizeof(buf), "%s/type", grp_dev); +- util_rec_set(rec, "type", buf); ++ if (util_file_read_line(buf, sizeof(buf), "%s/type", grp_dev)) ++ util_rec_set(rec, "type", "-"); ++ else ++ util_rec_set(rec, "type", buf); + +- util_file_read_line(buf, sizeof(buf), "%s/%s/online", grp_dev, sub_dev); +- if (strcmp(buf, "0") == 0) +- util_rec_set(rec, "online", "offline"); ++ if (util_file_read_line(buf, sizeof(buf), "%s/%s/online", ++ grp_dev, sub_dev)) ++ util_rec_set(rec, "online", "-"); + else +- util_rec_set(rec, "online", "online"); ++ if (strcmp(buf, "0") == 0) ++ util_rec_set(rec, "online", "offline"); ++ else ++ util_rec_set(rec, "online", "online"); + + util_file_read_ul(&facility, 16, "%s/ap_functions", grp_dev); + if (facility & MASK_COPRO) +@@ -339,7 +366,7 @@ static void read_subdev_rec_default(struct util_rec *rec, const char *grp_dev, + + util_file_read_line(buf, sizeof(buf), "%s/%s/request_count", + grp_dev, sub_dev); +- util_rec_set(rec, "request_count", buf); ++ util_rec_set(rec, "requests", buf); + } + + /* +@@ -348,20 +375,19 @@ static void read_subdev_rec_default(struct util_rec *rec, const char *grp_dev, + static void read_subdev_rec_verbose(struct util_rec *rec, const char *grp_dev, + const char *sub_dev) + { ++ int i; + unsigned long facility; +- char buf[256]; +- long depth; ++ char buf[256], afile[PATH_MAX]; ++ long depth, pending1, pending2; + + if (l.verbose == 0) + return; + +- util_file_read_line(buf, sizeof(buf), "%s/%s/pendingq_count", +- grp_dev, sub_dev); +- util_rec_set(rec, "pendingq_count", buf); +- +- util_file_read_line(buf, sizeof(buf), "%s/%s/requestq_count", +- grp_dev, sub_dev); +- util_rec_set(rec, "requestq_count", buf); ++ util_file_read_l(&pending1, 10, "%s/%s/pendingq_count", ++ grp_dev, sub_dev); ++ util_file_read_l(&pending2, 10, "%s/%s/requestq_count", ++ grp_dev, sub_dev); ++ util_rec_set(rec, "pending", "%ld", pending1 + pending2); + + util_file_read_line(buf, sizeof(buf), "%s/hwtype", grp_dev); + util_rec_set(rec, "hwtype", buf); +@@ -370,7 +396,18 @@ static void read_subdev_rec_verbose(struct util_rec *rec, const char *grp_dev, + util_rec_set(rec, "depth", "%02d", depth + 1); + + util_file_read_ul(&facility, 16, "%s/ap_functions", grp_dev); +- util_rec_set(rec, "facility", "0x%08x", facility); ++ for (i = 0; i < MAX_FAC_BITS; i++) ++ buf[i] = facility & fac_bits[i].mask ? fac_bits[i].c : '-'; ++ buf[i] = '\0'; ++ util_rec_set(rec, "facility", buf); ++ ++ snprintf(afile, sizeof(afile), "%s/%s/driver", grp_dev, sub_dev); ++ afile[sizeof(afile) - 1] = '\0'; ++ memset(buf, 0, sizeof(buf)); ++ if (readlink(afile, buf, sizeof(buf)) > 0) ++ util_rec_set(rec, "driver", strrchr(buf, '/') + 1); ++ else ++ util_rec_set(rec, "driver", "-no-driver-"); + } + + /* +@@ -382,9 +419,13 @@ static void show_subdevice(struct util_rec *rec, const char *grp_dev, + if (!util_path_is_dir("%s/%s", grp_dev, sub_dev)) + errx(EXIT_FAILURE, "Error - cryptographic device %s/%s does not exist.", grp_dev, sub_dev); + +- /* Skip devices, which are not supported by zcrypt layer */ +- if (!util_path_is_readable("%s/type", grp_dev) || +- !util_path_is_readable("%s/%s/online", grp_dev, sub_dev)) ++ /* ++ * If not verbose mode, skip devices which are not supported ++ * by the zcrypt layer. ++ */ ++ if (l.verbose == 0 && ++ (!util_path_is_readable("%s/type", grp_dev) || ++ !util_path_is_readable("%s/%s/online", grp_dev, sub_dev))) + return; + + util_rec_set(rec, "card", sub_dev); +@@ -414,11 +455,13 @@ static void show_subdevices(struct util_rec *rec, const char *grp_dev) + */ + static void read_rec_default(struct util_rec *rec, const char *grp_dev) + { +- unsigned long facility; + char buf[256]; ++ unsigned long facility; + +- util_file_read_line(buf, sizeof(buf), "%s/type", grp_dev); +- util_rec_set(rec, "type", buf); ++ if (util_file_read_line(buf, sizeof(buf), "%s/type", grp_dev)) ++ util_rec_set(rec, "type", "-"); ++ else ++ util_rec_set(rec, "type", buf); + + util_file_read_ul(&facility, 16, "%s/ap_functions", grp_dev); + if (facility & MASK_COPRO) +@@ -430,14 +473,16 @@ static void read_rec_default(struct util_rec *rec, const char *grp_dev) + else + util_rec_set(rec, "mode", "Unknown"); + +- util_file_read_line(buf, sizeof(buf), "%s/online", grp_dev); +- if (strcmp(buf, "0") == 0) +- util_rec_set(rec, "online", "offline"); ++ if (util_file_read_line(buf, sizeof(buf), "%s/online", grp_dev)) ++ util_rec_set(rec, "online", "-"); + else +- util_rec_set(rec, "online", "online"); ++ if (strcmp(buf, "0") == 0) ++ util_rec_set(rec, "online", "offline"); ++ else ++ util_rec_set(rec, "online", "online"); + + util_file_read_line(buf, sizeof(buf), "%s/request_count", grp_dev); +- util_rec_set(rec, "request_count", buf); ++ util_rec_set(rec, "requests", buf); + } + + /* +@@ -445,18 +490,17 @@ static void read_rec_default(struct util_rec *rec, const char *grp_dev) + */ + static void read_rec_verbose(struct util_rec *rec, const char *grp_dev) + { ++ int i; + unsigned long facility; +- char buf[256]; +- long depth; ++ char buf[256], afile[PATH_MAX]; ++ long depth, pending1, pending2; + + if (l.verbose == 0) + return; + +- util_file_read_line(buf, sizeof(buf), "%s/pendingq_count", grp_dev); +- util_rec_set(rec, "pendingq_count", buf); +- +- util_file_read_line(buf, sizeof(buf), "%s/requestq_count", grp_dev); +- util_rec_set(rec, "requestq_count", buf); ++ util_file_read_l(&pending1, 10, "%s/pendingq_count", grp_dev); ++ util_file_read_l(&pending2, 10, "%s/requestq_count", grp_dev); ++ util_rec_set(rec, "pending", "%ld", pending1 + pending2); + + util_file_read_line(buf, sizeof(buf), "%s/hwtype", grp_dev); + util_rec_set(rec, "hwtype", buf); +@@ -465,7 +509,18 @@ static void read_rec_verbose(struct util_rec *rec, const char *grp_dev) + util_rec_set(rec, "depth", "%02d", depth + 1); + + util_file_read_ul(&facility, 16, "%s/ap_functions", grp_dev); +- util_rec_set(rec, "facility", "0x%08x", facility); ++ for (i = 0; i < MAX_FAC_BITS; i++) ++ buf[i] = facility & fac_bits[i].mask ? fac_bits[i].c : '-'; ++ buf[i] = '\0'; ++ util_rec_set(rec, "facility", buf); ++ ++ snprintf(afile, sizeof(afile), "%s/driver", grp_dev); ++ afile[sizeof(afile) - 1] = '\0'; ++ memset(buf, 0, sizeof(buf)); ++ if (readlink(afile, buf, sizeof(buf)) > 0) ++ util_rec_set(rec, "driver", strrchr(buf, '/') + 1); ++ else ++ util_rec_set(rec, "driver", "-no-driver-"); + } + + /* +@@ -481,9 +536,14 @@ static void show_device(struct util_rec *rec, const char *device) + grp_dev = util_path_sysfs("devices/ap/%s", device); + if (!util_path_is_dir(grp_dev)) + errx(EXIT_FAILURE, "Error - cryptographic device %s does not exist.", device); +- /* Skip devices, which are not supported by zcrypt layer */ +- if (!util_path_is_readable("%s/type", grp_dev) || +- !util_path_is_readable("%s/online", grp_dev)) { ++ ++ /* ++ * If not verbose mode, skip devices which are not supported ++ * by the zcrypt layer. ++ */ ++ if (l.verbose == 0 && ++ (!util_path_is_readable("%s/type", grp_dev) || ++ !util_path_is_readable("%s/online", grp_dev))) { + goto out_free; + } + util_rec_set(rec, "card", card); +@@ -506,8 +566,7 @@ static void define_rec_default(struct util_rec *rec) + util_rec_def(rec, "type", UTIL_REC_ALIGN_LEFT, 5, "TYPE"); + util_rec_def(rec, "mode", UTIL_REC_ALIGN_LEFT, 11, "MODE"); + util_rec_def(rec, "online", UTIL_REC_ALIGN_LEFT, 7, "STATUS"); +- util_rec_def(rec, "request_count", UTIL_REC_ALIGN_RIGHT, 11, +- "REQUEST_CNT"); ++ util_rec_def(rec, "requests", UTIL_REC_ALIGN_RIGHT, 8, "REQUESTS"); + } + + /* +@@ -517,13 +576,11 @@ static void define_rec_verbose(struct util_rec *rec) + { + if (l.verbose == 0) + return; +- util_rec_def(rec, "pendingq_count", UTIL_REC_ALIGN_RIGHT, 12, +- "PENDINGQ_CNT"); +- util_rec_def(rec, "requestq_count", UTIL_REC_ALIGN_RIGHT, 12, +- "REQUESTQ_CNT"); +- util_rec_def(rec, "hwtype", UTIL_REC_ALIGN_RIGHT, 7, "HW_TYPE"); +- util_rec_def(rec, "depth", UTIL_REC_ALIGN_RIGHT, 7, "Q_DEPTH"); ++ util_rec_def(rec, "pending", UTIL_REC_ALIGN_RIGHT, 8, "PENDING"); ++ util_rec_def(rec, "hwtype", UTIL_REC_ALIGN_RIGHT, 6, "HWTYPE"); ++ util_rec_def(rec, "depth", UTIL_REC_ALIGN_RIGHT, 6, "QDEPTH"); + util_rec_def(rec, "facility", UTIL_REC_ALIGN_LEFT, 10, "FUNCTIONS"); ++ util_rec_def(rec, "driver", UTIL_REC_ALIGN_LEFT, 11, "DRIVER"); + } + + /* +-- +2.21.0 + + +From 47e15616b0c81f85918794a0af2073aac6455826 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Dan=20Hor=C3=A1k?= +Date: Tue, 11 Dec 2018 09:46:40 +0100 +Subject: [PATCH 14/21] zkey: Fails to run commands generated by 'zkey + cryptsetup' (#1650628) + +Description: zkey: Fails to run commands generated by 'zkey cryptsetup' +Symptom: Fails to run commands generated by 'zkey cryptsetup'. +Problem: When using 'zkey cryptsetup' with --run option the + execution of the generated commands may fail, when + the executable to be run is located in '/sbin'. +Solution: Include /sbin into PATH when executing commands. +Reproduction: Use 'zkey cryptsetup' with option --run on a distribution + where 'cryptsetup' is located in '/sbin'. +Upstream-ID: 9100327092c470c2e5b5819087c8094822a1c751 +--- + zkey/keystore.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/zkey/keystore.c b/zkey/keystore.c +index 11f555c..a4ad634 100644 +--- a/zkey/keystore.c ++++ b/zkey/keystore.c +@@ -3235,7 +3235,7 @@ static int _keystore_execute_cmd(const char *cmd, + { + int rc; + +- rc = setenv("PATH", "/bin:/usr/bin:/usr/sbin", 1); ++ rc = setenv("PATH", "/bin:/sbin:/usr/bin:/usr/sbin", 1); + if (rc < 0) + return rc; + +-- +2.21.0 + + +From 3328fadb3147a24bae10495259fa7fd00b973eec Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Dan=20Hor=C3=A1k?= +Date: Tue, 11 Dec 2018 10:14:05 +0100 +Subject: [PATCH 15/21] zkey: Enhance error message about missing CCA library + (#1655134) + +Description: zkey: Enhance error message about missing CCA library. +Symptom: "zkey-cryptsetup reencipher" fails with missing + library and confusing error message. +Problem: The "zkey reencipher" command as well as the "zkey-cryptsetup + reencipher" command requires the IBM CCA Host Libraries and + Tools package to be installed. This is a closed source + library that is not distributed by the distributions, but + must be downloaded separately from an IBM web page. +Solution: Enhance the error message to point to the web page where + the package can be downloaded. +Reproduction: Run the "zkey-cryptsetup reencipher" or "zkey reencipher" + command without having installed the IBM CCA Host Libraries + and Tools package. +--- + zkey/pkey.c | 13 +++++++++---- + zkey/zkey-cryptsetup.1 | 3 ++- + zkey/zkey.1 | 3 ++- + 3 files changed, 13 insertions(+), 6 deletions(-) + +diff --git a/zkey/pkey.c b/zkey/pkey.c +index fe43d02..15e606a 100644 +--- a/zkey/pkey.c ++++ b/zkey/pkey.c +@@ -48,6 +48,7 @@ + * Definitions for the CCA library + */ + #define CCA_LIBRARY_NAME "libcsulcca.so" ++#define CCA_WEB_PAGE "http://www.ibm.com/security/cryptocards" + + #define DEFAULT_KEYBITS 256 + +@@ -71,16 +72,20 @@ int load_cca_library(void **lib_csulcca, t_CSNBKTC *dll_CSNBKTC, bool verbose) + /* Load the CCA library */ + *lib_csulcca = dlopen(CCA_LIBRARY_NAME, RTLD_GLOBAL | RTLD_NOW); + if (*lib_csulcca == NULL) { +- warnx("%s\nEnsure that the IBM CCA Host Libraries and " +- "Tools are installed properly", dlerror()); ++ pr_verbose(verbose, "%s", dlerror()); ++ warnx("The command requires the IBM CCA Host Libraries and " ++ "Tools.\nFor the supported environments and downloads, " ++ "see:\n%s", CCA_WEB_PAGE); + return -ELIBACC; + } + + /* Get the Key Token Change function */ + *dll_CSNBKTC = (t_CSNBKTC)dlsym(*lib_csulcca, "CSNBKTC"); + if (*dll_CSNBKTC == NULL) { +- warnx("%s\nEnsure that the IBM CCA Host Libraries and " +- "Tools are installed properly", dlerror()); ++ pr_verbose(verbose, "%s", dlerror()); ++ warnx("The command requires the IBM CCA Host Libraries and " ++ "Tools.\nFor the supported environments and downloads, " ++ "see:\n%s", CCA_WEB_PAGE); + dlclose(*lib_csulcca); + *lib_csulcca = NULL; + return -ELIBACC; +diff --git a/zkey/zkey-cryptsetup.1 b/zkey/zkey-cryptsetup.1 +index bf92e21..988ef76 100644 +--- a/zkey/zkey-cryptsetup.1 ++++ b/zkey/zkey-cryptsetup.1 +@@ -182,7 +182,8 @@ behave in the same way as with \fBcryptsetup\fP. + .PP + .B Note: + The \fBreencipher\fP command requires the CCA host library (libcsulcca.so) +-to be installed. ++to be installed. For the supported environments and downloads, see: ++\fIhttp://www.ibm.com/security/cryptocards\fP + . + . + . +diff --git a/zkey/zkey.1 b/zkey/zkey.1 +index c9f7906..0837b27 100644 +--- a/zkey/zkey.1 ++++ b/zkey/zkey.1 +@@ -282,7 +282,8 @@ a staged re-enciphering for the \fBOLD\fP to \fBCURRENT\fP case. + .PP + .B Note: + The \fBreencipher\fP command requires the CCA host library (libcsulcca.so) +-to be installed. ++to be installed. For the supported environments and downloads, see: ++\fIhttp://www.ibm.com/security/cryptocards\fP + . + .SS "Import existing AES secure keys into the secure key repository" + . +-- +2.21.0 + + +From ba7d612c055c887d5cbb596a369d32f00c47711d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Dan=20Hor=C3=A1k?= +Date: Tue, 29 Jan 2019 13:06:21 +0100 +Subject: [PATCH 16/21] zfcpdump: add install script for zfcpdump kernel + (#1600480) + +Summary: zfcpdump: add install script for zfcpdump kernel +Description: zipl expects to find the zfcpdump kernel at a specific location + (usually /usr/lib/s390-tools/zfcpdump/zfcpdump-image). During + kernel installation however, the kernels are installed to /boot. + In order for zipl to find the image add a script that manages a + link to the latest installed zfcpdump kernel at said location. +--- + .gitignore | 3 +- + common.mak | 7 +- + zfcpdump/10-zfcpdump.install.in | 114 ++++++++++++++++++++++++++++++++ + zfcpdump/Makefile | 22 ++++-- + zipl/include/zipl.h | 7 -- + zipl/src/Makefile | 7 +- + zipl/src/job.c | 10 +-- + 7 files changed, 143 insertions(+), 27 deletions(-) + create mode 100644 zfcpdump/10-zfcpdump.install.in + +diff --git a/.gitignore b/.gitignore +index 042233f..6cbec8c 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -76,7 +76,8 @@ zdsfs/zdsfs + zdump/zgetdump + zfcpdump/cpioinit + zfcpdump/zfcpdump_part +-zfcpdump/zfcpdump_part.rd ++zfcpdump/zfcpdump-initrd ++zfcpdump/10-zfcpdump.install + ziomon/ziomon_mgr + ziomon/ziomon_util + ziomon/ziomon_zfcpdd +diff --git a/common.mak b/common.mak +index 6f0990e..6029687 100644 +--- a/common.mak ++++ b/common.mak +@@ -182,9 +182,10 @@ GROUP = $(shell id -gn) + export INSTALLDIR BINDIR LIBDIR MANDIR OWNER GROUP + + # Special defines for zfcpdump +-ZFCPDUMP_PART_IMAGE = zfcpdump_part.image +-ZFCPDUMP_PART_RD = zfcpdump_part.rd +-export ZFCPDUMP_DIR ZFCPDUMP_PART_IMAGE ZFCPDUMP_PART_RD ++ZFCPDUMP_IMAGE = zfcpdump-image ++ZFCPDUMP_INITRD = zfcpdump-initrd ++ZFCPDUMP_FLAVOR = zfcpdump ++export ZFCPDUMP_DIR ZFCPDUMP_IMAGE ZFCPDUMP_INITRD ZFCPDUMP_FLAVOR + + CFLAGS ?= $(DEFAULT_CFLAGS) $(OPT_FLAGS) + HOSTCFLAGS ?= $(DEFAULT_CFLAGS) $(OPT_FLAGS) +diff --git a/zfcpdump/10-zfcpdump.install.in b/zfcpdump/10-zfcpdump.install.in +new file mode 100644 +index 0000000..37fde3b +--- /dev/null ++++ b/zfcpdump/10-zfcpdump.install.in +@@ -0,0 +1,114 @@ ++#!/bin/bash ++# ++# 10-zfcpdump.install - Installation script to handle zfcpdump kernels ++# ++# Copyright IBM Corp. 2018 ++# ++# s390-tools is free software; you can redistribute it and/or modify ++# it under the terms of the MIT license. See LICENSE for details. ++# ++# ++# This script supports two modes: ++# ++# 1) Installing the images to /boot// ++# subdirectories, i.e. BOOT_DIR_ABS, as recommended by the BLS. ++# In this case file names are taken over from the original files. ++# ++# 2) Installing the images directly to /boot. In this case the files are ++# renamed to -. ++# ++# The existence of BOOT_DIR_ABS is taken as trigger to switch between both ++# modes. ++# ++# The KERNEL_VERSION is assumed to contain '@flavor@' to identify the image ++# as a zfcpdump kernel. ++ ++COMMAND="$1" ++KERNEL_VERSION="$2" ++BOOT_DIR_ABS="$3" ++KERNEL_IMAGE="$4" ++ ++# Location zipl looks for the zfcpdump kernel ++ZFCPDUMP_IMAGE='@zfcpdump_image@' ++ ++# Only handle zfcpdump kernels ++echo "$KERNEL_VERSION" | grep -q '@flavor@' || exit 0 ++ ++case "$COMMAND" in ++ add) ++ KERNEL_DIR="$(dirname $KERNEL_IMAGE)" ++ KERNEL_NAME="$(basename $KERNEL_IMAGE)" ++ ++ for f in \ ++ "$KERNEL_IMAGE" \ ++ "$KERNEL_DIR"/System.map \ ++ "$KERNEL_DIR"/config \ ++ "$KERNEL_DIR"/zImage.stub ++ do ++ test -e "$f" || continue ++ test -d "$BOOT_DIR_ABS" \ ++ && DEST="$BOOT_DIR_ABS/$(basename $f)" \ ++ || DEST="/boot/$(basename $f)-$KERNEL_VERSION" ++ ++ cp -aT "$f" "$DEST" ++ test $(command -v restorecon) && restorecon -R "$DEST" ++ done ++ ++ # hmac file need special treatment ++ f="$KERNEL_DIR/.$KERNEL_NAME.hmac" ++ if [ -e "$f" ]; then ++ test -d "$BOOT_DIR_ABS" \ ++ && DEST="$BOOT_DIR_ABS/$(basename $f)" \ ++ || DEST="/boot/.$KERNEL_NAME-$KERNEL_VERSION.hmac" ++ ++ cp -aT "$f" "$DEST" ++ test $(command -v restorecon) && restorecon -R "$DEST" ++ fi ++ ++ # Set link so zipl finds the kernel ++ test -d "$BOOT_DIR_ABS" \ ++ && TARGET="$BOOT_DIR_ABS/$KERNEL_NAME" \ ++ || TARGET="/boot/$KERNEL_NAME-$KERNEL_VERSION" ++ ln -sf "$TARGET" "$ZFCPDUMP_IMAGE" ++ ;; ++ ++ remove) ++ # On removal ++ # $KERNEL_IMAGE is empty -> $KERNEL_NAME is empty -> rebuild it ++ KERNEL_NAME="$(basename $(readlink $ZFCPDUMP_IMAGE))" ++ if [ -d "$BOOT_DIR_ABS" ]; then ++ INSTALL_DIR="$(dirname $BOOT_DIR_ABS)" ++ else ++ INSTALL_DIR="/boot/" ++ KERNEL_NAME="$(echo $KERNEL_NAME \ ++ | sed -e "s#\(.*\)-$KERNEL_VERSION#\1#")" ++ fi ++ ++ for f in $(find "$INSTALL_DIR" -name "*$KERNEL_VERSION*"); do ++ rm -rf "$f" ++ done ++ ++ # Update link to latest remaining zfcpdump kernel. ++ if [ $(readlink "$ZFCPDUMP_IMAGE" | grep "$KERNEL_VERSION") ] ++ then ++ NEXT_IMAGE=$( \ ++ find "$INSTALL_DIR" -type f \ ++ | grep '@flavor@' \ ++ | grep "$KERNEL_NAME" \ ++ | grep -v "hmac" \ ++ | sort -V \ ++ | tail -n1 ) ++ ++ test $NEXT_IMAGE \ ++ && ln -sf "$NEXT_IMAGE" "$ZFCPDUMP_IMAGE" \ ++ || rm -f "$ZFCPDUMP_IMAGE" ++ fi ++ ;; ++ *) ++ ;; ++esac ++ ++# Prevent execution of all other scripts. ++# The zfcpdump kernel is stripped down to the bare minimum needed for ++# dumping. It is not supposed to be used for any other purpose. ++exit 77 +diff --git a/zfcpdump/Makefile b/zfcpdump/Makefile +index 5fcb073..cb2fd41 100644 +--- a/zfcpdump/Makefile ++++ b/zfcpdump/Makefile +@@ -1,6 +1,7 @@ + include ../common.mak + + CPIOINIT = $(call echocmd," CPIOINI ",/$@)./cpioinit ++INSTALL_SCRIPTS = 10-zfcpdump.install + + ifeq (${HAVE_LIBC_STATIC},0) + +@@ -20,7 +21,7 @@ check_dep: + "HAVE_LIBC_STATIC=0", \ + "-static") + +-all: check_dep $(ZFCPDUMP_PART_RD) ++all: check_dep $(ZFCPDUMP_INITRD) scripts + + cpioinit: cpioinit.c + $(HOSTCC) $(HOSTCFLAGS) -o $@ $^ +@@ -29,17 +30,26 @@ zfcpdump_part: zfcpdump.o zfcpdump_part.o + $(LINK) $(ALL_LDFLAGS) $^ -static -o $@ + $(STRIP) -s $@ + +-$(ZFCPDUMP_PART_RD): cpioinit zfcpdump_part ++$(ZFCPDUMP_INITRD): cpioinit zfcpdump_part + $(CPIOINIT) zfcpdump_part > $@.tmp + $(GZIP) -f $@.tmp +- $(MV) $@.tmp.gz $(ZFCPDUMP_PART_RD) ++ $(MV) $@.tmp.gz $(ZFCPDUMP_INITRD) ++ ++scripts: $(INSTALL_SCRIPTS) ++ chmod +x $(INSTALL_SCRIPTS) + + install: all +- $(INSTALL) -m 611 $(ZFCPDUMP_PART_RD) $(DESTDIR)$(ZFCPDUMP_DIR) ++ $(INSTALL) -m 611 $(ZFCPDUMP_INITRD) $(DESTDIR)$(ZFCPDUMP_DIR) + ++%: %.in ++ zfcpdump_image=$(ZFCPDUMP_DIR)/$(ZFCPDUMP_IMAGE); \ ++ $(SED) -e "s#@zfcpdump_image@#$$zfcpdump_image#g" \ ++ -e "s#@flavor@#$(ZFCPDUMP_FLAVOR)#g" \ ++ < $< > $@ + endif + + clean: +- rm -f *.o *.gz *.tmp *~ zfcpdump_part cpioinit $(ZFCPDUMP_PART_RD) ++ rm -f *.o *.gz *.tmp *~ zfcpdump_part cpioinit $(ZFCPDUMP_INITRD) \ ++ $(INSTALL_SCRIPTS) + +-.PHONY: all clean install check_dep ++.PHONY: all clean install check_dep scripts +diff --git a/zipl/include/zipl.h b/zipl/include/zipl.h +index 2aed54f..770801e 100644 +--- a/zipl/include/zipl.h ++++ b/zipl/include/zipl.h +@@ -48,13 +48,6 @@ + #define MENU_DEFAULT_PROMPT 0 + #define MENU_DEFAULT_TIMEOUT 0 + +-#define FSDUMP_IMAGE STRINGIFY(ZFCPDUMP_DIR) "/" STRINGIFY(ZFCPDUMP_FS_IMAGE) +-#define FSDUMP_RAMDISK STRINGIFY(ZFCPDUMP_DIR) "/" STRINGIFY(ZFCPDUMP_FS_RD) +-#define FSDUMP_PART_IMAGE STRINGIFY(ZFCPDUMP_DIR) "/" \ +- STRINGIFY(ZFCPDUMP_PART_IMAGE) +-#define FSDUMP_PART_RAMDISK STRINGIFY(ZFCPDUMP_DIR) "/" \ +- STRINGIFY(ZFCPDUMP_PART_RD) +- + #define MAX_DUMP_VOLUMES 32 + + /* Internal component load address type */ +diff --git a/zipl/src/Makefile b/zipl/src/Makefile +index 1634c0d..be14fce 100644 +--- a/zipl/src/Makefile ++++ b/zipl/src/Makefile +@@ -2,11 +2,8 @@ + include ../../common.mak + + ALL_CPPFLAGS += -I../include -I../boot \ +- -DZFCPDUMP_DIR=$(ZFCPDUMP_DIR) \ +- -DZFCPDUMP_FS_IMAGE=$(ZFCPDUMP_FS_IMAGE) \ +- -DZFCPDUMP_FS_RD=$(ZFCPDUMP_FS_RD) \ +- -DZFCPDUMP_PART_IMAGE=$(ZFCPDUMP_PART_IMAGE) \ +- -DZFCPDUMP_PART_RD=$(ZFCPDUMP_PART_RD) \ ++ -DZFCPDUMP_IMAGE="STRINGIFY($(ZFCPDUMP_DIR)/$(ZFCPDUMP_IMAGE))" \ ++ -DZFCPDUMP_INITRD="STRINGIFY($(ZFCPDUMP_DIR)/$(ZFCPDUMP_INITRD))" \ + -D_FILE_OFFSET_BITS=64 $(NO_PIE_CFLAGS) + ALL_LDFLAGS += -Wl,-z,noexecstack $(NO_PIE_LDFLAGS) + +diff --git a/zipl/src/job.c b/zipl/src/job.c +index e6d2981..22d2549 100644 +--- a/zipl/src/job.c ++++ b/zipl/src/job.c +@@ -874,22 +874,22 @@ check_job_dump_images(struct job_dump_data* dump, char* name) + { + int rc; + /* Add data needed to convert fs dump job to IPL job */ +- rc = misc_check_readable_file(FSDUMP_PART_IMAGE); ++ rc = misc_check_readable_file(ZFCPDUMP_IMAGE); + if (rc) { + error_text("Need external file '%s' for partition dump", +- FSDUMP_PART_IMAGE); ++ ZFCPDUMP_IMAGE); + return rc; + } +- dump->image = misc_strdup(FSDUMP_PART_IMAGE); ++ dump->image = misc_strdup(ZFCPDUMP_IMAGE); + if (dump->image == NULL) + return -1; + dump->image_addr = DEFAULT_IMAGE_ADDRESS; + + /* Ramdisk is no longer required with new initramfs dump system */ +- if (misc_check_readable_file(FSDUMP_PART_RAMDISK)) ++ if (misc_check_readable_file(ZFCPDUMP_INITRD)) + dump->ramdisk = NULL; + else { +- dump->ramdisk = misc_strdup(FSDUMP_PART_RAMDISK); ++ dump->ramdisk = misc_strdup(ZFCPDUMP_INITRD); + if (dump->ramdisk == NULL) + return -1; + dump->ramdisk_addr = UNSPECIFIED_ADDRESS; +-- +2.21.0 + + +From eef1d70b8bd0ec96aa90f5dad9795196c85382ce Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Dan=20Hor=C3=A1k?= +Date: Wed, 9 Jan 2019 13:58:10 +0100 +Subject: [PATCH 17/21] pkey: Support autoloading kernel pkey module (#1664632) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The module is loaded automatically based on CPU features, but it's still +too late in some use cases. Thus allow distros to use explicit loading. + +See also: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=63c19be095d0f8eb8992674991e44b4228bd4179 + +Closes: https://github.com/ibm-s390-tools/s390-tools/pull/51 +Signed-off-by: Dan Horák +Reviewed-by: Ingo Franzki +Signed-off-by: Jan Höppner +(cherry picked from commit dffd41943e5c01be2f343da7726edabf9d2ec05e) +--- + etc/modules-load.d/s390-pkey.conf | 2 ++ + 1 file changed, 2 insertions(+) + create mode 100644 etc/modules-load.d/s390-pkey.conf + +diff --git a/etc/modules-load.d/s390-pkey.conf b/etc/modules-load.d/s390-pkey.conf +new file mode 100644 +index 0000000..972a099 +--- /dev/null ++++ b/etc/modules-load.d/s390-pkey.conf +@@ -0,0 +1,2 @@ ++# Load protected key support module on s390 early at boot ++pkey +-- +2.21.0 + + +From 7a3ba6fb39f015da0ee10e1dc0e14ae9fcf6347f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Dan=20Hor=C3=A1k?= +Date: Tue, 21 May 2019 13:39:08 +0200 +Subject: [PATCH 18/21] zipl: Secure Boot support for SCSI IPL (#1659401) + +Description: The Secure Boot firmware feature ensures that only signed + and verified code is executed during IPL. + This feature adds support for secure boot to the zipl + tool and internal loader. + +Upstream-ID: e764f460c457ab2a6000acb5f2eb7169866ce192 +Upstream-ID: 6825645a21a3221629e7d5aa9d5cfbf6e3bc4188 +Upstream-ID: 0c1a63ce5ec6059374d9f8dd55bffbb42ef9bd45 +Upstream-ID: 7c7e10ed8fb048efc4e0cd91b0f6fa704fba128e +Upstream-ID: 58a7462f65d85726168303bd58e7472bd4c82731 +Upstream-ID: 75d4317f208da1e25afd520fe43a1786333388ad +Upstream-ID: dc2e4395506956a99819484d8938e877c4c2cd88 +Upstream-ID: 7e7a77675d2b88b3d516d60aa64f2b1264b25117 +Upstream-ID: 331b54d573c38c7eed6617eef69cf296c2e86d6d +Upstream-ID: 6ea645b3453264a0f1a60955c4476dab54035f88 +--- + zipl/boot/Makefile | 26 ++- + zipl/boot/error.h | 3 + + zipl/boot/libc.c | 20 ++ + zipl/boot/libc.h | 1 + + zipl/boot/s390.h | 5 + + zipl/boot/stage2.c | 9 +- + zipl/boot/stage2.h | 3 +- + zipl/boot/stage2.lds | 5 +- + zipl/boot/stage3.c | 114 ++++++++--- + zipl/boot/stage3.h | 142 ++++++++++++++ + zipl/boot/stage3.lds | 38 ++-- + zipl/include/boot.h | 11 +- + zipl/include/bootmap.h | 31 +++ + zipl/include/job.h | 1 + + zipl/include/misc.h | 1 + + zipl/include/scan.h | 3 +- + zipl/include/zipl.h | 15 +- + zipl/man/zipl.8 | 15 ++ + zipl/man/zipl.conf.5 | 27 +++ + zipl/src/Makefile | 7 +- + zipl/src/boot.c | 33 ++-- + zipl/src/bootmap.c | 417 +++++++++++++++++++++++++++++++++-------- + zipl/src/job.c | 44 ++++- + zipl/src/misc.c | 1 - + zipl/src/scan.c | 34 ++-- + 25 files changed, 837 insertions(+), 169 deletions(-) + +diff --git a/zipl/boot/Makefile b/zipl/boot/Makefile +index 52b3a23..da7e95f 100644 +--- a/zipl/boot/Makefile ++++ b/zipl/boot/Makefile +@@ -13,10 +13,9 @@ FILES = fba0.bin fba1b.bin fba2.bin \ + eckd0_ldl.bin eckd0_cdl.bin \ + eckd1.bin eckd1b.bin eckd2.bin \ + tape0.bin \ +- eckd2dump_sv.bin tape2dump.bin fba2dump.bin eckd2dump_mv.bin \ +- stage3.bin ++ eckd2dump_sv.bin tape2dump.bin fba2dump.bin eckd2dump_mv.bin + +-all: data.o data.h tape0.bin ++all: data.o data.h tape0.bin stage3.bin + + # Prevent make from using some default rules... + %: %.S +@@ -44,7 +43,7 @@ eckd2.exec: head.o stage2.o cio.o eckd2.o libc.o menu.o sclp.o \ + fba2.exec: head.o stage2.o cio.o fba2.o libc.o menu.o sclp.o \ + kdump2.o kdump.o entry.o + stage3.exec: head.o stage3.o kdump3.o libc.o sclp.o sclp_stage3.o \ +- kdump.o entry.o ++ kdump.o entry.o stage3.lds + + %.exec: %.o + @STAGE=$$( \ +@@ -77,6 +76,22 @@ stage3.exec: head.o stage3.o kdump3.o libc.o sclp.o sclp_stage3.o \ + --only-section=.fixup \ + $< $@ + ++stage3.bin: stage3.exec ++ $(OBJCOPY) -O binary \ ++ --only-section=.stage2.head \ ++ --only-section=.text.dummy \ ++ --only-section=.text.start \ ++ --only-section=.text \ ++ --only-section=.ex_table \ ++ --only-section=.data \ ++ --only-section=.rodata.str1.2 \ ++ --only-section=.rodata \ ++ --only-section=.stage2dump.tail \ ++ --only-section=.eckd2dump_mv.tail \ ++ --only-section=.fixup \ ++ --pad-to=0xf000 \ ++ $< $@ ++ + data.o: $(FILES) + $(LD) $(NO_PIE_LDFLAGS) -r -b binary -o data.o $(FILES) + +@@ -86,6 +101,7 @@ data.h: data.o + echo "extern char $$SYMBOL;" >>data.h; done + + clean: +- rm -f *.o *.exec *.bin $(FILES) data.o data.h tape0.bin *.xxx *.yyy ++ rm -f *.o *.exec *.bin $(FILES) data.o data.h tape0.bin *.xxx *.yyy \ ++ stage3.bin + + .PHONY: all clean +diff --git a/zipl/boot/error.h b/zipl/boot/error.h +index 93fd748..715973e 100644 +--- a/zipl/boot/error.h ++++ b/zipl/boot/error.h +@@ -31,6 +31,9 @@ + /* Internal error */ + #define EINTERNAL 0x00004511 + ++/* Secure IPL error */ ++#define ESECUREBOOT 0x00004512 ++ + /* kdump: No operating system information was found */ + #define EOS_INFO_MISSING 0x00004520 + +diff --git a/zipl/boot/libc.c b/zipl/boot/libc.c +index f86f62a..5944c4e 100644 +--- a/zipl/boot/libc.c ++++ b/zipl/boot/libc.c +@@ -58,6 +58,26 @@ void *memcpy(void *dest, const void *src, unsigned long n) + return dest; + } + ++/* ++ * Move @n bytes of memory from @src to @dest. The memory regions may overlap. ++ */ ++void *memmove(void *dest, const void *src, unsigned long n) ++{ ++ const char *s = src; ++ char *d = dest; ++ ++ if (s < d) { ++ d += n; ++ s += n; ++ while (n--) ++ *--d = *--s; ++ } else { ++ while (n--) ++ *d++ = *s++; ++ } ++ return dest; ++} ++ + /* + * Copy string + */ +diff --git a/zipl/boot/libc.h b/zipl/boot/libc.h +index b05a116..44097fa 100644 +--- a/zipl/boot/libc.h ++++ b/zipl/boot/libc.h +@@ -49,6 +49,7 @@ typedef unsigned char uint8_t; + void printf(const char *, ...); + void sprintf(char *, const char *, ...); + void *memcpy(void *, const void *, unsigned long); ++void *memmove(void *, const void *, unsigned long); + void *memset(void *, int c, unsigned long); + char *strcat(char *, const char *); + int strncmp(const char *, const char *, unsigned long); +diff --git a/zipl/boot/s390.h b/zipl/boot/s390.h +index 279d16b..6e5a7ae 100644 +--- a/zipl/boot/s390.h ++++ b/zipl/boot/s390.h +@@ -35,6 +35,11 @@ struct psw_t { + uint64_t addr; + } __aligned(8); + ++struct psw32_t { ++ uint32_t mask; ++ uint32_t addr; ++} __aligned(8); ++ + void load_wait_psw(uint64_t, struct psw_t *); + + struct _lowcore { +diff --git a/zipl/boot/stage2.c b/zipl/boot/stage2.c +index 02d644e..99e1bd1 100644 +--- a/zipl/boot/stage2.c ++++ b/zipl/boot/stage2.c +@@ -115,8 +115,13 @@ void start(void) + /* skip header */ + entry = (struct component_entry *) + (load_address + sizeof(struct component_header)); +- +- while (entry->type == COMPONENT_LOAD) { ++ while (entry->type == COMPONENT_LOAD || ++ entry->type == COMPONENT_SIGNATURE) { ++ if (entry->type == COMPONENT_SIGNATURE) { ++ /* Skip unhandled signature components */ ++ entry++; ++ continue; ++ } + load_address = (void *)(unsigned long) + entry->address.load_address[1]; + load_blocklist(entry, subchannel_id, load_address); +diff --git a/zipl/boot/stage2.h b/zipl/boot/stage2.h +index b79c798..8fd5bd3 100644 +--- a/zipl/boot/stage2.h ++++ b/zipl/boot/stage2.h +@@ -61,7 +61,8 @@ struct component_entry { + + typedef enum { + COMPONENT_EXECUTE = 0x01, +- COMPONENT_LOAD = 0x02 ++ COMPONENT_LOAD = 0x02, ++ COMPONENT_SIGNATURE = 0x03 + } component_type; + + struct stage2_descr { +diff --git a/zipl/boot/stage2.lds b/zipl/boot/stage2.lds +index befe8e2..41efa79 100644 +--- a/zipl/boot/stage2.lds ++++ b/zipl/boot/stage2.lds +@@ -9,7 +9,8 @@ + * 0x2000-0x4fff Sections (load): head, text, data, rodata, rodata.str + * 0x5000-0x51ff eckd2dump_mv parameter block (426 bytes) + * 0x5200-0x5fff Sections: bss +- * 0x6000-0x9fff Memory allocation (heap) ++ * 0x6000-0x8fff Memory allocation (heap) ++ * 0x9000-0x9fff Memory to load stage3 parameter to + * 0xa000-0xdfff Memory to load stage3 to + * 0xe000-0xffff Stack + * +@@ -52,7 +53,7 @@ SECTIONS + + . = 0x6000; + __heap_start = .; +- . = 0xa000; ++ . = 0x9000; + __heap_stop = .; + + . = 0xf000; +diff --git a/zipl/boot/stage3.c b/zipl/boot/stage3.c +index eb02627..f7a9597 100644 +--- a/zipl/boot/stage3.c ++++ b/zipl/boot/stage3.c +@@ -12,35 +12,15 @@ + #include "libc.h" + #include "s390.h" + #include "stage3.h" ++#include "error.h" + +-/* +- * 48 Byte dummy space for external symbols +- * _parm_addr; address of parmline +- * _initrd_addr; address of initrd +- * _initrd_len; length of initrd +- * _load_psw; load psw of kernel +- * _extra_parm; use extra parm line mechanism? +- * stage3_flags; flags (e.g. STAGE3_FLAG_KDUMP) +- * +- * needed to blow up the binary and leave room +- */ +-__attribute__ ((section(".text.dummy"))) void _dummy(void) +-{ +- asm volatile( +- ".long 0x00000000\n" +- ".long 0x00000000\n" +- ".long 0x00000000\n" +- ".long 0x00000000\n" +- ".long 0x00000000\n" +- ".long 0x00000000\n" +- ".long 0x00000000\n" +- ".long 0x00000000\n" +- ".long 0x00000000\n" +- ".long 0x00000000\n" +- ".long 0x00000000\n" +- ".long 0x00000000\n" +- ); +-} ++#define for_each_rb_entry(entry, rb) \ ++ for (entry = rb->entries; \ ++ (void *) entry + sizeof(*entry) <= (void *) rb + rb->len; \ ++ entry++) ++ ++static const char *msg_sipl_inval = "Secure boot failure: invalid load address"; ++static const char *msg_sipl_unverified = "Secure boot failure: unverified load address"; + + static unsigned char ebc_037[256] = { + /* 0x00 NUL SOH STX ETX *SEL HT *RNL DEL */ +@@ -221,6 +201,64 @@ start_kernel(void) + : [psw] "a" (psw) ); + } + ++unsigned int ++is_verified_address(unsigned long image_addr) ++{ ++ struct ipl_rb_component_entry *comp; ++ struct ipl_rb_components *comps; ++ struct ipl_pl_hdr *pl_hdr; ++ struct ipl_rl_hdr *rl_hdr; ++ struct ipl_rb_hdr *rb_hdr; ++ unsigned long tmp; ++ void *rl_end; ++ ++ /* ++ * There is an IPL report, to find it load the pointer to the ++ * IPL parameter information block from lowcore and skip past ++ * the IPL parameter list, then align the address to a double ++ * word boundary. ++ */ ++ tmp = (unsigned long) S390_lowcore.ipl_parmblock_ptr; ++ pl_hdr = (struct ipl_pl_hdr *) tmp; ++ tmp = (tmp + pl_hdr->len + 7) & -8UL; ++ rl_hdr = (struct ipl_rl_hdr *) tmp; ++ /* Walk through the IPL report blocks in the IPL Report list */ ++ comps = NULL; ++ rl_end = (void *) rl_hdr + rl_hdr->len; ++ rb_hdr = (void *) rl_hdr + sizeof(*rl_hdr); ++ while ((void *) rb_hdr + sizeof(*rb_hdr) < rl_end && ++ (void *) rb_hdr + rb_hdr->len <= rl_end) { ++ switch (rb_hdr->rbt) { ++ case IPL_RBT_COMPONENTS: ++ comps = (struct ipl_rb_components *) rb_hdr; ++ break; ++ default: ++ break; ++ } ++ ++ rb_hdr = (void *) rb_hdr + rb_hdr->len; ++ } ++ for_each_rb_entry(comp, comps) { ++ if (image_addr == comp->addr && ++ comp->flags & IPL_RB_COMPONENT_FLAG_SIGNED && ++ comp->flags & IPL_RB_COMPONENT_FLAG_VERIFIED) ++ return 1; ++ } ++ return 0; ++} ++ ++unsigned int ++secure_boot_enabled() ++{ ++ struct ipl_pl_hdr *pl_hdr; ++ unsigned long tmp; ++ ++ tmp = (unsigned long) S390_lowcore.ipl_parmblock_ptr; ++ pl_hdr = (struct ipl_pl_hdr *) tmp; ++ ++ return pl_hdr->flags & IPL_FLAG_SECURE; ++} ++ + void start(void) + { + unsigned int subchannel_id; +@@ -228,6 +266,26 @@ void start(void) + unsigned char *command_line = (unsigned char *)COMMAND_LINE; + unsigned int begin = 0, end = 0, length = 0; + ++ /* ++ * IPL process is secure we have to use default IPL values and ++ * check if the psw jump address is within at the start of a ++ * verified component. If it is not IPL is aborted. ++ */ ++ if (secure_boot_enabled()) { ++ if (_image_addr != DEFAULT_IMAGE_ADDR || ++ _load_psw != DEFAULT_PSW_LOAD) ++ panic(ESECUREBOOT, "%s", msg_sipl_inval); ++ ++ if (!is_verified_address(_load_psw & PSW_ADDR_MASK)) ++ panic(ESECUREBOOT, "%s", msg_sipl_unverified); ++ } ++ /* ++ * cut the kernel header ++ */ ++ memmove((void *)_image_addr, ++ (void *)_image_addr + KERNEL_HEADER_SIZE, ++ _image_len - KERNEL_HEADER_SIZE); ++ + /* store subchannel ID into low core and into new kernel space */ + subchannel_id = S390_lowcore.subchannel_id; + *(unsigned int *)__LC_IPLDEV = subchannel_id; +diff --git a/zipl/boot/stage3.h b/zipl/boot/stage3.h +index cdc0d77..91477b1 100644 +--- a/zipl/boot/stage3.h ++++ b/zipl/boot/stage3.h +@@ -27,14 +27,156 @@ + #define STAGE3_FLAG_SCSI 0x0001000000000000ULL + #define STAGE3_FLAG_KDUMP 0x0002000000000000ULL + ++#define IPL_FLAG_SECURE 0x40 ++ ++#define DEFAULT_IMAGE_ADDR 0x10000 ++#define DEFAULT_PSW_LOAD 0x0008000080010000L ++#define PSW_ADDR_MASK 0x000000007FFFFFFFL ++#define KERNEL_HEADER_SIZE 65536 ++ + #define UNSPECIFIED_ADDRESS -1ULL + ++ ++/* IPL Parameter List header */ ++struct ipl_pl_hdr { ++ uint32_t len; ++ uint8_t flags; ++ uint8_t reserved1[2]; ++ uint8_t version; ++} __packed; ++ ++/* IPL Parameter Block header */ ++struct ipl_pb_hdr { ++ uint32_t len; ++ uint8_t pbt; ++} __packed; ++ ++/* IPL Parameter Block 0 with common fields */ ++struct ipl_pb0_common { ++ uint32_t len; ++ uint8_t pbt; ++ uint8_t flags; ++ uint8_t reserved1[2]; ++ uint8_t loadparm[8]; ++ uint8_t reserved2[84]; ++} __packed; ++ ++/* IPL Parameter Block 0 for FCP */ ++struct ipl_pb0_fcp { ++ uint32_t len; ++ uint8_t pbt; ++ uint8_t reserved1[3]; ++ uint8_t loadparm[8]; ++ uint8_t reserved2[304]; ++ uint8_t opt; ++ uint8_t reserved3[3]; ++ uint8_t cssid; ++ uint8_t reserved4[1]; ++ uint8_t devno; ++ uint8_t reserved5[4]; ++ uint64_t wwpn; ++ uint64_t lun; ++ uint32_t bootprog; ++ uint8_t reserved6[12]; ++ uint64_t br_lba; ++ uint32_t scp_data_len; ++ uint8_t reserved7[260]; ++ uint8_t scp_data[]; ++} __packed; ++ ++/* IPL Parameter Block 0 for CCW */ ++struct ipl_pb0_ccw { ++ uint32_t len; ++ uint8_t pbt; ++ uint8_t flags; ++ uint8_t reserved1[2]; ++ uint8_t loadparm[8]; ++ uint8_t reserved2[84]; ++ uint16_t reserved3 : 13; ++ uint8_t ssid : 3; ++ uint16_t devno; ++ uint8_t vm_flags; ++ uint8_t reserved4[3]; ++ uint32_t vm_parm_len; ++ uint8_t nss_name[8]; ++ uint8_t vm_parm[64]; ++ uint8_t reserved5[8]; ++} __packed; ++ ++struct ipl_parameter_block { ++ struct ipl_pl_hdr hdr; ++ union { ++ struct ipl_pb_hdr pb0_hdr; ++ struct ipl_pb0_common common; ++ struct ipl_pb0_fcp fcp; ++ struct ipl_pb0_ccw ccw; ++ char raw[PAGE_SIZE - sizeof(struct ipl_pl_hdr)]; ++ }; ++} __packed __aligned(PAGE_SIZE); ++ ++/* IPL Report List header */ ++struct ipl_rl_hdr { ++ uint32_t len; ++ uint8_t flags; ++ uint8_t reserved1[2]; ++ uint8_t version; ++ uint8_t reserved2[8]; ++} __packed; ++ ++/* IPL Report Block header */ ++struct ipl_rb_hdr { ++ uint32_t len; ++ uint8_t rbt; ++ uint8_t reserved1[11]; ++} __packed; ++ ++/* IPL Report Block types */ ++enum ipl_rbt { ++ IPL_RBT_CERTIFICATES = 1, ++ IPL_RBT_COMPONENTS = 2, ++}; ++ ++/* IPL Report Block for the certificate list */ ++struct ipl_rb_certificate_entry { ++ uint64_t addr; ++ uint64_t len; ++} __packed; ++ ++struct ipl_rb_certificates { ++ uint32_t len; ++ uint8_t rbt; ++ uint8_t reserved1[11]; ++ struct ipl_rb_certificate_entry entries[]; ++} __packed; ++ ++/* IPL Report Block for the component list */ ++struct ipl_rb_component_entry { ++ uint64_t addr; ++ uint64_t len; ++ uint8_t flags; ++ uint8_t reserved1[5]; ++ uint16_t certificate_index; ++ uint8_t reserved2[8]; ++}; ++ ++#define IPL_RB_COMPONENT_FLAG_SIGNED 0x80 ++#define IPL_RB_COMPONENT_FLAG_VERIFIED 0x40 ++ ++struct ipl_rb_components { ++ uint32_t len; ++ uint8_t rbt; ++ uint8_t reserved1[11]; ++ struct ipl_rb_component_entry entries[]; ++} __packed; ++ + extern unsigned long long _parm_addr; /* address of parmline */ + extern unsigned long long _initrd_addr; /* address of initrd */ + extern unsigned long long _initrd_len; /* length of initrd */ + extern unsigned long long _load_psw; /* load psw of kernel */ + extern unsigned long long _extra_parm; /* use extra parm line mechanism? */ + extern unsigned long long stage3_flags; /* flags (e.g. STAGE3_FLAG_KDUMP) */ ++extern unsigned long long _image_len; /* length of kernel */ ++extern unsigned long long _image_addr; /* target address of kernel */ + extern void kdump_stage3(); + + #endif /* STAGE3_H */ +diff --git a/zipl/boot/stage3.lds b/zipl/boot/stage3.lds +index 638fb25..c67bc32 100644 +--- a/zipl/boot/stage3.lds ++++ b/zipl/boot/stage3.lds +@@ -1,33 +1,47 @@ + /* + * Memory layout for stage 3 ++ * ========================= ++ * ++ * General memory layout ++ * --------------------- ++ * ++ * 0x0000-0x1fff Lowcore ++ * 0x2000-0x5fff Memory allocation (heap) ++ * 0x6000-0x8fff free ++ * 0x9000-0x9fff Stage3 parameter ++ * 0xa000-0xdfff Stage3 code + data ++ * 0xe000-0xffff Stack + */ + + SECTIONS + { + . = 0x0; + +- . = 0x7000; ++ . = 0x2000; + __heap_start = .; +- . = 0xa000; ++ . = 0x6000; + __heap_stop = .; + +- . = 0xa000; ++ ++ /* stage 3 parameter */ ++ . = 0x9000; + _parm_addr = .; +- . = 0xa008; ++ . = 0x9008; + _initrd_addr = .; +- . = 0xa010; ++ . = 0x9010; + _initrd_len = .; +- . = 0xa018; ++ . = 0x9018; + _load_psw = .; +- . = 0xa020; ++ . = 0x9020; + _extra_parm = .; +- . = 0xa028; ++ . = 0x9028; + stage3_flags =.; ++ . = 0x9030; ++ _image_len = .; ++ . = 0x9038; ++ _image_addr = .; + + . = 0xa000; +- .text.dummy : { *(.text.dummy) } +- +- . = 0xa050; + .text.start : { *(.text.start) } + .text : { *(.text) } + __ex_table_start = .; +@@ -35,11 +49,9 @@ SECTIONS + __ex_table_stop = .; + .eh_frame : { *(.eh_frame) } + +- . = 0xc000; + __bss_start = .; + .bss : { *(.bss) } + __bss_stop = .; + .rodata : {*(.rodata) } + .data : { *(.data) } +- + } +diff --git a/zipl/include/boot.h b/zipl/include/boot.h +index f21ab59..6bd2a9b 100644 +--- a/zipl/include/boot.h ++++ b/zipl/include/boot.h +@@ -248,6 +248,9 @@ struct boot_stage3_params { + uint64_t load_psw; + uint64_t extra_parm; + uint16_t flags; ++ uint16_t reserved[3]; ++ uint64_t image_len; ++ uint64_t image_addr; + } __attribute__ ((packed)); + + #define STAGE3_FLAG_SCSI 0x0001 +@@ -305,10 +308,10 @@ int boot_init_fba_stage1b(struct boot_fba_stage1b *stage1b, + disk_blockptr_t *stage2_list, + blocknum_t stage2_count); + int boot_get_eckd_stage2(void** data, size_t* size, struct job_data* job); +-size_t get_stage3_size(); +-int boot_get_stage3(void** buffer, size_t* bytecount, address_t parm_addr, +- address_t initrd_addr, size_t initrd_len, +- address_t image_addr, int extra_parm, uint16_t flags); ++int boot_get_stage3_parms(void **buffer, size_t *bytecount, address_t parm_addr, ++ address_t initrd_addr, size_t initrd_len, ++ address_t load_addr, int extra_parm, uint16_t flags, ++ size_t image_len); + int boot_get_tape_ipl(void** data, size_t* size, address_t parm_addr, + address_t initrd_addr, address_t image_addr); + int boot_get_tape_dump(void** data, size_t* size, uint64_t mem); +diff --git a/zipl/include/bootmap.h b/zipl/include/bootmap.h +index c03c041..4a0bd04 100644 +--- a/zipl/include/bootmap.h ++++ b/zipl/include/bootmap.h +@@ -16,6 +16,37 @@ + #include "job.h" + #include "zipl.h" + ++#define SIGNATURE_MAGIC "~Module signature appended~\n" ++#define PKCS7_FORMAT 0x01 ++ ++struct signature_header { ++ uint8_t format; ++ uint8_t reserved[3]; ++ uint32_t length; ++} __attribute((packed)); ++ ++typedef union { ++ uint64_t load_address; ++ uint64_t load_psw; ++ struct signature_header sig_head; ++} component_data; ++ ++/* ++ * The file_signature structure and the PKEY_ID definition ++ * are based on linux/scripts/sign-file.c ++ */ ++struct file_signature { ++ u8 algorithm; ++ u8 hash; ++ u8 id_type; ++ u8 signer_len; ++ u8 key_id_len; ++ u8 __pad[3]; ++ u32 sig_len; ++ char magic[28]; ++}; ++ ++#define PKEY_ID_PKCS7 0x02 + + int bootmap_create(struct job_data* job, disk_blockptr_t* program_table, + disk_blockptr_t *scsi_dump_sb_blockptr, +diff --git a/zipl/include/job.h b/zipl/include/job.h +index 4c9253f..fce811c 100644 +--- a/zipl/include/job.h ++++ b/zipl/include/job.h +@@ -121,6 +121,7 @@ struct job_data { + int add_files; + int dry_run; + int command_line; ++ int is_secure; + }; + + +diff --git a/zipl/include/misc.h b/zipl/include/misc.h +index 37a8a87..5a349a7 100644 +--- a/zipl/include/misc.h ++++ b/zipl/include/misc.h +@@ -51,6 +51,7 @@ int misc_check_readable_file(const char* filename); + int misc_check_writable_device(const char* devno, int blockdev, int chardev); + void misc_ebcdic_to_ascii(unsigned char *from, unsigned char *to); + void misc_ascii_to_ebcdic(unsigned char *from, unsigned char *to); ++unsigned int misc_check_secure_boot(void); + + #define ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) + #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) +diff --git a/zipl/include/scan.h b/zipl/include/scan.h +index 0fe415c..4dcee0b 100644 +--- a/zipl/include/scan.h ++++ b/zipl/include/scan.h +@@ -16,7 +16,7 @@ + + + #define SCAN_SECTION_NUM 9 +-#define SCAN_KEYWORD_NUM 21 ++#define SCAN_KEYWORD_NUM 22 + #define SCAN_KEYWORD_ONLY_NUM 1 + #define SCAN_AUTOMENU_NAME "zipl-automatic-menu" + +@@ -51,6 +51,7 @@ enum scan_keyword_id { + scan_keyword_targetoffset = 18, + scan_keyword_defaultauto = 19, + scan_keyword_kdump = 20, ++ scan_keyword_secure = 21, + }; + + enum scan_section_type { +diff --git a/zipl/include/zipl.h b/zipl/include/zipl.h +index 770801e..6f2d115 100644 +--- a/zipl/include/zipl.h ++++ b/zipl/include/zipl.h +@@ -20,10 +20,11 @@ + #define DISK_LAYOUT_ID 0x00000001 + + #define ZIPL_STAGE2_LOAD_ADDRESS 0x2000 +-#define ZIPL_STAGE3_ENTRY_ADDRESS 0xa050LL ++#define ZIPL_STAGE3_ENTRY_ADDRESS 0xa000LL + #define DEFAULT_IMAGE_ADDRESS 0x10000LL + #define KDUMP_IMAGE_ADDRESS 0x10010LL + #define DEFAULT_STAGE3_ADDRESS 0xa000LL ++#define DEFAULT_STAGE3_PARAMS_ADDRESS 0x9000LL + #define MINIMUM_ADDRESS 0x10000LL + #define ADDRESS_LIMIT 0x80000000LL + #define ADDRESS_LIMIT_KDUMP 0x2000000UL /* HSA size: 32 MiB */ +@@ -31,11 +32,15 @@ + #define MAXIMUM_PARMLINE_SIZE 0x380 + #define MAXIMUM_PHYSICAL_BLOCKSIZE 0x1000 + ++#define STAGE3_HEAP_SIZE 0x4000 ++#define STAGE3_HEAP_ADDRESS 0x2000 ++#define STAGE3_STACK_SIZE 0x1000 ++#define STAGE3_STACK_ADDRESS 0xF000 ++ + #define PSW_ADDRESS_MASK 0x000000007fffffffLL + #define PSW_LOAD 0x0008000080000000LL + #define PSW_DISABLED_WAIT 0x000a000000000000LL + +-#define KERNEL_HEADER_SIZE 65536 + #define BOOTMAP_FILENAME "bootmap" + #define BOOTMAP_TEMPLATE_FILENAME "bootmap_temp.XXXXXX" + +@@ -44,12 +49,18 @@ + #define ZIPL_CONF_VAR "ZIPLCONF" + #define ZIPL_DEFAULT_CONF "/etc/zipl.conf" + #define ZIPL_DEFAULT_BLSDIR "/boot/loader/entries" ++#define ZIPL_STAGE3_PATH TOOLS_LIBDIR "/stage3.bin" ++#define ZIPL_SIPL_PATH "/sys/firmware/ipl/has_secure" + + #define MENU_DEFAULT_PROMPT 0 + #define MENU_DEFAULT_TIMEOUT 0 + + #define MAX_DUMP_VOLUMES 32 + ++#define SECURE_BOOT_DISABLED 0 ++#define SECURE_BOOT_ENABLED 1 ++#define SECURE_BOOT_AUTO 2 ++ + /* Internal component load address type */ + typedef uint64_t address_t; + +diff --git a/zipl/man/zipl.8 b/zipl/man/zipl.8 +index 9891975..2f873f3 100644 +--- a/zipl/man/zipl.8 ++++ b/zipl/man/zipl.8 +@@ -352,6 +352,21 @@ whether they contain a dump signature or not. + This option can only be used together with + .BR \-\-mvdump . + ++.TP ++.BR "\-S " " or " "\-\-secure " ++Control the zIPL secure boot support. ++ can take one of three values: ++ ++ auto (default) ++ Write signatures if available and supported by the system. ++ 1 ++ Signatures are written independent of support indicated by the local ++ system. Also missing signatures for stage 3 and kernel IPL files ++ will result in an error. ++ 0 ++ No signatures will be written. ++ ++ + .SH EXAMPLE + 1. Scenario: prepare disk for booting a Linux kernel image using the + following parameters: +diff --git a/zipl/man/zipl.conf.5 b/zipl/man/zipl.conf.5 +index d4877d8..71d1252 100644 +--- a/zipl/man/zipl.conf.5 ++++ b/zipl/man/zipl.conf.5 +@@ -82,6 +82,8 @@ below). + .br + defaultmenu = menu1 + .br ++secure = auto ++.br + + [linux] + .br +@@ -517,6 +519,31 @@ An optional hexadecimal address may be provided to load the kernel to a + non-default memory location. + .PP + ++.B secure ++= ++.IR auto / 1 / 0 ++(configuration only) ++.IP ++.B Configuration section: ++.br ++Control the zIPL secure boot support. ++Set this option to one of the following: ++.IP " - " 12 ++.BR auto: ++Write signatures if available and supported by the system. ++.IP " - " 12 ++.BR 1: ++Signatures are written independent of support indicated by the local system. ++Also missing signatures for stage 3 and kernel IPL files will result in an error. ++.IP " - " 12 ++.BR 0: ++No signatures will be written. ++ ++The default value for ++.B 'secure' ++is auto. ++.PP ++ + .B segment + = + .IR segment\-file , address +diff --git a/zipl/src/Makefile b/zipl/src/Makefile +index be14fce..bed970c 100644 +--- a/zipl/src/Makefile ++++ b/zipl/src/Makefile +@@ -15,8 +15,9 @@ objects = misc.o error.o scan.o job.o boot.o bootmap.o disk.o \ + + zipl_helpers = $(basename $(wildcard zipl_helper.*.c)) + chreipl_helpers = $(subst zipl_,chreipl_, $(zipl_helpers)) ++zipl_stage3 = ../boot/stage3.bin + +-all: zipl $(chreipl_helpers) ++all: zipl $(chreipl_helpers) $(zipl_stage3) + + zipl: $(objects) $(libs) + +@@ -33,6 +34,7 @@ install: all + $(INSTALL) -m 755 $(zipl_helpers) $(chreipl_helpers) \ + $(DESTDIR)$(TOOLS_LIBDIR) + $(CP) --no-dereference $(chreipl_helpers) $(DESTDIR)$(TOOLS_LIBDIR) ++ $(CP) --no-dereference $(zipl_stage3) $(DESTDIR)$(TOOLS_LIBDIR) + + clean: + rm -f *.o $(zipl_helpers) $(chreipl_helpers) zipl +@@ -46,3 +48,6 @@ clean: + + ../boot/data.o: + make -C ../boot data.o ++ ++../boot/stage3.bin: ++ make -C ../boot stage3.bin +diff --git a/zipl/src/boot.c b/zipl/src/boot.c +index 279d246..b13bcb7 100644 +--- a/zipl/src/boot.c ++++ b/zipl/src/boot.c +@@ -14,6 +14,8 @@ + #include + #include + #include ++#include ++#include + + #include "../boot/data.h" + #include "boot.h" +@@ -68,20 +70,17 @@ boot_check_data(void) + return 0; + } + +-/* Export stage 3 size for partition dump with dump kernel */ +-size_t +-get_stage3_size() +-{ +- return DATA_SIZE(stage3); +-} +- +-/* Create a stage 3 loader in memory. ++/* ++ * Create a stage 3 parameter block in memory. + * Upon success, return 0 and set BUFFER to point to the data buffer and set +- * BYTECOUNT to contain the loader size in bytes. Return non-zero otherwise. */ ++ * BYTECOUNT to contain the parameter block size in bytes. ++ * Return non-zero otherwise. ++ */ + int +-boot_get_stage3(void** buffer, size_t* bytecount, address_t parm_addr, +- address_t initrd_addr, size_t initrd_len, address_t image_addr, +- int extra_parm, uint16_t flags) ++boot_get_stage3_parms(void **buffer, size_t *bytecount, address_t parm_addr, ++ address_t initrd_addr, size_t initrd_len, ++ address_t image_addr, int extra_parm, uint16_t flags, ++ size_t image_len) + { + struct boot_stage3_params params; + void* data; +@@ -92,9 +91,10 @@ boot_get_stage3(void** buffer, size_t* bytecount, address_t parm_addr, + return -1; + } + /* Get memory */ +- data = misc_malloc(DATA_SIZE(stage3)); ++ data = misc_malloc(sizeof(params)); + if (data == NULL) + return -1; ++ memset(data, 0, sizeof(params)); + /* Prepare params section */ + params.parm_addr = (uint64_t) parm_addr; + params.initrd_addr = (uint64_t) initrd_addr; +@@ -102,11 +102,12 @@ boot_get_stage3(void** buffer, size_t* bytecount, address_t parm_addr, + params.load_psw = (uint64_t)(image_addr | PSW_LOAD); + params.extra_parm = (uint64_t) extra_parm; + params.flags = flags; ++ params.image_len = (uint64_t) image_len; ++ params.image_addr = (uint64_t) image_addr; + /* Initialize buffer */ +- memcpy(data, DATA_ADDR(stage3), DATA_SIZE(stage3)); +- memcpy(data, ¶ms, sizeof(struct boot_stage3_params)); ++ memcpy(data, ¶ms, sizeof(params)); + *buffer = data; +- *bytecount = DATA_SIZE(stage3); ++ *bytecount = sizeof(params); + return 0; + } + +diff --git a/zipl/src/bootmap.c b/zipl/src/bootmap.c +index 1b71b03..456c2ef 100644 +--- a/zipl/src/bootmap.c ++++ b/zipl/src/bootmap.c +@@ -19,6 +19,7 @@ + #include + + #include "lib/util_part.h" ++#include "lib/util_path.h" + + #include "boot.h" + #include "bootmap.h" +@@ -117,6 +118,22 @@ check_menu_positions(struct job_menu_data* menu, char* name, + return 0; + } + ++static bool ++check_secure_boot_support(void) ++{ ++ unsigned int val; ++ FILE *fp; ++ ++ fp = fopen(ZIPL_SIPL_PATH, "r"); ++ if (!fp) ++ return false; ++ ++ fscanf(fp, "%d", &val); ++ fclose(fp); ++ ++ return val ? true : false; ++} ++ + + /* Write COUNT elements of the blocklist specified by LIST as a linked list + * of segment table blocks to the file identified by file descriptor FD. Upon +@@ -199,24 +216,21 @@ add_program_table(int fd, disk_blockptr_t* table, int entries, + return rc; + } + +- + struct component_entry { + uint8_t data[23]; + uint8_t type; +- union { +- uint64_t load_address; +- uint64_t load_psw; +- } address; ++ component_data compdat; + } __attribute((packed)); + + typedef enum { + component_execute = 0x01, +- component_load = 0x02 ++ component_load = 0x02, ++ component_signature = 0x03 + } component_type; + + static void + create_component_entry(void* buffer, disk_blockptr_t* pointer, +- component_type type, uint64_t address, ++ component_type type, component_data data, + struct disk_info* info) + { + struct component_entry* entry; +@@ -228,10 +242,15 @@ create_component_entry(void* buffer, disk_blockptr_t* pointer, + case component_load: + bootmap_store_blockptr(&entry->data, pointer, + info); +- entry->address.load_address = address; ++ entry->compdat.load_address = data.load_address; + break; + case component_execute: +- entry->address.load_psw = address; ++ entry->compdat.load_psw = data.load_psw; ++ break; ++ case component_signature: ++ bootmap_store_blockptr(&entry->data, pointer, ++ info); ++ entry->compdat.sig_head = data.sig_head; + break; + } + } +@@ -267,7 +286,7 @@ struct component_loc { + + static int + add_component_file(int fd, const char* filename, address_t load_address, +- off_t offset, void* component, int add_files, ++ size_t trailer, void *component, int add_files, + struct disk_info* info, struct job_target_data* target, + struct component_loc *location) + { +@@ -279,8 +298,6 @@ add_component_file(int fd, const char* filename, address_t load_address, + size_t size; + blocknum_t count; + int rc; +- int from; +- unsigned int to; + + if (add_files) { + /* Read file to buffer */ +@@ -289,17 +306,10 @@ add_component_file(int fd, const char* filename, address_t load_address, + error_text("Could not read file '%s'", filename); + return rc; + } +- /* Ensure minimum size */ +- if (size <= (size_t) offset) { +- error_reason("File '%s' is too small (has to be " +- "greater than %ld bytes)", filename, +- (long) offset); +- free(buffer); +- return -1; +- } ++ size -= trailer; + /* Write buffer */ +- count = disk_write_block_buffer(fd, 0, buffer + offset, +- size - offset, &list, info); ++ count = disk_write_block_buffer(fd, 0, buffer, ++ size, &list, info); + free(buffer); + if (count == 0) { + error_text("Could not write to bootmap file"); +@@ -321,20 +331,7 @@ add_component_file(int fd, const char* filename, address_t load_address, + disk_free_info(file_info); + if (count == 0) + return -1; +- if (count * info->phy_block_size <= (size_t) offset) { +- error_reason("File '%s' is too small (has to be " +- "greater than %ld bytes)", filename, +- (long) offset); +- free(list); +- return -1; +- } +- if (offset > 0) { +- /* Shorten list by offset */ +- from = offset / info->phy_block_size; +- count -= from; +- for (to=0; to < count; to++, from++) +- list[to] = list[from]; +- } ++ count -= DIV_ROUND_UP(trailer, info->phy_block_size); + } + /* Fill in component location */ + loc.addr = load_address; +@@ -346,7 +343,7 @@ add_component_file(int fd, const char* filename, address_t load_address, + free(list); + if (rc == 0) { + create_component_entry(component, &segment, component_load, +- load_address, info); ++ (component_data) load_address, info); + /* Return location if requested */ + if (location != NULL) + *location = loc; +@@ -354,11 +351,10 @@ add_component_file(int fd, const char* filename, address_t load_address, + return rc; + } + +- + static int +-add_component_buffer(int fd, void* buffer, size_t size, address_t load_address, ++add_component_buffer(int fd, void* buffer, size_t size, component_data data, + void* component, struct disk_info* info, +- struct component_loc *location) ++ struct component_loc *location, int type) + { + struct component_loc loc; + disk_blockptr_t segment; +@@ -372,17 +368,21 @@ add_component_buffer(int fd, void* buffer, size_t size, address_t load_address, + error_text("Could not write to bootmap file"); + return -1; + } +- /* Fill in component location */ +- loc.addr = load_address; +- loc.size = count * info->phy_block_size; ++ if (type == component_load) { ++ /* Fill in component location */ ++ loc.addr = data.load_address; ++ loc.size = count * info->phy_block_size; ++ } else { ++ loc.addr = 0; ++ loc.size = 0; ++ } + /* Try to compact list */ + count = disk_compact_blocklist(list, count, info); + /* Write segment table */ + rc = add_segment_table(fd, list, count, &segment, info); + free(list); + if (rc == 0) { +- create_component_entry(component, &segment, component_load, +- load_address, info); ++ create_component_entry(component, &segment, type, data, info); + /* Return location if requested */ + if (location != NULL) + *location = loc; +@@ -391,6 +391,30 @@ add_component_buffer(int fd, void* buffer, size_t size, address_t load_address, + } + + ++static int ++add_dummy_buffer(int fd, size_t size, address_t addr, void *component, ++ struct disk_info *info, struct component_loc *comp_loc) ++{ ++ char *buffer; ++ int rc; ++ ++ buffer = misc_malloc(size); ++ if (buffer == NULL) ++ return -1; ++ ++ memset(buffer, 0, size); ++ rc = add_component_buffer(fd, buffer, size, ++ (component_data) (uint64_t) addr, ++ component, info, comp_loc, component_load); ++ if (rc) { ++ free(buffer); ++ return rc; ++ } ++ free(buffer); ++ return 0; ++} ++ ++ + static void + print_components(const char *name[], struct component_loc *loc, int num) + { +@@ -409,23 +433,86 @@ print_components(const char *name[], struct component_loc *loc, int num) + } + } + ++static int ++extract_signature(char *filename, void **ret_signature, ++ struct signature_header *sig_head) ++{ ++ struct file_signature *file_sig; ++ size_t signature_size = 0; ++ void *signature; ++ char *buffer; ++ size_t size; ++ ++ if (misc_read_file(filename, &buffer, &size, 0)) ++ return 0; ++ ++ file_sig = (void *) buffer + size - sizeof(*file_sig); ++ if (memcmp(file_sig->magic, SIGNATURE_MAGIC, sizeof(file_sig->magic)) ++ != 0) ++ goto out; ++ ++ signature = misc_malloc(file_sig->sig_len); ++ if (signature == NULL) ++ goto out; ++ signature_size = file_sig->sig_len; ++ ++ memcpy(signature, buffer + size - signature_size - sizeof(*file_sig), ++ signature_size); ++ ++ *ret_signature = signature; ++ sig_head->length = signature_size; ++ ++ switch (file_sig->id_type) { ++ case PKEY_ID_PKCS7: ++ sig_head->format = PKCS7_FORMAT; ++ break; ++ default: ++ error_text("Unsupported signature type %02x", ++ file_sig->id_type); ++ signature_size = 0; ++ goto out; ++ } ++ /* return size of signature and corresponding header */ ++ signature_size += sizeof(*file_sig); ++out: ++ free(buffer); ++ return signature_size; ++} ++ ++static void ++check_remaining_filesize(size_t filesize, size_t signature_size, ++ struct disk_info *info, char *filename) ++{ ++ if ((filesize - signature_size) % info->phy_block_size) { ++ fprintf(stderr, ++ "Warning: Size of signed file %s is not a multiple of the disk block size\n", ++ filename); ++ } ++} + + static int + add_ipl_program(int fd, struct job_ipl_data* ipl, disk_blockptr_t* program, + int verbose, int add_files, component_header_type type, +- struct disk_info* info, struct job_target_data* target) ++ struct disk_info* info, struct job_target_data* target, ++ int is_secure) + { ++ struct component_loc comp_loc[10]; ++ struct signature_header sig_head; ++ size_t ramdisk_size, image_size; ++ bool secure_boot_supported; ++ size_t stage3_params_size; ++ const char *comp_name[10]; ++ size_t signature_size; ++ int offset, flags = 0; ++ void *stage3_params; + struct stat stats; +- void* table; +- void* stage3; +- size_t stage3_size; +- const char *comp_name[4] = {"kernel image", "parmline", +- "initial ramdisk", "internal loader"}; +- struct component_loc comp_loc[4]; ++ void *signature; ++ int comp_nr = 0; ++ void *table; + int rc; +- int offset, flags = 0; + + memset(comp_loc, 0, sizeof(comp_loc)); ++ memset(&sig_head, 0, sizeof(sig_head)); + table = misc_malloc(info->phy_block_size); + if (table == NULL) + return -1; +@@ -456,55 +543,189 @@ add_ipl_program(int fd, struct job_ipl_data* ipl, disk_blockptr_t* program, + return -1; + } + } +- if (info->type == disk_type_scsi) ++ ramdisk_size = stats.st_size; ++ if (info->type == disk_type_scsi) { + flags |= STAGE3_FLAG_SCSI; ++ /* ++ * Add dummy components for stage 3 heap and stack to block the ++ * associated memory areas against firmware use. ++ */ ++ rc = add_dummy_buffer(fd, STAGE3_HEAP_SIZE, STAGE3_HEAP_ADDRESS, ++ VOID_ADD(table, offset), info, ++ &comp_loc[comp_nr]); ++ if (rc) { ++ error_text("Could not add stage3 HEAP dummy"); ++ free(table); ++ return rc; ++ } ++ comp_name[comp_nr] = "heap area"; ++ offset += sizeof(struct component_entry); ++ comp_nr++; ++ rc = add_dummy_buffer(fd, STAGE3_STACK_SIZE, ++ STAGE3_STACK_ADDRESS, ++ VOID_ADD(table, offset), info, ++ &comp_loc[comp_nr]); ++ if (rc) { ++ error_text("Could not add stage3 STACK dummy"); ++ free(table); ++ return rc; ++ } ++ comp_name[comp_nr] = "stack area"; ++ offset += sizeof(struct component_entry); ++ comp_nr++; ++ } + if (ipl->is_kdump) + flags |= STAGE3_FLAG_KDUMP; + ++ /* Get kernel file size */ ++ if (stat(ipl->image, &stats)) { ++ error_reason(strerror(errno)); ++ error_text("Could not get information for file '%s'", ++ ipl->image); ++ free(table); ++ return -1; ++ } ++ image_size = stats.st_size; ++ secure_boot_supported = check_secure_boot_support(); ++ signature_size = extract_signature(ZIPL_STAGE3_PATH, &signature, ++ &sig_head); ++ if (signature_size && ++ (is_secure == SECURE_BOOT_ENABLED || ++ (is_secure == SECURE_BOOT_AUTO && secure_boot_supported))) { ++ if (verbose) ++ printf(" signature for.....: %s\n", ZIPL_STAGE3_PATH); ++ ++ rc = add_component_buffer(fd, signature, sig_head.length, ++ (component_data)sig_head, ++ VOID_ADD(table, offset), info, ++ &comp_loc[comp_nr], ++ component_signature); ++ if (rc) { ++ error_text("Could not add stage3 signature"); ++ free(table); ++ return rc; ++ } ++ comp_name[comp_nr] = "loader signature"; ++ offset += sizeof(struct component_entry); ++ comp_nr++; ++ free(signature); ++ } else if (is_secure == SECURE_BOOT_ENABLED) { ++ /* ++ * If secure boot is forced and we have failed to extract a ++ * signature for the stage 3 loader zipl will abort with an ++ * error message ++ */ ++ error_text("Could not install Secure Boot IPL records"); ++ error_reason("Missing signature in internal loader file %s", ++ ZIPL_STAGE3_PATH); ++ free(table); ++ return -1; ++ } ++ + /* Add stage 3 loader to bootmap */ +- rc = boot_get_stage3(&stage3, &stage3_size, ipl->parm_addr, +- ipl->ramdisk_addr, (size_t) stats.st_size, +- ipl->is_kdump ? ipl->image_addr + 0x10 : +- ipl->image_addr, +- (info->type == disk_type_scsi) ? 0 : 1, +- flags); ++ rc = add_component_file(fd, ZIPL_STAGE3_PATH, DEFAULT_STAGE3_ADDRESS, ++ signature_size, VOID_ADD(table, offset), 1, ++ info, target, &comp_loc[comp_nr]); + if (rc) { ++ error_text("Could not add internal loader file '%s'", ++ ZIPL_STAGE3_PATH); + free(table); + return rc; + } +- rc = add_component_buffer(fd, stage3, stage3_size, +- DEFAULT_STAGE3_ADDRESS, +- VOID_ADD(table, offset), info, &comp_loc[3]); +- free(stage3); ++ offset += sizeof(struct component_entry); ++ comp_name[comp_nr] = "internal loader"; ++ comp_nr++; ++ ++ /* Add stage 3 parameter to bootmap */ ++ rc = boot_get_stage3_parms(&stage3_params, &stage3_params_size, ++ ipl->parm_addr, ipl->ramdisk_addr, ++ ramdisk_size, ++ ipl->is_kdump ? ipl->image_addr + 0x10 : ++ ipl->image_addr, ++ (info->type == disk_type_scsi) ? 0 : 1, ++ flags, image_size); + if (rc) { +- error_text("Could not add stage 3 boot loader"); ++ free(table); ++ return rc; ++ } ++ rc = add_component_buffer(fd, stage3_params, stage3_params_size, ++ (component_data) (uint64_t) ++ DEFAULT_STAGE3_PARAMS_ADDRESS, ++ VOID_ADD(table, offset), info, ++ &comp_loc[comp_nr], component_load); ++ free(stage3_params); ++ if (rc) { ++ error_text("Could not add parameters"); + free(table); + return -1; + } + offset += sizeof(struct component_entry); ++ comp_name[comp_nr] = "parameters"; ++ comp_nr++; ++ + /* Add kernel image */ + if (verbose) { + printf(" kernel image......: %s\n", ipl->image); + } ++ signature_size = extract_signature(ipl->image, &signature, &sig_head); ++ if (signature_size && ++ (is_secure == SECURE_BOOT_ENABLED || ++ (is_secure == SECURE_BOOT_AUTO && secure_boot_supported))) { ++ if (verbose) ++ printf(" signature for.....: %s\n", ipl->image); ++ ++ rc = add_component_buffer(fd, signature, sig_head.length, ++ (component_data)sig_head, ++ VOID_ADD(table, offset), info, ++ &comp_loc[comp_nr], ++ component_signature); ++ if (rc) { ++ error_text("Could not add image signature"); ++ free(table); ++ return rc; ++ } ++ comp_name[comp_nr] = "image signature"; ++ offset += sizeof(struct component_entry); ++ comp_nr++; ++ free(signature); ++ check_remaining_filesize(image_size, signature_size, info, ++ ipl->image); ++ } else if (is_secure == SECURE_BOOT_ENABLED) { ++ /* ++ * If secure boot is forced and we have failed to extract a ++ * signature for the kernel image zipl will abort with an ++ * error message ++ */ ++ error_text("Could not install Secure Boot IPL records"); ++ error_reason("Missing signature in image file %s", ++ ipl->image); ++ free(table); ++ return -1; ++ } ++ + rc = add_component_file(fd, ipl->image, ipl->image_addr, +- KERNEL_HEADER_SIZE, VOID_ADD(table, offset), +- add_files, info, target, &comp_loc[0]); ++ signature_size, VOID_ADD(table, offset), ++ add_files, info, target, &comp_loc[comp_nr]); + if (rc) { + error_text("Could not add image file '%s'", ipl->image); + free(table); + return rc; + } + offset += sizeof(struct component_entry); ++ comp_name[comp_nr] = "kernel image"; ++ comp_nr++; ++ ++ /* Add kernel parmline */ + if (ipl->parmline != NULL) { +- /* Add kernel parmline */ + if (verbose) { + printf(" kernel parmline...: '%s'\n", ipl->parmline); + } + rc = add_component_buffer(fd, ipl->parmline, + strlen(ipl->parmline) + 1, +- ipl->parm_addr, ++ (component_data) ipl->parm_addr, + VOID_ADD(table, offset), +- info, &comp_loc[1]); ++ info, &comp_loc[comp_nr], ++ component_load); + if (rc) { + error_text("Could not add parmline '%s'", + ipl->parmline); +@@ -512,14 +733,45 @@ add_ipl_program(int fd, struct job_ipl_data* ipl, disk_blockptr_t* program, + return -1; + } + offset += sizeof(struct component_entry); ++ comp_name[comp_nr] = "parmline"; ++ comp_nr++; + } + + /* finally add ramdisk */ + if (ipl->ramdisk != NULL) { ++ signature_size = extract_signature(ipl->ramdisk, &signature, ++ &sig_head); ++ if (signature_size && ++ (is_secure == SECURE_BOOT_ENABLED || ++ (is_secure == SECURE_BOOT_AUTO && ++ secure_boot_supported))) { ++ if (verbose) { ++ printf(" signature for.....: %s\n", ++ ipl->ramdisk); ++ } ++ rc = add_component_buffer(fd, signature, ++ sig_head.length, ++ (component_data)sig_head, ++ VOID_ADD(table, offset), info, ++ &comp_loc[comp_nr], ++ component_signature); ++ if (rc) { ++ error_text("Could not add ramdisk signature"); ++ free(table); ++ return rc; ++ } ++ comp_name[comp_nr] = "ramdisk signature"; ++ offset += sizeof(struct component_entry); ++ comp_nr++; ++ free(signature); ++ check_remaining_filesize(ramdisk_size, signature_size, ++ info, ipl->ramdisk); ++ } + rc = add_component_file(fd, ipl->ramdisk, +- ipl->ramdisk_addr, 0, ++ ipl->ramdisk_addr, signature_size, + VOID_ADD(table, offset), +- add_files, info, target, &comp_loc[2]); ++ add_files, info, target, ++ &comp_loc[comp_nr]); + if (rc) { + error_text("Could not add ramdisk '%s'", + ipl->ramdisk); +@@ -527,13 +779,16 @@ add_ipl_program(int fd, struct job_ipl_data* ipl, disk_blockptr_t* program, + return -1; + } + offset += sizeof(struct component_entry); ++ comp_name[comp_nr] = "initial ramdisk"; ++ comp_nr++; + } + if (verbose) +- print_components(comp_name, comp_loc, 4); ++ print_components(comp_name, comp_loc, comp_nr); + /* Terminate component table */ + create_component_entry(VOID_ADD(table, offset), NULL, + component_execute, +- ZIPL_STAGE3_ENTRY_ADDRESS | PSW_LOAD, ++ (component_data) (uint64_t) ++ (ZIPL_STAGE3_ENTRY_ADDRESS | PSW_LOAD), + info); + /* Write component table */ + rc = disk_write_block_aligned(fd, table, info->phy_block_size, +@@ -584,7 +839,8 @@ if (rc) { + print_components(comp_name, comp_loc, 1); + /* Terminate component table */ + create_component_entry(VOID_ADD(table, offset), NULL, +- component_execute, PSW_DISABLED_WAIT, info); ++ component_execute, (component_data) (uint64_t) ++ PSW_DISABLED_WAIT, info); + /* Write component table */ + rc = disk_write_block_aligned(fd, table, info->phy_block_size, + program, info); +@@ -674,7 +930,7 @@ add_dump_program(int fd, struct job_dump_data* dump, + return rc; + ipl.parm_addr = dump->parm_addr; + return add_ipl_program(fd, &ipl, program, verbose, 1, +- type, info, target); ++ type, info, target, SECURE_BOOT_DISABLED); + } + + +@@ -711,7 +967,7 @@ build_program_table(int fd, struct job_data* job, disk_blockptr_t* pointer, + rc = add_ipl_program(fd, &job->data.ipl, &table[0], + verbose || job->command_line, + job->add_files, component_header, +- info, &job->target); ++ info, &job->target, job->is_secure); + break; + case job_segment: + if (job->command_line) +@@ -762,7 +1018,8 @@ build_program_table(int fd, struct job_data* job, disk_blockptr_t* pointer, + &table[job->data.menu.entry[i].pos], + verbose || job->command_line, + job->add_files, component_header, +- info, &job->target); ++ info, &job->target, ++ job->is_secure); + break; + case job_print_usage: + case job_print_version: +@@ -913,7 +1170,9 @@ bootmap_create(struct job_data *job, disk_blockptr_t *program_table, + ulong size; + ulong unused_size; + +- size = DIV_ROUND_UP(get_stage3_size(), info->phy_block_size); ++ /* Use approximated stage 3 size as starting point */ ++ size = MINIMUM_ADDRESS; ++ + /* Ramdisk */ + if (job->data.dump.ramdisk != NULL) { + if (stat(job->data.dump.ramdisk, &st)) +diff --git a/zipl/src/job.c b/zipl/src/job.c +index 22d2549..2d8de8f 100644 +--- a/zipl/src/job.c ++++ b/zipl/src/job.c +@@ -52,11 +52,12 @@ static struct option options[] = { + { "dry-run", no_argument, NULL, '0'}, + { "force", no_argument, NULL, 'f'}, + { "kdump", required_argument, NULL, 'k'}, ++ { "secure", required_argument, NULL, 'S'}, + { NULL, 0, NULL, 0 } + }; + + /* Command line option abbreviations */ +-static const char option_string[] = "-c:b:t:i:r:p:P:d:D:M:s:m:hHnVvaT:fk:"; ++static const char option_string[] = "-c:b:t:i:r:p:P:d:D:M:s:S:m:hHnVvaT:fk:"; + + struct command_line { + char* data[SCAN_KEYWORD_NUM]; +@@ -215,6 +216,11 @@ get_command_line(int argc, char* argv[], struct command_line* line) + } else + cmdline.menu = optarg; + break; ++ case 'S': ++ is_keyword = 1; ++ rc = store_option(&cmdline, scan_keyword_secure, ++ optarg); ++ break; + case 'h': + cmdline.help = 1; + break; +@@ -511,7 +517,7 @@ get_ipl_components(struct job_ipl_data *ipl, struct component_loc **clp, + /* Fill in component data */ + num = 0; + rc = set_cl_element(&cl[num++], "kernel image", ipl->image, +- &ipl->image_addr, 0, 0x10000, ++ &ipl->image_addr, 0, 0, + MAXIMUM_PHYSICAL_BLOCKSIZE); + if (rc) + goto error; +@@ -1263,6 +1269,26 @@ type_from_target(char *target, disk_type_t *type) + } + } + ++static int ++set_secure_ipl(char *keyword, struct job_data *job) ++{ ++ if (strcmp(keyword, "auto") == 0) { ++ job->is_secure = SECURE_BOOT_AUTO; ++ } else if (strcmp(keyword, "0") == 0) { ++ job->is_secure = SECURE_BOOT_DISABLED; ++ } else if (strcmp(keyword, "1") == 0) { ++ if (job->target.targettype != disk_type_scsi) { ++ error_reason("Secure boot forced for non-SCSI disk type"); ++ return -1; ++ } ++ job->is_secure = SECURE_BOOT_ENABLED; ++ } else { ++ error_reason("Invalid secure boot setting '%s'", ++ keyword); ++ return -1; ++ } ++ return 0; ++} + + static int + get_job_from_section_data(char* data[], struct job_data* job, char* section) +@@ -1345,6 +1371,13 @@ get_job_from_section_data(char* data[], struct job_data* job, char* section) + return -1; + } + } ++ /* Fill in secure boot */ ++ if (data[(int) scan_keyword_secure] != NULL) { ++ rc = set_secure_ipl(data[(int) scan_keyword_secure], ++ job); ++ if (rc) ++ return rc; ++ } + break; + case section_ipl_tape: + /* Tape IPL job */ +@@ -1502,6 +1535,13 @@ get_menu_job(struct scan_token* scan, char* menu, struct job_data* job) + job->data.menu.timeout = + atol(scan[i].content.keyword.value); + break; ++ case scan_keyword_secure: ++ rc = set_secure_ipl( ++ scan[i].content.keyword.value, ++ job); ++ if (rc) ++ return rc; ++ break; + case scan_keyword_target: + job->target.bootmap_dir = misc_strdup( + scan[i].content.keyword.value); +diff --git a/zipl/src/misc.c b/zipl/src/misc.c +index fd16810..057c9a0 100644 +--- a/zipl/src/misc.c ++++ b/zipl/src/misc.c +@@ -22,7 +22,6 @@ + #include "error.h" + #include "misc.h" + +- + /* Allocate SIZE bytes of memory. Upon success, return pointer to memory. + * Return NULL otherwise. */ + void * +diff --git a/zipl/src/scan.c b/zipl/src/scan.c +index fe72e9a..e57361e 100644 +--- a/zipl/src/scan.c ++++ b/zipl/src/scan.c +@@ -45,45 +45,45 @@ enum scan_key_state scan_key_table[SCAN_SECTION_NUM][SCAN_KEYWORD_NUM] = { + * ult to tofs e mete file isk ent et pt out ultm dump + * rs enu + * +- * targ targ targ targ targ defa kdum +- * etba etty etge etbl etof ulta p ++ * targ targ targ targ targ defa kdum secu ++ * etba etty etge etbl etof ulta p re + * se pe omet ocks fset uto + * ry ize + */ + /* default auto */ + {opt, inv, inv, inv, inv, inv, inv, inv, req, opt, opt, inv, inv, inv, +- opt, opt, opt, opt, opt, opt, inv}, ++ opt, opt, opt, opt, opt, opt, inv, opt}, + /* default menu */ + {inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, +- inv, inv, inv, inv, inv, inv, inv}, ++ inv, inv, inv, inv, inv, inv, inv, opt}, + /* default section */ + {req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, +- inv, inv, inv, inv, inv, inv, inv}, ++ inv, inv, inv, inv, inv, inv, inv, opt}, + /* ipl */ + {inv, inv, inv, req, opt, opt, opt, inv, req, inv, inv, inv, inv, inv, +- opt, opt, opt, opt, opt, inv, opt}, ++ opt, opt, opt, opt, opt, inv, opt, opt}, + /* segment load */ + {inv, inv, inv, inv, inv, inv, inv, req, req, inv, inv, inv, inv, inv, +- inv, inv, inv, inv, inv, inv, inv}, ++ inv, inv, inv, inv, inv, inv, inv, inv}, + /* part dump */ + {inv, req, inv, inv, inv, inv, inv, inv, opt, inv, inv, inv, inv, inv, +- inv, inv, inv, inv, inv, inv, inv}, ++ inv, inv, inv, inv, inv, inv, inv, inv}, + /* fs dump */ + {inv, inv, req, inv, opt, opt, inv, inv, req, inv, inv, inv, inv, inv, +- inv, inv, inv, inv, inv, inv, inv}, ++ inv, inv, inv, inv, inv, inv, inv, inv}, + /* ipl tape */ + {inv, inv, inv, req, opt, opt, opt, inv, inv, inv, inv, inv, req, inv, +- inv, inv, inv, inv, inv, inv, inv}, ++ inv, inv, inv, inv, inv, inv, inv, inv}, + /* multi volume dump */ + {inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, +- inv, inv, inv, inv, inv, inv, inv} ++ inv, inv, inv, inv, inv, inv, inv, inv} + }; + + /* Determines which keyword may be present in a menu section */ + enum scan_key_state scan_menu_key_table[SCAN_KEYWORD_NUM] = { + /* menu section */ + opt, inv, inv, inv, inv, inv, inv, inv, req, opt, opt, inv, inv, inv, +- opt, opt, opt, opt, opt, inv, inv ++ opt, opt, opt, opt, opt, inv, inv, opt + }; + + /* Mapping of keyword IDs to strings */ +@@ -111,6 +111,7 @@ static const struct { + { "timeout", scan_keyword_timeout}, + { "tape", scan_keyword_tape}, + { "kdump", scan_keyword_kdump}, ++ { "secure", scan_keyword_secure}, + }; + + /* List of keywords that are used without an assignment */ +@@ -1863,6 +1864,7 @@ scan_build_automenu(struct scan_token* scan) + /* defaultmenu */ 1 + + /* menu heading */ 1 + + /* keyword default,prompt,timeout */ 3 + ++ /* keyword secure */ 1 + + /* target keywords*/ num_targets + + /* missing target definitions */ num_sections * num_targets + + /* number assigment */ num_sections; +@@ -1978,6 +1980,14 @@ scan_build_automenu(struct scan_token* scan) + db_keyword[i])) + goto err; + } ++ /* secure= */ ++ i = (int) scan_keyword_secure; ++ if (db_keyword[i]) { ++ if (scan_append_keyword_assignment(new_scan, &i_new, ++ scan_keyword_secure, ++ db_keyword[i])) ++ goto err; ++ } + /* target= */ + /* targetbase= */ + /* targetgeometry= */ +-- +2.21.0 + + +From 100c89a273fb4bcc1deb93aaf77ac9264d9ac3ee Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Dan=20Hor=C3=A1k?= +Date: Thu, 2 May 2019 15:46:39 +0200 +Subject: [PATCH 19/21] zipl: update stage3 objcopy command for gcc9 (#1659401) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The objcopy command for stage3.bin needs to take the new rodata section into account. +See also PR #60. + +Signed-off-by: Dan Horák +--- + zipl/boot/Makefile | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/zipl/boot/Makefile b/zipl/boot/Makefile +index da7e95f..a049797 100644 +--- a/zipl/boot/Makefile ++++ b/zipl/boot/Makefile +@@ -85,6 +85,7 @@ stage3.bin: stage3.exec + --only-section=.ex_table \ + --only-section=.data \ + --only-section=.rodata.str1.2 \ ++ --only-section=.rodata.cst8 \ + --only-section=.rodata \ + --only-section=.stage2dump.tail \ + --only-section=.eckd2dump_mv.tail \ +-- +2.21.0 + + +From 78f0479055e025ba849766aa2d60c22a7bcdbfba Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Dan=20Hor=C3=A1k?= +Date: Tue, 21 May 2019 13:49:09 +0200 +Subject: [PATCH 20/21] s390-tools: Add zcryptstats tool (#1658756) + +Description: The zcryptstats tool displays usage statistics of + IBM Crypto Express adapters. It obtains cryptographic + performance measurement data periodically and displays + the data for each cryptographic device for each + interval. A cryptographic device can be either a card + device or queue device (APQN). + +Upstream-ID: 5f2ddad6a83e04f6a64ea39619148c80e56c0814 +Upstream-ID: b165500b6987f3fcbbb6daee6d84d66af7fbd41f +Upstream-ID: 58189b878697fef3bf405fdd864bf40f2149ccc0 +Upstream-ID: 7b4a05e5a36fd36ba1866047f6b4814f127ec846 +Upstream-ID: 8be43a1f16923da037d5f5bffca73c433ca1231b +Upstream-ID: 43fcb694bfd2e4515ce131ea3aba2f81e8437757 +--- + README.md | 1 + + include/lib/util_rec.h | 3 + + libutil/util_rec.c | 89 +- + libutil/util_rec_example.c | 7 + + zconf/zcrypt/Makefile | 7 +- + zconf/zcrypt/zcryptstats.8 | 247 ++++ + zconf/zcrypt/zcryptstats.c | 2418 ++++++++++++++++++++++++++++++++++++ + 7 files changed, 2768 insertions(+), 4 deletions(-) + create mode 100644 zconf/zcrypt/zcryptstats.8 + create mode 100644 zconf/zcrypt/zcryptstats.c + +diff --git a/README.md b/README.md +index 08c27d7..af1024e 100644 +--- a/README.md ++++ b/README.md +@@ -129,6 +129,7 @@ Package contents + or show encryption state of attached LUNs. + - lszcrypt: Show Information about zcrypt devices and configuration. + - chzcrypt: Modify the zcrypt configuration. ++ - zcryptstats: Display usage statistics of IBM Crypto Express adapters. + - znetconf: List and configure network devices for s390 network adapters. + - cio_ignore: Query and modify the contents of the CIO device driver + blacklist. +diff --git a/include/lib/util_rec.h b/include/lib/util_rec.h +index a44461a..7a0c2f6 100644 +--- a/include/lib/util_rec.h ++++ b/include/lib/util_rec.h +@@ -68,5 +68,8 @@ const char *util_rec_get(struct util_rec *rec, const char *key); + + void util_rec_print_hdr(struct util_rec *rec); + void util_rec_print(struct util_rec *rec); ++void util_rec_print_separator(struct util_rec *rec); ++ ++void util_rec_set_indent(struct util_rec *rec, int indent); + + #endif /** LIB_UTIL_REC_H @} */ +diff --git a/libutil/util_rec.c b/libutil/util_rec.c +index 621bebc..c216cf9 100644 +--- a/libutil/util_rec.c ++++ b/libutil/util_rec.c +@@ -64,6 +64,7 @@ struct rec_fmt { + int argz_sep; + } csv_p; + } d; ++ int indent; + }; + + /* +@@ -122,9 +123,50 @@ struct util_rec *util_rec_new_wide(const char *hdr_sep) + rec->fmt.type = REC_FMT_WIDE; + rec->fmt.d.wide_p.hdr_sep = util_strdup(hdr_sep); + rec->fmt.d.wide_p.argz_sep = ','; ++ rec->fmt.indent = 0; + return rec; + } + ++/* ++ * Print the indentation characters ++ */ ++static inline void rec_print_indention(int indent) ++{ ++ if (indent <= 0) ++ return; ++ ++ printf("%*s", indent, ""); ++} ++ ++/* ++ * Print record separator in "wide" output format ++ */ ++static void rec_print_wide_separator(struct util_rec *rec) ++{ ++ const char *hdr_sep = rec->fmt.d.wide_p.hdr_sep; ++ int size = 0, field_count = 0; ++ struct util_rec_fld *fld; ++ char *buf; ++ ++ if (!hdr_sep) ++ return; ++ ++ util_list_iterate(rec->list, fld) { ++ if (fld->hdr) { ++ size += fld->width; ++ field_count++; ++ } ++ } ++ ++ size += field_count - 1; ++ buf = util_malloc(size + 1); ++ memset(buf, (int)hdr_sep[0], size); ++ buf[size] = 0; ++ rec_print_indention(rec->fmt.indent); ++ printf("%s\n", buf); ++ free(buf); ++} ++ + /* + * Print record header in "wide" output format + */ +@@ -135,6 +177,7 @@ static void rec_print_wide_hdr(struct util_rec *rec) + struct util_rec_fld *fld; + char *buf; + ++ rec_print_indention(rec->fmt.indent); + util_list_iterate(rec->list, fld) { + if (col_nr) + printf(" "); +@@ -156,6 +199,7 @@ static void rec_print_wide_hdr(struct util_rec *rec) + buf = util_malloc(size + 1); + memset(buf, (int)hdr_sep[0], size); + buf[size] = 0; ++ rec_print_indention(rec->fmt.indent); + printf("%s\n", buf); + free(buf); + } +@@ -172,6 +216,7 @@ void rec_print_wide(struct util_rec *rec) + int fld_count = 0; + char *entry; + ++ rec_print_indention(rec->fmt.indent); + util_list_iterate(rec->list, fld) { + if (!fld->hdr) + continue; +@@ -225,6 +270,7 @@ struct util_rec *util_rec_new_long(const char *hdr_sep, const char *col_sep, + rec->fmt.d.long_p.key_size = key_size; + rec->fmt.d.long_p.val_size = val_size; + rec->fmt.d.long_p.argz_sep = ' '; ++ rec->fmt.indent = 0; + return rec; + } + +@@ -241,6 +287,7 @@ static void rec_print_long_hdr(struct util_rec *rec) + fld = rec_get_fld(rec, p->key); + util_assert(fld != NULL, "Record not found\n"); + util_assert(fld->hdr != NULL, "Header for field not found\n"); ++ rec_print_indention(rec->fmt.indent); + if (p->col_sep) { + printf("%-*s %s %-*s\n", p->key_size, fld->hdr, + p->col_sep, fld->width, fld->val); +@@ -255,6 +302,7 @@ static void rec_print_long_hdr(struct util_rec *rec) + buf = util_malloc(len + 1); + memset(buf, p->hdr_sep[0], len); + buf[len] = 0; ++ rec_print_indention(rec->fmt.indent); + printf("%s\n", buf); + free(buf); + } +@@ -277,19 +325,24 @@ static void rec_print_long(struct util_rec *rec) + continue; + if (!fld->val) + continue; ++ rec_print_indention(rec->fmt.indent); + item = argz_next(fld->val, fld->len, item); + if (p->col_sep) { + printf(" %-*s %s %s\n", + p->key_size - 8, fld->hdr, p->col_sep, item); +- while ((item = argz_next(fld->val, fld->len, item))) ++ while ((item = argz_next(fld->val, fld->len, item))) { ++ rec_print_indention(rec->fmt.indent); + printf(" %-*s %c %s\n", + p->key_size - 8, "", p->argz_sep, item); ++ } + } else { + printf(" %-*s %s\n", + p->key_size - 8, fld->hdr, fld->val); +- while ((item = argz_next(fld->val, fld->len, item))) ++ while ((item = argz_next(fld->val, fld->len, item))) { ++ rec_print_indention(rec->fmt.indent); + printf(" %-*s %s\n", + p->key_size - 8, "", item); ++ } + } + } + printf("\n"); +@@ -320,6 +373,7 @@ struct util_rec *util_rec_new_csv(const char *col_sep) + rec->fmt.type = REC_FMT_CSV; + rec->fmt.d.csv_p.col_sep = util_strdup(col_sep); + rec->fmt.d.csv_p.argz_sep = ' '; ++ rec->fmt.indent = 0; + return rec; + } + +@@ -332,6 +386,7 @@ void rec_print_csv_hdr(struct util_rec *rec) + struct util_rec_fld *fld; + int fld_count = 0; + ++ rec_print_indention(rec->fmt.indent); + util_list_iterate(rec->list, fld) { + if (fld_count) + printf("%c", *col_sep); +@@ -354,6 +409,7 @@ void rec_print_csv(struct util_rec *rec) + int fld_count = 0; + char *item = NULL; + ++ rec_print_indention(rec->fmt.indent); + util_list_iterate(rec->list, fld) { + item = argz_next(fld->val, fld->len, item); + if (fld_count) +@@ -470,6 +526,24 @@ void util_rec_print_hdr(struct util_rec *rec) + } + } + ++/** ++ * Print record separator according to output format ++ * ++ * @param[in] rec Record pointer ++ */ ++void util_rec_print_separator(struct util_rec *rec) ++{ ++ switch (rec->fmt.type) { ++ case REC_FMT_WIDE: ++ rec_print_wide_separator(rec); ++ break; ++ case REC_FMT_LONG: ++ break; ++ case REC_FMT_CSV: ++ break; ++ } ++} ++ + /** + * Set a field value to an argz vector + * +@@ -537,3 +611,14 @@ const char *util_rec_get(struct util_rec *rec, const char *key) + + return (fld != NULL) ? fld->val : NULL; + } ++ ++/** ++ * Sets the indentation of the record ++ * ++ * @param[in] rec Record pointer ++ * @param[in] indent Number of characters to indent ++ */ ++void util_rec_set_indent(struct util_rec *rec, int indent) ++{ ++ rec->fmt.indent = indent; ++} +diff --git a/libutil/util_rec_example.c b/libutil/util_rec_example.c +index bc38bb4..801f909 100644 +--- a/libutil/util_rec_example.c ++++ b/libutil/util_rec_example.c +@@ -42,6 +42,8 @@ static void print_records(const char *format, struct util_rec *rec) + /* Print the record */ + util_rec_print(rec); + } ++ /* Print a separator line (is a nop for long and csv format) */ ++ util_rec_print_separator(rec); + printf("\n"); + } + +@@ -72,6 +74,11 @@ int main(void) + print_records("Wide format", rec); + util_rec_free(rec); + ++ rec = util_rec_new_wide("-"); ++ util_rec_set_indent(rec, 4); ++ print_records("Wide format with indentation", rec); ++ util_rec_free(rec); ++ + rec = util_rec_new_long("-", ":", "number", 30, 20); + print_records("Long format", rec); + util_rec_free(rec); +diff --git a/zconf/zcrypt/Makefile b/zconf/zcrypt/Makefile +index d075f34..f679775 100644 +--- a/zconf/zcrypt/Makefile ++++ b/zconf/zcrypt/Makefile +@@ -1,24 +1,27 @@ + include ../../common.mak + +-all: chzcrypt lszcrypt zcryptctl ++all: chzcrypt lszcrypt zcryptctl zcryptstats + + libs = $(rootdir)/libutil/libutil.a + + chzcrypt: chzcrypt.o misc.o $(libs) + lszcrypt: lszcrypt.o misc.o $(libs) + zcryptctl: zcryptctl.o misc.o $(libs) ++zcryptstats: zcryptstats.o $(libs) + + install: all + $(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR) + $(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 chzcrypt $(DESTDIR)$(BINDIR) + $(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 lszcrypt $(DESTDIR)$(BINDIR) + $(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 zcryptctl $(DESTDIR)$(BINDIR) ++ $(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 zcryptstats $(DESTDIR)$(BINDIR) + $(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man8 + $(INSTALL) -m 644 -c chzcrypt.8 $(DESTDIR)$(MANDIR)/man8 + $(INSTALL) -m 644 -c lszcrypt.8 $(DESTDIR)$(MANDIR)/man8 + $(INSTALL) -m 644 -c zcryptctl.8 $(DESTDIR)$(MANDIR)/man8 ++ $(INSTALL) -m 644 -c zcryptstats.8 $(DESTDIR)$(MANDIR)/man8 + + clean: +- rm -f *.o chzcrypt lszcrypt zcryptctl ++ rm -f *.o chzcrypt lszcrypt zcryptctl zcryptstats + + .PHONY: all install clean +diff --git a/zconf/zcrypt/zcryptstats.8 b/zconf/zcrypt/zcryptstats.8 +new file mode 100644 +index 0000000..8c31c69 +--- /dev/null ++++ b/zconf/zcrypt/zcryptstats.8 +@@ -0,0 +1,247 @@ ++.\" Copyright IBM Corp. 2019 ++.\" s390-tools is free software; you can redistribute it and/or modify ++.\" it under the terms of the MIT license. See LICENSE for details. ++.\" ++.TH ZCRYPTSTATS 1 "January 2019" "s390-tools" ++.SH NAME ++zcryptstats \- Display usage statistics of IBM Crypto Express adapters ++. ++. ++.SH SYNOPSIS ++.B zcryptstats ++.RI [ OPTIONS ] ++.RI [ DEVICE_ID ++[...] ] ++. ++.PP ++.B zcryptstats ++.BR \-\-help | \-h ++.br ++.B zcryptstats ++.BR \-\-version | \-v ++. ++. ++. ++.SH DESCRIPTION ++. ++Use \fBzcryptstats\fP to display usage statistics of IBM Crypto Express ++adapters. ++.PP ++\fBzcryptstats\fP obtains cryptographic performance measurement data ++periodically and displays the data for each cryptographic device for each ++interval. ++A cryptographic device can be either a card device or a queue device (APQN). ++\fBzcryptstats\fP runs forever unless you limit the number of intervals with ++the \fB\-\-count\fP option. The default interval time is 10 seconds. ++Use the \fB\-\-interval\fP option to specify a different interval time. ++.PP ++By default, all available cryptographic devices are monitored. ++You can optionally specify the device IDs of the devices to be monitored. ++The card device representation and the queue device are both in hexadecimal ++notation. ++.PP ++Use the \fB\-\-no-apqn\fP option to omit the performance measurement data of ++the queues. If the system does not support obtaining cryptographic ++performance measurement data on the queue devices, only the card devices ++are monitored. ++.PP ++For each device, a set of counters is displayed. The amount and meaning of the ++counters are dependent on the device type and mode, see the COUNTERS section. ++For each counter and interval, the following values are displayed: ++.RS 2 ++.IP "\(bu" 2 ++Number of measured operations. ++.IP "\(bu" 2 ++Rate of the measured operation in operations per second. ++.IP "\(bu" 2 ++Utilization of the device in percent. ++.IP "\(bu" 2 ++Average duration of the operations. ++.RE ++.PP ++The sum of all operations is displayed in a separate \fBtotals\fP line. ++Use the \fB\-\-only-totals\fP option to omit the individual counters and ++display the totals only. Use the \fB\-\-no\-totals\fP option to omit the ++totals. ++.PP ++ ++.B Note: ++The utilization value of a counter can exceed 100%. This value is caused by ++the parallel execution of cryptographic operations. ++.PP ++Cryptographic performance measurement data might not be available when Linux ++is running as guest under z/VM or under KVM. \fBzcryptstats\fP then displays an ++error message and exits. ++. ++. ++. ++.SH OPTIONS ++. ++.TP ++.BR DEVICE_ID ++Specifies a cryptographic device for which statistics are displayed. ++A device ID can either be a card device ID ++(\fI\fP) or a queue device (APQN) ID (\fI.\fP). ++To filter all devices by domain, provide \fI.\fP. ++If no IDs are given, statistics are displayed for all available devices. ++. ++.TP ++.BR \-i ", " \-\-interval\~\fIINTERVAL\fP ++Specifies the interval time in seconds. If this option is omitted, then the ++default interval time of 10 seconds is used. ++. ++.TP ++.BR \-c ", " \-\-count\~\fICOUNT\fP ++Specifies the number of reports that are generated at \fIINTERVAL\fP seconds ++apart. If this option is omitted, the \fBzcryptstats\fP command generates ++reports continuously, until it is stopped with control-C. ++. ++.TP ++.BR \-o ", " \-\-output\~\fIJSON\fP|\fITABLE\fP|\fICSV\fP ++Displays the statistics in the specified format. If this option is omitted, a ++comprehensive report is displayed. Supported output formats are: ++.RS 8 ++.IP "\(bu" 2 ++\fBJSON:\fP Displays the statistics in Javascript Object Notation (JSON) format. ++JSON output field order is undefined, and new fields might be added in the ++future. ++.IP "\(bu" 2 ++\fBTABLE:\fP Displays the statistics in a human readable simple table format. ++The individual counters are omitted, and only the totals are displayed. ++This output format implies option \fB\-\-only-totals\fP. ++.IP "\(bu" 2 ++\fBCSV:\fP Displays the statistics in comma-separated values format. The values ++are separated with a semicolon. The individual counters are omitted, and only ++the totals are displayed. This output format implies option ++\fB\-\-only-totals\fP. ++.RE ++. ++.TP ++.BR \-t ", " \-\-no\-totals ++Excludes the totals of all counters of a card device or queue device ++(APQN). This option cannot be specified together with option ++\fB\-\-only\-totals\fP or option \fB\-\-output\fP \fITABLE\fP|\fICSV\fP. ++. ++.TP ++.BR \-T ", " \-\-only\-totals ++Displays only the totals of all counters of a card device or a queue device ++(APQN), but not the individual counters. This option is implied with ++option \fB\-\-output\fP \fITABLE\fP|\fICSV\fP. ++. ++.TP ++.BR \-a ", " \-\-no\-apqn ++Displays only the counters of the card device, but omits the counters of the ++queue device (APQN). If the system does not support obtaining cryptographic ++performance measurement data on the queue devices, this option is implied. ++. ++.TP ++.BR \-M ", " \-\-map\-type\~\fIMAPPING\fP ++Maps unknown cryptographic device types and modes to known types and modes. ++This option should only be used when new, so far unknown cryptographic devices ++are found. You can then map them to known devices and modes, provided that the ++new cryptographic devices report the same counters as the known cryptographic ++device to which it is mapped. ++The mapping specification consists of a comma-separated list of ++\fIFROM\-TYPE\fP:\fIFROM\-MODE\fP=\fITO\-TYPE\fP:\fITO\-MODE\fP specifications. ++The type and mode values must be specified in decimal notation. ++. ++.TP ++.BR \-A ", " \-\-all ++Displays all cards devices and queue devices (APQNs), not only those that are ++available to the Linux instance. Using this option additional cryptographic ++devices that are available in the CEC, but not available to the Linux system ++are also monitored. ++This option cannot be specified together with option \fB\-\-only-online\fP. ++. ++.TP ++.BR \-O ", " \-\-only\-online ++Displays only online cards devices and queue devices (APQNs). This option ++cannot be specified together with option \fB\-\-all\fP. ++. ++.TP ++.BR \-V ", " \-\-verbose ++Displays additional information messages during processing. ++.TP ++.BR \-h ", " \-\-help ++Displays help text and exits. ++.TP ++.BR \-v ", " \-\-version ++Displays version information and exits. ++. ++. ++. ++.SH COUNTERS ++. ++.PP ++.B IBM Crypto Express adapter in accelerator mode: ++.RS 4 ++.TP ++.B All ++All operations on the adapter ++.TP ++.B RSA Key-gen ++RSA-key-generation operations (also included in \fBAll\fP). ++.RE ++.PP ++.B IBM Crypto Express adapter in CCA co-processor mode: ++.RS 4 ++.TP ++.B RSA 1024 ME ++1024-bit ME-format RSA operations. ++.TP ++.B RSA 2048 ME ++2048-bit ME-format RSA operations. ++.TP ++.B RSA 1024 CRT ++1024-bit CRT-format RSA operations. ++.TP ++.B RSA 2048 CRT ++2048-bit CRT-format RSA operations. ++.TP ++.B RSA 4096 ME ++4096-bit ME-format RSA operations. ++.TP ++.B RSA 4096 CTR ++4096-bit CRT-format RSA operations. ++.RE ++.PP ++.B IBM Crypto Express adapter in EP11 co-processor mode: ++.RS 4 ++.TP ++.B Asym. Slow ++Slow asymmetric-key functions. ++.TP ++.B Asym. Fast ++Fast asymmetric-key functions. ++.TP ++.B Symm. Partial ++Symmetric-key functions that return partial or incremental results. ++.TP ++.B Symm. Complete ++Symmetric-key functions that return a complete or final result. ++.TP ++.B Asym. Key-gen ++asymmetric-key generation function. ++.RE ++.PP ++. ++. ++. ++.SH EXAMPLES ++.TP ++.B zcryptstats 02 ++Display statistics for all cryptographic devices with card ID \fB02\fP. ++.TP ++.B zcryptstats 02.0005 --interval 5 ++Display statistics for cryptographic devices with card ID \fB02\fP and domain ++ID \fB0005\fP in a 5 second interval. ++.TP ++.B zcryptstats .0005 --count 10 ++Display statistics for cryptographic devices with domain ID \fB0005\fP with the ++default interval time of 10 seconds, for 10 intervals. ++.TP ++.B zcryptstats 02 --output JSON ++Display statistics for all cryptographic devices with card ID \fB02\fP in ++\fBJSON\fP output format. ++.TP ++ +diff --git a/zconf/zcrypt/zcryptstats.c b/zconf/zcrypt/zcryptstats.c +new file mode 100644 +index 0000000..136d5ba +--- /dev/null ++++ b/zconf/zcrypt/zcryptstats.c +@@ -0,0 +1,2418 @@ ++/* ++ * zcryptstats - Show usage statistics of IBM Crypto Express adapters ++ * ++ * Copyright IBM Corp. 2019 ++ * ++ * s390-tools is free software; you can redistribute it and/or modify ++ * it under the terms of the MIT license. See LICENSE for details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "lib/util_base.h" ++#include "lib/util_file.h" ++#include "lib/util_libc.h" ++#include "lib/util_opt.h" ++#include "lib/util_path.h" ++#include "lib/util_prg.h" ++#include "lib/util_rec.h" ++#include "lib/util_scandir.h" ++#include "lib/zt_common.h" ++ ++#ifndef offsetof ++ #define offsetof(type, member) ((size_t) &((type *)0)->member) ++#endif ++#ifndef offsetofend ++ #define offsetofend(type, member) \ ++ (offsetof(type, member) + sizeof(((type *)0)->member)) ++#endif ++ ++#define SYSFS_DEVICES_AP_PATH "devices/ap" ++#define SYSFS_DEVICES_CARD "devices/ap/card%02x" ++#define SYSFS_DEVICES_APQN "devices/ap/card%02x/%02x.%04x" ++#define SYSFS_DEVICES_CARD_ONLINE "devices/ap/card%02x/online" ++#define SYSFS_DEVICES_APQN_ONLINE "devices/ap/card%02x/%02x.%04x/online" ++#define CHSC_DEVICE "/dev/chsc" ++#define NUM_CARDS_OLD 64 ++#define NUM_CARDS 256 ++#define NUM_DOMAINS 256 ++ ++#define MASK_WORD_BITS (sizeof(uint32_t) * 8) ++#define MASK_WORD_NO(n) ((n) / MASK_WORD_BITS) ++#define MASK_BIT_IN_WORD(n) ((n) % MASK_WORD_BITS) ++#define MASK_BIT(n) (0x80000000 >> MASK_BIT_IN_WORD(n)) ++ ++struct chsc_apdn { ++ uint8_t ap_index; ++ uint8_t domain_index; ++} __packed; ++ ++struct chsc_scdmd_request { ++ struct chsc_header header; ++ struct chsc_apdn first_drid; ++ struct chsc_apdn last_drid; ++ uint32_t s:1; ++ uint32_t reserved1:31; ++ uint32_t reserved2; ++ uint32_t apsm[8]; ++ uint32_t dsm[8]; ++} __packed; ++ ++struct chsc_scdmd_response { ++ struct chsc_header header; ++ uint32_t reserved1; ++ uint16_t p:1; ++ uint16_t reserved2:15; ++ struct chsc_apdn crid; ++ uint32_t reserved3; ++} __packed; ++ ++struct chsc_scdmd_area { ++ struct chsc_scdmd_request request; ++ struct chsc_scdmd_response response; ++ uint8_t response_data[CHSC_SIZE - sizeof(struct chsc_scdmd_request) - ++ sizeof(struct chsc_scdmd_response)]; ++} __packed; ++ ++struct chsc_scmd_request { ++ struct chsc_header header; ++ uint8_t reserved1; ++ uint8_t zeros1:6; ++ uint8_t one:1; ++ uint8_t zero:1; ++ uint8_t fcs; ++ uint8_t lcs; ++ uint32_t reserved2; ++ uint32_t reserved3; ++} __packed; ++ ++struct chsc_scmd_response { ++ struct chsc_header header; ++ uint32_t reserved1; ++ uint32_t p:1; ++ uint32_t reserved2:31; ++ uint32_t reserved3; ++} __packed; ++ ++struct chsc_scmd_area { ++ struct chsc_scmd_request request; ++ struct chsc_scmd_response response; ++ uint8_t response_data[CHSC_SIZE - sizeof(struct chsc_scmd_request) - ++ sizeof(struct chsc_scmd_response)]; ++} __packed; ++ ++struct chsc_cmb_header { ++ uint8_t reserved1; ++ uint8_t ct; /* AP_DEVICE_TYPE_xxx values */ ++ uint8_t format; ++ uint8_t ax; ++ float s; ++ uint32_t v; ++ uint8_t dx; ++ uint8_t mt; ++ uint16_t l4; ++} __packed; ++ ++struct chsc_cmb_entry { ++ u64 t; ++ u64 c; ++} __packed; ++ ++struct chsc_cmb_area { ++ struct chsc_cmb_header header; ++ struct chsc_cmb_entry entries[32]; ++} __packed; ++ ++#define CRYPTO_TYPE_PCICC 3 ++#define CRYPTO_TYPE_PCICA 4 ++#define CRYPTO_TYPE_PCIXCC 5 ++#define CRYPTO_TYPE_CEX2A 6 ++#define CRYPTO_TYPE_CEX2C 7 ++#define CRYPTO_TYPE_CEX3A 8 ++#define CRYPTO_TYPE_CEX3C 9 ++#define CRYPTO_TYPE_CEX4S 10 ++#define CRYPTO_TYPE_CEX5S 11 ++#define CRYPTO_TYPE_CEX6S 12 ++ ++#define CRYPTO_TYPE_TOLERATION CRYPTO_TYPE_CEX6S ++ ++struct crypto_counter { ++ const char *name; ++ bool is_totals; ++}; ++ ++struct crypto_mode { ++ const char *name; ++ char indicatior_char; ++ unsigned int num_counters; ++ const struct crypto_counter *counters; ++}; ++ ++struct crypto_type { ++ const char *name; ++ unsigned int num_modes; ++ const struct crypto_mode *modes; ++}; ++ ++#define NUM_COPROC_COUNTERS 2 ++const struct crypto_counter counter_coproc[NUM_COPROC_COUNTERS] = { ++ { .name = "All", .is_totals = true }, ++ { .name = "RSA Key-gen" }, ++}; ++ ++#define NUM_ACCEL_COUNTERS 6 ++const struct crypto_counter counter_accel[NUM_ACCEL_COUNTERS] = { ++ { .name = "RSA 1024 ME" }, ++ { .name = "RSA 2048 ME" }, ++ { .name = "RSA 1024 CRT" }, ++ { .name = "RSA 2048 CRT" }, ++ { .name = "RSA 4096 ME" }, ++ { .name = "RSA 4096 CTR" }, ++}; ++ ++#define NUM_EP11_COUNTERS 5 ++const struct crypto_counter counter_ep11[NUM_EP11_COUNTERS] = { ++ { .name = "Asym. Slow" }, ++ { .name = "Asym. Fast" }, ++ { .name = "Symm. Partial" }, ++ { .name = "Symm. Complete" }, ++ { .name = "Asym. Key-gen" }, ++}; ++ ++#define NUM_PCICA_COUNTERS 20 ++const struct crypto_counter counter_pcica[NUM_PCICA_COUNTERS] = { ++ { .name = "RSA 1024 ME (E0)" }, ++ { .name = "RSA 2048 ME (E0)" }, ++ { .name = "RSA 1024 CRT (E0)" }, ++ { .name = "RSA 2048 CRT (E0)" }, ++ { .name = "RSA 1024 ME (E1)" }, ++ { .name = "RSA 2048 ME (E1)" }, ++ { .name = "RSA 1024 CRT (E1)" }, ++ { .name = "RSA 2048 CRT (E1)" }, ++ { .name = "RSA 1024 ME (E2)" }, ++ { .name = "RSA 2048 ME (E2)" }, ++ { .name = "RSA 1024 CRT (E2)" }, ++ { .name = "RSA 2048 CRT (E2)" }, ++ { .name = "RSA 1024 ME (E3)" }, ++ { .name = "RSA 2048 ME (E3)" }, ++ { .name = "RSA 1024 CRT (E3)" }, ++ { .name = "RSA 2048 CRT (E3)" }, ++ { .name = "RSA 1024 ME (E4)" }, ++ { .name = "RSA 2048 ME (E4)" }, ++ { .name = "RSA 1024 CRT (E4)" }, ++ { .name = "RSA 2048 CRT (E4)" }, ++}; ++ ++#define NUM_COPROC_MODES 1 ++const struct crypto_mode mode_coproc[1] = { ++ { .num_counters = NUM_COPROC_COUNTERS, ++ .counters = counter_coproc}, ++}; ++ ++#define NUM_ACCEL_MODES 1 ++const struct crypto_mode mode_accel[1] = { ++ { .num_counters = NUM_ACCEL_COUNTERS, ++ .counters = counter_accel }, ++}; ++ ++#define NUM_PCICA_MODES 1 ++const struct crypto_mode mode_pcica[1] = { ++ { .num_counters = NUM_PCICA_COUNTERS, ++ .counters = counter_pcica }, ++}; ++ ++#define NUM_CEX456_MODES 11 ++const struct crypto_mode mode_cex456[NUM_CEX456_MODES] = { ++ { 0 }, ++ { 0 }, ++ { 0 }, ++ { 0 }, ++ { 0 }, ++ { 0 }, ++ { 0 }, ++ { 0 }, ++ { .name = "Accelerator", .indicatior_char = 'A', ++ .num_counters = NUM_ACCEL_COUNTERS, ++ .counters = counter_accel }, ++ { .name = "CCA co-processor", .indicatior_char = 'C', ++ .num_counters = NUM_COPROC_COUNTERS, ++ .counters = counter_coproc}, ++ { .name = "EP11 co-processor", .indicatior_char = 'P', ++ .num_counters = NUM_EP11_COUNTERS, ++ .counters = counter_ep11 }, ++}; ++ ++#define NUM_CRYPTO_TYPES 13 ++const struct crypto_type crypto_types[NUM_CRYPTO_TYPES] = { ++ { 0 }, ++ { 0 }, ++ { 0 }, ++ { .name = "PCICC", .num_modes = NUM_COPROC_MODES, ++ .modes = mode_coproc }, ++ { .name = "PCICA", .num_modes = NUM_PCICA_MODES, ++ .modes = mode_pcica }, ++ { .name = "PCIXCC", .num_modes = NUM_COPROC_MODES, ++ .modes = mode_coproc}, ++ { .name = "CEX2A", .num_modes = NUM_ACCEL_MODES, ++ .modes = mode_accel }, ++ { .name = "CEX2C", .num_modes = NUM_COPROC_MODES, ++ .modes = mode_coproc }, ++ { .name = "CEX3A", .num_modes = NUM_ACCEL_MODES, ++ .modes = mode_accel }, ++ { .name = "CEX3C", .num_modes = NUM_COPROC_MODES, ++ .modes = mode_coproc }, ++ { .name = "CEX4", .num_modes = NUM_CEX456_MODES, ++ .modes = mode_cex456 }, ++ { .name = "CEX5", .num_modes = NUM_CEX456_MODES, ++ .modes = mode_cex456 }, ++ { .name = "CEX6", .num_modes = NUM_CEX456_MODES, ++ .modes = mode_cex456 }, ++}; ++ ++ ++struct type_mapping { ++ uint8_t from_type; ++ uint8_t from_mode; ++ uint8_t to_type; ++ uint8_t to_mode; ++ struct type_mapping *next; ++}; ++ ++struct device_selection { ++ int card; ++ int domain; /* -1 if not specified */ ++ struct device_selection *next; ++}; ++ ++struct interval_data { ++ bool current_valid; ++ bool previous_valid; ++ struct chsc_cmb_area current; ++ struct chsc_cmb_area previous; ++}; ++ ++struct card_data { ++ struct interval_data data; ++ struct interval_data *domains[NUM_DOMAINS]; ++}; ++ ++struct interval_values { ++ u64 count; ++ double rate; ++ double utilization; ++ double duration; ++}; ++ ++struct print_func { ++ int (*print_initialize)(void); ++ int (*print_terminate)(void); ++ int (*print_header)(void); ++ int (*print_footer)(void); ++ int (*print_interval_header)(unsigned long interval_count, ++ const char *timestamp); ++ int (*print_interval_footer)(void); ++ int (*print_device_header)(bool is_apqn, uint8_t card, uint8_t domain, ++ const char *type, const char *timestamp); ++ int (*print_device_footer)(void); ++ int (*print_counter_data)(bool is_apqn, uint8_t card, uint8_t domain, ++ const char *type, const char *timestamp, ++ const char *name, ++ struct interval_values *vals); ++ int (*print_counter_separator)(void); ++}; ++ ++#define pr_call(func) g.print_funcs->func == NULL ? 0 : g.print_funcs->func ++ ++static int default_print_initialize(void); ++static int default_print_terminate(void); ++static int default_print_header(void); ++static int default_print_footer(void); ++static int default_print_interval_header(unsigned long interval_count, ++ const char *timestamp); ++static int default_print_device_header(bool is_apqn, uint8_t card, ++ uint8_t domain, const char *type, ++ const char *timestamp); ++static int default_print_device_footer(void); ++static int default_print_counter_data(bool is_apqn, uint8_t card, ++ uint8_t domain, const char *type, ++ const char *timestamp, const char *name, ++ struct interval_values *vals); ++static int default_print_counter_separator(void); ++ ++static const struct print_func default_print = { ++ .print_initialize = default_print_initialize, ++ .print_terminate = default_print_terminate, ++ .print_header = default_print_header, ++ .print_footer = default_print_footer, ++ .print_interval_header = default_print_interval_header, ++ .print_device_header = default_print_device_header, ++ .print_device_footer = default_print_device_footer, ++ .print_counter_data = default_print_counter_data, ++ .print_counter_separator = default_print_counter_separator, ++}; ++ ++static int json_print_initialize(void); ++static int json_print_header(void); ++static int json_print_footer(void); ++static int json_print_interval_header(unsigned long interval_count, ++ const char *timestamp); ++static int json_print_interval_footer(void); ++static int json_print_device_header(bool is_apqn, uint8_t card, ++ uint8_t domain, const char *type, ++ const char *timestamp); ++static int json_print_device_footer(void); ++static int json_print_counter_data(bool is_apqn, uint8_t card, uint8_t domain, ++ const char *type, const char *timestamp, ++ const char *name, ++ struct interval_values *vals); ++ ++static const struct print_func json_print = { ++ .print_initialize = json_print_initialize, ++ .print_header = json_print_header, ++ .print_footer = json_print_footer, ++ .print_interval_header = json_print_interval_header, ++ .print_interval_footer = json_print_interval_footer, ++ .print_device_header = json_print_device_header, ++ .print_device_footer = json_print_device_footer, ++ .print_counter_data = json_print_counter_data, ++}; ++ ++ ++static int table_print_initialize(void); ++static int table_print_terminate(void); ++static int table_print_header(void); ++static int table_print_interval_footer(void); ++static int table_print_counter_data(bool is_apqn, uint8_t card, uint8_t domain, ++ const char *type, const char *timestamp, ++ const char *name, ++ struct interval_values *vals); ++ ++static const struct print_func table_print = { ++ .print_initialize = table_print_initialize, ++ .print_terminate = table_print_terminate, ++ .print_header = table_print_header, ++ .print_interval_footer = table_print_interval_footer, ++ .print_counter_data = table_print_counter_data, ++}; ++ ++static int csv_print_initialize(void); ++static int csv_print_terminate(void); ++static int csv_print_header(void); ++static int csv_print_counter_data(bool is_apqn, uint8_t card, uint8_t domain, ++ const char *type, const char *timestamp, ++ const char *name, ++ struct interval_values *vals); ++ ++static const struct print_func csv_print = { ++ .print_initialize = csv_print_initialize, ++ .print_terminate = csv_print_terminate, ++ .print_header = csv_print_header, ++ .print_counter_data = csv_print_counter_data, ++}; ++ ++/* ++ * Program configuration ++ */ ++const struct util_prg prg = { ++ .desc = "Display usage statistics of IBM Crypto Express adapters", ++ .args = "[DEVICE_IDS]", ++ .copyright_vec = { ++ { ++ .owner = "IBM Corp.", ++ .pub_first = 2019, ++ .pub_last = 2019, ++ }, ++ UTIL_PRG_COPYRIGHT_END ++ } ++}; ++ ++/* ++ * Global variables for program options ++ */ ++static struct zcryptstats_globals { ++ long interval; ++ unsigned long count; ++ bool no_totals; ++ bool only_totals; ++ bool no_apqn; ++ char *map_type; ++ char **device_ids; ++ bool all; ++ bool only_online; ++ bool verbose; ++ int chsc_fd; ++ uint8_t max_card_used; ++ uint32_t card_mask[8]; ++ uint8_t min_card; ++ uint8_t max_card; ++ uint32_t domain_mask[8]; ++ uint8_t min_domain; ++ uint8_t max_domain; ++ struct device_selection *dev_selection; ++ struct type_mapping *type_mapping; ++ struct card_data *cards[NUM_CARDS]; ++ const struct print_func *print_funcs; ++ struct util_rec *device_rec; ++ struct util_rec *counter_rec; ++ bool first_device; ++ bool first_counter; ++} g = { ++ .interval = 10, ++ .chsc_fd = -1, ++ .print_funcs = &default_print, ++}; ++ ++ ++static volatile bool quit; ++ ++/* ++ * Configuration of command line options ++ */ ++static struct util_opt opt_vec[] = { ++ /***********************************************************/ ++ { ++ .flags = UTIL_OPT_FLAG_SECTION, ++ .desc = "OPTIONS", ++ }, ++ { ++ .option = {"interval", required_argument, NULL, 'i'}, ++ .argument = "INTERVAL", ++ .desc = "Specifies the interval time in seconds. If omitted, a " ++ "default interval of 10 seconds is used", ++ }, ++ { ++ .option = {"count", required_argument, NULL, 'c'}, ++ .argument = "COUNT", ++ .desc = "Specifies the number of reports that are generated " ++ "at INTERVAL seconds apart. If omitted, reports are " ++ "generated continuously, until stopped with control-C", ++ }, ++ { ++ .option = {"output", required_argument, NULL, 'o'}, ++ .argument = "JSON|TABLE|CSV", ++ .desc = "Displays the statistics in the specified format. If " ++ "this option is omitted, a comprehensive report is " ++ "displayed. Supported output formats are: JSON, TABLE, " ++ "CSV. With TABLE and CSV the display of the individual " ++ "counters are omitted, and only the totals are " ++ "displayed. CSV and TABLE output formats imply option " ++ "--only-totals", ++ }, ++ { ++ .option = {"no-totals", 0, NULL, 't'}, ++ .desc = "Excludes the totals of all counters of a card " ++ "device or queue device (APQN). It can not be " ++ "specified together with option --only-totals or " ++ "option --output TABLE|CSV", ++ }, ++ { ++ .option = {"only-totals", 0, NULL, 'T'}, ++ .desc = "Displays only the totals of all counters of a card " ++ "device or a queue device (APQN), but not the " ++ "individual counters. This option is implied with " ++ "option --output TABLE|CSV", ++ }, ++ { ++ .option = {"no-apqn", 0, NULL, 'a'}, ++ .desc = "Displays only the counters of the card device, but " ++ "omits the counters of the queue device (APQN). If the " ++ "system does not support obtaining cryptographic " ++ "performance measurement data on the queue devices, " ++ "then this option is implied", ++ }, ++ { ++ .option = {"map-type", required_argument, NULL, 'M'}, ++ .argument = "MAPPING", ++ .desc = "Maps unknown cryptographic device types and modes to " ++ "known types and modes. This option should only be " ++ "used when new, so far unknown cryptographic devices " ++ "are found. You can then map them to known devices and " ++ "modes, provided that the new cryptographic devices " ++ "report the same counters as the known cryptographic " ++ "device to which it is mapped. The mapping " ++ "specification consists of a comma-separated list of " ++ "FROM-TYPE:FROM-MODE=TO-TYPE:TO-MODE specifications. " ++ "The type and mode values must be specified in decimal " ++ "notation", ++ }, ++ { ++ .option = {"all", 0, NULL, 'A'}, ++ .desc = "Displays all cards devices and queue devices (APQNs), " ++ "not only those that are available to the Linux " ++ "system. Using this option additional cryptographic " ++ "devices that are available in the CEC, but not " ++ "available to the Linux system are also monitored. " ++ "This option can not be specified together with option " ++ "--only-online", ++ }, ++ { ++ .option = {"only-online", 0, NULL, 'O'}, ++ .desc = "Displays only online cards devices and queue devices " ++ "(APQNs). This option can not be specified together " ++ "with option --all" ++ }, ++ { ++ .option = {"verbose", 0, NULL, 'V'}, ++ .desc = "Prints additional information messages during " ++ "processing", ++ }, ++ UTIL_OPT_HELP, ++ UTIL_OPT_VERSION, ++ UTIL_OPT_END ++}; ++ ++#define pr_verbose(fmt...) do { \ ++ if (g.verbose) \ ++ warnx(fmt); \ ++ } while (0) ++ ++/* ++ * Describe adapter ids ++ */ ++static void print_adapter_id_help(void) ++{ ++ printf("\n"); ++ printf("DEVICE_IDS\n"); ++ util_print_indented(" List of cryptographic device IDs separated by " ++ "blanks for which statistics are displayed. " ++ "DEVICE_ID can either be a card device ID " ++ "('') or a queue device ID (." ++ "'). To filter all devices by domain, " ++ "provide '.'. If no IDs are given, " ++ "statistics are displayed for all available " ++ "devices.", 2); ++ printf("\n"); ++ printf("EXAMPLE:\n"); ++ util_print_indented(" Display statistics for all cryptographic " ++ "devices with card ID '02.", 2); ++ printf(" # zcryptstats 02\n"); ++ printf("\n"); ++ util_print_indented(" Display statistics for cryptographic devices " ++ "with card ID '02' and domain ID '0005'.", 2); ++ printf(" # zcryptstats 02.0005\n"); ++ printf("\n"); ++} ++ ++static struct type_mapping *find_type_mapping(uint8_t from_type, ++ uint8_t from_mode) ++{ ++ struct type_mapping *map = g.type_mapping; ++ ++ while (map != NULL) { ++ if (map->from_type == from_type && map->from_mode == from_mode) ++ return map; ++ map = map->next; ++ } ++ return NULL; ++} ++ ++/* ++ * Get the name of the card for a crypto type and mode. ++ * Note: This function might return the address of a static string variable. ++ * It is only valid until this function is called again. ++ */ ++static const char *get_card_name(uint8_t type, uint8_t mode) ++{ ++ const struct crypto_type *ct; ++ const struct crypto_mode *m; ++ static char temp_name[250]; ++ struct type_mapping *map; ++ ++ map = find_type_mapping(type, mode); ++ if (map != NULL) { ++ type = map->to_type; ++ mode = map->to_mode; ++ } else if (type >= NUM_CRYPTO_TYPES) { ++ type = CRYPTO_TYPE_TOLERATION; ++ } ++ ++ if (type >= NUM_CRYPTO_TYPES) ++ return "UNKNOWN ADAPTER TYPE"; ++ ++ ct = &crypto_types[type]; ++ if (ct->name == NULL || ct->modes == NULL || ct->num_modes == 0) ++ return "UNKNOWN ADAPTER TYPE"; ++ ++ if (mode >= ct->num_modes) ++ return ct->name; ++ ++ m = &ct->modes[mode]; ++ snprintf(temp_name, sizeof(temp_name) - 1, "%s%c (%s)", ct->name, ++ m->indicatior_char, m->name != NULL ? m->name : ""); ++ return temp_name; ++} ++ ++/* ++ * Get the name of a counter for a crypto type, mode and index. ++ * Note: This function might return the address of a static string variable. ++ * It is only valid until this function is called again. ++ */ ++static const char *get_counter_name(uint8_t type, uint8_t mode, uint8_t index) ++{ ++ const struct crypto_type *ct; ++ const struct crypto_mode *m; ++ static char temp_name[250]; ++ struct type_mapping *map; ++ ++ map = find_type_mapping(type, mode); ++ if (map != NULL) { ++ type = map->to_type; ++ mode = map->to_mode; ++ } else if (type >= NUM_CRYPTO_TYPES) { ++ type = CRYPTO_TYPE_TOLERATION; ++ } ++ ++ if (type >= NUM_CRYPTO_TYPES) ++ goto generic; ++ ++ ct = &crypto_types[type]; ++ if (ct->name == NULL || ct->modes == NULL || ct->num_modes == 0) ++ goto generic; ++ ++ if (mode >= ct->num_modes) ++ goto generic; ++ ++ m = &ct->modes[mode]; ++ if (m->counters == NULL || m->num_counters == 0) ++ goto generic; ++ ++ if (index >= m->num_counters) ++ goto generic; ++ ++ return m->counters[index].name; ++ ++generic: ++ snprintf(temp_name, sizeof(temp_name) - 1, "COUNTER %u", index); ++ return temp_name; ++} ++ ++/* ++ * Returns true if a counter for a crypto type, mode and index represents the ++ * total number of operations. ++ */ ++static bool is_counter_totals(uint8_t type, uint8_t mode, uint8_t index) ++{ ++ const struct crypto_type *ct; ++ const struct crypto_mode *m; ++ struct type_mapping *map; ++ ++ map = find_type_mapping(type, mode); ++ if (map != NULL) { ++ type = map->to_type; ++ mode = map->to_mode; ++ } else if (type >= NUM_CRYPTO_TYPES) { ++ type = CRYPTO_TYPE_TOLERATION; ++ } ++ ++ if (type >= NUM_CRYPTO_TYPES) ++ return false; ++ ++ ct = &crypto_types[type]; ++ if (ct->name == NULL || ct->modes == NULL || ct->num_modes == 0) ++ return false; ++ ++ if (mode >= ct->num_modes) ++ return false; ++ ++ m = &ct->modes[mode]; ++ if (m->counters == NULL || m->num_counters == 0) ++ return false; ++ ++ if (index >= m->num_counters) ++ return false; ++ ++ return m->counters[index].is_totals; ++} ++ ++/* ++ * Returns true if the card is available ++ */ ++static bool is_card_available(uint8_t card) ++{ ++ char *path; ++ bool ret; ++ ++ path = util_path_sysfs(SYSFS_DEVICES_CARD, card); ++ ret = util_path_is_dir(path); ++ free(path); ++ ++ return ret; ++} ++ ++/* ++ * Returns true if the APQN is available ++ */ ++static bool is_apqn_available(uint8_t card, uint8_t domain) ++{ ++ char *path; ++ bool ret; ++ ++ path = util_path_sysfs(SYSFS_DEVICES_APQN, card, card, domain); ++ ret = util_path_is_dir(path); ++ free(path); ++ ++ return ret; ++} ++ ++/* ++ * Returns true if the card is online ++ */ ++static bool is_card_online(uint8_t card) ++{ ++ unsigned long online; ++ char *path; ++ int rc; ++ ++ path = util_path_sysfs(SYSFS_DEVICES_CARD_ONLINE, card); ++ rc = util_file_read_ul(&online, 10, path); ++ free(path); ++ ++ return rc == 0 && online != 0; ++} ++ ++/* ++ * Returns true if the APQN is online ++ */ ++static bool is_apqn_online(uint8_t card, uint8_t domain) ++{ ++ unsigned long online; ++ char *path; ++ int rc; ++ ++ path = util_path_sysfs(SYSFS_DEVICES_APQN_ONLINE, card, card, domain); ++ rc = util_file_read_ul(&online, 10, path); ++ free(path); ++ ++ if (rc != 0) ++ return false; ++ ++ return online != 0; ++} ++ ++/* ++ * Updates the APQNs data with data for the current interval. ++ */ ++static void update_apqn_data(uint8_t card, uint8_t domain, ++ struct chsc_cmb_area *cmb, size_t cmb_len) ++{ ++ struct card_data *cd = g.cards[card]; ++ struct interval_data *dd; ++ ++ if (cd == NULL) { ++ cd = util_malloc(sizeof(struct card_data)); ++ memset(cd, 0, sizeof(struct card_data)); ++ g.cards[card] = cd; ++ ++ pr_verbose("Card %02x added", card); ++ } ++ ++ dd = cd->domains[domain]; ++ if (dd == NULL) { ++ dd = util_malloc(sizeof(struct interval_data)); ++ memset(dd, 0, sizeof(struct interval_data)); ++ cd->domains[domain] = dd; ++ ++ pr_verbose("APQN %02x.%04x added", card, domain); ++ } else { ++ if (!dd->current_valid) { ++ dd->previous = dd->current; ++ dd->previous_valid = true; ++ } ++ } ++ ++ memset(&dd->current, 0, sizeof(struct chsc_cmb_area)); ++ memcpy(&dd->current, cmb, cmb_len); ++ dd->current_valid = true; ++} ++ ++/* ++ * Updates the card's data with data for the current interval. ++ */ ++static void update_card_data(uint8_t card, struct chsc_cmb_area *cmb, ++ size_t cmb_len) ++{ ++ struct card_data *cd = g.cards[card]; ++ ++ if (cd == NULL) { ++ cd = util_malloc(sizeof(struct card_data)); ++ memset(cd, 0, sizeof(struct card_data)); ++ g.cards[card] = cd; ++ ++ pr_verbose("Card %02x added", card); ++ } else { ++ if (!cd->data.current_valid) { ++ cd->data.previous = cd->data.current; ++ cd->data.previous_valid = true; ++ } ++ }; ++ ++ memset(&cd->data.current, 0, sizeof(struct chsc_cmb_area)); ++ memcpy(&cd->data.current, cmb, cmb_len); ++ cd->data.current_valid = true; ++} ++ ++/* ++ * Frees the interval data of a card ++ */ ++static void free_card_data(struct card_data *cd) ++{ ++ struct interval_data *dd; ++ int domain; ++ ++ if (cd == NULL) ++ return; ++ ++ for (domain = 0; domain < NUM_DOMAINS; domain++) { ++ dd = cd->domains[domain]; ++ if (dd == NULL) ++ continue; ++ ++ free(dd); ++ cd->domains[domain] = NULL; ++ } ++ ++ free(cd); ++} ++ ++/* ++ * Frees the interval data ++ */ ++static void free_interval_data(void) ++{ ++ struct card_data *cd; ++ int card; ++ ++ for (card = 0; card < NUM_CARDS; card++) { ++ cd = g.cards[card]; ++ if (cd == NULL) ++ continue; ++ ++ free_card_data(cd); ++ g.cards[card] = NULL; ++ } ++} ++ ++/* ++ * Returns the highest card index used by the system. ++ * If there is a card with an index > 0x3f, then the returned number is 0xff, ++ * else 0x3f is returned. ++ */ ++static int get_max_card_index(uint8_t *max_index) ++{ ++ struct dirent **dev_vec = NULL; ++ int i, count, card, rc = 0; ++ char *path; ++ ++ path = util_path_sysfs(SYSFS_DEVICES_AP_PATH); ++ if (!util_path_is_dir(path)) { ++ warnx("Crypto device driver is not available"); ++ rc = -ENODEV; ++ goto out; ++ } ++ ++ count = util_scandir(&dev_vec, NULL, path, "card[0-9a-fA-F]+"); ++ if (count < 1) { ++ warnx("No crypto card devices found"); ++ rc = -ENODEV; ++ goto out; ++ } ++ ++ *max_index = NUM_CARDS_OLD - 1; ++ for (i = 0; i < count; i++) { ++ if (sscanf(dev_vec[i]->d_name, "card%x", &card) != 1) ++ continue; ++ if (card >= NUM_CARDS_OLD) ++ *max_index = NUM_CARDS - 1; ++ } ++ ++ pr_verbose("Max card index used: %u", *max_index); ++ ++out: ++ free(path); ++ if (dev_vec != NULL) ++ free(dev_vec); ++ return rc; ++} ++ ++/* ++ * Returns the size of the CMB. The size is either contained in l4 field ++ * of the cmb, or a fix length dependent on the crypto type, if l4 is zero. ++ */ ++static size_t get_cmb_length(struct chsc_cmb_area *cmb) ++{ ++ size_t len = cmb->header.l4; ++ ++ if (len != 0) ++ return len; ++ ++ switch (cmb->header.ct) { ++ case CRYPTO_TYPE_PCICC: ++ case CRYPTO_TYPE_PCIXCC: ++ case CRYPTO_TYPE_CEX2C: ++ case CRYPTO_TYPE_CEX3C: ++ return 64; ++ case CRYPTO_TYPE_PCICA: ++ return 336; ++ case CRYPTO_TYPE_CEX2A: ++ case CRYPTO_TYPE_CEX3A: ++ return 80; ++ default: ++ warnx("Zero length value in CMB"); ++ return 0; ++ } ++} ++ ++/* ++ * Return true if the device is in the device selection list and mask ++ */ ++static bool filter_device(uint8_t card, uint8_t domain, bool is_apqn) ++{ ++ struct device_selection *dev; ++ bool found; ++ ++ /* Check for selection mask */ ++ if ((g.card_mask[MASK_WORD_NO(card)] & ++ MASK_BIT(card)) == 0) { ++ pr_verbose("Skipping card %02x (mask)", card); ++ return false; ++ } ++ if (is_apqn) { ++ if ((g.domain_mask[MASK_WORD_NO(domain)] & ++ MASK_BIT(domain)) == 0) { ++ pr_verbose("Skipping APQN %02x.%04x (mask)", card, ++ domain); ++ return false; ++ } ++ } ++ ++ /* Check for device selection list */ ++ if (g.dev_selection != NULL) { ++ dev = g.dev_selection; ++ found = false; ++ while (dev != NULL) { ++ if (is_apqn == false) { ++ /* Its a card */ ++ if (card == (dev->card >= 0 ? dev->card : ++ card)) { ++ found = true; ++ break; ++ } ++ } else { ++ /* Its an APQN */ ++ if (card == (dev->card >= 0 ? dev->card : ++ card) && ++ domain == (dev->domain >= 0 ? dev->domain : ++ domain)) { ++ found = true; ++ break; ++ } ++ } ++ ++ dev = dev->next; ++ } ++ ++ if (!found) { ++ if (is_apqn) ++ pr_verbose("Skipping APQN %02x.%04x " ++ "(selection)", card, domain); ++ else ++ pr_verbose("Skipping card %02x (selection)", ++ card); ++ return false; ++ } ++ } ++ ++ if (g.all) ++ return true; ++ ++ /* Check if card/APQN is available in the system (SYSFS) */ ++ if (!is_card_available(card)) { ++ pr_verbose("Skipping card %02x (not available)", card); ++ return false; ++ } ++ if (is_apqn && !is_apqn_available(card, domain)) { ++ pr_verbose("Skipping APQN %02x.%04x (not available)", ++ card, domain); ++ return false; ++ } ++ ++ if (g.only_online) { ++ /* Check if card/APQN is online */ ++ if (!is_card_online(card)) { ++ pr_verbose("Skipping card %02x (not online)", card); ++ return false; ++ } ++ if (is_apqn && !is_apqn_online(card, domain)) { ++ pr_verbose("Skipping APQN %02x.%04x (not online)", ++ card, domain); ++ return false; ++ } ++ } ++ ++ return true; ++} ++ ++/* ++ * Process a crypto measurement block. ++ * Passes back the actual length of the CMB processed and its card number. ++ * Returns -ENODEV when the CMB is skipped. ++ */ ++static int process_cmb(struct chsc_cmb_area *cmb, size_t size, size_t *length, ++ uint8_t *card) ++{ ++ size_t len; ++ ++ len = get_cmb_length(cmb); ++ if (len == 0) ++ return -EINVAL; ++ ++ if (len > size) { ++ warnx("Length value in CMB exceeds size of CMB"); ++ return -EINVAL; ++ } ++ ++ if (card != NULL) ++ *card = cmb->header.ax; ++ if (length != NULL) ++ *length = len; ++ ++ if (filter_device(cmb->header.ax, cmb->header.dx, ++ cmb->header.format == 1) == false) ++ return -ENODEV; ++ ++ if (cmb->header.format == 1) ++ update_apqn_data(cmb->header.ax, cmb->header.dx, cmb, len); ++ else ++ update_card_data(cmb->header.ax, cmb, len); ++ ++ return 0; ++} ++ ++/* ++ * Translate the CHSC response code to an error (0 or negative errno) ++ */ ++static int chsc_error_from_response(int response) ++{ ++ if (response != 0x0001) ++ pr_verbose("CHSC Response code: %04x", response); ++ ++ switch (response) { ++ case 0x0001: ++ return 0; ++ case 0x0002: ++ return -EOPNOTSUPP; ++ case 0x0003: ++ case 0x0006: ++ case 0x0007: ++ case 0x0008: ++ case 0x000a: ++ case 0x0103: ++ case 0x0104: ++ return -EINVAL; ++ case 0x0004: ++ return -EOPNOTSUPP; ++ case 0x000b: ++ return -EBUSY; ++ case 0x0102: ++ return -ENOMEM; ++ case 0x0105: ++ return -EACCES; ++ case 0x0100: ++ case 0x0107: ++ return -ENODEV; ++ default: ++ return -EIO; ++ } ++} ++ ++/* ++ * Process the APQN measurement data and extract the CMBs ++ */ ++static int process_apqn_measurement_data(struct chsc_scdmd_area *scdmd_area) ++{ ++ size_t size = scdmd_area->response.header.length - ++ sizeof(struct chsc_scdmd_response); ++ size_t len, ofs = 0; ++ int rc; ++ ++ while (ofs < size) { ++ rc = process_cmb((struct chsc_cmb_area *) ++ &scdmd_area->response_data[ofs], ++ size - ofs, &len, NULL); ++ if (rc != 0 && rc != -ENODEV) ++ return rc; ++ ofs += len; ++ ++ } ++ ++ return 0; ++} ++ ++/* ++ * Get Crypto Measurement data on the APQN level ++ */ ++static int get_apqn_measurement_data(uint8_t card) ++{ ++ struct chsc_scdmd_area scdmd_area; ++ int rc; ++ ++ memset(&scdmd_area, 0, sizeof(scdmd_area)); ++ do { ++ scdmd_area.request.header.code = 0x102d; ++ scdmd_area.request.header.length = ++ sizeof(struct chsc_scdmd_request); ++ scdmd_area.request.first_drid.ap_index = card; ++ scdmd_area.request.first_drid.domain_index = g.min_domain; ++ scdmd_area.request.last_drid.ap_index = card; ++ scdmd_area.request.last_drid.domain_index = g.max_domain; ++ scdmd_area.request.s = 1; ++ scdmd_area.request.apsm[MASK_WORD_NO(card)] |= MASK_BIT(card); ++ memcpy(scdmd_area.request.dsm, g.domain_mask, ++ sizeof(scdmd_area.request.dsm)); ++ ++ rc = ioctl(g.chsc_fd, CHSC_START_SYNC, &scdmd_area); ++ if (rc != 0) { ++ rc = -errno; ++ warnx("Failed to get APQN measurement data for card " ++ "%02x: %s", card, strerror(errno)); ++ break; ++ } ++ ++ rc = chsc_error_from_response(scdmd_area.response.header.code); ++ if (rc != 0) { ++ if (rc != -EOPNOTSUPP && rc != -ENODEV) { ++ warnx("Failed to get APQN crypto measurement " ++ "data for card %02x: %s", card, ++ strerror(-rc)); ++ } else { ++ pr_verbose("Failed to get APQN crypto " ++ "measurement data for card %02x: %s", ++ card, strerror(-rc)); ++ /* ++ * ignore return code other than -EOPNOTSUPP ++ * and -ENODEV ++ */ ++ rc = 0; ++ } ++ break; ++ } ++ ++ rc = process_apqn_measurement_data(&scdmd_area); ++ if (rc != 0) ++ break; ++ ++ if (scdmd_area.response.p) ++ scdmd_area.request.first_drid = ++ scdmd_area.response.crid; ++ } while (scdmd_area.response.p); ++ ++ return rc; ++} ++ ++/* ++ * Process the card measurement data and extract the CMBs ++ */ ++static int process_card_measurement_data(struct chsc_scmd_area *scmd_area, ++ uint8_t *last_card) ++{ ++ size_t size = scmd_area->response.header.length - ++ sizeof(struct chsc_scmd_response); ++ size_t len, ofs = 0; ++ int rc; ++ ++ while (ofs < size) { ++ rc = process_cmb((struct chsc_cmb_area *) ++ &scmd_area->response_data[ofs], ++ size - ofs, &len, last_card); ++ if (rc != 0 && rc != -ENODEV) ++ return rc; ++ ofs += len; ++ ++ if (rc == -ENODEV) ++ continue; ++ ++ if (!g.no_apqn) { ++ rc = get_apqn_measurement_data(*last_card); ++ if (rc != 0) ++ return rc; ++ } ++ } ++ ++ return 0; ++} ++ ++/* ++ * Get Crypto Measurement data on the card level ++ */ ++static int get_card_measurement_data(void) ++{ ++ struct chsc_scmd_area scmd_area; ++ uint8_t last_card = 0; ++ int rc; ++ ++ memset(&scmd_area, 0, sizeof(scmd_area)); ++ do { ++ scmd_area.request.header.code = 0x102e; ++ scmd_area.request.header.length = ++ sizeof(struct chsc_scmd_request); ++ scmd_area.request.one = 1; ++ scmd_area.request.fcs = g.min_card; ++ scmd_area.request.lcs = g.max_card; ++ ++ rc = ioctl(g.chsc_fd, CHSC_START_SYNC, &scmd_area); ++ if (rc != 0) { ++ rc = -errno; ++ warnx("Failed to get card measurement data: %s", ++ strerror(errno)); ++ break; ++ } ++ ++ rc = chsc_error_from_response(scmd_area.response.header.code); ++ if (rc != 0) { ++ warnx("Failed to get card crypto measurement data: %s", ++ strerror(-rc)); ++ break; ++ } ++ ++ rc = process_card_measurement_data(&scmd_area, &last_card); ++ if (rc != 0) ++ break; ++ ++ if (scmd_area.response.p) ++ scmd_area.request.fcs = last_card + 1; ++ } while (scmd_area.response.p && last_card < g.max_card); ++ ++ return rc; ++} ++ ++/* ++ * Signal handler for SIGALRM ++ */ ++static void alarm_handler(int UNUSED(sig)) ++{ ++ if (!quit) ++ alarm(g.interval); ++} ++ ++/* ++ * Signal handler for SIGINT and SIGTERM ++ */ ++static void int_handler(int UNUSED(sig)) ++{ ++ quit = true; ++ raise(SIGALRM); ++} ++ ++/* ++ * Calculates the time difference between tv1 and tv2 in seconds ++ */ ++static float time_diff(struct timeval *tv1, struct timeval *tv2) ++{ ++ struct timeval tv_diff; ++ ++ tv_diff.tv_sec = tv2->tv_sec - tv1->tv_sec; ++ tv_diff.tv_usec = tv2->tv_usec - tv1->tv_usec; ++ if (tv_diff.tv_usec < 0) { ++ tv_diff.tv_sec--; ++ tv_diff.tv_usec += 1000000; ++ } ++ ++ return (float)tv_diff.tv_sec + (float)(0.000001 * tv_diff.tv_usec); ++} ++ ++/* ++ * Initialize the default print format ++ */ ++static int default_print_initialize(void) ++{ ++ g.device_rec = util_rec_new_wide("-"); ++ util_rec_def(g.device_rec, "device", UTIL_REC_ALIGN_LEFT, 7, ++ "DEVICE"); ++ util_rec_def(g.device_rec, "kind", UTIL_REC_ALIGN_LEFT, 5, ""); ++ util_rec_def(g.device_rec, "type", UTIL_REC_ALIGN_LEFT, 33, ++ "TYPE"); ++ util_rec_def(g.device_rec, "time", UTIL_REC_ALIGN_LEFT, 20, ++ "TIMESTAMP"); ++ ++ g.counter_rec = util_rec_new_wide("-"); ++ util_rec_def(g.counter_rec, "name", UTIL_REC_ALIGN_LEFT, 18, ++ "COUNTER"); ++ util_rec_def(g.counter_rec, "ops", UTIL_REC_ALIGN_RIGHT, 10, ++ "OPS"); ++ util_rec_def(g.counter_rec, "rate", UTIL_REC_ALIGN_RIGHT, 12, ++ "RATE"); ++ util_rec_def(g.counter_rec, "utilization", UTIL_REC_ALIGN_RIGHT, ++ 12, "UTILIZATION"); ++ util_rec_def(g.counter_rec, "duration", UTIL_REC_ALIGN_RIGHT, ++ 15, "AVG.DURATION"); ++ ++ return 0; ++} ++ ++/* ++ * Terminate the default print format ++ */ ++static int default_print_terminate(void) ++{ ++ util_rec_free(g.counter_rec); ++ util_rec_free(g.device_rec); ++ ++ return 0; ++} ++ ++/* ++ * Print the header lines for the default print format ++ */ ++static int default_print_header(void) ++{ ++ char timestamp[64]; ++ struct utsname un; ++ struct tm *tm; ++ time_t t; ++ ++ time(&t); ++ tm = localtime(&t); ++ strftime(timestamp, sizeof(timestamp), "%x", tm); ++ ++ if (uname(&un) != 0) ++ return -errno; ++ ++ printf("%s %s (%s) \t%s\t%s\n\n", un.sysname, un.release, ++ un.nodename, timestamp, un.machine); ++ ++ return 0; ++} ++ ++/* ++ * Print the footer lines for the default print format ++ */ ++static int default_print_footer(void) ++{ ++ printf("\n"); ++ return 0; ++} ++ ++/* ++ * Print the interval header lines for the default print format ++ */ ++static int default_print_interval_header(unsigned long interval_count, ++ const char *timestamp) ++{ ++ ++ printf("*****************************************************" ++ "***************\n"); ++ printf("TIME: %s\t\tINTERVAL: %lu\n\n", timestamp, interval_count); ++ return 0; ++} ++ ++/* ++ * Prints the separator lines in front of a device for the default print format ++ */ ++static int default_print_device_header(bool is_apqn, uint8_t card, ++ uint8_t domain, const char *type, ++ const char *timestamp) ++{ ++ if (is_apqn) ++ util_rec_set(g.device_rec, "device", "%02x.%04x", card, ++ domain); ++ else ++ util_rec_set(g.device_rec, "device", "%02x", card); ++ util_rec_set(g.device_rec, "kind", "%s", ++ is_apqn ? "APQN" : "CARD"); ++ util_rec_set(g.device_rec, "type", "%s", type); ++ util_rec_set(g.device_rec, "time", "%s", timestamp); ++ ++ util_rec_print_hdr(g.device_rec); ++ util_rec_print(g.device_rec); ++ printf("\n"); ++ ++ util_rec_set_indent(g.counter_rec, is_apqn ? 8 : 4); ++ util_rec_print_hdr(g.counter_rec); ++ ++ return 0; ++} ++ ++/* ++ * Prints the separator lines after a device for the default print format ++ */ ++static int default_print_device_footer(void) ++{ ++ ++ printf("\n"); ++ return 0; ++} ++ ++ ++/** ++ * Prints the counter data for the default print format ++ */ ++static int default_print_counter_data(bool UNUSED(is_apqn), ++ uint8_t UNUSED(card), ++ uint8_t UNUSED(domain), ++ const char *UNUSED(type), ++ const char *UNUSED(timestamp), ++ const char *name, ++ struct interval_values *vals) ++{ ++ util_rec_set(g.counter_rec, "name", "%s", name); ++ util_rec_set(g.counter_rec, "ops", "%llu", vals->count); ++ util_rec_set(g.counter_rec, "rate", "%.2f", vals->rate); ++ util_rec_set(g.counter_rec, "utilization", "%.2f %%", ++ vals->utilization * 100); ++ if (vals->duration >= 1) ++ util_rec_set(g.counter_rec, "duration", "%.3f sec ", ++ vals->duration); ++ else if (vals->duration >= 0.001) ++ util_rec_set(g.counter_rec, "duration", "%.3f msec", ++ vals->duration * 1000); ++ else ++ util_rec_set(g.counter_rec, "duration", "%.3f usec", ++ vals->duration * 1000000); ++ util_rec_print(g.counter_rec); ++ ++ return 0; ++} ++ ++/* ++ * Prints a separator between the counter lines and the totals line for the ++ * default print format ++ */ ++static int default_print_counter_separator(void) ++{ ++ util_rec_print_separator(g.counter_rec); ++ return 0; ++} ++ ++/* ++ * Initialize the JSON print format ++ */ ++static int json_print_initialize(void) ++{ ++ /* Use a decimal point to make JSON code compliant with RFC7159 */ ++ setlocale(LC_NUMERIC, "C"); ++ return 0; ++} ++ ++/* ++ * Print the header lines for the JSON print format ++ */ ++static int json_print_header(void) ++{ ++ char timestamp[64]; ++ struct utsname un; ++ struct tm *tm; ++ time_t t; ++ ++ time(&t); ++ tm = localtime(&t); ++ strftime(timestamp, sizeof(timestamp), "%x", tm); ++ ++ if (uname(&un) != 0) ++ return -errno; ++ ++ printf("{\"zcryptstats\": {\n"); ++ printf("\t\"host\": {\n"); ++ printf("\t\t\"nodename\": \"%s\",\n", un.nodename); ++ printf("\t\t\"sysname\": \"%s\",\n", un.sysname); ++ printf("\t\t\"release\": \"%s\",\n", un.release); ++ printf("\t\t\"machine\": \"%s\",\n", un.machine); ++ printf("\t\t\"date\": \"%s\",\n", timestamp); ++ printf("\t\t\"statistics\": [\n"); ++ ++ return 0; ++} ++ ++/* ++ * Print the footer lines for the JSON print format ++ */ ++static int json_print_footer(void) ++{ ++ printf("\n\t\t]\n"); ++ printf("\t}\n"); ++ printf("}}\n"); ++ ++ return 0; ++} ++ ++/* ++ * Print the interval header lines for the JSON print format ++ */ ++static int json_print_interval_header(unsigned long interval_count, ++ const char *timestamp) ++{ ++ if (interval_count > 1) ++ printf(",\n"); ++ printf("\t\t\t{\n"); ++ printf("\t\t\t\t\"interval\": %lu, \"timestamp\": \"%s\"," ++ " \"devices\": [\n", interval_count, timestamp); ++ ++ return 0; ++} ++ ++/* ++ * Print the interval footer lines for the JSON print format ++ */ ++static int json_print_interval_footer(void) ++{ ++ if (!g.first_device) ++ printf("\n"); ++ printf("\t\t\t\t]\n"); ++ printf("\t\t\t}"); ++ ++ return 0; ++} ++ ++/* ++ * Prints the separator lines in front of a device for the JSON print format ++ */ ++static int json_print_device_header(bool is_apqn, uint8_t card, ++ uint8_t domain, const char *type, ++ const char *UNUSED(timestamp)) ++{ ++ if (!g.first_device) ++ printf(",\n"); ++ printf("\t\t\t\t\t{"); ++ if (is_apqn) ++ printf("\"device\": \"%02x.%04x\"", card, ++ domain); ++ else ++ printf("\"device\": \"%02x\"", card); ++ printf(", \"type\": \"%s\",\n", type); ++ printf("\t\t\t\t\t \"counters\": [\n"); ++ ++ return 0; ++} ++ ++/* ++ * Prints the separator lines after a device for the JSON print format ++ */ ++static int json_print_device_footer(void) ++{ ++ if (!g.first_counter) ++ printf("\n"); ++ printf("\t\t\t\t\t ]}"); ++ ++ return 0; ++} ++ ++ ++/** ++ * Prints the counter data for the JSON print format ++ */ ++static int json_print_counter_data(bool UNUSED(is_apqn), ++ uint8_t UNUSED(card), ++ uint8_t UNUSED(domain), ++ const char *UNUSED(type), ++ const char *UNUSED(timestamp), ++ const char *name, ++ struct interval_values *vals) ++{ ++ if (!g.first_counter) ++ printf(",\n"); ++ printf("\t\t\t\t\t\t{\"counter\": \"%s\", \"ops\": %llu, " ++ "\"rate\": %.2f, \"utilization\": %.2f, \"duration\": %.9f}", ++ name, vals->count, vals->rate, vals->utilization * 100, ++ vals->duration); ++ ++ return 0; ++} ++ ++static int table_print_initialize(void) ++{ ++ g.counter_rec = util_rec_new_wide("-"); ++ util_rec_def(g.counter_rec, "time", UTIL_REC_ALIGN_LEFT, 20, ++ "TIMESTAMP"); ++ util_rec_def(g.counter_rec, "device", UTIL_REC_ALIGN_LEFT, 7, ++ "DEVICE"); ++ util_rec_def(g.counter_rec, "ops", UTIL_REC_ALIGN_RIGHT, 10, ++ "OPS"); ++ util_rec_def(g.counter_rec, "rate", UTIL_REC_ALIGN_RIGHT, 12, ++ "RATE"); ++ util_rec_def(g.counter_rec, "utilization", UTIL_REC_ALIGN_RIGHT, ++ 12, "UTILIZATION"); ++ util_rec_def(g.counter_rec, "duration", UTIL_REC_ALIGN_RIGHT, ++ 15, "AVG.DURATION"); ++ return 0; ++} ++ ++static int table_print_terminate(void) ++{ ++ util_rec_free(g.counter_rec); ++ return 0; ++} ++ ++static int table_print_header(void) ++{ ++ int rc; ++ ++ rc = default_print_header(); ++ if (rc != 0) ++ return rc; ++ ++ util_rec_print_hdr(g.counter_rec); ++ return 0; ++} ++ ++static int table_print_interval_footer(void) ++{ ++ util_rec_print_separator(g.counter_rec); ++ return 0; ++} ++ ++static int table_print_counter_data(bool is_apqn, uint8_t card, uint8_t domain, ++ const char *UNUSED(type), ++ const char *timestamp, ++ const char *UNUSED(name), ++ struct interval_values *vals) ++{ ++ if (is_apqn) ++ util_rec_set(g.counter_rec, "device", "%02x.%04x", card, ++ domain); ++ else ++ util_rec_set(g.counter_rec, "device", "%02x", card); ++ util_rec_set(g.counter_rec, "time", "%s", timestamp); ++ ++ util_rec_set(g.counter_rec, "ops", "%llu", vals->count); ++ util_rec_set(g.counter_rec, "rate", "%.2f", vals->rate); ++ util_rec_set(g.counter_rec, "utilization", "%.2f %%", ++ vals->utilization * 100); ++ if (vals->duration >= 1) ++ util_rec_set(g.counter_rec, "duration", "%.3f sec ", ++ vals->duration); ++ else if (vals->duration >= 0.001) ++ util_rec_set(g.counter_rec, "duration", "%.3f msec", ++ vals->duration * 1000); ++ else ++ util_rec_set(g.counter_rec, "duration", "%.3f usec", ++ vals->duration * 1000000); ++ ++ util_rec_print(g.counter_rec); ++ ++ return 0; ++} ++ ++static int csv_print_initialize(void) ++{ ++ /* Use a decimal point to not conflict with the colon separator char */ ++ setlocale(LC_NUMERIC, "C"); ++ ++ g.counter_rec = util_rec_new_csv(","); ++ util_rec_def(g.counter_rec, "time", UTIL_REC_ALIGN_LEFT, 20, ++ "TIMESTAMP"); ++ util_rec_def(g.counter_rec, "device", UTIL_REC_ALIGN_LEFT, 7, ++ "DEVICE"); ++ util_rec_def(g.counter_rec, "ops", UTIL_REC_ALIGN_RIGHT, 10, ++ "OPS"); ++ util_rec_def(g.counter_rec, "rate", UTIL_REC_ALIGN_RIGHT, 12, ++ "RATE"); ++ util_rec_def(g.counter_rec, "utilization", UTIL_REC_ALIGN_RIGHT, ++ 12, "UTILIZATION"); ++ util_rec_def(g.counter_rec, "duration", UTIL_REC_ALIGN_RIGHT, ++ 15, "AVG.DURATION"); ++ return 0; ++} ++ ++static int csv_print_terminate(void) ++{ ++ util_rec_free(g.counter_rec); ++ return 0; ++} ++ ++static int csv_print_header(void) ++{ ++ util_rec_print_hdr(g.counter_rec); ++ return 0; ++} ++ ++ ++static int csv_print_counter_data(bool is_apqn, uint8_t card, uint8_t domain, ++ const char *UNUSED(type), ++ const char *timestamp, ++ const char *UNUSED(name), ++ struct interval_values *vals) ++{ ++ if (is_apqn) ++ util_rec_set(g.counter_rec, "device", "%02x.%04x", card, ++ domain); ++ else ++ util_rec_set(g.counter_rec, "device", "%02x", card); ++ util_rec_set(g.counter_rec, "time", "%s", timestamp); ++ util_rec_set(g.counter_rec, "ops", "%llu", vals->count); ++ util_rec_set(g.counter_rec, "rate", "%.2f", vals->rate); ++ util_rec_set(g.counter_rec, "utilization", "%.2f %%", ++ vals->utilization * 100); ++ util_rec_set(g.counter_rec, "duration", "%.9f", vals->duration); ++ ++ util_rec_print(g.counter_rec); ++ ++ return 0; ++} ++ ++/* ++ * Calculates number of ops, utilization, duration and rate of an ++ * interval from the timer values, scale and interval time. ++ */ ++static void calc_interval_values(struct chsc_cmb_entry *current, ++ struct chsc_cmb_entry *previous, ++ float scale, ++ float interval_time, ++ struct interval_values *result) ++{ ++ u64 tdiff; ++ ++ tdiff = current->t - previous->t; ++ result->count = current->c - previous->c; ++ result->utilization = (double)(tdiff) * scale / interval_time; ++ if (result->count > 0) ++ result->duration = (double)(tdiff) * scale / result->count; ++ else ++ result->duration = 0; ++ result->rate = (double)result->count / interval_time; ++} ++ ++/* ++ * Print the measurement data of an interval ++ */ ++static int print_interval_data(struct interval_data *data, ++ const char *timestamp, float interval_time) ++{ ++ struct chsc_cmb_entry total_current; ++ struct chsc_cmb_entry total_previous; ++ struct interval_values vals; ++ const char *type, *counter; ++ uint32_t mask = 0x80000000; ++ bool totals_found = false; ++ size_t len; ++ int i, rc; ++ ++ len = get_cmb_length(&data->current); ++ type = get_card_name(data->current.header.ct, data->current.header.mt); ++ ++ rc = pr_call(print_device_header)(data->current.header.format == 1, ++ data->current.header.ax, ++ data->current.header.dx, type, ++ timestamp); ++ if (rc != 0) ++ return rc; ++ ++ memset(&total_current, 0, sizeof(total_current)); ++ memset(&total_previous, 0, sizeof(total_previous)); ++ ++ g.first_counter = true; ++ ++ for (i = 0; i < 32 && ++ offsetofend(struct chsc_cmb_area, entries[i]) <= len; i++) { ++ if (data->current.header.v & mask) { ++ if (is_counter_totals(data->current.header.ct, ++ data->current.header.mt, i)) { ++ total_current.t = data->current.entries[i].t; ++ total_current.c = data->current.entries[i].c; ++ total_previous.t = data->previous.entries[i].t; ++ total_previous.c = data->previous.entries[i].c; ++ totals_found = true; ++ } else if (!totals_found) { ++ total_current.t += data->current.entries[i].t; ++ total_current.c += data->current.entries[i].c; ++ total_previous.t += data->previous.entries[i].t; ++ total_previous.c += data->previous.entries[i].c; ++ } ++ ++ if (g.only_totals) ++ continue; ++ ++ calc_interval_values(&data->current.entries[i], ++ &data->previous.entries[i], ++ data->current.header.s, ++ interval_time, ++ &vals); ++ ++ counter = get_counter_name(data->current.header.ct, ++ data->current.header.mt, i); ++ ++ rc = pr_call(print_counter_data)( ++ data->current.header.format == 1, ++ data->current.header.ax, ++ data->current.header.dx, type, ++ timestamp, counter, &vals); ++ if (rc != 0) ++ break; ++ ++ g.first_counter = false; ++ } ++ mask >>= 1; ++ } ++ ++ if (!g.no_totals) { ++ rc = pr_call(print_counter_separator)(); ++ if (rc != 0) ++ return rc; ++ ++ calc_interval_values(&total_current, &total_previous, ++ data->current.header.s, interval_time, ++ &vals); ++ ++ rc = pr_call(print_counter_data)( ++ data->current.header.format == 1, ++ data->current.header.ax, ++ data->current.header.dx, type, ++ timestamp, "Total", &vals); ++ if (rc != 0) ++ return rc; ++ } ++ ++ rc = pr_call(print_device_footer)(); ++ if (rc != 0) ++ return rc; ++ ++ return 0; ++} ++ ++/* ++ * Print the measured data ++ */ ++static int print_measurement_data(unsigned long interval_count, ++ float interval_time, const char *timestamp) ++{ ++ bool header_printed = false; ++ struct interval_data *dd; ++ struct card_data *cd; ++ int card, domain, rc; ++ ++ g.first_device = true; ++ for (card = 0; card < NUM_CARDS; card++) { ++ cd = g.cards[card]; ++ if (cd == NULL) ++ continue; ++ ++ if (!cd->data.current_valid) { ++ /* Not update in last interval -> free it */ ++ free_card_data(cd); ++ g.cards[card] = NULL; ++ ++ pr_verbose("Card %02x removed", card); ++ continue; ++ } ++ ++ if (cd->data.previous_valid) { ++ if (memcmp(&cd->data.current.header, ++ &cd->data.previous.header, ++ sizeof(struct chsc_cmb_header)) != 0) { ++ free_card_data(cd); ++ g.cards[card] = NULL; ++ ++ pr_verbose("CMB header mismatch, card %02x " ++ "removed", card); ++ continue; ++ } ++ ++ if (!header_printed) { ++ rc = pr_call(print_interval_header)( ++ interval_count, timestamp); ++ if (rc != 0) ++ return rc; ++ header_printed = true; ++ } ++ ++ rc = print_interval_data(&cd->data, timestamp, ++ interval_time); ++ if (rc != 0) ++ return rc; ++ ++ g.first_device = false; ++ } ++ ++ cd->data.current_valid = false; ++ ++ for (domain = 0; domain < NUM_DOMAINS; domain++) { ++ dd = cd->domains[domain]; ++ if (dd == NULL) ++ continue; ++ ++ if (!dd->current_valid) { ++ /* Not update in last interval -> free it */ ++ free(dd); ++ cd->domains[domain] = NULL; ++ ++ pr_verbose("APQN %02x.%04x removed", card, ++ domain); ++ } ++ ++ if (dd->previous_valid) { ++ if (memcmp(&dd->current.header, ++ &dd->previous.header, ++ sizeof(struct chsc_cmb_header))) { ++ free(dd); ++ cd->domains[domain] = NULL; ++ ++ pr_verbose("CMB header mismatch, APQN " ++ "%02x.%04x removed", card, ++ domain); ++ continue; ++ } ++ ++ rc = print_interval_data(dd, timestamp, ++ interval_time); ++ if (rc != 0) ++ return rc; ++ } ++ ++ dd->current_valid = false; ++ } ++ } ++ ++ if (header_printed) { ++ rc = pr_call(print_interval_footer)(); ++ if (rc != 0) ++ return rc; ++ } else if (interval_count > 0) { ++ pr_verbose("No data was reported in this interval"); ++ warnx("Failed to get card crypto measurement data: %s", ++ strerror(ENODEV)); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Perform the measurement in intervals ++ */ ++static int perform_measurement(void) ++{ ++ struct timeval tv_current, tv_previous; ++ struct sigaction alrm_act, int_act; ++ unsigned long interval_count = 0; ++ float interval_time; ++ char timestamp[64]; ++ struct tm *tm; ++ int rc; ++ ++ /* Set a handler for SIGINT/SIGTERM */ ++ memset(&int_act, 0, sizeof(int_act)); ++ int_act.sa_handler = int_handler; ++ sigaction(SIGINT, &int_act, NULL); ++ sigaction(SIGTERM, &int_act, NULL); ++ ++ /* Set a handler for SIGALRM */ ++ memset(&alrm_act, 0, sizeof(alrm_act)); ++ alrm_act.sa_handler = alarm_handler; ++ sigaction(SIGALRM, &alrm_act, NULL); ++ ++ rc = pr_call(print_initialize)(); ++ if (rc != 0) ++ return rc; ++ ++ rc = pr_call(print_header)(); ++ if (rc != 0) ++ return 0; ++ ++ alarm(g.interval); ++ ++ memset(&tv_current, 0, sizeof(tv_current)); ++ while (!quit) { ++ pr_verbose("Interval %lu", interval_count); ++ ++ tv_previous = tv_current; ++ rc = gettimeofday(&tv_current, NULL); ++ if (rc != 0) ++ break; ++ ++ tm = localtime(&tv_current.tv_sec); ++ if (tm == NULL) ++ break; ++ strftime(timestamp, sizeof(timestamp), "%x %X", tm); ++ interval_time = time_diff(&tv_previous, &tv_current); ++ ++ rc = get_card_measurement_data(); ++ if (rc != 0) ++ break; ++ ++ rc = print_measurement_data(interval_count, interval_time, ++ timestamp); ++ if (rc != 0) ++ break; ++ ++ if (g.count > 0 && interval_count >= g.count) { ++ pr_verbose("Interval limit reached"); ++ break; ++ } ++ interval_count++; ++ ++ if (quit) ++ break; ++ ++ pause(); ++ } ++ ++ if (quit) ++ pr_verbose("Measurement stopped by user"); ++ ++ alarm(0); ++ memset(&alrm_act, 0, sizeof(alrm_act)); ++ alrm_act.sa_handler = SIG_DFL; ++ sigaction(SIGALRM, &alrm_act, NULL); ++ ++ rc = pr_call(print_footer)(); ++ if (rc != 0) ++ return 0; ++ ++ rc = pr_call(print_terminate)(); ++ if (rc != 0) ++ return rc; ++ ++ return 0; ++} ++ ++/* ++ * Parse the type mapping specification: ++ * TYPE:MODE=TYPE:MODE[,TYPE:MODE=TYPE:MODE[,...]] ++ */ ++static int parse_type_mapping(char *mapping) ++{ ++ unsigned int from_type, to_type, from_mode, to_mode; ++ struct type_mapping *map; ++ char *tok; ++ ++ tok = strtok(mapping, ","); ++ while (tok != NULL) { ++ if (sscanf(tok, "%u:%u=%u:%u", &from_type, &from_mode, ++ &to_type, &to_mode) != 4) { ++ warnx("Invalid type mapping: %s", tok); ++ return -EINVAL; ++ } ++ ++ pr_verbose("from_type: %u from_mode: %u to_type: %u " ++ "to_mode: %u", from_type, from_mode, to_type, ++ to_mode); ++ ++ if (from_type < NUM_CRYPTO_TYPES && ++ crypto_types[from_type].name != NULL && ++ from_mode < crypto_types[from_type].num_modes && ++ crypto_types[from_type].modes[from_mode].counters != NULL) { ++ warnx("Cannot map a known type/mode to another " ++ "type/mode: %s", tok); ++ return -EINVAL; ++ } ++ ++ if (to_type >= NUM_CRYPTO_TYPES || ++ crypto_types[to_type].name == NULL || ++ to_mode >= crypto_types[to_type].num_modes || ++ crypto_types[to_type].modes[to_mode].counters == NULL) { ++ warnx("Cannot map a type/mode to an unknown " ++ "type/mode: %s", tok); ++ return -EINVAL; ++ } ++ ++ map = util_malloc(sizeof(struct type_mapping)); ++ map->from_type = from_type; ++ map->from_mode = from_mode; ++ map->to_type = to_type; ++ map->to_mode = to_mode; ++ ++ map->next = g.type_mapping; ++ g.type_mapping = map; ++ ++ tok = strtok(NULL, ","); ++ } ++ ++ return 0; ++} ++ ++static void free_type_mapping(void) ++{ ++ struct type_mapping *map = g.type_mapping; ++ struct type_mapping *next; ++ ++ while (map != NULL) { ++ next = map->next; ++ free(map); ++ map = next; ++ } ++} ++ ++static int add_device_selection(const char *device_id) ++{ ++ int card = -1, domain = -1; ++ struct device_selection *dev; ++ ++ pr_verbose("device_id: '%s'", device_id); ++ ++ /* check for 'card[.domain]' specification */ ++ if (sscanf(device_id, "%x.%x", &card, &domain) >= 1) { ++ pr_verbose("card: %d domain: %d", card, domain); ++ if (card < 0 || card > g.max_card_used) { ++ warnx("Invalid card specified: %s", device_id); ++ return -EINVAL; ++ } ++ g.card_mask[MASK_WORD_NO(card)] |= MASK_BIT(card); ++ g.min_card = MIN(g.min_card, card); ++ g.max_card = MAX(g.max_card, card); ++ ++ if (domain >= 0) { ++ if (domain > NUM_DOMAINS) { ++ warnx("Invalid domain specified: %s", ++ device_id); ++ return -EINVAL; ++ } ++ g.domain_mask[MASK_WORD_NO(domain)] |= ++ MASK_BIT(domain); ++ g.min_domain = MIN(g.max_domain, domain); ++ g.max_domain = MAX(g.max_domain, domain); ++ } else { ++ memset(g.domain_mask, 0xff, sizeof(g.domain_mask)); ++ g.min_domain = 0; ++ g.max_domain = NUM_DOMAINS - 1; ++ } ++ ++ dev = util_malloc(sizeof(struct device_selection)); ++ dev->card = card; ++ dev->domain = domain; ++ dev->next = g.dev_selection; ++ g.dev_selection = dev; ++ ++ return 0; ++ } ++ /* check for '.domain' specification */ ++ if (device_id[0] == '.' && ++ sscanf(device_id + 1, "%x", &domain) == 1) { ++ pr_verbose("domain: %d", domain); ++ if (domain < 0 || domain > NUM_DOMAINS) { ++ warnx("Invalid domain specified: %s", device_id); ++ return -EINVAL; ++ } ++ ++ g.domain_mask[MASK_WORD_NO(domain)] |= MASK_BIT(domain); ++ g.min_domain = MIN(g.max_domain, domain); ++ g.max_domain = MAX(g.max_domain, domain); ++ memset(g.card_mask, 0xff, sizeof(g.card_mask)); ++ g.min_card = 0; ++ g.max_card = g.max_card_used; ++ ++ dev = util_malloc(sizeof(struct device_selection)); ++ dev->card = -1; ++ dev->domain = domain; ++ dev->next = g.dev_selection; ++ g.dev_selection = dev; ++ ++ return 0; ++ } ++ ++ warnx("Invalid device ID specified: %s", device_id); ++ return -EINVAL; ++} ++ ++/* ++ * Frees the device selection list ++ */ ++static void free_device_selection(void) ++{ ++ struct device_selection *dev = g.dev_selection; ++ struct device_selection *next; ++ ++ while (dev != NULL) { ++ next = dev->next; ++ free(dev); ++ ++ dev = next; ++ } ++} ++ ++/* ++ * Build the AP and domain selection mask from the specified device ID's. ++ */ ++static int parse_device_selection(void) ++{ ++ int i, rc; ++ ++ g.min_card = NUM_CARDS - 1; ++ g.max_card = 0; ++ g.min_domain = NUM_DOMAINS - 1; ++ g.max_domain = 0; ++ ++ for (i = 0; g.device_ids[i] != NULL; i++) { ++ rc = add_device_selection(g.device_ids[i]); ++ if (rc != 0) ++ return rc; ++ } ++ ++ if (i == 0) { ++ /* No device-IDs specified */ ++ memset(g.card_mask, 0xff, sizeof(g.card_mask)); ++ g.min_card = 0; ++ g.max_card = g.max_card_used; ++ memset(g.domain_mask, 0xff, sizeof(g.domain_mask)); ++ g.min_domain = 0; ++ g.max_domain = NUM_DOMAINS - 1; ++ } ++ ++ pr_verbose("Min card: %u, max card: %u", g.min_card, g.max_card); ++ pr_verbose("Min domain: %u, max domain: %u", g.min_domain, ++ g.max_domain); ++ ++ return 0; ++} ++ ++/* ++ * Entry point ++ */ ++int main(int argc, char *argv[]) ++{ ++ char *endp; ++ int c, rc; ++ ++ util_prg_init(&prg); ++ util_opt_init(opt_vec, NULL); ++ ++ while (1) { ++ c = util_opt_getopt_long(argc, argv); ++ if (c == -1) ++ break; ++ switch (c) { ++ case 'i': ++ g.interval = strtoll(optarg, &endp, 0); ++ if (*optarg == '\0' || *endp != '\0' || ++ g.interval <= 0 || ++ (g.interval == LLONG_MAX && errno == ERANGE)) { ++ warnx("Invalid value for '--interval'|" ++ "'-i': '%s'", optarg); ++ util_prg_print_parse_error(); ++ return EXIT_FAILURE; ++ } ++ break; ++ case 'c': ++ g.count = strtoull(optarg, &endp, 0); ++ if (*optarg == '\0' || *endp != '\0' || g.count == 0 || ++ (g.count == LLONG_MAX && errno == ERANGE)) { ++ warnx("Invalid value for '--count'|" ++ "'-c': '%s'", optarg); ++ util_prg_print_parse_error(); ++ return EXIT_FAILURE; ++ } ++ break; ++ case 'o': ++ if (strcasecmp(optarg, "JSON") == 0) { ++ g.print_funcs = &json_print; ++ } else if (strcasecmp(optarg, "TABLE") == 0) { ++ g.only_totals = true; ++ g.print_funcs = &table_print; ++ } else if (strcasecmp(optarg, "CSV") == 0) { ++ g.only_totals = true; ++ g.print_funcs = &csv_print; ++ } else { ++ warnx("Invalid value for '--output'|" ++ "'-o': '%s'", optarg); ++ util_prg_print_parse_error(); ++ return EXIT_FAILURE; ++ } ++ break; ++ case 't': ++ g.no_totals = true; ++ break; ++ case 'T': ++ g.only_totals = true; ++ break; ++ case 'a': ++ g.no_apqn = true; ++ break; ++ case 'M': ++ g.map_type = optarg; ++ break; ++ case 'A': ++ g.all = true; ++ break; ++ case 'O': ++ g.only_online = true; ++ break; ++ case 'V': ++ g.verbose = true; ++ break; ++ case 'h': ++ util_prg_print_help(); ++ util_opt_print_help(); ++ print_adapter_id_help(); ++ return EXIT_SUCCESS; ++ case 'v': ++ util_prg_print_version(); ++ return EXIT_SUCCESS; ++ default: ++ util_opt_print_parse_error(c, argv); ++ return EXIT_FAILURE; ++ } ++ } ++ ++ /* remaining positional args are device IDs */ ++ g.device_ids = &argv[optind]; ++ ++ if (g.only_totals && g.no_totals) { ++ warnx("Either --no-totals or --only-totals can be specified, " ++ "but not both"); ++ return EXIT_FAILURE; ++ } ++ ++ if (g.only_online && g.all) { ++ warnx("Either --only-online or --all can be specified, " ++ "but not both"); ++ return EXIT_FAILURE; ++ } ++ ++ pr_verbose("Interval: %ld Count: %ld", g.interval, g.count); ++ ++ rc = get_max_card_index(&g.max_card_used); ++ if (rc != 0) { ++ rc = EXIT_FAILURE; ++ goto out; ++ } ++ ++ rc = parse_device_selection(); ++ if (rc != 0) { ++ rc = EXIT_FAILURE; ++ goto out; ++ } ++ ++ if (g.map_type != NULL) { ++ rc = parse_type_mapping(g.map_type); ++ if (rc != 0) { ++ rc = EXIT_FAILURE; ++ goto out; ++ } ++ } ++ ++ g.chsc_fd = open(CHSC_DEVICE, O_RDWR); ++ if (g.chsc_fd < 0) { ++ warnx("File '%s:' %s", CHSC_DEVICE, strerror(errno)); ++ return EXIT_FAILURE; ++ } ++ pr_verbose("Device '%s' has been opened successfully", CHSC_DEVICE); ++ ++ /* Don't buffer data if redirected to a pipe */ ++ setbuf(stdout, NULL); ++ ++ rc = perform_measurement(); ++ if (rc != 0) { ++ rc = EXIT_FAILURE; ++ goto out; ++ } ++out: ++ if (g.chsc_fd >= 0) ++ close(g.chsc_fd); ++ free_device_selection(); ++ free_type_mapping(); ++ free_interval_data(); ++ ++ return rc; ++} ++ +-- +2.21.0 + + +From c0670b62ccd7a9f1f1b3a8a49114c2e3c673ecd9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jan=20H=C3=B6ppner?= +Date: Mon, 1 Apr 2019 09:53:06 +0200 +Subject: [PATCH 21/21] zpcictl: Check for regular directory (#1695001) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +In case a regular directory was specified, rather than a device node, +the check if the device exists will pass. The following code paths then +assume a slot id was specified. This in turn may lead to a buffer +overflow when the device data is copied to to the zpci_device struct. + +Check if the specified path is a regular directory and prevent a +possible later buffer overflow and copying wrong data respectively. + +Signed-off-by: Jan Höppner +(cherry picked from commit c7a255fcd9433bba6dd516f6b28a139bbc5351d3) +--- + zpcictl/zpcictl.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/zpcictl/zpcictl.c b/zpcictl/zpcictl.c +index 7cfa0d3..f2a55ad 100644 +--- a/zpcictl/zpcictl.c ++++ b/zpcictl/zpcictl.c +@@ -249,8 +249,12 @@ static int device_exists(char *dev) + char *path; + int rc = 0; + ++ /* In case a device node is specified, this will be sufficiant */ ++ if (util_path_exists(dev) && !util_path_is_dir(dev)) ++ return 1; ++ + path = util_path_sysfs("bus/pci/devices/%s", dev); +- if (util_path_exists(path) || util_path_exists(dev)) ++ if (util_path_exists(path)) + rc = 1; + free(path); + +-- +2.21.0 + diff --git a/SOURCES/s390-tools-zipl-fiemap.patch b/SOURCES/s390-tools-zipl-fiemap.patch new file mode 100644 index 0000000..032e1f4 --- /dev/null +++ b/SOURCES/s390-tools-zipl-fiemap.patch @@ -0,0 +1,106 @@ +From 0318dfbc726a82ce1e9309e55186f3c4faae72f1 Mon Sep 17 00:00:00 2001 +From: Eric Sandeen +Date: Wed, 12 Sep 2018 09:40:22 -0500 +Subject: [PATCH] zipl: use FIEMAP mapping ioctl if it exists + +zipl currently uses the FIBMAP ioctl to map blocks for the bootloader; +on XFS, if FIBMAP is requested on a reflinked file, it will fail - +and FIBMAP returns 0 in this case, which is indistinguishable from a +hole. This causes boot to fail because the file is not mapped. + +We can use the FIEMAP ioctl instead, which is able to map reflinked +files. While FIEMAP is able to map entire extents at once, here we +simply use it to obtain the mapping block-by-block so that it fits +in with the current FIBMAP calls. + +Signed-off-by: Eric Sandeen +--- + zipl/src/disk.c | 57 +++++++++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 53 insertions(+), 4 deletions(-) + +diff --git a/zipl/src/disk.c b/zipl/src/disk.c +index 0d8e7796..43092bf1 100644 +--- a/zipl/src/disk.c ++++ b/zipl/src/disk.c +@@ -21,6 +21,8 @@ + #include + #include + #include ++#include ++#include + + #include "lib/util_proc.h" + +@@ -550,8 +552,12 @@ disk_get_blocknum(int fd, int fd_is_basedisk, blocknum_t logical, + { + struct statfs buf; + blocknum_t phy_per_fs; +- int mapped; ++ blocknum_t mapped; ++ int block; + int subblock; ++ int fiemap_size; ++ int map_offset; ++ struct fiemap *fiemap; + + /* No file system: partition or raw disk */ + if (info->fs_block_size == -1) { +@@ -576,12 +582,55 @@ disk_get_blocknum(int fd, int fd_is_basedisk, blocknum_t logical, + } + /* Get mapping in file system blocks */ + phy_per_fs = info->fs_block_size / info->phy_block_size; +- mapped = logical / phy_per_fs; + subblock = logical % phy_per_fs; +- if (ioctl(fd, FIBMAP, &mapped)) { +- error_reason("Could not get file mapping"); ++ ++ /* First try FIEMAP, more complicated to set up */ ++ fiemap_size = sizeof(struct fiemap) + sizeof(struct fiemap_extent); ++ ++ fiemap = misc_malloc(fiemap_size); ++ if (!fiemap) + return -1; ++ memset(fiemap, 0, fiemap_size); ++ ++ fiemap->fm_extent_count = 1; ++ fiemap->fm_flags = FIEMAP_FLAG_SYNC; ++ /* fm_start, fm_length in bytes; logical is in physical block units */ ++ fiemap->fm_start = logical * info->phy_block_size; ++ fiemap->fm_length = info->phy_block_size; ++ ++ if (ioctl(fd, FS_IOC_FIEMAP, (unsigned long)fiemap)) { ++ /* FIEMAP failed, fall back to FIBMAP */ ++ block = logical / phy_per_fs; ++ if (ioctl(fd, FIBMAP, &block)) { ++ error_reason("Could not get file mapping"); ++ free(fiemap); ++ return -1; ++ } ++ mapped = block; ++ } else { ++ if (fiemap->fm_mapped_extents) { ++ if (fiemap->fm_extents[0].fe_flags & ++ FIEMAP_EXTENT_ENCODED) { ++ error_reason("File mapping is encoded"); ++ free(fiemap); ++ return -1; ++ } ++ /* ++ * returned extent may start prior to our request ++ */ ++ map_offset = fiemap->fm_start - ++ fiemap->fm_extents[0].fe_logical; ++ mapped = fiemap->fm_extents[0].fe_physical + ++ map_offset; ++ /* set mapped to fs block units */ ++ mapped = mapped / info->fs_block_size; ++ } else { ++ mapped = 0; ++ } + } ++ ++ free(fiemap); ++ + if (mapped == 0) { + /* This is a hole in the file */ + *physical = 0; diff --git a/SOURCES/s390-tools-zipl-invert-script-options.patch b/SOURCES/s390-tools-zipl-invert-script-options.patch new file mode 100644 index 0000000..93d5cc7 --- /dev/null +++ b/SOURCES/s390-tools-zipl-invert-script-options.patch @@ -0,0 +1,84 @@ +From 2faae5cf51c49e3f166b8526eee276dab2fe7308 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Wed, 30 May 2018 14:33:25 +0200 +Subject: [PATCH] zipl-switch-to-blscfg: invert ignore-default and + use-version-name options + +These options were added because the zipl maintainers wanted a different +default behaviour for the migration script than the one we use. Instead +of requiring to always use these options, just invert the logic for us. + +Signed-off-by: Javier Martinez Canillas +--- + scripts/zipl-switch-to-blscfg | 16 +++++++++------- + scripts/zipl-switch-to-blscfg.1 | 8 ++++---- + 2 files changed, 13 insertions(+), 11 deletions(-) + +diff --git a/scripts/zipl-switch-to-blscfg b/scripts/zipl-switch-to-blscfg +index 871935c783f..d8d5eca5867 100755 +--- a/scripts/zipl-switch-to-blscfg ++++ b/scripts/zipl-switch-to-blscfg +@@ -57,14 +57,14 @@ Options: + --backup-suffix=SUFFIX suffix used for backup files, defaults to .bak + --bls-directory=DIR path to generate BLS files, defaults to /boot/loader/entries + --config-file=FILE path to zipl configuration file, defaults to /etc/zipl.conf +- --ignore-default ignore the default option from the zipl configuration file +- --use-version-name use the section kernel version as the BLS file name ++ --leave-default leave the default option from the zipl configuration file ++ --use-section-name use the section name as the BLS file name + + EOF + } + + OPTS="$(getopt -o hv --long help,version,backup-suffix:,bls-directory:,config-file:,\ +-ignore-default,use-version-name -n \'$SCRIPTNAME\' -- "$@")" ++leave-default,use-section-name -n \'$SCRIPTNAME\' -- "$@")" + eval set -- "$OPTS" + + BACKUP_SUFFIX=.bak +@@ -73,6 +73,8 @@ CMDLINE_LINUX_DEBUG=" systemd.log_level=debug systemd.log_target=kmsg" + LINUX_DEBUG_VERSION_POSTFIX="_with_debugging" + LINUX_DEBUG_TITLE_POSTFIX=" with debugging" + CONFIG="/etc/zipl.conf" ++ignore_default=true ++version_name=true + + while [ ${#} -gt 0 ]; do + case "$1" in +@@ -96,11 +98,11 @@ while [ ${#} -gt 0 ]; do + CONFIG=${2} + shift + ;; +- --ignore-default) +- ignore_default=true ++ --leave-default) ++ ignore_default=false + ;; +- --use-version-name) +- version_name=true ++ --use-section-name) ++ version_name=false + ;; + --) + shift +diff --git a/scripts/zipl-switch-to-blscfg.1 b/scripts/zipl-switch-to-blscfg.1 +index 6bd14d00d14..71b904ffd1c 100644 +--- a/scripts/zipl-switch-to-blscfg.1 ++++ b/scripts/zipl-switch-to-blscfg.1 +@@ -37,9 +37,9 @@ The DIRECTORY where the BLS fragments will be generated. The directory is create + The FILE used for zipl configuration file, defaults to /etc/zipl.conf. + + .TP +-\fB\-\-ignore-default\fP +-Ignore the default option from the zipl configuration file ++\fB\-\-leave-default\fP ++Leave the default option from the zipl configuration file + + .TP +-\fB\-\-use-version-name\fP +-Use the section kernel version as the BLS file name ++\fB\-\-use-section-name\fP ++Use the section name as the BLS file name +-- +2.17.0 + diff --git a/SOURCES/s390-tools-zipl-sort-like-rpm.patch b/SOURCES/s390-tools-zipl-sort-like-rpm.patch new file mode 100644 index 0000000..6cfff9b --- /dev/null +++ b/SOURCES/s390-tools-zipl-sort-like-rpm.patch @@ -0,0 +1,148 @@ +From 8ec7b75204f3c7bf691e14b89c73c5dd28d2a824 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 15 Oct 2018 13:54:16 -0400 +Subject: [PATCH] blscfg: sort like rpm nvr, not like a single version + +Signed-off-by: Peter Jones +--- + zipl/src/scan.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++- + zipl/src/Makefile | 3 +- + 2 files changed, 96 insertions(+), 3 deletions(-) + +diff --git a/zipl/src/scan.c b/zipl/src/scan.c +index fe72e9ab13d..63186222783 100644 +--- a/zipl/src/scan.c ++++ b/zipl/src/scan.c +@@ -33,6 +33,8 @@ + + #include "lib/util_base.h" + ++#include ++ + #include "boot.h" + #include "error.h" + #include "misc.h" +@@ -652,14 +654,104 @@ bls_filter(const struct dirent *ent) + return strncmp(ent->d_name + offset, ".conf", strlen(".conf")) == 0; + } + ++/* returns name/version/release */ ++/* NULL string pointer returned if nothing found */ ++static void ++split_package_string (char *package_string, char **name, ++ char **version, char **release) ++{ ++ char *package_version, *package_release; ++ ++ /* Release */ ++ package_release = strrchr (package_string, '-'); ++ ++ if (package_release != NULL) ++ *package_release++ = '\0'; ++ ++ *release = package_release; ++ ++ /* Version */ ++ package_version = strrchr(package_string, '-'); ++ ++ if (package_version != NULL) ++ *package_version++ = '\0'; ++ ++ *version = package_version; ++ /* Name */ ++ *name = package_string; ++ ++ /* Bubble up non-null values from release to name */ ++ if (name != NULL && *name == NULL) { ++ *name = (*version == NULL ? *release : *version); ++ *version = *release; ++ *release = NULL; ++ } ++ if (*version == NULL) { ++ *version = *release; ++ *release = NULL; ++ } ++} ++ ++static int ++split_cmp(char *nvr0, char *nvr1, int has_name) ++{ ++ int ret = 0; ++ char *name0, *version0, *release0; ++ char *name1, *version1, *release1; ++ ++ split_package_string(nvr0, has_name ? &name0 : NULL, &version0, &release0); ++ split_package_string(nvr1, has_name ? &name1 : NULL, &version1, &release1); ++ ++ if (has_name) { ++ ret = rpmvercmp(name0 == NULL ? "" : name0, ++ name1 == NULL ? "" : name1); ++ if (ret != 0) ++ return ret; ++ } ++ ++ ret = rpmvercmp(version0 == NULL ? "" : version0, ++ version1 == NULL ? "" : version1); ++ if (ret != 0) ++ return ret; ++ ++ ret = rpmvercmp(release0 == NULL ? "" : release0, ++ release1 == NULL ? "" : release1); ++ return ret; ++} ++ ++/* return 1: filename0 is newer than filename1 */ ++/* 0: filename0 and filename1 are the same version */ ++/* -1: filename1 is newer than filename0 */ ++static int bls_cmp(const char *filename0, const char *filename1) ++{ ++ char *id0, *id1; ++ int l, r; ++ ++ id0 = strdup(filename0); ++ id1 = strdup(filename1); ++ ++ l = strlen(id0); ++ if (l > 5 && strcmp(id0 + l - 5, ".conf")) ++ id0[l-5] = '\0'; ++ ++ l = strlen(id1); ++ if (l > 5 && strcmp(id1 + l - 5, ".conf")) ++ id1[l-5] = '\0'; ++ ++ r = split_cmp(id0, id1, 1); ++ ++ free(id0); ++ free(id1); ++ ++ return r; ++} + + static int + bls_sort(const struct dirent **ent_a, const struct dirent **ent_b) + { +- return strverscmp((*ent_a)->d_name, (*ent_b)->d_name); ++ return bls_cmp((*ent_a)->d_name, (*ent_b)->d_name); + } + +- + static int + scan_append_section_heading(struct scan_token* scan, int* index, char* name); + static int +diff --git a/zipl/src/Makefile b/zipl/src/Makefile +index 1634c0d5121..bc797990652 100644 +--- a/zipl/src/Makefile ++++ b/zipl/src/Makefile +@@ -11,7 +11,8 @@ ALL_CPPFLAGS += -I../include -I../boot \ + ALL_LDFLAGS += -Wl,-z,noexecstack $(NO_PIE_LDFLAGS) + + libs = $(rootdir)/libutil/libutil.a \ +- $(rootdir)/libu2s/libu2s.a ++ $(rootdir)/libu2s/libu2s.a \ ++ -lrpm + + objects = misc.o error.o scan.o job.o boot.o bootmap.o disk.o \ + install.o zipl.o $(rootdir)/zipl/boot/data.o +-- +2.17.1 + diff --git a/SOURCES/s390-tools-zipl-title-section-name.patch b/SOURCES/s390-tools-zipl-title-section-name.patch new file mode 100644 index 0000000..f0523c6 --- /dev/null +++ b/SOURCES/s390-tools-zipl-title-section-name.patch @@ -0,0 +1,50 @@ +From ce171812a829d6e0fe1c7d1f91d2ddd301f03bec Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Tue, 6 Nov 2018 13:29:32 +0100 +Subject: [PATCH] zipl: use the BLS "title" field as the IPL section name + +Most bootloaders use the BootLoaderSpec "title" field to name the entries +in their boot menu. The zipl bootloader used the "version" field instead, +since it was wrongly assumed that the zipl boot menu didn't support names +that contained spaces, which are usually present in a BLS "title" field. + +But this is not the case, names with space characters are supported by the +IPL and is just a constraint of the section heading in the zipl.conf file. + +So to be consistent with all the other bootloaders, use the "title" field +also on zipl when populating the boot menu entries from BLS files. + +Signed-off-by: Javier Martinez Canillas +--- + scripts/zipl-switch-to-blscfg | 1 + + zipl/src/scan.c | 2 +- + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/scripts/zipl-switch-to-blscfg b/scripts/zipl-switch-to-blscfg +index 5272033e9848..5141b1c0dd6d 100755 +--- a/scripts/zipl-switch-to-blscfg ++++ b/scripts/zipl-switch-to-blscfg +@@ -150,6 +150,7 @@ while IFS='= ' read key val; do + if [ -f "${OUTPUT}" ]; then + print_error "BLS file ${OUTPUT} already exists" + fi ++ echo "title $section" >> ${OUTPUT} + fi + elif [[ $val ]]; then + val="$(echo $val | sed -e 's/^[ \t"]*//;s/[ \t"]*$//')" +diff --git a/zipl/src/scan.c b/zipl/src/scan.c +index fe72e9ab13df..9160d083e5cb 100644 +--- a/zipl/src/scan.c ++++ b/zipl/src/scan.c +@@ -701,7 +701,7 @@ scan_bls_field(struct misc_file_buffer *file, struct scan_token* scan, + file->buffer[key_end] = '\0'; + file->buffer[val_end] = '\0'; + +- if (strncmp("version", &file->buffer[key_start], key_end - key_start) == 0) { ++ if (strncmp("title", &file->buffer[key_start], key_end - key_start) == 0) { + scan_append_section_heading(scan, index, &file->buffer[val_start]); + } + +-- +2.19.1 + diff --git a/SOURCES/zfcp.udev b/SOURCES/zfcp.udev new file mode 100644 index 0000000..5558f8b --- /dev/null +++ b/SOURCES/zfcp.udev @@ -0,0 +1 @@ +KERNEL=="zfcp", RUN+="/sbin/zfcpconf.sh" diff --git a/SOURCES/zfcpconf.sh b/SOURCES/zfcpconf.sh new file mode 100644 index 0000000..45d10a1 --- /dev/null +++ b/SOURCES/zfcpconf.sh @@ -0,0 +1,56 @@ +#!/bin/sh + +# config file syntax: +# deviceno WWPN FCPLUN +# +# Example: +# 0.0.4000 0x5005076300C213e9 0x5022000000000000 +# 0.0.4001 0x5005076300c213e9 0x5023000000000000 +# +# +# manual setup: +# modprobe zfcp +# echo 1 > /sys/bus/ccw/drivers/zfcp/0.0.4000/online +# echo LUN > /sys/bus/ccw/drivers/zfcp/0.0.4000/WWPN/unit_add +# +# Example: +# modprobe zfcp +# echo 1 > /sys/bus/ccw/drivers/zfcp/0.0.4000/online +# echo 0x5022000000000000 > /sys/bus/ccw/drivers/zfcp/0.0.4000/0x5005076300c213e9/unit_add + +CONFIG=/etc/zfcp.conf +PATH=/bin:/sbin + +if [ -f "$CONFIG" ]; then + if [ ! -d /sys/bus/ccw/drivers/zfcp ]; then + modprobe zfcp + fi + if [ ! -d /sys/bus/ccw/drivers/zfcp ]; then + return + fi + sed 'y/ABCDEF/abcdef/' < $CONFIG | while read line; do + case $line in + \#*) ;; + *) + [ -z "$line" ] && continue + set $line + if [ $# -eq 5 ]; then + DEVICE=$1 + SCSIID=$2 + WWPN=$3 + SCSILUN=$4 + FCPLUN=$5 + echo "Warning: Deprecated values in /etc/zfcp.conf, ignoring SCSI ID $SCSIID and SCSI LUN $SCSILUN" + elif [ $# -eq 3 ]; then + DEVICE=${1##*0x} + WWPN=$2 + FCPLUN=$3 + fi + [ `cat /sys/bus/ccw/drivers/zfcp/${DEVICE}/online` = "0" ] \ + && echo 1 > /sys/bus/ccw/drivers/zfcp/${DEVICE}/online + [ ! -d /sys/bus/ccw/drivers/zfcp/${DEVICE}/${WWPN}/${FCPLUN} ] \ + && echo $FCPLUN > /sys/bus/ccw/drivers/zfcp/${DEVICE}/${WWPN}/unit_add + ;; + esac + done +fi diff --git a/SPECS/s390utils.spec b/SPECS/s390utils.spec new file mode 100644 index 0000000..39d56ed --- /dev/null +++ b/SPECS/s390utils.spec @@ -0,0 +1,1742 @@ +%define cmsfsver 1.1.8c +%define vipaver 2.1.0 + +Name: s390utils +Summary: Utilities and daemons for IBM z Systems +Group: System Environment/Base +Version: 2.6.0 +Release: 15%{?dist} +Epoch: 2 +License: MIT +ExclusiveArch: s390 s390x +#URL: http://www.ibm.com/developerworks/linux/linux390/s390-tools.html +URL: https://github.com/ibm-s390-tools/s390-tools +Source0: https://github.com/ibm-s390-tools/s390-tools/archive/v%{version}.tar.gz#/s390-tools-%{version}.tar.gz +Source4: http://www.linuxvm.org/Patches/S390/cmsfs-%{cmsfsver}.tar.gz +Source5: zfcpconf.sh +# http://www.ibm.com/developerworks/linux/linux390/src_vipa-%%{vipaver}.html +Source6: http://download.boulder.ibm.com/ibmdl/pub/software/dw/linux390/ht_src/src_vipa-%{vipaver}.tar.gz +Source7: zfcp.udev +# files for DASD initialization +Source12: dasd.udev +Source13: dasdconf.sh +Source14: device_cio_free +Source15: device_cio_free.service +Source16: ccw_init +Source17: ccw.udev +Source21: normalize_dasd_arg +Source22: 00-zipl-prepare.install +Source23: 20-zipl-kernel.install +Source24: 52-zipl-rescue.install +Source25: 91-zipl.install + +# backported stuff for RHEL +Patch0: s390-tools-rhel.patch +# BLS support in zipl +# change the defaults to match Fedora environment +Patch100: s390-tools-zipl-invert-script-options.patch +# https://github.com/ibm-s390-tools/s390-tools/pull/36 +Patch101: s390-tools-zipl-fiemap.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1640968 +Patch102: s390-tools-zipl-sort-like-rpm.patch +# https://github.com/ibm-s390-tools/s390-tools/pull/47 +Patch103: s390-tools-zipl-title-section-name.patch + +Patch1000: cmsfs-1.1.8-warnings.patch +Patch1001: cmsfs-1.1.8-kernel26.patch +Patch1002: cmsfs-1.1.8-use-detected-filesystem-block-size-on-FBA-devices.patch + +Requires: s390utils-base = %{epoch}:%{version}-%{release} +Requires: s390utils-osasnmpd = %{epoch}:%{version}-%{release} +Requires: s390utils-cpuplugd = %{epoch}:%{version}-%{release} +Requires: s390utils-mon_statd = %{epoch}:%{version}-%{release} +Requires: s390utils-iucvterm = %{epoch}:%{version}-%{release} +Requires: s390utils-ziomon = %{epoch}:%{version}-%{release} +Requires: s390utils-cmsfs = %{epoch}:%{version}-%{release} + +BuildRequires: gcc-c++ +BuildRequires: rpm-devel + +%description +This is a meta package for installing the default s390-tools sub packages. +If you do not need all default sub packages, it is recommended to install the +required sub packages separately. + +The s390utils packages contain a set of user space utilities that should to +be used together with the zSeries (s390) Linux kernel and device drivers. + +%prep +%setup -q -n s390-tools-%{version} -a 4 -a 6 + +# Backported suff for RHEL +%patch0 -p1 + +# BLS support in zipl +%patch100 -p1 -b .zipl-invert-script-options +%patch101 -p1 -b .zipl-fiemap +%patch102 -p1 -b .zipl-sort-like-rpm +%patch103 -p1 -b .zipl-title-section-name + +# +# cmsfs +# +pushd cmsfs-%{cmsfsver} +# Patch to fix a couple of code bugs +%patch1000 -p1 -b .warnings + +# build on kernel-2.6, too +%patch1001 -p1 -b .cmsfs26 + +# use detected filesystem block size (#651012) +%patch1002 -p1 -b .use-detected-block-size +popd + + +# remove --strip from install +find . -name Makefile | xargs sed -i 's/$(INSTALL) -s/$(INSTALL)/g' + +pushd cmsfs-%{cmsfsver} +# cmdfs: fix encoding +iconv -f ISO8859-1 -t UTF-8 -o README.new README +touch -r README README.new +mv README.new README +# prepare docs +mv README README.cmsfs +mv CREDITS CREDITS.cmsfs +popd + + +%build +make \ + CFLAGS="%{build_cflags}" CXXFLAGS="%{build_cflags}" LDFLAGS="%{build_ldflags}" \ + BINDIR=/usr/sbin \ + DISTRELEASE=%{release} \ + V=1 + +pushd cmsfs-%{cmsfsver} +./configure +make CC="gcc %{build_cflags} -fno-strict-aliasing %{build_ldflags}" +popd + +pushd src_vipa-%{vipaver} +make CC_FLAGS="%{build_cflags} -fPIC" LD_FLAGS="%{build_ldflags} -shared" LIBDIR=%{_libdir} +popd + + +%install +make install \ + HAVE_DRACUT=1 \ + DESTDIR=$RPM_BUILD_ROOT \ + BINDIR=/usr/sbin \ + SYSTEMDSYSTEMUNITDIR=%{_unitdir} \ + DISTRELEASE=%{release} \ + V=1 + +mkdir -p $RPM_BUILD_ROOT{/boot,%{_udevrulesdir},%{_sysconfdir}/{profile.d,sysconfig},%{_prefix}/lib/modules-load.d} +install -p -m 644 zipl/boot/tape0.bin $RPM_BUILD_ROOT/boot/tape0 +install -p -m 755 %{SOURCE5} $RPM_BUILD_ROOT%{_sbindir} +install -p -m 755 %{SOURCE13} $RPM_BUILD_ROOT%{_sbindir} +install -p -m 755 %{SOURCE21} $RPM_BUILD_ROOT%{_sbindir} +install -p -m 644 %{SOURCE7} $RPM_BUILD_ROOT%{_udevrulesdir}/56-zfcp.rules +install -p -m 644 %{SOURCE12} $RPM_BUILD_ROOT%{_udevrulesdir}/56-dasd.rules + +touch $RPM_BUILD_ROOT%{_sysconfdir}/{zfcp.conf,dasd.conf} + +# upstream udev rules +install -Dp -m 644 etc/udev/rules.d/*.rules $RPM_BUILD_ROOT%{_udevrulesdir} + +# upstream modules config +install -Dp -m 644 etc/modules-load.d/*.conf $RPM_BUILD_ROOT%{_prefix}/lib/modules-load.d + +# Install kernel-install scripts +install -d -m 0755 %{buildroot}%{_prefix}/lib/kernel/install.d/ +install -D -m 0755 -t %{buildroot}%{_prefix}/lib/kernel/install.d/ %{SOURCE22} +install -D -m 0755 -t %{buildroot}%{_prefix}/lib/kernel/install.d/ zfcpdump/10-zfcpdump.install +install -D -m 0755 -t %{buildroot}%{_prefix}/lib/kernel/install.d/ %{SOURCE23} +install -D -m 0755 -t %{buildroot}%{_prefix}/lib/kernel/install.d/ %{SOURCE24} +install -D -m 0755 -t %{buildroot}%{_prefix}/lib/kernel/install.d/ %{SOURCE25} +install -d -m 0755 %{buildroot}%{_sysconfdir}/kernel/install.d/ +install -m 0644 /dev/null %{buildroot}%{_sysconfdir}/kernel/install.d/20-grubby.install + +# cmsfs tools must be available in /sbin +for f in cat lst vol cp ck; do + install -p -m 755 cmsfs-%{cmsfsver}/cmsfs${f} $RPM_BUILD_ROOT%{_sbindir} + install -p -m 644 cmsfs-%{cmsfsver}/cmsfs${f}.8 $RPM_BUILD_ROOT%{_mandir}/man8 +done + +# src_vipa +pushd src_vipa-%{vipaver} +make install LIBDIR=%{_libdir} SBINDIR=%{_bindir} INSTROOT=$RPM_BUILD_ROOT LDCONFIG=/bin/true +popd + +# install usefull headers for devel subpackage +mkdir -p $RPM_BUILD_ROOT%{_includedir}/%{name} +install -p -m 644 include/lib/vtoc.h $RPM_BUILD_ROOT%{_includedir}/%{name} + +# device_cio_free +install -p -m 755 %{SOURCE14} $RPM_BUILD_ROOT%{_sbindir} +pushd $RPM_BUILD_ROOT%{_sbindir} +for lnk in dasd zfcp znet; do + ln -sf device_cio_free ${lnk}_cio_free +done +popd +install -p -m 644 %{SOURCE15} $RPM_BUILD_ROOT%{_unitdir} + +# ccw +install -p -m 755 %{SOURCE16} $RPM_BUILD_ROOT/usr/lib/udev/ccw_init +install -p -m 644 %{SOURCE17} $RPM_BUILD_ROOT%{_udevrulesdir}/81-ccw.rules + +# zipl.conf to be ghosted +touch $RPM_BUILD_ROOT%{_sysconfdir}/zipl.conf + + +%files +%doc README.md + +# +# ************************* s390-tools base package ************************* +# +%package base +# src_vipa is CPL +License: MIT and CPL +Summary: S390 base tools +Group: System Environment/Base +Requires: gawk sed coreutils +Requires: sysfsutils +Requires: sg3_utils +Requires: ethtool +Requires: network-scripts +%{?systemd_requires} +BuildRequires: perl-generators +BuildRequires: ncurses-devel +BuildRequires: libpfm-devel +BuildRequires: glibc-static +BuildRequires: cryptsetup-devel >= 2.0.3 +BuildRequires: json-c-devel + + +%description base +s390 base tools. This collection provides the following utilities: + * dasdfmt: + Low-level format ECKD DASDs with the classical linux disk layout or the + new z/OS compatible disk layout. + + * fdasd: + Create or modify partitions on ECKD DASDs formatted with the z/OS + compatible disk layout. + + * dasdview: + Display DASD and VTOC information or dump the contents of a DASD to the + console. + + * dasdinfo: + Display unique DASD ID, either UID or volser. + + * udev rules: + - 59-dasd.rules: rules for unique DASD device nodes created in /dev/disk/. + + * zipl: + Make DASDs or tapes bootable for system IPL or system dump. + + * zgetdump: + Retrieve system dumps from either tapes or DASDs. + + * qetharp: + Read and flush the ARP cache on OSA Express network cards. + + * tape390_display: + Display information on the message display facility of a zSeries tape + device. + + * tape390_crypt: + Control and query crypto settings for 3592 zSeries tape devices. + + * qethconf: + bash shell script simplifying the usage of qeth IPA (IP address + takeover), VIPA (Virtual IP address) and Proxy ARP. + + * dbginfo.sh: + Shell script collecting useful information about the current system for + debugging purposes. + + * zfcpdump: + Dump tool to create system dumps on fibre channel attached SCSI disks. + It is installed using the zipl command. + + * zfcpdump_v2: + Version 2 of the zfcpdump tool. Now based on the upstream 2.6.26 Linux + kernel. + + * ip_watcher: + Provides HiperSockets Network Concentrator functionality. + It looks for addresses in the HiperSockets and sets them as Proxy ARP + on the OSA cards. It also adds routing entries for all IP addresses + configured on active HiperSockets devices. + Use start_hsnc.sh to start HiperSockets Network Concentrator. + + * tunedasd: + Adjust tunable parameters on DASD devices. + + * vmconvert: + Convert system dumps created by the z/VM VMDUMP command into dumps with + LKCD format. These LKCD dumps can then be analyzed with the dump analysis + tool lcrash. + + * vmcp: + Allows Linux users to send commands to the z/VM control program (CP). + The normal usage is to invoke vmcp with the command you want to + execute. The response of z/VM is written to the standard output. + + * vmur: + Allows to work with z/VM spool file queues (reader, punch, printer). + + * zfcpdbf: + Display debug data of zfcp. zfcp provides traces via the s390 debug + feature. Those traces are filtered with the zfcpdbf script, i.e. merge + several traces, make it more readable etc. + + * scsi_logging_level: + Create, get or set the logging level for the SCSI logging facility. + + * zconf: + Set of scripts to configure and list status information of Linux for + zSeries IO devices. + - chccwdev: Modify generic attributes of channel attached devices. + - lscss: List channel subsystem devices. + - lsdasd: List channel attached direct access storage devices (DASD). + - lsqeth: List all qeth-based network devices with their corresponding + settings. + - lstape: List tape devices, both channel and FCP attached. + - lszfcp: Shows information contained in sysfs about zfcp adapters, + ports and units that are online. + - lschp: List information about available channel-paths. + - chchp: Modify channel-path state. + - lsluns: List available SCSI LUNs depending on adapter or port. + - lszcrypt: Show Information about zcrypt devices and configuration. + - chzcrypt: Modify zcrypt configuration. + - znetconf: List and configure network devices for System z network + adapters. + - cio_ignore: Query and modify the contents of the CIO device driver + blacklist. + + * dumpconf: + Allows to configure the dump device used for system dump in case a kernel + panic occurs. This tool can also be used as an init script for etc/init.d. + Prerequisite for dumpconf is a Linux kernel with the "dump on panic" + feature. + + * ipl_tools: + Tools set to configure and list reipl and shutdown actions. + - lsreipl: List information of reipl device. + - chreipl: Change reipl device settings. + - lsshut: List actions which will be done in case of halt, poff, reboot + or panic. + - chshut: Change actions which should be done in case of halt, poff, + reboot or panic. + + * cpi: + Allows to set the system and sysplex names from the Linux guest to + the HMC/SE using the Control Program Identification feature. + +For more information refer to the following publications: + * "Device Drivers, Features, and Commands" chapter "Useful Linux commands" + * "Using the dump tools" + +%pre base +# check for zkeyadm group and create it +getent group zkeyadm > /dev/null || groupadd -r zkeyadm + +%post base +%systemd_post cpi.service +%if 0 +# enable in F-31 +%systemd_post device_cio_free.service +%else +# explicit enable for upgrade patch from s390utils-base < 2.6.0-4 +systemctl --no-reload preset device_cio_free.service >/dev/null 2>&1 || : +%endif +%systemd_post dumpconf.service + +%preun base +%systemd_preun cpi.service +%systemd_preun device_cio_free.service +%systemd_preun dumpconf.service + +%postun base +%systemd_postun_with_restart cpi.service +%systemd_postun_with_restart dumpconf.service + +%files base +%doc README.md zdev/src/*.txt +%doc LICENSE +%{_sbindir}/chccwdev +%{_sbindir}/chchp +%{_sbindir}/chcpumf +%{_sbindir}/chreipl +%{_sbindir}/chshut +%{_sbindir}/chzcrypt +%{_sbindir}/chzdev +%{_sbindir}/cio_ignore +%{_sbindir}/dasdfmt +%{_sbindir}/dasdinfo +%{_sbindir}/dasdstat +%{_sbindir}/dasdview +%{_sbindir}/dbginfo.sh +%{_sbindir}/fdasd +%{_sbindir}/hyptop +%{_sbindir}/ip_watcher.pl +%{_sbindir}/lschp +%{_sbindir}/lscss +%{_sbindir}/lsdasd +%{_sbindir}/lsqeth +%{_sbindir}/lsluns +%{_sbindir}/lsreipl +%{_sbindir}/lsscm +%{_sbindir}/lsshut +%{_sbindir}/lstape +%{_sbindir}/lszcrypt +%{_sbindir}/lszdev +%{_sbindir}/lszfcp +%{_sbindir}/qetharp +%{_sbindir}/qethconf +%{_sbindir}/qethqoat +%{_sbindir}/scsi_logging_level +%{_sbindir}/start_hsnc.sh +%{_sbindir}/tape390_crypt +%{_sbindir}/tape390_display +%{_sbindir}/ttyrun +%{_sbindir}/tunedasd +%{_sbindir}/vmcp +%{_sbindir}/vmur +%{_sbindir}/xcec-bridge +%{_sbindir}/zcryptctl +%{_sbindir}/zcryptstats +%{_sbindir}/zfcpdbf +%{_sbindir}/zgetdump +%{_sbindir}/zipl +%{_sbindir}/zipl-switch-to-blscfg +%{_sbindir}/znetconf +%{_sbindir}/zpcictl +%{_bindir}/lscpumf +%{_bindir}/dump2tar +%{_bindir}/vmconvert +%{_bindir}/zkey +%{_bindir}/zkey-cryptsetup +%{_unitdir}/cpi.service +%{_unitdir}/dumpconf.service +%ghost %config(noreplace) %{_sysconfdir}/zipl.conf +%config(noreplace) %{_sysconfdir}/sysconfig/cpi +%config(noreplace) %{_sysconfdir}/sysconfig/dumpconf +/lib/s390-tools/ +/usr/lib/dracut/modules.d/95zdev/ +%{_mandir}/man1/dbginfo.sh.1* +%{_mandir}/man1/dump2tar.1* +%{_mandir}/man1/lscpumf.1* +%{_mandir}/man1/vmconvert.1* +%{_mandir}/man1/zfcpdbf.1* +%{_mandir}/man1/zipl-switch-to-blscfg.1* +%{_mandir}/man1/zkey.1* +%{_mandir}/man1/zkey-cryptsetup.1* +%{_mandir}/man4/prandom.4* +%{_mandir}/man5/zipl.conf.5* +%{_mandir}/man8/chccwdev.8* +%{_mandir}/man8/chchp.8* +%{_mandir}/man8/chcpumf.8* +%{_mandir}/man8/chreipl.8* +%{_mandir}/man8/chshut.8* +%{_mandir}/man8/chzcrypt.8* +%{_mandir}/man8/chzdev.8* +%{_mandir}/man8/cio_ignore.8* +%{_mandir}/man8/dasdfmt.8* +%{_mandir}/man8/dasdinfo.8* +%{_mandir}/man8/dasdstat.8* +%{_mandir}/man8/dasdview.8* +%{_mandir}/man8/dumpconf.8* +%{_mandir}/man8/fdasd.8* +%{_mandir}/man8/hyptop.8* +%{_mandir}/man8/lschp.8* +%{_mandir}/man8/lscss.8* +%{_mandir}/man8/lsdasd.8* +%{_mandir}/man8/lsluns.8* +%{_mandir}/man8/lsqeth.8* +%{_mandir}/man8/lsreipl.8* +%{_mandir}/man8/lsscm.8* +%{_mandir}/man8/lsshut.8* +%{_mandir}/man8/lstape.8* +%{_mandir}/man8/lszcrypt.8* +%{_mandir}/man8/lszdev.8* +%{_mandir}/man8/lszfcp.8* +%{_mandir}/man8/qetharp.8* +%{_mandir}/man8/qethconf.8* +%{_mandir}/man8/qethqoat.8* +%{_mandir}/man8/tape390_crypt.8* +%{_mandir}/man8/tape390_display.8* +%{_mandir}/man8/ttyrun.8* +%{_mandir}/man8/tunedasd.8* +%{_mandir}/man8/vmcp.8* +%{_mandir}/man8/vmur.8* +%{_mandir}/man8/zcryptctl.8* +%{_mandir}/man8/zcryptstats.8* +%{_mandir}/man8/zgetdump.8* +%{_mandir}/man8/zipl.8* +%{_mandir}/man8/znetconf.8* +%{_mandir}/man8/zpcictl.8* +%dir %{_datadir}/s390-tools/ +%{_datadir}/s390-tools/cpumf/ +%{_datadir}/s390-tools/netboot/ +%dir %attr(0770,root,zkeyadm) %{_sysconfdir}/zkey +%dir %attr(0770,root,zkeyadm) %{_sysconfdir}/zkey/repository + +# Additional Redhat specific stuff +/boot/tape0 +%ghost %config(noreplace) %{_sysconfdir}/dasd.conf +%ghost %config(noreplace) %{_sysconfdir}/zfcp.conf +%{_sbindir}/dasdconf.sh +%{_sbindir}/zfcpconf.sh +%{_sbindir}/dasd_cio_free +%{_sbindir}/device_cio_free +%{_sbindir}/zfcp_cio_free +%{_sbindir}/znet_cio_free +%{_sbindir}/normalize_dasd_arg +%{_unitdir}/device_cio_free.service +/usr/lib/udev/ccw_init +%{_udevrulesdir}/40-z90crypt.rules +%{_udevrulesdir}/56-zfcp.rules +%{_udevrulesdir}/56-dasd.rules +%{_udevrulesdir}/59-dasd.rules +%{_udevrulesdir}/60-readahead.rules +%{_udevrulesdir}/81-ccw.rules +%{_udevrulesdir}/90-cpi.rules +%{_sysconfdir}/kernel/install.d/20-grubby.install +%{_prefix}/lib/kernel/install.d/00-zipl-prepare.install +%{_prefix}/lib/kernel/install.d/10-zfcpdump.install +%{_prefix}/lib/kernel/install.d/20-zipl-kernel.install +%{_prefix}/lib/kernel/install.d/52-zipl-rescue.install +%{_prefix}/lib/kernel/install.d/91-zipl.install +%{_prefix}/lib/modules-load.d/s390-pkey.conf + +# src_vipa +%{_bindir}/src_vipa.sh +%{_libdir}/src_vipa.so +%{_mandir}/man8/src_vipa.8* + +# +# *********************** s390-tools osasnmpd package *********************** +# +%package osasnmpd +Summary: SNMP sub-agent for OSA-Express cards +Group: System Environment/Daemons +Requires: net-snmp +Requires: psmisc +BuildRequires: net-snmp-devel + +%description osasnmpd +UCD-SNMP/NET-SNMP sub-agent implementing MIBs provided by OSA-Express +features Fast Ethernet, Gigabit Ethernet, High Speed Token Ring and +ATM Ethernet LAN Emulation in QDIO mode. + +%files osasnmpd +%{_sbindir}/osasnmpd +%{_udevrulesdir}/57-osasnmpd.rules +%{_mandir}/man8/osasnmpd.8* + +# +# *********************** s390-tools mon_statd package ********************** +# +%package mon_statd +Summary: Monitoring daemons for Linux in z/VM +Group: System Environment/Daemons +Requires: coreutils +%{?systemd_requires} + +%description mon_statd +Monitoring daemons for Linux in z/VM: + + - mon_fsstatd: Daemon that writes file system utilization data to the + z/VM monitor stream. + + - mon_procd: Daemon that writes process information data to the z/VM + monitor stream. + +%post mon_statd +%systemd_post mon_fsstatd.service +%systemd_post mon_procd.service + +%preun mon_statd +%systemd_preun mon_fsstatd.service +%systemd_preun mon_procd.service + +%postun mon_statd +%systemd_postun_with_restart mon_fsstatd.service +%systemd_postun_with_restart mon_procd.service + +%files mon_statd +%{_sbindir}/mon_fsstatd +%{_sbindir}/mon_procd +%config(noreplace) %{_sysconfdir}/sysconfig/mon_fsstatd +%config(noreplace) %{_sysconfdir}/sysconfig/mon_procd +%{_unitdir}/mon_fsstatd.service +%{_unitdir}/mon_procd.service +%{_mandir}/man8/mon_fsstatd.8* +%{_mandir}/man8/mon_procd.8* + +# +# *********************** s390-tools cpuplugd package *********************** +# +%package cpuplugd +Summary: Daemon that manages CPU and memory resources +Group: System Environment/Daemons +%{?systemd_requires} +BuildRequires: systemd + +%description cpuplugd +Daemon that manages CPU and memory resources based on a set of rules. +Depending on the workload CPUs can be enabled or disabled. The amount of +memory can be increased or decreased exploiting the CMM1 feature. + +%post cpuplugd +%systemd_post cpuplugd.service + +%preun cpuplugd +%systemd_preun cpuplugd.service + +%postun cpuplugd +%systemd_postun_with_restart cpuplugd.service + +%files cpuplugd +%config(noreplace) %{_sysconfdir}/cpuplugd.conf +%{_sbindir}/cpuplugd +%{_mandir}/man5/cpuplugd.conf.5* +%{_mandir}/man8/cpuplugd.8* +%{_unitdir}/cpuplugd.service + +# +# *********************** s390-tools ziomon package ************************* +# +%package ziomon +Summary: S390 ziomon tools +Group: Applications/System +Requires: blktrace +Requires: coreutils +Requires: device-mapper-multipath +Requires: gawk +Requires: grep +Requires: lsscsi +Requires: procps-ng +Requires: rsync +Requires: sed +Requires: tar +Requires: util-linux + +%description ziomon +Tool set to collect data for zfcp performance analysis and report. + +%files ziomon +%{_sbindir}/ziomon +%{_sbindir}/ziomon_fcpconf +%{_sbindir}/ziomon_mgr +%{_sbindir}/ziomon_util +%{_sbindir}/ziomon_zfcpdd +%{_sbindir}/ziorep_config +%{_sbindir}/ziorep_traffic +%{_sbindir}/ziorep_utilization +%{_mandir}/man8/ziomon.8* +%{_mandir}/man8/ziomon_fcpconf.8* +%{_mandir}/man8/ziomon_mgr.8* +%{_mandir}/man8/ziomon_util.8* +%{_mandir}/man8/ziomon_zfcpdd.8* +%{_mandir}/man8/ziorep_config.8* +%{_mandir}/man8/ziorep_traffic.8* +%{_mandir}/man8/ziorep_utilization.8* + +# +# *********************** s390-tools iucvterm package ************************* +# +%package iucvterm +Summary: z/VM IUCV terminal applications +Group: Applications/System +Requires(pre): shadow-utils +Requires(post): grep +Requires(postun): grep +BuildRequires: gettext +BuildRequires: systemd + +%description iucvterm +A set of applications to provide terminal access via the z/VM Inter-User +Communication Vehicle (IUCV). The terminal access does not require an +active TCP/IP connection between two Linux guest operating systems. + +- iucvconn: Application to establish a terminal connection via z/VM IUCV. +- iucvtty: Application to provide terminal access via z/VM IUCV. +- ts-shell: Terminal server shell to authorize and control IUCV terminal + connections for individual Linux users. + +%pre iucvterm +# check for ts-shell group and create it +getent group ts-shell > /dev/null || groupadd -r ts-shell + +%post iucvterm +# /etc/shells is provided by "setup" +grep -q '^/usr/bin/ts-shell$' /etc/shells \ + || echo "/usr/bin/ts-shell" >> /etc/shells + +%postun iucvterm +if [ $1 = 0 ] +then + # remove ts-shell from /etc/shells on uninstall + grep -v '^/usr/bin/ts-shell$' /etc/shells > /etc/shells.ts-new + mv /etc/shells.ts-new /etc/shells + chmod 0644 /etc/shells +fi + +%files iucvterm +%dir %{_sysconfdir}/iucvterm +%config(noreplace) %attr(0640,root,ts-shell) %{_sysconfdir}/iucvterm/ts-audit-systems.conf +%config(noreplace) %attr(0640,root,ts-shell) %{_sysconfdir}/iucvterm/ts-authorization.conf +%config(noreplace) %attr(0640,root,ts-shell) %{_sysconfdir}/iucvterm/ts-shell.conf +%config(noreplace) %attr(0640,root,ts-shell) %{_sysconfdir}/iucvterm/unrestricted.conf +%{_bindir}/iucvconn +%{_bindir}/iucvtty +%{_bindir}/ts-shell +%{_sbindir}/chiucvallow +%{_sbindir}/lsiucvallow +%dir %attr(2770,root,ts-shell) /var/log/ts-shell +%doc iucvterm/doc/ts-shell +%{_mandir}/man1/iucvconn.1* +%{_mandir}/man1/iucvtty.1* +%{_mandir}/man1/ts-shell.1* +%{_mandir}/man7/af_iucv.7* +%{_mandir}/man8/chiucvallow.8* +%{_mandir}/man9/hvc_iucv.9* +%{_unitdir}/iucvtty-login@.service +%{_unitdir}/ttyrun-getty@.service + +# +# *********************** cmsfs package *********************** +# +%package cmsfs +License: GPLv2 +Summary: CMS file system tools +Group: System Environment/Base +URL: http://www.casita.net/pub/cmsfs/cmsfs.html +# Requires: + +%description cmsfs +This package contains the CMS file system tools. + +%files cmsfs +%{_sbindir}/cmsfscat +%{_sbindir}/cmsfsck +%{_sbindir}/cmsfscp +%{_sbindir}/cmsfslst +%{_sbindir}/cmsfsvol +%{_mandir}/man8/cmsfscat.8* +%{_mandir}/man8/cmsfsck.8* +%{_mandir}/man8/cmsfscp.8* +%{_mandir}/man8/cmsfslst.8* +%{_mandir}/man8/cmsfsvol.8* + +# +# *********************** cmsfs-fuse package *********************** +# +%package cmsfs-fuse +Summary: CMS file system based on FUSE +Group: System Environment/Base +BuildRequires: fuse-devel +Requires: fuse + +%description cmsfs-fuse +This package contains the CMS file system based on FUSE. + +%files cmsfs-fuse +%dir %{_sysconfdir}/cmsfs-fuse +%config(noreplace) %{_sysconfdir}/cmsfs-fuse/filetypes.conf +%{_bindir}/cmsfs-fuse +%{_mandir}/man1/cmsfs-fuse.1* + +# +# *********************** zdsfs package *********************** +# +%package zdsfs +Summary: z/OS data set access based on FUSE +Group: System Environment/Base +BuildRequires: fuse-devel +Requires: fuse + +%description zdsfs +This package contains the z/OS data set access based on FUSE. + +%files zdsfs +%{_bindir}/zdsfs +%{_mandir}/man1/zdsfs.1* + +# +# *********************** hmcdrvfs package *********************** +# +%package hmcdrvfs +Summary: HMC drive file system based on FUSE +Group: System Environment/Base +BuildRequires: fuse-devel +Requires: fuse + +%description hmcdrvfs +This package contains a HMC drive file system based on FUSE and a tool +to list files and directories. + +%files hmcdrvfs +%{_bindir}/hmcdrvfs +%{_sbindir}/lshmc +%{_mandir}/man1/hmcdrvfs.1* +%{_mandir}/man8/lshmc.8* + +# +# *********************** cpacfstatsd package *********************** +# +%package cpacfstatsd +Summary: Monitor and maintain CPACF activity counters +Group: System Environment/Base +Requires(post): systemd +Requires(preun): systemd +Requires(postun): systemd +Requires(pre): shadow-utils +BuildRequires: systemd + +%description cpacfstatsd +The cpacfstats tools provide a client/server application set to monitor +and maintain CPACF activity counters. + +%post cpacfstatsd +%systemd_post cpacfstatsd.service + +%preun cpacfstatsd +%systemd_preun cpacfstatsd.service + +%postun cpacfstatsd +%systemd_postun_with_restart cpacfstatsd.service + +%pre cpacfstatsd +getent group cpacfstats >/dev/null || groupadd -r cpacfstats + +%files cpacfstatsd +%{_bindir}/cpacfstats +%{_sbindir}/cpacfstatsd +%{_mandir}/man1/cpacfstats.1* +%{_mandir}/man8/cpacfstatsd.8* +%{_unitdir}/cpacfstatsd.service + +# +# *********************** devel package *********************** +# +%package devel +Summary: Development files +Group: Development/Libraries + +%description devel +User-space development files for the s390/s390x architecture. + +%files devel +%{_includedir}/%{name} + + +%changelog +* Wed Feb 27 2019 Dan Horák - 2:2.6.0-15 +- zpcictl: Check for regular directory (#1695001) +- s390-tools: Add zcryptstats tool (#1658756) +- zipl: Secure Boot support for SCSI IPL (#1659401) +- Resolves: #1659401 #1658756 #1695001 + +* Wed Feb 27 2019 Dan Horák - 2:2.6.0-14 +- pkey: Support autoloading kernel pkey module (#1664632) +- Related: #1664632 + +* Fri Feb 01 2019 Dan Horák - 2:2.6.0-13 +- create cpacfstats group needed by cpacfstatsd (#1670076) +- Resolves: #1670076 + +* Tue Jan 29 2019 Dan Horák - 2:2.6.0-12 +- zfcpdump: add install script for zfcpdump kernel (#1600480) +- pkey: Support autoloading kernel pkey module (#1664632) +- Make kernel-install to update default if present in zipl.conf (#1665060) +- Resolves: #1600480 #1664632 #1665060 + +* Tue Dec 11 2018 Dan Horák - 2:2.6.0-11 +- zkey: Fails to run commands generated by 'zkey cryptsetup' (#1650628) +- zkey: Enhance error message about missing CCA library (#1655134) +- Resolves: #1650628 #1655134 + +* Mon Nov 19 2018 Dan Horák - 2:2.6.0-10 +- lszcrypt: support for alternate zcrypt device drivers (#1646355) +- zcryptctl: add zcryptctl to manage multiple zcrypt nodes (#1646354) +- qethqoat: add OSA-Express7S support (#1644384) +- zdev: qeth BridgePort and VNICC attribute conflict (#1643452) +- zpcictl: Change wording of man-page and help output (#1643451) +- zpcictl: Read device link to obtain device address (#1639220) +- zpcictl: Add tool to manage PCI devices (#1525409) +- Resolves: #1525409 #1639220 #1643451 #1643452 #1644384 #1646354 #1646355 + +* Tue Nov 06 2018 Javier Martinez Canillas - 2.6.0-9 +- Make zipl to use the BLS title field as the IPL section name +- Resolves: #1645200 + +* Mon Oct 22 2018 Dan Horák - 2:2.6.0-8 +- don't relink the zkey tools +- Resolves: #1624169 + +* Mon Oct 15 2018 Peter Jones - 2.6.0-7 +- Make the blscfg sort order match what grub2 and grubby do. (pjones) +- Add a ~debug suffix instead of -debug to sort it correctly. (javierm) +- Resolves: #1640968 + +* Mon Oct 01 2018 Dan Horák - 2:2.6.0-6 +- Fix kernel-install scripts issues (#1634803) +- Resolves: #1634803 + +* Fri Sep 21 2018 Dan Horák - 2:2.6.0-5 +- Makefile cleanups (#1624169) +- Resolves: #1624169 + +* Mon Sep 17 2018 Dan Horák - 2:2.6.0-4 +- drop redundant systemd services installation (#1631682) +- Resolves #1631682 + +* Fri Sep 14 2018 Dan Horák - 2:2.6.0-3 +- add FIEMAP support into zipl (#1623163) +- Resolves: #1623163 + +* Tue Aug 14 2018 Dan Horák - 2:2.6.0-2 +- fix R:/BR: perl + +* Fri Aug 10 2018 Dan Horák - 2:2.6.0-1 +- rebased to 2.6.0 (#1584283) +- include zdev dracut module +- Resolves: #1584283 + +* Fri Aug 10 2018 Josh Boyer - 2:2.5.0-6 +- Rebuild against net-snmp 5.8 +- Resolves: #1584510 + +* Tue Jul 31 2018 Dan Horák - 2:2.5.0-5 +- add missing zkey infrastructure (#1610242) + +* Fri Jul 27 2018 Dan Horák - 2:2.5.0-4 +- don't override TERM for console + +* Thu Jul 26 2018 Dan Horák - 2:2.5.0-3 +- network-scripts are required for network device initialization + +* Sat Jul 14 2018 Fedora Release Engineering - 2:2.5.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild + +* Mon Jun 11 2018 Dan Horák - 2:2.5.0-1 +- rebased to 2.5.0 + +* Thu May 24 2018 Javier Martinez Canillas - 2:2.4.0-2 +- zipl: Add BootLoaderSpec support +- Add kernel-install scripts to create BLS fragment files + +* Wed May 09 2018 Dan Horák - 2:2.4.0-1 +- rebased to 2.4.0 + +* Fri Apr 13 2018 Dan Horák - 2:2.3.0-3 +- fix building zipl with PIE (#1566140) + +* Mon Mar 12 2018 Dan Horák - 2:2.3.0-2 +- fix LDFLAGS injection (#1552661) + +* Wed Feb 21 2018 Rafael Santos - 2:2.3.0-1 +- rebased to 2.3.0 + +* Fri Feb 09 2018 Fedora Release Engineering - 2:2.2.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Mon Jan 22 2018 Dan Horák - 2:2.2.0-2 +- fix build with non-standard %%dist + +* Thu Dec 07 2017 Dan Horák - 2:2.2.0-1 +- rebased to 2.2.0 + +* Mon Sep 25 2017 Dan Horák - 2:2.1.0-1 +- rebased to 2.1.0 + +* Wed Aug 23 2017 Dan Horák - 2:2.0.0-1 +- rebased to first public release on github, functionally same as 1.39.0 +- relicensed to MIT + +* Wed Aug 23 2017 Dan Horák - 2:1.39.0-1 +- rebased to 1.39.0 +- completed switch to systemd +- further cleanups and consolidation + +* Wed Aug 16 2017 Dan Horák - 2:1.37.1-4 +- rebuild for librpm soname bump in rpm 4.13.90 + +* Thu Aug 03 2017 Fedora Release Engineering - 2:1.37.1-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Thu Jul 27 2017 Fedora Release Engineering - 2:1.37.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Fri May 19 2017 Dan Horák - 2:1.37.1-1 +- rebased to 1.37.1 +- removed chmem/lsmem as they are now provided by util-linux >= 2.30 (#1452792) + +* Sat Feb 11 2017 Fedora Release Engineering - 2:1.36.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Thu Dec 01 2016 Dan Horák - 2:1.36.1-1 +- rebased to 1.36.1 + +* Wed Sep 07 2016 Dan Horák - 2:1.36.0-1 +- rebased to 1.36.0 +- switch cpuplugd to systemd service + +* Fri Apr 22 2016 Dan Horák - 2:1.34.0-1 +- rebased to 1.34.0 + +* Thu Feb 04 2016 Fedora Release Engineering - 2:1.30.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild + +* Thu Oct 01 2015 Dan Horák - 2:1.30.0-2 +- rebuild for librpm soname bump + +* Fri Jul 17 2015 Dan Horák - 2:1.30.0-1 +- rebased to 1.30.0 + +* Tue Jun 23 2015 Dan Horák - 2:1.29.0-1 +- rebased to 1.29.0 +- dropped daemon hardening patch as hardening is enabled globally +- added hmcdrvfs and cpacfstatsd subpackages +- install systemd units where available + +* Fri Jun 19 2015 Fedora Release Engineering - 2:1.23.0-16 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Tue Apr 07 2015 Dan Horák - 2:1.23.0-15 +- remove bashism from zfcpconf.sh + +* Wed Jan 28 2015 Dan Horák - 2:1.23.0-14 +- refresh from RHEL-7 + - update patches + - add zdsfs subpackage + - rebase src_vipa to 2.1.0 + +* Thu Oct 09 2014 Dan Horák - 2:1.23.0-13 +- update device_cio_free script +- udpate Requires for ziomon subpackage + +* Wed Jun 11 2014 Dan Horák - 2:1.23.0-12 +- update for -Werror=format-security + +* Sun Jun 08 2014 Fedora Release Engineering - 2:1.23.0-11 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Tue Mar 04 2014 Dan Horák - 2:1.23.0-10 +- fix zFCP device discovery in anaconda GUI (#1054691) + +* Mon Feb 10 2014 Dan Horák - 2:1.23.0-9 +- znetconf: Allow for 16-char network interface names (#1062285) +- qetharp: Allow for 16-char network interface names (#1062250) + +* Mon Feb 03 2014 Dan Horák - 2:1.23.0-8 +- znetconf,lsqeth: Allow for 16-char network interface name (#1060303) + +* Wed Jan 29 2014 Dan Horák - 2:1.23.0-7 +- zipl: Fix zfcpdump "struct job_ipl_data" initialization (#1058856) + +* Wed Jan 15 2014 Dan Horák - 2:1.23.0-6 +- zipl: fix segmentation fault in automenu array (#1017541) +- zfcpconf.sh: check current online state before setting zfcp device online (#1042496) + +* Tue Nov 19 2013 Dan Horák - 2:1.23.0-5 +- dbginfo.sh: enhancements for script execution and man page (#1031144) +- dbginfo.sh: avoid double data collection (#1032068) + +* Wed Nov 06 2013 Dan Horák - 2:1.23.0-4 +- build daemons hardened (#881250) +- zipl: Use "possible_cpus" kernel parameter (#1016180) + +* Wed Aug 21 2013 Dan Horák - 2:1.23.0-3 +- dbginfo.sh: Avoiding exclusion list for pipes in sysfs (#996732) +- zipl: Fix zipl "--force" option for DASD multi-volume dump (#997361) + +* Sun Aug 04 2013 Fedora Release Engineering - 2:1.23.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild + +* Wed Jul 24 2013 Dan Horák - 2:1.23.0-1 +- rebased to 1.23 (#804774) + +* Wed Jun 05 2013 Dan Horák - 2:1.20.0-5 +- update with patches from RHEL-6 +- rebase zIPL to 1.21 to fix booting from FBA DASD (#970859) + +* Tue May 21 2013 Dan Horák - 2:1.20.0-4 +- drop the libzfcphbaapi subpackage as it is moved to its own package (#963670) +- update the zfcp udev rules (#958197) +- fix runtime dependencies for osasnmpd (#965413) + +* Wed Mar 27 2013 Dan Horák - 2:1.20.0-3 +- disable libzfcphbaapi subpackage, fails to build with recent kernels + +* Thu Feb 14 2013 Fedora Release Engineering - 2:1.20.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + +* Wed Dec 19 2012 Dan Horák - 2:1.20.0-1 +- updated to 1.20.0 (#804774) + +* Thu Nov 22 2012 Dan Horák - 2:1.19.0-4 +- clean BuildRequires a bit + +* Mon Sep 17 2012 Dan Horák - 2:1.19.0-3 +- zipl: Flush disk buffers before installing IPL record (#857814) + +* Mon Aug 27 2012 Dan Horák 2:1.19.0-2 +- add support for CEX4 devices to chzcrypt/lszcrypt (#847092) + +* Mon Aug 27 2012 Dan Horák 2:1.19.0-1 +- updated to 1.19.0 (#804774) +- fixed syntax in s390.sh script (#851096) +- spec cleanup + +* Tue Aug 21 2012 Dan Horák 2:1.17.0-1 +- updated to 1.17.0 +- add support for new storage device on System z (#847086) + +* Thu Aug 16 2012 Dan Horák 2:1.16.0-11 +- fix libzfcphbaapi for recent kernels + +* Sat Jul 21 2012 Fedora Release Engineering - 2:1.16.0-10 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Fri May 25 2012 Dan Horák 2:1.16.0-9 +- improve DASD parameters handling in normalize_dasd_arg (#824807) + +* Wed May 23 2012 Dan Horák 2:1.16.0-8 +- add normalize_dasd_arg script (#823078) + +* Mon May 14 2012 Dan Horák 2:1.16.0-7 +- ethtool is required by lsqeth (#821421) + +* Fri May 11 2012 Dan Horák 2:1.16.0-6 +- updated the Fedora patch set - no vol_id tool in udev (#819530) + +* Fri May 4 2012 Dan Horák 2:1.16.0-5 +- zipl.conf must be owned by s390utils-base (#818877) + +* Tue Apr 17 2012 Dan Horák 2:1.16.0-4 +- install the z90crypt udev rule (moved here from the udev package) + +* Tue Apr 10 2012 Dan Horák 2:1.16.0-3 +- include fixed ccw_init and updated device_cio_free + +* Sat Jan 14 2012 Fedora Release Engineering - 2:1.16.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Thu Dec 15 2011 Dan Horák 2:1.16.0-1 +- rebased to 1.16.0 + +* Tue Aug 16 2011 Dan Horák 2:1.14.0-1 +- rebased to 1.14.0 + +* Wed Apr 27 2011 Dan Horák 2:1.8.2-32 +- updated ccw udev rules +- converted cio_free_device from an upstart job to systemd unit (jstodola) +- mon_statd: switch to using udevadm settle (#688140) +- cpuplugd: Fix incorrect multiplication in rules evaluation (#693365) +- cmsfs-fuse: Delete old file if renaming to an existing file (#690505) +- cmsfs-fuse: Enlarge fsname string (#690506) +- cmsfs-fuse: Unable to use cmsfs-fuse if $HOME is not set (#690514) +- hyptop: Prevent interactive mode on s390 line mode terminals (#690810) + +* Fri Mar 18 2011 Dan Horák 2:1.8.2-31 +- mon_statd: switch to using udevadm settle (#688140) +- hyptop: Fix man page typo for "current weight" (#684244) +- fdasd: buffer overflow when writing to read-only device (#688340) +- cmsfs-fuse: fix read and write errors in text mode (#680465) +- cmsfs-fuse needs fuse (#631546) +- dumpconf: Add DELAY_MINUTES description to man page (#676706) +- iucvterm scriptlet need shadow-utils (#677247) +- use lower-case in udev rules (#597360) +- add support for the 1731/02 OSM/OSX network device (#636849) +- xcec-bridge: fix multicast forwarding (#619504) +- ziomon: wrong return codes (#623250) +- qethconf: process devices with non-zero subchannel (#627692) +- wait for completion of any pending actions affecting device (#631527) +- add infrastructure code for new features (#631541) +- hyptop: Show hypervisor performance data on System z (#631541) +- cmsfs-fuse: support for CMS EDF filesystems via fuse (#631546) +- lsmem/chmem: Tools to manage memory hotplug (#631561) +- dumpconf: Prevent re-IPL loop for dump on panic (#633411) +- ttyrun: run a program if a terminal device is available (#633420) +- zgetdump/zipl: Add ELF dump support (needed for makedumpfile) (#633437) +- znetconf: support for OSA CHPID types OSX and OSM (#633534) +- iucvtty: do not specify z/VM user ID as argument to login -h (#636204) +- tunedasd: add new option -Q / --query_reserve (#644935) +- fdasd/dasdfmt: fix format 7 label (#649787) +- cpuplugd: cmm_pages not set and restored correctly (#658517) +- lsluns: Fix LUN reporting for SAN volume controller (SVC) (#659828) +- lsluns: Accept uppercase and lowercase hex digits (#660361) +- cmsfs: use detected filesystem block size (#651012) +- device_cio_free: use the /proc/cio_settle interface when waiting for devices +- libzfcphbaapi library needs kernel-devel during build and thus is limited to s390x +- libzfcphbaapi library rebased to 2.1 (#633414) +- new zfcp tools added (#633409) + +* Wed Feb 09 2011 Fedora Release Engineering - 2:1.8.2-30 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Tue Jul 13 2010 Dan Horák 2:1.8.2-29 +- lsluns: uninitialized value on adapter offline (#611795) +- zfcpdbf: Fix 'Use of uninitialized value' and output issues (#612622) + +* Wed Jul 7 2010 Dan Horák 2:1.8.2-28 +- fix linking with --no-add-needed + +* Tue Jun 29 2010 Dan Horák 2:1.8.2-27 +- make znet_cio_free work also when no interface config files exists (#609073) +- fix --dates option in zfcpdbf (#609092) + +* Mon Jun 28 2010 Dan Horák 2:1.8.2-26 +- follow symlinks in ziorep (#598574) +- do not restrict group names to be alphanumeric in ts-shell (#598641) +- znetconf --drive|-d option returning 'unknown driver' for qeth (#601846) +- fix stack overwrite in cpuplugd (#601847) +- fix cmm_min/max limit checks in cpuplugd (#606366) +- set cpu_min to 1 by default in cpuplugd (#606416) +- build with -fno-strict-aliasing (#599396) +- remove reference to z/VM from the cpi initscript (#601753) +- fix return values for the mon_statd initscript (#606805) +- ignore backup and similar config files in device_cio_free (#533494) + +* Fri May 28 2010 Dan Horák 2:1.8.2-25 +- fixed device_cio_free command line handling (#595569) + +* Thu May 20 2010 Dan Horák 2:1.8.2-24 +- added a check for the length of the parameters line (#594031) + +* Wed May 19 2010 Dan Horák 2:1.8.2-23 +- make ccw_init compatible with posix shell (#546615) + +* Wed May 5 2010 Dan Horák 2:1.8.2-22 +- scripts can't depend on stuff from /usr (#587364) + +* Mon May 3 2010 Dan Horák 2:1.8.2-21 +- updated patch for the "reinitialize array in lsqeth" issue (#587757) + +* Fri Apr 30 2010 Dan Horák 2:1.8.2-20 +- updated lsdasd man page (#587044) +- reinitialize array in lsqeth (#587599) + +* Wed Apr 28 2010 Dan Horák 2:1.8.2-19 +- fixed mismatch between man and -h in chshut (#563625) +- use the merged ccw_init script (#533494, #561814) + +* Thu Apr 22 2010 Dan Horák 2:1.8.2-18 +- lsluns utility from the base subpackage requires sg3_utils + +* Wed Apr 21 2010 Dan Horák 2:1.8.2-17 +- updated device_cio_free script (#576015) + +* Wed Mar 31 2010 Dan Horák 2:1.8.2-16 +- updated device_cio_free upstart config file (#578260) +- fix multipathing in ziomon (#577318) + +* Mon Mar 29 2010 Dan Horák 2:1.8.2-15 +- remove check for ziorep_config availability (#576579) +- install upstart event file into /etc/init (#561339) +- device_cio_free updates + - don't use basename/dirname + - correctly parse /etc/ccw.conf (#533494) + +* Mon Mar 22 2010 Dan Horák 2:1.8.2-14 +- don't use memory cgroups in zfcpdump kernel (#575183) +- fix df usage in ziomon (#575833) + +* Thu Mar 11 2010 Dan Horák 2:1.8.2-13 +- dropped dependency on redhat-lsb (#542702) + +* Wed Mar 10 2010 Dan Horák 2:1.8.2-12 +- run device_cio_free on startup (#561339) +- use hex index for chpidtype table in znetconf (#561056) +- handle status during IPL SSCH (#559250) +- don't show garbage in vmconvert's progress bar (#567681) +- don't print enviroment when there are no devices to wait for (#570763) +- fix zfcp dump partition error (#572313) +- switched to new initscripts for cpuplugd and fsstatd/procd (#524218, #524477) + +* Tue Feb 16 2010 Dan Horák 2:1.8.2-11 +- moved ccw udev stuff from initscripts to s390utils +- updated ccw_init with delay loops and layer2 handling (#561926) + +* Fri Jan 22 2010 Dan Horák 2:1.8.2-10.1 +- really update zfcpconf.sh script from dracut + +* Wed Jan 20 2010 Dan Horák 2:1.8.2-10 +- fixed return codes in ziorep (#556849) +- fixed return code in lstape (#556910) +- fixed reading the size of /proc/sys/vm/cmm_pages in cpuplugd (#556911) +- support new attributes in lsqeth (#556915) + +* Wed Jan 13 2010 Dan Horák 2:1.8.2-9 +- updated device_cio_free script (#533494) +- fixed uppercase conversion in lscss (#554768) + +* Fri Jan 8 2010 Dan Horák 2:1.8.2-8 +- updated device_cio_free script (#533494) + +* Fri Jan 8 2010 Dan Horák 2:1.8.2-7 +- updated device_cio_free script (#533494) + +* Tue Dec 22 2009 Dan Horák 2:1.8.2-6.1 +- fixed return value in cpi initscript (#541389) + +* Tue Dec 22 2009 Dan Horák 2:1.8.2-6 +- fixed return value in cpi initscript (#541389) +- updated zfcpconf.sh script from dracut +- added device-mapper support into zipl (#546280) +- added missing check and print NSS name in case an NSS has been IPLed (#546297) +- added device_cio_free script and its symlinks (#533494) +- added qualified return codes and further error handling in znetconf (#548487) + +* Fri Nov 13 2009 Dan Horák 2:1.8.2-5 +- added multiple fixes from IBM (#533955, #537142, #537144) + +* Thu Nov 12 2009 Dan Horák 2:1.8.2-4 +- added udev rules and script for dasd initialization (#536966) +- added ghosted zfcp and dasd config files, fixes their ownership on the system +- fixed upgrade path for libzfcphbaapi-devel subpackage + +* Mon Nov 9 2009 Dan Horák 2:1.8.2-3 +- added files for the CPI feature (#463282) +- built lib-zfcp-hbaabi library as vendor lib, switched from -devel (no devel content now) to -docs subpackage (#532707) + +* Fri Oct 30 2009 Dan Horák 2:1.8.2-2 +- install dasd udev rules provided by the s390-tools +- added patch for setting readahead value + +* Thu Oct 8 2009 Dan Horák 2:1.8.2-1 +- added patch for improving mon_statd behaviour +- rebased to 1.8.2 + +* Fri Oct 2 2009 Dan Horák 2:1.8.1-8 +- really changed ramdisk load address (#526339) +- change the required and optional subpackages for the meta package + +* Wed Sep 30 2009 Dan Horák 2:1.8.1-7 +- changed ramdisk load address (#526339) +- updated zfcpconf.sh script to new sysfs interface (#526324) +- added 1.8.1 fixes from IBM (#525495) + +* Fri Sep 25 2009 Dan Horák 2:1.8.1-6 +- fix issues in lib-zfcp-hbaapi with a patch + +* Thu Sep 24 2009 Dan Horák 2:1.8.1-5 +- drop support for Fedora < 10 + +* Thu Sep 24 2009 Dan Horák 2:1.8.1-4 +- fixed string overflow in vtoc_volume_label_init (#525318) + +* Thu Sep 3 2009 Dan Horák 2:1.8.1-3 +- create devel subpackage with some useful headers +- preserving timestamps on installed files + +* Wed Aug 26 2009 Dan Horák 2:1.8.1-2 +- Fix byte check for disk encryption check in lsluns (#510032) +- Fix cmm configuration file value initialization parser in cpuplugd (#511379) +- Check only ZFCP devices in lszfcp (#518669) + +* Mon Jun 29 2009 Dan Horák 2:1.8.1-1 +- update to 1.8.1 +- drop upstreamed patches +- create iucvterm subpackage +- update src_vipa locations patch +- install cmsfs tools into /sbin +- add post 1.8.1 fixes from IBM + +* Fri Apr 17 2009 Dan Horák 2:1.8.0-6 +- fix build with newer kernels + +* Wed Mar 25 2009 Dan Horák 2:1.8.0-5 +- reword the summaries a bit +- add downloadable URLs for Sources +- fix CFLAGS usage + +* Fri Mar 13 2009 Dan Horák 2:1.8.0-4 +- next round of clean-up for compliance with Fedora + +* Sun Mar 8 2009 Dan Horák 2:1.8.0-3 +- little clean-up for compliance with Fedora + +* Fri Dec 12 2008 Hans-Joachim Picht 2:1.8.0-2 +- Adapted package for F9 + +* Tue Dec 9 2008 Michael Holzheu 2:1.8.0-1 +- Changed spec file to create sub packages +- Updated to zfcphbaapi version 2.0 + +* Tue Oct 28 2008 Dan Horák 2:1.7.0-4 +- disable build-id feature in zipl (#468017) + +* Wed Sep 24 2008 Dan Horák 2:1.7.0-3 +- drop the mon_tools patch (mon_statd service starts both mon_procd and mon_fsstatd since 1.7.0) + +* Thu Aug 28 2008 Dan Horák 2:1.7.0-2 +- preserve timestamps on installed files +- add proper handling of initscripts +- fix permissions for some files + +* Tue Aug 12 2008 Dan Horák 2:1.7.0-1 +- update to s390-tools 1.7.0, src_vipa 2.0.4 and cmsfs 1.1.8c +- rebase or drop RHEL5 patches + +* Fri Jul 25 2008 Dan Horák 2:1.5.3-19.el5 +- fix use "vmconvert" directly on the vmur device node (#439389) +- fix the Linux Raid partition type is not retained when changed through fdasd (#445271) +- include missing files into the package (#442584) +- Resolves: #439389, #445271, #442584 + +* Fri Jul 25 2008 Dan Horák 2:1.5.3-18.el5 +- split the warnings patch into s390-tools and cmsfs parts +- mismatch between installed /etc/zfcp.conf and zfcpconf.sh expected format (#236016) +- dbginfo.sh exits before running all tests and drops errors (#243299) +- updates for cleanup SCSI dumper code for upstream integration - tool (#253118) +- fix segfault when using LD_PRELOAD=/usr/lib64/src_vipa.so (#282751) +- add support for timeout parameter in /etc/zipl.conf (#323651) +- fixes not listing all the dasds passed as arguments to lsdasd command (#369891) +- fix for zipl fail when section is specified and target is not repeated for all sections (#381201) +- fix for dasdview -s option fails to ignore the garbage value passed (#412951) +- update documentation for zfcpdump (#437477) +- update documentation for lsqeth (#455908) +- Resolves: #236016, #243299, #253118, #282751, #323651, #369891, #381201, #412951, #437477, #455908 + +* Fri Mar 28 2008 Phil Knirsch 2:1.5.3-17.el5 +- Fix error messages and proc/0 entry are not handled correctly (#438819) + +* Wed Feb 06 2008 Phil Knirsch 2:1.5.3-16.el5 +- Fixed a build problem with the mon_tools patch (#253029) + +* Mon Feb 04 2008 Phil Knirsch 2:1.5.3-14.el5 +- Added zfcpdump kernel symlink to dumpconf init script (#430550) + +* Fri Jan 18 2008 Phil Knirsch 2:1.5.3-13.el5 +- Fix tape390_crypt query shows wrong msg 'Kernel does not support tape encryption' (#269181) + +* Wed Jan 16 2008 Phil Knirsch 2:1.5.3-12.el5 +- Add System z guest file system size in Monitor APPLDATA (#253029) +- Add Dynamic CHPID reconfiguration via SCLP - tools (#253076) +- Add z/VM unit-record device driver - tools (#253078) +- Cleanup SCSI dumper code for upstream integration - tool (#253118) + +* Tue Jan 08 2008 Phil Knirsch 2:1.5.3-11.el5 +- Fix installer LVM partitions that show up as "unknown" in fdasd (#250176) +- Fixed zfcpconf.sh failure if / and /usr are separated (#279201) + +* Mon Sep 24 2007 Phil Knirsch 2:1.5.3-10.el5.14 +- Added missing openssl-devel buildrequires (#281361) + +* Thu Aug 23 2007 Phil Knirsch 2:1.5.3-10.el5.13 +- Last updage for -t parameter patch (#202086) + +* Tue Aug 14 2007 Phil Knirsch 2:1.5.3-10.el5.12 +- Fix handling of external timer interrupts (#250352) + +* Tue Jul 31 2007 Phil Knirsch 2:1.5.3-10.el5.11 +- Update fix for -t parameter for image operations (#202086) + +* Fri Jul 27 2007 Phil Knirsch 2:1.5.3-10.el5.10 +- Fixed udev regression from RHEL 4 with /dev/dasd/ (#208189) +- Fixed missing -d option for zgetdump (#228094) + +* Thu Jun 28 2007 Phil Knirsch 2:1.5.3-10.el5.9 +- Fix optional -t parameter for image operations (#202086) + +* Wed Jun 27 2007 Phil Knirsch 2:1.5.3-10.el5.8 +- Fix wrong manpage (#202250) +- Fix zfcp devices not showing up after boot (#223569) +- Fix help menu of lsqeth showing wrong file (#225159) +- Add tape encryption userspace tool (#228080) +- Add dump on panic initscript and sysconf (#228094) +- Fix a off-by-one error in zfcpdbf (#230527) +- Fix zipl aborting with floating point exception if the target specified is a logical volume (#231240) +- Fix boot menu use wrong conversion table for input on LPAR (#240399) + +* Mon Jan 22 2007 Phil Knirsch 2:1.5.3-10.el5.6 +- Fixed problem with invisible zfcp devices after boot (#223569) + +* Mon Jan 15 2007 Phil Knirsch 2:1.5.3-10.el5.5 +- Extended fix for automenu bug (#202086) + +* Thu Jan 11 2007 Phil Knirsch 2:1.5.3-10.el5.4 +- Updated dbginfo.sh patch to final fix from IBM (#214805) + +* Wed Nov 29 2006 Phil Knirsch 2:1.5.3-10.el5.3 +- Fixed problem with missing debugfs for dbginfo.sh (#214805) + +* Thu Nov 09 2006 Phil Knirsch 2:1.5.3-10.el5.2 +- Fixed lszfcp bug related to sysfsutils (#210515) + +* Tue Nov 07 2006 Phil Knirsch 2:1.5.3-10.el5.1 +- Removed wrong additional $ in src_vipa.sh (#213395) +- Release and Buildroot specfile fixes + +* Wed Sep 13 2006 Phil Knirsch 2:1.5.3-10 +- Needed to bump release + +* Tue Sep 12 2006 Phil Knirsch 2:1.5.3-9 +- Added libsysfs requirement (#201863) +- Fixed zipl problem with missing default target for automenus (#202086) + +* Thu Aug 10 2006 Phil Knirsch 2:1.5.3-8 +- Added missing sysfsutils requirement for lszfcp (#201863) + +* Tue Jul 25 2006 Phil Knirsch 2:1.5.3-7 +- Included zfcpdbf, dbginfo.sh and the man1 manpages to package (#184812) + +* Tue Jul 18 2006 Phil Knirsch 2:1.5.3-6 +- Disabled sysfs support due to API changes in sysfs-2.0.0 + +* Fri Jul 14 2006 Karsten Hopp 2:1.5.3-5 +- buildrequire net-snmp-devel + +* Fri Jul 14 2006 Jesse Keating - 2:1.5.3-4 +- rebuild +- Add missing br libsysfs-devel, indent, zlib-devel + +* Wed May 17 2006 Phil Knirsch 2:1.5.3-1 +- Made src_vipa build on current toolchain again + +* Tue May 16 2006 Phil Knirsch +- Update to s390-tools-1.5.3 from IBM +- Included vmconvert +- Dropped obsolete asm patch + +* Tue Feb 07 2006 Jesse Keating - 2:1.5.0-2.1 +- rebuilt for new gcc4.1 snapshot and glibc changes + +* Mon Jan 30 2006 Phil Knirsch 2:1.5.0-2 +- Fixed problem with s390-tools-1.5.0-fdasd-raid.patch +- Don't try to remove the non empty _bindir +- Some more install cleanups + +* Thu Jan 26 2006 Phil Knirsch +- Fixed some .macro errors in zipl/boot + +* Fri Dec 09 2005 Jesse Keating +- rebuilt + +* Thu Oct 20 2005 Phil Knirsch 2:1.5.0-1 +- Large update from 1.3.2 to 1.5.0 +- Include osasnmpd and vmcp now by default + +* Tue Sep 06 2005 Phil Knirsch 2:1.3.2-7 +- Fixed a couple of code bugs (#143808) + +* Fri Jul 29 2005 Phil Knirsch 2:1.3.2-6 +- Corrected filelist for libdir to only include *.so files + +* Tue Jun 21 2005 Phil Knirsch 2:1.3.2-5 +- Added src_vipa to s390utils + +* Wed Mar 02 2005 Phil Knirsch 2:1.3.2-4 +- bump release and rebuild with gcc 4 + +* Tue Oct 26 2004 Phil Knirsch 2:1.3.2-3 +- Put binaries for system recovery in /sbin again. + +* Fri Oct 15 2004 Phil Knirsch 2:1.3.2-1 +- Update to s390-tools-1.3.2 +- Added qetharp, qethconf, ip_watcher, tunedasd and various other tools to + improve functionality on s390(x). + +* Wed Oct 06 2004 Phil Knirsch 2:1.3.1-7 +- Made the raid patch less verbose (#129656) + +* Thu Sep 16 2004 Phil Knirsch 2:1.3.1-6 +- Added prompt=1 and timeout=15 to automatically generated menu + +* Tue Aug 31 2004 Karsten Hopp 2:1.3.1-5 +- install zfcpconf.sh into /sbin + +* Tue Aug 24 2004 Karsten Hopp 2:1.3.1-4 +- add zfcpconf.sh to read /etc/zfcp.conf and configure the zfcp + devices + +* Thu Jun 24 2004 Phil Knirsch 2:1.3.1-3 +- Fixed another automenu bug with dumpto and dumptofs (#113204). + +* Thu Jun 17 2004 Phil Knirsch 2:1.3.1-2 +- Fixed automenu patch. +- Fixed problem with installation from tape (#121788). + +* Wed Jun 16 2004 Phil Knirsch 2:1.3.1-1 +- Updated to latest upstream version s390-tools-1.3.1 + +* Tue Jun 15 2004 Elliot Lee +- rebuilt + +* Mon Jun 07 2004 Karsten Hopp +- add cmsfs utils + +* Tue Mar 02 2004 Elliot Lee +- rebuilt + +* Thu Feb 19 2004 Phil Knirsch 2:1.2.4-4 +- Fixed rebuilt on fc2. + +* Thu Feb 19 2004 Phil Knirsch 2:1.2.4-3 +- Fixed automenu patch, was allocating 1 line to little. + +* Mon Feb 16 2004 Phil Knirsch 2:1.2.4-2 +- rebuilt + +* Mon Feb 16 2004 Phil Knirsch 2:1.2.4-1 +- Updated to latest developerworks release 1.2.4 +- Disabled zfcpdump build until i find a way to build it as none-root. + +* Fri Feb 13 2004 Elliot Lee 2:1.2.3-3 +- rebuilt + +* Thu Dec 04 2003 Phil Knirsch 2:1.2.3-2 +- Fixed zfcpdump build. + +* Fri Nov 28 2003 Phil Knirsch 2:1.2.3-1 +- New bugfix release 1.2.3 came out today, updated again. + +* Wed Nov 26 2003 Phil Knirsch 2:1.2.2-1 +- Updated to latest Developerworks version 1.2.2 +- Cleaned up specfile and patches a little. + +* Wed Nov 12 2003 Phil Knirsch 2:1.2.1-4.1 +- rebuilt + +* Wed Nov 12 2003 Phil Knirsch 2:1.2.1-4 +- Another fix for the new automenu patch. Target was an optional parameter in + old s390utils, provided compatibility behaviour. + +* Mon Oct 20 2003 Phil Knirsch 2:1.2.1-3.1 +- rebuilt + +* Mon Oct 20 2003 Phil Knirsch 2:1.2.1-3 +- Small fix for the new automenu patch, default section didn't work correctly + +* Mon Oct 20 2003 Phil Knirsch 2:1.2.1-2.1 +- rebuilt + +* Fri Oct 17 2003 Phil Knirsch 2:1.2.1-2 +- Patched new zipl to be backwards compatible to old multiboot feature. + +* Thu Oct 9 2003 Harald Hoyer 2:1.2.1-1 +- second round at updating to 1.2.1 + +* Thu Oct 09 2003 Florian La Roche +- first round at updating to 1.2.1 + +* Sat Sep 27 2003 Florian La Roche +- add /boot/tape0 for .tdf tape boots + +* Fri Jul 25 2003 Florian La Roche +- apply dasdfmt patch from 1.2.1 + +* Fri Jun 20 2003 Phil Knirsch 1.1.7-1 +- Updated to latest upstream version 1.1.7 + +* Fri May 02 2003 Pete Zaitcev 1.1.6-7 +- Fix usage of initialized permissions for bootmap. + +* Tue Apr 29 2003 Florian La Roche +- add extra tape loader from Pete Zaitcev + +* Mon Apr 14 2003 Karsten Hopp 2:1.1.6-5 +- drop cpint support + +* Mon Mar 24 2003 Karsten Hopp 1.1.6-4 +- use multiboot as default +- add option to disable multiboot + +* Sat Mar 22 2003 Karsten Hopp 1.1.6-3 +- add multiboot patch + +* Mon Mar 10 2003 Karsten Hopp 1.1.6-2 +- added percentage patch (used by anaconda to display progress bars) + +* Thu Feb 27 2003 Phil Knirsch 1.1.6-1 +- Updated to newest upstream version 1.1.6 + +* Tue Feb 04 2003 Phil Knirsch 1.1.5-1 +- Updated to newest upstream version 1.1.5 + +* Tue Feb 04 2003 Karsten Hopp 1.1.4-3 +- install libraries in /lib*, not /usr/lib*, they are required + by some tools in /sbin + +* Sun Feb 02 2003 Florian La Roche +- fix filelist to not include debug files + +* Fri Jan 24 2003 Phil Knirsch 1.1.4-1 +- Updated to latest upstream version of IBM. +- Removed all unecessary patches and updated still needed patches. +- Fixed version number. Needed to introduce epoch though. +- A little specfile cleanup. +- Dropped oco-setver and oco-convert as we don't need them anymore. + +* Wed Jan 22 2003 Phil Knirsch 20020226-4 +- Added ExclusiveArch tag. + +* Mon Oct 21 2002 Phil Knirsch 20020226-3 +- Removed fdisk -> fdasd symlink. Is now provided by util-linux. +- Disabled f5 patch for s390x for now. Enable it later for newer kernels again. + +* Mon May 27 2002 Phil Knirsch +- Fixed dasdview to build on kernels > 2.4.18. + +* Wed Apr 24 2002 Karsten Hopp +- add IBM 5 patch + +* Tue Jan 29 2002 Karsten Hopp +- add IBM 4 patch +- add profile.d scripts to set correct TERM in 3270 console + +* Tue Dec 18 2001 Karsten Hopp +- add cpint programs + +* Mon Nov 26 2001 Harald Hoyer 20011012-6 +- fix for #56720 + +* Thu Nov 15 2001 Karsten Hopp +- add fdisk - > fdasd symlink + +* Mon Nov 12 2001 Karsten Hopp +- add IBM patch (11/09/2001) and redo percentage patch + +* Thu Nov 08 2001 Karsten Hopp +- re-enable DASD if dasdfmt is interrupted with Ctrl-C + +* Mon Nov 05 2001 Harald Hoyer 20011012-4 +- added s390-tools-dasdfmt-percentage.patch + +* Mon Oct 22 2001 Karsten Hopp +- remove postinstall script + +* Mon Oct 15 2001 Karsten Hopp +- add IBM's s390-utils-2.patch +- add console to securetty + +* Mon Oct 01 2001 Karsten Hopp +- added oco-setkver and oco-convert + +* Fri Aug 31 2001 Karsten Hopp +- don't write error message in silent mode + +* Thu Aug 23 2001 Harald Hoyer +- added s390-tools-dasdfmt-status.patch + +* Tue Aug 21 2001 Karsten Hopp +- update to the version from Aug 20 + +* Tue Aug 14 2001 Karsten Hopp +- fix permissions + +* Mon Aug 13 2001 Karsten Hopp +- rename package to s390utils. s390-tools is no longer needed. + +* Thu Aug 02 2001 Karsten Hopp +- initial build