mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Compare commits
58 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d8b8114e6f | |||
| c4e4b926b4 | |||
| 6324f62da7 | |||
| 3ade063ea2 | |||
| 92a3b30323 | |||
| 673ff375d9 | |||
| 4e2ebe0370 | |||
| 78b053326c | |||
| ab06a5d88a | |||
| a0a71efde0 | |||
| b4b2202ff5 | |||
| a26f61c4fe | |||
| a28b396d9e | |||
| 0012eaf68e | |||
| c22d282e67 | |||
| 071522f7d2 | |||
| ae7217806b | |||
| 9f6150db34 | |||
| b39bdfbf6e | |||
| 71fe58111c | |||
| 5e46632767 | |||
| 1bd64f5b0f | |||
| d311506dc4 | |||
| 08e4520a4f | |||
| 46fd42af0c | |||
| a8b0d7ace8 | |||
| a29b3c8997 | |||
| 27dce3317a | |||
| 4382901daa | |||
| bcbb6fcae6 | |||
| b16a6d4fe1 | |||
| 0d15a07c0a | |||
| 5394cd363c | |||
| 0906293cd8 | |||
| a9e13a2d69 | |||
| ee2c6d4160 | |||
| 455ad953a9 | |||
| 02a0d12988 | |||
| be47b51890 | |||
| 2677a4182d | |||
| 812df795c3 | |||
| a0d6edf03c | |||
| 81920f7cfd | |||
| 40dd63e2ac | |||
| a8579a0727 | |||
| 2ab27bdaf2 | |||
| 03fef264bd | |||
| 927a48e607 | |||
| fbcb3f384a | |||
| c7fe21b019 | |||
| 50a4740443 | |||
| 164d4817ec | |||
| abec41f514 | |||
| fcb503ea3c | |||
| 2eea614bbf | |||
| 3a13cb43f2 | |||
| e8fca95592 | |||
| b5604850ab |
@@ -11,3 +11,11 @@ tab_width = 8
|
|||||||
|
|
||||||
[*.sh]
|
[*.sh]
|
||||||
shell_variant = bash # used by `shfmt`
|
shell_variant = bash # used by `shfmt`
|
||||||
|
|
||||||
|
[*.y{a,}ml]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[*.py]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
|||||||
+3
-2
@@ -5,7 +5,7 @@ List of all individuals having contributed content to s390-tools
|
|||||||
- Alexandra Winter
|
- Alexandra Winter
|
||||||
- Alexey Ishchuk
|
- Alexey Ishchuk
|
||||||
- Andreas Herrmann
|
- Andreas Herrmann
|
||||||
- Andre Wild
|
- André Wild
|
||||||
- Antoinette Kaschner
|
- Antoinette Kaschner
|
||||||
- Arnd Bergmann
|
- Arnd Bergmann
|
||||||
- Axel Wirbser
|
- Axel Wirbser
|
||||||
@@ -19,6 +19,7 @@ List of all individuals having contributed content to s390-tools
|
|||||||
- Clemens von Mann
|
- Clemens von Mann
|
||||||
- Colin Walters
|
- Colin Walters
|
||||||
- Dan Horak
|
- Dan Horak
|
||||||
|
- Dan Horák
|
||||||
- Despina Papadopoulou
|
- Despina Papadopoulou
|
||||||
- Dimitri John Ledkov
|
- Dimitri John Ledkov
|
||||||
- Eberhard Pasch
|
- Eberhard Pasch
|
||||||
@@ -53,7 +54,7 @@ List of all individuals having contributed content to s390-tools
|
|||||||
- Ingo Franzki
|
- Ingo Franzki
|
||||||
- Ingo Tuchscherer
|
- Ingo Tuchscherer
|
||||||
- Jan Glauber
|
- Jan Glauber
|
||||||
- Jan Hoeppner
|
- Jan Höppner
|
||||||
- Jan Willeke
|
- Jan Willeke
|
||||||
- Jason J. Herne
|
- Jason J. Herne
|
||||||
- Javier Martinez Canillas
|
- Javier Martinez Canillas
|
||||||
|
|||||||
+34
-1
@@ -1,6 +1,39 @@
|
|||||||
Release history for s390-tools (MIT version)
|
Release history for s390-tools (MIT version)
|
||||||
--------------------------------------------
|
--------------------------------------------
|
||||||
* __v2.20.0 (2021-02-04)__
|
* __v2.21.0 (2022-04-20)__
|
||||||
|
|
||||||
|
For Linux kernel version: 5.17
|
||||||
|
|
||||||
|
Add new tools / libraries:
|
||||||
|
- libcpumf: Create library libcpumf for CPU Measurement functions
|
||||||
|
|
||||||
|
Changes of existing tools:
|
||||||
|
- chreipl-fcp-mpath: bundle a pre-cooked version of the manpage for build
|
||||||
|
environments without access to `pandoc`
|
||||||
|
- dbginfo.sh: Add multipath info to map paths to FC addressing and prio group
|
||||||
|
- dbginfo.sh: Collect config files of systemd-modules-load.service
|
||||||
|
- dbginfo.sh: Sort list of environment variables for readability
|
||||||
|
- dbginfo.sh: Replace "which" by builtin command "type"
|
||||||
|
- dbginfo.sh: Rework script formatting (indents, order)
|
||||||
|
- dbginfo.sh: Update sysfs collection (excludes, messages)
|
||||||
|
- genprotimg: Add Protected Virtualization (PV) dump support
|
||||||
|
- genprotimg: Remove DigiCert root CA pinning
|
||||||
|
- lszcrypt: Add CEX8S support
|
||||||
|
- zcryptctl: Add control domain handling
|
||||||
|
- zcryptstats: Add CEX8 support
|
||||||
|
- zipl: Allow optional entries that are left out when files are missing
|
||||||
|
- zipl: make IPL sections defined with BLS to inherit a target field
|
||||||
|
- zpcictl: Add option to trigger firmware reset
|
||||||
|
|
||||||
|
Bug Fixes:
|
||||||
|
- cpictl: Handle excessive kernel version numbers
|
||||||
|
- dbginfo.sh: Collect all places where modprobe.d config files could exist
|
||||||
|
- fdasd: Fix endless menu loop on EOF
|
||||||
|
- zdump/dfi: Fix segfault due to double free
|
||||||
|
- zdump: Fix /dev/mem reading
|
||||||
|
- zpcictl: Fix race of SCLP reset and Linux recovery
|
||||||
|
|
||||||
|
* __v2.20.0 (2022-02-04)__
|
||||||
|
|
||||||
For Linux kernel version: 5.16
|
For Linux kernel version: 5.16
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ include common.mak
|
|||||||
#
|
#
|
||||||
BASELIB_DIRS = libutil libseckey
|
BASELIB_DIRS = libutil libseckey
|
||||||
LIB_DIRS = libvtoc libzds libdasd libvmdump libccw libvmcp libekmfweb \
|
LIB_DIRS = libvtoc libzds libdasd libvmdump libccw libvmcp libekmfweb \
|
||||||
libkmipclient
|
libkmipclient libcpumf
|
||||||
TOOL_DIRS = zipl zdump fdasd dasdfmt dasdview tunedasd \
|
TOOL_DIRS = zipl zdump fdasd dasdfmt dasdview tunedasd \
|
||||||
tape390 osasnmpd qetharp ip_watcher qethconf scripts zconf \
|
tape390 osasnmpd qetharp ip_watcher qethconf scripts zconf \
|
||||||
vmconvert vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \
|
vmconvert vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \
|
||||||
|
|||||||
@@ -478,5 +478,6 @@ the different tools are provided:
|
|||||||
Summarized: chreipl-fcp-mpath requires GNU Bash, GNU Core Utilities,
|
Summarized: chreipl-fcp-mpath requires GNU Bash, GNU Core Utilities,
|
||||||
util-linux, udev, and multipath-tools. When using `HAVE_DRACUT=1` with the
|
util-linux, udev, and multipath-tools. When using `HAVE_DRACUT=1` with the
|
||||||
make invocation, it also requires dracut. When using `ENABLE_DOC=1` with the
|
make invocation, it also requires dracut. When using `ENABLE_DOC=1` with the
|
||||||
make invocation to build a man page and render the README.md as HTML, make
|
make invocation to build a fresh man page (instead of using the pre-cooked
|
||||||
further requires pandoc and GNU awk for the build process.
|
version) and render the README.md as HTML, make further requires pandoc and
|
||||||
|
GNU awk for the build process.
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
8e604dab39577678bc9f24bfe5e2ee35354b2f4b1759edd16093157b1ecce9d3 README.md
|
||||||
@@ -9,4 +9,3 @@
|
|||||||
/README.html
|
/README.html
|
||||||
/README.pdf
|
/README.pdf
|
||||||
/chreipl-fcp-mpath.md
|
/chreipl-fcp-mpath.md
|
||||||
/chreipl-fcp-mpath.7
|
|
||||||
|
|||||||
@@ -11,6 +11,8 @@
|
|||||||
# - chreipl-fcp-mpath.mak
|
# - chreipl-fcp-mpath.mak
|
||||||
# bash:
|
# bash:
|
||||||
# - bash
|
# - bash
|
||||||
|
# GNU coreutils:
|
||||||
|
# - sha256sum
|
||||||
# If $(ENABLE_DOC) is `1`:
|
# If $(ENABLE_DOC) is `1`:
|
||||||
# GNU awk:
|
# GNU awk:
|
||||||
# - gawk
|
# - gawk
|
||||||
@@ -100,20 +102,41 @@ chreiplzfcpmp-doc-man-meta = \
|
|||||||
-V footer="s390-tools $(S390_TOOLS_RELEASE)"
|
-V footer="s390-tools $(S390_TOOLS_RELEASE)"
|
||||||
|
|
||||||
chreipl-fcp-mpath.7: PANDOCFLAGS += $(chreiplzfcpmp-doc-man-meta)
|
chreipl-fcp-mpath.7: PANDOCFLAGS += $(chreiplzfcpmp-doc-man-meta)
|
||||||
|
chreipl-fcp-mpath.7: .chreipl-fcp-mpath.7.cksum
|
||||||
|
|
||||||
.INTERMEDIATE: chreipl-fcp-mpath.md
|
.INTERMEDIATE: chreipl-fcp-mpath.md
|
||||||
chreipl-fcp-mpath.md: README.md
|
chreipl-fcp-mpath.md: README.md
|
||||||
gawk -- '/NOT-IN-MAN \{/,/NOT-IN-MAN \}/ { next } { print }' $(<) > $(@)
|
gawk -- '/NOT-IN-MAN \{/,/NOT-IN-MAN \}/ { next } { print }' $(<) > $(@)
|
||||||
|
|
||||||
|
.chreipl-fcp-mpath.7.cksum: README.md
|
||||||
|
sha256sum $(<) > $(@)
|
||||||
|
|
||||||
.PHONY: chreipl-fcp-mpath-doc-clean
|
.PHONY: chreipl-fcp-mpath-doc-clean
|
||||||
chreipl-fcp-mpath-doc-clean:
|
chreipl-fcp-mpath-doc-clean:
|
||||||
rm -f README.html README.pdf chreipl-fcp-mpath.md chreipl-fcp-mpath.7
|
rm -f README.html README.pdf chreipl-fcp-mpath.md
|
||||||
|
|
||||||
chreipl-fcp-mpath: chreipl-fcp-mpath-doc
|
chreipl-fcp-mpath: chreipl-fcp-mpath-doc
|
||||||
chreipl-fcp-mpath-clean: chreipl-fcp-mpath-doc-clean
|
chreipl-fcp-mpath-clean: chreipl-fcp-mpath-doc-clean
|
||||||
|
|
||||||
|
else # $(ENABLE_DOC) != 1
|
||||||
|
|
||||||
|
# We bundle a pre-cooked man page with the source-code so that distributions
|
||||||
|
# don't need `pandoc` in order to be able to ship the man page. As of this
|
||||||
|
# writing multiple distributions don't have a packaged version of it.
|
||||||
|
#
|
||||||
|
# In order to remember to regenerate this pre-cooked version whenever the
|
||||||
|
# README.md is changed, we also generate a checksum of the README.md, bundle
|
||||||
|
# that as well, and compare that whenever `make` is called. This way, the
|
||||||
|
# freshness of the man page can be checked, even if `pandoc` is not available,
|
||||||
|
# or ENABLE_DOC disabled.
|
||||||
|
|
||||||
|
MANPAGE_FRESH := $(shell sha256sum --check .chreipl-fcp-mpath.7.cksum >/dev/null && echo 1 || echo 0)
|
||||||
|
ifeq ($(MANPAGE_FRESH),0)
|
||||||
|
$(warning chreipl-fcp-mpath.7 is outdated, please regenerate it by calling `make ENABLE_DOC=1`)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
endif # $(ENABLE_DOC) == 1
|
||||||
|
|
||||||
#
|
#
|
||||||
## Install
|
## Install
|
||||||
#
|
#
|
||||||
@@ -180,8 +203,6 @@ chreipl-fcp-mpath-install: chreipl-fcp-mpath-install-dracut-config
|
|||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(ENABLE_DOC),1)
|
|
||||||
|
|
||||||
# chreipl-fcp-mpath: install man page
|
# chreipl-fcp-mpath: install man page
|
||||||
INSTDIRS += $(MANDIR)
|
INSTDIRS += $(MANDIR)
|
||||||
$(DESTDIR)$(MANDIR)/man7: install_dirs
|
$(DESTDIR)$(MANDIR)/man7: install_dirs
|
||||||
@@ -194,8 +215,6 @@ chreipl-fcp-mpath-install-man-page: chreipl-fcp-mpath.7
|
|||||||
|
|
||||||
chreipl-fcp-mpath-install: chreipl-fcp-mpath-install-man-page
|
chreipl-fcp-mpath-install: chreipl-fcp-mpath-install-man-page
|
||||||
|
|
||||||
endif
|
|
||||||
|
|
||||||
#
|
#
|
||||||
## Utility
|
## Utility
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -120,18 +120,20 @@ in place, but the toolset has some software dependencies besides the
|
|||||||
requirements in section [Requirements](#requirements):
|
requirements in section [Requirements](#requirements):
|
||||||
|
|
||||||
- GNU Bash;
|
- GNU Bash;
|
||||||
- GNU Core Utilities (mktemp, readlink, sync, truncate);
|
- GNU Core Utilities (mktemp, readlink, sync, truncate, sha256sum);
|
||||||
- util-linux (flock, hexdump, logger);
|
- util-linux (flock, hexdump, logger);
|
||||||
- udev / systemd-udev;
|
- udev / systemd-udev;
|
||||||
- multipath-tools.
|
- multipath-tools.
|
||||||
|
|
||||||
To make use of the optional dracut configuration you need: dracut.
|
To make use of the optional dracut configuration you need: dracut.
|
||||||
|
|
||||||
To build and install the documentation (man page) you need:
|
To build a fresh version of the documentation (man page) you need:
|
||||||
|
|
||||||
- pandoc;
|
- pandoc;
|
||||||
- GNU Core Utilities (date);
|
- GNU Core Utilities (date);
|
||||||
- GNU awk.
|
- GNU awk;
|
||||||
|
|
||||||
|
otherwise the pre-cooked version shipped with the source will be used.
|
||||||
|
|
||||||
INSTALLATION
|
INSTALLATION
|
||||||
============
|
============
|
||||||
@@ -160,7 +162,7 @@ steps and copies the resulting components to their final destination.
|
|||||||
| Option | Values | Default | Effect
|
| Option | Values | Default | Effect
|
||||||
| :----- | :----: | :-----: | :-----
|
| :----- | :----: | :-----: | :-----
|
||||||
| HAVE_DRACUT | 0, 1 | 0 | Install a dracut configuration file that includes **chreipl-fcp-mpath** in the initial ramdisks built with **dracut**.
|
| HAVE_DRACUT | 0, 1 | 0 | Install a dracut configuration file that includes **chreipl-fcp-mpath** in the initial ramdisks built with **dracut**.
|
||||||
| ENABLE_DOC | 0, 1 | 0 | Build and install a man page for **chreipl-fcp-mpath**.
|
| ENABLE_DOC | 0, 1 | 0 | Build a fresh version of the man page for **chreipl-fcp-mpath**.
|
||||||
|
|
||||||
Specify any options as arguments for both the **make** and **make install**
|
Specify any options as arguments for both the **make** and **make install**
|
||||||
command as shown in the following example:
|
command as shown in the following example:
|
||||||
@@ -195,8 +197,8 @@ the boot record to find the new initial ramdisk.
|
|||||||
|
|
||||||
~ # zipl
|
~ # zipl
|
||||||
|
|
||||||
With dracut and documentation enabled, **make install** deploys the following
|
With dracut enabled, **make install** deploys the following files to these
|
||||||
files to these default locations:
|
default locations:
|
||||||
|
|
||||||
/usr/lib/chreipl-fcp-mpath/chreipl-fcp-mpath-common.sh
|
/usr/lib/chreipl-fcp-mpath/chreipl-fcp-mpath-common.sh
|
||||||
/usr/lib/dracut/dracut.conf.d/70-chreipl-fcp-mpath.conf
|
/usr/lib/dracut/dracut.conf.d/70-chreipl-fcp-mpath.conf
|
||||||
|
|||||||
@@ -0,0 +1,183 @@
|
|||||||
|
.\" Automatically generated by Pandoc 2.16.1
|
||||||
|
.\"
|
||||||
|
.TH "CHREIPL-FCP-MPATH" "7" "2022-02-24" "s390-tools 2.20.0-build-20220224" "Administrator Manual"
|
||||||
|
.hy
|
||||||
|
.SH NAME
|
||||||
|
.PP
|
||||||
|
chreipl-fcp-mpath - use multipath information for re-IPL path failover
|
||||||
|
on a running Linux instance
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.PP
|
||||||
|
The IPL process of Linux on Z or LinuxONE from an FCP-attached SCSI
|
||||||
|
volume uses exactly one path to the volume.
|
||||||
|
If this path is unavailable, the IPL fails.
|
||||||
|
.PP
|
||||||
|
The \f[B]chreipl-fcp-mpath\f[R] toolset monitors \f[B]udev\f[R] events
|
||||||
|
about paths to the re-IPL volume.
|
||||||
|
If the currently configured re-IPL path becomes unavailable, the toolset
|
||||||
|
checks for operational paths to the same volume.
|
||||||
|
If available, it reconfigures the re-IPL settings to use an operational
|
||||||
|
path.
|
||||||
|
.PP
|
||||||
|
Thus, re-IPL from an FCP-attached SCSI volume can be successful despite
|
||||||
|
path failures on a running Linux instance if at least one path to the
|
||||||
|
re-IPL volume remains operational.
|
||||||
|
.PP
|
||||||
|
\f[B]Chreipl-fcp-mpath\f[R] requires \f[B]udev\f[R],
|
||||||
|
\f[B]multipathd\f[R] and \f[B]dm-multipath\f[R].
|
||||||
|
Once installed, the toolset runs automatically and autonomously.
|
||||||
|
No user intervention is possible or required.
|
||||||
|
.PP
|
||||||
|
Other than installing the toolset, there is no user interface for
|
||||||
|
\f[B]chreipl-fcp-mpath\f[R].
|
||||||
|
.SS Requirements
|
||||||
|
.PP
|
||||||
|
The \f[B]chreipl-fcp-mpath\f[R] tool has the following requirements on
|
||||||
|
the Linux instance that is being monitored:
|
||||||
|
.IP \[bu] 2
|
||||||
|
The Linux instance must have started successfully, during IPL.
|
||||||
|
.IP \[bu] 2
|
||||||
|
The running Linux instance must use \f[B]dm-multipath\f[R] and
|
||||||
|
\f[B]multipathd\f[R] for the configured re-IPL volume - a volume that
|
||||||
|
contains a zipl boot record and has one of its paths used in the re-IPL
|
||||||
|
configuration.
|
||||||
|
.IP \[bu] 2
|
||||||
|
\f[B]udev\f[R] must run.
|
||||||
|
.IP \[bu] 2
|
||||||
|
The toolset must observe at least one event about the configured re-IPL
|
||||||
|
path.
|
||||||
|
Examples for such events are: the SCSI disk comes online, or a path of
|
||||||
|
the corresponding multipath device goes down or comes back online.
|
||||||
|
.RS 2
|
||||||
|
.IP \[bu] 2
|
||||||
|
The WWID of the re-IPL volume must not change while the Linux instance
|
||||||
|
is running.
|
||||||
|
.RE
|
||||||
|
.IP \[bu] 2
|
||||||
|
When the configured re-IPL path becomes unavailable while the Linux
|
||||||
|
instance is running, at least one operational path to the re-IPL volume
|
||||||
|
must be available, or must become available.
|
||||||
|
If no such path is available when the Linux instance is rebooted, the
|
||||||
|
re-IPL path is not changed.
|
||||||
|
.IP \[bu] 2
|
||||||
|
The tool assumes that any manually reconfigured re-IPL device is valid
|
||||||
|
and operational.
|
||||||
|
.RS 2
|
||||||
|
.PP
|
||||||
|
The tool treats a newly configured re-IPL device like the initially
|
||||||
|
configured re-IPL device.
|
||||||
|
In particular, if the newly configured re-IPL device fulfills the
|
||||||
|
requirements of the tool, re-IPL path failover takes place if the
|
||||||
|
configured re-IPL path becomes unavailable.
|
||||||
|
.RE
|
||||||
|
.SS Caution with Manual Changes to the Configured re-IPL Target
|
||||||
|
.PP
|
||||||
|
\f[B]chreipl-fcp-mpath\f[R] is designed to accept operator-inititated
|
||||||
|
changes of the re-IPL device.
|
||||||
|
However, concurrent changes by the operator and tool driven changes can
|
||||||
|
result in the operator change being overwritten.
|
||||||
|
.PP
|
||||||
|
To avoid this problem, change the re-IPL device only during steady-state
|
||||||
|
operations, when no path events happen.
|
||||||
|
Alternatively, make sure that no events are processed while you change
|
||||||
|
the device.
|
||||||
|
See EXAMPLES for one way to suspend event processing.
|
||||||
|
.SH MESSAGES
|
||||||
|
.PP
|
||||||
|
During monitoring and event processing, \f[B]chreipl-fcp-mpath\f[R]
|
||||||
|
writes messages to the syslog.
|
||||||
|
.PP
|
||||||
|
When the configured re-IPL path is changed to a different path to the
|
||||||
|
same volume (priority \f[I]daemon.notice\f[R]):
|
||||||
|
.RS
|
||||||
|
.PP
|
||||||
|
Changed re-IPL path to: <device-bus-id>:<wwpn>:<lun>.
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
When a path event indicates that the last available path has become
|
||||||
|
non-operational (priority \f[I]daemon.alert\f[R]):
|
||||||
|
.RS
|
||||||
|
.PP
|
||||||
|
The re-IPL device cannot be changed because no operational path to the
|
||||||
|
re-IPL volume remains.
|
||||||
|
The next re-IPL might fail unless you re-attach or enable at least one
|
||||||
|
valid path to the re-IPL volume.
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
When changing the configured re-IPL device failed because of an error
|
||||||
|
with the used Linux kernel interface (priority \f[I]daemon.crit\f[R]):
|
||||||
|
.RS
|
||||||
|
.PP
|
||||||
|
Changing the re-IPL device failed.
|
||||||
|
The current re-IPL settings might be inconsistent.
|
||||||
|
Check and correct the settings (see the README.md of chreipl-fcp-mpath)
|
||||||
|
to make sure that the current re-IPL device is valid.
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
A failure to change the re-IPL device can indicate an inconsistent
|
||||||
|
setting that cannot be corrected automatically by
|
||||||
|
\f[B]chreipl-fcp-mpath\f[R].
|
||||||
|
As a result, the next re-IPL might fail or might not use the intended
|
||||||
|
re-IPL device.
|
||||||
|
.PP
|
||||||
|
You can use the following tools to check and correct the current
|
||||||
|
settings:
|
||||||
|
.IP \[bu] 2
|
||||||
|
\f[B]lsreipl\f[R] to confirm that the intended re-IPL device is
|
||||||
|
configured;
|
||||||
|
.IP \[bu] 2
|
||||||
|
\f[B]chreipl\f[R] to change the re-IPL device;
|
||||||
|
.IP \[bu] 2
|
||||||
|
\f[B]lszfcp\f[R] to inspect the state of available paths to the re-IPL
|
||||||
|
device.
|
||||||
|
.SH EXAMPLES
|
||||||
|
.SS Manual Changes to the Configured re-IPL Device
|
||||||
|
.PP
|
||||||
|
As outlined in DESCRIPTION, be cautious when manually changing the
|
||||||
|
configured re-IPL device.
|
||||||
|
Assure that your reconfiguration actions do not collide with concurrent
|
||||||
|
automatic event processing by \f[B]chreipl-fcp-mpath\f[R].
|
||||||
|
You can avoid such collisions, by stopping event processing, making your
|
||||||
|
changes, and then re-enabling event processing.
|
||||||
|
You need \f[I]root\f[R] privileges for running the commands in the
|
||||||
|
following example:
|
||||||
|
.IP
|
||||||
|
.nf
|
||||||
|
\f[C]
|
||||||
|
\[ti] # udevadm settle
|
||||||
|
\[ti] # udevadm control --stop-exec-queue
|
||||||
|
\[ti] # chreipl ...
|
||||||
|
\[ti] # udevadm control --start-exec-queue
|
||||||
|
\f[R]
|
||||||
|
.fi
|
||||||
|
.SS Listing messages with journalctl
|
||||||
|
.PP
|
||||||
|
If your Linux instance includes \f[B]journalctl\f[R], use the following
|
||||||
|
command to list all messages that are issued by
|
||||||
|
\f[B]chreipl-fcp-mpath\f[R]:
|
||||||
|
.IP
|
||||||
|
.nf
|
||||||
|
\f[C]
|
||||||
|
\[ti] # journalctl -t chreipl-fcp-mpath
|
||||||
|
\f[R]
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
To list only messages that were issued since the last IPL, use this
|
||||||
|
command:
|
||||||
|
.IP
|
||||||
|
.nf
|
||||||
|
\f[C]
|
||||||
|
\[ti] # journalctl -t chreipl-fcp-mpath -b
|
||||||
|
\f[R]
|
||||||
|
.fi
|
||||||
|
.SH REPORTING BUGS
|
||||||
|
.PP
|
||||||
|
Use the \f[B]Issues\f[R] functionality on GitHub to report any bugs in
|
||||||
|
\f[B]chreipl-fcp-mpath\f[R]: s390-tools
|
||||||
|
Issues (https://github.com/ibm-s390-linux/s390-tools/issues).
|
||||||
|
.SH SEE ALSO
|
||||||
|
.PP
|
||||||
|
\f[B]chreipl\f[R](8), \f[B]dracut\f[R](8), \f[B]journalctl\f[R](1),
|
||||||
|
\f[B]lsreipl(8)\f[R], \f[B]lszfcp\f[R](8), \f[B]multipath\f[R](8),
|
||||||
|
\f[B]multipathd\f[R](8), \f[B]udev\f[R](7), \f[B]udevadm\f[R](8),
|
||||||
|
\f[B]zipl\f[R](8)
|
||||||
+10
-10
@@ -5,7 +5,7 @@ COMMON_INCLUDED = true
|
|||||||
# The variable "DISTRELEASE" should be overwritten in rpm spec files with:
|
# The variable "DISTRELEASE" should be overwritten in rpm spec files with:
|
||||||
# "make DISTRELEASE=%{release}" and "make install DISTRELEASE=%{release}"
|
# "make DISTRELEASE=%{release}" and "make install DISTRELEASE=%{release}"
|
||||||
VERSION = 2
|
VERSION = 2
|
||||||
RELEASE = 20
|
RELEASE = 21
|
||||||
PATCHLEVEL = 0
|
PATCHLEVEL = 0
|
||||||
DISTRELEASE = build-$(shell date +%Y%m%d)
|
DISTRELEASE = build-$(shell date +%Y%m%d)
|
||||||
S390_TOOLS_RELEASE = $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)
|
S390_TOOLS_RELEASE = $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)
|
||||||
@@ -59,11 +59,8 @@ define cmd_define
|
|||||||
endef
|
endef
|
||||||
|
|
||||||
$(eval $(call cmd_define, AS," AS ",$(CROSS_COMPILE)as))
|
$(eval $(call cmd_define, AS," AS ",$(CROSS_COMPILE)as))
|
||||||
$(eval $(call cmd_define, LINK," LINK ",$(CROSS_COMPILE)gcc))
|
|
||||||
$(eval $(call cmd_define, LD," LD ",$(CROSS_COMPILE)ld))
|
|
||||||
$(eval $(call cmd_define, CC," CC ",$(CROSS_COMPILE)gcc))
|
$(eval $(call cmd_define, CC," CC ",$(CROSS_COMPILE)gcc))
|
||||||
$(eval $(call cmd_define, HOSTCC," HOSTCC ",gcc))
|
$(eval $(call cmd_define, HOSTCC," HOSTCC ",gcc))
|
||||||
$(eval $(call cmd_define, LINKXX," LINKXX ",$(CROSS_COMPILE)g++))
|
|
||||||
$(eval $(call cmd_define, CXX," CXX ",$(CROSS_COMPILE)g++))
|
$(eval $(call cmd_define, CXX," CXX ",$(CROSS_COMPILE)g++))
|
||||||
$(eval $(call cmd_define, CPP," CPP ",$(CROSS_COMPILE)gcc -E))
|
$(eval $(call cmd_define, CPP," CPP ",$(CROSS_COMPILE)gcc -E))
|
||||||
$(eval $(call cmd_define, AR," AR ",$(CROSS_COMPILE)ar))
|
$(eval $(call cmd_define, AR," AR ",$(CROSS_COMPILE)ar))
|
||||||
@@ -84,6 +81,8 @@ CHECKTOOL = $(call echocmd," CHECK ",/$@)$(CHECK_SILENT)
|
|||||||
SKIP = echo " SKIP $(call reldir) due to"
|
SKIP = echo " SKIP $(call reldir) due to"
|
||||||
|
|
||||||
INSTALL = install
|
INSTALL = install
|
||||||
|
LINK = $(CC)
|
||||||
|
LINKXX = $(CXX)
|
||||||
CP = cp
|
CP = cp
|
||||||
ifneq ("${V}","1")
|
ifneq ("${V}","1")
|
||||||
MAKEFLAGS += --quiet
|
MAKEFLAGS += --quiet
|
||||||
@@ -92,13 +91,12 @@ ifneq ("${V}","1")
|
|||||||
else
|
else
|
||||||
echocmd=
|
echocmd=
|
||||||
endif
|
endif
|
||||||
|
DEFAULT_CFLAGS = -g -rdynamic -fstack-protector-all -W -Wall -Wformat-security
|
||||||
ifeq ("${W}","1")
|
ifeq ("${W}","1")
|
||||||
DEFAULT_CFLAGS = -g -rdynamic -fstack-protector-all -W -Wall -Wformat-security -Wextra
|
DEFAULT_CFLAGS += -Wextra -Wshadow -Wundef -Wuninitialized -Wdouble-promotion -Wconversion
|
||||||
else
|
|
||||||
DEFAULT_CFLAGS = -g -rdynamic -fstack-protector-all -W -Wall -Wformat-security
|
|
||||||
endif
|
endif
|
||||||
ifeq ("${D}","1")
|
ifeq ("${D}","1")
|
||||||
DEFAULT_CFLAGS += -Og
|
DEFAULT_CFLAGS += -Og -g3 -ggdb3
|
||||||
else
|
else
|
||||||
DEFAULT_CFLAGS += -O3
|
DEFAULT_CFLAGS += -O3
|
||||||
endif
|
endif
|
||||||
@@ -252,11 +250,9 @@ export AS LD CC CPP AR NM STRIP OBJCOPY OBJDUMP INSTALL CFLAGS CXXFLAGS \
|
|||||||
|
|
||||||
ifneq ($(shell $(CC_SILENT) -dumpspecs 2>/dev/null | grep -e '[^f]no-pie'),)
|
ifneq ($(shell $(CC_SILENT) -dumpspecs 2>/dev/null | grep -e '[^f]no-pie'),)
|
||||||
NO_PIE_CFLAGS := -fno-pie
|
NO_PIE_CFLAGS := -fno-pie
|
||||||
NO_PIE_LINKFLAGS := -no-pie
|
|
||||||
NO_PIE_LDFLAGS := -no-pie
|
NO_PIE_LDFLAGS := -no-pie
|
||||||
else
|
else
|
||||||
NO_PIE_CFLAGS :=
|
NO_PIE_CFLAGS :=
|
||||||
NO_PIE_LINKFLAGS :=
|
|
||||||
NO_PIE_LDFLAGS :=
|
NO_PIE_LDFLAGS :=
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@@ -371,6 +367,10 @@ $(rootdir)/libvmcp/libvmcp.a: $(rootdir)/libvmcp
|
|||||||
$(MAKE) -C $(rootdir)/libvmcp/ libvmcp.a
|
$(MAKE) -C $(rootdir)/libvmcp/ libvmcp.a
|
||||||
.PHONY: $(rootdir)/libvmcp
|
.PHONY: $(rootdir)/libvmcp
|
||||||
|
|
||||||
|
$(rootdir)/libcpumf/libcpumf.a: $(rootdir)/libcpumf
|
||||||
|
$(MAKE) -C $(rootdir)/libcpumf/ libcpumf.a
|
||||||
|
.PHONY: $(rootdir)/libcpumf
|
||||||
|
|
||||||
$(rootdir)/libekmfweb/libekmfweb.so: $(rootdir)/libekmfweb
|
$(rootdir)/libekmfweb/libekmfweb.so: $(rootdir)/libekmfweb
|
||||||
$(MAKE) -C $(rootdir)/libekmfweb/ libekmfweb.so
|
$(MAKE) -C $(rootdir)/libekmfweb/ libekmfweb.so
|
||||||
.PHONY: $(rootdir)/libekmfweb
|
.PHONY: $(rootdir)/libekmfweb
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ MAN_FILES = lscpumf.1 chcpumf.8 lshwc.1
|
|||||||
|
|
||||||
all: $(BIN_FILES)
|
all: $(BIN_FILES)
|
||||||
|
|
||||||
libs = $(rootdir)/libutil/libutil.a
|
libs = $(rootdir)/libutil/libutil.a $(rootdir)/libcpumf/libcpumf.a
|
||||||
|
|
||||||
lscpumf: lscpumf.o $(libs)
|
lscpumf: lscpumf.o $(libs)
|
||||||
chcpumf: chcpumf.o $(libs)
|
chcpumf: chcpumf.o $(libs)
|
||||||
|
|||||||
+20
-39
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* chcpumf - Change CPU Measurement Facility Characteristics
|
* chcpumf - Change CPU Measurement Facility Characteristics
|
||||||
*
|
*
|
||||||
* Copyright IBM Corp. 2020
|
* Copyright IBM Corp. 2020, 2022
|
||||||
*
|
*
|
||||||
* s390-tools is free software; you can redistribute it and/or modify
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
@@ -20,9 +20,9 @@
|
|||||||
#include "lib/util_prg.h"
|
#include "lib/util_prg.h"
|
||||||
#include "lib/util_base.h"
|
#include "lib/util_base.h"
|
||||||
|
|
||||||
#include "defines.h"
|
#include "lib/libcpumf.h"
|
||||||
|
|
||||||
static int verbose;
|
static unsigned int verbose;
|
||||||
static unsigned long min_sdb, max_sdb;
|
static unsigned long min_sdb, max_sdb;
|
||||||
|
|
||||||
static struct util_opt opt_vec[] = {
|
static struct util_opt opt_vec[] = {
|
||||||
@@ -85,55 +85,30 @@ static long parse_buffersize(char *string)
|
|||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void read_sfb(unsigned long *min, unsigned long *max)
|
static int write_sfb(unsigned int min, unsigned int max)
|
||||||
{
|
|
||||||
unsigned long cur_min_sdb, cur_max_sdb;
|
|
||||||
FILE *fp;
|
|
||||||
|
|
||||||
if (geteuid())
|
|
||||||
errx(EXIT_FAILURE, "Must run as root");
|
|
||||||
fp = fopen(PERF_SFB_SIZE, "r");
|
|
||||||
if (!fp)
|
|
||||||
err(EXIT_FAILURE, PERF_SFB_SIZE);
|
|
||||||
if (fscanf(fp, "%ld,%ld", &cur_min_sdb, &cur_max_sdb) != 2) {
|
|
||||||
fclose(fp);
|
|
||||||
errx(EXIT_FAILURE, "Can not parse file " PERF_SFB_SIZE);
|
|
||||||
} else {
|
|
||||||
if (*min == 0)
|
|
||||||
*min = cur_min_sdb;
|
|
||||||
if (*max == 0)
|
|
||||||
*max = cur_max_sdb;
|
|
||||||
}
|
|
||||||
fclose(fp);
|
|
||||||
if (*min >= *max)
|
|
||||||
errx(EXIT_FAILURE,
|
|
||||||
"The specified maximum must be greater than the minimum");
|
|
||||||
}
|
|
||||||
|
|
||||||
static int write_sfb(unsigned long min, unsigned long max)
|
|
||||||
{
|
{
|
||||||
int rc = EXIT_SUCCESS;
|
int rc = EXIT_SUCCESS;
|
||||||
char text[64];
|
char text[64];
|
||||||
size_t len;
|
size_t len;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|
||||||
fp = fopen(PERF_SFB_SIZE, "w");
|
fp = fopen(S390_CPUMSF_BUFFERSZ, "w");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
err(EXIT_FAILURE, PERF_SFB_SIZE);
|
err(EXIT_FAILURE, S390_CPUMSF_BUFFERSZ);
|
||||||
snprintf(text, sizeof text, "%ld,%ld", min, max);
|
snprintf(text, sizeof(text), "%u,%u", min, max);
|
||||||
len = strlen(text) + 1;
|
len = strlen(text) + 1;
|
||||||
if (fwrite(text, 1, len, fp) != len) {
|
if (fwrite(text, 1, len, fp) != len) {
|
||||||
warn(PERF_SFB_SIZE);
|
warn(S390_CPUMSF_BUFFERSZ);
|
||||||
rc = EXIT_FAILURE;
|
rc = EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
if (fclose(fp)) {
|
if (fclose(fp)) {
|
||||||
warn(PERF_SFB_SIZE);
|
warn(S390_CPUMSF_BUFFERSZ);
|
||||||
rc = EXIT_FAILURE;
|
rc = EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
if (verbose && rc != EXIT_FAILURE)
|
if (verbose && rc != EXIT_FAILURE)
|
||||||
warnx("Sampling buffer sizes:\n"
|
warnx("Sampling buffer sizes:\n"
|
||||||
" Minimum:%7ld sample-data-blocks\n"
|
" Minimum:%7d sample-data-blocks\n"
|
||||||
" Maximum:%7ld sample-data-blocks\n",
|
" Maximum:%7d sample-data-blocks\n",
|
||||||
min, max);
|
min, max);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -183,15 +158,21 @@ static int parse_args(int argc, char **argv)
|
|||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
struct stat sbuf;
|
unsigned long my_min, my_max;
|
||||||
|
|
||||||
util_prg_init(&prg);
|
util_prg_init(&prg);
|
||||||
util_opt_init(opt_vec, NULL);
|
util_opt_init(opt_vec, NULL);
|
||||||
|
|
||||||
parse_args(argc, argv);
|
parse_args(argc, argv);
|
||||||
if (stat(PERF_PATH PERF_SF, &sbuf))
|
if (geteuid())
|
||||||
|
errx(EXIT_FAILURE, "Must run as root");
|
||||||
|
if (!libcpumf_have_sfb())
|
||||||
errx(EXIT_FAILURE,
|
errx(EXIT_FAILURE,
|
||||||
"No CPU-measurement sampling facility detected");
|
"No CPU-measurement sampling facility detected");
|
||||||
read_sfb(&min_sdb, &max_sdb);
|
libcpumf_sfb_info(&my_min, &my_max);
|
||||||
|
if (!min_sdb)
|
||||||
|
min_sdb = my_min;
|
||||||
|
if (!max_sdb)
|
||||||
|
max_sdb = my_max;
|
||||||
return write_sfb(min_sdb, max_sdb);
|
return write_sfb(min_sdb, max_sdb);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
/*
|
|
||||||
* Defines for CPU Measurement Facility Characteristics
|
|
||||||
*
|
|
||||||
* Copyright IBM Corp. 2020
|
|
||||||
*
|
|
||||||
* 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 DEFINES_H
|
|
||||||
#define DEFINES_H
|
|
||||||
|
|
||||||
#define PERF_SFB_SIZE "/sys/module/kernel/parameters/cpum_sfb_size"
|
|
||||||
#define PERF_PATH "/sys/bus/event_source/devices/"
|
|
||||||
#define PERF_SF "cpum_sf"
|
|
||||||
#define PERF_CF "cpum_cf"
|
|
||||||
|
|
||||||
#endif
|
|
||||||
+49
-146
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* lscpumf - Show CPU Measurement Facility Characteristics
|
* lscpumf - Show CPU Measurement Facility Characteristics
|
||||||
*
|
*
|
||||||
* Copyright IBM Corp. 2020
|
* Copyright IBM Corp. 2020, 2022
|
||||||
*
|
*
|
||||||
* s390-tools is free software; you can redistribute it and/or modify
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
#include "lib/util_opt.h"
|
#include "lib/util_opt.h"
|
||||||
#include "lib/util_prg.h"
|
#include "lib/util_prg.h"
|
||||||
|
|
||||||
#include "defines.h"
|
#include "lib/libcpumf.h"
|
||||||
|
|
||||||
#define ACTION_NONE 0
|
#define ACTION_NONE 0
|
||||||
#define ACTION_INFO 1
|
#define ACTION_INFO 1
|
||||||
@@ -45,9 +45,6 @@ static bool actions[ACTION_SAMPLE + 1]; /* Specified command line options */
|
|||||||
#define PER_SDBT_SIZE 511
|
#define PER_SDBT_SIZE 511
|
||||||
|
|
||||||
/* File names to read data from */
|
/* File names to read data from */
|
||||||
#define SERVICELEVEL "/proc/service_levels"
|
|
||||||
#define CPUMF_CF_TYPE "/sys/devices/cpum_cf/type"
|
|
||||||
#define CPUMF_SF_TYPE "/sys/devices/cpum_sf/type"
|
|
||||||
|
|
||||||
static struct util_opt opt_vec[] = {
|
static struct util_opt opt_vec[] = {
|
||||||
UTIL_OPT_SECTION("OPTIONS"),
|
UTIL_OPT_SECTION("OPTIONS"),
|
||||||
@@ -92,19 +89,18 @@ static char prefix[32]; /* Counter prefix */
|
|||||||
static bool show_names;
|
static bool show_names;
|
||||||
|
|
||||||
static struct cpumf_info {
|
static struct cpumf_info {
|
||||||
unsigned int first_vn; /* Counter facility first version nr */
|
int first_vn; /* Counter facility first version nr */
|
||||||
unsigned int second_vn; /* Counter facility second version nr */
|
int second_vn; /* Counter facility second version nr */
|
||||||
unsigned int authorization; /* Counter facility authorization */
|
int authorization; /* Counter facility authorization */
|
||||||
float version;
|
|
||||||
unsigned long min_rate; /* Minimum sampling rate */
|
unsigned long min_rate; /* Minimum sampling rate */
|
||||||
unsigned long max_rate; /* Maximum sampling rate */
|
unsigned long max_rate; /* Maximum sampling rate */
|
||||||
unsigned long cpu_speed; /* CPU Cycles per micro second */
|
unsigned long cpu_speed; /* CPU Cycles per micro second */
|
||||||
unsigned int basic_sample_sz; /* # of Bytes per basic sample */
|
int basic_sample_sz; /* # of Bytes per basic sample */
|
||||||
unsigned int diag_sample_sz; /* # of bytes per diagnostic sample */
|
int diag_sample_sz; /* # of bytes per diagnostic sample */
|
||||||
unsigned char have_counter; /* CPUM counter facility detected */
|
bool have_counter; /* CPUM counter facility detected */
|
||||||
unsigned char have_samples; /* CPUM sampling facility detected */
|
bool have_samples; /* CPUM sampling facility detected */
|
||||||
unsigned int min_sfb; /* Minimum sampling buffer size */
|
unsigned long min_sfb; /* Minimum sampling buffer size */
|
||||||
unsigned int max_sfb; /* Maximum sampling buffer size */
|
unsigned long max_sfb; /* Maximum sampling buffer size */
|
||||||
unsigned short machine_type; /* Machine Type */
|
unsigned short machine_type; /* Machine Type */
|
||||||
} cpumf;
|
} cpumf;
|
||||||
|
|
||||||
@@ -2565,26 +2561,12 @@ static struct counters cpumcf_z15_counters[] = {
|
|||||||
* If perf_pmu_register() kernel function assigned any other (higher) type
|
* If perf_pmu_register() kernel function assigned any other (higher) type
|
||||||
* number, set the prefix to <type-nr>:
|
* number, set the prefix to <type-nr>:
|
||||||
*/
|
*/
|
||||||
static int read_cpumf_type(const char *filename, const char *type)
|
static void set_prefix(int nr)
|
||||||
{
|
{
|
||||||
int nr, rc = EXIT_FAILURE;
|
if (nr == PERF_TYPE_RAW)
|
||||||
FILE *fp = fopen(filename, "r");
|
strcat(prefix, "r");
|
||||||
|
else
|
||||||
if (fp == NULL) {
|
snprintf(prefix, sizeof(prefix), "%d:", nr);
|
||||||
warnx("No CPU-measurement %s facility detected", type);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
if (fscanf(fp, "%d", &nr) != 1) {
|
|
||||||
warnx("Can not parse file %s", filename);
|
|
||||||
} else {
|
|
||||||
rc = EXIT_SUCCESS;
|
|
||||||
if (nr == PERF_TYPE_RAW)
|
|
||||||
strcat(prefix, "r");
|
|
||||||
else
|
|
||||||
snprintf(prefix, sizeof prefix, "%d:", nr);
|
|
||||||
}
|
|
||||||
fclose(fp);
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse tool parameters. In case of --help or --version, print
|
/* Parse tool parameters. In case of --help or --version, print
|
||||||
@@ -2661,8 +2643,6 @@ static unsigned long div_ceil(unsigned long a, unsigned long b)
|
|||||||
|
|
||||||
static void show_info(struct cpumf_info *p, int details)
|
static void show_info(struct cpumf_info *p, int details)
|
||||||
{
|
{
|
||||||
struct stat sbuf;
|
|
||||||
|
|
||||||
if (!p->have_counter && !p->have_samples) {
|
if (!p->have_counter && !p->have_samples) {
|
||||||
warnx("No CPU-measurement facilities detected");
|
warnx("No CPU-measurement facilities detected");
|
||||||
return;
|
return;
|
||||||
@@ -2672,7 +2652,7 @@ static void show_info(struct cpumf_info *p, int details)
|
|||||||
if (details) {
|
if (details) {
|
||||||
printf("----------------------------------------------"
|
printf("----------------------------------------------"
|
||||||
"----------------------------\n");
|
"----------------------------\n");
|
||||||
printf("Version: %3.1f\n\n", p->version);
|
printf("Version: %d.%d\n\n", p->first_vn, p->second_vn);
|
||||||
printf("Authorized counter sets:\n");
|
printf("Authorized counter sets:\n");
|
||||||
if (!p->authorization)
|
if (!p->authorization)
|
||||||
printf(" None\n");
|
printf(" None\n");
|
||||||
@@ -2689,8 +2669,7 @@ static void show_info(struct cpumf_info *p, int details)
|
|||||||
if (0x8000 & p->authorization)
|
if (0x8000 & p->authorization)
|
||||||
printf(" Coprocessor Group counter Set\n");
|
printf(" Coprocessor Group counter Set\n");
|
||||||
printf("\nLinux perf event support: %s\n\n",
|
printf("\nLinux perf event support: %s\n\n",
|
||||||
(stat(PERF_PATH PERF_CF, &sbuf)) ? "No" :
|
!p->have_counter ? "No" : "Yes (PMU: cpum_cf)");
|
||||||
"Yes (PMU: " PERF_CF ")");
|
|
||||||
|
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
@@ -2718,19 +2697,18 @@ static void show_info(struct cpumf_info *p, int details)
|
|||||||
p->diag_sample_sz);
|
p->diag_sample_sz);
|
||||||
|
|
||||||
printf("\nLinux perf event support: %s\n\n",
|
printf("\nLinux perf event support: %s\n\n",
|
||||||
(stat(PERF_PATH PERF_SF, &sbuf)) ? "No" :
|
!p->have_samples ? "No" : "Yes (PMU: cpum_sf)");
|
||||||
"Yes (PMU: " PERF_SF ")");
|
|
||||||
|
|
||||||
printf("Current sampling buffer settings for %s:\n",
|
printf("Current sampling buffer settings for"
|
||||||
PERF_SF);
|
" cpum_sf:\n");
|
||||||
printf(" Basic-sampling mode\n");
|
printf(" Basic-sampling mode\n");
|
||||||
total = p->min_sfb + div_ceil(p->min_sfb, PER_SDBT_SIZE);
|
total = p->min_sfb + div_ceil(p->min_sfb, PER_SDBT_SIZE);
|
||||||
human(text, sizeof text, PAGE_SIZE * total);
|
human(text, sizeof(text), PAGE_SIZE * total);
|
||||||
printf(" Minimum: %6d"
|
printf(" Minimum: %6ld"
|
||||||
" sample-data-blocks (%6s)\n", p->min_sfb, text);
|
" sample-data-blocks (%6s)\n", p->min_sfb, text);
|
||||||
total = p->max_sfb + div_ceil(p->max_sfb, PER_SDBT_SIZE);
|
total = p->max_sfb + div_ceil(p->max_sfb, PER_SDBT_SIZE);
|
||||||
human(text, sizeof text, PAGE_SIZE * total);
|
human(text, sizeof(text), PAGE_SIZE * total);
|
||||||
printf(" Maximum: %6d"
|
printf(" Maximum: %6ld"
|
||||||
" sample-data-blocks (%6s)\n\n", p->max_sfb,
|
" sample-data-blocks (%6s)\n\n", p->max_sfb,
|
||||||
text);
|
text);
|
||||||
|
|
||||||
@@ -2739,13 +2717,13 @@ static void show_info(struct cpumf_info *p, int details)
|
|||||||
fdiag = div_ceil(p->diag_sample_sz, p->basic_sample_sz);
|
fdiag = div_ceil(p->diag_sample_sz, p->basic_sample_sz);
|
||||||
total = fdiag * p->min_sfb
|
total = fdiag * p->min_sfb
|
||||||
+ div_ceil(p->min_sfb, PER_SDBT_SIZE);
|
+ div_ceil(p->min_sfb, PER_SDBT_SIZE);
|
||||||
human(text, sizeof text, PAGE_SIZE * total);
|
human(text, sizeof(text), PAGE_SIZE * total);
|
||||||
printf(" Minimum: %6ld"
|
printf(" Minimum: %6ld"
|
||||||
" sample-data-blocks (%6s)\n",
|
" sample-data-blocks (%6s)\n",
|
||||||
fdiag * p->min_sfb, text);
|
fdiag * p->min_sfb, text);
|
||||||
total = fdiag * p->max_sfb
|
total = fdiag * p->max_sfb
|
||||||
+ div_ceil(p->max_sfb * fdiag, PER_SDBT_SIZE);
|
+ div_ceil(p->max_sfb * fdiag, PER_SDBT_SIZE);
|
||||||
human(text, sizeof text, PAGE_SIZE * total);
|
human(text, sizeof(text), PAGE_SIZE * total);
|
||||||
printf(" Maximum: %6ld"
|
printf(" Maximum: %6ld"
|
||||||
" sample-data-blocks (%6s)\n", fdiag * p->max_sfb,
|
" sample-data-blocks (%6s)\n", fdiag * p->max_sfb,
|
||||||
text);
|
text);
|
||||||
@@ -2755,27 +2733,6 @@ static void show_info(struct cpumf_info *p, int details)
|
|||||||
warnx("No CPU-measurement sampling facility detected");
|
warnx("No CPU-measurement sampling facility detected");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read CPU Measurement sampling facility device driver minimum and maximum
|
|
||||||
* buffer size
|
|
||||||
*/
|
|
||||||
static int read_sfb(struct cpumf_info *p)
|
|
||||||
{
|
|
||||||
int rc = EXIT_SUCCESS;
|
|
||||||
FILE *fp;
|
|
||||||
|
|
||||||
fp = fopen(PERF_SFB_SIZE, "r");
|
|
||||||
if (!fp) {
|
|
||||||
warn(PERF_SFB_SIZE);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
if (fscanf(fp, "%d,%d", &p->min_sfb, &p->max_sfb) != 2) {
|
|
||||||
warnx("Can not parse %s", PERF_SFB_SIZE);
|
|
||||||
rc = EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
fclose(fp);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set the counter name for z15 counter numbered 265. It is either named
|
/* Set the counter name for z15 counter numbered 265. It is either named
|
||||||
* DFLT_CCERROR or DFLT_CCFINISH, depending on the linux version. The
|
* DFLT_CCERROR or DFLT_CCFINISH, depending on the linux version. The
|
||||||
* counter was renamed from CCERROR to CCFINISH in linux version 5.8.
|
* counter was renamed from CCERROR to CCFINISH in linux version 5.8.
|
||||||
@@ -2803,81 +2760,23 @@ static void read_ccerror(struct counters *cp, size_t cp_cnt)
|
|||||||
/* Read allnecessary information from /sysfs file /proc/service_levels */
|
/* Read allnecessary information from /sysfs file /proc/service_levels */
|
||||||
static int read_info(void)
|
static int read_info(void)
|
||||||
{
|
{
|
||||||
char *linep = NULL;
|
int rc = EXIT_FAILURE;
|
||||||
size_t line_sz;
|
|
||||||
ssize_t nbytes;
|
|
||||||
FILE *slp;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
memset(&cpumf, 0, sizeof cpumf);
|
cpumf.have_counter = libcpumf_cpumcf_info(&cpumf.first_vn,
|
||||||
slp = fopen(SERVICELEVEL, "r");
|
&cpumf.second_vn,
|
||||||
if (!slp) {
|
&cpumf.authorization);
|
||||||
warn(SERVICELEVEL);
|
cpumf.have_samples = libcpumf_cpumsf_info(&cpumf.min_rate,
|
||||||
return EXIT_FAILURE;
|
&cpumf.max_rate,
|
||||||
}
|
&cpumf.cpu_speed,
|
||||||
|
&cpumf.basic_sample_sz,
|
||||||
while ((nbytes = getline(&linep, &line_sz, slp)) != EOF) {
|
&cpumf.diag_sample_sz);
|
||||||
if (!strncmp(linep, "CPU-MF: Counter facility:", 25)) {
|
if (cpumf.have_samples)
|
||||||
rc = sscanf(linep, "CPU-MF: Counter facility:"
|
libcpumf_sfb_info(&cpumf.min_sfb, &cpumf.max_sfb);
|
||||||
" version=%f authorization=%x",
|
|
||||||
&cpumf.version, &cpumf.authorization);
|
|
||||||
if (rc != 2) {
|
|
||||||
warnx("Can not parse line %s", linep);
|
|
||||||
rc = EXIT_FAILURE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
cpumf.have_counter = 1;
|
|
||||||
cpumf.first_vn = (int)cpumf.version;
|
|
||||||
cpumf.second_vn = ((int)(10 * cpumf.version) % 10);
|
|
||||||
}
|
|
||||||
if (!strncmp(linep, "CPU-MF: Sampling facility: min", 30)) {
|
|
||||||
rc = sscanf(linep, "CPU-MF: Sampling facility:"
|
|
||||||
" min_rate=%ld max_rate=%ld cpu_speed=%ld",
|
|
||||||
&cpumf.min_rate, &cpumf.max_rate,
|
|
||||||
&cpumf.cpu_speed);
|
|
||||||
if (rc != 3) {
|
|
||||||
warnx("Can not parse line %s", linep);
|
|
||||||
rc = EXIT_FAILURE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
cpumf.have_samples = 1;
|
|
||||||
}
|
|
||||||
if (!strncmp(linep, "CPU-MF: Sampling facility: mode=basic", 37)) {
|
|
||||||
rc = sscanf(linep, "CPU-MF: Sampling facility:"
|
|
||||||
" mode=basic sample_size=%u",
|
|
||||||
&cpumf.basic_sample_sz);
|
|
||||||
if (rc != 1) {
|
|
||||||
warnx("Can not parse line %s", linep);
|
|
||||||
rc = EXIT_FAILURE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!strncmp(linep, "CPU-MF: Sampling facility: mode=diag", 36)) {
|
|
||||||
rc = sscanf(linep, "CPU-MF: Sampling facility:"
|
|
||||||
" mode=diagnostic sample_size=%u",
|
|
||||||
&cpumf.diag_sample_sz);
|
|
||||||
if (rc != 1) {
|
|
||||||
warnx("Can not parse line %s", linep);
|
|
||||||
rc = EXIT_FAILURE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (cpumf.have_samples) {
|
|
||||||
rc = read_sfb(&cpumf);
|
|
||||||
if (rc == EXIT_FAILURE)
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
cpumf.machine_type = util_arch_machine_type();
|
cpumf.machine_type = util_arch_machine_type();
|
||||||
if (cpumf.machine_type == UTIL_ARCH_MACHINE_TYPE_UNKNOWN) {
|
if (cpumf.machine_type == UTIL_ARCH_MACHINE_TYPE_UNKNOWN)
|
||||||
rc = EXIT_FAILURE;
|
rc = EXIT_FAILURE;
|
||||||
goto out;
|
else
|
||||||
}
|
rc = EXIT_SUCCESS;
|
||||||
rc = EXIT_SUCCESS;
|
|
||||||
out:
|
|
||||||
fclose(slp);
|
|
||||||
free(linep);
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3051,14 +2950,18 @@ int main(int argc, char **argv)
|
|||||||
case ACTION_CNT:
|
case ACTION_CNT:
|
||||||
case ACTION_CNTALL:
|
case ACTION_CNTALL:
|
||||||
all = ret == ACTION_CNTALL;
|
all = ret == ACTION_CNTALL;
|
||||||
ret = read_cpumf_type(CPUMF_CF_TYPE, "counter");
|
ret = libcpumf_pmutype(S390_CPUMF_CF);
|
||||||
if (ret == EXIT_SUCCESS)
|
if (ret >= EXIT_SUCCESS) {
|
||||||
|
set_prefix(ret);
|
||||||
show_counter(all);
|
show_counter(all);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ACTION_SAMPLE:
|
case ACTION_SAMPLE:
|
||||||
ret = read_cpumf_type(CPUMF_SF_TYPE, "sampling");
|
ret = libcpumf_pmutype(S390_CPUMF_SF);
|
||||||
if (ret == EXIT_SUCCESS)
|
if (ret >= EXIT_SUCCESS) {
|
||||||
|
set_prefix(ret);
|
||||||
show_sample();
|
show_sample();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ACTION_NONE:
|
case ACTION_NONE:
|
||||||
case ACTION_INFO:
|
case ACTION_INFO:
|
||||||
|
|||||||
+32
-80
@@ -38,17 +38,18 @@
|
|||||||
#include "lib/util_path.h"
|
#include "lib/util_path.h"
|
||||||
#include "lib/util_scandir.h"
|
#include "lib/util_scandir.h"
|
||||||
#include "lib/util_libc.h"
|
#include "lib/util_libc.h"
|
||||||
|
#include "lib/libcpumf.h"
|
||||||
|
|
||||||
#include "lshwc.h"
|
#include "lshwc.h"
|
||||||
|
|
||||||
#define SERVICELEVEL "/proc/service_levels"
|
|
||||||
#define CPUS_ONLINE "/sys/devices/system/cpu/online"
|
#define CPUS_ONLINE "/sys/devices/system/cpu/online"
|
||||||
#define CPUS_POSSIBLE "/sys/devices/system/cpu/possible"
|
#define CPUS_POSSIBLE "/sys/devices/system/cpu/possible"
|
||||||
#define CPUS_KERNELMAX "/sys/devices/system/cpu/kernel_max"
|
#define CPUS_KERNELMAX "/sys/devices/system/cpu/kernel_max"
|
||||||
#define MAXCTRS 512
|
#define MAXCTRS 512
|
||||||
#define IOCTLSLEEP 60U
|
#define IOCTLSLEEP 60U
|
||||||
|
|
||||||
static unsigned int read_interval = IOCTLSLEEP, cfvn, csvn, authorization;
|
static unsigned int read_interval = IOCTLSLEEP;
|
||||||
|
static int cfvn, csvn, authorization;
|
||||||
static unsigned long loop_count = 1;
|
static unsigned long loop_count = 1;
|
||||||
static unsigned char *ioctlbuffer;
|
static unsigned char *ioctlbuffer;
|
||||||
static bool allcpu;
|
static bool allcpu;
|
||||||
@@ -151,20 +152,6 @@ static unsigned long getnumber(char *word, char stopchar)
|
|||||||
return no;
|
return no;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove all whitespace from string. */
|
|
||||||
static void kill_whitespace(char *s)
|
|
||||||
{
|
|
||||||
char *cp = s;
|
|
||||||
|
|
||||||
for (; *s != '\0'; ++s) {
|
|
||||||
if (isspace(*s))
|
|
||||||
continue;
|
|
||||||
if (isprint(*s))
|
|
||||||
*cp++ = *s;
|
|
||||||
}
|
|
||||||
*cp = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read file to get all online CPUs */
|
/* Read file to get all online CPUs */
|
||||||
static bool get_cpus(char *file, char *buf, size_t bufsz)
|
static bool get_cpus(char *file, char *buf, size_t bufsz)
|
||||||
{
|
{
|
||||||
@@ -242,29 +229,34 @@ static char *show_ctrset(unsigned long set)
|
|||||||
static void parse_cpulist(char *parm, struct s390_hwctr_start *start)
|
static void parse_cpulist(char *parm, struct s390_hwctr_start *start)
|
||||||
{
|
{
|
||||||
uint64_t *words = start->cpumask;
|
uint64_t *words = start->cpumask;
|
||||||
unsigned long i, no_a, no_b;
|
unsigned int i, no_a, no_b;
|
||||||
char *cp, *tokens[16]; /* Used to parse command line params */
|
cpu_set_t cpulist;
|
||||||
char cpubuf[256];
|
int rc;
|
||||||
|
|
||||||
|
CPU_ZERO(&cpulist);
|
||||||
start->data_bytes = 0;
|
start->data_bytes = 0;
|
||||||
if (parm)
|
start->counter_sets = S390_HWCTR_ALL; /* Default all counter sets */
|
||||||
kill_whitespace(parm);
|
|
||||||
if (!parm || *parm == ':') {
|
if (parm) { /* CPU list with optional counter set */
|
||||||
/* No CPU list or just counter sets */
|
char *cp = strchr(parm, ':');
|
||||||
if (!get_cpus(CPUS_ONLINE, cpubuf, sizeof(cpubuf)))
|
|
||||||
exit(EXIT_FAILURE);
|
if (cp) { /* Handle counter set */
|
||||||
if (parm)
|
*cp = '\0';
|
||||||
strcat(cpubuf, parm);
|
start->counter_sets = parse_ctrset(++cp);
|
||||||
parm = cpubuf;
|
}
|
||||||
|
|
||||||
|
if (strlen(parm) > 0) /* Handle CPU list */
|
||||||
|
rc = libcpumf_cpuset(parm, &cpulist);
|
||||||
|
else
|
||||||
|
rc = libcpumf_cpuset_fn(S390_CPUS_ONLINE, &cpulist);
|
||||||
|
if (rc)
|
||||||
|
errx(EXIT_FAILURE, "Cannot use CPU list %s", parm);
|
||||||
|
} else { /* No CPU list and no counter sets */
|
||||||
|
rc = libcpumf_cpuset_fn(S390_CPUS_ONLINE, &cpulist);
|
||||||
|
if (rc)
|
||||||
|
err(EXIT_FAILURE, "Cannot read file " S390_CPUS_ONLINE);
|
||||||
}
|
}
|
||||||
|
|
||||||
cp = strchr(parm, ':');
|
|
||||||
if (cp) { /* Handle counter set */
|
|
||||||
*cp = '\0';
|
|
||||||
start->counter_sets = parse_ctrset(++cp);
|
|
||||||
} else {
|
|
||||||
start->counter_sets = S390_HWCTR_ALL;
|
|
||||||
}
|
|
||||||
/* Check with authorized counter sets */
|
/* Check with authorized counter sets */
|
||||||
if ((start->counter_sets & authorization) != start->counter_sets) {
|
if ((start->counter_sets & authorization) != start->counter_sets) {
|
||||||
unsigned int noton = ~(start->counter_sets & authorization);
|
unsigned int noton = ~(start->counter_sets & authorization);
|
||||||
@@ -276,19 +268,10 @@ static void parse_cpulist(char *parm, struct s390_hwctr_start *start)
|
|||||||
show_ctrset(noton));
|
show_ctrset(noton));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(tokens) && (tokens[i] = strtok(parm, ","));
|
for (rc = 0; rc < CPU_SETSIZE; ++rc)
|
||||||
++i, parm = NULL) {
|
if (CPU_ISSET(rc, &cpulist))
|
||||||
cp = strchr(tokens[i], '-'); /* Range character? */
|
if (!check_set(rc, rc, start->counter_sets))
|
||||||
if (cp) {
|
errx(EXIT_FAILURE, "Invalid CPU %d", rc);
|
||||||
no_a = getnumber(tokens[i], *cp);
|
|
||||||
no_b = getnumber(++cp, '\0');
|
|
||||||
} else {
|
|
||||||
no_b = getnumber(tokens[i], '\0');
|
|
||||||
no_a = no_b;
|
|
||||||
}
|
|
||||||
if (!check_set(no_a, no_b, start->counter_sets))
|
|
||||||
errx(EXIT_FAILURE, "Invalid CPU list %s", tokens[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Convert the CPU list to a bitmask for kernel cpumask_t */
|
/* Convert the CPU list to a bitmask for kernel cpumask_t */
|
||||||
for (i = 0, no_b = 0; i < max_possible_cpus; ++i) {
|
for (i = 0, no_b = 0; i < max_possible_cpus; ++i) {
|
||||||
@@ -632,37 +615,6 @@ static int do_it(char *s)
|
|||||||
return rc ? EXIT_FAILURE : EXIT_SUCCESS;
|
return rc ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read counter first and second version number */
|
|
||||||
static bool get_cvn(void)
|
|
||||||
{
|
|
||||||
char *linep = NULL;
|
|
||||||
bool good = false;
|
|
||||||
size_t line_sz;
|
|
||||||
ssize_t nbytes;
|
|
||||||
FILE *slp;
|
|
||||||
|
|
||||||
slp = fopen(SERVICELEVEL, "r");
|
|
||||||
if (!slp) {
|
|
||||||
warn(SERVICELEVEL);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
while ((nbytes = getline(&linep, &line_sz, slp)) != EOF) {
|
|
||||||
if (!strncmp(linep, "CPU-MF: Counter facility:", 25)) {
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
rc = sscanf(linep, "CPU-MF: Counter facility: version=%d.%d authorization=%x",
|
|
||||||
&cfvn, &csvn, &authorization);
|
|
||||||
good = rc == 3;
|
|
||||||
if (!good)
|
|
||||||
warnx("Cannot parse line %s", linep);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fclose(slp);
|
|
||||||
free(linep);
|
|
||||||
return good;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct util_opt opt_vec[] = {
|
static struct util_opt opt_vec[] = {
|
||||||
UTIL_OPT_SECTION("OPTIONS"),
|
UTIL_OPT_SECTION("OPTIONS"),
|
||||||
{
|
{
|
||||||
@@ -746,7 +698,7 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
have_support();
|
have_support();
|
||||||
if (!get_cvn())
|
if (!libcpumf_cpumcf_info(&cfvn, &csvn, &authorization))
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
if (!check_setpossible())
|
if (!check_setpossible())
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
|||||||
+3
-1
@@ -408,8 +408,10 @@ static int read_line(void)
|
|||||||
{
|
{
|
||||||
bzero(line_buffer, LINE_LENGTH);
|
bzero(line_buffer, LINE_LENGTH);
|
||||||
line_ptr = line_buffer;
|
line_ptr = line_buffer;
|
||||||
if (!fgets(line_buffer, LINE_LENGTH, stdin))
|
if (!fgets(line_buffer, LINE_LENGTH, stdin)) {
|
||||||
|
clearerr(stdin);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
while (*line_ptr && !isgraph(*line_ptr))
|
while (*line_ptr && !isgraph(*line_ptr))
|
||||||
line_ptr++;
|
line_ptr++;
|
||||||
|
|
||||||
|
|||||||
@@ -74,9 +74,9 @@ stage3b_reloc.elf:
|
|||||||
|
|
||||||
%.elf: %.o
|
%.elf: %.o
|
||||||
case $* in \
|
case $* in \
|
||||||
stage3a) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-T,stage3a.lds";; \
|
stage3a) SFLAGS="$(NO_PIE_LDFLAGS) -nostdlib -Wl,-T,stage3a.lds";; \
|
||||||
stage3b) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-T,stage3b.lds";; \
|
stage3b) SFLAGS="$(NO_PIE_LDFLAGS) -nostdlib -Wl,-T,stage3b.lds";; \
|
||||||
stage3b_reloc) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-estage3b_reloc_start,-Ttext,0";; \
|
stage3b_reloc) SFLAGS="$(NO_PIE_LDFLAGS) -nostdlib -Wl,-estage3b_reloc_start,-Ttext,0";; \
|
||||||
esac; \
|
esac; \
|
||||||
$(LINK) $$SFLAGS -m64 $(filter %.o, $^) -o $@
|
$(LINK) $$SFLAGS -m64 $(filter %.o, $^) -o $@
|
||||||
@chmod a-x $@
|
@chmod a-x $@
|
||||||
|
|||||||
+28
-14
@@ -87,13 +87,23 @@ CRLs. Optional.
|
|||||||
.TP
|
.TP
|
||||||
\fB\-\-root\-ca\fR=\fI\,FILE\/\fR
|
\fB\-\-root\-ca\fR=\fI\,FILE\/\fR
|
||||||
Specifies the root CA certificate for the verification. If omitted,
|
Specifies the root CA certificate for the verification. If omitted,
|
||||||
the DigiCert root CA certificate installed on the system is used. Use
|
the system wide root CAs installed on the system is used. Use
|
||||||
this only if you trust the specified certificate. Optional.
|
this only if you trust the specified certificate. Optional.
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-no-verify\fR
|
\fB\-\-no-verify\fR
|
||||||
Do not require the host-key documents to be valid. For testing
|
Do not require the host-key documents to be valid. For testing
|
||||||
purposes, do not use for a production image. Optional.
|
purposes, do not use for a production image. Optional.
|
||||||
.TP
|
.TP
|
||||||
|
\fB\-\-comm\-key\fR=\fI\,FILE\/\fR
|
||||||
|
Specifies the encryption key you want to use for the PV guest dump. Use a
|
||||||
|
secure, random, plaintext AES-256 GCM key. Optional.
|
||||||
|
.TP
|
||||||
|
\fB\-\-enable\-dump\fR
|
||||||
|
Enable PV guest dumps. Requires the \fB\-\-comm-key\fR option. Optional.
|
||||||
|
.TP
|
||||||
|
\fB\-\-disable\-dump\fR
|
||||||
|
Disable PV guest dumps. This is the default. Optional.
|
||||||
|
.TP
|
||||||
\fB\-\-enable\-pckmo\fR
|
\fB\-\-enable\-pckmo\fR
|
||||||
Enable the support for the DEA, TDEA, AES, and ECC PCKMO key encryption
|
Enable the support for the DEA, TDEA, AES, and ECC PCKMO key encryption
|
||||||
functions. This is the default. Optional.
|
functions. This is the default. Optional.
|
||||||
@@ -105,21 +115,25 @@ functions. Optional.
|
|||||||
\fB\-v\fR, \fB\-\-version\fR
|
\fB\-v\fR, \fB\-\-version\fR
|
||||||
Prints version information, then exits.
|
Prints version information, then exits.
|
||||||
|
|
||||||
.SH EXAMPLE
|
.SH EXAMPLES
|
||||||
|
|
||||||
|
These are examples to generate a protected virtualization image in
|
||||||
|
\fI\,/boot/vmlinuz.pv\/\fR, using the kernel file \fI\,vmlinuz\/\fR, the
|
||||||
|
initrd in \fI\,initramfs\/\fR, the kernel parameters contained in
|
||||||
|
\fI\,parmfile\/\fR, the intermediate CA in \fI\,DigiCertCA.crt\/\fR, the
|
||||||
|
IBM Z signing key in \fI\,ibm-z-host-key-signing.crt\/\fR, and the
|
||||||
|
host-key document in \fI\,host_key.crt\/\fR. An AES-256 GCM key is stored in
|
||||||
|
\fI\,comm-key\/\fR, which is used for the PV guest dump support in the second
|
||||||
|
example.
|
||||||
|
|
||||||
|
Generate a protected virtualization image:
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
Generate a protected virtualization image in
|
.B genprotimg \-i \fI\,vmlinuz\/\fR \-r \fI\,initramfs\/\fR \-p \fI\,parmfile\/\fR \-k \fI\,host_key.crt\/\fR \-C \fI\,ibm-z-host-key-signing.crt\/\fR \-C \fI\,DigiCertCA.crt\fR \-o \fI\,/boot/vmlinuz.pv\/\fR
|
||||||
\fI\,/boot/vmlinuz.pv\/\fR, using the kernel file \fI\,vmlinuz\/\fR,
|
|
||||||
the initrd in \fI\,initramfs\/\fR, the kernel parameters contained in
|
Generate a protected virtualization image with PV guest dump support:
|
||||||
\fI\,parmfile\/\fR, the intermediate CA in \fI\,DigiCertCA.crt\/\fR,
|
|
||||||
the IBM Z signing key in \fI\,ibm-z-host-key-signing.crt\/\fR, and the
|
|
||||||
host-key document in \fI\,host_key.crt\/\fR:
|
|
||||||
.PP
|
|
||||||
.Vb 1
|
|
||||||
.EX
|
|
||||||
\& genprotimg \-i \fI\,vmlinuz\/\fR \-r \fI\,initramfs\/\fR \-p \fI\,parmfile\/\fR \-k \fI\,host_key.crt\/\fR \-C \fI\,ibm-z-host-key-signing.crt\/\fR \-C \fI\,DigiCertCA.crt \-o \fI\,/boot/vmlinuz.pv\/\fR
|
|
||||||
.EE
|
|
||||||
.Ve
|
|
||||||
.PP
|
.PP
|
||||||
|
.B genprotimg \-i \fI\,vmlinuz\/\fR \-r \fI\,initramfs\/\fR \-p \fI\,parmfile\/\fR \-k \fI\,host_key.crt\/\fR \-C \fI\,ibm-z-host-key-signing.crt\/\fR \-C \fI\,DigiCertCA.crt\fR \-o \fI\,/boot/vmlinuz.pv\/\fR \-\-enable\-dump \-\-comm\-key \fI\,comm-key\fR
|
||||||
|
|
||||||
.SH NOTES
|
.SH NOTES
|
||||||
.IP "1." 4
|
.IP "1." 4
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ BODY_FILE=$(mktemp)
|
|||||||
ISSUER_DN_FILE=$(mktemp)
|
ISSUER_DN_FILE=$(mktemp)
|
||||||
SUBJECT_DN_FILE=$(mktemp)
|
SUBJECT_DN_FILE=$(mktemp)
|
||||||
DEF_ISSUER_DN_FILE=$(mktemp)
|
DEF_ISSUER_DN_FILE=$(mktemp)
|
||||||
|
CANONICAL_ISSUER_DN_FILE=$(mktemp)
|
||||||
CRL_SERIAL_FILE=$(mktemp)
|
CRL_SERIAL_FILE=$(mktemp)
|
||||||
|
|
||||||
# Cleanup on exit
|
# Cleanup on exit
|
||||||
@@ -30,7 +31,7 @@ cleanup()
|
|||||||
{
|
{
|
||||||
rm -f $ISSUER_PUBKEY_FILE $SIGNATURE_FILE $BODY_FILE \
|
rm -f $ISSUER_PUBKEY_FILE $SIGNATURE_FILE $BODY_FILE \
|
||||||
$ISSUER_DN_FILE $SUBJECT_DN_FILE $DEF_ISSUER_DN_FILE \
|
$ISSUER_DN_FILE $SUBJECT_DN_FILE $DEF_ISSUER_DN_FILE \
|
||||||
$CRL_SERIAL_FILE
|
$CANONICAL_ISSUER_DN_FILE $CRL_SERIAL_FILE
|
||||||
}
|
}
|
||||||
trap cleanup EXIT
|
trap cleanup EXIT
|
||||||
|
|
||||||
@@ -47,13 +48,21 @@ set -e
|
|||||||
usage()
|
usage()
|
||||||
{
|
{
|
||||||
cat <<-EOF
|
cat <<-EOF
|
||||||
Usage: `basename $1` host-key-doc signing-key-cert [-c CA-cert] [-r CRL]
|
Usage: `basename $1` [-d] [-c CA-cert] [-r CRL] host-key-doc signing-key-cert
|
||||||
|
|
||||||
Verify an IBM Secure Execution host key document against
|
Verify an IBM Secure Execution host key document against
|
||||||
a signing key.
|
a signing key.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-d disable default issuer check of host-key-doc
|
||||||
|
-c CA-cert trusted CA certificate
|
||||||
|
-r CRL list of revoked host-key-docs
|
||||||
|
|
||||||
Note that in order to have the full trust chain verified
|
Note that in order to have the full trust chain verified
|
||||||
it is necessary to provide the issueing CA's certificate.
|
it is necessary to provide the issuing CA's certificate.
|
||||||
|
The default issuer check may be disabled if a non-default
|
||||||
|
signing key certificate needs to be verified against the
|
||||||
|
CA certificate.
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
@@ -121,20 +130,34 @@ default_issuer()
|
|||||||
commonName = International Business Machines Corporation
|
commonName = International Business Machines Corporation
|
||||||
countryName = US
|
countryName = US
|
||||||
localityName = Poughkeepsie
|
localityName = Poughkeepsie
|
||||||
organizationalUnitName = IBM Z Host Key Signing Service
|
organizationalUnitName = Key Signing Service
|
||||||
organizationName = International Business Machines Corporation
|
organizationName = International Business Machines Corporation
|
||||||
stateOrProvinceName = New York
|
stateOrProvinceName = New York
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
verify_issuer_files()
|
# As organizationalUnitName can have an arbitrary prefix but must
|
||||||
|
# end with "Key Signing Service" let's normalize the OU name by
|
||||||
|
# stripping off the prefix
|
||||||
|
verify_default_issuer()
|
||||||
{
|
{
|
||||||
default_issuer > $DEF_ISSUER_DN_FILE
|
default_issuer > $DEF_ISSUER_DN_FILE
|
||||||
|
|
||||||
if ! diff $ISSUER_DN_FILE $DEF_ISSUER_DN_FILE
|
sed "s/\(^[ ]*organizationalUnitName[ ]*=[ ]*\).*\(Key Signing Service$\)/\1\2/" \
|
||||||
|
$ISSUER_DN_FILE > $CANONICAL_ISSUER_DN_FILE
|
||||||
|
|
||||||
|
if ! diff $CANONICAL_ISSUER_DN_FILE $DEF_ISSUER_DN_FILE
|
||||||
then
|
then
|
||||||
echo Incorrect default issuer >&2 && exit 1
|
echo Incorrect default issuer >&2 && exit 1
|
||||||
fi
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_issuer_files()
|
||||||
|
{
|
||||||
|
if [ $1 -eq 1 ]
|
||||||
|
then
|
||||||
|
verify_default_issuer
|
||||||
|
fi
|
||||||
|
|
||||||
if diff $ISSUER_DN_FILE $SUBJECT_DN_FILE
|
if diff $ISSUER_DN_FILE $SUBJECT_DN_FILE
|
||||||
then
|
then
|
||||||
@@ -196,14 +219,16 @@ check_file()
|
|||||||
# check args
|
# check args
|
||||||
CRL_FILE=
|
CRL_FILE=
|
||||||
CA_FILE=
|
CA_FILE=
|
||||||
|
CHECK_DEFAULT_ISSUER=1
|
||||||
|
|
||||||
args=$(getopt -qu "r:c:h" $*)
|
args=$(getopt -qu "dr:c:h" $*)
|
||||||
if [ $? = 0 ]
|
if [ $? = 0 ]
|
||||||
then
|
then
|
||||||
set -- $args
|
set -- $args
|
||||||
while [ $1 != "" ]
|
while [ $1 != "" ]
|
||||||
do
|
do
|
||||||
case $1 in
|
case $1 in
|
||||||
|
-d) CHECK_DEFAULT_ISSUER=0; shift;;
|
||||||
-r) CRL_FILE=$2; shift 2;;
|
-r) CRL_FILE=$2; shift 2;;
|
||||||
-c) CA_FILE=$2; shift 2;;
|
-c) CA_FILE=$2; shift 2;;
|
||||||
-h) usage $0; exit 0;;
|
-h) usage $0; exit 0;;
|
||||||
@@ -244,7 +269,7 @@ exit 1
|
|||||||
# Verify the issuer
|
# Verify the issuer
|
||||||
canonical_dn x509 $HKD_FILE issuer $ISSUER_DN_FILE
|
canonical_dn x509 $HKD_FILE issuer $ISSUER_DN_FILE
|
||||||
canonical_dn x509 $HKSK_FILE subject $SUBJECT_DN_FILE
|
canonical_dn x509 $HKSK_FILE subject $SUBJECT_DN_FILE
|
||||||
verify_issuer_files
|
verify_issuer_files $CHECK_DEFAULT_ISSUER
|
||||||
|
|
||||||
# Verify dates
|
# Verify dates
|
||||||
verify_dates $(cert_time $HKD_FILE startdate) $(cert_time $HKD_FILE enddate)
|
verify_dates $(cert_time $HKD_FILE startdate) $(cert_time $HKD_FILE enddate)
|
||||||
@@ -261,7 +286,7 @@ then
|
|||||||
echo -n "CRL "
|
echo -n "CRL "
|
||||||
canonical_dn crl $CRL_FILE issuer $ISSUER_DN_FILE
|
canonical_dn crl $CRL_FILE issuer $ISSUER_DN_FILE
|
||||||
canonical_dn x509 $HKSK_FILE subject $SUBJECT_DN_FILE
|
canonical_dn x509 $HKSK_FILE subject $SUBJECT_DN_FILE
|
||||||
verify_issuer_files
|
verify_issuer_files $CHECK_DEFAULT_ISSUER
|
||||||
|
|
||||||
verify_dates $(crl_time $CRL_FILE lastupdate) $(crl_time $CRL_FILE nextupdate) 'CRL'
|
verify_dates $(crl_time $CRL_FILE lastupdate) $(crl_time $CRL_FILE nextupdate) 'CRL'
|
||||||
|
|
||||||
|
|||||||
@@ -29,9 +29,6 @@
|
|||||||
*/
|
*/
|
||||||
#define PV_CERTS_SECURITY_LEVEL 2
|
#define PV_CERTS_SECURITY_LEVEL 2
|
||||||
|
|
||||||
/* SKID for DigiCert Assured ID Root CA */
|
|
||||||
#define DIGICERT_ASSURED_ID_ROOT_CA_SKID "45EBA2AFF492CB82312D518BA7A7219DF36DC80F"
|
|
||||||
|
|
||||||
union ecdh_pub_key {
|
union ecdh_pub_key {
|
||||||
struct {
|
struct {
|
||||||
uint8_t x[80];
|
uint8_t x[80];
|
||||||
|
|||||||
@@ -24,11 +24,15 @@
|
|||||||
#define PV_MAGIC_NUMBER 0x49424d5365634578ULL
|
#define PV_MAGIC_NUMBER 0x49424d5365634578ULL
|
||||||
#define PV_VERSION_1 0x00000100U
|
#define PV_VERSION_1 0x00000100U
|
||||||
|
|
||||||
|
/* Internal helper macro */
|
||||||
|
#define __PV_BIT(nr) (1ULL << (63 - (nr)))
|
||||||
|
|
||||||
/* Plaintext control flags */
|
/* Plaintext control flags */
|
||||||
#define PV_PCF_PCKM_ECC (1ULL << 5) /* PCKMO encrypt-ECC-key functions allowed */
|
#define PV_PCF_ALLOW_DUMPING __PV_BIT(34) /* dumping of the configuration is allowed */
|
||||||
#define PV_PCF_PCKMO_AES (1ULL << 6) /* PCKMO encrypt-AES-key functions allowed */
|
#define PV_PCF_NO_DECRYPTION __PV_BIT(35) /* prevent Ultravisor decryption during unpack operation */
|
||||||
#define PV_PCF_PCKMO_DEA_TDEA (1ULL << 7) /* PCKMO encrypt-DEA/TDEA-key functions allowed */
|
#define PV_PCF_PCKMO_DEA_TDEA __PV_BIT(56) /* PCKMO encrypt-DEA/TDEA-key functions allowed */
|
||||||
#define PV_PCF_NO_DECRYPTION (1ULL << 28) /* prevent Ultravisor decryption during unpack operation */
|
#define PV_PCF_PCKMO_AES __PV_BIT(57) /* PCKMO encrypt-AES-key functions allowed */
|
||||||
|
#define PV_PCF_PCKM_ECC __PV_BIT(58) /* PCKMO encrypt-ECC-key functions allowed */
|
||||||
|
|
||||||
/* maxima for the PV version 1 */
|
/* maxima for the PV version 1 */
|
||||||
#define PV_V1_IPIB_MAX_SIZE PAGE_SIZE
|
#define PV_V1_IPIB_MAX_SIZE PAGE_SIZE
|
||||||
|
|||||||
+85
-44
@@ -64,13 +64,17 @@ static gint pv_args_validate_options(PvArgs *args, GError **err)
|
|||||||
{
|
{
|
||||||
PvComponentType KERNEL = PV_COMP_TYPE_KERNEL;
|
PvComponentType KERNEL = PV_COMP_TYPE_KERNEL;
|
||||||
|
|
||||||
if (args->pcf && args->allow_pckmo != PV_NOT_SET) {
|
/* Check for mutually exclusive arguments */
|
||||||
g_set_error(err, PV_PARSE_ERROR, PV_PARSE_ERROR_SYNTAX,
|
if (args->pcf && !(args->allow_pckmo == PV_NOT_SET &&
|
||||||
_("The '--x-pcf' and '--(enable|disable)-pckmo' options are mutually"
|
args->allow_dump == PV_NOT_SET)) {
|
||||||
" exclusive.\nUse 'genprotimg --help' for more information"));
|
g_set_error(
|
||||||
|
err, PV_PARSE_ERROR, PV_PARSE_ERROR_SYNTAX,
|
||||||
|
_("The '--x-pcf' option cannot be used with the '--(enable|disable)-pckmo' or"
|
||||||
|
" '--(enable|disable)-dump' flags.\nUse 'genprotimg --help' for more information"));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check for unused arguments */
|
||||||
if (args->unused_values->len > 0) {
|
if (args->unused_values->len > 0) {
|
||||||
g_autofree gchar *unused = NULL;
|
g_autofree gchar *unused = NULL;
|
||||||
|
|
||||||
@@ -88,6 +92,14 @@ static gint pv_args_validate_options(PvArgs *args, GError **err)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check for mandatory arguments */
|
||||||
|
if (args->allow_dump == PV_TRUE && !args->cust_comm_key_path) {
|
||||||
|
g_set_error(err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
|
||||||
|
_("Option '--allow-dump' requires the '--comm-key' option.\nUse 'genprotimg "
|
||||||
|
"--help' for more information"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (!args->output_path) {
|
if (!args->output_path) {
|
||||||
g_set_error(err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
|
g_set_error(err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
|
||||||
_("Option '--output' is required.\nUse 'genprotimg --help' for more information"));
|
_("Option '--output' is required.\nUse 'genprotimg --help' for more information"));
|
||||||
@@ -111,7 +123,7 @@ static gint pv_args_validate_options(PvArgs *args, GError **err)
|
|||||||
g_strv_length(args->untrusted_cert_paths) == 0)) {
|
g_strv_length(args->untrusted_cert_paths) == 0)) {
|
||||||
g_set_error(
|
g_set_error(
|
||||||
err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
|
err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
|
||||||
_("Either specify the IBM Z signing key and (DigiCert) intermediate CA certificate\n"
|
_("Either specify the IBM Z signing key and intermediate CA certificate\n"
|
||||||
"by using the '--cert' option, or use the '--no-verify' flag to disable the\n"
|
"by using the '--cert' option, or use the '--no-verify' flag to disable the\n"
|
||||||
"host-key document verification completely (at your own risk)."));
|
"host-key document verification completely (at your own risk)."));
|
||||||
return -1;
|
return -1;
|
||||||
@@ -155,14 +167,14 @@ static gboolean cb_set_string_option(const gchar *option, const gchar *value,
|
|||||||
{
|
{
|
||||||
gchar **args_option = NULL;
|
gchar **args_option = NULL;
|
||||||
|
|
||||||
|
if (g_str_equal(option, "--comm-key"))
|
||||||
|
args_option = &args->cust_comm_key_path;
|
||||||
if (g_str_equal(option, "--root-ca"))
|
if (g_str_equal(option, "--root-ca"))
|
||||||
args_option = &args->root_ca_path;
|
args_option = &args->root_ca_path;
|
||||||
if (g_str_equal(option, "-o") || g_str_equal(option, "--output"))
|
if (g_str_equal(option, "-o") || g_str_equal(option, "--output"))
|
||||||
args_option = &args->output_path;
|
args_option = &args->output_path;
|
||||||
if (g_str_equal(option, "--x-comp-key"))
|
if (g_str_equal(option, "--x-comp-key"))
|
||||||
args_option = &args->xts_key_path;
|
args_option = &args->xts_key_path;
|
||||||
if (g_str_equal(option, "--x-comm-key"))
|
|
||||||
args_option = &args->cust_comm_key_path;
|
|
||||||
if (g_str_equal(option, "--x-header-key"))
|
if (g_str_equal(option, "--x-header-key"))
|
||||||
args_option = &args->cust_root_key_path;
|
args_option = &args->cust_root_key_path;
|
||||||
if (g_str_equal(option, "--x-pcf"))
|
if (g_str_equal(option, "--x-pcf"))
|
||||||
@@ -188,19 +200,6 @@ static gboolean cb_set_string_option(const gchar *option, const gchar *value,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean cb_enable_disable_flag(const gchar *option, const gchar *value G_GNUC_UNUSED,
|
|
||||||
PvArgs *args, GError **err G_GNUC_UNUSED)
|
|
||||||
{
|
|
||||||
if (g_str_equal(option, "--enable-pckmo"))
|
|
||||||
args->allow_pckmo = PV_TRUE;
|
|
||||||
else if (g_str_equal(option, "--disable-pckmo"))
|
|
||||||
args->allow_pckmo = PV_FALSE;
|
|
||||||
else
|
|
||||||
g_assert_not_reached();
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean cb_set_log_level(const gchar *option G_GNUC_UNUSED,
|
static gboolean cb_set_log_level(const gchar *option G_GNUC_UNUSED,
|
||||||
const gchar *value G_GNUC_UNUSED, PvArgs *args,
|
const gchar *value G_GNUC_UNUSED, PvArgs *args,
|
||||||
GError **err G_GNUC_UNUSED)
|
GError **err G_GNUC_UNUSED)
|
||||||
@@ -217,8 +216,51 @@ static gboolean cb_remaining_values(const gchar *option G_GNUC_UNUSED,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MUT_EXCL_BOOL_FLAG_CB_NAME(FLAG, VALUE) (cb_##FLAG##_##VALUE)
|
||||||
|
#define DEFINE_MUT_EXCL_BOOL_FLAG_CB(FLAG, VALUE) \
|
||||||
|
static gboolean MUT_EXCL_BOOL_FLAG_CB_NAME(FLAG, VALUE)( \
|
||||||
|
const gchar *option G_GNUC_UNUSED, const gchar *value G_GNUC_UNUSED, \
|
||||||
|
PvArgs *args, GError **err) \
|
||||||
|
{ \
|
||||||
|
if (!(args->allow_##FLAG == PV_NOT_SET || \
|
||||||
|
args->allow_##FLAG == VALUE)) { \
|
||||||
|
g_set_error(err, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, \
|
||||||
|
"'--enable-" #FLAG "' and '--disable-" #FLAG \
|
||||||
|
"' are mutually exclusive"); \
|
||||||
|
return FALSE; \
|
||||||
|
} \
|
||||||
|
args->allow_##FLAG = VALUE; \
|
||||||
|
return TRUE; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DEFINE_MUT_EXCL_BOOL_FLAG_CBS(FLAG) \
|
||||||
|
DEFINE_MUT_EXCL_BOOL_FLAG_CB(FLAG, PV_TRUE) \
|
||||||
|
DEFINE_MUT_EXCL_BOOL_FLAG_CB(FLAG, PV_FALSE)
|
||||||
|
|
||||||
|
#define MUT_EXCL_BOOL_FLAG(FLAG, ENABLE_DESC, DISABLE_DESC) \
|
||||||
|
{ \
|
||||||
|
.long_name = "enable-" #FLAG, \
|
||||||
|
.short_name = 0, \
|
||||||
|
.flags = G_OPTION_FLAG_NO_ARG, \
|
||||||
|
.arg = G_OPTION_ARG_CALLBACK, \
|
||||||
|
.arg_data = MUT_EXCL_BOOL_FLAG_CB_NAME(FLAG, PV_TRUE), \
|
||||||
|
.description = ENABLE_DESC, \
|
||||||
|
}, \
|
||||||
|
{ \
|
||||||
|
.long_name = "disable-" #FLAG, \
|
||||||
|
.short_name = 0, \
|
||||||
|
.flags = G_OPTION_FLAG_NO_ARG, \
|
||||||
|
.arg = G_OPTION_ARG_CALLBACK, \
|
||||||
|
.arg_data = MUT_EXCL_BOOL_FLAG_CB_NAME(FLAG, PV_FALSE), \
|
||||||
|
.description = DISABLE_DESC, \
|
||||||
|
}
|
||||||
|
|
||||||
#define INDENT " "
|
#define INDENT " "
|
||||||
|
|
||||||
|
/* Define the callbacks for mutually exclusive command line flags */
|
||||||
|
DEFINE_MUT_EXCL_BOOL_FLAG_CBS(dump)
|
||||||
|
DEFINE_MUT_EXCL_BOOL_FLAG_CBS(pckmo)
|
||||||
|
|
||||||
gint pv_args_parse_options(PvArgs *args, gint *argc, gchar **argv[],
|
gint pv_args_parse_options(PvArgs *args, gint *argc, gchar **argv[],
|
||||||
GError **err)
|
GError **err)
|
||||||
{
|
{
|
||||||
@@ -282,21 +324,28 @@ gint pv_args_parse_options(PvArgs *args, gint *argc, gchar **argv[],
|
|||||||
.description = _("Use the kernel parameters stored in PARMFILE\n" INDENT
|
.description = _("Use the kernel parameters stored in PARMFILE\n" INDENT
|
||||||
"(optional)."),
|
"(optional)."),
|
||||||
.arg_description = _("PARMFILE") },
|
.arg_description = _("PARMFILE") },
|
||||||
{.long_name = "enable-pckmo",
|
MUT_EXCL_BOOL_FLAG(
|
||||||
.short_name = 0,
|
dump,
|
||||||
.flags = G_OPTION_FLAG_NO_ARG,
|
_("Enable PV guest dumps (optional). This option\n" INDENT
|
||||||
.arg = G_OPTION_ARG_CALLBACK,
|
"requires the '--comm-key' option."),
|
||||||
.arg_data = cb_enable_disable_flag,
|
_("Disable PV guest dumps (default) (optional).")),
|
||||||
.description = _("Enable the support for the DEA, TDEA, AES, and\n" INDENT
|
MUT_EXCL_BOOL_FLAG(
|
||||||
"ECC PCKMO key encryption functions (default)\n" INDENT
|
pckmo,
|
||||||
"(optional).")},
|
_("Enable the support for the DEA, TDEA, AES, and\n" INDENT
|
||||||
{.long_name = "disable-pckmo",
|
"ECC PCKMO key encryption functions (default)\n" INDENT
|
||||||
.short_name = 0,
|
"(optional)."),
|
||||||
.flags = G_OPTION_FLAG_NO_ARG,
|
_("Disable the support for the DEA, TDEA, AES, and\n" INDENT
|
||||||
.arg = G_OPTION_ARG_CALLBACK,
|
"ECC PCKMO key encryption functions (optional).")),
|
||||||
.arg_data = cb_enable_disable_flag,
|
{ .long_name = "comm-key",
|
||||||
.description = _("Disable the support for the DEA, TDEA, AES, and\n" INDENT
|
.short_name = 0,
|
||||||
"ECC PCKMO key encryption functions (optional).")},
|
.flags = G_OPTION_FLAG_FILENAME,
|
||||||
|
.arg = G_OPTION_ARG_CALLBACK,
|
||||||
|
.arg_data = cb_set_string_option,
|
||||||
|
.description = _(
|
||||||
|
"FILE contains the key with which you encrypt\n" INDENT
|
||||||
|
"the PV guest dump (optional). Required by\n" INDENT
|
||||||
|
"the '--enable-dump' option."),
|
||||||
|
.arg_description = _("FILE") },
|
||||||
{ .long_name = "crl",
|
{ .long_name = "crl",
|
||||||
.short_name = 0,
|
.short_name = 0,
|
||||||
.flags = G_OPTION_FLAG_NONE,
|
.flags = G_OPTION_FLAG_NONE,
|
||||||
@@ -355,15 +404,6 @@ gint pv_args_parse_options(PvArgs *args, gint *argc, gchar **argv[],
|
|||||||
};
|
};
|
||||||
|
|
||||||
GOptionEntry x_entries[] = {
|
GOptionEntry x_entries[] = {
|
||||||
{ .long_name = "x-comm-key",
|
|
||||||
.short_name = 0,
|
|
||||||
.flags = G_OPTION_FLAG_FILENAME,
|
|
||||||
.arg = G_OPTION_ARG_CALLBACK,
|
|
||||||
.arg_data = cb_set_string_option,
|
|
||||||
.description = _(
|
|
||||||
"Use FILE as the customer communication key.\n" INDENT
|
|
||||||
"Optional; default: auto-generated."),
|
|
||||||
.arg_description = _("FILE") },
|
|
||||||
{ .long_name = "x-comp-key",
|
{ .long_name = "x-comp-key",
|
||||||
.short_name = 0,
|
.short_name = 0,
|
||||||
.flags = G_OPTION_FLAG_FILENAME,
|
.flags = G_OPTION_FLAG_FILENAME,
|
||||||
@@ -446,6 +486,7 @@ PvArgs *pv_args_new(void)
|
|||||||
g_autoptr(PvArgs) args = g_new0(PvArgs, 1);
|
g_autoptr(PvArgs) args = g_new0(PvArgs, 1);
|
||||||
|
|
||||||
args->unused_values = g_ptr_array_new_with_free_func(g_free);
|
args->unused_values = g_ptr_array_new_with_free_func(g_free);
|
||||||
|
args->allow_dump = PV_NOT_SET;
|
||||||
args->allow_pckmo = PV_NOT_SET;
|
args->allow_pckmo = PV_NOT_SET;
|
||||||
return g_steal_pointer(&args);
|
return g_steal_pointer(&args);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ typedef struct {
|
|||||||
gboolean offline;
|
gboolean offline;
|
||||||
gchar *pcf;
|
gchar *pcf;
|
||||||
gchar *scf;
|
gchar *scf;
|
||||||
|
PvTristate allow_dump;
|
||||||
PvTristate allow_pckmo;
|
PvTristate allow_pckmo;
|
||||||
gchar *psw_addr; /* PSW address which will be used for the start of
|
gchar *psw_addr; /* PSW address which will be used for the start of
|
||||||
* the actual component (e.g. Linux kernel)
|
* the actual component (e.g. Linux kernel)
|
||||||
|
|||||||
@@ -229,7 +229,9 @@ static gint pv_img_set_psw_addr(PvImage *img, const gchar *psw_addr_s,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gint pv_img_set_control_flags(PvImage *img, const gchar *pcf_s,
|
static gint pv_img_set_control_flags(PvImage *img, const gchar *pcf_s,
|
||||||
const gchar *scf_s, PvTristate allow_pckmo, GError **err)
|
const gchar *scf_s,
|
||||||
|
PvTristate allow_dump,
|
||||||
|
PvTristate allow_pckmo, GError **err)
|
||||||
{
|
{
|
||||||
uint64_t flags;
|
uint64_t flags;
|
||||||
|
|
||||||
@@ -247,6 +249,11 @@ static gint pv_img_set_control_flags(PvImage *img, const gchar *pcf_s,
|
|||||||
img->scf = flags;
|
img->scf = flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (allow_dump == PV_TRUE)
|
||||||
|
img->pcf |= PV_PCF_ALLOW_DUMPING;
|
||||||
|
else if (allow_dump == PV_FALSE)
|
||||||
|
img->pcf &= ~PV_PCF_ALLOW_DUMPING;
|
||||||
|
|
||||||
if (allow_pckmo == PV_TRUE)
|
if (allow_pckmo == PV_TRUE)
|
||||||
img->pcf |= PV_PCF_PCKM_ECC | PV_PCF_PCKMO_AES | PV_PCF_PCKMO_DEA_TDEA;
|
img->pcf |= PV_PCF_PCKM_ECC | PV_PCF_PCKMO_AES | PV_PCF_PCKMO_DEA_TDEA;
|
||||||
else if (allow_pckmo == PV_FALSE)
|
else if (allow_pckmo == PV_FALSE)
|
||||||
@@ -304,9 +311,10 @@ static gint pv_img_hostkey_verify(GSList *host_key_certs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Load all untrusted certificates (e.g. IBM Z signing key and
|
/* Load all untrusted certificates (e.g. IBM Z signing key and
|
||||||
* DigiCert intermediate CA) that are required to establish a chain of
|
* intermediate CA) that are required to establish a chain of trust
|
||||||
* trust starting from the host-key document up to the root CA (if not
|
* starting from the host-key document up to the root CA (if not
|
||||||
* otherwise specified that's the DigiCert Assured ID Root CA).
|
* otherwise specified that can be one of the system wide installed
|
||||||
|
* root CAs, e.g. DigiCert).
|
||||||
*/
|
*/
|
||||||
untrusted_certs_with_path = load_certificates(untrusted_cert_paths, err);
|
untrusted_certs_with_path = load_certificates(untrusted_cert_paths, err);
|
||||||
if (!untrusted_certs_with_path)
|
if (!untrusted_certs_with_path)
|
||||||
@@ -341,9 +349,8 @@ static gint pv_img_hostkey_verify(GSList *host_key_certs,
|
|||||||
* For this we must check:
|
* For this we must check:
|
||||||
*
|
*
|
||||||
* 1. Can a chain of trust be established ending in a root CA
|
* 1. Can a chain of trust be established ending in a root CA
|
||||||
* 2. Is the correct root CA ued? It has either to be the
|
* 2. Is the correct root CA used? It has either to be a system CA
|
||||||
* 'DigiCert Assured ID Root CA' or the root CA specified via
|
* or the root CA specified via command line.
|
||||||
* command line.
|
|
||||||
*/
|
*/
|
||||||
for (gint i = 0; i < sk_X509_num(ibm_signing_certs); ++i) {
|
for (gint i = 0; i < sk_X509_num(ibm_signing_certs); ++i) {
|
||||||
X509 *ibm_signing_cert = sk_X509_value(ibm_signing_certs, i);
|
X509 *ibm_signing_cert = sk_X509_value(ibm_signing_certs, i);
|
||||||
@@ -364,17 +371,12 @@ static gint pv_img_hostkey_verify(GSList *host_key_certs,
|
|||||||
if (verify_cert(ibm_signing_cert, ctx, err) < 0)
|
if (verify_cert(ibm_signing_cert, ctx, err) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
/* Verify the build chain of trust chain. If the user passes a
|
/* If there is a chain of trust using either the provided root
|
||||||
* trusted root CA on the command line then the check for the
|
* CA on the command line or a system wide trusted root CA.
|
||||||
* Subject Key Identifier (SKID) is skipped, otherwise let's
|
|
||||||
* check if the SKID meets our expectation.
|
|
||||||
*/
|
*/
|
||||||
if (!root_ca_path &&
|
if (check_chain_parameters(X509_STORE_CTX_get0_chain(ctx),
|
||||||
check_chain_parameters(X509_STORE_CTX_get0_chain(ctx),
|
err) < 0)
|
||||||
get_digicert_assured_id_root_ca_skid(),
|
|
||||||
err) < 0) {
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
|
||||||
|
|
||||||
ibm_signing_crls = store_ctx_find_valid_crls(ctx, ibm_signing_cert, err);
|
ibm_signing_crls = store_ctx_find_valid_crls(ctx, ibm_signing_cert, err);
|
||||||
if (!ibm_signing_crls) {
|
if (!ibm_signing_crls) {
|
||||||
@@ -588,7 +590,7 @@ PvImage *pv_img_new(PvArgs *args, const gchar *stage3a_path, GError **err)
|
|||||||
g_warning(_("host-key document verification is disabled. Your workload is not secured."));
|
g_warning(_("host-key document verification is disabled. Your workload is not secured."));
|
||||||
|
|
||||||
if (args->root_ca_path)
|
if (args->root_ca_path)
|
||||||
g_warning(_("A different root CA than the default DigiCert root CA is selected. Ensure that this root CA is trusted."));
|
g_warning(_("The root CA is selected through the command line. Ensure that this root CA is trusted."));
|
||||||
|
|
||||||
ret->comps = pv_img_comps_new(EVP_sha512(), EVP_sha512(), EVP_sha512(), err);
|
ret->comps = pv_img_comps_new(EVP_sha512(), EVP_sha512(), EVP_sha512(), err);
|
||||||
if (!ret->comps)
|
if (!ret->comps)
|
||||||
@@ -608,7 +610,9 @@ PvImage *pv_img_new(PvArgs *args, const gchar *stage3a_path, GError **err)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* set the control flags: PCF and SCF */
|
/* set the control flags: PCF and SCF */
|
||||||
if (pv_img_set_control_flags(ret, args->pcf, args->scf, args->allow_pckmo, err) < 0)
|
if (pv_img_set_control_flags(ret, args->pcf, args->scf,
|
||||||
|
args->allow_dump, args->allow_pckmo,
|
||||||
|
err) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* read in the keys */
|
/* read in the keys */
|
||||||
|
|||||||
@@ -1079,8 +1079,8 @@ int store_set_verify_param(X509_STORE *store, GError **err)
|
|||||||
g_abort();
|
g_abort();
|
||||||
|
|
||||||
/* The maximum depth level of the chain of trust for the verification of
|
/* The maximum depth level of the chain of trust for the verification of
|
||||||
* the IBM Z signing key is 2, i.e. IBM Z signing key -> (DigiCert)
|
* the IBM Z signing key is 2, i.e. IBM Z signing key -> intermediate CA
|
||||||
* intermediate CA -> (DigiCert) root CA
|
* -> root CA
|
||||||
*/
|
*/
|
||||||
X509_VERIFY_PARAM_set_depth(param, 2);
|
X509_VERIFY_PARAM_set_depth(param, 2);
|
||||||
|
|
||||||
@@ -1267,46 +1267,38 @@ static int security_level_to_bits(int level)
|
|||||||
return security_bits[level];
|
return security_bits[level];
|
||||||
}
|
}
|
||||||
|
|
||||||
static ASN1_OCTET_STRING *digicert_assured_id_root_ca;
|
|
||||||
|
|
||||||
const ASN1_OCTET_STRING *get_digicert_assured_id_root_ca_skid(void)
|
|
||||||
{
|
|
||||||
pv_crypto_init();
|
|
||||||
return digicert_assured_id_root_ca;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Used for the caching of the downloaded CRLs */
|
/* Used for the caching of the downloaded CRLs */
|
||||||
static GHashTable *cached_crls;
|
static GHashTable *cached_crls;
|
||||||
|
|
||||||
void pv_crypto_init(void)
|
void pv_crypto_init(void)
|
||||||
{
|
{
|
||||||
if (digicert_assured_id_root_ca)
|
if (cached_crls)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
cached_crls = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
|
cached_crls = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
|
||||||
(GDestroyNotify)X509_CRL_free);
|
(GDestroyNotify)X509_CRL_free);
|
||||||
digicert_assured_id_root_ca = s2i_ASN1_OCTET_STRING(
|
|
||||||
NULL, NULL, DIGICERT_ASSURED_ID_ROOT_CA_SKID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void pv_crypto_cleanup(void)
|
void pv_crypto_cleanup(void)
|
||||||
{
|
{
|
||||||
if (!digicert_assured_id_root_ca)
|
if (!cached_crls)
|
||||||
return;
|
return;
|
||||||
g_clear_pointer(&cached_crls, g_hash_table_destroy);
|
g_clear_pointer(&cached_crls, g_hash_table_destroy);
|
||||||
g_clear_pointer(&digicert_assured_id_root_ca, ASN1_OCTET_STRING_free);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gint check_chain_parameters(const STACK_OF_X509 *chain,
|
gint check_chain_parameters(const STACK_OF_X509 *chain,
|
||||||
const ASN1_OCTET_STRING *skid, GError **err)
|
GError **err)
|
||||||
{
|
{
|
||||||
const ASN1_OCTET_STRING *ca_skid = NULL;
|
const X509_NAME *ca_x509_subject = NULL;
|
||||||
|
g_autofree gchar *ca_subject = NULL;
|
||||||
gint len = sk_X509_num(chain);
|
gint len = sk_X509_num(chain);
|
||||||
X509 *ca = NULL;
|
X509 *ca = NULL;
|
||||||
|
|
||||||
g_assert(skid);
|
|
||||||
/* at least one root and one leaf certificate must be defined */
|
/* at least one root and one leaf certificate must be defined */
|
||||||
g_assert(len >= 2);
|
if (len < 2) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("there must be at least on root and one leaf certificate in the chain of trust"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* get the root certificate of the chain of trust */
|
/* get the root certificate of the chain of trust */
|
||||||
ca = sk_X509_value(chain, len - 1);
|
ca = sk_X509_value(chain, len - 1);
|
||||||
@@ -1316,19 +1308,21 @@ gint check_chain_parameters(const STACK_OF_X509 *chain,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ca_skid = X509_get0_subject_key_id(ca);
|
ca_x509_subject = X509_get_subject_name(ca);
|
||||||
if (!ca_skid) {
|
if (!ca_x509_subject) {
|
||||||
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_MALFORMED_ROOT_CA,
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||||
_("malformed root certificate"));
|
_("subject of the root CA cannot be retrieved"));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ASN1_STRING_cmp(ca_skid, skid) != 0) {
|
ca_subject = X509_NAME_oneline(ca_x509_subject, NULL, 0);
|
||||||
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_WRONG_CA_USED,
|
if (!ca_subject) {
|
||||||
_("expecting DigiCert root CA to be used"));
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("subject name of the root CA cannot be retrieved"));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_info("Root CA used: '%s'", ca_subject);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -125,7 +125,6 @@ int check_crl_valid_for_cert(X509_CRL *crl, X509 *cert,
|
|||||||
gint verify_flags, GError **err);
|
gint verify_flags, GError **err);
|
||||||
void pv_crypto_init(void);
|
void pv_crypto_init(void);
|
||||||
void pv_crypto_cleanup(void);
|
void pv_crypto_cleanup(void);
|
||||||
const ASN1_OCTET_STRING *get_digicert_assured_id_root_ca_skid(void);
|
|
||||||
gint verify_host_key(X509 *host_key, GSList *issuer_pairs,
|
gint verify_host_key(X509 *host_key, GSList *issuer_pairs,
|
||||||
gint verify_flags, int level, GError **err);
|
gint verify_flags, int level, GError **err);
|
||||||
X509 *load_cert_from_file(const char *path, GError **err);
|
X509 *load_cert_from_file(const char *path, GError **err);
|
||||||
@@ -138,8 +137,7 @@ X509_STORE *store_setup(const gchar *root_ca_path,
|
|||||||
int store_set_verify_param(X509_STORE *store, GError **err);
|
int store_set_verify_param(X509_STORE *store, GError **err);
|
||||||
X509_CRL *load_crl_by_cert(X509 *cert, GError **err);
|
X509_CRL *load_crl_by_cert(X509 *cert, GError **err);
|
||||||
STACK_OF_X509_CRL *try_load_crls_by_certs(GSList *certs_with_path);
|
STACK_OF_X509_CRL *try_load_crls_by_certs(GSList *certs_with_path);
|
||||||
gint check_chain_parameters(const STACK_OF_X509 *chain,
|
gint check_chain_parameters(const STACK_OF_X509 *chain, GError **err);
|
||||||
const ASN1_OCTET_STRING *skid, GError **err);
|
|
||||||
X509_NAME *c2b_name(const X509_NAME *name);
|
X509_NAME *c2b_name(const X509_NAME *name);
|
||||||
|
|
||||||
STACK_OF_X509 *delete_ibm_signing_certs(STACK_OF_X509 *certs);
|
STACK_OF_X509 *delete_ibm_signing_certs(STACK_OF_X509 *certs);
|
||||||
|
|||||||
@@ -0,0 +1,106 @@
|
|||||||
|
/* Copyright IBM Corp. 2022
|
||||||
|
*
|
||||||
|
* 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 LIBCPUMF_H
|
||||||
|
#define LIBCPUMF_H
|
||||||
|
|
||||||
|
#include <sched.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define S390_CPUMF_CF "/sys/devices/cpum_cf/"
|
||||||
|
#define S390_CPUMF_CFDIAG "/sys/devices/cpum_cf_diag/"
|
||||||
|
#define S390_CPUMF_SF "/sys/devices/cpum_sf/"
|
||||||
|
#define S390_CPUS_POSSIBLE "/sys/devices/system/cpu/possible"
|
||||||
|
#define S390_CPUS_ONLINE "/sys/devices/system/cpu/online"
|
||||||
|
#define S390_CPUMSF_BUFFERSZ "/sys/module/kernel/parameters/cpum_sfb_size"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read out the PMU type from a given file.
|
||||||
|
*
|
||||||
|
* Return the PMU type number assigned to this PMU by the kernel. This is
|
||||||
|
* a non zero number.
|
||||||
|
* If the PMU does not exist return -1 and set errno.
|
||||||
|
*
|
||||||
|
* @param[in] dirname Name of the event directory in sysfs
|
||||||
|
*/
|
||||||
|
int libcpumf_pmutype(const char *dirname);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read out the CPU list from a given file name, for example from files
|
||||||
|
* /sys/devices/system/cpu/online or /sys/devices/system/cpu/possible.
|
||||||
|
*
|
||||||
|
* Return the cpu_set_t created from parsing the CPU list in the second
|
||||||
|
* parameter.
|
||||||
|
* Return code of zero indicates proper conversion and -1 indicates an
|
||||||
|
* error.
|
||||||
|
*
|
||||||
|
* @param[in] buffer Comma separated string of a CPU list
|
||||||
|
* @param[in] filename Name of a sysfs CPU list file name
|
||||||
|
* @param[out] mask Converted buffer into cpu_set_t mask structure
|
||||||
|
*/
|
||||||
|
int libcpumf_cpuset(const char *buffer, cpu_set_t *mask);
|
||||||
|
int libcpumf_cpuset_fn(const char *filename, cpu_set_t *mask);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read CPU Measurement Counting Facility hardware information
|
||||||
|
*
|
||||||
|
* Return true if CPU Measurement Counter facility information has been
|
||||||
|
* retrieved and is valid.
|
||||||
|
*
|
||||||
|
* Return false if the information could not be extracted from the file.
|
||||||
|
*
|
||||||
|
* @param[out] cfvn Contains CPUMF counter first version number
|
||||||
|
* @param[out] csvn Contains CPUMF counter second version number
|
||||||
|
* @param[out] auth Contains CPUMF counter set authorization level
|
||||||
|
*/
|
||||||
|
bool libcpumf_cpumcf_info(int *cfvn, int *csvn, int *auth);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if CPU Measurement Counter Facility is available.
|
||||||
|
*/
|
||||||
|
bool libcpumf_have_cpumcf(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read CPU Measurement Sampling Facility hardware information
|
||||||
|
*
|
||||||
|
* Read all necessary information from /sysfs file /proc/service_levels
|
||||||
|
* to return CPU Measurement Counter Sampling facility information
|
||||||
|
* characteristics.
|
||||||
|
* Return true on success and false when the data can not be retrieved.
|
||||||
|
*
|
||||||
|
* @param[out] min Minimum supported sampling interval
|
||||||
|
* @param[out] max Maximum supported sampling interval
|
||||||
|
* @param[out] speed Current CPU speed, number of CPU cylces per
|
||||||
|
* microsecond
|
||||||
|
* @param[out] basic_sz Basic sample size in bytes
|
||||||
|
* @param[out] diag_sz Diagnostic sample size in bytes
|
||||||
|
*/
|
||||||
|
bool libcpumf_cpumsf_info(unsigned long *min, unsigned long *max,
|
||||||
|
unsigned long *speed, int *basic_sz, int *diag_sz);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if CPU Measurement Sampling Facility is available.
|
||||||
|
*/
|
||||||
|
bool libcpumf_have_cpumsf(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if CPU Measurement Sampling Facility buffer sizes are
|
||||||
|
* available.
|
||||||
|
*/
|
||||||
|
bool libcpumf_have_sfb(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read CPU Measurement Sampling Facility supported sampling buffer sizes.
|
||||||
|
*
|
||||||
|
* Return the minimum and maximum CPU Measurement sampling facitity buffer
|
||||||
|
* sizes supported.
|
||||||
|
* Return true on success and false otherwise.
|
||||||
|
*
|
||||||
|
* @param[out] min Minimum supported sampling buffer size
|
||||||
|
* @param[out] max Maximum supported sampling buffer size
|
||||||
|
*/
|
||||||
|
bool libcpumf_sfb_info(unsigned long *min, unsigned long *max);
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
include ../common.mak
|
||||||
|
|
||||||
|
lib = libcpumf.a
|
||||||
|
|
||||||
|
examples = libcpumf_example
|
||||||
|
|
||||||
|
all: $(lib)
|
||||||
|
examples: $(lib) $(examples)
|
||||||
|
|
||||||
|
objects = libcpumf_pmutype.o libcpumf_cpuset.o libcpumf_support.o
|
||||||
|
|
||||||
|
$(lib): $(objects)
|
||||||
|
|
||||||
|
install: all
|
||||||
|
|
||||||
|
libcpumf_example: libcpumf_example.o $(lib)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.o $(lib) $(examples)
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
/* Copyright IBM Corp. 2022
|
||||||
|
*
|
||||||
|
* 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 <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "lib/libcpumf.h"
|
||||||
|
|
||||||
|
int libcpumf_cpuset(const char *parm, cpu_set_t *mask)
|
||||||
|
{
|
||||||
|
char *cp, *buffer = strdup(parm);
|
||||||
|
int to, from, rc;
|
||||||
|
|
||||||
|
if (!buffer) /* Errno set to ENOMEM */
|
||||||
|
return -1;
|
||||||
|
/* Check for invalid characters, such as 11.12 instead 11-12
|
||||||
|
* but allow blanks and newline. Newline is appended
|
||||||
|
* when the string is taken from sysfs files, for example
|
||||||
|
* /sys/devices/system/cpu/online
|
||||||
|
*/
|
||||||
|
if (strspn(buffer, "0123456789-,\n ") != strlen(buffer)) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
CPU_ZERO(mask);
|
||||||
|
for (; (cp = strtok(buffer, ",")); buffer = NULL) {
|
||||||
|
char *dash = strchr(cp, '-'); /* Range character? */
|
||||||
|
bool is_ok;
|
||||||
|
|
||||||
|
if (dash) {
|
||||||
|
rc = sscanf(cp, "%d-%d", &from, &to);
|
||||||
|
is_ok = rc == 2;
|
||||||
|
} else {
|
||||||
|
rc = sscanf(cp, "%d", &to);
|
||||||
|
from = to;
|
||||||
|
is_ok = rc == 1;
|
||||||
|
}
|
||||||
|
if (!is_ok) {
|
||||||
|
errno = ERANGE;
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
for (; from <= to; ++from)
|
||||||
|
CPU_SET(from, mask);
|
||||||
|
}
|
||||||
|
rc = 0;
|
||||||
|
out:
|
||||||
|
free(buffer);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int libcpumf_cpuset_fn(const char *filename, cpu_set_t *mask)
|
||||||
|
{
|
||||||
|
char *txt = NULL;
|
||||||
|
ssize_t ret = -1;
|
||||||
|
size_t len = 0;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = fopen(filename, "r");
|
||||||
|
if (!fp)
|
||||||
|
return ret;
|
||||||
|
/* Read out file, one line expected */
|
||||||
|
ret = getline(&txt, &len, fp);
|
||||||
|
fclose(fp);
|
||||||
|
if (ret > 0)
|
||||||
|
ret = libcpumf_cpuset(txt, mask);
|
||||||
|
free(txt);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
/* Copyright IBM Corp. 2022
|
||||||
|
*
|
||||||
|
* 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 <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "lib/libcpumf.h"
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
unsigned long min, max, speed, sfb_min, sfb_max;
|
||||||
|
int rc, pmu, cfvn, csvn, auth;
|
||||||
|
cpu_set_t set;
|
||||||
|
|
||||||
|
pmu = libcpumf_pmutype(S390_CPUMF_CF);
|
||||||
|
if (pmu >= 0)
|
||||||
|
printf("PMU %stype %d\n", S390_CPUMF_CF, pmu);
|
||||||
|
else
|
||||||
|
printf("PMU %stype error %d\n", S390_CPUMF_CF, errno);
|
||||||
|
pmu = libcpumf_pmutype(S390_CPUMF_SF);
|
||||||
|
if (pmu >= 0)
|
||||||
|
printf("PMU %stype %d\n", S390_CPUMF_SF, pmu);
|
||||||
|
else
|
||||||
|
printf("PMU %stype error %d\n", S390_CPUMF_SF, errno);
|
||||||
|
pmu = libcpumf_pmutype(S390_CPUMF_CFDIAG);
|
||||||
|
if (pmu >= 0)
|
||||||
|
printf("PMU %stype %d\n", S390_CPUMF_CFDIAG, pmu);
|
||||||
|
else
|
||||||
|
printf("PMU %stype error %d\n", S390_CPUMF_CFDIAG, errno);
|
||||||
|
|
||||||
|
rc = libcpumf_cpuset_fn(S390_CPUS_ONLINE, &set);
|
||||||
|
if (rc == 0) {
|
||||||
|
puts("Online CPUs:");
|
||||||
|
for (int i = 0; i < CPU_SETSIZE; ++i)
|
||||||
|
if (CPU_ISSET(i, &set))
|
||||||
|
printf("%d ", i);
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
rc = libcpumf_cpuset("0-7,9,11-12 ,15", &set);
|
||||||
|
if (rc == 0) {
|
||||||
|
puts("String CPUs:");
|
||||||
|
for (int i = 0; i < CPU_SETSIZE; ++i)
|
||||||
|
if (CPU_ISSET(i, &set))
|
||||||
|
printf("%d ", i);
|
||||||
|
putchar('\n');
|
||||||
|
} else {
|
||||||
|
printf("libcpumf_cpuset input invalid %d\n", errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("CPUMCF support %d\n", libcpumf_have_cpumcf());
|
||||||
|
rc = libcpumf_cpumcf_info(&cfvn, &csvn, &auth);
|
||||||
|
printf("libcpumf_cpumcf_info %d", rc);
|
||||||
|
if (rc)
|
||||||
|
printf(" cfvn %d csvn %d authorization %#x", cfvn, csvn, auth);
|
||||||
|
putchar('\n');
|
||||||
|
|
||||||
|
printf("CPUMSF support %d\n", libcpumf_have_cpumsf());
|
||||||
|
rc = libcpumf_cpumsf_info(&min, &max, &speed, &cfvn, &csvn);
|
||||||
|
printf("libcpumf_cpumsf_info %d", rc);
|
||||||
|
if (rc)
|
||||||
|
printf(" min %ld max %ld speed %#lx basic %d diag %d", min,
|
||||||
|
max, speed, cfvn, csvn);
|
||||||
|
putchar('\n');
|
||||||
|
|
||||||
|
printf("CPUMSF have sfb %d\n", libcpumf_have_sfb());
|
||||||
|
rc = libcpumf_sfb_info(&sfb_min, &sfb_max);
|
||||||
|
printf("libcpumf_sfb_info %d", rc);
|
||||||
|
if (rc)
|
||||||
|
printf(" sfb_min %lu sfb_max %lu", sfb_min, sfb_max);
|
||||||
|
putchar('\n');
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/* Copyright IBM Corp. 2022
|
||||||
|
*
|
||||||
|
* 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 <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "lib/libcpumf.h"
|
||||||
|
|
||||||
|
int libcpumf_pmutype(const char *dirname)
|
||||||
|
{
|
||||||
|
FILE *file;
|
||||||
|
char *fn;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = asprintf(&fn, "%s/type", dirname);
|
||||||
|
if (ret == -1) /* No memory, errno set */
|
||||||
|
return ret;
|
||||||
|
file = fopen(fn, "r");
|
||||||
|
free(fn);
|
||||||
|
ret = -1; /* Errno set on file open error */
|
||||||
|
if (file) {
|
||||||
|
/* Read out a single number from that file */
|
||||||
|
if (fscanf(file, "%u", &ret) != 1)
|
||||||
|
/* Unexpected format error, set errno */
|
||||||
|
errno = -ERANGE;
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
/* Copyright IBM Corp. 2022
|
||||||
|
*
|
||||||
|
* 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 <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include "lib/libcpumf.h"
|
||||||
|
|
||||||
|
#define SERVICELEVEL "/proc/service_levels"
|
||||||
|
|
||||||
|
bool libcpumf_cpumcf_info(int *cfvn, int *csvn, int *auth)
|
||||||
|
{
|
||||||
|
char *linep = NULL;
|
||||||
|
bool rc = false;
|
||||||
|
size_t line_sz;
|
||||||
|
ssize_t nbytes;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = fopen(SERVICELEVEL, "r");
|
||||||
|
if (!fp)
|
||||||
|
err(EXIT_FAILURE, SERVICELEVEL);
|
||||||
|
|
||||||
|
while ((nbytes = getline(&linep, &line_sz, fp)) != EOF) {
|
||||||
|
if (!strncmp(linep, "CPU-MF: Counter facility:", 25)) {
|
||||||
|
int cnt = sscanf(linep, "CPU-MF: Counter facility:"
|
||||||
|
" version=%d.%d authorization=%x",
|
||||||
|
cfvn, csvn, auth);
|
||||||
|
if (cnt != 3) {
|
||||||
|
warnx("Can not parse line %s", linep);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
rc = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
fclose(fp);
|
||||||
|
free(linep);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool libcpumf_have_cpumcf(void)
|
||||||
|
{
|
||||||
|
int cfvn, csvn, auth;
|
||||||
|
|
||||||
|
return libcpumf_cpumcf_info(&cfvn, &csvn, &auth);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool libcpumf_cpumsf_info(unsigned long *min, unsigned long *max,
|
||||||
|
unsigned long *speed, int *basic_sz, int *diag_sz)
|
||||||
|
{
|
||||||
|
char *linep = NULL;
|
||||||
|
bool rc = true;
|
||||||
|
size_t line_sz;
|
||||||
|
ssize_t nbytes;
|
||||||
|
int hit = 0;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = fopen(SERVICELEVEL, "r");
|
||||||
|
if (!fp)
|
||||||
|
err(EXIT_FAILURE, SERVICELEVEL);
|
||||||
|
|
||||||
|
while ((nbytes = getline(&linep, &line_sz, fp)) != EOF) {
|
||||||
|
int ok;
|
||||||
|
|
||||||
|
if (!strncmp(linep, "CPU-MF: Sampling facility: min", 30)) {
|
||||||
|
ok = sscanf(linep, "CPU-MF: Sampling facility:"
|
||||||
|
" min_rate=%ld max_rate=%ld cpu_speed=%ld",
|
||||||
|
min, max, speed);
|
||||||
|
if (ok != 3) {
|
||||||
|
warnx("Can not parse line %s", linep);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
hit += 1;
|
||||||
|
}
|
||||||
|
if (!strncmp(linep, "CPU-MF: Sampling facility: mode=basic", 37)) {
|
||||||
|
ok = sscanf(linep, "CPU-MF: Sampling facility:"
|
||||||
|
" mode=basic sample_size=%u", basic_sz);
|
||||||
|
if (ok != 1) {
|
||||||
|
warnx("Can not parse line %s", linep);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
hit += 1;
|
||||||
|
}
|
||||||
|
if (!strncmp(linep, "CPU-MF: Sampling facility: mode=diag", 36)) {
|
||||||
|
ok = sscanf(linep, "CPU-MF: Sampling facility:"
|
||||||
|
" mode=diagnostic sample_size=%u",
|
||||||
|
diag_sz);
|
||||||
|
if (ok != 1) {
|
||||||
|
warnx("Can not parse line %s", linep);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
hit += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
fclose(fp);
|
||||||
|
free(linep);
|
||||||
|
if (hit != 3)
|
||||||
|
rc = false;
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool libcpumf_have_cpumsf(void)
|
||||||
|
{
|
||||||
|
unsigned long a, b, c;
|
||||||
|
int basic_sz, diag_sz;
|
||||||
|
|
||||||
|
return libcpumf_cpumsf_info(&a, &b, &c, &basic_sz, &diag_sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool libcpumf_have_sfb(void)
|
||||||
|
{
|
||||||
|
unsigned long a, b;
|
||||||
|
|
||||||
|
return libcpumf_sfb_info(&a, &b);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool libcpumf_sfb_info(unsigned long *min, unsigned long *max)
|
||||||
|
{
|
||||||
|
int rc = false;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = fopen(S390_CPUMSF_BUFFERSZ, "r");
|
||||||
|
if (!fp)
|
||||||
|
err(EXIT_FAILURE, "%s", S390_CPUMSF_BUFFERSZ);
|
||||||
|
if (fscanf(fp, "%lu,%lu", min, max) == 2)
|
||||||
|
rc = true;
|
||||||
|
fclose(fp);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
@@ -1549,6 +1549,59 @@ int SK_EP11_reencipher_key(const struct sk_ext_ep11_lib *ep11_lib,
|
|||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memcpy(blob, lrb.payload, lrb.pllen);
|
||||||
|
|
||||||
|
/* re-encipher MACed SPKI */
|
||||||
|
rb.domain = domain;
|
||||||
|
lrb.domain = domain;
|
||||||
|
|
||||||
|
resp_len = sizeof(resp);
|
||||||
|
req_len = ep11.dll_xcpa_cmdblock(req, sizeof(req), XCP_ADM_REENCRYPT,
|
||||||
|
&rb, NULL, key_token + hdr->len,
|
||||||
|
key_token_length - hdr->len);
|
||||||
|
if (req_len < 0) {
|
||||||
|
sk_debug(debug, "Failed to build XCP command block");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = ep11.dll_m_admin(resp, &resp_len, NULL, NULL, req, req_len, NULL,
|
||||||
|
0, ep11_lib->target);
|
||||||
|
if (rv != CKR_OK || resp_len == 0) {
|
||||||
|
sk_debug(debug, "Command XCP_ADM_REENCRYPT failed. "
|
||||||
|
"rc = 0x%lx, resp_len = %ld", rv, resp_len);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = ep11.dll_xcpa_internal_rv(resp, resp_len, &lrb, &rv);
|
||||||
|
if (rc != 0) {
|
||||||
|
sk_debug(debug, "Failed to parse response. rc = %d", rc);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rv != CKR_OK) {
|
||||||
|
sk_debug(debug, "Failed to re-encrypt the EP11 secure key. "
|
||||||
|
"rc = 0x%lx", rv);
|
||||||
|
switch (rv) {
|
||||||
|
case CKR_IBM_WKID_MISMATCH:
|
||||||
|
sk_debug(debug, "The EP11 secure key is currently "
|
||||||
|
"encrypted under a different master that does "
|
||||||
|
"not match the master key in the CURRENT "
|
||||||
|
"master key register of APQN %02X.%04X",
|
||||||
|
card, domain);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key_token_length - hdr->len != lrb.pllen) {
|
||||||
|
sk_debug(debug, "Re-encrypted EP11 secure key size has "
|
||||||
|
"changed: org-len: %lu, new-len: %lu",
|
||||||
|
hdr->len - sizeof(*hdr), lrb.pllen);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(key_token + hdr->len, lrb.payload, lrb.pllen);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -245,6 +245,11 @@ get_system_level()
|
|||||||
read -r d_major d_minor d_minor2 <<< "$(split_version "$ver_str" "._-" 3)"
|
read -r d_major d_minor d_minor2 <<< "$(split_version "$ver_str" "._-" 3)"
|
||||||
read -r k_ver k_patchlvl k_sublvl k_sublvl2 <<< "$(split_kver "$kver_str" 4)"
|
read -r k_ver k_patchlvl k_sublvl k_sublvl2 <<< "$(split_kver "$kver_str" 4)"
|
||||||
|
|
||||||
|
# Handle excessive sublevel numbers consistently
|
||||||
|
if [[ "$k_sublvl2" -gt 65535 ]] ; then
|
||||||
|
k_sublvl2=0
|
||||||
|
fi
|
||||||
|
|
||||||
# Apply distro-specific logic
|
# Apply distro-specific logic
|
||||||
case "$distro" in
|
case "$distro" in
|
||||||
"rhel")
|
"rhel")
|
||||||
|
|||||||
+679
-596
File diff suppressed because it is too large
Load Diff
+37
-5
@@ -1,6 +1,6 @@
|
|||||||
.\" lszcrypt.8
|
.\" lszcrypt.8
|
||||||
.\"
|
.\"
|
||||||
.\" Copyright 2019 IBM Corp.
|
.\" Copyright IBM Corp. 2019, 2022
|
||||||
.\" s390-tools is free software; you can redistribute it and/or modify
|
.\" s390-tools is free software; you can redistribute it and/or modify
|
||||||
.\" it under the terms of the MIT license. See LICENSE for details.
|
.\" it under the terms of the MIT license. See LICENSE for details.
|
||||||
.\"
|
.\"
|
||||||
@@ -10,13 +10,14 @@
|
|||||||
.\" nroff -man lszcrypt.8
|
.\" nroff -man lszcrypt.8
|
||||||
.\" to process this source
|
.\" to process this source
|
||||||
.\"
|
.\"
|
||||||
.TH LSZCRYPT 8 "OCT 2020" "s390-tools"
|
.TH LSZCRYPT 8 "FEB 2022" "s390-tools"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
lszcrypt \- display zcrypt device and configuration information
|
lszcrypt \- display zcrypt device and configuration information
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.TP 9
|
.TP 9
|
||||||
.B lszcrypt
|
.B lszcrypt
|
||||||
.RB "[ " -V " ] "
|
.RB "[" <filteroptions> "]"
|
||||||
|
.RB "[" -V "]"
|
||||||
[
|
[
|
||||||
.I <device-id>
|
.I <device-id>
|
||||||
[...]]
|
[...]]
|
||||||
@@ -31,7 +32,12 @@ lszcrypt \- display zcrypt device and configuration information
|
|||||||
.TP
|
.TP
|
||||||
.B lszcrypt -h
|
.B lszcrypt -h
|
||||||
.TP
|
.TP
|
||||||
|
.B lszcrypt -s
|
||||||
|
.TP
|
||||||
.B lszcrypt -v
|
.B lszcrypt -v
|
||||||
|
. TP
|
||||||
|
.B <filteroptions>
|
||||||
|
[--accelonly|--ccaonly|--ep11only] [--cardonly|--queueonly]
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
The
|
The
|
||||||
.B lszcrypt
|
.B lszcrypt
|
||||||
@@ -109,8 +115,26 @@ B - indicate both (control and usage domain)
|
|||||||
.B -h, --help
|
.B -h, --help
|
||||||
Displays help text and exits.
|
Displays help text and exits.
|
||||||
.TP 8
|
.TP 8
|
||||||
|
.B -s, --serial
|
||||||
|
Shows the serial numbers for CCA and EP11 crypto cards.
|
||||||
|
.TP 8
|
||||||
.B -v, --version
|
.B -v, --version
|
||||||
Displays version information and exits.
|
Displays version information and exits.
|
||||||
|
.TP 8
|
||||||
|
.B --accelonly
|
||||||
|
Show only information for cards/queues in Accelerator mode.
|
||||||
|
.TP 8
|
||||||
|
.B --ccaonly
|
||||||
|
Show only information for cards/queues in CCA-Coprocessor mode.
|
||||||
|
.TP 8
|
||||||
|
.B --ep11only
|
||||||
|
Show only information for cards/queues in EP11-Coprocessor mode.
|
||||||
|
.TP 8
|
||||||
|
.B --cardonly
|
||||||
|
Show only information for cards but no queue info.
|
||||||
|
.TP 8
|
||||||
|
.B --queueonly
|
||||||
|
Show only information for queues but no card info.
|
||||||
.SH LISTING DETAILS
|
.SH LISTING DETAILS
|
||||||
Here is an explanation of the columns displayed. Please note that some
|
Here is an explanation of the columns displayed. Please note that some
|
||||||
of the columns show up in verbose mode only.
|
of the columns show up in verbose mode only.
|
||||||
@@ -123,7 +147,7 @@ dot for a queue line.
|
|||||||
.B TYPE and HWTYPE
|
.B TYPE and HWTYPE
|
||||||
The HWTYPE is a numeric value showing which type of hardware the zcrypt
|
The HWTYPE is a numeric value showing which type of hardware the zcrypt
|
||||||
device driver presumes that this crypto card is. The currently known values
|
device driver presumes that this crypto card is. The currently known values
|
||||||
are 7=CEX3C, 8=CEX3A, 10=CEX4, 11=CEX5, 12=CEX6 and 13=CEX7.
|
are 7=CEX3C, 8=CEX3A, 10=CEX4, 11=CEX5, 12=CEX6, 13=CEX7 and 14=CEX8.
|
||||||
.br
|
.br
|
||||||
The TYPE is a human readable value showing the hardware type and the basic
|
The TYPE is a human readable value showing the hardware type and the basic
|
||||||
function type (A=Accelerator, C=CCA Coprocessor, P=EP11 Coprocessor). So
|
function type (A=Accelerator, C=CCA Coprocessor, P=EP11 Coprocessor). So
|
||||||
@@ -154,6 +178,9 @@ cryptographic operations. 'offline' is displayed when a card or queue
|
|||||||
is switched to (software) offline. If a card is 'deconfigured' via
|
is switched to (software) offline. If a card is 'deconfigured' via
|
||||||
HMC, SE or chzcrypt the field shows 'deconfig'.
|
HMC, SE or chzcrypt the field shows 'deconfig'.
|
||||||
.br
|
.br
|
||||||
|
A crypto card may also reach a 'checkstopped' state. lszcrypt shows
|
||||||
|
this as 'chkstop'.
|
||||||
|
.br
|
||||||
If a queue is not bound to a device driver there is no detailed
|
If a queue is not bound to a device driver there is no detailed
|
||||||
information available and thus the status shows only '-'.
|
information available and thus the status shows only '-'.
|
||||||
.br
|
.br
|
||||||
@@ -204,12 +231,17 @@ operations within the guests.
|
|||||||
.B DRIVER
|
.B DRIVER
|
||||||
.br
|
.br
|
||||||
Shows which card or queue device driver currently handles this crypto
|
Shows which card or queue device driver currently handles this crypto
|
||||||
resource. Currently known drivers are cex4card/cex4queue (CEX4-CEX7
|
resource. Currently known drivers are cex4card/cex4queue (CEX4-CEX8
|
||||||
hardware), cex2card/cex2cqueue (CEX2C and CEX3C hardware),
|
hardware), cex2card/cex2cqueue (CEX2C and CEX3C hardware),
|
||||||
cex2acard/cex2aqueue (CEX2A and CEX3A hardware) and vfio_ap (queue reserved
|
cex2acard/cex2aqueue (CEX2A and CEX3A hardware) and vfio_ap (queue reserved
|
||||||
for use by kvm hypervisor for kvm guests and not accessible to host
|
for use by kvm hypervisor for kvm guests and not accessible to host
|
||||||
applications). It is also valid to have no driver handling a queue which is
|
applications). It is also valid to have no driver handling a queue which is
|
||||||
shown as a -no-driver- entry.
|
shown as a -no-driver- entry.
|
||||||
|
.SH NOTES
|
||||||
|
Use only one of the mode filtering options --accelonly, --ccaonly, --ep11only.
|
||||||
|
Same with card/queue filtering: Use only one of --cardonly, --queueonly.
|
||||||
|
However, one of the mode filtering options and one of the card/queue filtering
|
||||||
|
can be combined.
|
||||||
.SH EXAMPLES
|
.SH EXAMPLES
|
||||||
.TP
|
.TP
|
||||||
.B lszcrypt
|
.B lszcrypt
|
||||||
|
|||||||
+210
-20
@@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* lszcrypt - Display zcrypt devices and configuration settings
|
* lszcrypt - Display zcrypt devices and configuration settings
|
||||||
*
|
*
|
||||||
* Copyright IBM Corp. 2008, 2020
|
* Copyright IBM Corp. 2008, 2022
|
||||||
*
|
*
|
||||||
* s390-tools is free software; you can redistribute it and/or modify
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
@@ -29,6 +29,11 @@
|
|||||||
*/
|
*/
|
||||||
static struct lszcrypt_l {
|
static struct lszcrypt_l {
|
||||||
int verbose;
|
int verbose;
|
||||||
|
int showaccel;
|
||||||
|
int showcca;
|
||||||
|
int showep11;
|
||||||
|
int showcard;
|
||||||
|
int showqueue;
|
||||||
} l;
|
} l;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -39,6 +44,7 @@ static struct lszcrypt_l {
|
|||||||
#define CAP_CCA "CCA Secure Key"
|
#define CAP_CCA "CCA Secure Key"
|
||||||
#define CAP_RNG "Long RNG"
|
#define CAP_RNG "Long RNG"
|
||||||
#define CAP_EP11 "EP11 Secure Key"
|
#define CAP_EP11 "EP11 Secure Key"
|
||||||
|
#define CAP_APMMS "AP bus max message size limit %ld Kb"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Card types
|
* Card types
|
||||||
@@ -95,6 +101,13 @@ static const struct util_prg prg = {
|
|||||||
/*
|
/*
|
||||||
* Configuration of command line options
|
* Configuration of command line options
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define OPT_ACCELONLY 0x81
|
||||||
|
#define OPT_CCAONLY 0x82
|
||||||
|
#define OPT_EP11ONLY 0x83
|
||||||
|
#define OPT_CARDONLY 0x84
|
||||||
|
#define OPT_QUEUEONLY 0x85
|
||||||
|
|
||||||
static struct util_opt opt_vec[] = {
|
static struct util_opt opt_vec[] = {
|
||||||
{
|
{
|
||||||
.option = {"bus", 0, NULL, 'b'},
|
.option = {"bus", 0, NULL, 'b'},
|
||||||
@@ -113,6 +126,35 @@ static struct util_opt opt_vec[] = {
|
|||||||
.option = {"verbose", 0, NULL, 'V'},
|
.option = {"verbose", 0, NULL, 'V'},
|
||||||
.desc = "Print verbose messages",
|
.desc = "Print verbose messages",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.option = {"accelonly", 0, NULL, OPT_ACCELONLY},
|
||||||
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
||||||
|
.desc = "Show only information from cards/queues in Accelerator mode",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.option = {"ccaonly", 0, NULL, OPT_CCAONLY},
|
||||||
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
||||||
|
.desc = "Show only information from cards/queues in CCA-Coprocessor mode",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.option = {"ep11only", 0, NULL, OPT_EP11ONLY},
|
||||||
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
||||||
|
.desc = "Show only information from cards/queues in EP11-Coprocessor mode",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.option = {"cardonly", 0, NULL, OPT_CARDONLY},
|
||||||
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
||||||
|
.desc = "Show only information from cards but no queue info",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.option = {"queueonly", 0, NULL, OPT_QUEUEONLY},
|
||||||
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
||||||
|
.desc = "Show only information from queues but no card info",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.option = {"serial", 0, NULL, 's'},
|
||||||
|
.desc = "Show the serial numbers for CCA and EP11 crypto cards",
|
||||||
|
},
|
||||||
UTIL_OPT_HELP,
|
UTIL_OPT_HELP,
|
||||||
UTIL_OPT_VERSION,
|
UTIL_OPT_VERSION,
|
||||||
UTIL_OPT_END
|
UTIL_OPT_END
|
||||||
@@ -247,13 +289,94 @@ static void show_domains(void)
|
|||||||
show_domains_util_rec(domain_array);
|
show_domains_util_rec(domain_array);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Show serialnumbers
|
||||||
|
*/
|
||||||
|
static void show_serialnumbers(void)
|
||||||
|
{
|
||||||
|
struct util_rec *rec = util_rec_new_wide("-");
|
||||||
|
struct dirent **dev_vec;
|
||||||
|
int i, count;
|
||||||
|
char *ap, *path, *device, *grp_dev, card[16], buf[256];
|
||||||
|
long config = -1, online = -1, chkstop = -1;
|
||||||
|
unsigned long facility;
|
||||||
|
|
||||||
|
/* check if ap driver is available */
|
||||||
|
ap = util_path_sysfs("bus/ap");
|
||||||
|
if (!util_path_is_dir(ap))
|
||||||
|
errx(EXIT_FAILURE, "Crypto device driver not available.");
|
||||||
|
|
||||||
|
/* define the record */
|
||||||
|
util_rec_def(rec, "card", UTIL_REC_ALIGN_LEFT, 8, "CARD.DOM");
|
||||||
|
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, "status", UTIL_REC_ALIGN_LEFT, 10, "STATUS");
|
||||||
|
util_rec_def(rec, "serialnr", UTIL_REC_ALIGN_LEFT, 8, "SERIALNR");
|
||||||
|
|
||||||
|
/* scan the devices */
|
||||||
|
path = util_path_sysfs("devices/ap/");
|
||||||
|
count = util_scandir(&dev_vec, alphasort, path, "card[0-9a-fA-F]+");
|
||||||
|
if (count < 1)
|
||||||
|
errx(EXIT_FAILURE, "No crypto card devices found.");
|
||||||
|
util_rec_print_hdr(rec);
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
device = dev_vec[i]->d_name;
|
||||||
|
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);
|
||||||
|
if (!util_path_is_readable("%s/type", grp_dev) ||
|
||||||
|
!util_path_is_readable("%s/online", grp_dev))
|
||||||
|
goto next;
|
||||||
|
strcpy(card, device + 4);
|
||||||
|
util_rec_set(rec, "card", card);
|
||||||
|
util_file_read_line(buf, sizeof(buf), "%s/type", grp_dev);
|
||||||
|
util_rec_set(rec, "type", buf);
|
||||||
|
util_file_read_ul(&facility, 16, "%s/ap_functions", grp_dev);
|
||||||
|
if (facility & MASK_COPRO)
|
||||||
|
util_rec_set(rec, "mode", "CCA-Coproc");
|
||||||
|
else if (facility & MASK_EP11)
|
||||||
|
util_rec_set(rec, "mode", "EP11-Coproc");
|
||||||
|
else
|
||||||
|
goto next;
|
||||||
|
if (util_path_is_readable("%s/config", grp_dev))
|
||||||
|
util_file_read_l(&config, 10, "%s/config", grp_dev);
|
||||||
|
if (util_path_is_readable("%s/chkstop", grp_dev))
|
||||||
|
util_file_read_l(&chkstop, 10, "%s/chkstop", grp_dev);
|
||||||
|
if (util_path_is_readable("%s/online", grp_dev))
|
||||||
|
util_file_read_l(&online, 10, "%s/online", grp_dev);
|
||||||
|
if (config == 0) {
|
||||||
|
util_rec_set(rec, "status", "deconfig");
|
||||||
|
} else {
|
||||||
|
if (chkstop > 0)
|
||||||
|
util_rec_set(rec, "status", "chkstop");
|
||||||
|
else if (online > 0)
|
||||||
|
util_rec_set(rec, "status", "online");
|
||||||
|
else if (online == 0)
|
||||||
|
util_rec_set(rec, "status", "offline");
|
||||||
|
else
|
||||||
|
util_rec_set(rec, "status", "-");
|
||||||
|
}
|
||||||
|
if (util_file_read_line(buf, sizeof(buf), "%s/serialnr", grp_dev))
|
||||||
|
util_rec_set(rec, "serialnr", "-");
|
||||||
|
else {
|
||||||
|
buf[8] = '\0';
|
||||||
|
util_rec_set(rec, "serialnr", buf);
|
||||||
|
}
|
||||||
|
util_rec_print(rec);
|
||||||
|
next:
|
||||||
|
free(grp_dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(path);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Show capability
|
* Show capability
|
||||||
*/
|
*/
|
||||||
static void show_capability(const char *id_str)
|
static void show_capability(const char *id_str)
|
||||||
{
|
{
|
||||||
unsigned long func_val;
|
unsigned long func_val;
|
||||||
long hwtype, id;
|
long hwtype, id, max_msg_size;
|
||||||
char *p, *ap, *dev, card[16], cbuf[256];
|
char *p, *ap, *dev, card[16], cbuf[256];
|
||||||
|
|
||||||
/* check if ap driver is available */
|
/* check if ap driver is available */
|
||||||
@@ -272,6 +395,9 @@ static void show_capability(const char *id_str)
|
|||||||
/* If sysfs attribute is missing, set functions to 0 */
|
/* If sysfs attribute is missing, set functions to 0 */
|
||||||
if (util_file_read_ul(&func_val, 16, "%s/ap_functions", dev))
|
if (util_file_read_ul(&func_val, 16, "%s/ap_functions", dev))
|
||||||
func_val = 0x00000000;
|
func_val = 0x00000000;
|
||||||
|
/* try to read the ap bus max message size for this card */
|
||||||
|
if (util_file_read_l(&max_msg_size, 10, "%s/max_msg_size", dev))
|
||||||
|
max_msg_size = 0;
|
||||||
/* Skip devices, which are not supported by zcrypt layer */
|
/* Skip devices, which are not supported by zcrypt layer */
|
||||||
if (!util_path_is_readable("%s/type", dev) ||
|
if (!util_path_is_readable("%s/type", dev) ||
|
||||||
!util_path_is_readable("%s/online", dev)) {
|
!util_path_is_readable("%s/online", dev)) {
|
||||||
@@ -289,9 +415,9 @@ static void show_capability(const char *id_str)
|
|||||||
case 6:
|
case 6:
|
||||||
case 8:
|
case 8:
|
||||||
if (func_val & MASK_RSA4K)
|
if (func_val & MASK_RSA4K)
|
||||||
printf("%s", CAP_RSA4K);
|
printf("%s\n", CAP_RSA4K);
|
||||||
else
|
else
|
||||||
printf("%s", CAP_RSA2K);
|
printf("%s\n", CAP_RSA2K);
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
case 9:
|
case 9:
|
||||||
@@ -300,37 +426,39 @@ static void show_capability(const char *id_str)
|
|||||||
printf("%s (%s)\n", CAP_CCA, cbuf);
|
printf("%s (%s)\n", CAP_CCA, cbuf);
|
||||||
else
|
else
|
||||||
printf("%s\n", CAP_CCA);
|
printf("%s\n", CAP_CCA);
|
||||||
printf("%s", CAP_RNG);
|
printf("%s\n", CAP_RNG);
|
||||||
break;
|
break;
|
||||||
case 10: /* CEX4S */
|
case 10: /* CEX4S */
|
||||||
case 11: /* CEX5S */
|
case 11: /* CEX5S */
|
||||||
case 12: /* CEX6S */
|
case 12: /* CEX6S */
|
||||||
case 13: /* CEX7S */
|
case 13: /* CEX7S */
|
||||||
|
case 14: /* CEX8S */
|
||||||
if (func_val & MASK_ACCEL) {
|
if (func_val & MASK_ACCEL) {
|
||||||
if (func_val & MASK_RSA4K)
|
if (func_val & MASK_RSA4K)
|
||||||
printf("%s", CAP_RSA4K);
|
printf("%s\n", CAP_RSA4K);
|
||||||
else
|
else
|
||||||
printf("%s", CAP_RSA2K);
|
printf("%s\n", CAP_RSA2K);
|
||||||
} else if (func_val & MASK_COPRO) {
|
} else if (func_val & MASK_COPRO) {
|
||||||
printf("%s\n", CAP_RSA4K);
|
printf("%s\n", CAP_RSA4K);
|
||||||
if (cbuf[0])
|
if (cbuf[0])
|
||||||
printf("%s (%s)\n", CAP_CCA, cbuf);
|
printf("%s (%s)\n", CAP_CCA, cbuf);
|
||||||
else
|
else
|
||||||
printf("%s\n", CAP_CCA);
|
printf("%s\n", CAP_CCA);
|
||||||
printf("%s", CAP_RNG);
|
printf("%s\n", CAP_RNG);
|
||||||
} else if (func_val & MASK_EP11) {
|
} else if (func_val & MASK_EP11) {
|
||||||
printf("%s", CAP_EP11);
|
printf("%s\n", CAP_EP11);
|
||||||
} else {
|
} else {
|
||||||
printf("Detailed capability information for %s (hardware type %ld) is not available.",
|
printf("Detailed capability information for %s (hardware type %ld) is not available.\n",
|
||||||
card, hwtype);
|
card, hwtype);
|
||||||
}
|
}
|
||||||
|
if (max_msg_size > 0)
|
||||||
|
printf(CAP_APMMS "\n", max_msg_size / 1024);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printf("Detailed capability information for %s (hardware type %ld) is not available.",
|
printf("Detailed capability information for %s (hardware type %ld) is not available.\n",
|
||||||
card, hwtype);
|
card, hwtype);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
printf("\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -375,7 +503,7 @@ static int read_driver(const char *dir, const char *subdir, char *buf, size_t bu
|
|||||||
static void read_subdev_rec_default(struct util_rec *rec, const char *grp_dev,
|
static void read_subdev_rec_default(struct util_rec *rec, const char *grp_dev,
|
||||||
const char *sub_dev)
|
const char *sub_dev)
|
||||||
{
|
{
|
||||||
long config = -1, online = -1;
|
long config = -1, online = -1, chkstop = -1;
|
||||||
char buf[256];
|
char buf[256];
|
||||||
unsigned long facility;
|
unsigned long facility;
|
||||||
|
|
||||||
@@ -386,6 +514,8 @@ static void read_subdev_rec_default(struct util_rec *rec, const char *grp_dev,
|
|||||||
|
|
||||||
if (util_path_is_readable("%s/%s/config", grp_dev, sub_dev))
|
if (util_path_is_readable("%s/%s/config", grp_dev, sub_dev))
|
||||||
util_file_read_l(&config, 10, "%s/%s/config", grp_dev, sub_dev);
|
util_file_read_l(&config, 10, "%s/%s/config", grp_dev, sub_dev);
|
||||||
|
if (util_path_is_readable("%s/%s/chkstop", grp_dev, sub_dev))
|
||||||
|
util_file_read_l(&chkstop, 10, "%s/%s/chkstop", grp_dev, sub_dev);
|
||||||
if (util_path_is_readable("%s/%s/online", grp_dev, sub_dev))
|
if (util_path_is_readable("%s/%s/online", grp_dev, sub_dev))
|
||||||
util_file_read_l(&online, 10, "%s/%s/online", grp_dev, sub_dev);
|
util_file_read_l(&online, 10, "%s/%s/online", grp_dev, sub_dev);
|
||||||
|
|
||||||
@@ -393,7 +523,9 @@ static void read_subdev_rec_default(struct util_rec *rec, const char *grp_dev,
|
|||||||
if (config == 0) {
|
if (config == 0) {
|
||||||
util_rec_set(rec, "status", "deconfig");
|
util_rec_set(rec, "status", "deconfig");
|
||||||
} else {
|
} else {
|
||||||
if (online > 0)
|
if (chkstop > 0)
|
||||||
|
util_rec_set(rec, "status", "chkstop");
|
||||||
|
else if (online > 0)
|
||||||
util_rec_set(rec, "status", "online");
|
util_rec_set(rec, "status", "online");
|
||||||
else if (online == 0)
|
else if (online == 0)
|
||||||
util_rec_set(rec, "status", "offline");
|
util_rec_set(rec, "status", "offline");
|
||||||
@@ -489,6 +621,9 @@ static void show_subdevice(struct util_rec *rec, const char *grp_dev,
|
|||||||
!util_path_is_readable("%s/%s/online", grp_dev, sub_dev)))
|
!util_path_is_readable("%s/%s/online", grp_dev, sub_dev)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!l.showqueue)
|
||||||
|
return;
|
||||||
|
|
||||||
util_rec_set(rec, "card", sub_dev);
|
util_rec_set(rec, "card", sub_dev);
|
||||||
read_subdev_rec_default(rec, grp_dev, sub_dev);
|
read_subdev_rec_default(rec, grp_dev, sub_dev);
|
||||||
read_subdev_rec_verbose(rec, grp_dev, sub_dev);
|
read_subdev_rec_verbose(rec, grp_dev, sub_dev);
|
||||||
@@ -516,7 +651,7 @@ 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)
|
static void read_rec_default(struct util_rec *rec, const char *grp_dev)
|
||||||
{
|
{
|
||||||
long config = -1, online = -1;
|
long config = -1, online = -1, chkstop = -1;
|
||||||
char buf[256];
|
char buf[256];
|
||||||
unsigned long facility;
|
unsigned long facility;
|
||||||
|
|
||||||
@@ -537,12 +672,16 @@ static void read_rec_default(struct util_rec *rec, const char *grp_dev)
|
|||||||
|
|
||||||
if (util_path_is_readable("%s/config", grp_dev))
|
if (util_path_is_readable("%s/config", grp_dev))
|
||||||
util_file_read_l(&config, 10, "%s/config", grp_dev);
|
util_file_read_l(&config, 10, "%s/config", grp_dev);
|
||||||
|
if (util_path_is_readable("%s/chkstop", grp_dev))
|
||||||
|
util_file_read_l(&chkstop, 10, "%s/chkstop", grp_dev);
|
||||||
if (util_path_is_readable("%s/online", grp_dev))
|
if (util_path_is_readable("%s/online", grp_dev))
|
||||||
util_file_read_l(&online, 10, "%s/online", grp_dev);
|
util_file_read_l(&online, 10, "%s/online", grp_dev);
|
||||||
if (config == 0) {
|
if (config == 0) {
|
||||||
util_rec_set(rec, "status", "deconfig");
|
util_rec_set(rec, "status", "deconfig");
|
||||||
} else {
|
} else {
|
||||||
if (online > 0)
|
if (chkstop > 0)
|
||||||
|
util_rec_set(rec, "status", "chkstop");
|
||||||
|
else if (online > 0)
|
||||||
util_rec_set(rec, "status", "online");
|
util_rec_set(rec, "status", "online");
|
||||||
else if (online == 0)
|
else if (online == 0)
|
||||||
util_rec_set(rec, "status", "offline");
|
util_rec_set(rec, "status", "offline");
|
||||||
@@ -603,7 +742,7 @@ static void read_rec_verbose(struct util_rec *rec, const char *grp_dev)
|
|||||||
*/
|
*/
|
||||||
static void show_device(struct util_rec *rec, const char *device)
|
static void show_device(struct util_rec *rec, const char *device)
|
||||||
{
|
{
|
||||||
char *grp_dev, card[16];
|
char *grp_dev, card[16], type[16], t = '\0';
|
||||||
|
|
||||||
strcpy(card, &device[4]);
|
strcpy(card, &device[4]);
|
||||||
grp_dev = util_path_sysfs("devices/ap/%s", device);
|
grp_dev = util_path_sysfs("devices/ap/%s", device);
|
||||||
@@ -621,11 +760,21 @@ static void show_device(struct util_rec *rec, const char *device)
|
|||||||
}
|
}
|
||||||
util_rec_set(rec, "card", card);
|
util_rec_set(rec, "card", card);
|
||||||
|
|
||||||
|
if (util_file_read_line(type, sizeof(type), "%s/type", grp_dev) == 0)
|
||||||
|
t = type[strlen(type) - 1];
|
||||||
|
|
||||||
|
if ((t == 'A' && !l.showaccel) ||
|
||||||
|
(t == 'C' && !l.showcca) ||
|
||||||
|
(t == 'P' && !l.showep11))
|
||||||
|
goto out_free;
|
||||||
|
|
||||||
read_rec_default(rec, grp_dev);
|
read_rec_default(rec, grp_dev);
|
||||||
read_rec_verbose(rec, grp_dev);
|
read_rec_verbose(rec, grp_dev);
|
||||||
|
|
||||||
util_rec_print(rec);
|
if (l.showcard)
|
||||||
show_subdevices(rec, grp_dev);
|
util_rec_print(rec);
|
||||||
|
if (l.showqueue)
|
||||||
|
show_subdevices(rec, grp_dev);
|
||||||
out_free:
|
out_free:
|
||||||
free(grp_dev);
|
free(grp_dev);
|
||||||
}
|
}
|
||||||
@@ -799,9 +948,27 @@ int main(int argc, char **argv)
|
|||||||
case 'd':
|
case 'd':
|
||||||
show_domains();
|
show_domains();
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
case 's':
|
||||||
|
show_serialnumbers();
|
||||||
|
return EXIT_SUCCESS;
|
||||||
case 'V':
|
case 'V':
|
||||||
l.verbose++;
|
l.verbose++;
|
||||||
break;
|
break;
|
||||||
|
case OPT_ACCELONLY:
|
||||||
|
l.showaccel = 1;
|
||||||
|
break;
|
||||||
|
case OPT_CCAONLY:
|
||||||
|
l.showcca = 1;
|
||||||
|
break;
|
||||||
|
case OPT_EP11ONLY:
|
||||||
|
l.showep11 = 1;
|
||||||
|
break;
|
||||||
|
case OPT_CARDONLY:
|
||||||
|
l.showcard = 1;
|
||||||
|
break;
|
||||||
|
case OPT_QUEUEONLY:
|
||||||
|
l.showqueue = 1;
|
||||||
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
util_prg_print_help();
|
util_prg_print_help();
|
||||||
util_opt_print_help();
|
util_opt_print_help();
|
||||||
@@ -815,6 +982,29 @@ int main(int argc, char **argv)
|
|||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (l.showaccel + l.showcca + l.showep11) {
|
||||||
|
case 0:
|
||||||
|
l.showaccel = l.showcca = l.showep11 = 1;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
warnx("Only one of --accelonly or --ccaonly or --ep11only can be specified");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (l.showcard + l.showqueue) {
|
||||||
|
case 0:
|
||||||
|
l.showcard = l.showqueue = 1;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
warnx("Only one of --cardonly or --queueonly can be specified");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
if (optind == argc)
|
if (optind == argc)
|
||||||
show_devices_all();
|
show_devices_all();
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.\" zcryptctl.8
|
.\" zcryptctl.8
|
||||||
.\"
|
.\"
|
||||||
.\" Copyright 2018 IBM Corp.
|
.\" Copyright 2018, 2022 IBM Corp.
|
||||||
.\" s390-tools is free software; you can redistribute it and/or modify
|
.\" s390-tools is free software; you can redistribute it and/or modify
|
||||||
.\" it under the terms of the MIT license. See LICENSE for details.
|
.\" it under the terms of the MIT license. See LICENSE for details.
|
||||||
.\"
|
.\"
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
.\" nroff -man zcryptctl.8
|
.\" nroff -man zcryptctl.8
|
||||||
.\" to process this source
|
.\" to process this source
|
||||||
.\"
|
.\"
|
||||||
.TH ZCRYPTCTL 8 "AUG 2018" "s390-tools"
|
.TH ZCRYPTCTL 8 "JAN 2022" "s390-tools"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
zcryptctl \- display information and administrate zcrypt multiple device nodes
|
zcryptctl \- display information and administrate zcrypt multiple device nodes
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
@@ -35,6 +35,11 @@ zcryptctl \- display information and administrate zcrypt multiple device nodes
|
|||||||
.B deldom
|
.B deldom
|
||||||
.I node-name domain-nr
|
.I node-name domain-nr
|
||||||
.TP
|
.TP
|
||||||
|
.B zcryptctl addctrl
|
||||||
|
.R |
|
||||||
|
.B delctrl
|
||||||
|
.I node-name domain-nr
|
||||||
|
.TP
|
||||||
.B zcryptctl addioctl
|
.B zcryptctl addioctl
|
||||||
.R |
|
.R |
|
||||||
.B delioctl
|
.B delioctl
|
||||||
@@ -57,6 +62,7 @@ driver. Each zcrypt device node can be restricted in terms of crypto
|
|||||||
cards, domains, and available ioctls. Such a device node can be used
|
cards, domains, and available ioctls. Such a device node can be used
|
||||||
as a base for container solutions like Docker to control and restrict
|
as a base for container solutions like Docker to control and restrict
|
||||||
the access to crypto resources.
|
the access to crypto resources.
|
||||||
|
See the NOTES section below for information on control domains.
|
||||||
.SH COMMANDS
|
.SH COMMANDS
|
||||||
.TP 8
|
.TP 8
|
||||||
.B zcryptctl list
|
.B zcryptctl list
|
||||||
@@ -96,6 +102,14 @@ Update the filter for the specified zcrypt device node and add or
|
|||||||
delete a domain to be accessible through this node. The symbol
|
delete a domain to be accessible through this node. The symbol
|
||||||
\fBALL\fP can be used to enable or disable all domains.
|
\fBALL\fP can be used to enable or disable all domains.
|
||||||
.TP
|
.TP
|
||||||
|
.B zcryptctl addctrl
|
||||||
|
.R |
|
||||||
|
.B delctrl
|
||||||
|
.I node-name domain-nr
|
||||||
|
Update the filter for the specified zcrypt device node and add or
|
||||||
|
delete a control domain to be accessible through this node. The symbol
|
||||||
|
\fBALL\fP can be used to enable or disable all domains.
|
||||||
|
.TP
|
||||||
.B zcryptctl addioctl
|
.B zcryptctl addioctl
|
||||||
.R |
|
.R |
|
||||||
.B delioctl
|
.B delioctl
|
||||||
@@ -116,19 +130,20 @@ line and the settings are applied. Syntax is simple:
|
|||||||
.IP "node=<node-name>"
|
.IP "node=<node-name>"
|
||||||
.IP "aps=<list of ap numbers separated by space, tab or ','>"
|
.IP "aps=<list of ap numbers separated by space, tab or ','>"
|
||||||
.IP "doms=<list of domain numbers separated by space, tab or ','>"
|
.IP "doms=<list of domain numbers separated by space, tab or ','>"
|
||||||
|
.IP "ctrls=<list of control domain numbers separated by space, tab or ','>"
|
||||||
.IP "ioctls=<list of ioctl as numeric or symbolic number separated by space, tab or ','>"
|
.IP "ioctls=<list of ioctl as numeric or symbolic number separated by space, tab or ','>"
|
||||||
.LP
|
.LP
|
||||||
Empty lines are ignored and the '#' marks the rest of the
|
Empty lines are ignored and the '#' marks the rest of the
|
||||||
line as comment.
|
line as comment.
|
||||||
.LP
|
.LP
|
||||||
The \fBnode=\fP line creates a new zcrypt device node, the \fBaps=\fP,
|
The \fBnode=\fP line creates a new zcrypt device node, the \fBaps=\fP,
|
||||||
\fBdoms=\fP and \fBioctls=\fP lines customize the previously created
|
\fBdoms=\fP, \fBctrls=\fP and \fBioctls=\fP lines customize the
|
||||||
node. The symbol \fBALL\fP is also recognized for aps, doms, and
|
previously created node. The symbol \fBALL\fP is also recognized for
|
||||||
ioctls.
|
aps, doms, and ioctls.
|
||||||
.LP
|
.LP
|
||||||
Each action must fit into one line, spreading over multiple lines is
|
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
|
not supported. But you can use more than one \fBaps=\fP, \fBdoms=\fP,
|
||||||
and \fBioctls=\fP lines to customize the very same node.
|
\fBctrls=\fP and \fBioctls=\fP lines to customize the very same node.
|
||||||
.LP
|
.LP
|
||||||
Processing stops when a line cannot be parsed or the current action
|
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
|
fails. In this case the exit status is non zero but the successful
|
||||||
@@ -139,6 +154,17 @@ actions until the failure occurs are not rolled back.
|
|||||||
List the current configuration in a form suitable for input to the
|
List the current configuration in a form suitable for input to the
|
||||||
\fBzcryptctl config\fP command.
|
\fBzcryptctl config\fP command.
|
||||||
.LP
|
.LP
|
||||||
|
.SH NOTES
|
||||||
|
|
||||||
|
Control domain filtering is only supported for custom device
|
||||||
|
<nodename> if the \fBadmask\fP file in sysfs under
|
||||||
|
/sys/class/zcrypt/<nodename>/admask exists. If this file does not
|
||||||
|
exist, the kernel is too old and does not support control command
|
||||||
|
filtering. This is the same effect as setting the control domain mask
|
||||||
|
to ALL. Note that, even though you can allow more than available to
|
||||||
|
the system, you can only send control commands to control domains
|
||||||
|
available to the system.
|
||||||
|
|
||||||
.SH EXIT STATUS
|
.SH EXIT STATUS
|
||||||
On successful completion of the command the exit status is 0. A non
|
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
|
zero return code (and some kind of failure message) is emitted if the
|
||||||
|
|||||||
+121
-4
@@ -2,7 +2,7 @@
|
|||||||
* zcryptctl - Maintain zcrypt multi device nodes.
|
* zcryptctl - Maintain zcrypt multi device nodes.
|
||||||
*
|
*
|
||||||
* by Harald Freudenberger <freude@linux.ibm.com>
|
* by Harald Freudenberger <freude@linux.ibm.com>
|
||||||
* Copyright IBM Corp. 2018
|
* Copyright IBM Corp. 2018, 2022
|
||||||
*
|
*
|
||||||
* s390-tools is free software; you can redistribute it and/or modify
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
@@ -58,6 +58,8 @@
|
|||||||
#define CMD_DEL_IOCTL 0x0009
|
#define CMD_DEL_IOCTL 0x0009
|
||||||
#define CMD_CONFIG 0x000A
|
#define CMD_CONFIG 0x000A
|
||||||
#define CMD_LISTCONFIG 0x000B
|
#define CMD_LISTCONFIG 0x000B
|
||||||
|
#define CMD_ADD_CTRL 0x000C
|
||||||
|
#define CMD_DEL_CTRL 0x000D
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Program configuration
|
* Program configuration
|
||||||
@@ -70,7 +72,7 @@ static const struct util_prg prg = {
|
|||||||
{
|
{
|
||||||
.owner = "IBM Corp.",
|
.owner = "IBM Corp.",
|
||||||
.pub_first = 2018,
|
.pub_first = 2018,
|
||||||
.pub_last = 2018,
|
.pub_last = 2022,
|
||||||
},
|
},
|
||||||
UTIL_PRG_COPYRIGHT_END
|
UTIL_PRG_COPYRIGHT_END
|
||||||
}
|
}
|
||||||
@@ -345,6 +347,18 @@ static int cmd_list(int cmd,
|
|||||||
if (test_bit(i, buf))
|
if (test_bit(i, buf))
|
||||||
printf("%c%d", n++ == 0 ? tab : ',', i);
|
printf("%c%d", n++ == 0 ? tab : ',', i);
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
|
if (cmd == CMD_LISTCONFIG)
|
||||||
|
printf(" ctrls =");
|
||||||
|
else
|
||||||
|
printf(" control domains:");
|
||||||
|
if (read_dn_attr(de->d_name, "admask", buf, sizeof(buf)) != 0)
|
||||||
|
errx(EXIT_FAILURE,
|
||||||
|
"Could not fetch admask 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)
|
if (cmd == CMD_LISTCONFIG)
|
||||||
printf(" ioctls =");
|
printf(" ioctls =");
|
||||||
else
|
else
|
||||||
@@ -526,6 +540,52 @@ static int cmd_add_del_dom(int cmd, const char *node, const char *arg)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void add_del_ctrl(int cmd, const char *node, int dom)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
char buf[PATH_MAX];
|
||||||
|
|
||||||
|
if (cmd == CMD_ADD_CTRL)
|
||||||
|
sprintf(buf, "+%d", dom);
|
||||||
|
else
|
||||||
|
sprintf(buf, "-%d", dom);
|
||||||
|
rc = write_dn_attr(node, "admask", buf);
|
||||||
|
if (rc != 0)
|
||||||
|
errx(EXIT_FAILURE,
|
||||||
|
"Could not write into sysfs entry to %s domain %d for zdev node '%s'",
|
||||||
|
cmd == CMD_ADD_CTRL ? "add" : "remove", dom, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmd_add_del_ctrl(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_ctrl(cmd, node, dom);
|
||||||
|
printf("Control domain %d %s\n", dom,
|
||||||
|
(cmd == CMD_ADD_CTRL ? "added" : "removed"));
|
||||||
|
} else {
|
||||||
|
for (dom = 0; dom < MAX_ZDEV_DOMAINS_EXT; dom++)
|
||||||
|
add_del_ctrl(cmd, node, dom);
|
||||||
|
printf("All control domains %s\n",
|
||||||
|
(cmd == CMD_ADD_CTRL ? "added" : "removed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void add_del_ioctl(int cmd, const char *node, int ioctlnr)
|
static void add_del_ioctl(int cmd, const char *node, int ioctlnr)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
@@ -694,12 +754,34 @@ static int cmd_config(int cmd _UNUSED_,
|
|||||||
break;
|
break;
|
||||||
if (!_match_string(&p, buf))
|
if (!_match_string(&p, buf))
|
||||||
errx(EXIT_FAILURE,
|
errx(EXIT_FAILURE,
|
||||||
"Missing argument(s) for aps=... at '%-8.8s...' in line %d '%s'",
|
"Missing argument(s) for doms=... at '%-8.8s...' in line %d '%s'",
|
||||||
p, nr, line);
|
p, nr, line);
|
||||||
cmd_add_del_dom(CMD_ADD_DOM, node, buf);
|
cmd_add_del_dom(CMD_ADD_DOM, node, buf);
|
||||||
while (isblank(*p) || *p == ',')
|
while (isblank(*p) || *p == ',')
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
|
} else if (_match_keyword(&p, "ctrls")) {
|
||||||
|
if (!havenode)
|
||||||
|
errx(EXIT_FAILURE,
|
||||||
|
"Missing node=... before processing any ctrls=... 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 ctrls=... at '%-8.8s...' in line %d '%s'",
|
||||||
|
p, nr, line);
|
||||||
|
cmd_add_del_ctrl(CMD_ADD_CTRL, node, buf);
|
||||||
|
while (isblank(*p) || *p == ',')
|
||||||
|
p++;
|
||||||
|
}
|
||||||
} else if (_match_keyword(&p, "ioctls")) {
|
} else if (_match_keyword(&p, "ioctls")) {
|
||||||
if (!havenode)
|
if (!havenode)
|
||||||
errx(EXIT_FAILURE,
|
errx(EXIT_FAILURE,
|
||||||
@@ -810,13 +892,35 @@ static struct zcryptctl_cmds_s {
|
|||||||
.cmd = CMD_DEL_DOM,
|
.cmd = CMD_DEL_DOM,
|
||||||
.command = "deldom",
|
.command = "deldom",
|
||||||
.function = cmd_add_del_dom,
|
.function = cmd_add_del_dom,
|
||||||
.usage = "zcryptctl deldom <adapter>",
|
.usage = "zcryptctl deldom <domain>",
|
||||||
.description =
|
.description =
|
||||||
"Update the filter for the specified zcrypt device node and\n"
|
"Update the filter for the specified zcrypt device node and\n"
|
||||||
"remove a crypto domain from the allowed domains list. The\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"
|
"domain argument may be a number in the range 0-255 or the\n"
|
||||||
"symbol ALL.",
|
"symbol ALL.",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.cmd = CMD_ADD_CTRL,
|
||||||
|
.command = "addctrl",
|
||||||
|
.function = cmd_add_del_ctrl,
|
||||||
|
.usage = "zcryptctl addctrl <domain>",
|
||||||
|
.description =
|
||||||
|
"Update the filter for the specified zcrypt device node and\n"
|
||||||
|
"add a crypto control domain to be accessible via this node.\n"
|
||||||
|
"The domain argument may be a number in the range 0-255 or\n"
|
||||||
|
"the symbol ALL.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.cmd = CMD_DEL_CTRL,
|
||||||
|
.command = "delctrl",
|
||||||
|
.function = cmd_add_del_ctrl,
|
||||||
|
.usage = "zcryptctl delctrl <domain>",
|
||||||
|
.description =
|
||||||
|
"Update the filter for the specified zcrypt device node and\n"
|
||||||
|
"remove a crypto control domain from the allowed domains list.\n"
|
||||||
|
"The domain argument may be a number in the range 0-255 or\n"
|
||||||
|
"the symbol ALL.",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.cmd = CMD_ADD_IOCTL,
|
.cmd = CMD_ADD_IOCTL,
|
||||||
.command = "addioctl",
|
.command = "addioctl",
|
||||||
@@ -1003,6 +1107,19 @@ int main(int argc, char *argv[])
|
|||||||
argv[optind + 1],
|
argv[optind + 1],
|
||||||
argv[optind + 2]);
|
argv[optind + 2]);
|
||||||
break;
|
break;
|
||||||
|
case CMD_ADD_CTRL:
|
||||||
|
case CMD_DEL_CTRL:
|
||||||
|
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_ADD_IOCTL:
|
||||||
case CMD_DEL_IOCTL:
|
case CMD_DEL_IOCTL:
|
||||||
if (optind + 1 >= argc)
|
if (optind + 1 >= argc)
|
||||||
|
|||||||
+16
-14
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* zcryptstats - Show usage statistics of IBM Crypto Express adapters
|
* zcryptstats - Show usage statistics of IBM Crypto Express adapters
|
||||||
*
|
*
|
||||||
* Copyright IBM Corp. 2019
|
* Copyright IBM Corp. 2019, 2022
|
||||||
*
|
*
|
||||||
* s390-tools is free software; you can redistribute it and/or modify
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
@@ -148,8 +148,9 @@ struct chsc_cmb_area {
|
|||||||
#define CRYPTO_TYPE_CEX5S 11
|
#define CRYPTO_TYPE_CEX5S 11
|
||||||
#define CRYPTO_TYPE_CEX6S 12
|
#define CRYPTO_TYPE_CEX6S 12
|
||||||
#define CRYPTO_TYPE_CEX7S 13
|
#define CRYPTO_TYPE_CEX7S 13
|
||||||
|
#define CRYPTO_TYPE_CEX8S 14
|
||||||
|
|
||||||
#define CRYPTO_TYPE_TOLERATION CRYPTO_TYPE_CEX7S
|
#define CRYPTO_TYPE_TOLERATION CRYPTO_TYPE_CEX8S
|
||||||
|
|
||||||
struct crypto_counter {
|
struct crypto_counter {
|
||||||
const char *name;
|
const char *name;
|
||||||
@@ -236,8 +237,8 @@ static const struct crypto_mode mode_pcica[1] = {
|
|||||||
.counters = counter_pcica },
|
.counters = counter_pcica },
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NUM_CEX4567_MODES 11
|
#define NUM_CEX45678_MODES 11
|
||||||
static const struct crypto_mode mode_cex4567[NUM_CEX4567_MODES] = {
|
static const struct crypto_mode mode_cex45678[NUM_CEX45678_MODES] = {
|
||||||
{ 0 },
|
{ 0 },
|
||||||
{ 0 },
|
{ 0 },
|
||||||
{ 0 },
|
{ 0 },
|
||||||
@@ -257,7 +258,7 @@ static const struct crypto_mode mode_cex4567[NUM_CEX4567_MODES] = {
|
|||||||
.counters = counter_ep11 },
|
.counters = counter_ep11 },
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NUM_CRYPTO_TYPES 14
|
#define NUM_CRYPTO_TYPES 15
|
||||||
static const struct crypto_type crypto_types[NUM_CRYPTO_TYPES] = {
|
static const struct crypto_type crypto_types[NUM_CRYPTO_TYPES] = {
|
||||||
{ 0 },
|
{ 0 },
|
||||||
{ 0 },
|
{ 0 },
|
||||||
@@ -276,14 +277,16 @@ static const struct crypto_type crypto_types[NUM_CRYPTO_TYPES] = {
|
|||||||
.modes = mode_accel },
|
.modes = mode_accel },
|
||||||
{ .name = "CEX3C", .num_modes = NUM_COPROC_MODES,
|
{ .name = "CEX3C", .num_modes = NUM_COPROC_MODES,
|
||||||
.modes = mode_coproc },
|
.modes = mode_coproc },
|
||||||
{ .name = "CEX4", .num_modes = NUM_CEX4567_MODES,
|
{ .name = "CEX4", .num_modes = NUM_CEX45678_MODES,
|
||||||
.modes = mode_cex4567 },
|
.modes = mode_cex45678 },
|
||||||
{ .name = "CEX5", .num_modes = NUM_CEX4567_MODES,
|
{ .name = "CEX5", .num_modes = NUM_CEX45678_MODES,
|
||||||
.modes = mode_cex4567 },
|
.modes = mode_cex45678 },
|
||||||
{ .name = "CEX6", .num_modes = NUM_CEX4567_MODES,
|
{ .name = "CEX6", .num_modes = NUM_CEX45678_MODES,
|
||||||
.modes = mode_cex4567 },
|
.modes = mode_cex45678 },
|
||||||
{ .name = "CEX7", .num_modes = NUM_CEX4567_MODES,
|
{ .name = "CEX7", .num_modes = NUM_CEX45678_MODES,
|
||||||
.modes = mode_cex4567 },
|
.modes = mode_cex45678 },
|
||||||
|
{ .name = "CEX8", .num_modes = NUM_CEX45678_MODES,
|
||||||
|
.modes = mode_cex45678 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -2424,4 +2427,3 @@ out:
|
|||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-6
@@ -804,17 +804,17 @@ void ccw_unblacklist_id_range(const char *range)
|
|||||||
|
|
||||||
static char ***id_bitmap_new(void)
|
static char ***id_bitmap_new(void)
|
||||||
{
|
{
|
||||||
return misc_malloc(sizeof(char **) * CSSID_MAX);
|
return misc_malloc(sizeof(char **) * (CSSID_MAX + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void id_bitmap_free(char ***id_bitmap)
|
static void id_bitmap_free(char ***id_bitmap)
|
||||||
{
|
{
|
||||||
unsigned int cssid, ssid;
|
unsigned int cssid, ssid;
|
||||||
|
|
||||||
for (cssid = 0; cssid < CSSID_MAX; cssid++) {
|
for (cssid = 0; cssid <= CSSID_MAX; cssid++) {
|
||||||
if (!id_bitmap[cssid])
|
if (!id_bitmap[cssid])
|
||||||
continue;
|
continue;
|
||||||
for (ssid = 0; ssid < SSID_MAX; ssid++)
|
for (ssid = 0; ssid <= SSID_MAX; ssid++)
|
||||||
free(id_bitmap[cssid][ssid]);
|
free(id_bitmap[cssid][ssid]);
|
||||||
free(id_bitmap[cssid]);
|
free(id_bitmap[cssid]);
|
||||||
}
|
}
|
||||||
@@ -965,15 +965,15 @@ static struct util_list *cio_ignore_get_ranges(bool autoconf)
|
|||||||
ranges = strlist_new();
|
ranges = strlist_new();
|
||||||
|
|
||||||
id_bitmap = id_bitmap_collect(autoconf);
|
id_bitmap = id_bitmap_collect(autoconf);
|
||||||
for (cssid = 0; cssid < CSSID_MAX; cssid++) {
|
for (cssid = 0; cssid <= CSSID_MAX; cssid++) {
|
||||||
if (!id_bitmap[cssid])
|
if (!id_bitmap[cssid])
|
||||||
continue;
|
continue;
|
||||||
for (ssid = 0; ssid < SSID_MAX; ssid++) {
|
for (ssid = 0; ssid <= SSID_MAX; ssid++) {
|
||||||
if (!id_bitmap[cssid][ssid])
|
if (!id_bitmap[cssid][ssid])
|
||||||
continue;
|
continue;
|
||||||
first = NULL;
|
first = NULL;
|
||||||
last = NULL;
|
last = NULL;
|
||||||
for (devno = 0; devno < DEVNO_MAX; devno++) {
|
for (devno = 0; devno <= DEVNO_MAX; devno++) {
|
||||||
if (!id_bitmap_get(id_bitmap, cssid, ssid,
|
if (!id_bitmap_get(id_bitmap, cssid, ssid,
|
||||||
devno)) {
|
devno)) {
|
||||||
if (first) {
|
if (first) {
|
||||||
|
|||||||
@@ -556,7 +556,6 @@ static int open_dump(void)
|
|||||||
}
|
}
|
||||||
if (mv_dumper_read() != 0)
|
if (mv_dumper_read() != 0)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
zg_close(g.fh);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -280,7 +280,7 @@ off_t zg_seek(struct zg_fh *zg_fh, off_t off, enum zg_check check)
|
|||||||
{
|
{
|
||||||
off_t rc;
|
off_t rc;
|
||||||
|
|
||||||
if (off >= zg_fh->sb.st_size)
|
if (S_ISREG(zg_fh->sb.st_mode) && off >= zg_fh->sb.st_size)
|
||||||
ERR_EXIT("Trying to seek past file end \"%s\"", zg_fh->path);
|
ERR_EXIT("Trying to seek past file end \"%s\"", zg_fh->path);
|
||||||
|
|
||||||
rc = lseek(zg_fh->fh, off, SEEK_SET);
|
rc = lseek(zg_fh->fh, off, SEEK_SET);
|
||||||
|
|||||||
+6
-6
@@ -68,11 +68,11 @@ stage3.exec: head.o stage3.o kdump3.o libc.o ebcdic.o ebcdic_conv.o sclp.o \
|
|||||||
}' \
|
}' \
|
||||||
); \
|
); \
|
||||||
case $$STAGE in \
|
case $$STAGE in \
|
||||||
0) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-Ttext,0";; \
|
0) SFLAGS="$(NO_PIE_LDFLAGS) -nostdlib -Wl,-Ttext,0";; \
|
||||||
1) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-Ttext,0x18";; \
|
1) SFLAGS="$(NO_PIE_LDFLAGS) -nostdlib -Wl,-Ttext,0x18";; \
|
||||||
1b) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-Ttext,0xE000";; \
|
1b) SFLAGS="$(NO_PIE_LDFLAGS) -nostdlib -Wl,-Ttext,0xE000";; \
|
||||||
2) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-T,stage2.lds";; \
|
2) SFLAGS="$(NO_PIE_LDFLAGS) -nostdlib -Wl,-T,stage2.lds";; \
|
||||||
3) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-T,stage3.lds";; \
|
3) SFLAGS="$(NO_PIE_LDFLAGS) -nostdlib -Wl,-T,stage3.lds";; \
|
||||||
esac; \
|
esac; \
|
||||||
$(LINK) $$SFLAGS -m64 $(filter %.o, $^) -o $@
|
$(LINK) $$SFLAGS -m64 $(filter %.o, $^) -o $@
|
||||||
|
|
||||||
@@ -110,7 +110,7 @@ stage3.bin: stage3.exec
|
|||||||
$< $@
|
$< $@
|
||||||
|
|
||||||
data.o: $(FILES)
|
data.o: $(FILES)
|
||||||
$(LD) $(NO_PIE_LDFLAGS) -r -b binary -o data.o $(FILES)
|
$(LINK) $(NO_PIE_LDFLAGS) -static -nostdlib -Wl,--relocatable -Wl,--format,binary -o data.o $(FILES)
|
||||||
|
|
||||||
data.h: data.o
|
data.h: data.o
|
||||||
rm -f data.h
|
rm -f data.h
|
||||||
|
|||||||
@@ -13,6 +13,8 @@
|
|||||||
#ifndef JOB_H
|
#ifndef JOB_H
|
||||||
#define JOB_H
|
#define JOB_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include "disk.h"
|
#include "disk.h"
|
||||||
#include "zipl.h"
|
#include "zipl.h"
|
||||||
|
|
||||||
@@ -46,6 +48,8 @@ struct job_common_ipl_data {
|
|||||||
address_t image_addr;
|
address_t image_addr;
|
||||||
address_t parm_addr;
|
address_t parm_addr;
|
||||||
address_t ramdisk_addr;
|
address_t ramdisk_addr;
|
||||||
|
bool optional;
|
||||||
|
bool ignore;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct job_ipl_data {
|
struct job_ipl_data {
|
||||||
|
|||||||
+2
-1
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#define SCAN_SECTION_NUM 9
|
#define SCAN_SECTION_NUM 9
|
||||||
#define SCAN_KEYWORD_NUM 22
|
#define SCAN_KEYWORD_NUM 23
|
||||||
#define SCAN_KEYWORD_ONLY_NUM 1
|
#define SCAN_KEYWORD_ONLY_NUM 1
|
||||||
#define SCAN_AUTOMENU_NAME "zipl-automatic-menu"
|
#define SCAN_AUTOMENU_NAME "zipl-automatic-menu"
|
||||||
|
|
||||||
@@ -52,6 +52,7 @@ enum scan_keyword_id {
|
|||||||
scan_keyword_defaultauto = 19,
|
scan_keyword_defaultauto = 19,
|
||||||
scan_keyword_kdump = 20,
|
scan_keyword_kdump = 20,
|
||||||
scan_keyword_secure = 21,
|
scan_keyword_secure = 21,
|
||||||
|
scan_keyword_optional = 22,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum scan_section_type {
|
enum scan_section_type {
|
||||||
|
|||||||
@@ -447,6 +447,23 @@ This option cannot be used together with either
|
|||||||
.BR 'segment' .
|
.BR 'segment' .
|
||||||
.PP
|
.PP
|
||||||
|
|
||||||
|
.B optional
|
||||||
|
=
|
||||||
|
.IR 0 / 1
|
||||||
|
(configuration only)
|
||||||
|
.IP
|
||||||
|
.B Configuration section:
|
||||||
|
.br
|
||||||
|
If this option is set to 1 the configuration section will only be included in
|
||||||
|
the boot menu if the referenced image file exists, and running
|
||||||
|
.B zipl
|
||||||
|
will not fail if the image file is missing.
|
||||||
|
|
||||||
|
The default value for
|
||||||
|
.B 'optional'
|
||||||
|
is 0.
|
||||||
|
.PP
|
||||||
|
|
||||||
.B parameters
|
.B parameters
|
||||||
=
|
=
|
||||||
.I kernel\-parameters
|
.I kernel\-parameters
|
||||||
|
|||||||
@@ -394,6 +394,10 @@ store_stage2_menu(void* data, size_t size, struct job_data* job)
|
|||||||
return 0;
|
return 0;
|
||||||
/* Config texts */
|
/* Config texts */
|
||||||
for (i = 0; i < job->data.menu.num; i++) {
|
for (i = 0; i < job->data.menu.num; i++) {
|
||||||
|
if (job->data.menu.entry[i].data.ipl.common.ignore) {
|
||||||
|
params->config[job->data.menu.entry[i].pos] = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
const char *kdump_str = "";
|
const char *kdump_str = "";
|
||||||
if (job->data.menu.entry[i].data.ipl.is_kdump)
|
if (job->data.menu.entry[i].data.ipl.is_kdump)
|
||||||
kdump_str = " (kdump)";
|
kdump_str = " (kdump)";
|
||||||
|
|||||||
@@ -1089,6 +1089,12 @@ build_program_table(int fd, char *filename, struct job_data *job,
|
|||||||
for (i=0; i < job->data.menu.num; i++) {
|
for (i=0; i < job->data.menu.num; i++) {
|
||||||
switch (job->data.menu.entry[i].id) {
|
switch (job->data.menu.entry[i].id) {
|
||||||
case job_ipl:
|
case job_ipl:
|
||||||
|
if (job->data.menu.entry[i].data.ipl.common.ignore) {
|
||||||
|
printf("Skipping #%d: IPL section '%s' (missing files)\n",
|
||||||
|
job->data.menu.entry[i].pos,
|
||||||
|
job->data.menu.entry[i].name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
printf("Adding #%d: IPL section '%s'%s",
|
printf("Adding #%d: IPL section '%s'%s",
|
||||||
job->data.menu.entry[i].pos,
|
job->data.menu.entry[i].pos,
|
||||||
job->data.menu.entry[i].name,
|
job->data.menu.entry[i].name,
|
||||||
|
|||||||
+41
-11
@@ -758,7 +758,8 @@ static void error_text_section(const char *text, const char *section, const char
|
|||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
check_common_ipl_data(struct job_common_ipl_data *common, const char *section)
|
check_common_ipl_data(struct job_common_ipl_data *common, const char *section,
|
||||||
|
bool may_ignore)
|
||||||
{
|
{
|
||||||
uint64_t max_parm_size, len;
|
uint64_t max_parm_size, len;
|
||||||
char *buffer = NULL;
|
char *buffer = NULL;
|
||||||
@@ -768,10 +769,16 @@ check_common_ipl_data(struct job_common_ipl_data *common, const char *section)
|
|||||||
if (common->image != NULL) {
|
if (common->image != NULL) {
|
||||||
rc = misc_read_file(common->image, &buffer, &size, 0);
|
rc = misc_read_file(common->image, &buffer, &size, 0);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
error_text_section("Image file", section, common->image);
|
if (may_ignore && common->optional) {
|
||||||
|
printf("Optional section '%s': Missing image file '%s'\n",
|
||||||
|
section, common->image);
|
||||||
|
error_clear_reason();
|
||||||
|
common->ignore = true;
|
||||||
|
rc = 0;
|
||||||
|
goto skip_image;
|
||||||
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size < MAX_COMMAND_LINE_SIZE + sizeof(uint64_t)) {
|
if (size < MAX_COMMAND_LINE_SIZE + sizeof(uint64_t)) {
|
||||||
error_text_section("Image file", section, common->image);
|
error_text_section("Image file", section, common->image);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -789,12 +796,19 @@ check_common_ipl_data(struct job_common_ipl_data *common, const char *section)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
skip_image:
|
||||||
if (common->ramdisk != NULL) {
|
if (common->ramdisk != NULL) {
|
||||||
rc = misc_check_readable_file(common->ramdisk);
|
rc = misc_check_readable_file(common->ramdisk);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
error_text_section("Ramdisk file", section, common->ramdisk);
|
if (common->optional) {
|
||||||
return rc;
|
printf("Optional section '%s': Missing ramdisk file '%s'\n",
|
||||||
|
section, common->ramdisk);
|
||||||
|
error_clear_reason();
|
||||||
|
common->ignore = true;
|
||||||
|
rc = 0;
|
||||||
|
} else {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -802,13 +816,17 @@ check_common_ipl_data(struct job_common_ipl_data *common, const char *section)
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
check_job_ipl_data(struct job_ipl_data *ipl, char *name,
|
check_job_ipl_data(struct job_ipl_data *ipl, char *name,
|
||||||
struct job_envblk_data *envblk)
|
struct job_envblk_data *envblk, bool may_ignore)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = check_common_ipl_data(&ipl->common, name);
|
rc = check_common_ipl_data(&ipl->common, name, may_ignore);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
if (ipl->common.ignore)
|
||||||
|
return 0;
|
||||||
|
|
||||||
return finalize_ipl_address_data(ipl, name, envblk);
|
return finalize_ipl_address_data(ipl, name, envblk);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -887,9 +905,15 @@ check_job_menu_data(struct job_menu_data *menu, struct job_envblk_data *envblk)
|
|||||||
case job_ipl:
|
case job_ipl:
|
||||||
rc = check_job_ipl_data(&menu->entry[i].data.ipl,
|
rc = check_job_ipl_data(&menu->entry[i].data.ipl,
|
||||||
menu->entry[i].name,
|
menu->entry[i].name,
|
||||||
envblk);
|
envblk, true);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
/* default_pos is 1-indexed */
|
||||||
|
if (menu->default_pos == i + 1 &&
|
||||||
|
menu->entry[i].data.ipl.common.ignore) {
|
||||||
|
error_text("Cannot ignore default entry");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case job_print_usage:
|
case job_print_usage:
|
||||||
case job_print_version:
|
case job_print_version:
|
||||||
@@ -917,7 +941,7 @@ check_job_ipl_tape_data(struct job_ipl_tape_data *ipl, char* name)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rc = check_common_ipl_data(&ipl->common, name);
|
rc = check_common_ipl_data(&ipl->common, name, false);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
return finalize_common_address_data(&ipl->common, name);
|
return finalize_common_address_data(&ipl->common, name);
|
||||||
@@ -1016,7 +1040,7 @@ check_job_data(struct job_data* job)
|
|||||||
break;
|
break;
|
||||||
case job_ipl:
|
case job_ipl:
|
||||||
rc = check_job_ipl_data(&job->data.ipl, job->name,
|
rc = check_job_ipl_data(&job->data.ipl, job->name,
|
||||||
&job->envblk);
|
&job->envblk, false);
|
||||||
break;
|
break;
|
||||||
case job_menu:
|
case job_menu:
|
||||||
rc = check_job_menu_data(&job->data.menu, &job->envblk);
|
rc = check_job_menu_data(&job->data.menu, &job->envblk);
|
||||||
@@ -1295,6 +1319,12 @@ get_job_from_section_data(char* data[], struct job_data* job, char* section)
|
|||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
job->data.ipl.common.optional = false;
|
||||||
|
if (data[(int) scan_keyword_optional] != NULL) {
|
||||||
|
job->data.ipl.common.optional =
|
||||||
|
atoi(data[(int) scan_keyword_optional]) == 1;
|
||||||
|
}
|
||||||
|
job->data.ipl.common.ignore = false;
|
||||||
break;
|
break;
|
||||||
case section_ipl_tape:
|
case section_ipl_tape:
|
||||||
/* Tape IPL job */
|
/* Tape IPL job */
|
||||||
|
|||||||
+170
-108
@@ -47,45 +47,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
|
* ult to tofs e mete file isk ent et pt out ultm dump
|
||||||
* rs enu
|
* rs enu
|
||||||
*
|
*
|
||||||
* targ targ targ targ targ defa kdum secu
|
* targ targ targ targ targ defa kdum secu opti
|
||||||
* etba etty etge etbl etof ulta p re
|
* etba etty etge etbl etof ulta p re onal
|
||||||
* se pe omet ocks fset uto
|
* se pe omet ocks fset uto
|
||||||
* ry ize
|
* ry ize
|
||||||
*/
|
*/
|
||||||
/* default auto */
|
/* default auto */
|
||||||
{opt, inv, inv, inv, inv, inv, inv, inv, req, opt, opt, inv, inv, inv,
|
{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, opt, inv, opt, inv},
|
||||||
/* default menu */
|
/* 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, req, inv, inv,
|
||||||
inv, inv, inv, inv, inv, inv, inv, opt},
|
inv, inv, inv, inv, inv, inv, inv, opt, inv},
|
||||||
/* default section */
|
/* default section */
|
||||||
{req, 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, inv, inv, inv, inv, inv, opt},
|
inv, inv, inv, inv, inv, inv, inv, opt, inv},
|
||||||
/* ipl */
|
/* ipl */
|
||||||
{inv, inv, inv, req, opt, opt, opt, inv, req, inv, inv, inv, inv, inv,
|
{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, opt, inv, opt, opt, opt},
|
||||||
/* segment load */
|
/* segment load */
|
||||||
{inv, inv, inv, inv, inv, inv, inv, req, req, inv, inv, inv, inv, inv,
|
{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, inv, inv},
|
||||||
/* part dump */
|
/* part dump */
|
||||||
{inv, req, inv, inv, inv, inv, inv, inv, opt, inv, inv, inv, inv, inv,
|
{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, inv, inv},
|
||||||
/* fs dump */
|
/* fs dump */
|
||||||
{inv, inv, req, inv, opt, opt, inv, inv, req, inv, inv, inv, inv, inv,
|
{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, inv, inv},
|
||||||
/* ipl tape */
|
/* ipl tape */
|
||||||
{inv, inv, inv, req, opt, opt, opt, inv, inv, inv, inv, inv, req, inv,
|
{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, inv, inv},
|
||||||
/* multi volume dump */
|
/* 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, req,
|
||||||
inv, inv, 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 */
|
/* Determines which keyword may be present in a menu section */
|
||||||
static enum scan_key_state scan_menu_key_table[SCAN_KEYWORD_NUM] = {
|
static enum scan_key_state scan_menu_key_table[SCAN_KEYWORD_NUM] = {
|
||||||
/* menu section */
|
/* menu section */
|
||||||
opt, inv, inv, inv, inv, inv, inv, inv, req, opt, opt, inv, inv, inv,
|
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, opt, inv, inv, opt, inv
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Mapping of keyword IDs to strings */
|
/* Mapping of keyword IDs to strings */
|
||||||
@@ -114,6 +114,7 @@ static const struct {
|
|||||||
{ "tape", scan_keyword_tape},
|
{ "tape", scan_keyword_tape},
|
||||||
{ "kdump", scan_keyword_kdump},
|
{ "kdump", scan_keyword_kdump},
|
||||||
{ "secure", scan_keyword_secure},
|
{ "secure", scan_keyword_secure},
|
||||||
|
{ "optional", scan_keyword_optional},
|
||||||
};
|
};
|
||||||
|
|
||||||
/* List of keywords that are used without an assignment */
|
/* List of keywords that are used without an assignment */
|
||||||
@@ -794,102 +795,6 @@ static int sort_bls_fields(struct misc_file_buffer *file, char *filename)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
|
||||||
scan_bls(const char* blsdir, struct scan_token** token, int scan_size)
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
int size, remaining = 0, n, current, rc = -1;
|
|
||||||
struct scan_token* buffer;
|
|
||||||
struct scan_token* array = *token;
|
|
||||||
struct dirent** bls_entries;
|
|
||||||
struct misc_file_buffer file;
|
|
||||||
struct stat sb;
|
|
||||||
char filename[PATH_MAX];
|
|
||||||
|
|
||||||
if (!(stat(blsdir, &sb) == 0 && S_ISDIR(sb.st_mode)))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
n = scandir(blsdir, &bls_entries, bls_filter, bls_sort);
|
|
||||||
if (n <= 0)
|
|
||||||
return n;
|
|
||||||
|
|
||||||
while (array[count].id != 0)
|
|
||||||
count++;
|
|
||||||
|
|
||||||
remaining = scan_size - count;
|
|
||||||
|
|
||||||
/* The array of scanned tokens is allocated when the zipl config file is
|
|
||||||
* parsed. Its size is a multiple of INITIAL_ARRAY_LENGTH so it may have
|
|
||||||
* enough space to scan all the tokens that are defined in the BLS files.
|
|
||||||
* Calculate if is enough assuming that a BLS fragment can contain up to
|
|
||||||
* 4 tokens: a section heading and 3 keywords (image, ramdisk, parameter).
|
|
||||||
*/
|
|
||||||
if (remaining < n * 4) {
|
|
||||||
size = scan_size - remaining + (n * 4);
|
|
||||||
buffer = (struct scan_token *)misc_malloc(size * sizeof(struct scan_token));
|
|
||||||
if (!buffer)
|
|
||||||
goto err;
|
|
||||||
memset(buffer, 0, size * sizeof(struct scan_token));
|
|
||||||
memcpy(buffer, array, count * sizeof(struct scan_token));
|
|
||||||
} else {
|
|
||||||
buffer = array;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (n--) {
|
|
||||||
sprintf(filename, "%s/%s", blsdir, bls_entries[n]->d_name);
|
|
||||||
printf("Using BLS config file '%s'\n", filename);
|
|
||||||
|
|
||||||
rc = misc_get_file_buffer(filename, &file);
|
|
||||||
if (rc)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
rc = sort_bls_fields(&file, filename);
|
|
||||||
if (rc)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
while ((size_t)file.pos < file.length) {
|
|
||||||
current = misc_get_char(&file, 0);
|
|
||||||
switch (current) {
|
|
||||||
case '#':
|
|
||||||
file.pos++;
|
|
||||||
skip_line(&file);
|
|
||||||
break;
|
|
||||||
case EOF:
|
|
||||||
break;
|
|
||||||
case '\t':
|
|
||||||
case '\n':
|
|
||||||
case '\0':
|
|
||||||
case ' ':
|
|
||||||
file.pos++;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
rc = scan_bls_field(&file, buffer, &count);
|
|
||||||
if (rc) {
|
|
||||||
error_reason("Incorrect BLS field in "
|
|
||||||
"config file %s\n", filename);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
misc_free_file_buffer(&file);
|
|
||||||
free(bls_entries[n]);
|
|
||||||
}
|
|
||||||
|
|
||||||
*token = buffer;
|
|
||||||
rc = 0;
|
|
||||||
err:
|
|
||||||
if (n > 0) {
|
|
||||||
do {
|
|
||||||
free(bls_entries[n]);
|
|
||||||
} while (n-- > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(bls_entries);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Search scanned tokens SCAN for a section/menu heading (according to
|
/* Search scanned tokens SCAN for a section/menu heading (according to
|
||||||
* TYPE) of the given NAME, beginning at token OFFSET. Return the index of
|
* TYPE) of the given NAME, beginning at token OFFSET. Return the index of
|
||||||
@@ -1358,6 +1263,163 @@ scan_get_section_keywords(struct scan_token* scan, int* index, char* name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the default target defined either in the defaultboot section or the
|
||||||
|
* menu section for the defaultmenu if there is a default menu defined.
|
||||||
|
*/
|
||||||
|
static char *scan_get_default_target(struct scan_token *scan)
|
||||||
|
{
|
||||||
|
int keyword_line[SCAN_KEYWORD_NUM];
|
||||||
|
char *keyword[SCAN_KEYWORD_NUM];
|
||||||
|
int num_line[BOOT_MENU_ENTRIES];
|
||||||
|
char *num[BOOT_MENU_ENTRIES];
|
||||||
|
int i, j, rc;
|
||||||
|
|
||||||
|
/* Find the defaultboot section */
|
||||||
|
i = scan_find_section(scan, DEFAULTBOOT_SECTION,
|
||||||
|
scan_id_section_heading, 0);
|
||||||
|
if (i < 0) {
|
||||||
|
error_reason("No '%s' section found and no section specified on command line",
|
||||||
|
DEFAULTBOOT_SECTION);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get keyword and number data */
|
||||||
|
rc = scan_get_section_keywords(scan, &i, DEFAULTBOOT_SECTION, keyword,
|
||||||
|
keyword_line, NULL, NULL);
|
||||||
|
if (rc) {
|
||||||
|
error_reason("Could not get keywords for '%s' section",
|
||||||
|
DEFAULTBOOT_SECTION);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if a defaultmenu is set */
|
||||||
|
i = (int) scan_keyword_defaultmenu;
|
||||||
|
if (keyword[i]) {
|
||||||
|
j = scan_find_section(scan, keyword[i],
|
||||||
|
scan_id_menu_heading, 0);
|
||||||
|
if (j < 0) {
|
||||||
|
error_reason("No '%s' section found", keyword[i]);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get keyword and number data */
|
||||||
|
rc = scan_get_section_keywords(scan, &j, keyword[i], keyword,
|
||||||
|
keyword_line, num, num_line);
|
||||||
|
if (rc) {
|
||||||
|
error_reason("Could not get keywords for '%s' section",
|
||||||
|
keyword[i]);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return keyword[(int) scan_keyword_target];
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BLS_TOKEN_MAX 5 /* section heading, image, ramdisk, parameter, target */
|
||||||
|
|
||||||
|
int scan_bls(const char *blsdir, struct scan_token **token, int scan_size)
|
||||||
|
{
|
||||||
|
int size, remaining = 0, n, current, rc = -1, count = 0;
|
||||||
|
struct scan_token *array = *token;
|
||||||
|
struct misc_file_buffer file;
|
||||||
|
struct dirent **bls_entries;
|
||||||
|
struct scan_token *buffer;
|
||||||
|
char filename[PATH_MAX];
|
||||||
|
char *target = NULL;
|
||||||
|
struct stat sb;
|
||||||
|
|
||||||
|
if (!(stat(blsdir, &sb) == 0 && S_ISDIR(sb.st_mode)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
n = scandir(blsdir, &bls_entries, bls_filter, bls_sort);
|
||||||
|
if (n <= 0)
|
||||||
|
return n;
|
||||||
|
|
||||||
|
while (array[count].id != 0)
|
||||||
|
count++;
|
||||||
|
|
||||||
|
remaining = scan_size - count;
|
||||||
|
|
||||||
|
/* The array of scanned tokens is allocated when the zipl config file is
|
||||||
|
* parsed. Its size is a multiple of INITIAL_ARRAY_LENGTH so it may have
|
||||||
|
* enough space to scan all the tokens that are defined in the BLS files.
|
||||||
|
* Calculate if is enough assuming that a BLS fragment can contain up to
|
||||||
|
* BLS_TOKEN_MAX.
|
||||||
|
*/
|
||||||
|
if (remaining < n * BLS_TOKEN_MAX) {
|
||||||
|
size = scan_size - remaining + (n * BLS_TOKEN_MAX);
|
||||||
|
buffer = (struct scan_token *)misc_malloc(size * sizeof(struct scan_token));
|
||||||
|
if (!buffer)
|
||||||
|
goto err;
|
||||||
|
memset(buffer, 0, size * sizeof(struct scan_token));
|
||||||
|
memcpy(buffer, array, count * sizeof(struct scan_token));
|
||||||
|
} else {
|
||||||
|
buffer = array;
|
||||||
|
}
|
||||||
|
|
||||||
|
target = scan_get_default_target(array);
|
||||||
|
while (n--) {
|
||||||
|
sprintf(filename, "%s/%s", blsdir, bls_entries[n]->d_name);
|
||||||
|
printf("Using BLS config file '%s'\n", filename);
|
||||||
|
|
||||||
|
rc = misc_get_file_buffer(filename, &file);
|
||||||
|
if (rc)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
rc = sort_bls_fields(&file, filename);
|
||||||
|
if (rc)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
while ((size_t)file.pos < file.length) {
|
||||||
|
current = misc_get_char(&file, 0);
|
||||||
|
switch (current) {
|
||||||
|
case '#':
|
||||||
|
file.pos++;
|
||||||
|
skip_line(&file);
|
||||||
|
break;
|
||||||
|
case EOF:
|
||||||
|
break;
|
||||||
|
case '\t':
|
||||||
|
case '\n':
|
||||||
|
case '\0':
|
||||||
|
case ' ':
|
||||||
|
file.pos++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rc = scan_bls_field(&file, buffer, &count);
|
||||||
|
if (rc) {
|
||||||
|
error_reason("Incorrect BLS field in config file %s\n",
|
||||||
|
filename);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target != NULL)
|
||||||
|
scan_append_keyword_assignment(buffer, &count,
|
||||||
|
scan_keyword_target,
|
||||||
|
target);
|
||||||
|
|
||||||
|
misc_free_file_buffer(&file);
|
||||||
|
free(bls_entries[n]);
|
||||||
|
}
|
||||||
|
|
||||||
|
*token = buffer;
|
||||||
|
rc = 0;
|
||||||
|
err:
|
||||||
|
if (n > 0) {
|
||||||
|
do {
|
||||||
|
free(bls_entries[n]);
|
||||||
|
} while (n-- > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(bls_entries);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Check section at INDEX for compliance with config file rules. Upon success,
|
/* Check section at INDEX for compliance with config file rules. Upon success,
|
||||||
* return zero and advance INDEX to point to the end of the section. Return
|
* return zero and advance INDEX to point to the end of the section. Return
|
||||||
* non-zero otherwise. */
|
* non-zero otherwise. */
|
||||||
|
|||||||
+41
-3
@@ -1,4 +1,4 @@
|
|||||||
.\" Copyright IBM Corp. 2018
|
.\" Copyright IBM Corp. 2022
|
||||||
.\" s390-tools is free software; you can redistribute it and/or modify
|
.\" s390-tools is free software; you can redistribute it and/or modify
|
||||||
.\" it under the terms of the MIT license. See LICENSE for details.
|
.\" it under the terms of the MIT license. See LICENSE for details.
|
||||||
.\"
|
.\"
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
. PD
|
. PD
|
||||||
..
|
..
|
||||||
.
|
.
|
||||||
.TH zpcictl 8 "Oct 2018" s390-tools zpcictl
|
.TH zpcictl 8 "Mar 2022" s390-tools zpcictl
|
||||||
.
|
.
|
||||||
.SH NAME
|
.SH NAME
|
||||||
zpcictl - Manage PCI devices on IBM Z
|
zpcictl - Manage PCI devices on IBM Z
|
||||||
@@ -52,7 +52,45 @@ device (e.g.
|
|||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
.SS Error Handling Options
|
.SS Error Handling Options
|
||||||
.OD reset "" "DEVICE"
|
.OD reset "" "DEVICE"
|
||||||
Reset and re-initialize the PCI device.
|
Reset and re-initialize the PCI device and report a device error to the Support
|
||||||
|
Element (SE). The reset consists of a controlled shutdown and a subsequent
|
||||||
|
re-enabling of the device from the shut off state. This process destroys and
|
||||||
|
then re-creates higher level interfaces such as network interfaces and block
|
||||||
|
devices. This reset is disruptive and often requires manual intervention on
|
||||||
|
multiple layers. In particular, network interfaces that are part of a bonded
|
||||||
|
interface must be re-added to the bond after the reset. Similarly, block
|
||||||
|
devices backed by an NVMe that are part of a software RAID must be re-synced by
|
||||||
|
re-adding to the RAID after resetting the NVMe.
|
||||||
|
|
||||||
|
Use this reset option only if the less disruptive automatic recovery mechanism
|
||||||
|
is not supported by your kernel or it failed to restore the device's
|
||||||
|
functionality. Unsuccessful automatic recovery can result in kernel messages
|
||||||
|
indicating required manual intervention. If the device is malfunctioning
|
||||||
|
without automatic recovery being triggered, consider using the \fB--reset-fw\fR
|
||||||
|
option to trigger a less disruptive automatic recovery through
|
||||||
|
a firmware-driven reset.
|
||||||
|
.PP
|
||||||
|
.
|
||||||
|
.OD reset-fw "" "DEVICE"
|
||||||
|
Reset the PCI device using a firmware-driven reset that also reports a device
|
||||||
|
error on the Support Element (SE). If supported by your kernel, automatic recovery
|
||||||
|
re-initializes the device after the firmware reports a successful device reset.
|
||||||
|
|
||||||
|
Use this option if the device is malfunctioning and automatic recovery is
|
||||||
|
supported by the kernel but was not triggered. This condition can occur if the
|
||||||
|
error is not detected by the low level PCI interfaces. A successful automatic
|
||||||
|
recovery after the firmware-driven reset, is less disruptive than the full
|
||||||
|
reset that is performed by the \fB--reset\fR option. Other than the full reset,
|
||||||
|
the automatic recovery does not completely shut down the device and re-create
|
||||||
|
it from the shut down state. Instead, it works with the device driver to
|
||||||
|
restore the device in place. Thus, higher level interfaces such as network
|
||||||
|
interfaces and block devices remain intact. In particular, with this type of
|
||||||
|
reset high availability mechanisms like a bonded network interface or
|
||||||
|
a software RAID can transparently re-integrate the recovered device. For
|
||||||
|
example, after a failure and recovery, a software RAID can resync a stroage
|
||||||
|
device or a network interface can be re-integrated in a bond. In contrast to
|
||||||
|
a complete shut down, the device driver remains active and informs higher
|
||||||
|
layers of both the occurence of an error state and the eventual recovery.
|
||||||
.PP
|
.PP
|
||||||
.
|
.
|
||||||
.OD deconfigure "" "DEVICE"
|
.OD deconfigure "" "DEVICE"
|
||||||
|
|||||||
+31
-2
@@ -46,12 +46,27 @@ static const struct util_prg prg = {
|
|||||||
#define OPT_RESET 128
|
#define OPT_RESET 128
|
||||||
#define OPT_DECONF 129
|
#define OPT_DECONF 129
|
||||||
#define OPT_REPORT_ERR 130
|
#define OPT_REPORT_ERR 130
|
||||||
|
#define OPT_RESET_FW 131
|
||||||
|
|
||||||
static struct util_opt opt_vec[] = {
|
static struct util_opt opt_vec[] = {
|
||||||
UTIL_OPT_SECTION("ERROR HANDLING OPTIONS"),
|
UTIL_OPT_SECTION("ERROR HANDLING OPTIONS"),
|
||||||
{
|
{
|
||||||
.option = { "reset", no_argument, NULL, OPT_RESET },
|
.option = { "reset", no_argument, NULL, OPT_RESET },
|
||||||
.desc = "Reset the device",
|
.desc = "Reset the device and report an error to the Support Element (SE). "
|
||||||
|
"The reset consists of a controlled shutdown and a subsequent "
|
||||||
|
"re-enabling of the device. As a result, higher level interfaces such "
|
||||||
|
"as network interfaces and block devices are destroyed and re-created.\n"
|
||||||
|
"Manual configuration steps might be required to re-integrate the device, "
|
||||||
|
"for example, in bonded interfaces or software RAIDs.\n"
|
||||||
|
"Use this option only if the automatic recovery failed, or if it did "
|
||||||
|
"not succeed to restore regular operations of the device and manual "
|
||||||
|
"intervention is required.\n",
|
||||||
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.option = { "reset-fw", no_argument, NULL, OPT_RESET_FW },
|
||||||
|
.desc = "Reset the device through a firmware driven reset that triggers "
|
||||||
|
"automatic recovery and reports an error to the Support Element (SE).\n",
|
||||||
.flags = UTIL_OPT_FLAG_NOSHORT,
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -337,10 +352,19 @@ static void sclp_issue_action(struct zpci_device *pdev, int action)
|
|||||||
*/
|
*/
|
||||||
static void sclp_reset_device(struct zpci_device *pdev)
|
static void sclp_reset_device(struct zpci_device *pdev)
|
||||||
{
|
{
|
||||||
sclp_issue_action(pdev, SCLP_ERRNOTIFY_AQ_RESET);
|
sclp_issue_action(pdev, SCLP_ERRNOTIFY_AQ_REPORT_ERR);
|
||||||
sysfs_write_value(pdev, "recover", 1);
|
sysfs_write_value(pdev, "recover", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reset the PCI device via firmware and let auto recovery handle
|
||||||
|
* re-initialization
|
||||||
|
*/
|
||||||
|
static void sclp_reset_device_fw(struct zpci_device *pdev)
|
||||||
|
{
|
||||||
|
sclp_issue_action(pdev, SCLP_ERRNOTIFY_AQ_RESET);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* De-Configure/repair PCI device. Moves the device from configured
|
* De-Configure/repair PCI device. Moves the device from configured
|
||||||
* to reserved state.
|
* to reserved state.
|
||||||
@@ -372,6 +396,9 @@ static void parse_cmdline(int argc, char *argv[], struct options *opts)
|
|||||||
case OPT_RESET:
|
case OPT_RESET:
|
||||||
opts->reset = 1;
|
opts->reset = 1;
|
||||||
break;
|
break;
|
||||||
|
case OPT_RESET_FW:
|
||||||
|
opts->reset_fw = 1;
|
||||||
|
break;
|
||||||
case OPT_DECONF:
|
case OPT_DECONF:
|
||||||
opts->deconfigure = 1;
|
opts->deconfigure = 1;
|
||||||
break;
|
break;
|
||||||
@@ -411,6 +438,8 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
if (opts.reset)
|
if (opts.reset)
|
||||||
sclp_reset_device(&pdev);
|
sclp_reset_device(&pdev);
|
||||||
|
if (opts.reset_fw)
|
||||||
|
sclp_reset_device_fw(&pdev);
|
||||||
else if (opts.deconfigure)
|
else if (opts.deconfigure)
|
||||||
sclp_deconfigure(&pdev);
|
sclp_deconfigure(&pdev);
|
||||||
else if (opts.report)
|
else if (opts.report)
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
struct options {
|
struct options {
|
||||||
unsigned int reset;
|
unsigned int reset;
|
||||||
|
unsigned int reset_fw;
|
||||||
unsigned int deconfigure;
|
unsigned int deconfigure;
|
||||||
unsigned int report;
|
unsigned int report;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user