mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Compare commits
128 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
60c687238d | ||
|
|
57b992ffa1 | ||
|
|
1f07a41d5a | ||
|
|
512b47c004 | ||
|
|
818ffbc4b0 | ||
|
|
5e65df7375 | ||
|
|
4eb80d14a0 | ||
|
|
7247a61e0b | ||
|
|
c856f28e11 | ||
|
|
ca30cfd341 | ||
|
|
58ecf1f363 | ||
|
|
d36ff82999 | ||
|
|
d4398aea89 | ||
|
|
672548ce30 | ||
|
|
344965bd29 | ||
|
|
d6a96f07c1 | ||
|
|
6a99d95d4f | ||
|
|
3f1bd3bb66 | ||
|
|
0fbc4edd29 | ||
|
|
b8a9f0d1d3 | ||
|
|
d280e5b1fa | ||
|
|
e04acab0ed | ||
|
|
d868ce5ec7 | ||
|
|
dec58c349e | ||
|
|
d82f5e1f49 | ||
|
|
156450f359 | ||
|
|
c0392efa39 | ||
|
|
3c5644ccfd | ||
|
|
3fb356ebd2 | ||
|
|
fe68ec513d | ||
|
|
a86fb8b091 | ||
|
|
f32bff9688 | ||
|
|
7d355b0fec | ||
|
|
ab4445c261 | ||
|
|
e14363373b | ||
|
|
d9ca409978 | ||
|
|
13596f18da | ||
|
|
80b66da1d8 | ||
|
|
3eb9af9c97 | ||
|
|
f093d0bfd4 | ||
|
|
6a2f4fd376 | ||
|
|
e2f92e4079 | ||
|
|
c944f23d7e | ||
|
|
5872f8a21b | ||
|
|
a090a1ffe8 | ||
|
|
5e24f74fde | ||
|
|
340da73bb7 | ||
|
|
f642019bcc | ||
|
|
7cc542352e | ||
|
|
cf99ea019e | ||
|
|
15c22ec742 | ||
|
|
45ac847dc9 | ||
|
|
4a223c70f2 | ||
|
|
26d636f234 | ||
|
|
aade05b01d | ||
|
|
c3821f0821 | ||
|
|
ac0ac48f6f | ||
|
|
54519b4465 | ||
|
|
9f2e406525 | ||
|
|
edaad2a927 | ||
|
|
262a827ab4 | ||
|
|
4b33d80595 | ||
|
|
4c401162c0 | ||
|
|
168acec5ea | ||
|
|
aab339d3e3 | ||
|
|
1f459af568 | ||
|
|
46f09a0adc | ||
|
|
f65003a14e | ||
|
|
e092b4024a | ||
|
|
9d7bab18a4 | ||
|
|
8688d47e3d | ||
|
|
04bb72c0dc | ||
|
|
1c065082d2 | ||
|
|
38642e6905 | ||
|
|
ebdf888a2f | ||
|
|
9745e4678a | ||
|
|
33a17df9fc | ||
|
|
4ff7aeff39 | ||
|
|
edb75870b5 | ||
|
|
a3c746846d | ||
|
|
4044accf03 | ||
|
|
943e7e7198 | ||
|
|
4f00cb6346 | ||
|
|
9d55086720 | ||
|
|
eaa2ef6ba4 | ||
|
|
37c3752b31 | ||
|
|
8585efadbe | ||
|
|
13648dd6f4 | ||
|
|
427dff3450 | ||
|
|
08bc0a947a | ||
|
|
c3d583fe9c | ||
|
|
983a72dab9 | ||
|
|
811152c08a | ||
|
|
6a1b9cf10a | ||
|
|
599b141b8a | ||
|
|
b9e47e356b | ||
|
|
5e2a477bbf | ||
|
|
bba34cb975 | ||
|
|
a674011c0d | ||
|
|
c78b5cd2ba | ||
|
|
f3e374ac77 | ||
|
|
1e6a9dbd56 | ||
|
|
564a2601f6 | ||
|
|
f4eb7e4907 | ||
|
|
c5a91199e3 | ||
|
|
144bddbf5b | ||
|
|
36ef451e6b | ||
|
|
1064e5b9cc | ||
|
|
d121ffa3f0 | ||
|
|
57f18c5f59 | ||
|
|
3b2a8777b1 | ||
|
|
89ead069f9 | ||
|
|
05de40cdeb | ||
|
|
a74103dba7 | ||
|
|
b4868c21bf | ||
|
|
8826028bdc | ||
|
|
09aa7f2010 | ||
|
|
e7d3638c6b | ||
|
|
68b0b4c268 | ||
|
|
caeb4470cd | ||
|
|
8b11ea73ac | ||
|
|
45e20a5044 | ||
|
|
105b30a805 | ||
|
|
70a7fc3e72 | ||
|
|
2d3774932b | ||
|
|
a5c1923d32 | ||
|
|
0348a8443e | ||
|
|
dba9616a5b |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -46,6 +46,7 @@ libutil/util_prg_example
|
||||
libutil/util_rec_example
|
||||
libutil/util_scandir_example
|
||||
libzds/libzds.a
|
||||
libvmcp/vmcp_example
|
||||
mon_tools/mon_fsstatd
|
||||
mon_tools/mon_procd
|
||||
osasnmpd/osasnmpd
|
||||
@@ -86,4 +87,5 @@ zipl/boot/*.exec
|
||||
zipl/boot/data.h
|
||||
zipl/src/chreipl_helper.device-mapper
|
||||
zipl/src/zipl
|
||||
zipl/src/zipl_helper.device-mapper
|
||||
zkey/zkey
|
||||
|
||||
@@ -16,6 +16,7 @@ List of all individuals having contributed content to s390-tools
|
||||
- Clemens von Mann
|
||||
- Dan Horak
|
||||
- Despina Papadopoulou
|
||||
- Dimitri John Ledkov
|
||||
- Eberhard Pasch
|
||||
- Einar Lueck
|
||||
- Erwin Vicari
|
||||
@@ -45,6 +46,7 @@ List of all individuals having contributed content to s390-tools
|
||||
- Jan Glauber
|
||||
- Jan Hoeppner
|
||||
- Jan Willeke
|
||||
- Javier Martinez Canillas
|
||||
- Jean-Baptiste Joret
|
||||
- Jens Remus
|
||||
- Jochen Roehrig
|
||||
@@ -96,6 +98,7 @@ List of all individuals having contributed content to s390-tools
|
||||
- Thomas Weber
|
||||
- Ursula Braun
|
||||
- Utz Bacher
|
||||
- Vasily Gorbik
|
||||
- Viktor Mihajlovski
|
||||
- Volker Sameske
|
||||
- Wolfgang Taphorn
|
||||
|
||||
61
CHANGELOG.md
61
CHANGELOG.md
@@ -1,5 +1,66 @@
|
||||
Release history for s390-tools (MIT version)
|
||||
--------------------------------------------
|
||||
* __v2.6.0 (2018-08-10)__
|
||||
|
||||
For Linux kernel version: 4.18
|
||||
|
||||
Add new tool:
|
||||
- zkey: Add zkey-cryptsetup tool
|
||||
Changes of existing tools:
|
||||
- netboot: add BOOTIF support
|
||||
|
||||
Bug Fixes:
|
||||
- mon_procd: fix parsing of /proc/<pid>/stat
|
||||
- netboot: Include compressed kernel modules in initramfs
|
||||
- netboot: Send client architecture and handle path prefix
|
||||
|
||||
* __v2.5.0 (2018-06-08)__
|
||||
|
||||
For Linux kernel version: 4.17
|
||||
|
||||
Changes of existing tools:
|
||||
- zdev: Add support for reading firmware configuration files
|
||||
- zipl: Add BootLoaderSpec support
|
||||
- scripts: Add script to switch zipl config to a BootLoaderSpec setup
|
||||
|
||||
Bug Fixes:
|
||||
- lsluns: Print a message if no adapter or port exists
|
||||
|
||||
* __v2.4.0 (2018-05-07)__
|
||||
|
||||
For Linux kernel version: 4.16
|
||||
|
||||
Changes of existing tools:
|
||||
- dbginfo: Gather nvme related data
|
||||
- zipl: Rewrite helper script in C
|
||||
- libutil: Add function util_strstrip
|
||||
- libvmcp: Introduce libvmcp
|
||||
- zipl: Extend DASD stand-alone dumpers to drop zero pages
|
||||
- zgetdump: Add verbose option
|
||||
- zgetdump: Add 'Dump file size' field for zgetdump -i output
|
||||
- cpumf: Add IBM z14 ZR1 to the CPU Measurement Facility model list
|
||||
- zkey: Add build dependency to OpenSSL (libcrypto)
|
||||
- zkey: Add keystore implementation
|
||||
|
||||
|
||||
Bug Fixes:
|
||||
- hmcdrvfs: fix parsing of link count >= 1000
|
||||
- zgetdump: Avoid Segfault on processing dumps with memory limit
|
||||
- chreipl: correct fcp reipl sysfs write sequence
|
||||
- udev: Replace WAIT_FOR with TEST keyword
|
||||
|
||||
* __v2.3.0 (2018-01-30)__
|
||||
|
||||
For Linux kernel version: 4.15
|
||||
|
||||
Changes of existing tools:
|
||||
- lscpumf: Add support for IBM z14 hardware counters
|
||||
- libdasd: Introduce libdasd and use for dasd tools
|
||||
- zipl: Always build and link without PIE
|
||||
|
||||
Bug Fixes:
|
||||
- zgetdump: Fix handling of DASD multi-volume dump for partitions above 4 GB
|
||||
- zdev: Fix zdev dracut module aborting on unknown root device
|
||||
|
||||
* __v2.2.0 (2017-12-07)__
|
||||
|
||||
|
||||
2
Makefile
2
Makefile
@@ -3,7 +3,7 @@ ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/ar
|
||||
# Include common definitions
|
||||
include common.mak
|
||||
|
||||
LIB_DIRS = libvtoc libu2s libutil libzds libdasd libvmdump libccw
|
||||
LIB_DIRS = libvtoc libu2s libutil libzds libdasd libvmdump libccw libvmcp
|
||||
TOOL_DIRS = zipl zdump fdasd dasdfmt dasdview tunedasd \
|
||||
tape390 osasnmpd qetharp ip_watcher qethconf scripts zconf \
|
||||
vmconvert vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \
|
||||
|
||||
16
README.md
16
README.md
@@ -264,12 +264,16 @@ build options:
|
||||
| pfm | `HAVE_PFM` | cpacfstats |
|
||||
| net-snmp | `HAVE_SNMP` | osasnmpd |
|
||||
| glibc-static | `HAVE_LIBC_STATIC` | zfcpdump |
|
||||
| openssl | `HAVE_OPENSSL` | zkey |
|
||||
| cryptsetup | `HAVE_CRYPTSETUP2` | zkey-cryptsetup |
|
||||
| json-c | `HAVE_JSONC` | zkey-cryptsetup |
|
||||
|
||||
This table lists additional build or install options:
|
||||
|
||||
| __COMPONENT__ | __OPTION__ | __TOOLS__ |
|
||||
|----------------|:----------------:|:-------------------------------:|
|
||||
| dracut | `HAVE_DRACUT` | zdev |
|
||||
| initramfs-tools| `HAVE_INITRAMFS` | zdev |
|
||||
|
||||
The s390-tools build process uses "pkg-config" if available and hard-coded
|
||||
compiler and linker options otherwise.
|
||||
@@ -366,3 +370,15 @@ the different tools are provided:
|
||||
For running znetconf these programs are required:
|
||||
- modprobe (kmod)
|
||||
- vmcp (s390-tools)
|
||||
|
||||
* zkey:
|
||||
For building the zkey tools you need openssl version 0.9.7 or newer installed
|
||||
(openssl-devel.rpm). Also required are cryptsetup version 2.0.3 or newer
|
||||
(cryptsetup-devel.rpm), and json-c version 0.12 or newer (json-c-devel.rpm).
|
||||
Tip: you may skip the zkey build by adding `HAVE_OPENSSL=0`, and you may
|
||||
may skip the zkey-cryptsetup build by adding `HAVE_CRYPTSETUP2=0`, or
|
||||
`HAVE_JSONC=0` to the make invocation.
|
||||
A new group 'zkeyadm' needs to be created and all users intending to use the
|
||||
tool must be added to this group. The owner of the default key repository
|
||||
'/etc/zkey/repository' must be set to group 'zkeyadm' with write permission
|
||||
for this group.
|
||||
|
||||
18
common.mak
18
common.mak
@@ -5,7 +5,7 @@ COMMON_INCLUDED = true
|
||||
# The variable "DISTRELEASE" should be overwritten in rpm spec files with:
|
||||
# "make DISTRELEASE=%{release}" and "make install DISTRELEASE=%{release}"
|
||||
VERSION = 2
|
||||
RELEASE = 2
|
||||
RELEASE = 6
|
||||
PATCHLEVEL = 0
|
||||
DISTRELEASE = build-$(shell date +%Y%m%d)
|
||||
S390_TOOLS_RELEASE = $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)
|
||||
@@ -218,12 +218,22 @@ endif
|
||||
export AS LD CC CPP AR NM STRIP OBJCOPY OBJDUMP INSTALL CFLAGS CXXFLAGS \
|
||||
LDFLAGS CPPFLAGS ALL_CFLAGS ALL_CXXFLAGS ALL_LDFLAGS ALL_CPPFLAGS
|
||||
|
||||
ifneq ($(shell $(CC_SILENT) -dumpspecs 2>/dev/null | grep -e '[^f]no-pie'),)
|
||||
NO_PIE_CFLAGS := -fno-pie
|
||||
NO_PIE_LINKFLAGS := -no-pie
|
||||
NO_PIE_LDFLAGS := -no-pie
|
||||
else
|
||||
NO_PIE_CFLAGS :=
|
||||
NO_PIE_LINKFLAGS :=
|
||||
NO_PIE_LDFLAGS :=
|
||||
endif
|
||||
|
||||
# Overwrite implicite makefile rules for having nice compile output
|
||||
%.o: %.c
|
||||
$(CC) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -c $< -o $@
|
||||
ifeq ("${C}","1")
|
||||
$(CHECKTOOL) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -c $< -o $@
|
||||
endif
|
||||
$(CC) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -c $< -o $@
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) $(ALL_CPPFLAGS) $(ALL_CXXFLAGS) -c $< -o $@
|
||||
@@ -328,6 +338,10 @@ $(rootdir)/libvmdump/libvmdump.a: $(rootdir)/libvmdump
|
||||
$(MAKE) -C $(rootdir)/libvmdump/ libvmdump.a
|
||||
.PHONY: $(rootdir)/libvmdump
|
||||
|
||||
$(rootdir)/libvmcp/libvmcp.a: $(rootdir)/libvmcp
|
||||
$(MAKE) -C $(rootdir)/libvmcp/ libvmcp.a
|
||||
.PHONY: $(rootdir)/libvmcp
|
||||
|
||||
$(rootdir)/zipl/boot/data.o:
|
||||
$(MAKE) -C $(rootdir)/zipl/boot/ data.o
|
||||
|
||||
|
||||
@@ -4,10 +4,12 @@ include ../common.mak
|
||||
|
||||
|
||||
CPUMF_DATADIR = $(TOOLS_DATADIR)/cpumf
|
||||
DATA_FILES = cpum-cf-hw-counter.map cpum-cf-generic.ctr \
|
||||
DATA_FILES = cpum-cf-hw-counter.map \
|
||||
cpum-cf-cfvn-1.ctr cpum-cf-cfvn-3.ctr \
|
||||
cpum-cf-csvn-generic.ctr \
|
||||
cpum-cf-extended-z10.ctr cpum-cf-extended-z196.ctr \
|
||||
cpum-cf-extended-zEC12.ctr cpum-sf-modes.ctr \
|
||||
cpum-cf-extended-z13.ctr
|
||||
cpum-cf-extended-z13.ctr cpum-cf-extended-z14.ctr
|
||||
LIB_FILES = bin/cpumf_helper
|
||||
USRBIN_SCRIPTS = bin/lscpumf
|
||||
USRSBIN_SCRIPTS = bin/chcpumf
|
||||
|
||||
54
cpumf/bin/cpumf_helper.in
Normal file → Executable file
54
cpumf/bin/cpumf_helper.in
Normal file → Executable file
@@ -172,7 +172,7 @@ sub cpumf_parse_ctrdef($;$)
|
||||
|
||||
# Parse short description (optional)
|
||||
if ($line =~ m/^Short-Description:\s*(\S.*)?$/) {
|
||||
$h->{ctr}->{shortdesc} = $1 || "";
|
||||
$h->{$ctr}->{shortdesc} = $1 || "";
|
||||
|
||||
# Parse start of counter description
|
||||
} elsif ($line =~ m/^Description:\s*(\S.*)?$/) {
|
||||
@@ -210,6 +210,8 @@ my $system_z_hwtype_map = {
|
||||
2828 => 'IBM zEnterprise BC12',
|
||||
2964 => 'IBM z13',
|
||||
2965 => 'IBM z13s',
|
||||
3906 => 'IBM z14',
|
||||
3907 => 'IBM z14 ZR1',
|
||||
};
|
||||
|
||||
sub get_hardware_type()
|
||||
@@ -228,6 +230,28 @@ sub get_hardware_type()
|
||||
return $type;
|
||||
}
|
||||
|
||||
sub get_cpum_cf_version()
|
||||
{
|
||||
my $SL;
|
||||
|
||||
my $v = {
|
||||
cfvn => 0,
|
||||
csvn => 0,
|
||||
};
|
||||
|
||||
return $v unless open($SL, '<', $SERVICE_LEVELS);
|
||||
while (my $line = <$SL>) {
|
||||
# CPU-MF: Counter facility: version=3.5
|
||||
if ($line =~ m/^CPU-MF: Counter facility: version=(\d+)\.(\d+)/) {
|
||||
$v->{cfvn} = $1; # Counter First Version Number
|
||||
$v->{csvn} = $2; # Counter Second Version Number
|
||||
last;
|
||||
}
|
||||
}
|
||||
close($SL);
|
||||
return $v
|
||||
}
|
||||
|
||||
sub cpumf_load_ctrdef($;$)
|
||||
{
|
||||
my $hw_type = shift();
|
||||
@@ -236,10 +260,20 @@ sub cpumf_load_ctrdef($;$)
|
||||
my $ctrmap = cpumf_hardware_counter_map();
|
||||
return unless $ctrmap;
|
||||
|
||||
# Obtain CPU-MF counter facility versions
|
||||
my $version = get_cpum_cf_version();
|
||||
|
||||
# List of "generic" counter sets
|
||||
my @def = ();
|
||||
push @def, "cfvn-" . $version->{cfvn};
|
||||
push @def, "csvn-generic";
|
||||
|
||||
my $h = {};
|
||||
# Load generic counter sets
|
||||
cpumf_parse_ctrdef($ctrmap->{0}, $h) or
|
||||
croak "Failed to read generic counter definition: $!\n";
|
||||
# Load counter set definition
|
||||
foreach my $ent (@def) {
|
||||
cpumf_parse_ctrdef($ctrmap->{$ent}, $h) or
|
||||
croak "Failed to read counter definition for $ent: $!\n";
|
||||
}
|
||||
# Load hardware model specific counter set(s)
|
||||
if ($hw_type && $ctrmap->{$hw_type}) {
|
||||
# Hardware-model specific counter sets are:
|
||||
@@ -322,7 +356,7 @@ sub cpumf_helper_main()
|
||||
GetOptions(
|
||||
"i|info" => \$conf->{opt_info},
|
||||
"c|counter=i" => \$conf->{opt_ctr},
|
||||
"ctr-def=i" => \$conf->{opt_ctrdef},
|
||||
"ctr-def=s" => \$conf->{opt_ctrdef},
|
||||
"hardware-type" => \$conf->{opt_hwtype},
|
||||
"ctr-set-names" => \$conf->{opt_ctrset_names},
|
||||
"ctr-set-ids" => \$conf->{opt_ctrset_ids},
|
||||
@@ -427,11 +461,13 @@ B<--ctr-def> option and specify the System z hardware type.
|
||||
|
||||
Displays the System z hardware type.
|
||||
|
||||
=item B<--ctr-def> I<hardware_type>
|
||||
=item B<--ctr-def> I<ctr-definition>
|
||||
|
||||
Displays detailed information about a particular counter set for the specified
|
||||
System z hardware type, I<hardware_type>. If you specify zero for
|
||||
I<hardware_type>, type-independent counter sets are displayed.
|
||||
Displays detailed information about the specified counter definition.
|
||||
Valid counter definitions start with C<cfvn-> or <csvn-> followed by
|
||||
the counter first/second version number of the CPU-Measurement Counter
|
||||
Facility. To display counter information of model-specific counter
|
||||
sets, specify the System z hardware type for I<ctr-definition>.
|
||||
|
||||
=item B<--ctr-set-names>
|
||||
|
||||
|
||||
60
cpumf/data/cpum-cf-cfvn-1.ctr
Normal file
60
cpumf/data/cpum-cf-cfvn-1.ctr
Normal file
@@ -0,0 +1,60 @@
|
||||
Counter: 0 Name:CPU_CYCLES
|
||||
Short-Description:CPU Cycles
|
||||
Description:
|
||||
Cycle Count
|
||||
.
|
||||
Counter: 1 Name:INSTRUCTIONS
|
||||
Short-Description:Instructions
|
||||
Description:
|
||||
Instruction Count
|
||||
.
|
||||
Counter: 2 Name:L1I_DIR_WRITES
|
||||
Short-Description:L1I Directory Writes
|
||||
Description:
|
||||
Level-1 I-Cache Directory Write Count
|
||||
.
|
||||
Counter: 3 Name:L1I_PENALTY_CYCLES
|
||||
Short-Description:L1I Penalty Cycles
|
||||
Description:
|
||||
Level-1 I-Cache Penalty Cycle Count
|
||||
.
|
||||
Counter: 4 Name:L1D_DIR_WRITES
|
||||
Short-Description:L1D Directory Writes
|
||||
Description:
|
||||
Level-1 D-Cache Directory Write Count
|
||||
.
|
||||
Counter: 5 Name:L1D_PENALTY_CYCLES
|
||||
Short-Description:L1D Penalty Cycles
|
||||
Description:
|
||||
Level-1 D-Cache Penalty Cycle Count
|
||||
.
|
||||
Counter: 32 Name:PROBLEM_STATE_CPU_CYCLES
|
||||
Short-Description:Problem-State CPU Cycles
|
||||
Description:
|
||||
Problem-State Cycle Count
|
||||
.
|
||||
Counter: 33 Name:PROBLEM_STATE_INSTRUCTIONS
|
||||
Short-Description:Problem-State Instructions
|
||||
Description:
|
||||
Problem-State Instruction Count
|
||||
.
|
||||
Counter: 34 Name:PROBLEM_STATE_L1I_DIR_WRITES
|
||||
Short-Description:Problem-State L1I Directory Writes
|
||||
Description:
|
||||
Problem-State Level-1 I-Cache Directory Write Count
|
||||
.
|
||||
Counter: 35 Name:PROBLEM_STATE_L1I_PENALTY_CYCLES
|
||||
Short-Description:Problem-State L1I Penalty Cycles
|
||||
Description:
|
||||
Problem-State Level-1 I-Cache Penalty Cycle Count
|
||||
.
|
||||
Counter: 36 Name:PROBLEM_STATE_L1D_DIR_WRITES
|
||||
Short-Description:Problem-State L1D Directory Writes
|
||||
Description:
|
||||
Problem-State Level-1 D-Cache Directory Write Count
|
||||
.
|
||||
Counter: 37 Name:PROBLEM_STATE_L1D_PENALTY_CYCLES
|
||||
Short-Description:Problem-State L1D Penalty Cycles
|
||||
Description:
|
||||
Problem-State Level-1 D-Cache Penalty Cycle Count
|
||||
.
|
||||
40
cpumf/data/cpum-cf-cfvn-3.ctr
Normal file
40
cpumf/data/cpum-cf-cfvn-3.ctr
Normal file
@@ -0,0 +1,40 @@
|
||||
Counter: 0 Name:CPU_CYCLES
|
||||
Short-Description:CPU Cycles
|
||||
Description:
|
||||
Cycle Count
|
||||
.
|
||||
Counter: 1 Name:INSTRUCTIONS
|
||||
Short-Description:Instructions
|
||||
Description:
|
||||
Instruction Count
|
||||
.
|
||||
Counter: 2 Name:L1I_DIR_WRITES
|
||||
Short-Description:L1I Directory Writes
|
||||
Description:
|
||||
Level-1 I-Cache Directory Write Count
|
||||
.
|
||||
Counter: 3 Name:L1I_PENALTY_CYCLES
|
||||
Short-Description:L1I Penalty Cycles
|
||||
Description:
|
||||
Level-1 I-Cache Penalty Cycle Count
|
||||
.
|
||||
Counter: 4 Name:L1D_DIR_WRITES
|
||||
Short-Description:L1D Directory Writes
|
||||
Description:
|
||||
Level-1 D-Cache Directory Write Count
|
||||
.
|
||||
Counter: 5 Name:L1D_PENALTY_CYCLES
|
||||
Short-Description:L1D Penalty Cycles
|
||||
Description:
|
||||
Level-1 D-Cache Penalty Cycle Count
|
||||
.
|
||||
Counter: 32 Name:PROBLEM_STATE_CPU_CYCLES
|
||||
Short-Description:Problem-State CPU Cycles
|
||||
Description:
|
||||
Problem-State Cycle Count
|
||||
.
|
||||
Counter: 33 Name:PROBLEM_STATE_INSTRUCTIONS
|
||||
Short-Description:Problem-State Instructions
|
||||
Description:
|
||||
Problem-State Instruction Count
|
||||
.
|
||||
@@ -1,130 +1,98 @@
|
||||
Counter: 0 Name:CPU_CYCLES
|
||||
Description:
|
||||
Cycle Count
|
||||
.
|
||||
Counter: 1 Name:INSTRUCTIONS
|
||||
Description:
|
||||
Instruction Count
|
||||
.
|
||||
Counter: 2 Name:L1I_DIR_WRITES
|
||||
Description:
|
||||
Level-1 I-Cache Directory Write Count
|
||||
.
|
||||
Counter: 3 Name:L1I_PENALTY_CYCLES
|
||||
Description:
|
||||
Level-1 I-Cache Penalty Cycle Count
|
||||
.
|
||||
Counter: 4 Name:L1D_DIR_WRITES
|
||||
Description:
|
||||
Level-1 D-Cache Directory Write Count
|
||||
.
|
||||
Counter: 5 Name:L1D_PENALTY_CYCLES
|
||||
Description:
|
||||
Level-1 D-Cache Penalty Cycle Count
|
||||
.
|
||||
Counter: 32 Name:PROBLEM_STATE_CPU_CYCLES
|
||||
Description:
|
||||
Problem-State Cycle Count
|
||||
.
|
||||
Counter: 33 Name:PROBLEM_STATE_INSTRUCTIONS
|
||||
Description:
|
||||
Problem-State Instruction Count
|
||||
.
|
||||
Counter: 34 Name:PROBLEM_STATE_L1I_DIR_WRITES
|
||||
Description:
|
||||
Problem-State Level-1 I-Cache Directory Write Count
|
||||
.
|
||||
Counter: 35 Name:PROBLEM_STATE_L1I_PENALTY_CYCLES
|
||||
Description:
|
||||
Problem-State Level-1 I-Cache Penalty Cycle Count
|
||||
.
|
||||
Counter: 36 Name:PROBLEM_STATE_L1D_DIR_WRITES
|
||||
Description:
|
||||
Problem-State Level-1 D-Cache Directory Write Count
|
||||
.
|
||||
Counter: 37 Name:PROBLEM_STATE_L1D_PENALTY_CYCLES
|
||||
Description:
|
||||
Problem-State Level-1 D-Cache Penalty Cycle Count
|
||||
.
|
||||
Counter: 64 Name:PRNG_FUNCTIONS
|
||||
Short-Description:PRNG Functions
|
||||
Description:
|
||||
Total number of the PRNG functions issued by the CPU
|
||||
.
|
||||
Counter: 65 Name:PRNG_CYCLES
|
||||
Short-Description:PRNG Cycles
|
||||
Description:
|
||||
Total number of CPU cycles when the DEA/AES coprocessor is busy
|
||||
performing PRNG functions issued by the CPU
|
||||
.
|
||||
Counter: 66 Name:PRNG_BLOCKED_FUNCTIONS
|
||||
Short-Description:PRNG Blocked Functions
|
||||
Description:
|
||||
Total number of the PRNG functions that are issued by the CPU and are
|
||||
blocked because the DEA/AES coprocessor is busy performing a function
|
||||
issued by another CPU
|
||||
.
|
||||
Counter: 67 Name:PRNG_BLOCKED_CYCLES
|
||||
Short-Description:PRNG Blocked Cycles
|
||||
Description:
|
||||
Total number of CPU cycles blocked for the PRNG functions issued by
|
||||
the CPU because the DEA/AES coprocessor is busy performing a function
|
||||
issued by another CPU
|
||||
.
|
||||
Counter: 68 Name:SHA_FUNCTIONS
|
||||
Short-Description:SHA Functions
|
||||
Description:
|
||||
Total number of SHA functions issued by the CPU
|
||||
.
|
||||
Counter: 69 Name:SHA_CYCLES
|
||||
Short-Description:SHA Cycles
|
||||
Description:
|
||||
Total number of CPU cycles when the SHA coprocessor is busy performing
|
||||
the SHA functions issued by the CPU
|
||||
.
|
||||
Counter: 70 Name:SHA_BLOCKED_FUNCTIONS
|
||||
Short-Description:SHA Blocked Functions
|
||||
Description:
|
||||
Total number of the SHA functions that are issued by the CPU and are
|
||||
blocked because the SHA coprocessor is busy performing a function issued
|
||||
by another CPU
|
||||
.
|
||||
Counter: 71 Name:SHA_BLOCKED_CYCLES
|
||||
Short-Description:SHA Bloced Cycles
|
||||
Description:
|
||||
Total number of CPU cycles blocked for the SHA functions issued by the
|
||||
CPU because the SHA coprocessor is busy performing a function issued
|
||||
by another CPU
|
||||
.
|
||||
Counter: 72 Name:DEA_FUNCTIONS
|
||||
Short-Description:DEA Functions
|
||||
Description:
|
||||
Total number of the DEA functions issued by the CPU
|
||||
.
|
||||
Counter: 73 Name:DEA_CYCLES
|
||||
Short-Description:DEA Cycles
|
||||
Description:
|
||||
Total number of CPU cycles when the DEA/AES coprocessor is busy
|
||||
performing the DEA functions issued by the CPU
|
||||
.
|
||||
Counter: 74 Name:DEA_BLOCKED_FUNCTIONS
|
||||
Short-Description:DEA Blocked Functions
|
||||
Description:
|
||||
Total number of the DEA functions that are issued by the CPU and are
|
||||
blocked because the DEA/AES coprocessor is busy performing a function
|
||||
issued by another CPU
|
||||
.
|
||||
Counter: 75 Name:DEA_BLOCKED_CYCLES
|
||||
Short-Description:DEA Blocked Cycles
|
||||
Description:
|
||||
Total number of CPU cycles blocked for the DEA functions issued by the
|
||||
CPU because the DEA/AES coprocessor is busy performing a function issued
|
||||
by another CPU
|
||||
.
|
||||
Counter: 76 Name:AES_FUNCTIONS
|
||||
Short-Description:AES Functions
|
||||
Description:
|
||||
Total number of AES functions issued by the CPU
|
||||
.
|
||||
Counter: 77 Name:AES_CYCLES
|
||||
Short-Description:AES Cycles
|
||||
Description:
|
||||
Total number of CPU cycles when the DEA/AES coprocessor is busy
|
||||
performing the AES functions issued by the CPU
|
||||
.
|
||||
Counter: 78 Name:AES_BLOCKED_FUNCTIONS
|
||||
Short-Description:AES Blocked Functions
|
||||
Description:
|
||||
Total number of AES functions that are issued by the CPU and are blocked
|
||||
because the DEA/AES coprocessor is busy performing a function issued
|
||||
by another CPU
|
||||
.
|
||||
Counter: 79 Name:AES_BLOCKED_CYCLES
|
||||
Short-Description:AES Blocked Cycles
|
||||
Description:
|
||||
Total number of CPU cycles blocked for the AES functions issued by the
|
||||
CPU because the DEA/AES coprocessor is busy performing a function issued
|
||||
@@ -1,96 +1,114 @@
|
||||
Counter: 128 Name:L1I_L2_SOURCED_WRITES
|
||||
Short-Description:L1I L2 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 I-Cache directory where the returned
|
||||
cache line was sourced from the Level-2 (L1.5) cache
|
||||
.
|
||||
Counter: 129 Name:L1D_L2_SOURCED_WRITES
|
||||
Short-Description:L1D L2 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 D-Cache directory where the installed
|
||||
cache line was sourced from the Level-2 (L1.5) cache
|
||||
.
|
||||
Counter: 130 Name:L1I_L3_LOCAL_WRITES
|
||||
Short-Description:L1I L3 Local Writes
|
||||
Description:
|
||||
A directory write to the Level-1 I-Cache directory where the installed
|
||||
cache line was sourced from the Level-3 cache that is on the same book
|
||||
as the Instruction cache (Local L2 cache)
|
||||
.
|
||||
Counter: 131 Name:L1D_L3_LOCAL_WRITES
|
||||
Short-Description:L1D L3 Local Writes
|
||||
Description:
|
||||
A directory write to the Level-1 D-Cache directory where the installtion
|
||||
cache line was source from the Level-3 cache that is on the same book
|
||||
as the Data cache (Local L2 cache)
|
||||
.
|
||||
Counter: 132 Name:L1I_L3_REMOTE_WRITES
|
||||
Short-Description:L1I L3 Remote Writes
|
||||
Description:
|
||||
A directory write to the Level-1 I-Cache directory where the installed
|
||||
cache line was sourced from a Level-3 cache that is not on the same
|
||||
book as the Instruction cache (Remote L2 cache)
|
||||
.
|
||||
Counter: 133 Name:L1D_L3_REMOTE_WRITES
|
||||
Short-Description:L1D L3 Remote Writes
|
||||
Description:
|
||||
A directory write to the Level-1 D-Cache directory where the installed
|
||||
cache line was sourced from a Level-3 cache that is not on the same
|
||||
book as the Data cache (Remote L2 cache)
|
||||
.
|
||||
Counter: 134 Name:L1D_LMEM_SOURCED_WRITES
|
||||
Short-Description:L1D Local Memory Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 D-Cache directory where the installed
|
||||
cache line was sourced from memory that is attached to the same book
|
||||
as the Data cache (Local Memory)
|
||||
.
|
||||
Counter: 135 Name:L1I_LMEM_SOURCED_WRITES
|
||||
Short-Description:L1I Local Memory Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 I-Cache where the installed cache
|
||||
line was sourced from memory that is attached to the s ame book as the
|
||||
Instruction cahe (local Memory)
|
||||
Instruction cache (Local Memory)
|
||||
.
|
||||
Counter: 136 Name:L1D_RO_EXCL_WRITES
|
||||
Short-Description:L1D Read-only Exclusive Writes
|
||||
Description:
|
||||
A directory write to the Level-1 D-Cache where the line was originally
|
||||
in a Read-Only state in the cache but has been updated to be in the
|
||||
Exclusive state that allows stores to the cache line
|
||||
.
|
||||
Counter: 137 Name:L1I_CACHELINE_INVALIDATES
|
||||
Short-Description:L1I Cacheline Invalidates
|
||||
Description:
|
||||
A cache line in the Level-1 I-Cache has been invalidated by a store on
|
||||
the same CPU as the Level-1 I-Cache
|
||||
.
|
||||
Counter: 138 Name:ITLB1_WRITES
|
||||
Short-Description:ITLB1 Writes
|
||||
Description:
|
||||
A translation entry has been written into the Level-1 Instruction
|
||||
Translation Lookaside Buffer
|
||||
.
|
||||
Counter: 139 Name:DTLB1_WRITES
|
||||
Short-Description:DTLB1 Writes
|
||||
Description:
|
||||
A translation entry has been written to the Level-1 Data Translation
|
||||
Lookaside Buffer
|
||||
.
|
||||
Counter: 140 Name:TLB2_PTE_WRITES
|
||||
Short-Description:TLB2 PTE Writes
|
||||
Description:
|
||||
A translation entry has been written to the Level-2 TLB Page Table
|
||||
Entry arrays
|
||||
.
|
||||
Counter: 141 Name:TLB2_CRSTE_WRITES
|
||||
Short-Description:TLB2 CRSTE Writes
|
||||
Description:
|
||||
A translation entry has been written to the Level-2 TLB Common Region
|
||||
Segment Table Entry arrays
|
||||
.
|
||||
Counter: 142 Name:TLB2_CRSTE_HPAGE_WRITES
|
||||
Short-Description:TLB2 CRSTE One-Megabyte Page Writes
|
||||
Description:
|
||||
A translation entry has been written to the Level-2 TLB Common Region
|
||||
Segment Table Entry arrays for a one-megabyte large page translation
|
||||
.
|
||||
Counter: 145 Name:ITLB1_MISSES
|
||||
Short-Description:ITLB1 Misses
|
||||
Description:
|
||||
Level-1 Instruction TLB miss in progress. Incremented by one for every
|
||||
cycle an ITLB1 miss is in progress
|
||||
.
|
||||
Counter: 146 Name:DTLB1_MISSES
|
||||
Short-Description:DTLB1 Misses
|
||||
Description:
|
||||
Level-1 Data TLB miss in progress. Incremented by one for every cycle
|
||||
an DTLB1 miss is in progress
|
||||
.
|
||||
Counter: 147 Name:L2C_STORES_SENT
|
||||
Short-Description:L2C Stores Sent
|
||||
Description:
|
||||
Incremented by one for every store sent to Level-2 (L1.5) cache
|
||||
.
|
||||
|
||||
@@ -16,288 +16,343 @@
|
||||
#
|
||||
# Extended Counter Set
|
||||
# ---------------------------------------------------------------------
|
||||
Counter:128 Name:L1D_WRITES_RO_EXCL
|
||||
Counter:128 Name:L1D_RO_EXCL_WRITES
|
||||
Short-Description:L1D Read-only Exclusive Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache where the line was
|
||||
originally in a Read-Only state in the cache but has been updated
|
||||
to be in the Exclusive state that allows stores to the cache line.
|
||||
.
|
||||
Counter:129 Name:DTLB1_WRITES
|
||||
Short-Description:DTLB1 Writes
|
||||
Description:
|
||||
A translation entry has been written to the Level-1 Data Translation
|
||||
Lookaside Buffer
|
||||
.
|
||||
Counter:130 Name:DTLB1_MISSES
|
||||
Short-Description:DTLB1 Misses
|
||||
Description:
|
||||
Level-1 Data TLB miss in progress. Incremented by one for every cycle
|
||||
a DTLB1 miss is in progress.
|
||||
.
|
||||
Counter:131 Name:DTLB1_HPAGE_WRITES
|
||||
Short-Description:DTLB1 One-Megabyte Page Writes
|
||||
Description:
|
||||
A translation entry has been written to the Level-1 Data Translation
|
||||
Lookaside Buffer for a one-megabyte page
|
||||
.
|
||||
Counter:132 Name:DTLB1_GPAGE_WRITES
|
||||
Short-Description:DTLB1 Two-Gigabyte Page Writes
|
||||
A translation entry has been written to the Level-1 Data Translation
|
||||
Lookaside Buffer for a two-gigabyte page.
|
||||
.
|
||||
Counter:133 Name:L1D_L2D_SOURCED_WRITES
|
||||
Short-Description:L1D L2D Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from the Level-2 Data cache
|
||||
.
|
||||
Counter:134 Name:ITLB1_WRITES
|
||||
Short-Description:ITLB1 Writes
|
||||
Description:
|
||||
A translation entry has been written to the Level-1 Instruction
|
||||
Translation Lookaside Buffer
|
||||
.
|
||||
Counter:135 Name:ITLB1_MISSES
|
||||
Short-Description:ITLB1 Misses
|
||||
Description:
|
||||
Level-1 Instruction TLB miss in progress. Incremented by one for every
|
||||
cycle an ITLB1 miss is in progress
|
||||
.
|
||||
Counter:136 Name:L1I_L2I_SOURCED_WRITES
|
||||
Short-Description:L1I L2I Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where the
|
||||
returned cache line was sourced from the Level-2 Instruction cache
|
||||
.
|
||||
Counter:137 Name:TLB2_PTE_WRITES
|
||||
Short-Description:TLB2 PTE Writes
|
||||
Description:
|
||||
A translation entry has been written to the Level-2 TLB Page Table
|
||||
Entry arrays
|
||||
.
|
||||
Counter:138 Name:TLB2_CRSTE_HPAGE_WRITES
|
||||
Short-Description:TLB2 CRSTE One-Megabyte Page Writes
|
||||
Description:
|
||||
A translation entry has been written to the Level-2 TLB Combined Region
|
||||
Segment Table Entry arrays for a one-megabyte large page translation
|
||||
.
|
||||
Counter:139 Name:TLB2_CRSTE_WRITES
|
||||
Short-Description:TLB2 CRSTE Writes
|
||||
Description:
|
||||
A translation entry has been written to the Level-2 TLB Combined Region
|
||||
Segment Table Entry arrays
|
||||
.
|
||||
Counter:140 Name:TX_C_TEND
|
||||
Short-Description:Completed TEND instructions in constrained TX mode
|
||||
Description:
|
||||
A TEND instruction has completed in a constrained transactional-execution
|
||||
mode
|
||||
.
|
||||
Counter:141 Name:TX_NC_TEND
|
||||
Short-Description:Completed TEND instructions in non-constrained TX mode
|
||||
Description:
|
||||
A TEND instruction has completed in a non-constrained
|
||||
transactional-execution mode
|
||||
.
|
||||
Counter:143 Name:L1C_TLB1_MISSES
|
||||
Short-Description:L1C TLB1 Misses
|
||||
Description:
|
||||
Increments by one for any cycle where a Level-1 cache or Level-1 TLB miss
|
||||
is in progress.
|
||||
.
|
||||
Counter:144 Name:L1D_ONCHIP_L3_SOURCED_WRITES
|
||||
Short-Description:L1D On-Chip L3 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from an On-Chip Level-3 cache without intervention
|
||||
.
|
||||
Counter:145 Name:L1D_ONCHIP_L3_SOURCED_WRITES_IV
|
||||
Short-Description:L1D On-Chip L3 Sourced Writes with Intervention
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from an On-Chip Level-3 cache with intervention
|
||||
.
|
||||
Counter:146 Name:L1D_ONNODE_L4_SOURCED_WRITES
|
||||
Short-Description:L1D On-Node L4 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from an On-Node Level-4 cache
|
||||
.
|
||||
Counter:147 Name:L1D_ONNODE_L3_SOURCED_WRITES_IV
|
||||
Short-Description:L1D On-Node L3 Sourced Writes with Intervention
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from an On-Node Level-3 cache with intervention
|
||||
.
|
||||
Counter:148 Name:L1D_ONNODE_L3_SOURCED_WRITES
|
||||
Short-Description:L1D On-Node L3 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from an On-Node Level-3 cache without intervention
|
||||
.
|
||||
Counter:149 Name:L1D_ONDRAWER_L4_SOURCED_WRITES
|
||||
Short-Description:L1D On-Drawer L4 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from an On-Drawer Level-4 cache
|
||||
.
|
||||
Counter:150 Name:L1D_ONDRAWER_L3_SOURCED_WRITES_IV
|
||||
Short-Description:L1D On-Drawer L3 Sourced Writes with Intervention
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from an On-Drawer Level-3 cache with intervention
|
||||
.
|
||||
Counter:151 Name:L1D_ONDRAWER_L3_SOURCED_WRITES
|
||||
Short-Description:L1D On-Drawer L3 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from an On-Drawer Level-3 cache without intervention
|
||||
.
|
||||
Counter:152 Name:L1D_OFFDRAWER_SCOL_L4_SOURCED_WRITES
|
||||
Short-Description:L1D Off-Drawer Same-Column L4 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from an Off-Drawer Same-Column Level-4 cache
|
||||
.
|
||||
Counter:153 Name:L1D_OFFDRAWER_SCOL_L3_SOURCED_WRITES_IV
|
||||
Short-Description:L1D Off-Drawer Same-Column L3 Sourced Writes with Intervention
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from an Off-Drawer Same-Column Level-3 cache with
|
||||
intervention
|
||||
.
|
||||
Counter:154 Name:L1D_OFFDRAWER_SCOL_L3_SOURCED_WRITES
|
||||
Short-Description:L1D Off-Drawer Same-Column L3 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from an Off-Drawer Same-Column Level-3 cache
|
||||
without intervention
|
||||
.
|
||||
Counter:155 Name:L1D_OFFDRAWER_FCOL_L4_SOURCED_WRITES
|
||||
Short-Description:L1D Off-Drawer Far-Column L3 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from an Off-Drawer Far-Column Level-4 cache
|
||||
.
|
||||
Counter:156 Name:L1D_OFFDRAWER_FCOL_L3_SOURCED_WRITES_IV
|
||||
Short-Description:L1D Off-Drawer Far-Column L3 Sourced Writes with Intervention
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from an Off-Drawer Far-Column Level-3 cache with
|
||||
intervention
|
||||
.
|
||||
Counter:157 Name:L1D_OFFDRAWER_FCOL_L3_SOURCED_WRITES
|
||||
Short-Description:L1D Off-Drawer Far-Column L3 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from an Off-Drawer Far-Column Level-3 cache
|
||||
without intervention
|
||||
.
|
||||
Counter:158 Name:L1D_ONNODE_MEM_SOURCED_WRITES
|
||||
Short-Description:L1D On-Node Memory Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from On-Node memory
|
||||
.
|
||||
Counter:159 Name:L1D_ONDRAWER_MEM_SOURCED_WRITES
|
||||
Short-Description:L1D On-Drawer Memory Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from On-Drawer memory
|
||||
.
|
||||
Counter:160 Name:L1D_OFFDRAWER_MEM_SOURCED_WRITES
|
||||
Short-Description:L1D Off-Drawer Memory Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from On-Drawer memory
|
||||
.
|
||||
Counter:161 Name:L1D_ONCHIP_MEM_SOURCED_WRITES
|
||||
Short-Description:L1D On-Chip Memory Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from On-Chip memory
|
||||
.
|
||||
Counter:162 Name:L1I_ONCHIP_L3_SOURCED_WRITES
|
||||
Short-Description:L1I On-Chip L3 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where the
|
||||
returned cache line was sourced from an On-Chip Level-3 cache without
|
||||
intervention
|
||||
.
|
||||
Counter:163 Name:L1I_ONCHIP_L3_SOURCED_WRITES_IV
|
||||
Short-Description:L1I On-Chip L3 Sourced Writes with Intervention
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where the
|
||||
returned cache line was sourced from an On Chip Level-3 cache with
|
||||
intervention
|
||||
.
|
||||
Counter:164 Name:L1I_ONNODE_L4_SOURCED_WRITES
|
||||
Short-Description:L1I On-Chip L4 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where the
|
||||
returned cache line was sourced from an On-Node Level-4 cache
|
||||
.
|
||||
Counter:165 Name:L1I_ONNODE_L3_SOURCED_WRITES_IV
|
||||
Short-Description:L1I On-Node L3 Sourced Writes with Intervention
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where
|
||||
the returned cache line was sourced from an On-Node Level-3 cache
|
||||
with intervention
|
||||
.
|
||||
Counter:166 Name:L1I_ONNODE_L3_SOURCED_WRITES
|
||||
Short-Description:L1I On-Node L3 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where
|
||||
the returned cache line was sourced from an On-Node Level-3 cache
|
||||
without intervention
|
||||
.
|
||||
Counter:167 Name:L1I_ONDRAWER_L4_SOURCED_WRITES
|
||||
Short-Description:L1I On-Drawer L4 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where
|
||||
the returned cache line was sourced from an On-Drawer Level-4 cache
|
||||
.
|
||||
Counter:168 Name:L1I_ONDRAWER_L3_SOURCED_WRITES_IV
|
||||
Short-Description:L1I On-Drawer L3 Sourced Writes with Intervention
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where
|
||||
the returned cache line was sourced from an On-Drawer Level-3 cache
|
||||
with intervention
|
||||
.
|
||||
Counter:169 Name:L1I_ONDRAWER_L3_SOURCED_WRITES
|
||||
Short-Description:L1I On-Drawer L3 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where
|
||||
the returned cache line was sourced from an On-Drawer Level-3 cache
|
||||
without intervention
|
||||
.
|
||||
Counter:170 Name:L1I_OFFDRAWER_SCOL_L4_SOURCED_WRITES
|
||||
Short-Description:L1I Off-Drawer Same-Column L4 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where
|
||||
the returned cache line was sourced from an Off-Drawer Same-Column
|
||||
Level-4 cache
|
||||
.
|
||||
Counter:171 Name:L1I_OFFDRAWER_SCOL_L3_SOURCED_WRITES_IV
|
||||
Short-Description:L1I Off-Drawer Same-Column L3 Sourced Writes with Intervention
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where
|
||||
the returned cache line was sourced from an Off-Drawer Same-Column
|
||||
Level-3 cache with intervention
|
||||
.
|
||||
Counter:172 Name:L1I_OFFDRAWER_SCOL_L3_SOURCED_WRITES
|
||||
Short-Description:L1I Off-Drawer Same-Column L3 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where
|
||||
the returned cache line was sourced from an Off-Drawer Same-Column
|
||||
Level-3 cache without intervention
|
||||
.
|
||||
Counter:173 Name:L1I_OFFDRAWER_FCOL_L4_SOURCED_WRITES
|
||||
Short-Description:L1I Off-Drawer Far-Column L4 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where
|
||||
the returned cache line was sourced from an Off-Drawer Far-Column
|
||||
Level-4 cache
|
||||
.
|
||||
Counter:174 Name:L1I_OFFDRAWER_FCOL_L3_SOURCED_WRITES_IV
|
||||
Short-Description:L1I Off-Drawer Far-Column L3 Sourced Writes with Intervention
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where
|
||||
the returned cache line was sourced from an Off-Drawer Far-Column
|
||||
Level-3 cache with intervention
|
||||
.
|
||||
Counter:175 Name:L1I_OFFDRAWER_FCOL_L3_SOURCED_WRITES
|
||||
Short-Description:L1I Off-Drawer Far-Column L3 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where
|
||||
the returned cache line was sourced from an Off-Drawer Far-Column
|
||||
Level-3 cache without intervention
|
||||
.
|
||||
Counter:176 Name:L1I_ONNODE_MEM_SOURCED_WRITES
|
||||
Short-Description:L1I On-Node Memory Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where
|
||||
the returned cache line was sourced from On-Node memory
|
||||
.
|
||||
Counter:177 Name:L1I_ONDRAWER_MEM_SOURCED_WRITES
|
||||
Short-Description:L1I On-Drawer Memory Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where
|
||||
the returned cache line was sourced from On-Drawer memory
|
||||
.
|
||||
Counter:178 Name:L1I_OFFDRAWER_MEM_SOURCED_WRITES
|
||||
Short-Description:L1I Off-Drawer Memory Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where
|
||||
the returned cache line was sourced from On-Drawer memory
|
||||
.
|
||||
Counter:179 Name:L1I_ONCHIP_MEM_SOURCED_WRITES
|
||||
Short-Description:L1I On-Chip Memory Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where
|
||||
the returned cache line was sourced from On-Chip memory
|
||||
.
|
||||
Counter:218 Name:TX_NC_TABORT
|
||||
Short-Description:Aborted transactions in non-constrained TX mode
|
||||
Description:
|
||||
A transaction abort has occurred in a non-constrained
|
||||
transactional-execution mode
|
||||
.
|
||||
Counter:219 Name:TX_C_TABORT_NO_SPECIAL
|
||||
Short-Description:Aborted transactions in constrained TX mode not using special completion logic
|
||||
Description:
|
||||
A transaction abort has occurred in a constrained transactional-execution
|
||||
mode and the CPU is not using any special logic to allow the transaction
|
||||
to complete
|
||||
.
|
||||
Counter:220 Name:TX_C_TABORT_SPECIAL
|
||||
Short-Description:Aborted transactions in constrained TX mode using special completion logic
|
||||
Description:
|
||||
A transaction abort has occurred in a constrained transactional-execution
|
||||
mode and the CPU is using special logic to allow the transaction to
|
||||
@@ -307,10 +362,12 @@ complete
|
||||
# MT-diagnostic counter set
|
||||
# ---------------------------------------------------------------------
|
||||
Counter:448 Name:MT_DIAG_CYCLES_ONE_THR_ACTIVE
|
||||
Short-Description:Cycle count with one thread active
|
||||
Description:
|
||||
Cycle count with one thread active
|
||||
.
|
||||
Counter:449 Name:MT_DIAG_CYCLES_TWO_THR_ACTIVE
|
||||
Short-Description:Cycle count with two threads active
|
||||
Description:
|
||||
Cycle count with two threads active
|
||||
.
|
||||
|
||||
357
cpumf/data/cpum-cf-extended-z14.ctr
Normal file
357
cpumf/data/cpum-cf-extended-z14.ctr
Normal file
@@ -0,0 +1,357 @@
|
||||
# Counter decriptions for the
|
||||
# IBM z14 extended counter and MT-diagnostic counter set
|
||||
#
|
||||
# Notes for transactional-execution mode symbolic names:
|
||||
# TX .. transactional-execution mode
|
||||
# NC .. nonconstrained
|
||||
# C .. constrained
|
||||
#
|
||||
# Undefined counters in the extended counter set:
|
||||
# 142
|
||||
# 158-161
|
||||
# 176-223
|
||||
# 227-231
|
||||
# 233-242
|
||||
# 246-255
|
||||
# Undefined counters in the MT-diagnostic counter set:
|
||||
# 450-495
|
||||
#
|
||||
#
|
||||
# Extended Counter Set
|
||||
# ---------------------------------------------------------------------
|
||||
Counter:128 Name:L1D_RO_EXCL_WRITES
|
||||
Short-Description:L1D Read-only Exclusive Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache where the line was
|
||||
originally in a Read-Only state in the cache but has been updated
|
||||
to be in the Exclusive state that allows stores to the cache line
|
||||
.
|
||||
Counter:129 Name:DTLB2_WRITES
|
||||
Short-Description:DTLB2 Writes
|
||||
Description:
|
||||
A translation has been written into The Translation Lookaside
|
||||
Buffer 2 (TLB2) and the request was made by the data cache
|
||||
.
|
||||
Counter:130 Name:DTLB2_MISSES
|
||||
Short-Description:DTLB2 Misses
|
||||
Description:
|
||||
A TLB2 miss is in progress for a request made by the data cache.
|
||||
Incremented by one for every TLB2 miss in progress for the Level-1
|
||||
Data cache on this cycle
|
||||
.
|
||||
Counter:131 Name:DTLB2_HPAGE_WRITES
|
||||
Short-Description:DTLB2 One-Megabyte Page Writes
|
||||
Description:
|
||||
A translation entry was written into the Combined Region and Segment
|
||||
Table Entry array in the Level-2 TLB for a one-megabyte page or a
|
||||
Last Host Translation was done
|
||||
.
|
||||
Counter:132 Name:DTLB2_GPAGE_WRITES
|
||||
Short-Description:DTLB2 Two-Gigabyte Page Writes
|
||||
Description:
|
||||
A translation entry for a two-gigabyte page was written into the
|
||||
Level-2 TLB
|
||||
.
|
||||
Counter:133 Name:L1D_L2D_SOURCED_WRITES
|
||||
Short-Description:L1D L2D Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the
|
||||
returned cache line was sourced from the Level-2 Data cache
|
||||
.
|
||||
Counter:134 Name:ITLB2_WRITES
|
||||
Short-Description:ITLB2 Writes
|
||||
Description:
|
||||
A translation entry has been written into the Translation Lookaside
|
||||
Buffer 2 (TLB2) and the request was made by the instruction cache
|
||||
.
|
||||
Counter:135 Name:ITLB2_MISSES
|
||||
Short-Description:ITLB2 Misses
|
||||
Description:
|
||||
A TLB2 miss is in progress for a request made by the instruction cache.
|
||||
Incremented by one for every TLB2 miss in progress for the Level-1
|
||||
Instruction cache in a cycle
|
||||
.
|
||||
Counter:136 Name:L1I_L2I_SOURCED_WRITES
|
||||
Short-Description:L1I L2I Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where the
|
||||
returned cache line was sourced from the Level-2 Instruction cache
|
||||
.
|
||||
Counter:137 Name:TLB2_PTE_WRITES
|
||||
Short-Description:TLB2 PTE Writes
|
||||
Description:
|
||||
A translation entry was written into the Page Table Entry array in the
|
||||
Level-2 TLB
|
||||
.
|
||||
Counter:138 Name:TLB2_CRSTE_WRITES
|
||||
Short-Description:TLB2 CRSTE Writes
|
||||
Description:
|
||||
Translation entries were written into the Combined Region and Segment
|
||||
Table Entry array and the Page Table Entry array in the Level-2 TLB
|
||||
.
|
||||
Counter:139 Name:TLB2_ENGINES_BUSY
|
||||
Short-Description:TLB2 Engines Busy
|
||||
Description:
|
||||
The number of Level-2 TLB translation engines busy in a cycle
|
||||
.
|
||||
Counter:140 Name:TX_C_TEND
|
||||
Short-Description:Completed TEND instructions in constrained TX mode
|
||||
Description:
|
||||
A TEND instruction has completed in a constrained transactional-execution
|
||||
mode
|
||||
.
|
||||
Counter:141 Name:TX_NC_TEND
|
||||
Short-Description:Completed TEND instructions in non-constrained TX mode
|
||||
Description:
|
||||
A TEND instruction has completed in a non-constrained
|
||||
transactional-execution mode
|
||||
.
|
||||
Counter:143 Name:L1C_TLB2_MISSES
|
||||
Short-Description:L1C TLB2 Misses
|
||||
Description:
|
||||
Increments by one for any cycle where a level-1 cache or level-2 TLB miss
|
||||
is in progress
|
||||
.
|
||||
Counter:144 Name:L1D_ONCHIP_L3_SOURCED_WRITES
|
||||
Short-Description:L1D On-Chip L3 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from an On-Chip Level-3 cache without intervention
|
||||
.
|
||||
Counter:145 Name:L1D_ONCHIP_MEMORY_SOURCED_WRITES
|
||||
Short-Description:L1D On-Chip Memory Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from On-Chip memory
|
||||
.
|
||||
Counter:146 Name:L1D_ONCHIP_L3_SOURCED_WRITES_IV
|
||||
Short-Description:L1D On-Chip L3 Sourced Writes with Intervention
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from an On-Chip Level-3 cache with intervention
|
||||
.
|
||||
Counter:147 Name:L1D_ONCLUSTER_L3_SOURCED_WRITES
|
||||
Short-Description:L1D On-Cluster L3 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from On-Cluster Level-3 cache withountervention
|
||||
.
|
||||
Counter:148 Name:L1D_ONCLUSTER_MEMORY_SOURCED_WRITES
|
||||
Short-Description:L1D On-Cluster Memory Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from an On-Cluster memory
|
||||
.
|
||||
Counter:149 Name:L1D_ONCLUSTER_L3_SOURCED_WRITES_IV
|
||||
Short-Description:L1D On-Cluster L3 Sourced Writes with Intervention
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from an On-Cluster Level-3 cache with intervention
|
||||
.
|
||||
Counter:150 Name:L1D_OFFCLUSTER_L3_SOURCED_WRITES
|
||||
Short-Description:L1D Off-Cluster L3 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from an Off-Cluster Level-3 cache without
|
||||
intervention
|
||||
.
|
||||
Counter:151 Name:L1D_OFFCLUSTER_MEMORY_SOURCED_WRITES
|
||||
Short-Description:L1D Off-Cluster Memory Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from Off-Cluster memory
|
||||
.
|
||||
Counter:152 Name:L1D_OFFCLUSTER_L3_SOURCED_WRITES_IV
|
||||
Short-Description:L1D Off-Cluster L3 Sourced Writes with Intervention
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from an Off-Cluster Level-3 cache with intervention
|
||||
.
|
||||
Counter:153 Name:L1D_OFFDRAWER_L3_SOURCED_WRITES
|
||||
Short-Description:L1D Off-Drawer L3 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from an Off-Drawer Level-3 cache without
|
||||
intervention
|
||||
.
|
||||
Counter:154 Name:L1D_OFFDRAWER_MEMORY_SOURCED_WRITES
|
||||
Short-Description:L1D Off-Drawer Memory Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from Off-Drawer memory
|
||||
.
|
||||
Counter:155 Name:L1D_OFFDRAWER_L3_SOURCED_WRITES_IV
|
||||
Short-Description:L1D Off-Drawer L3 Sourced Writes with Intervention
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from an Off-Drawer Level-3 cache with intervention
|
||||
.
|
||||
Counter:156 Name:L1D_ONDRAWER_L4_SOURCED_WRITES
|
||||
Short-Description:L1D On-Drawer L4 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from On-Drawer Level-4 cache
|
||||
.
|
||||
Counter:157 Name:L1D_OFFDRAWER_L4_SOURCED_WRITES
|
||||
Short-Description:L1D Off-Drawer L4 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from Off-Drawer Level-4 cache
|
||||
.
|
||||
Counter:158 Name:L1D_ONCHIP_L3_SOURCED_WRITES_RO
|
||||
Short-Description:L1D On-Chip L3 Sourced Writes read-only
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from On-Chip L3 but a read-only invalidate was
|
||||
done to remove other copies of the cache line
|
||||
.
|
||||
Counter:162 Name:L1I_ONCHIP_L3_SOURCED_WRITES
|
||||
Short-Description:L1I On-Chip L3 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where the
|
||||
returned cache ine was sourced from an On-Chip Level-3 cache without
|
||||
intervention
|
||||
.
|
||||
Counter:163 Name:L1I_ONCHIP_MEMORY_SOURCED_WRITES
|
||||
Short-Description:L1I On-Chip Memory Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where the
|
||||
returned cache ine was sourced from On-Chip memory
|
||||
.
|
||||
Counter:164 Name:L1I_ONCHIP_L3_SOURCED_WRITES_IV
|
||||
Short-Description:L1I On-Chip L3 Sourced Writes with Intervention
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where the
|
||||
returned cache ine was sourced from an On-Chip Level-3 cache with
|
||||
intervention
|
||||
.
|
||||
Counter:165 Name:L1I_ONCLUSTER_L3_SOURCED_WRITES
|
||||
Short-Description:L1I On-Cluster L3 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where the
|
||||
returned cache line was sourced from an On-Cluster Level-3 cache without
|
||||
intervention
|
||||
.
|
||||
Counter:166 Name:L1I_ONCLUSTER_MEMORY_SOURCED_WRITES
|
||||
Short-Description:L1I On-Cluster Memory Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where the
|
||||
returned cache line was sourced from an On-Cluster memory
|
||||
.
|
||||
Counter:167 Name:L1I_ONCLUSTER_L3_SOURCED_WRITES_IV
|
||||
Short-Description:L1I On-Cluster L3 Sourced Writes with Intervention
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where the
|
||||
returned cache line was sourced from On-Cluster Level-3 cache with
|
||||
intervention
|
||||
.
|
||||
Counter:168 Name:L1I_OFFCLUSTER_L3_SOURCED_WRITES
|
||||
Short-Description:L1I Off-Cluster L3 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where the
|
||||
returned cache line was sourced from an Off-Cluster Level-3 cache without
|
||||
intervention
|
||||
.
|
||||
Counter:169 Name:L1I_OFFCLUSTER_MEMORY_SOURCED_WRITES
|
||||
Short-Description:L1I Off-Cluster Memory Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where the
|
||||
returned cache line was sourced from Off-Cluster memory
|
||||
.
|
||||
Counter:170 Name:L1I_OFFCLUSTER_L3_SOURCED_WRITES_IV
|
||||
Short-Description:L1I Off-Cluster L3 Sourced Writes with Intervention
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where the
|
||||
returned cache line was sourced from an Off-Cluster Level-3 cache with
|
||||
intervention
|
||||
.
|
||||
Counter:171 Name:L1I_OFFDRAWER_L3_SOURCED_WRITES
|
||||
Short-Description:L1I Off-Drawer L3 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where the
|
||||
returned cache line was sourced from an Off-Drawer Level-3 cache without
|
||||
intervention
|
||||
.
|
||||
Counter:172 Name:L1I_OFFDRAWER_MEMORY_SOURCED_WRITES
|
||||
Short-Description:L1I Off-Drawer Memory Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where the
|
||||
returned cache line was sourced from Off-Drawer memory
|
||||
.
|
||||
Counter:173 Name:L1I_OFFDRAWER_L3_SOURCED_WRITES_IV
|
||||
Short-Description:L1I Off-Drawer L3 Sourced Writes with Intervention
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where the
|
||||
returned cache line was sourced from an Off-Drawer Level-3 cache with
|
||||
intervention
|
||||
.
|
||||
Counter:174 Name:L1I_ONDRAWER_L4_SOURCED_WRITES
|
||||
Short-Description:L1I On-Drawer L4 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where the
|
||||
returned cache line was sourced from On-Drawer Level-4 cache
|
||||
.
|
||||
Counter:175 Name:L1I_OFFDRAWER_L4_SOURCED_WRITES
|
||||
Short-Description:L1I Off-Drawer L4 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where the
|
||||
returned cache line was sourced from Off-Drawer Level-4 cache
|
||||
.
|
||||
Counter:224 Name:BCD_DFP_EXECUTION_SLOTS
|
||||
Short-Description:BCD DFP Execution Slots
|
||||
Description:
|
||||
Count of floating point execution slots used for finished Binary Coded
|
||||
Decimal to Decimal Floating Point conversions. Instructions: CDZT,
|
||||
CXZT, CZDT, CZXT
|
||||
.
|
||||
Counter:225 Name:VX_BCD_EXECUTION_SLOTS
|
||||
Short-Description:VX BCD Execution Slots
|
||||
Description:
|
||||
Count of floating point execution slots used for finished vector arithmetic
|
||||
Binary Coded Decimal instructions. Instructions: VAP, VSP, VMPVMSP, VDP,
|
||||
VSDP, VRP, VLIP, VSRP, VPSOPVCP, VTP, VPKZ, VUPKZ, VCVB, VCVBG, VCVDVCVDG
|
||||
.
|
||||
Counter:226 Name:DECIMAL_INSTRUCTIONS
|
||||
Short-Description:Decimal Instructions
|
||||
Description:
|
||||
Decimal instructions dispatched. Instructions: CVB, CVD, AP, CP, DP, ED,
|
||||
EDMK, MP, SRP, SP, ZAP
|
||||
.
|
||||
Counter:232 Name:LAST_HOST_TRANSLATIONS
|
||||
Short-Description:Last host translation done
|
||||
Description:
|
||||
Last Host Translation done
|
||||
.
|
||||
Counter:243 Name:TX_NC_TABORT
|
||||
Short-Description:Aborted transactions in non-constrained TX mode
|
||||
Description:
|
||||
A transaction abort has occurred in a non-constrained
|
||||
transactional-execution mode
|
||||
.
|
||||
Counter:244 Name:TX_C_TABORT_NO_SPECIAL
|
||||
Short-Description:Aborted transactions in constrained TX mode not using special completion logic
|
||||
Description:
|
||||
A transaction abort has occurred in a constrained transactional-execution
|
||||
mode and the CPU is not using any special logic to allow the transaction
|
||||
to complete
|
||||
.
|
||||
Counter:245 Name:TX_C_TABORT_SPECIAL
|
||||
Short-Description:Aborted transactions in constrained TX mode using special completion logic
|
||||
Description:
|
||||
A transaction abort has occurred in a constrained transactional-execution
|
||||
mode and the CPU is using special logic to allow the transaction to
|
||||
complete
|
||||
.
|
||||
#
|
||||
# MT-diagnostic counter set
|
||||
# ---------------------------------------------------------------------
|
||||
Counter:448 Name:MT_DIAG_CYCLES_ONE_THR_ACTIVE
|
||||
Short-Description:Cycle count with one thread active
|
||||
Description:
|
||||
Cycle count with one thread active
|
||||
.
|
||||
Counter:449 Name:MT_DIAG_CYCLES_TWO_THR_ACTIVE
|
||||
Short-Description:Cycle count with two threads active
|
||||
Description:
|
||||
Cycle count with two threads active
|
||||
.
|
||||
@@ -1,121 +1,145 @@
|
||||
Counter: 128 Name:L1D_L2_SOURCED_WRITES
|
||||
Short-Description:L1D L2 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 D-Cache directory where the returned
|
||||
cache line was sourced from the Level-2 cache
|
||||
.
|
||||
Counter: 129 Name:L1I_L2_SOURCED_WRITES
|
||||
Short-Description:L1I L2 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 I-Cache directory where the returned
|
||||
cache line was sourced from the Level-2 cache
|
||||
.
|
||||
Counter: 130 Name:DTLB1_MISSES
|
||||
Short-Description:DTLB1 Misses
|
||||
Description:
|
||||
Level-1 Data TLB miss in progress. Incremented by one for every cycle
|
||||
a DTLB1 miss is in progress.
|
||||
.
|
||||
Counter: 131 Name:ITLB1_MISSES
|
||||
Short-Description:ITLB1 Misses
|
||||
Description:
|
||||
Level-1 Instruction TLB miss in progress. Incremented by one for every
|
||||
cycle a ITLB1 miss is in progress.
|
||||
.
|
||||
Counter: 133 Name:L2C_STORES_SENT
|
||||
Short-Description:L2C Stores Sent
|
||||
Description:
|
||||
Incremented by one for every store sent to Level-2 cache
|
||||
.
|
||||
Counter: 134 Name:L1D_OFFBOOK_L3_SOURCED_WRITES
|
||||
Short-Description:L1D Off-Book L3 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 D-Cache directory where the returned
|
||||
cache line was sourced from an Off Book Level-3 cache
|
||||
.
|
||||
Counter: 135 Name:L1D_ONBOOK_L4_SOURCED_WRITES
|
||||
Short-Description:L1D On-Book L4 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 D-Cache directory where the returned
|
||||
cache line was sourced from an On Book Level-4 cache
|
||||
.
|
||||
Counter: 136 Name:L1I_ONBOOK_L4_SOURCED_WRITES
|
||||
Short-Description:L1I On-Book L4 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 I-Cache directory where the returned
|
||||
cache line was sourced from an On Book Level-4 cache
|
||||
.
|
||||
Counter: 137 Name:L1D_RO_EXCL_WRITES
|
||||
Short-Description:L1D Read-only Exclusive Writes
|
||||
Description:
|
||||
A directory write to the Level-1 D-Cache where the line was originally
|
||||
in a Read-Only state in the cache but has been updated to be in the
|
||||
Exclusive state that allows stores to the cache line
|
||||
.
|
||||
Counter: 138 Name:L1D_OFFBOOK_L4_SOURCED_WRITES
|
||||
Short-Description:L1D Off-Book L4 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 D-Cache directory where the returned
|
||||
cache line was sourced from an Off Book Level-4 cache
|
||||
.
|
||||
Counter: 139 Name:L1I_OFFBOOK_L4_SOURCED_WRITES
|
||||
Short-Description:L1I Off-Book L4 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 I-Cache directory where the returned
|
||||
cache line was sourced from an Off Book Level-4 cache
|
||||
.
|
||||
Counter: 140 Name:DTLB1_HPAGE_WRITES
|
||||
Short-Description:DTLB1 One-Megabyte Page Writes
|
||||
Description:
|
||||
A translation entry has been written to the Level-1 Data Translation
|
||||
Lookaside Buffer for a one-megabyte page
|
||||
.
|
||||
Counter: 141 Name:L1D_LMEM_SOURCED_WRITES
|
||||
Short-Description:L1D Local Memory Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 D-Cache where the installed cache line
|
||||
was sourced from memory that is attached to the same book as the Data
|
||||
cache (Local Memory)
|
||||
.
|
||||
Counter: 142 Name:L1I_LMEM_SOURCED_WRITES
|
||||
Short-Description:L1I Local Memory Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 I-Cache where the installed cache
|
||||
line was sourced from memory that is attached to the same book as the
|
||||
Instruction cache (Local Memory)
|
||||
.
|
||||
Counter: 143 Name:L1I_OFFBOOK_L3_SOURCED_WRITES
|
||||
Short-Description:L1I Off-Book L3 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 I-Cache directory where the returned
|
||||
cache line was sourced from an Off Book Level-3 cache
|
||||
.
|
||||
Counter: 144 Name:DTLB1_WRITES
|
||||
Short-Description:DTLB1 Writes
|
||||
Description:
|
||||
A translation entry has been written to the Level-1 Data Translation
|
||||
Lookaside Buffer
|
||||
.
|
||||
Counter: 145 Name:ITLB1_WRITES
|
||||
Short-Description:ITLB1 Writes
|
||||
Description:
|
||||
A translation entry has been written to the Level-1 Instruction
|
||||
Translation Lookaside Buffer
|
||||
.
|
||||
Counter: 146 Name:TLB2_PTE_WRITES
|
||||
Short-Description:TLB2 PTE Writes
|
||||
Description:
|
||||
A translation entry has been written to the Level-2 TLB Page Table
|
||||
Entry arrays
|
||||
.
|
||||
Counter: 147 Name:TLB2_CRSTE_HPAGE_WRITES
|
||||
Short-Description:TLB2 CRSTE One-Megabyte Page Writes
|
||||
Description:
|
||||
A translation entry has been written to the Level-2 TLB Common Region
|
||||
Segment Table Entry arrays for a one-megabyte large page translation
|
||||
.
|
||||
Counter: 148 Name:TLB2_CRSTE_WRITES
|
||||
Short-Description:TLB2 CRSTE Writes
|
||||
Description:
|
||||
A translation entry has been written to the Level-2 TLB Common Region
|
||||
Segment Table Entry arrays
|
||||
.
|
||||
Counter: 150 Name:L1D_ONCHIP_L3_SOURCED_WRITES
|
||||
Short-Description:L1D On-Chip L3 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 D-Cache directory where the returned
|
||||
cache line was sourced from an On Chip Level-3 cache
|
||||
.
|
||||
Counter: 152 Name:L1D_OFFCHIP_L3_SOURCED_WRITES
|
||||
Short-Description:L1D Off-Chip L3 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 D-Cache directory where the returned
|
||||
cache line was sourced from an Off Chip/On Book Level-3 cache
|
||||
.
|
||||
Counter: 153 Name:L1I_ONCHIP_L3_SOURCED_WRITES
|
||||
Short-Description:L1I On-Chip L3 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 I-Cache directory where the returned
|
||||
cache line was sourced from an On Chip Level-3 cache
|
||||
.
|
||||
Counter: 155 Name:L1I_OFFCHIP_L3_SOURCED_WRITES
|
||||
Short-Description:L1I Off-Chip L3 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 I-Cache directory where the returned
|
||||
cache line was sourced from an Off Chip/On Book Level-3 cache
|
||||
|
||||
@@ -1,98 +1,117 @@
|
||||
Counter: 128 Name:DTLB1_MISSES
|
||||
Short-Description:DTLB1 Misses
|
||||
Description:
|
||||
Level-1 Data TLB miss in progress. Incremented by one for every cycle
|
||||
a DTLB1 miss is in progress.
|
||||
.
|
||||
Counter:129 Name:ITLB1_MISSES
|
||||
Short-Description:ITLB1 Misses
|
||||
Description:
|
||||
Level-1 Instruction TLB miss in progress. Incremented by one for every
|
||||
cycle a ITLB1 miss is in progress.
|
||||
.
|
||||
Counter:130 Name:L1D_L2I_SOURCED_WRITES
|
||||
Short-Description:L1D L2I Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from the Level-2 Instruction cache
|
||||
.
|
||||
Counter:131 Name:L1I_L2I_SOURCED_WRITES
|
||||
Short-Description:L1I L2I Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where the
|
||||
returned cache line was sourced from the Level-2 Instruction cache
|
||||
.
|
||||
Counter:132 Name:L1D_L2D_SOURCED_WRITES
|
||||
Short-Description:L1D L2D Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from the Level-2 Data cache
|
||||
.
|
||||
Counter:133 Name:DTLB1_WRITES
|
||||
Short-Description:DTLB1 Writes
|
||||
Description:
|
||||
A translation entry has been written to the Level-1 Data Translation
|
||||
Lookaside Buffer
|
||||
.
|
||||
Counter:135 Name:L1D_LMEM_SOURCED_WRITES
|
||||
Short-Description:L1D Local Memory Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache where the installed cache line
|
||||
was sourced from memory that is attached to the same book as the Data
|
||||
cache (Local Memory)
|
||||
.
|
||||
Counter:137 Name:L1I_LMEM_SOURCED_WRITES
|
||||
Short-Description:L1I Local Memory Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache where the installed cache
|
||||
line was sourced from memory that is attached to the same book as the
|
||||
Instruction cache (Local Memory)
|
||||
.
|
||||
Counter:138 Name:L1D_RO_EXCL_WRITES
|
||||
Short-Description:L1D Read-only Exclusive Writes
|
||||
Description:
|
||||
A directory write to the Level-1 D-Cache where the line was originally
|
||||
in a Read-Only state in the cache but has been updated to be in the
|
||||
Exclusive state that allows stores to the cache line
|
||||
.
|
||||
Counter:139 Name:DTLB1_HPAGE_WRITES
|
||||
Short-Description:DTLB1 One-Megabyte Page Writes
|
||||
Description:
|
||||
A translation entry has been written to the Level-1 Data Translation
|
||||
Lookaside Buffer for a one-megabyte page
|
||||
.
|
||||
Counter:140 Name:ITLB1_WRITES
|
||||
Short-Description:ITLB1 Writes
|
||||
Description:
|
||||
A translation entry has been written to the Level-1 Instruction
|
||||
Translation Lookaside Buffer
|
||||
.
|
||||
Counter:141 Name:TLB2_PTE_WRITES
|
||||
Short-Description:TLB2 PTE Writes
|
||||
Description:
|
||||
A translation entry has been written to the Level-2 TLB Page Table
|
||||
Entry arrays
|
||||
.
|
||||
Counter:142 Name:TLB2_CRSTE_HPAGE_WRITES
|
||||
Short-Description:TLB2 CRSTE One-Megabyte Page Writes
|
||||
Description:
|
||||
A translation entry has been written to the Level-2 TLB Common Region
|
||||
Segment Table Entry arrays for a one-megabyte large page translation
|
||||
.
|
||||
Counter:143 Name:TLB2_CRSTE_WRITES
|
||||
Short-Description:TLB2 CRSTE Writes
|
||||
Description:
|
||||
A translation entry has been written to the Level-2 TLB Common Region
|
||||
Segment Table Entry arrays
|
||||
.
|
||||
Counter:144 Name:L1D_ONCHIP_L3_SOURCED_WRITES
|
||||
Short-Description:L1D On-Chip L3 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from an On Chip Level-3 cache without intervention
|
||||
.
|
||||
Counter:145 Name:L1D_OFFCHIP_L3_SOURCED_WRITES
|
||||
Short-Description:L1D Off-Chip L3 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from an Off Chip/On Book Level-3 cache without
|
||||
intervention
|
||||
.
|
||||
Counter:146 Name:L1D_OFFBOOK_L3_SOURCED_WRITES
|
||||
Short-Description:L1D Off-Book L3 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from an Off Book Level-3 cache without intervention
|
||||
.
|
||||
Counter:147 Name:L1D_ONBOOK_L4_SOURCED_WRITES
|
||||
Short-Description:L1D On-Book L4 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from an On Book Level-4 cache
|
||||
.
|
||||
Counter:148 Name:L1D_OFFBOOK_L4_SOURCED_WRITES
|
||||
Short-Description:L1D Off-Book L4 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from an Off Book Level-4 cache
|
||||
@@ -104,16 +123,19 @@ cache line was sourced from an Off Book Level-4 cache
|
||||
# C .. constrained
|
||||
#
|
||||
Counter:149 Name:TX_NC_TEND
|
||||
Short-Description:Completed TEND instructions in non-constrained TX mode
|
||||
Description:
|
||||
A TEND instruction has completed in a nonconstrained
|
||||
transactional-execution mode
|
||||
.
|
||||
Counter:150 Name:L1D_ONCHIP_L3_SOURCED_WRITES_IV
|
||||
Short-Description:L1D On-Chip L3 Sourced Writes with Intervention
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from a On Chip Level-3 cache with intervention
|
||||
.
|
||||
Counter:151 Name:L1D_OFFCHIP_L3_SOURCED_WRITES_IV
|
||||
Short-Description:L1D Off-Chip L3 Sourced Writes with Intervention
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from an Off Chip/On Book Level-3 cache with
|
||||
@@ -121,73 +143,86 @@ intervention
|
||||
.
|
||||
# XXX Remove SOURCED from L1D_OFFBOOK_L3_SOURCED_WRITES...
|
||||
Counter:152 Name:L1D_OFFBOOK_L3_SOURCED_WRITES_IV
|
||||
Short-Description:L1D Off-Book L3 Sourced Writes with Intervention
|
||||
Description:
|
||||
A directory write to the Level-1 Data cache directory where the returned
|
||||
cache line was sourced from an Off Book Level-3 cache with intervention
|
||||
.
|
||||
Counter:153 Name:L1I_ONCHIP_L3_SOURCED_WRITES
|
||||
Short-Description:L1I On-Chip L3 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where the
|
||||
returned cache line was sourced from an On Chip Level-3 cache without
|
||||
intervention
|
||||
.
|
||||
Counter:154 Name:L1I_OFFCHIP_L3_SOURCED_WRITES
|
||||
Short-Description:L1I Off-Chip L3 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where the
|
||||
returned cache line was sourced from an Off Chip/On Book Level-3 cache
|
||||
without intervention
|
||||
.
|
||||
Counter:155 Name:L1I_OFFBOOK_L3_SOURCED_WRITES
|
||||
Short-Description:L1I Off-Book L3 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where the
|
||||
returned cache line was sourced from an Off Book Level-3 cache without
|
||||
intervention
|
||||
.
|
||||
Counter:156 Name:L1I_ONBOOK_L4_SOURCED_WRITES
|
||||
Short-Description:L1I On-Book L4 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where the
|
||||
returned cache line was sourced from an On Book Level-4 cache
|
||||
.
|
||||
Counter:157 Name:L1I_OFFBOOK_L4_SOURCED_WRITES
|
||||
Short-Description:L1I Off-Book L4 Sourced Writes
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where the
|
||||
returned cache line was sourced from an Off Book Level-4 cache
|
||||
.
|
||||
Counter:158 Name:TX_C_TEND
|
||||
Short-Description:Completed TEND instructions in constrained TX mode
|
||||
Description:
|
||||
A TEND instruction has completed in a constrained transactional-execution
|
||||
mode
|
||||
.
|
||||
Counter:159 Name:L1I_ONCHIP_L3_SOURCED_WRITES_IV
|
||||
Short-Description:L1I On-Chip L3 Sourced Writes with Intervention
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where the
|
||||
returned cache line was sourced from an On Chip Level-3 cache with
|
||||
intervention
|
||||
.
|
||||
Counter:160 Name:L1I_OFFCHIP_L3_SOURCED_WRITES_IV
|
||||
Short-Description:L1I Off-Chip L3 Sourced Writes with Intervention
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where the
|
||||
returned cache line was sourced from an Off Chip/On Book Level-3 cache
|
||||
with intervention
|
||||
.
|
||||
Counter:161 Name:L1I_OFFBOOK_L3_SOURCED_WRITES_IV
|
||||
Short-Description:L1I Off-Book L3 Sourced Writes with Intervention
|
||||
Description:
|
||||
A directory write to the Level-1 Instruction cache directory where the
|
||||
returned cache line was sourced from an Off Book Level-3 cache with
|
||||
intervention
|
||||
.
|
||||
Counter:177 Name:TX_NC_TABORT
|
||||
Short-Description:Aborted transactions in non-constrained TX mode
|
||||
Description:
|
||||
A transaction abort has occurred in a nonconstrained
|
||||
transactional-execution mode
|
||||
.
|
||||
Counter:178 Name:TX_C_TABORT_NO_SPECIAL
|
||||
Short-Description:Aborted transactions in constrained TX mode not using special completion logic
|
||||
Description:
|
||||
A transaction abort has occurred in a constrained transactional-execution
|
||||
mode and the CPU is not using any special logic to allow the transaction
|
||||
to complete
|
||||
.
|
||||
Counter:179 Name:TX_C_TABORT_SPECIAL
|
||||
Short-Description:Aborted transactions in constrained TX mode using special completion logic
|
||||
Description:
|
||||
A transaction abort has occurred in a constrained transactional-execution
|
||||
mode and the CPU is using special logic to allow the transaction to
|
||||
|
||||
@@ -1,11 +1,22 @@
|
||||
# CPU-measurement facilities
|
||||
#
|
||||
# Mapping of IBM System z hardware types to extended counter set defintions
|
||||
# Mapping of:
|
||||
# 1. CPU-MF counter first/second version numbers to "generic" counter
|
||||
# definitions
|
||||
# 2. IBM z Systems hardware to respective extended counter set definitions
|
||||
#
|
||||
#
|
||||
{
|
||||
# Definition # File name
|
||||
0 => 'cpum-cf-generic.ctr',
|
||||
|
||||
# CFVN
|
||||
'cfvn-1' => 'cpum-cf-cfvn-1.ctr',
|
||||
'cfvn-3' => 'cpum-cf-cfvn-3.ctr',
|
||||
|
||||
# CSVN
|
||||
'csvn-generic' => 'cpum-cf-csvn-generic.ctr',
|
||||
|
||||
# Extended counters
|
||||
2097 => 'cpum-cf-extended-z10.ctr',
|
||||
2098 => 'cpum-cf-extended-z10.ctr',
|
||||
2817 => 'cpum-cf-extended-z196.ctr',
|
||||
@@ -14,4 +25,6 @@
|
||||
2828 => 'cpum-cf-extended-zEC12.ctr',
|
||||
2964 => 'cpum-cf-extended-z13.ctr',
|
||||
2965 => 'cpum-cf-extended-z13.ctr',
|
||||
3906 => 'cpum-cf-extended-z14.ctr',
|
||||
3907 => 'cpum-cf-extended-z14.ctr',
|
||||
};
|
||||
|
||||
@@ -3,11 +3,13 @@
|
||||
#
|
||||
# Basic-sampling mode
|
||||
Counter: 0xB0000 Name:SF_CYCLES_BASIC
|
||||
Short-Description:Sample CPU Cycles Using Basic-sampling Mode
|
||||
Description:
|
||||
Sample CPU cycles using basic-sampling mode
|
||||
.
|
||||
# Diagnostic-sampling mode (includes basic-sampling)
|
||||
Counter: 0xBD000 Name:SF_CYCLES_BASIC_DIAG
|
||||
Short-Description:Sample CPU Cycle Using Diagnostic-sampling Mode (not for ordinary use)
|
||||
Description:
|
||||
Sample CPU cycle using diagnostic-sampling mode (not for ordinary use)
|
||||
.
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* dasdfmt - Format DASD ECKD devices for use by Linux
|
||||
*
|
||||
* Copyright IBM Corp. 1999, 2017
|
||||
* Copyright Red Hat Inc. 2017
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
@@ -12,6 +13,7 @@
|
||||
#include <sys/time.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#include "lib/dasd_base.h"
|
||||
#include "lib/dasd_sys.h"
|
||||
#include "lib/util_opt.h"
|
||||
#include "lib/util_prg.h"
|
||||
@@ -26,6 +28,7 @@
|
||||
#define SEC_PER_HOUR (60 * 60)
|
||||
|
||||
static int filedes;
|
||||
static char dev_filename[PATH_MAX];
|
||||
static int disk_disabled;
|
||||
static format_data_t format_params;
|
||||
static format_mode_t mode;
|
||||
@@ -33,7 +36,6 @@ static char *prog_name;
|
||||
static volatile sig_atomic_t program_interrupt_in_progress;
|
||||
static int reqsize;
|
||||
|
||||
|
||||
static const struct util_prg prg = {
|
||||
.desc = "Use dasdfmt to format a DASD ECKD device for use by Linux.\n"
|
||||
"DEVICE is the node of the device (e.g. '/dev/dasda').",
|
||||
@@ -265,24 +267,6 @@ static void draw_progress(dasdfmt_info_t *info, int cyl, unsigned int cylinders,
|
||||
}
|
||||
}
|
||||
|
||||
static int reread_partition_table(void)
|
||||
{
|
||||
int i = 0;
|
||||
int rc = -1;
|
||||
|
||||
/* If the BLKRRPART ioctl fails, it is most likely due to
|
||||
the device just beeing in use by udev. So it is worthwhile
|
||||
to retry the ioctl after a second as it is likely to succeed.
|
||||
*/
|
||||
while (rc && (i < 5)) {
|
||||
++i;
|
||||
rc = ioctl(filedes, BLKRRPART, NULL);
|
||||
if (rc)
|
||||
sleep(1);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function for recs_per_track.
|
||||
*/
|
||||
@@ -312,16 +296,18 @@ static unsigned int recs_per_track(struct dasd_eckd_characteristics *rdc,
|
||||
kn = ceil_quot(kl + 6, 232) + 1;
|
||||
return 1729 / (10 + 9 + ceil_quot(kl + 6 * kn, 34) +
|
||||
9 + ceil_quot(dl + 6 * dn, 34));
|
||||
} else
|
||||
} else {
|
||||
return 1729 / (10 + 9 + ceil_quot(dl + 6 * dn, 34));
|
||||
}
|
||||
case 0x9345:
|
||||
dn = ceil_quot(dl + 6, 232) + 1;
|
||||
if (kl) {
|
||||
kn = ceil_quot(kl + 6, 232) + 1;
|
||||
return 1420 / (18 + 7 + ceil_quot(kl + 6 * kn, 34) +
|
||||
ceil_quot(dl + 6 * dn, 34));
|
||||
} else
|
||||
} else {
|
||||
return 1420 / (18 + 7 + ceil_quot(dl + 6 * dn, 34));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -404,7 +390,7 @@ static void evaluate_format_error(dasdfmt_info_t *info, format_check_t *cdata,
|
||||
break;
|
||||
case DASD_FMT_ERR_RECORD_ID:
|
||||
ERRMSG("Invalid record ID at cyl: %d trk: %d rec: %d.\n",
|
||||
cyl, head, cdata->rec);
|
||||
cyl, head, cdata->rec);
|
||||
break;
|
||||
case DASD_FMT_ERR_KEY_LENGTH:
|
||||
ERRMSG("Invalid key length (found %d, expected %d) "
|
||||
@@ -414,6 +400,30 @@ static void evaluate_format_error(dasdfmt_info_t *info, format_check_t *cdata,
|
||||
}
|
||||
}
|
||||
|
||||
static void disk_enable(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = dasd_disk_enable(filedes);
|
||||
if (err != 0)
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: (prepare device) IOCTL "
|
||||
"BIODASDENABLE failed (%s)\n", prog_name,
|
||||
strerror(err));
|
||||
disk_disabled = 0;
|
||||
}
|
||||
|
||||
static void disk_disable(const char *device)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = dasd_disk_disable(device, &filedes);
|
||||
if (err != 0)
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: (prepare device) IOCTL "
|
||||
"BIODASDDISABLE failed. (%s)\n", prog_name,
|
||||
strerror(err));
|
||||
disk_disabled = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* signal handler:
|
||||
* enables the disk again in case of SIGTERM, SIGINT and SIGQUIT
|
||||
@@ -428,27 +438,18 @@ static void program_interrupt_signal(int sig)
|
||||
|
||||
if (disk_disabled) {
|
||||
printf("Re-accessing the device...\n");
|
||||
rc = ioctl(filedes, BIODASDENABLE, &format_params);
|
||||
if (rc)
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: (signal handler) IOCTL "
|
||||
"BIODASDENABLE failed (%s)\n", prog_name,
|
||||
strerror(errno));
|
||||
disk_enable();
|
||||
}
|
||||
|
||||
printf("Rereading the partition table...\n");
|
||||
rc = reread_partition_table();
|
||||
rc = dasd_reread_partition_table(dev_filename, 5);
|
||||
if (rc) {
|
||||
ERRMSG("%s: (signal handler) Re-reading partition table "
|
||||
"failed. (%s)\n", prog_name, strerror(errno));
|
||||
"failed. (%s)\n", prog_name, strerror(rc));
|
||||
} else {
|
||||
printf("Exiting...\n");
|
||||
}
|
||||
|
||||
rc = close(filedes);
|
||||
if (rc)
|
||||
ERRMSG("%s: (signal handler) Unable to close device (%s)\n",
|
||||
prog_name, strerror(errno));
|
||||
|
||||
signal(sig, SIG_DFL);
|
||||
raise(sig);
|
||||
}
|
||||
@@ -497,30 +498,15 @@ static void get_device_name(char *devname,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve DASD information
|
||||
*/
|
||||
static void get_device_info(dasdfmt_info_t *info)
|
||||
static void get_blocksize(const char *device, unsigned int *blksize)
|
||||
{
|
||||
dasd_information2_t dasd_info;
|
||||
int err;
|
||||
|
||||
if (ioctl(filedes, BIODASDINFO2, &dasd_info))
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl call to retrieve "
|
||||
"device information failed (%s).\n",
|
||||
prog_name, strerror(errno));
|
||||
|
||||
info->dasd_info = dasd_info;
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve blocksize of device
|
||||
*/
|
||||
static void get_blocksize(unsigned int *blksize)
|
||||
{
|
||||
if (ioctl(filedes, BLKSSZGET, blksize) != 0)
|
||||
err = dasd_get_blocksize(device, blksize);
|
||||
if (err != 0)
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl to get the blocksize "
|
||||
"of the device failed (%s).\n", prog_name,
|
||||
strerror(errno));
|
||||
strerror(err));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -534,7 +520,7 @@ static void check_blocksize(dasdfmt_info_t *info, unsigned int blksize)
|
||||
info->dasd_info.format == DASD_FORMAT_NONE)
|
||||
return;
|
||||
|
||||
get_blocksize(&dev_blksize);
|
||||
get_blocksize(dev_filename, &dev_blksize);
|
||||
if (dev_blksize != blksize) {
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "WARNING: Device is formatted with a "
|
||||
"different blocksize (%d).\nUse --mode=full to "
|
||||
@@ -576,16 +562,15 @@ static void check_layout(dasdfmt_info_t *info, unsigned int intensity)
|
||||
*/
|
||||
static void check_disk(dasdfmt_info_t *info, char *devname)
|
||||
{
|
||||
int ro, errno_save;
|
||||
int err;
|
||||
bool ro;
|
||||
|
||||
if (ioctl(filedes, BLKROGET, &ro) != 0) {
|
||||
errno_save = errno;
|
||||
close(filedes);
|
||||
err = dasd_is_ro(devname, &ro);
|
||||
if (err != 0)
|
||||
ERRMSG_EXIT(EXIT_FAILURE,
|
||||
"%s: the ioctl call to retrieve read/write "
|
||||
"status information failed (%s)\n",
|
||||
prog_name, strerror(errno_save));
|
||||
}
|
||||
prog_name, strerror(err));
|
||||
|
||||
if (ro)
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "Disk is read only!\n");
|
||||
@@ -775,9 +760,11 @@ static format_check_t check_track_format(dasdfmt_info_t *info, format_data_t *p)
|
||||
.stop_unit = p->stop_unit
|
||||
}, 0
|
||||
};
|
||||
int err;
|
||||
|
||||
if (ioctl(filedes, BIODASDCHECKFMT, &cdata)) {
|
||||
if (errno == ENOTTY) {
|
||||
err = dasd_check_format(dev_filename, &cdata);
|
||||
if (err != 0) {
|
||||
if (err == ENOTTY) {
|
||||
ERRMSG("%s: Missing kernel support for format checking",
|
||||
prog_name);
|
||||
if (mode == EXPAND) {
|
||||
@@ -788,7 +775,7 @@ static format_check_t check_track_format(dasdfmt_info_t *info, format_data_t *p)
|
||||
ERRMSG_EXIT(EXIT_FAILURE, ".\n");
|
||||
}
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: Could no check format: %s\n",
|
||||
prog_name, strerror(errno));
|
||||
prog_name, strerror(err));
|
||||
}
|
||||
|
||||
return cdata;
|
||||
@@ -804,7 +791,7 @@ static int process_tracks(dasdfmt_info_t *info, unsigned int cylinders,
|
||||
format_data_t step = *format_params;
|
||||
unsigned long step_value;
|
||||
unsigned long cur_trk;
|
||||
int cyl = 0;
|
||||
int cyl = 0, err;
|
||||
|
||||
check_hashmarks(info);
|
||||
|
||||
@@ -827,10 +814,11 @@ static int process_tracks(dasdfmt_info_t *info, unsigned int cylinders,
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (ioctl(filedes, BIODASDFMT, &step) != 0)
|
||||
err = dasd_format_disk(filedes, &step);
|
||||
if (err != 0)
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl call "
|
||||
"to format tracks failed. (%s)\n",
|
||||
prog_name, strerror(errno));
|
||||
prog_name, strerror(err));
|
||||
}
|
||||
|
||||
cyl = cur_trk / heads + 1;
|
||||
@@ -965,7 +953,7 @@ static int dasdfmt_get_volser(char *devname, dasd_information2_t *dasd_info,
|
||||
unsigned int blksize;
|
||||
volume_label_t vlabel;
|
||||
|
||||
get_blocksize(&blksize);
|
||||
get_blocksize(devname, &blksize);
|
||||
|
||||
if ((strncmp(dasd_info->type, "ECKD", 4) == 0) &&
|
||||
!dasd_info->FBA_layout) {
|
||||
@@ -992,25 +980,25 @@ static void dasdfmt_write_labels(dasdfmt_info_t *info, volume_label_t *vlabel,
|
||||
format5_label_t f5;
|
||||
format7_label_t f7;
|
||||
unsigned int blksize;
|
||||
int rc;
|
||||
int rc, fd;
|
||||
void *ipl1_record, *ipl2_record;
|
||||
int ipl1_record_len, ipl2_record_len;
|
||||
|
||||
|
||||
if (info->verbosity > 0)
|
||||
printf("Retrieving dasd information... ");
|
||||
|
||||
get_blocksize(&blksize);
|
||||
get_blocksize(dev_filename, &blksize);
|
||||
|
||||
/*
|
||||
* Don't rely on the cylinders returned by HDIO_GETGEO, they might be
|
||||
* to small. geo is only used to get the number of sectors, which may
|
||||
* vary depending on the format.
|
||||
*/
|
||||
if (ioctl(filedes, HDIO_GETGEO, &geo) != 0)
|
||||
rc = dasd_get_geo(dev_filename, &geo);
|
||||
if (rc != 0)
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: (write labels) IOCTL "
|
||||
"HDIO_GETGEO failed (%s).\n",
|
||||
prog_name, strerror(errno));
|
||||
prog_name, strerror(rc));
|
||||
|
||||
if (info->verbosity > 0)
|
||||
printf("ok\n");
|
||||
@@ -1036,26 +1024,40 @@ static void dasdfmt_write_labels(dasdfmt_info_t *info, volume_label_t *vlabel,
|
||||
ipl2_record_len = sizeof(ipl2.data);
|
||||
}
|
||||
|
||||
if (lseek(filedes, 0, SEEK_SET) != 0)
|
||||
fd = open(dev_filename, O_RDWR);
|
||||
if (fd < 0)
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: Unable to open device "
|
||||
"'%s' (%s)\n", prog_name, dev_filename,
|
||||
strerror(errno));
|
||||
|
||||
if (lseek(fd, 0, SEEK_SET) != 0) {
|
||||
close(fd);
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: lseek command 0 failed "
|
||||
"(%s)\n", prog_name, strerror(errno));
|
||||
}
|
||||
|
||||
rc = write(filedes, ipl1_record, ipl1_record_len);
|
||||
if (rc != ipl1_record_len)
|
||||
rc = write(fd, ipl1_record, ipl1_record_len);
|
||||
if (rc != ipl1_record_len) {
|
||||
close(fd);
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: Writing the bootstrap IPL1 "
|
||||
"failed, only wrote %d bytes.\n", prog_name, rc);
|
||||
}
|
||||
|
||||
label_position = blksize;
|
||||
rc = lseek(filedes, label_position, SEEK_SET);
|
||||
if (rc != label_position)
|
||||
rc = lseek(fd, label_position, SEEK_SET);
|
||||
if (rc != label_position) {
|
||||
close(fd);
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: lseek command to %i failed "
|
||||
"(%s).\n", prog_name, label_position,
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
rc = write(filedes, ipl2_record, ipl2_record_len);
|
||||
if (rc != ipl2_record_len)
|
||||
rc = write(fd, ipl2_record, ipl2_record_len);
|
||||
if (rc != ipl2_record_len) {
|
||||
close(fd);
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: Writing the bootstrap IPL2 "
|
||||
"failed, only wrote %d bytes.\n", prog_name, rc);
|
||||
}
|
||||
|
||||
/* write VTOC */
|
||||
vtoc_init_format4_label(&f4, geo.cylinders, cylinders, heads,
|
||||
@@ -1071,32 +1073,36 @@ static void dasdfmt_write_labels(dasdfmt_info_t *info, volume_label_t *vlabel,
|
||||
if (info->verbosity > 0)
|
||||
printf("Writing label...\n");
|
||||
|
||||
rc = lseek(filedes, label_position, SEEK_SET);
|
||||
if (rc != label_position)
|
||||
rc = lseek(fd, label_position, SEEK_SET);
|
||||
if (rc != label_position) {
|
||||
close(fd);
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: lseek command to %i failed "
|
||||
"(%s).\n", prog_name, label_position,
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: cdl volume labels do not contain the 'formatted_blocks' part
|
||||
* and ldl labels do not contain the key field
|
||||
*/
|
||||
if (info->cdl_format) {
|
||||
rc = write(filedes, vlabel, (sizeof(*vlabel) -
|
||||
sizeof(vlabel->formatted_blocks)));
|
||||
rc = write(fd, vlabel, (sizeof(*vlabel) -
|
||||
sizeof(vlabel->formatted_blocks)));
|
||||
} else {
|
||||
vlabel->ldl_version = 0xf2; /* EBCDIC '2' */
|
||||
vlabel->formatted_blocks = cylinders * heads * geo.sectors;
|
||||
rc = write(filedes, &vlabel->vollbl, (sizeof(*vlabel)
|
||||
- sizeof(vlabel->volkey)));
|
||||
rc = write(fd, &vlabel->vollbl, (sizeof(*vlabel)
|
||||
- sizeof(vlabel->volkey)));
|
||||
}
|
||||
|
||||
if (((rc != sizeof(*vlabel) - sizeof(vlabel->formatted_blocks)) &&
|
||||
info->cdl_format) ||
|
||||
((rc != (sizeof(*vlabel) - sizeof(vlabel->volkey))) &&
|
||||
(!info->cdl_format)))
|
||||
!info->cdl_format)) {
|
||||
close(fd);
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: Error writing volume label "
|
||||
"(%d).\n", prog_name, rc);
|
||||
}
|
||||
|
||||
if (info->verbosity > 0)
|
||||
printf("Writing VTOC... ");
|
||||
@@ -1104,48 +1110,62 @@ static void dasdfmt_write_labels(dasdfmt_info_t *info, volume_label_t *vlabel,
|
||||
label_position = (VTOC_START_CC * heads + VTOC_START_HH) *
|
||||
geo.sectors * blksize;
|
||||
|
||||
rc = lseek(filedes, label_position, SEEK_SET);
|
||||
if (rc != label_position)
|
||||
rc = lseek(fd, label_position, SEEK_SET);
|
||||
if (rc != label_position) {
|
||||
close(fd);
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: lseek command to %i failed "
|
||||
"(%s).\n", prog_name, label_position,
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
/* write VTOC FMT4 DSCB */
|
||||
rc = write(filedes, &f4, sizeof(format4_label_t));
|
||||
if (rc != sizeof(format4_label_t))
|
||||
rc = write(fd, &f4, sizeof(format4_label_t));
|
||||
if (rc != sizeof(format4_label_t)) {
|
||||
close(fd);
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: Error writing FMT4 label "
|
||||
"(%d).\n", prog_name, rc);
|
||||
}
|
||||
|
||||
label_position += blksize;
|
||||
|
||||
rc = lseek(filedes, label_position, SEEK_SET);
|
||||
if (rc != label_position)
|
||||
rc = lseek(fd, label_position, SEEK_SET);
|
||||
if (rc != label_position) {
|
||||
close(fd);
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: lseek to %i failed (%s).\n",
|
||||
prog_name, label_position, strerror(errno));
|
||||
}
|
||||
|
||||
/* write VTOC FMT5 DSCB */
|
||||
rc = write(filedes, &f5, sizeof(format5_label_t));
|
||||
if (rc != sizeof(format5_label_t))
|
||||
rc = write(fd, &f5, sizeof(format5_label_t));
|
||||
if (rc != sizeof(format5_label_t)) {
|
||||
close(fd);
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: Error writing FMT5 label "
|
||||
"(%d).\n", prog_name, rc);
|
||||
}
|
||||
|
||||
if ((cylinders * heads) > BIG_DISK_SIZE) {
|
||||
label_position += blksize;
|
||||
|
||||
rc = lseek(filedes, label_position, SEEK_SET);
|
||||
if (rc != label_position)
|
||||
rc = lseek(fd, label_position, SEEK_SET);
|
||||
if (rc != label_position) {
|
||||
close(fd);
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: lseek to %i failed "
|
||||
"(%s).\n", prog_name, label_position,
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
/* write VTOC FMT 7 DSCB (only on big disks) */
|
||||
rc = write(filedes, &f7, sizeof(format7_label_t));
|
||||
if (rc != sizeof(format7_label_t))
|
||||
rc = write(fd, &f7, sizeof(format7_label_t));
|
||||
if (rc != sizeof(format7_label_t)) {
|
||||
close(fd);
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: Error writing FMT7 "
|
||||
"label (rc=%d).\n", prog_name, rc);
|
||||
}
|
||||
}
|
||||
|
||||
fsync(filedes);
|
||||
fsync(fd);
|
||||
|
||||
close(fd);
|
||||
|
||||
if (info->verbosity > 0)
|
||||
printf("ok\n");
|
||||
@@ -1225,27 +1245,25 @@ static void dasdfmt_prepare_and_format(dasdfmt_info_t *info,
|
||||
.intensity = ((p->intensity & ~DASD_FMT_INT_FMT_NOR0)
|
||||
| DASD_FMT_INT_INVAL)
|
||||
};
|
||||
int err;
|
||||
|
||||
if (!((info->withoutprompt) && (info->verbosity < 1)))
|
||||
if (!(info->withoutprompt && (info->verbosity < 1)))
|
||||
printf("Formatting the device. This may take a while "
|
||||
"(get yourself a coffee).\n");
|
||||
|
||||
if (info->verbosity > 0)
|
||||
printf("Detaching the device...\n");
|
||||
|
||||
if (ioctl(filedes, BIODASDDISABLE, p) != 0)
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: (prepare device) IOCTL "
|
||||
"BIODASDDISABLE failed. (%s)\n", prog_name,
|
||||
strerror(errno));
|
||||
disk_disabled = 1;
|
||||
disk_disable(dev_filename);
|
||||
|
||||
if (info->verbosity > 0)
|
||||
printf("Invalidate first track...\n");
|
||||
|
||||
if (ioctl(filedes, BIODASDFMT, &temp) != 0)
|
||||
err = dasd_format_disk(filedes, &temp);
|
||||
if (err != 0)
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: (invalidate first track) IOCTL "
|
||||
"BIODASDFMT failed. (%s)\n", prog_name,
|
||||
strerror(errno));
|
||||
strerror(err));
|
||||
|
||||
/* except track 0 from standard formatting procss */
|
||||
p->start_unit = 1;
|
||||
@@ -1260,19 +1278,16 @@ static void dasdfmt_prepare_and_format(dasdfmt_info_t *info,
|
||||
if (info->verbosity > 0)
|
||||
printf("Revalidate first track...\n");
|
||||
|
||||
if (ioctl(filedes, BIODASDFMT, &temp) != 0)
|
||||
err = dasd_format_disk(filedes, &temp);
|
||||
if (err != 0)
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: (re-validate first track) IOCTL"
|
||||
" BIODASDFMT failed (%s)\n", prog_name,
|
||||
strerror(errno));
|
||||
strerror(err));
|
||||
|
||||
if (info->verbosity > 0)
|
||||
printf("Re-accessing the device...\n");
|
||||
|
||||
if (ioctl(filedes, BIODASDENABLE, p) != 0)
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: (prepare device) IOCTL "
|
||||
"BIODASDENABLE failed. (%s)\n", prog_name,
|
||||
strerror(errno));
|
||||
disk_disabled = 0;
|
||||
disk_enable();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1281,18 +1296,14 @@ static void dasdfmt_prepare_and_format(dasdfmt_info_t *info,
|
||||
static void dasdfmt_expand_format(dasdfmt_info_t *info, unsigned int cylinders,
|
||||
unsigned int heads, format_data_t *p)
|
||||
{
|
||||
if (!((info->withoutprompt) && (info->verbosity < 1)))
|
||||
if (!(info->withoutprompt && (info->verbosity < 1)))
|
||||
printf("Formatting the device. This may take a while "
|
||||
"(get yourself a coffee).\n");
|
||||
|
||||
if (info->verbosity > 0)
|
||||
printf("Detaching the device...\n");
|
||||
|
||||
if (ioctl(filedes, BIODASDDISABLE, p) != 0)
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: (prepare device) IOCTL "
|
||||
"BIODASDDISABLE failed. (%s)\n", prog_name,
|
||||
strerror(errno));
|
||||
disk_disabled = 1;
|
||||
disk_disable(dev_filename);
|
||||
|
||||
dasdfmt_format(info, cylinders, heads, p);
|
||||
|
||||
@@ -1302,11 +1313,7 @@ static void dasdfmt_expand_format(dasdfmt_info_t *info, unsigned int cylinders,
|
||||
if (info->verbosity > 0)
|
||||
printf("Re-accessing the device...\n");
|
||||
|
||||
if (ioctl(filedes, BIODASDENABLE, p) != 0)
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: (prepare device) IOCTL "
|
||||
"BIODASDENABLE failed. (%s)\n", prog_name,
|
||||
strerror(errno));
|
||||
disk_disabled = 0;
|
||||
disk_enable();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1318,6 +1325,7 @@ static void dasdfmt_quick_format(dasdfmt_info_t *info, unsigned int cylinders,
|
||||
{
|
||||
format_check_t cdata = { .expect = {0}, 0 };
|
||||
format_data_t tmp = *p;
|
||||
int err;
|
||||
|
||||
if (info->force) {
|
||||
printf("Skipping format check due to --force.\n");
|
||||
@@ -1344,25 +1352,20 @@ static void dasdfmt_quick_format(dasdfmt_info_t *info, unsigned int cylinders,
|
||||
}
|
||||
}
|
||||
|
||||
if (!((info->withoutprompt) && (info->verbosity < 1)))
|
||||
if (!(info->withoutprompt && (info->verbosity < 1)))
|
||||
printf("Formatting the first two tracks of the device.\n");
|
||||
|
||||
/* Disable the device before we do anything */
|
||||
if (ioctl(filedes, BIODASDDISABLE, p))
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl to disable the device "
|
||||
"failed. (%s)\n", prog_name, strerror(errno));
|
||||
disk_disabled = 1;
|
||||
disk_disable(dev_filename);
|
||||
|
||||
/* Now do the actual formatting of our first two tracks */
|
||||
if (ioctl(filedes, BIODASDFMT, p))
|
||||
err = dasd_format_disk(filedes, p);
|
||||
if (err != 0)
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl to format the device "
|
||||
"failed. (%s)\n", prog_name, strerror(errno));
|
||||
"failed. (%s)\n", prog_name, strerror(err));
|
||||
|
||||
/* Re-Enable the device so that we can continue working with it */
|
||||
if (ioctl(filedes, BIODASDENABLE, p))
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl to enable the device "
|
||||
"failed. (%s)\n", prog_name, strerror(errno));
|
||||
disk_disabled = 0;
|
||||
disk_enable();
|
||||
}
|
||||
|
||||
static void do_format_dasd(dasdfmt_info_t *info, char *devname,
|
||||
@@ -1371,7 +1374,7 @@ static void do_format_dasd(dasdfmt_info_t *info, char *devname,
|
||||
unsigned int heads)
|
||||
{
|
||||
char inp_buffer[5];
|
||||
int count;
|
||||
int count, err;
|
||||
|
||||
p->start_unit = 0;
|
||||
|
||||
@@ -1448,9 +1451,10 @@ static void do_format_dasd(dasdfmt_info_t *info, char *devname,
|
||||
dasdfmt_write_labels(info, vlabel, cylinders, heads);
|
||||
|
||||
printf("Rereading the partition table... ");
|
||||
if (reread_partition_table()) {
|
||||
err = dasd_reread_partition_table(dev_filename, 5);
|
||||
if (err != 0) {
|
||||
ERRMSG("%s: error during rereading the partition "
|
||||
"table: %s.\n", prog_name, strerror(errno));
|
||||
"table: %s.\n", prog_name, strerror(err));
|
||||
} else {
|
||||
printf("ok\n");
|
||||
}
|
||||
@@ -1465,7 +1469,6 @@ int main(int argc, char *argv[])
|
||||
volume_label_t vlabel;
|
||||
char old_volser[7];
|
||||
|
||||
char dev_filename[PATH_MAX];
|
||||
char str[ERR_LENGTH];
|
||||
char buf[7];
|
||||
|
||||
@@ -1636,18 +1639,17 @@ int main(int argc, char *argv[])
|
||||
|
||||
get_device_name(dev_filename, optind, argc, argv);
|
||||
|
||||
filedes = open(dev_filename, O_RDWR);
|
||||
if (filedes == -1)
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: Unable to open device %s: %s\n",
|
||||
prog_name, dev_filename, strerror(errno));
|
||||
|
||||
get_device_info(&info);
|
||||
rc = dasd_get_info(dev_filename, &info.dasd_info);
|
||||
if (rc != 0)
|
||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl call to retrieve "
|
||||
"device information failed (%s).\n",
|
||||
prog_name, strerror(rc));
|
||||
|
||||
/* Either let the user specify the blksize or get it from the kernel */
|
||||
if (!info.blksize_specified) {
|
||||
if (!(mode == FULL ||
|
||||
info.dasd_info.format == DASD_FORMAT_NONE) || info.check)
|
||||
get_blocksize(&format_params.blksize);
|
||||
get_blocksize(dev_filename, &format_params.blksize);
|
||||
else
|
||||
format_params = ask_user_for_blksize(format_params);
|
||||
}
|
||||
@@ -1686,9 +1688,5 @@ int main(int argc, char *argv[])
|
||||
do_format_dasd(&info, dev_filename, &vlabel,
|
||||
&format_params, cylinders, heads);
|
||||
|
||||
if (close(filedes) != 0)
|
||||
ERRMSG("%s: error during close: %s\ncontinuing...\n",
|
||||
prog_name, strerror(errno));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -31,120 +31,6 @@
|
||||
* SECTION: Definition needed for DASD-API (see dasd.h) *
|
||||
****************************************************************************/
|
||||
|
||||
#define DASD_IOCTL_LETTER 'D'
|
||||
|
||||
/*
|
||||
* struct dasd_information2_t
|
||||
* represents any data about the device, which is visible to userspace.
|
||||
* including format and features.
|
||||
*/
|
||||
typedef struct dasd_information2_t {
|
||||
unsigned int devno; /* S/390 devno */
|
||||
unsigned int real_devno; /* for aliases */
|
||||
unsigned int schid; /* S/390 subchannel identifier */
|
||||
unsigned int cu_type : 16; /* from SenseID */
|
||||
unsigned int cu_model : 8; /* from SenseID */
|
||||
unsigned int dev_type : 16; /* from SenseID */
|
||||
unsigned int dev_model : 8; /* from SenseID */
|
||||
unsigned int open_count;
|
||||
unsigned int req_queue_len;
|
||||
unsigned int chanq_len; /* length of chanq */
|
||||
char type[4]; /* from discipline.name, */
|
||||
/* 'none' for unknown */
|
||||
unsigned int status; /* current device level */
|
||||
unsigned int label_block; /* where to find the VOLSER */
|
||||
unsigned int FBA_layout; /* fixed block size (like AIXVOL) */
|
||||
unsigned int characteristics_size;
|
||||
unsigned int confdata_size;
|
||||
char characteristics[64]; /* from read_device_characteristics */
|
||||
char configuration_data[256]; /* from read_configuration_data */
|
||||
unsigned int format; /* format info like formatted/cdl/ldl/... */
|
||||
unsigned int features; /* dasd features like 'ro',... */
|
||||
unsigned int reserved0; /* reserved for further use ,... */
|
||||
unsigned int reserved1; /* reserved for further use ,... */
|
||||
unsigned int reserved2; /* reserved for further use ,... */
|
||||
unsigned int reserved3; /* reserved for further use ,... */
|
||||
unsigned int reserved4; /* reserved for further use ,... */
|
||||
unsigned int reserved5; /* reserved for further use ,... */
|
||||
unsigned int reserved6; /* reserved for further use ,... */
|
||||
unsigned int reserved7; /* reserved for further use ,... */
|
||||
} dasd_information2_t;
|
||||
|
||||
|
||||
struct dasd_eckd_characteristics {
|
||||
unsigned short cu_type;
|
||||
struct {
|
||||
unsigned char support:2;
|
||||
unsigned char async:1;
|
||||
unsigned char reserved:1;
|
||||
unsigned char cache_info:1;
|
||||
unsigned char model:3;
|
||||
} __attribute__ ((packed)) cu_model;
|
||||
unsigned short dev_type;
|
||||
unsigned char dev_model;
|
||||
struct {
|
||||
unsigned char mult_burst:1;
|
||||
unsigned char RT_in_LR:1;
|
||||
unsigned char reserved1:1;
|
||||
unsigned char RD_IN_LR:1;
|
||||
unsigned char reserved2:4;
|
||||
unsigned char reserved3:8;
|
||||
unsigned char defect_wr:1;
|
||||
unsigned char XRC_supported:1;
|
||||
unsigned char reserved4:1;
|
||||
unsigned char striping:1;
|
||||
unsigned char reserved5:4;
|
||||
unsigned char cfw:1;
|
||||
unsigned char reserved6:2;
|
||||
unsigned char cache:1;
|
||||
unsigned char dual_copy:1;
|
||||
unsigned char dfw:1;
|
||||
unsigned char reset_alleg:1;
|
||||
unsigned char sense_down:1;
|
||||
} __attribute__ ((packed)) facilities;
|
||||
unsigned char dev_class;
|
||||
unsigned char unit_type;
|
||||
unsigned short no_cyl;
|
||||
unsigned short trk_per_cyl;
|
||||
unsigned char sec_per_trk;
|
||||
unsigned char byte_per_track[3];
|
||||
unsigned short home_bytes;
|
||||
unsigned char formula;
|
||||
union {
|
||||
struct {
|
||||
unsigned char f1;
|
||||
unsigned short f2;
|
||||
unsigned short f3;
|
||||
} __attribute__ ((packed)) f_0x01;
|
||||
struct {
|
||||
unsigned char f1;
|
||||
unsigned char f2;
|
||||
unsigned char f3;
|
||||
unsigned char f4;
|
||||
unsigned char f5;
|
||||
} __attribute__ ((packed)) f_0x02;
|
||||
} __attribute__ ((packed)) factors;
|
||||
unsigned short first_alt_trk;
|
||||
unsigned short no_alt_trk;
|
||||
unsigned short first_dia_trk;
|
||||
unsigned short no_dia_trk;
|
||||
unsigned short first_sup_trk;
|
||||
unsigned short no_sup_trk;
|
||||
unsigned char MDR_ID;
|
||||
unsigned char OBR_ID;
|
||||
unsigned char director;
|
||||
unsigned char rd_trk_set;
|
||||
unsigned short max_rec_zero;
|
||||
unsigned char reserved1;
|
||||
unsigned char RWANY_in_LR;
|
||||
unsigned char factor6;
|
||||
unsigned char factor7;
|
||||
unsigned char factor8;
|
||||
unsigned char reserved2[3];
|
||||
unsigned char reserved3[6];
|
||||
unsigned int long_no_cyl;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*
|
||||
* Represents possible format modes that can be specified when formatting
|
||||
* a DASD.
|
||||
@@ -159,17 +45,6 @@ static const char mode_str[3][10] = {
|
||||
"Full", "Quick", "Expand"
|
||||
};
|
||||
|
||||
/*
|
||||
* struct format_data_t
|
||||
* represents all data necessary to format a dasd
|
||||
*/
|
||||
typedef struct format_data_t {
|
||||
unsigned int start_unit; /* from track */
|
||||
unsigned int stop_unit; /* to track */
|
||||
unsigned int blksize; /* sectorsize */
|
||||
unsigned int intensity;
|
||||
} format_data_t;
|
||||
|
||||
/*
|
||||
* values to be used for format_data_t.intensity
|
||||
* 0/8: normal format
|
||||
@@ -183,24 +58,6 @@ typedef struct format_data_t {
|
||||
#define DASD_FMT_INT_COMPAT 8 /* use OS/390 compatible disk layout */
|
||||
#define DASD_FMT_INT_FMT_NOR0 16 /* remove permission to write record zero */
|
||||
|
||||
/*
|
||||
* struct format_check_t
|
||||
* represents all data necessary to evaluate the format of
|
||||
* different tracks of a dasd
|
||||
*/
|
||||
typedef struct format_check_t {
|
||||
/* Input */
|
||||
struct format_data_t expect;
|
||||
|
||||
/* Output */
|
||||
unsigned int result; /* Error indication (DASD_FMT_ERR_*) */
|
||||
unsigned int unit; /* Track that is in error */
|
||||
unsigned int rec; /* Record that is in error */
|
||||
unsigned int num_records; /* Records in the track in error */
|
||||
unsigned int blksize; /* Block-size of first record in error */
|
||||
unsigned int key_length; /* Key length of first record in error */
|
||||
} format_check_t;
|
||||
|
||||
/*
|
||||
* values to be used in format_check_t for indicating
|
||||
* possible format errors
|
||||
@@ -221,33 +78,6 @@ typedef struct format_check_t {
|
||||
#define DASD_FORMAT_LDL 1
|
||||
#define DASD_FORMAT_CDL 2
|
||||
|
||||
/* Disable the volume (for Linux) */
|
||||
#define BIODASDDISABLE _IO(DASD_IOCTL_LETTER,0)
|
||||
/* Enable the volume (for Linux) */
|
||||
#define BIODASDENABLE _IO(DASD_IOCTL_LETTER,1)
|
||||
|
||||
/* Get information on a dasd device (enhanced) */
|
||||
#define BIODASDINFO2 _IOR(DASD_IOCTL_LETTER, 3, dasd_information2_t)
|
||||
|
||||
/* #define BIODASDFORMAT _IOW(IOCTL_LETTER,0,format_data_t) , deprecated */
|
||||
#define BIODASDFMT _IOW(DASD_IOCTL_LETTER,1,format_data_t)
|
||||
|
||||
/* Check device format according to format_data_t */
|
||||
#define BIODASDCHECKFMT _IOWR(DASD_IOCTL_LETTER, 2, format_check_t)
|
||||
|
||||
/****************************************************************************
|
||||
* SECTION: Further IOCTL Definitions (see fs.h and hdreq.h ) *
|
||||
****************************************************************************/
|
||||
/* re-read partition table */
|
||||
#define BLKRRPART _IO(0x12,95)
|
||||
/* get block device sector size */
|
||||
#define BLKSSZGET _IO(0x12,104)
|
||||
/* get read-only status (0 = read_write) */
|
||||
#define BLKROGET _IO(0x12,94)
|
||||
|
||||
/* get device geometry */
|
||||
#define HDIO_GETGEO 0x0301
|
||||
|
||||
/****************************************************************************
|
||||
* SECTION: DASDFMT internal types *
|
||||
****************************************************************************/
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
include ../common.mak
|
||||
|
||||
libs = $(rootdir)/libu2s/libu2s.a \
|
||||
$(rootdir)/libutil/libutil.a
|
||||
$(rootdir)/libutil/libutil.a \
|
||||
$(rootdir)/libdasd/libdasd.a
|
||||
|
||||
all: dasdinfo
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <sys/utsname.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "lib/dasd_base.h"
|
||||
#include "lib/util_base.h"
|
||||
#include "lib/util_file.h"
|
||||
#include "lib/util_opt.h"
|
||||
@@ -29,10 +30,6 @@
|
||||
#include "lib/zt_common.h"
|
||||
|
||||
#define RD_BUFFER_SIZE 80
|
||||
#define BLKSSZGET _IO(0x12,104)
|
||||
#define DASD_IOCTL_LETTER 'D'
|
||||
#define BIODASDINFO _IOR(DASD_IOCTL_LETTER,1,struct dasd_information)
|
||||
#define BIODASDINFO2 _IOR(DASD_IOCTL_LETTER,3,struct dasd_information2)
|
||||
#define TEMP_DEV_MAX_RETRIES 1000
|
||||
|
||||
static const struct util_prg prg = {
|
||||
@@ -100,67 +97,7 @@ struct volume_label {
|
||||
char volid[6];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct dasd_information2 {
|
||||
unsigned int devno;
|
||||
unsigned int real_devno;
|
||||
unsigned int schid;
|
||||
unsigned int cu_type : 16;
|
||||
unsigned int cu_model : 8;
|
||||
unsigned int dev_type : 16;
|
||||
unsigned int dev_model : 8;
|
||||
unsigned int open_count;
|
||||
unsigned int req_queue_len;
|
||||
unsigned int chanq_len;
|
||||
char type[4];
|
||||
unsigned int status;
|
||||
unsigned int label_block;
|
||||
unsigned int FBA_layout;
|
||||
unsigned int characteristics_size;
|
||||
unsigned int confdata_size;
|
||||
char characteristics[64];
|
||||
char configuration_data[256];
|
||||
unsigned int format;
|
||||
unsigned int features;
|
||||
unsigned int reserved0;
|
||||
unsigned int reserved1;
|
||||
unsigned int reserved2;
|
||||
unsigned int reserved3;
|
||||
unsigned int reserved4;
|
||||
unsigned int reserved5;
|
||||
unsigned int reserved6;
|
||||
unsigned int reserved7;
|
||||
};
|
||||
|
||||
struct dasd_information {
|
||||
unsigned int devno;
|
||||
unsigned int real_devno;
|
||||
unsigned int schid;
|
||||
unsigned int cu_type : 16;
|
||||
unsigned int cu_model : 8;
|
||||
unsigned int dev_type : 16;
|
||||
unsigned int dev_model : 8;
|
||||
unsigned int open_count;
|
||||
unsigned int req_queue_len;
|
||||
unsigned int chanq_len;
|
||||
char type[4];
|
||||
unsigned int status;
|
||||
unsigned int label_block;
|
||||
unsigned int FBA_layout;
|
||||
unsigned int characteristics_size;
|
||||
unsigned int confdata_size;
|
||||
char characteristics[64];
|
||||
char configuration_data[256];
|
||||
};
|
||||
|
||||
struct dasd_data
|
||||
{
|
||||
struct dasd_information2 dasd_info;
|
||||
int dasd_info_version;
|
||||
int blksize;
|
||||
};
|
||||
|
||||
static char EBCtoASC[256] =
|
||||
{
|
||||
static char EBCtoASC[256] = {
|
||||
/* 0x00 NUL SOH STX ETX *SEL HT *RNL DEL */
|
||||
0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
|
||||
/* 0x08 -GE -SPS -RPT VT FF CR SO SI */
|
||||
@@ -227,12 +164,12 @@ static char EBCtoASC[256] =
|
||||
0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
|
||||
};
|
||||
|
||||
static char *dinfo_ebcdic_dec (char *source, char *target, int l)
|
||||
static char *dinfo_ebcdic_dec(char *source, char *target, int l)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < l; i++)
|
||||
target[i]=EBCtoASC[(unsigned char)(source[i])];
|
||||
target[i] = EBCtoASC[(unsigned char)(source[i])];
|
||||
|
||||
return target;
|
||||
}
|
||||
@@ -242,51 +179,49 @@ static int dinfo_read_dasd_uid(char *uidfile, char *readbuf)
|
||||
return util_file_read_line(readbuf, RD_BUFFER_SIZE, uidfile);
|
||||
}
|
||||
|
||||
static int dinfo_read_dasd_vlabel (char *device, struct volume_label *vlabel,
|
||||
char *readbuf)
|
||||
static int dinfo_read_dasd_vlabel(char *device, struct volume_label *vlabel,
|
||||
char *readbuf)
|
||||
{
|
||||
struct dasd_data data;
|
||||
struct volume_label tmp;
|
||||
int vlsize = sizeof(struct volume_label);
|
||||
dasd_information2_t dasd_info;
|
||||
unsigned long vlabel_start;
|
||||
unsigned int blksize;
|
||||
char vollbl[5];
|
||||
int f;
|
||||
char *space;
|
||||
|
||||
if ((f = open(device, O_RDONLY)) < 0) {
|
||||
printf("Could not open device node.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (ioctl(f, BLKSSZGET, &data.blksize) != 0) {
|
||||
if (dasd_get_blocksize(device, &blksize) != 0) {
|
||||
printf("Unable to figure out block size.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (ioctl(f, BIODASDINFO2, &data.dasd_info) == 0)
|
||||
data.dasd_info_version = 2;
|
||||
else {
|
||||
if (ioctl(f, BIODASDINFO, &data.dasd_info) != 0) {
|
||||
printf("Unable to figure out DASD informations.\n");
|
||||
goto error;
|
||||
}
|
||||
if (dasd_get_info(device, &dasd_info) != 0) {
|
||||
printf("Unable to figure out DASD informations.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
vlabel_start = data.dasd_info.label_block * data.blksize;
|
||||
if (lseek(f, vlabel_start, SEEK_SET) < 0)
|
||||
f = open(device, O_RDONLY);
|
||||
if (f < 0) {
|
||||
printf("Could not open device node.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
vlabel_start = dasd_info.label_block * blksize;
|
||||
if (lseek(f, vlabel_start, SEEK_SET) < 0)
|
||||
goto error_close;
|
||||
|
||||
bzero(vlabel, vlsize);
|
||||
|
||||
if (read(f, vlabel, vlsize) != vlsize) {
|
||||
printf("Could not read volume label.\n");
|
||||
goto error;
|
||||
goto error_close;
|
||||
}
|
||||
|
||||
if (data.dasd_info.FBA_layout) {
|
||||
if (dasd_info.FBA_layout) {
|
||||
bzero(&tmp, vlsize);
|
||||
memcpy(&tmp, vlabel, vlsize);
|
||||
memcpy(vlabel->vollbl, &tmp, vlsize-4);
|
||||
memcpy(vlabel->vollbl, &tmp, vlsize - 4);
|
||||
}
|
||||
|
||||
close(f);
|
||||
@@ -301,16 +236,17 @@ static int dinfo_read_dasd_vlabel (char *device, struct volume_label *vlabel,
|
||||
(strncmp(vollbl, "CMS1", 4) == 0)) {
|
||||
strncpy(readbuf, vlabel->volid, 6);
|
||||
dinfo_ebcdic_dec(readbuf, readbuf, 6);
|
||||
space = strchr(readbuf,' ');
|
||||
space = strchr(readbuf, ' ');
|
||||
if (space)
|
||||
*space = 0;
|
||||
} else
|
||||
} else {
|
||||
strcpy(readbuf, "");
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
error:
|
||||
error_close:
|
||||
close(f);
|
||||
error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -321,7 +257,7 @@ static void *dinfo_malloc(size_t size)
|
||||
result = malloc(size);
|
||||
if (result == NULL) {
|
||||
printf("Could not allocate %lld bytes of memory",
|
||||
(unsigned long long) size);
|
||||
(unsigned long long)size);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -332,7 +268,7 @@ static char *dinfo_make_path(char *dirname, char *filename)
|
||||
size_t len;
|
||||
|
||||
len = strlen(dirname) + strlen(filename) + 2;
|
||||
result = (char *) dinfo_malloc(len);
|
||||
result = (char *)dinfo_malloc(len);
|
||||
if (result == NULL)
|
||||
return NULL;
|
||||
sprintf(result, "%s/%s", dirname, filename);
|
||||
@@ -342,8 +278,8 @@ static char *dinfo_make_path(char *dirname, char *filename)
|
||||
static int dinfo_create_devnode(dev_t dev, char **devno)
|
||||
{
|
||||
char *result;
|
||||
char * pathname[] = { "/dev", getenv("TMPDIR"), "/tmp",
|
||||
getenv("HOME"), "." , "/"};
|
||||
char *pathname[] = { "/dev", getenv("TMPDIR"), "/tmp",
|
||||
getenv("HOME"), ".", "/"};
|
||||
char filename[] = "dasdinfo0000";
|
||||
mode_t mode;
|
||||
unsigned int path;
|
||||
@@ -354,10 +290,10 @@ static int dinfo_create_devnode(dev_t dev, char **devno)
|
||||
mode = S_IFBLK | S_IRWXU;
|
||||
|
||||
/* Try several locations for the temporary device node. */
|
||||
for (path=0; path < sizeof(pathname) / sizeof(pathname[0]); path++) {
|
||||
for (path = 0; path < UTIL_ARRAY_SIZE(pathname); path++) {
|
||||
if (pathname[path] == NULL)
|
||||
continue;
|
||||
for (retry=0; retry < TEMP_DEV_MAX_RETRIES; retry++) {
|
||||
for (retry = 0; retry < TEMP_DEV_MAX_RETRIES; retry++) {
|
||||
sprintf(filename, "dasdinfo%04d", retry);
|
||||
result = dinfo_make_path(pathname[path], filename);
|
||||
if (result == NULL)
|
||||
@@ -366,7 +302,8 @@ static int dinfo_create_devnode(dev_t dev, char **devno)
|
||||
if (rc == 0) {
|
||||
/* Need this test to cover
|
||||
* 'nodev'-mounted
|
||||
* filesystems. */
|
||||
* filesystems.
|
||||
*/
|
||||
fd = open(result, O_RDONLY);
|
||||
if (fd != -1) {
|
||||
close(fd);
|
||||
@@ -375,8 +312,9 @@ static int dinfo_create_devnode(dev_t dev, char **devno)
|
||||
}
|
||||
remove(result);
|
||||
retry = TEMP_DEV_MAX_RETRIES;
|
||||
} else if (errno != EEXIST)
|
||||
} else if (errno != EEXIST) {
|
||||
retry = TEMP_DEV_MAX_RETRIES;
|
||||
}
|
||||
free(result);
|
||||
}
|
||||
}
|
||||
@@ -400,7 +338,8 @@ static int dinfo_extract_dev(dev_t *dev, char *str)
|
||||
|
||||
bzero(tmp, RD_BUFFER_SIZE);
|
||||
strncpy(tmp, str, RD_BUFFER_SIZE);
|
||||
if ((p = strchr(tmp, ':')) == NULL) {
|
||||
p = strchr(tmp, ':');
|
||||
if (p == NULL) {
|
||||
printf("Error: unable to extract major/minor\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -439,6 +378,7 @@ dinfo_is_busiddir(const char *fpath, const struct stat *UNUSED(sb),
|
||||
char *tempdir;
|
||||
char linkdir[128];
|
||||
ssize_t i;
|
||||
|
||||
if (tflag != FTW_D || (strncmp((fpath + ftwbuf->base), searchbusid,
|
||||
strlen(searchbusid)) != 0))
|
||||
return FTW_CONTINUE;
|
||||
@@ -454,7 +394,7 @@ dinfo_is_busiddir(const char *fpath, const struct stat *UNUSED(sb),
|
||||
if ((i < 0) || (i >= 128))
|
||||
return -1;
|
||||
/* append '\0' because readlink returns non zero terminated string */
|
||||
tempdir[i+1] = '\0';
|
||||
tempdir[i + 1] = '\0';
|
||||
if (strstr(linkdir, "dasd") == NULL)
|
||||
return FTW_CONTINUE;
|
||||
free(busiddir);
|
||||
@@ -470,15 +410,17 @@ dinfo_find_entry(const char *dir, const char *searchstring,
|
||||
{
|
||||
DIR *directory = NULL;
|
||||
struct dirent *dir_entry = NULL;
|
||||
|
||||
directory = opendir(dir);
|
||||
if (directory == NULL)
|
||||
return -1;
|
||||
while ((dir_entry = readdir(directory)) != NULL) {
|
||||
/* compare if the found entry has exactly the same name
|
||||
and type as searched */
|
||||
/* compare if the found entry has exactly the same name and type
|
||||
* as searched
|
||||
*/
|
||||
if ((strncmp(dir_entry->d_name, searchstring,
|
||||
strlen(searchstring)) == 0)
|
||||
&& (dir_entry->d_type & type)) {
|
||||
strlen(searchstring)) == 0) &&
|
||||
(dir_entry->d_type & type)) {
|
||||
*result = strdup(dir_entry->d_name);
|
||||
if (*result == NULL)
|
||||
goto out;
|
||||
@@ -555,7 +497,8 @@ static int dinfo_get_uid_from_devnode(char **uidfile, char *devnode)
|
||||
sprintf(stat_dev, "%d:%d", major(stat_buffer.st_rdev),
|
||||
minor(stat_buffer.st_rdev));
|
||||
|
||||
if ((directory = opendir("/sys/block/")) == NULL) {
|
||||
directory = opendir("/sys/block/");
|
||||
if (directory == NULL) {
|
||||
printf("Error: could not open directory /sys/block\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -573,7 +516,7 @@ static int dinfo_get_uid_from_devnode(char **uidfile, char *devnode)
|
||||
continue;
|
||||
|
||||
if (strncmp(stat_dev, readbuf,
|
||||
MAX(strlen(stat_dev), strlen(readbuf)-1)) == 0) {
|
||||
MAX(strlen(stat_dev), strlen(readbuf) - 1)) == 0) {
|
||||
rc = snprintf(*uidfile, RD_BUFFER_SIZE,
|
||||
"/sys/block/%s/device/uid",
|
||||
dir_entry->d_name);
|
||||
@@ -591,7 +534,7 @@ static int dinfo_get_uid_from_devnode(char **uidfile, char *devnode)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct utsname uname_buf;
|
||||
int version, release;
|
||||
@@ -635,13 +578,13 @@ int main(int argc, char * argv[])
|
||||
print_vlabel = 1;
|
||||
break;
|
||||
case 'i':
|
||||
busid=strdup(optarg);
|
||||
busid = strdup(optarg);
|
||||
break;
|
||||
case 'b':
|
||||
blockdev=strdup(optarg);
|
||||
blockdev = strdup(optarg);
|
||||
break;
|
||||
case 'd':
|
||||
devnode=strdup(optarg);
|
||||
devnode = strdup(optarg);
|
||||
break;
|
||||
case 'e':
|
||||
export = 1;
|
||||
@@ -661,11 +604,11 @@ int main(int argc, char * argv[])
|
||||
}
|
||||
|
||||
uname(&uname_buf);
|
||||
sscanf(uname_buf.release, "%d.%d", &version,&release);
|
||||
if (strcmp(uname_buf.sysname,"Linux") ||
|
||||
sscanf(uname_buf.release, "%d.%d", &version, &release);
|
||||
if (strcmp(uname_buf.sysname, "Linux") ||
|
||||
version < 2 || (version == 2 && release < 6)) {
|
||||
printf("%s %d.%d is not supported\n", uname_buf.sysname,
|
||||
version,release);
|
||||
version, release);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -693,9 +636,9 @@ int main(int argc, char * argv[])
|
||||
|
||||
/* try to read the uid attribute */
|
||||
if (busid) {
|
||||
sprintf(uidfile,"/sys/bus/ccw/devices/%s/uid", busid);
|
||||
sprintf(uidfile, "/sys/bus/ccw/devices/%s/uid", busid);
|
||||
} else if (blockdev) {
|
||||
sprintf(uidfile,"/sys/block/%s/device/uid", blockdev);
|
||||
sprintf(uidfile, "/sys/block/%s/device/uid", blockdev);
|
||||
} else if (devnode) {
|
||||
if (dinfo_get_uid_from_devnode(&uidfile, devnode) != 0)
|
||||
goto error;
|
||||
@@ -715,12 +658,11 @@ int main(int argc, char * argv[])
|
||||
if (!srchuid)
|
||||
break;
|
||||
}
|
||||
if (srchuid) {
|
||||
if (srchuid)
|
||||
srchuid[0] = '\0';
|
||||
}
|
||||
if (export) {
|
||||
if (export)
|
||||
printf("ID_UID=%s\n", readbuf);
|
||||
} else
|
||||
else
|
||||
printf("%s\n", readbuf);
|
||||
if (!print_vlabel && !print_extended_uid)
|
||||
goto out;
|
||||
@@ -729,9 +671,9 @@ int main(int argc, char * argv[])
|
||||
|
||||
if (print_extended_uid) {
|
||||
if (dinfo_read_dasd_uid(uidfile, readbuf) == 0) {
|
||||
if (export) {
|
||||
if (export)
|
||||
printf("ID_XUID=%s\n", readbuf);
|
||||
} else
|
||||
else
|
||||
printf("%s\n", readbuf);
|
||||
if (!print_vlabel)
|
||||
goto out;
|
||||
@@ -768,9 +710,9 @@ int main(int argc, char * argv[])
|
||||
}
|
||||
|
||||
if (dinfo_read_dasd_vlabel(device, &vlabel, readbuf) == 0) {
|
||||
if (export) {
|
||||
printf("ID_SERIAL=%s\n",readbuf);
|
||||
} else
|
||||
if (export)
|
||||
printf("ID_SERIAL=%s\n", readbuf);
|
||||
else
|
||||
printf("%s\n", readbuf);
|
||||
goto out;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,139 +17,6 @@
|
||||
* SECTION: Definitions needed for DASD-API (see dasd.h)
|
||||
*******************************************************************************/
|
||||
|
||||
#define DASD_IOCTL_LETTER 'D'
|
||||
|
||||
/*
|
||||
* struct dasd_information_t
|
||||
* represents any data about the device, which is visible to userspace.
|
||||
* including foramt and features.
|
||||
*/
|
||||
typedef struct dasd_information_t {
|
||||
unsigned int devno; /* S/390 devno */
|
||||
unsigned int real_devno; /* for aliases */
|
||||
unsigned int schid; /* S/390 subchannel identifier */
|
||||
unsigned int cu_type : 16; /* from SenseID */
|
||||
unsigned int cu_model : 8; /* from SenseID */
|
||||
unsigned int dev_type : 16; /* from SenseID */
|
||||
unsigned int dev_model : 8; /* from SenseID */
|
||||
unsigned int open_count;
|
||||
unsigned int req_queue_len;
|
||||
unsigned int chanq_len; /* length of chanq */
|
||||
char type[4]; /* from discipline.name, 'none' for unknown */
|
||||
unsigned int status; /* current device level */
|
||||
unsigned int label_block; /* where to find the VOLSER */
|
||||
unsigned int FBA_layout; /* fixed block size (like AIXVOL) */
|
||||
unsigned int characteristics_size;
|
||||
unsigned int confdata_size;
|
||||
char characteristics[64]; /* from read_device_characteristics */
|
||||
char configuration_data[256]; /* from read_configuration_data */
|
||||
} dasd_information_t;
|
||||
|
||||
typedef struct dasd_information2_t {
|
||||
unsigned int devno; /* S/390 devno */
|
||||
unsigned int real_devno; /* for aliases */
|
||||
unsigned int schid; /* S/390 subchannel identifier */
|
||||
unsigned int cu_type : 16; /* from SenseID */
|
||||
unsigned int cu_model : 8; /* from SenseID */
|
||||
unsigned int dev_type : 16; /* from SenseID */
|
||||
unsigned int dev_model : 8; /* from SenseID */
|
||||
unsigned int open_count;
|
||||
unsigned int req_queue_len;
|
||||
unsigned int chanq_len; /* length of chanq */
|
||||
char type[4]; /* from discipline.name, 'none' for unknown */
|
||||
unsigned int status; /* current device level */
|
||||
unsigned int label_block; /* where to find the VOLSER */
|
||||
unsigned int FBA_layout; /* fixed block size (like AIXVOL) */
|
||||
unsigned int characteristics_size;
|
||||
unsigned int confdata_size;
|
||||
unsigned char characteristics[64];/*from read_device_characteristics */
|
||||
unsigned char configuration_data[256];/*from read_configuration_data */
|
||||
unsigned int format; /* format info like formatted/cdl/ldl/... */
|
||||
unsigned int features; /* dasd features like 'ro',... */
|
||||
unsigned int reserved0; /* reserved for further use ,... */
|
||||
unsigned int reserved1; /* reserved for further use ,... */
|
||||
unsigned int reserved2; /* reserved for further use ,... */
|
||||
unsigned int reserved3; /* reserved for further use ,... */
|
||||
unsigned int reserved4; /* reserved for further use ,... */
|
||||
unsigned int reserved5; /* reserved for further use ,... */
|
||||
unsigned int reserved6; /* reserved for further use ,... */
|
||||
unsigned int reserved7; /* reserved for further use ,... */
|
||||
} dasd_information2_t;
|
||||
|
||||
struct dasd_eckd_characteristics {
|
||||
unsigned short cu_type;
|
||||
struct {
|
||||
unsigned char support:2;
|
||||
unsigned char async:1;
|
||||
unsigned char reserved:1;
|
||||
unsigned char cache_info:1;
|
||||
unsigned char model:3;
|
||||
} __attribute__ ((packed)) cu_model;
|
||||
unsigned short dev_type;
|
||||
unsigned char dev_model;
|
||||
struct {
|
||||
unsigned char mult_burst:1;
|
||||
unsigned char RT_in_LR:1;
|
||||
unsigned char reserved1:1;
|
||||
unsigned char RD_IN_LR:1;
|
||||
unsigned char reserved2:4;
|
||||
unsigned char reserved3:8;
|
||||
unsigned char defect_wr:1;
|
||||
unsigned char XRC_supported:1;
|
||||
unsigned char reserved4:1;
|
||||
unsigned char striping:1;
|
||||
unsigned char reserved5:4;
|
||||
unsigned char cfw:1;
|
||||
unsigned char reserved6:2;
|
||||
unsigned char cache:1;
|
||||
unsigned char dual_copy:1;
|
||||
unsigned char dfw:1;
|
||||
unsigned char reset_alleg:1;
|
||||
unsigned char sense_down:1;
|
||||
} __attribute__ ((packed)) facilities;
|
||||
unsigned char dev_class;
|
||||
unsigned char unit_type;
|
||||
unsigned short no_cyl;
|
||||
unsigned short trk_per_cyl;
|
||||
unsigned char sec_per_trk;
|
||||
unsigned char byte_per_track[3];
|
||||
unsigned short home_bytes;
|
||||
unsigned char formula;
|
||||
union {
|
||||
struct {
|
||||
unsigned char f1;
|
||||
unsigned short f2;
|
||||
unsigned short f3;
|
||||
} __attribute__ ((packed)) f_0x01;
|
||||
struct {
|
||||
unsigned char f1;
|
||||
unsigned char f2;
|
||||
unsigned char f3;
|
||||
unsigned char f4;
|
||||
unsigned char f5;
|
||||
} __attribute__ ((packed)) f_0x02;
|
||||
} __attribute__ ((packed)) factors;
|
||||
unsigned short first_alt_trk;
|
||||
unsigned short no_alt_trk;
|
||||
unsigned short first_dia_trk;
|
||||
unsigned short no_dia_trk;
|
||||
unsigned short first_sup_trk;
|
||||
unsigned short no_sup_trk;
|
||||
unsigned char MDR_ID;
|
||||
unsigned char OBR_ID;
|
||||
unsigned char director;
|
||||
unsigned char rd_trk_set;
|
||||
unsigned short max_rec_zero;
|
||||
unsigned char reserved1;
|
||||
unsigned char RWANY_in_LR;
|
||||
unsigned char factor6;
|
||||
unsigned char factor7;
|
||||
unsigned char factor8;
|
||||
unsigned char reserved2[3];
|
||||
unsigned char reserved3[6];
|
||||
unsigned int long_no_cyl;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*
|
||||
* values to be used for dasd_information2_t.format
|
||||
* 0x00: NOT formatted
|
||||
@@ -170,21 +37,6 @@ struct dasd_eckd_characteristics {
|
||||
#define DASD_FEATURE_READONLY 1
|
||||
#define DASD_FEATURE_USEDIAG 2
|
||||
|
||||
/* Get information on a dasd device (enhanced) */
|
||||
#define BIODASDINFO _IOR(DASD_IOCTL_LETTER,1,dasd_information_t)
|
||||
#define BIODASDINFO2 _IOR(DASD_IOCTL_LETTER,3,dasd_information2_t)
|
||||
|
||||
/********************************************************************************
|
||||
* SECTION: Further IOCTL Definitions (see fs.h and hdreq.h)
|
||||
*******************************************************************************/
|
||||
/* get block device sector size */
|
||||
#define BLKSSZGET _IO(0x12,104)
|
||||
/* return device size in bytes (u64 *arg) */
|
||||
#define BLKGETSIZE64 _IOR(0x12,114,size_t)
|
||||
|
||||
/* get device geometry */
|
||||
#define HDIO_GETGEO 0x0301
|
||||
|
||||
/********************************************************************************
|
||||
* SECTION: DASDVIEW internal types
|
||||
*******************************************************************************/
|
||||
@@ -215,7 +67,7 @@ typedef struct dasdview_info
|
||||
char device[PATH_MAX];
|
||||
dasd_information2_t dasd_info;
|
||||
int dasd_info_version;
|
||||
int blksize;
|
||||
unsigned int blksize;
|
||||
struct hd_geometry geo;
|
||||
u_int32_t hw_cylinders;
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ SUBSYSTEM!="block", GOTO="ra_end"
|
||||
|
||||
ACTION!="add", GOTO="ra_change"
|
||||
# on device add set initial readahead to 512 (instead of in kernel 128)
|
||||
KERNEL=="sd*[!0-9]", WAIT_FOR="queue/read_ahead_kb", ATTR{queue/read_ahead_kb}="512"
|
||||
KERNEL=="sd*[!0-9]", TEST=="queue/read_ahead_kb", ATTR{queue/read_ahead_kb}="512"
|
||||
|
||||
LABEL="ra_change"
|
||||
|
||||
|
||||
124
fdasd/fdasd.c
124
fdasd/fdasd.c
@@ -11,6 +11,7 @@
|
||||
#include <stdio.h>
|
||||
#include <sys/sysmacros.h>
|
||||
|
||||
#include "lib/dasd_base.h"
|
||||
#include "lib/dasd_sys.h"
|
||||
#include "lib/util_base.h"
|
||||
#include "lib/util_opt.h"
|
||||
@@ -220,8 +221,7 @@ static u_int32_t get_usable_cylinders(fdasd_anchor_t *anc)
|
||||
return anc->f4->DS4DCYL;
|
||||
/* normal volume */
|
||||
if (anc->f4->DS4DEVCT.DS4DEVFG & ALTERNATE_CYLINDERS_USED)
|
||||
cyl = anc->f4->DS4DEVCT.DS4DSCYL -
|
||||
(u_int16_t) anc->f4->DS4DEVAC;
|
||||
cyl = anc->f4->DS4DEVCT.DS4DSCYL - (u_int16_t)anc->f4->DS4DEVAC;
|
||||
else
|
||||
cyl = anc->f4->DS4DEVCT.DS4DSCYL;
|
||||
|
||||
@@ -230,9 +230,8 @@ static u_int32_t get_usable_cylinders(fdasd_anchor_t *anc)
|
||||
|
||||
static void get_addr_of_highest_f1_f8_label(fdasd_anchor_t *anc, cchhb_t *addr)
|
||||
{
|
||||
|
||||
u_int8_t record;
|
||||
/* We have to count the follwing labels:
|
||||
/* We have to count the following labels:
|
||||
* one format 4
|
||||
* one format 5
|
||||
* format 7 only if we have moren then BIG_DISK_SIZE tracks
|
||||
@@ -769,7 +768,7 @@ static int fdasd_parse_conffile(fdasd_anchor_t *anc,
|
||||
} else {
|
||||
errno = 0;
|
||||
anc->confdata[i].start = strtol(token[0],
|
||||
(char **) NULL, 10);
|
||||
(char **)NULL, 10);
|
||||
if (errno != 0 || anc->confdata[i].start == 0) {
|
||||
snprintf(err_str, ERROR_STRING_SIZE,
|
||||
"invalid partition start in config "
|
||||
@@ -784,7 +783,7 @@ static int fdasd_parse_conffile(fdasd_anchor_t *anc,
|
||||
} else {
|
||||
errno = 0;
|
||||
anc->confdata[i].stop = strtol(token[1],
|
||||
(char **) NULL, 10);
|
||||
(char **)NULL, 10);
|
||||
if (errno != 0 || anc->confdata[i].stop == 0) {
|
||||
snprintf(err_str, ERROR_STRING_SIZE,
|
||||
"invalid partition end in config "
|
||||
@@ -884,9 +883,9 @@ static void fdasd_check_conffile_input(fdasd_anchor_t *anc,
|
||||
anc->fspace_trk = start - FIRST_USABLE_TRK;
|
||||
|
||||
if (i < USABLE_PARTITIONS - 1) {
|
||||
if (anc->confdata[i+1].start != 0)
|
||||
if (anc->confdata[i + 1].start != 0)
|
||||
part_info->fspace_trk =
|
||||
anc->confdata[i+1].start-stop-1;
|
||||
anc->confdata[i + 1].start - stop - 1;
|
||||
else
|
||||
part_info->fspace_trk = last_trk - stop;
|
||||
} else if (i == USABLE_PARTITIONS - 1) {
|
||||
@@ -916,8 +915,8 @@ static void fdasd_verify_device(fdasd_anchor_t *anc, char *name)
|
||||
if (!S_ISBLK(dst.st_mode)) {
|
||||
snprintf(err_str, ERROR_STRING_SIZE,
|
||||
"Device '%s' (%d/%d) is not a block device\n", name,
|
||||
(unsigned short) major(dst.st_rdev),
|
||||
(unsigned short) minor(dst.st_rdev));
|
||||
(unsigned short)major(dst.st_rdev),
|
||||
(unsigned short)minor(dst.st_rdev));
|
||||
fdasd_error(anc, device_verification_failed, err_str);
|
||||
}
|
||||
|
||||
@@ -925,8 +924,8 @@ static void fdasd_verify_device(fdasd_anchor_t *anc, char *name)
|
||||
snprintf(err_str, ERROR_STRING_SIZE,
|
||||
"Partition '%s' (%d/%d) detected where device is "
|
||||
"required\n", name,
|
||||
(unsigned short) major(dst.st_rdev),
|
||||
(unsigned short) minor(dst.st_rdev));
|
||||
(unsigned short)major(dst.st_rdev),
|
||||
(unsigned short)minor(dst.st_rdev));
|
||||
fdasd_error(anc, device_verification_failed, err_str);
|
||||
}
|
||||
|
||||
@@ -962,8 +961,8 @@ static void fdasd_verify_device(fdasd_anchor_t *anc, char *name)
|
||||
|
||||
if (anc->verbose) {
|
||||
printf("Verification successful for '%s' (%d/%d)\n", name,
|
||||
(unsigned short) major(dst.st_rdev),
|
||||
(unsigned short) minor(dst.st_rdev));
|
||||
(unsigned short)major(dst.st_rdev),
|
||||
(unsigned short)minor(dst.st_rdev));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1028,15 +1027,13 @@ static void fdasd_verify_options(fdasd_anchor_t *anc)
|
||||
}
|
||||
}
|
||||
|
||||
if (anc->auto_partition &&
|
||||
(options.conffile || anc->print_table)) {
|
||||
if (anc->auto_partition && (options.conffile || anc->print_table)) {
|
||||
fdasd_error(anc, parser_failed,
|
||||
"Option 'auto' cannot be used with "
|
||||
"'config' and 'table'.\n");
|
||||
}
|
||||
|
||||
if (options.conffile &&
|
||||
(anc->print_table)) {
|
||||
if (options.conffile && anc->print_table) {
|
||||
fdasd_error(anc, parser_failed,
|
||||
"Option 'config' cannot be used with"
|
||||
" 'table'.\n");
|
||||
@@ -1232,26 +1229,13 @@ static int fdasd_get_volser(fdasd_anchor_t *anc, char *volser)
|
||||
*/
|
||||
static void fdasd_reread_partition_table(fdasd_anchor_t *anc)
|
||||
{
|
||||
char err_str[ERROR_STRING_SIZE];
|
||||
int fd;
|
||||
|
||||
if (!anc->silent)
|
||||
printf("rereading partition table...\n");
|
||||
|
||||
fd = open(options.device, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
snprintf(err_str, ERROR_STRING_SIZE,
|
||||
"Could not open device '%s' "
|
||||
"in read-only mode!\n", options.device);
|
||||
fdasd_error(anc, unable_to_open_disk, err_str);
|
||||
}
|
||||
|
||||
if (ioctl(fd, BLKRRPART, NULL) != 0) {
|
||||
close(fd);
|
||||
if (dasd_reread_partition_table(options.device, 1) != 0) {
|
||||
fdasd_error(anc, unable_to_ioctl, "Error while rereading "
|
||||
"partition table.\nPlease reboot!");
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1335,7 +1319,7 @@ static void fdasd_write_vtoc_labels(fdasd_anchor_t *anc)
|
||||
while (getpos(anc, k) > -1)
|
||||
k++;
|
||||
|
||||
setpos(anc, k, i-1);
|
||||
setpos(anc, k, i - 1);
|
||||
|
||||
strncpy(ch, "LINUX.V "
|
||||
" ", 44);
|
||||
@@ -1414,7 +1398,7 @@ static void fdasd_write_labels(fdasd_anchor_t *anc)
|
||||
if (anc->vtoc_changed)
|
||||
fdasd_write_vtoc_labels(anc);
|
||||
|
||||
if ((anc->vtoc_changed) || (anc->vlabel_changed))
|
||||
if (anc->vtoc_changed || anc->vlabel_changed)
|
||||
fdasd_reread_partition_table(anc);
|
||||
}
|
||||
|
||||
@@ -1500,9 +1484,9 @@ static void fdasd_reuse_vtoc(fdasd_anchor_t *anc)
|
||||
|
||||
if (!anc->silent) {
|
||||
snprintf(str, INPUT_BUF_SIZE,
|
||||
"WARNING: this will re-create your VTOC "
|
||||
"entries using the partition\n "
|
||||
"information of your existing VTOC. Continue?");
|
||||
"WARNING: this will re-create your VTOC "
|
||||
"entries using the partition\n "
|
||||
"information of your existing VTOC. Continue?");
|
||||
|
||||
if (yes_no(str) != 0)
|
||||
return;
|
||||
@@ -1637,9 +1621,11 @@ static void fdasd_change_part_type(fdasd_anchor_t *anc)
|
||||
printf("\n");
|
||||
|
||||
part_type = 0;
|
||||
while (part_type < 1 || part_type > UTIL_ARRAY_SIZE(partition_types) - 1) {
|
||||
while (!isdigit(part_type =
|
||||
read_char("new partition type: ")));
|
||||
while (part_type < 1 ||
|
||||
part_type > UTIL_ARRAY_SIZE(partition_types) - 1) {
|
||||
do {
|
||||
part_type = read_char("new partition type: ");
|
||||
} while (!isdigit(part_type));
|
||||
part_type -= 48;
|
||||
}
|
||||
|
||||
@@ -2094,7 +2080,8 @@ static void fdasd_check_disk_access(fdasd_anchor_t *anc)
|
||||
{
|
||||
char err_str[ERROR_STRING_SIZE];
|
||||
format1_label_t f1;
|
||||
int fd, pos, ro;
|
||||
int fd, pos;
|
||||
bool ro;
|
||||
|
||||
fd = open(options.device, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
@@ -2127,7 +2114,9 @@ static void fdasd_check_disk_access(fdasd_anchor_t *anc)
|
||||
fdasd_error(anc, unable_to_seek_disk, err_str);
|
||||
}
|
||||
|
||||
if (ioctl(fd, BLKROGET, &ro) != 0) {
|
||||
close(fd);
|
||||
|
||||
if (dasd_is_ro(options.device, &ro) != 0) {
|
||||
snprintf(err_str, ERROR_STRING_SIZE,
|
||||
"Could not get read-only status for device '%s'.",
|
||||
options.device);
|
||||
@@ -2138,8 +2127,6 @@ static void fdasd_check_disk_access(fdasd_anchor_t *anc)
|
||||
"You will not be able to save any changes.\n\n",
|
||||
options.device);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2171,16 +2158,18 @@ static unsigned int recs_per_track(unsigned short dev_type, unsigned int kl,
|
||||
kn = ceil_quot(kl + 6, 232) + 1;
|
||||
return 1729 / (10 + 9 + ceil_quot(kl + 6 * kn, 34) +
|
||||
9 + ceil_quot(dl + 6 * dn, 34));
|
||||
} else
|
||||
} else {
|
||||
return 1729 / (10 + 9 + ceil_quot(dl + 6 * dn, 34));
|
||||
}
|
||||
case DASD_9345_TYPE:
|
||||
dn = ceil_quot(dl + 6, 232) + 1;
|
||||
if (kl) {
|
||||
kn = ceil_quot(kl + 6, 232) + 1;
|
||||
return 1420 / (18 + 7 + ceil_quot(kl + 6 * kn, 34) +
|
||||
ceil_quot(dl + 6 * dn, 34));
|
||||
} else
|
||||
} else {
|
||||
return 1420 / (18 + 7 + ceil_quot(dl + 6 * dn, 34));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -2214,21 +2203,12 @@ static void fdasd_get_geometry(fdasd_anchor_t *anc)
|
||||
struct dasd_eckd_characteristics *characteristics;
|
||||
unsigned long long size_in_bytes;
|
||||
char err_str[ERROR_STRING_SIZE];
|
||||
dasd_information_t dasd_info;
|
||||
int fd, blksize = 0;
|
||||
dasd_information2_t dasd_info;
|
||||
unsigned int blksize = 0;
|
||||
|
||||
fd = open(options.device, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
snprintf(err_str, ERROR_STRING_SIZE,
|
||||
"Could not open device '%s' "
|
||||
"in read-only mode!\n", options.device);
|
||||
fdasd_error(anc, unable_to_open_disk, err_str);
|
||||
}
|
||||
if (ioctl(fd, BLKGETSIZE64, &size_in_bytes) != 0) {
|
||||
close(fd);
|
||||
if (dasd_get_blocksize_in_bytes(options.device, &size_in_bytes) != 0)
|
||||
fdasd_error(anc, unable_to_ioctl,
|
||||
"Could not retrieve disk size.");
|
||||
}
|
||||
/*
|
||||
* If anc->force_virtual is set, we do no real geometry detection.
|
||||
* anc->dev_type and anc->blksize have already been set via command
|
||||
@@ -2247,7 +2227,6 @@ static void fdasd_get_geometry(fdasd_anchor_t *anc)
|
||||
geo.start = 0;
|
||||
anc->label_pos = 2 * anc->blksize;
|
||||
anc->devno = 0;
|
||||
close(fd);
|
||||
if (anc->verbose) {
|
||||
printf("The force option is active. "
|
||||
"The following geometry will be used:\n"
|
||||
@@ -2259,24 +2238,21 @@ static void fdasd_get_geometry(fdasd_anchor_t *anc)
|
||||
return;
|
||||
}
|
||||
|
||||
if (ioctl(fd, HDIO_GETGEO, &geo) != 0) {
|
||||
close(fd);
|
||||
if (dasd_get_geo(options.device, &geo) != 0) {
|
||||
fdasd_error(anc, unable_to_ioctl,
|
||||
"Could not retrieve disk geometry information.");
|
||||
}
|
||||
if (ioctl(fd, BLKSSZGET, &blksize) != 0) {
|
||||
close(fd);
|
||||
if (dasd_get_blocksize(options.device, &blksize) != 0) {
|
||||
fdasd_error(anc, unable_to_ioctl,
|
||||
"Could not retrieve blocksize information.");
|
||||
}
|
||||
/* get disk type */
|
||||
if (ioctl(fd, BIODASDINFO, &dasd_info) != 0) {
|
||||
if (dasd_get_info(options.device, &dasd_info) != 0) {
|
||||
if (anc->verbose)
|
||||
printf("BIODASDINFO ioctl failed,"
|
||||
" use disk geometry only.\n");
|
||||
/* verify that the geometry matches a 3390 DASD */
|
||||
if (!fdasd_verify_geometry(DASD_3390_TYPE, blksize, &geo)) {
|
||||
close(fd);
|
||||
fdasd_error(anc, wrong_disk_type,
|
||||
"Disk geometry does not match a DASD device"
|
||||
" of type 3390.");
|
||||
@@ -2356,8 +2332,6 @@ static void fdasd_get_geometry(fdasd_anchor_t *anc)
|
||||
anc->label_pos = dasd_info.label_block * blksize;
|
||||
anc->devno = dasd_info.devno;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2384,10 +2358,8 @@ fdasd_read_int(unsigned long low, unsigned long dflt, unsigned long high,
|
||||
}
|
||||
|
||||
while (1) {
|
||||
while (!isdigit(read_char(msg_txt))
|
||||
&& (*line_ptr != '-' &&
|
||||
*line_ptr != '+' &&
|
||||
*line_ptr != '\0'))
|
||||
while (!isdigit(read_char(msg_txt)) &&
|
||||
(*line_ptr != '-' && *line_ptr != '+' && *line_ptr != '\0'))
|
||||
continue;
|
||||
if ((*line_ptr == '+' || *line_ptr == '-') && base != lower) {
|
||||
if (*line_ptr == '+')
|
||||
@@ -2411,13 +2383,13 @@ fdasd_read_int(unsigned long low, unsigned long dflt, unsigned long high,
|
||||
break;
|
||||
case 'm':
|
||||
case 'M':
|
||||
trk *= (1024*1024);
|
||||
trk *= (1024 * 1024);
|
||||
trk /= anc->blksize;
|
||||
trk /= geo.sectors;
|
||||
break;
|
||||
case 'g':
|
||||
case 'G':
|
||||
trk *= (1024*1024*1024);
|
||||
trk *= (1024 * 1024 * 1024);
|
||||
trk /= anc->blksize;
|
||||
trk /= geo.sectors;
|
||||
break;
|
||||
@@ -2546,7 +2518,6 @@ static int fdasd_get_partition_data(fdasd_anchor_t *anc, extent_t *part_extent,
|
||||
limit = part_tmp->start_trk - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (start == limit) {
|
||||
@@ -2642,7 +2613,7 @@ static void fdasd_enqueue_new_partition(fdasd_anchor_t *anc)
|
||||
FIRST_USABLE_TRK;
|
||||
}
|
||||
} else {
|
||||
/* there are partitons in front of the new one */
|
||||
/* there are partitions in front of the new one */
|
||||
if (part_info->start_trk == part_info->prev->end_trk + 1) {
|
||||
/* new partition is right behind the previous one */
|
||||
part_info->fspace_trk = part_info->prev->fspace_trk -
|
||||
@@ -2797,7 +2768,7 @@ static void fdasd_remove_partition(fdasd_anchor_t *anc)
|
||||
/*
|
||||
* writes a standard volume label and a standard VTOC with
|
||||
* only one partition to disc. With this function is it
|
||||
* possible to create one partiton in non-interactive mode,
|
||||
* possible to create one partition in non-interactive mode,
|
||||
* which can be used within shell scripts
|
||||
*/
|
||||
static void fdasd_auto_partition(fdasd_anchor_t *anc)
|
||||
@@ -3067,7 +3038,6 @@ int main(int argc, char *argv[])
|
||||
fdasd_recreate_vtoc(&anchor);
|
||||
anchor.option_recreate = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
117
fdasd/fdasd.h
117
fdasd/fdasd.h
@@ -14,125 +14,8 @@
|
||||
* SECTION: Definitions needed for DASD-API (see dasd.h) *
|
||||
*****************************************************************************/
|
||||
|
||||
#define DASD_IOCTL_LETTER 'D'
|
||||
|
||||
#define DASD_PARTN_BITS 2
|
||||
|
||||
/*
|
||||
* struct dasd_information_t
|
||||
* represents any data about the device, which is visible to userspace.
|
||||
* including foramt and featueres.
|
||||
*/
|
||||
typedef struct dasd_information_t {
|
||||
unsigned int devno; /* S/390 devno */
|
||||
unsigned int real_devno; /* for aliases */
|
||||
unsigned int schid; /* S/390 subchannel identifier */
|
||||
unsigned int cu_type : 16; /* from SenseID */
|
||||
unsigned int cu_model : 8; /* from SenseID */
|
||||
unsigned int dev_type : 16; /* from SenseID */
|
||||
unsigned int dev_model : 8; /* from SenseID */
|
||||
unsigned int open_count;
|
||||
unsigned int req_queue_len;
|
||||
unsigned int chanq_len; /* length of chanq */
|
||||
char type[4]; /* from discipline.name, 'none' for */
|
||||
/* unknown */
|
||||
unsigned int status; /* current device level */
|
||||
unsigned int label_block; /* where to find the VOLSER */
|
||||
unsigned int FBA_layout; /* fixed block size (like AIXVOL) */
|
||||
unsigned int characteristics_size;
|
||||
unsigned int confdata_size;
|
||||
char characteristics[64]; /* from read_device_characteristics */
|
||||
char configuration_data[256]; /* from read_configuration_data */
|
||||
} dasd_information_t;
|
||||
|
||||
struct dasd_eckd_characteristics {
|
||||
unsigned short cu_type;
|
||||
struct {
|
||||
unsigned char support:2;
|
||||
unsigned char async:1;
|
||||
unsigned char reserved:1;
|
||||
unsigned char cache_info:1;
|
||||
unsigned char model:3;
|
||||
} __attribute__ ((packed)) cu_model;
|
||||
unsigned short dev_type;
|
||||
unsigned char dev_model;
|
||||
struct {
|
||||
unsigned char mult_burst:1;
|
||||
unsigned char RT_in_LR:1;
|
||||
unsigned char reserved1:1;
|
||||
unsigned char RD_IN_LR:1;
|
||||
unsigned char reserved2:4;
|
||||
unsigned char reserved3:8;
|
||||
unsigned char defect_wr:1;
|
||||
unsigned char XRC_supported:1;
|
||||
unsigned char reserved4:1;
|
||||
unsigned char striping:1;
|
||||
unsigned char reserved5:4;
|
||||
unsigned char cfw:1;
|
||||
unsigned char reserved6:2;
|
||||
unsigned char cache:1;
|
||||
unsigned char dual_copy:1;
|
||||
unsigned char dfw:1;
|
||||
unsigned char reset_alleg:1;
|
||||
unsigned char sense_down:1;
|
||||
} __attribute__ ((packed)) facilities;
|
||||
unsigned char dev_class;
|
||||
unsigned char unit_type;
|
||||
unsigned short no_cyl;
|
||||
unsigned short trk_per_cyl;
|
||||
unsigned char sec_per_trk;
|
||||
unsigned char byte_per_track[3];
|
||||
unsigned short home_bytes;
|
||||
unsigned char formula;
|
||||
union {
|
||||
struct {
|
||||
unsigned char f1;
|
||||
unsigned short f2;
|
||||
unsigned short f3;
|
||||
} __attribute__ ((packed)) f_0x01;
|
||||
struct {
|
||||
unsigned char f1;
|
||||
unsigned char f2;
|
||||
unsigned char f3;
|
||||
unsigned char f4;
|
||||
unsigned char f5;
|
||||
} __attribute__ ((packed)) f_0x02;
|
||||
} __attribute__ ((packed)) factors;
|
||||
unsigned short first_alt_trk;
|
||||
unsigned short no_alt_trk;
|
||||
unsigned short first_dia_trk;
|
||||
unsigned short no_dia_trk;
|
||||
unsigned short first_sup_trk;
|
||||
unsigned short no_sup_trk;
|
||||
unsigned char MDR_ID;
|
||||
unsigned char OBR_ID;
|
||||
unsigned char director;
|
||||
unsigned char rd_trk_set;
|
||||
unsigned short max_rec_zero;
|
||||
unsigned char reserved1;
|
||||
unsigned char RWANY_in_LR;
|
||||
unsigned char factor6;
|
||||
unsigned char factor7;
|
||||
unsigned char factor8;
|
||||
unsigned char reserved2[3];
|
||||
unsigned char reserved3[6];
|
||||
unsigned int long_no_cyl;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Get information on a dasd device (enhanced) */
|
||||
#define BIODASDINFO _IOR(DASD_IOCTL_LETTER,1,dasd_information_t)
|
||||
|
||||
/*****************************************************************************
|
||||
* SECTION: Further IOCTL Definitions (see fs.h and hdreq.h) *
|
||||
*****************************************************************************/
|
||||
#define BLKROGET _IO(0x12,94) /* get read-only status (0 = read_write) */
|
||||
#define BLKRRPART _IO(0x12,95) /* re-read partition table */
|
||||
#define BLKSSZGET _IO(0x12,104)/* get block device sector size */
|
||||
#define BLKGETSIZE64 _IOR(0x12,114,size_t) /* device size in bytes (u64 *arg)*/
|
||||
|
||||
/* get device geometry */
|
||||
#define HDIO_GETGEO 0x0301
|
||||
|
||||
/*****************************************************************************
|
||||
* SECTION: FDASD internal types *
|
||||
*****************************************************************************/
|
||||
|
||||
@@ -49,7 +49,7 @@ install: all install-scripts
|
||||
install-scripts: lshmc
|
||||
@for i in $^; do \
|
||||
cat $$i | \
|
||||
sed -e 's+%S390_TOOLS_VERSION%+$(S390_TOOLS_RELEASE)+' \
|
||||
sed -e 's/%S390_TOOLS_VERSION%/$(S390_TOOLS_RELEASE)/' \
|
||||
>$(DESTDIR)$(USRSBINDIR)/$$i; \
|
||||
chown $(OWNER).$(GROUP) $(DESTDIR)$(USRSBINDIR)/$$i; \
|
||||
chmod 755 $(DESTDIR)$(USRSBINDIR)/$$i; \
|
||||
|
||||
@@ -821,10 +821,13 @@ static char *hmcdrv_parse_line(char *line, char *namebuf,
|
||||
if ((*line != '\0') && (*line != '\n')) {
|
||||
field = hmcdrv_parse_ntoken(field, line, &attr);
|
||||
|
||||
while ((*line != '\0') &&
|
||||
(*line != '\n') &&
|
||||
!isspace(*line))
|
||||
while ((*line != '\0') && (*line != '\n')) {
|
||||
if (isspace(*line))
|
||||
break;
|
||||
if (field == 1 && isdigit(*line))
|
||||
break;
|
||||
++line; /* search end of field */
|
||||
}
|
||||
}
|
||||
} /* while */
|
||||
|
||||
|
||||
207
include/lib/dasd_base.h
Normal file
207
include/lib/dasd_base.h
Normal file
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* dasd_base - Library for DASD related functions
|
||||
*
|
||||
* DASD related helper functions for accessing device information
|
||||
*
|
||||
* Copyright IBM Corp. 2013, 2017
|
||||
* Copyright Red Hat Inc. 2017
|
||||
*
|
||||
* 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 LIB_DASD_BASE_H
|
||||
#define LIB_DASD_BASE_H
|
||||
|
||||
#ifdef __linux__
|
||||
#include <linux/hdreg.h>
|
||||
#endif
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
typedef struct dasd_information2_t {
|
||||
unsigned int devno; /* S/390 devno */
|
||||
unsigned int real_devno; /* for aliases */
|
||||
unsigned int schid; /* S/390 subchannel identifier */
|
||||
unsigned int cu_type : 16; /* from SenseID */
|
||||
unsigned int cu_model : 8; /* from SenseID */
|
||||
unsigned int dev_type : 16; /* from SenseID */
|
||||
unsigned int dev_model : 8; /* from SenseID */
|
||||
unsigned int open_count;
|
||||
unsigned int req_queue_len;
|
||||
unsigned int chanq_len; /* length of chanq */
|
||||
char type[4]; /* from discipline.name, 'none' for unknown */
|
||||
unsigned int status; /* current device level */
|
||||
unsigned int label_block; /* where to find the VOLSER */
|
||||
unsigned int FBA_layout; /* fixed block size (like AIXVOL) */
|
||||
unsigned int characteristics_size;
|
||||
unsigned int confdata_size;
|
||||
unsigned char characteristics[64];/*from read_device_characteristics */
|
||||
unsigned char configuration_data[256];/*from read_configuration_data */
|
||||
unsigned int format; /* format info like formatted/cdl/ldl/... */
|
||||
unsigned int features; /* dasd features like 'ro',... */
|
||||
unsigned int reserved0; /* reserved for further use ,... */
|
||||
unsigned int reserved1; /* reserved for further use ,... */
|
||||
unsigned int reserved2; /* reserved for further use ,... */
|
||||
unsigned int reserved3; /* reserved for further use ,... */
|
||||
unsigned int reserved4; /* reserved for further use ,... */
|
||||
unsigned int reserved5; /* reserved for further use ,... */
|
||||
unsigned int reserved6; /* reserved for further use ,... */
|
||||
unsigned int reserved7; /* reserved for further use ,... */
|
||||
} dasd_information2_t;
|
||||
|
||||
struct dasd_eckd_characteristics {
|
||||
unsigned short cu_type;
|
||||
struct {
|
||||
unsigned char support:2;
|
||||
unsigned char async:1;
|
||||
unsigned char reserved:1;
|
||||
unsigned char cache_info:1;
|
||||
unsigned char model:3;
|
||||
} __attribute__ ((packed)) cu_model;
|
||||
unsigned short dev_type;
|
||||
unsigned char dev_model;
|
||||
struct {
|
||||
unsigned char mult_burst:1;
|
||||
unsigned char RT_in_LR:1;
|
||||
unsigned char reserved1:1;
|
||||
unsigned char RD_IN_LR:1;
|
||||
unsigned char reserved2:4;
|
||||
unsigned char reserved3:8;
|
||||
unsigned char defect_wr:1;
|
||||
unsigned char XRC_supported:1;
|
||||
unsigned char reserved4:1;
|
||||
unsigned char striping:1;
|
||||
unsigned char reserved5:4;
|
||||
unsigned char cfw:1;
|
||||
unsigned char reserved6:2;
|
||||
unsigned char cache:1;
|
||||
unsigned char dual_copy:1;
|
||||
unsigned char dfw:1;
|
||||
unsigned char reset_alleg:1;
|
||||
unsigned char sense_down:1;
|
||||
} __attribute__ ((packed)) facilities;
|
||||
unsigned char dev_class;
|
||||
unsigned char unit_type;
|
||||
unsigned short no_cyl;
|
||||
unsigned short trk_per_cyl;
|
||||
unsigned char sec_per_trk;
|
||||
unsigned char byte_per_track[3];
|
||||
unsigned short home_bytes;
|
||||
unsigned char formula;
|
||||
union {
|
||||
struct {
|
||||
unsigned char f1;
|
||||
unsigned short f2;
|
||||
unsigned short f3;
|
||||
} __attribute__ ((packed)) f_0x01;
|
||||
struct {
|
||||
unsigned char f1;
|
||||
unsigned char f2;
|
||||
unsigned char f3;
|
||||
unsigned char f4;
|
||||
unsigned char f5;
|
||||
} __attribute__ ((packed)) f_0x02;
|
||||
} __attribute__ ((packed)) factors;
|
||||
unsigned short first_alt_trk;
|
||||
unsigned short no_alt_trk;
|
||||
unsigned short first_dia_trk;
|
||||
unsigned short no_dia_trk;
|
||||
unsigned short first_sup_trk;
|
||||
unsigned short no_sup_trk;
|
||||
unsigned char MDR_ID;
|
||||
unsigned char OBR_ID;
|
||||
unsigned char director;
|
||||
unsigned char rd_trk_set;
|
||||
unsigned short max_rec_zero;
|
||||
unsigned char reserved1;
|
||||
unsigned char RWANY_in_LR;
|
||||
unsigned char factor6;
|
||||
unsigned char factor7;
|
||||
unsigned char factor8;
|
||||
unsigned char reserved2[3];
|
||||
unsigned char reserved3[6];
|
||||
unsigned int long_no_cyl;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*
|
||||
* struct format_data_t
|
||||
* represents all data necessary to format a dasd
|
||||
*/
|
||||
typedef struct format_data_t {
|
||||
unsigned int start_unit; /* from track */
|
||||
unsigned int stop_unit; /* to track */
|
||||
unsigned int blksize; /* sectorsize */
|
||||
unsigned int intensity;
|
||||
} format_data_t;
|
||||
|
||||
/*
|
||||
* struct format_check_t
|
||||
* represents all data necessary to evaluate the format of
|
||||
* different tracks of a dasd
|
||||
*/
|
||||
typedef struct format_check_t {
|
||||
/* Input */
|
||||
struct format_data_t expect;
|
||||
|
||||
/* Output */
|
||||
unsigned int result; /* Error indication (DASD_FMT_ERR_*) */
|
||||
unsigned int unit; /* Track that is in error */
|
||||
unsigned int rec; /* Record that is in error */
|
||||
unsigned int num_records; /* Records in the track in error */
|
||||
unsigned int blksize; /* Block-size of first record in error */
|
||||
unsigned int key_length; /* Key length of first record in error */
|
||||
} format_check_t;
|
||||
|
||||
#ifndef __linux__
|
||||
/* definition from hdreg.h */
|
||||
struct hd_geometry {
|
||||
unsigned char heads;
|
||||
unsigned char sectors;
|
||||
unsigned short cylinders;
|
||||
unsigned long start;
|
||||
};
|
||||
#endif
|
||||
|
||||
#define DASD_IOCTL_LETTER 'D'
|
||||
|
||||
/* Disable the volume (for Linux) */
|
||||
#define BIODASDDISABLE _IO(DASD_IOCTL_LETTER, 0)
|
||||
/* Enable the volume (for Linux) */
|
||||
#define BIODASDENABLE _IO(DASD_IOCTL_LETTER, 1)
|
||||
/* Get information on a dasd device (enhanced) */
|
||||
#define BIODASDINFO2 _IOR(DASD_IOCTL_LETTER, 3, dasd_information2_t)
|
||||
/* #define BIODASDFORMAT _IOW(IOCTL_LETTER,0,format_data_t) , deprecated */
|
||||
#define BIODASDFMT _IOW(DASD_IOCTL_LETTER, 1, format_data_t)
|
||||
/* Check device format according to format_data_t */
|
||||
#define BIODASDCHECKFMT _IOWR(DASD_IOCTL_LETTER, 2, format_check_t)
|
||||
|
||||
/********************************************************************************
|
||||
* SECTION: Further IOCTL Definitions (see fs.h and hdreq.h)
|
||||
*******************************************************************************/
|
||||
/* get read-only status (0 = read_write) */
|
||||
#define BLKROGET _IO(0x12, 94)
|
||||
/* re-read partition table */
|
||||
#define BLKRRPART _IO(0x12, 95)
|
||||
/* get block device sector size */
|
||||
#define BLKSSZGET _IO(0x12, 104)
|
||||
/* return device size in bytes (u64 *arg) */
|
||||
#define BLKGETSIZE64 _IOR(0x12, 114, size_t)
|
||||
|
||||
#ifndef __linux__ /* from <linux/hdreg.h> */
|
||||
#define HDIO_GETGEO 0x0301
|
||||
#endif
|
||||
|
||||
int dasd_check_format(const char *device, format_check_t *p);
|
||||
int dasd_format_disk(int fd, format_data_t *p);
|
||||
int dasd_disk_disable(const char *device, int *fd);
|
||||
int dasd_disk_enable(int fd);
|
||||
int dasd_get_blocksize(const char *device, unsigned int *blksize);
|
||||
int dasd_get_blocksize_in_bytes(const char *device, unsigned long long *blksize);
|
||||
int dasd_get_geo(const char *device, struct hd_geometry *geo);
|
||||
int dasd_get_info(const char *device, dasd_information2_t *info);
|
||||
int dasd_is_ro(const char *device, bool *ro);
|
||||
int dasd_reread_partition_table(const char *device, int ntries);
|
||||
|
||||
#endif /* LIB_DASD_BASE_H */
|
||||
@@ -14,6 +14,10 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Allocate memory or panic in case of failure
|
||||
*
|
||||
@@ -125,4 +129,10 @@ int __util_vsprintf(const char *func, const char *file, int line,
|
||||
char *util_strcat_realloc(char *str1, const char *str2);
|
||||
void util_str_toupper(char *str);
|
||||
|
||||
char *util_strstrip(char *s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /** LIB_UTIL_LIBC_H @} */
|
||||
|
||||
52
include/lib/vmcp.h
Normal file
52
include/lib/vmcp.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* vmcp - z/VM CP command library
|
||||
*
|
||||
* Copyright IBM Corp. 2005, 2018
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef LIB_VMCP_H
|
||||
#define LIB_VMCP_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define VMCP_DEVICE_NODE "/dev/vmcp" /* VMCP device name */
|
||||
#define VMCP_DEFAULT_BUFSZ 0x4000 /* VMCP default buffer size */
|
||||
|
||||
/*
|
||||
* Error codes returned by vmcp() function. This enables the caller
|
||||
* to emit a detailed error message on the type of failure.
|
||||
*/
|
||||
#define VMCP_SUCCESS 0 /* VMCP operation completed successfully */
|
||||
#define VMCP_ERR_OPEN (-1) /* Error Open of VMCP device */
|
||||
#define VMCP_ERR_SETBUF (-2) /* Error VMCP_SETBUF ioctl */
|
||||
#define VMCP_ERR_READ (-3) /* Error VMCP read system call */
|
||||
#define VMCP_ERR_GETCODE (-4) /* Error VMCP_GETCODE ioctl */
|
||||
#define VMCP_ERR_GETSIZE (-5) /* Error VMCP_GETSIZE ioctl */
|
||||
#define VMCP_ERR_TOOSMALL (-6) /* Error VMCP buffer too small for
|
||||
* response
|
||||
*/
|
||||
#define VMCP_ERR_WRITE (-7) /* Error VMCP write system call */
|
||||
|
||||
struct vmcp_parm {
|
||||
const char *cpcmd;
|
||||
unsigned int buffer_size;
|
||||
bool do_upper;
|
||||
int cprc;
|
||||
char *response;
|
||||
unsigned int response_size;
|
||||
};
|
||||
|
||||
int vmcp(struct vmcp_parm *cp);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "lib/dasd_base.h"
|
||||
|
||||
#define LINE_LENGTH 80
|
||||
#define VTOC_START_CC 0x0
|
||||
@@ -40,14 +41,6 @@
|
||||
|
||||
#define VTOC_ERROR "VTOC error:"
|
||||
|
||||
/* definition from hdreq.h */
|
||||
struct hd_geometry {
|
||||
unsigned char heads;
|
||||
unsigned char sectors;
|
||||
unsigned short cylinders;
|
||||
unsigned long start;
|
||||
};
|
||||
|
||||
typedef struct ttr
|
||||
{
|
||||
u_int16_t tt;
|
||||
|
||||
@@ -8,7 +8,7 @@ clean:
|
||||
rm -f *.o core xcec-bridge
|
||||
|
||||
install: ip_watcher.pl xcec-bridge start_hsnc.sh
|
||||
$(SED) -e 's+%S390_TOOLS_VERSION%+$(S390_TOOLS_RELEASE)+' \
|
||||
$(SED) -e 's/%S390_TOOLS_VERSION%/$(S390_TOOLS_RELEASE)/' \
|
||||
< start_hsnc.sh >$(DESTDIR)$(USRSBINDIR)/start_hsnc.sh; \
|
||||
chown $(OWNER).$(GROUP) $(DESTDIR)$(USRSBINDIR)/start_hsnc.sh; \
|
||||
chmod 755 $(DESTDIR)$(USRSBINDIR)/start_hsnc.sh; \
|
||||
|
||||
@@ -445,7 +445,7 @@ static void set_target_type_auto(const char *arg)
|
||||
{
|
||||
char busid[10];
|
||||
|
||||
if (access(arg, R_OK) == 0) {
|
||||
if (access(arg, F_OK) == 0) {
|
||||
set_target_type(TT_NODE, 1);
|
||||
return;
|
||||
}
|
||||
@@ -539,12 +539,19 @@ static void parse_chreipl_options(int argc, char *argv[])
|
||||
parse_pos_args(&argv[optind], argc - optind);
|
||||
}
|
||||
|
||||
static void verify_write_access(const char *path, const char *attr)
|
||||
static void check_exists(const char *path, const char *attr)
|
||||
{
|
||||
char fpath[PATH_MAX];
|
||||
|
||||
snprintf(fpath, sizeof(fpath), "/sys/firmware/%s", path);
|
||||
if (access(fpath, W_OK) != 0)
|
||||
if (access(fpath, F_OK) != 0)
|
||||
ERR_EXIT("System does not allow to set %s", attr);
|
||||
}
|
||||
|
||||
static void write_str_optional(char *string, char *file, int exit_on_fail,
|
||||
const char *attr)
|
||||
{
|
||||
if (write_str_errno(string, file) && exit_on_fail)
|
||||
ERR_EXIT("System does not allow to set %s", attr);
|
||||
}
|
||||
|
||||
@@ -585,22 +592,18 @@ static void chreipl_ccw(void)
|
||||
ERR_EXIT("Could not find DASD CCW device \"%s\"", l.busid);
|
||||
}
|
||||
|
||||
if (l.bootparms_set && strlen(l.bootparms) > BOOTPARMS_CCW_MAX) {
|
||||
ERR_EXIT("Maximum boot parameter length exceeded (%zu/%u)",
|
||||
strlen(l.bootparms), BOOTPARMS_CCW_MAX);
|
||||
}
|
||||
|
||||
/*
|
||||
* On old systems that use CCW reipl loadparm cannot be set
|
||||
*/
|
||||
if (l.loadparm_set)
|
||||
verify_write_access("reipl/ccw/loadparm", "loadparm");
|
||||
if (l.bootparms_set) {
|
||||
verify_write_access("reipl/ccw/parm", "boot parameters");
|
||||
if (strlen(l.bootparms) > BOOTPARMS_CCW_MAX)
|
||||
ERR_EXIT("Maximum boot parameter length exceeded "
|
||||
"(%zu/%u)", strlen(l.bootparms),
|
||||
BOOTPARMS_CCW_MAX);
|
||||
}
|
||||
if (access("/sys/firmware/reipl/ccw/parm", W_OK) == 0)
|
||||
write_str(l.bootparms, "reipl/ccw/parm");
|
||||
if (access("/sys/firmware/reipl/ccw/loadparm", W_OK) == 0)
|
||||
write_str(l.loadparm, "reipl/ccw/loadparm");
|
||||
write_str_optional(l.loadparm, "reipl/ccw/loadparm", l.loadparm_set,
|
||||
"loadparm");
|
||||
write_str_optional(l.bootparms, "reipl/ccw/parm", l.bootparms_set,
|
||||
"boot parameters");
|
||||
write_str(l.busid, "reipl/ccw/device");
|
||||
write_str("ccw", "reipl/reipl_type");
|
||||
|
||||
@@ -616,27 +619,21 @@ static void chreipl_fcp(void)
|
||||
ERR_EXIT("Device is on cio_ignore list, try \"cio_ignore -r %s\"?", l.busid);
|
||||
ERR_EXIT("Could not find FCP device \"%s\"", l.busid);
|
||||
}
|
||||
verify_write_access("reipl/fcp/device", "\"fcp\" re-IPL target");
|
||||
check_exists("reipl/fcp/device", "\"fcp\" re-IPL target");
|
||||
if (l.bootparms_set && strlen(l.bootparms) > BOOTPARMS_FCP_MAX) {
|
||||
ERR_EXIT("Maximum boot parameter length exceeded (%zu/%u)",
|
||||
strlen(l.bootparms), BOOTPARMS_FCP_MAX);
|
||||
}
|
||||
/*
|
||||
* On old systems the FCP reipl loadparm cannot be set
|
||||
*/
|
||||
if (l.loadparm_set)
|
||||
verify_write_access("reipl/fcp/loadparm", "loadparm");
|
||||
if (l.bootparms_set) {
|
||||
verify_write_access("reipl/fcp/scp_data", "boot parameters");
|
||||
if (strlen(l.bootparms) > BOOTPARMS_FCP_MAX)
|
||||
ERR_EXIT("Maximum boot parameter length exceeded "
|
||||
"(%zu/%u)", strlen(l.bootparms),
|
||||
BOOTPARMS_FCP_MAX);
|
||||
}
|
||||
if (access("/sys/firmware/reipl/fcp/scp_data", W_OK) == 0)
|
||||
write_str(l.bootparms, "reipl/fcp/scp_data");
|
||||
if (access("/sys/firmware/reipl/fcp/loadparm", W_OK) == 0)
|
||||
write_str(l.loadparm, "reipl/fcp/loadparm");
|
||||
write_str_optional(l.loadparm, "reipl/fcp/loadparm", l.loadparm_set,
|
||||
"loadparm");
|
||||
write_str_optional(l.bootparms, "reipl/fcp/scp_data", l.bootparms_set,
|
||||
"boot parameters");
|
||||
write_str(l.busid, "reipl/fcp/device");
|
||||
write_str(l.wwpn, "reipl/fcp/wwpn");
|
||||
write_str(l.lun, "reipl/fcp/lun");
|
||||
write_str("fcp", "reipl/reipl_type");
|
||||
/*
|
||||
* set the boot record logical block address. Master boot
|
||||
* record. It is always 0 for Linux
|
||||
@@ -645,6 +642,7 @@ static void chreipl_fcp(void)
|
||||
if (!l.bootprog_set)
|
||||
sprintf(l.bootprog, "0");
|
||||
write_str(l.bootprog, "reipl/fcp/bootprog");
|
||||
write_str("fcp", "reipl/reipl_type");
|
||||
|
||||
print_fcp(0, 0);
|
||||
}
|
||||
@@ -652,17 +650,14 @@ static void chreipl_fcp(void)
|
||||
static void chreipl_nss(void)
|
||||
{
|
||||
check_nss_opts();
|
||||
verify_write_access("reipl/nss/name", "\"nss\" re-IPL target");
|
||||
if (l.bootparms_set) {
|
||||
verify_write_access("reipl/nss/parm", "boot parameters");
|
||||
if (strlen(l.bootparms) > BOOTPARMS_NSS_MAX)
|
||||
ERR_EXIT("Maximum boot parameter length exceeded "
|
||||
"(%zu/%u)", strlen(l.bootparms),
|
||||
BOOTPARMS_NSS_MAX);
|
||||
check_exists("reipl/nss/name", "\"nss\" re-IPL target");
|
||||
if (l.bootparms_set && strlen(l.bootparms) > BOOTPARMS_NSS_MAX) {
|
||||
ERR_EXIT("Maximum boot parameter length exceeded (%zu/%u)",
|
||||
strlen(l.bootparms), BOOTPARMS_NSS_MAX);
|
||||
}
|
||||
write_str_optional(l.bootparms, "reipl/nss/parm", l.bootparms_set,
|
||||
"boot parameters");
|
||||
write_str(l.nss_name, "reipl/nss/name");
|
||||
if (access("/sys/firmware/reipl/nss/parm", W_OK) == 0)
|
||||
write_str(l.bootparms, "reipl/nss/parm");
|
||||
write_str("nss", "reipl/reipl_type");
|
||||
print_nss(0);
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ int write_str_errno(char *string, char *file)
|
||||
snprintf(path, sizeof(path), "/sys/firmware/%s", file);
|
||||
fh = open(path, O_WRONLY);
|
||||
if (fh < 0)
|
||||
ERR_EXIT_ERRNO("Could not open \"%s\"", file);
|
||||
return errno;
|
||||
if (write(fh, value, strlen(value)) < 0)
|
||||
return errno;
|
||||
close(fh);
|
||||
|
||||
@@ -4,7 +4,7 @@ lib = libdasd.a
|
||||
|
||||
all: $(lib)
|
||||
|
||||
objects = dasd_sys.o
|
||||
objects = dasd_sys.o dasd_ioctl.o
|
||||
|
||||
$(lib): $(objects) Makefile
|
||||
|
||||
|
||||
263
libdasd/dasd_ioctl.c
Normal file
263
libdasd/dasd_ioctl.c
Normal file
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* dasd_ioctl - Library for dasd-related ioctls
|
||||
*
|
||||
* DASD related helper functions for accessing device information via ioctls
|
||||
*
|
||||
* Copyright IBM Corp. 2013, 2017
|
||||
* Copyright Red Hat Inc. 2017
|
||||
*
|
||||
* 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 <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "lib/dasd_base.h"
|
||||
|
||||
#define COULD_NOT_OPEN_WARN(device) \
|
||||
warn("Could not open device '%s'", device)
|
||||
|
||||
#define COULD_NOT_CLOSE_WARN \
|
||||
warn("Unable to close device")
|
||||
|
||||
#define RUN_IOCTL(fd, req, argp) \
|
||||
do { \
|
||||
if (ioctl(fd, req, argp) != 0) { \
|
||||
int err = errno; \
|
||||
if (err != EBADF) \
|
||||
dasd_close_device(fd); \
|
||||
return err; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static int dasd_open_device(const char *device, int flags)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = open(device, flags);
|
||||
if (fd == -1)
|
||||
COULD_NOT_OPEN_WARN(device);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static void dasd_close_device(int fd)
|
||||
{
|
||||
if (close(fd) != 0)
|
||||
COULD_NOT_CLOSE_WARN;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get DASD block size information for device
|
||||
*
|
||||
* @param[in] device node device node's name
|
||||
* @param[out] blksize the block size
|
||||
*
|
||||
* @retval 0 in case of success
|
||||
* @retval errno in case of failure
|
||||
*
|
||||
*/
|
||||
int dasd_get_blocksize(const char *device, unsigned int *blksize)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = dasd_open_device(device, O_RDONLY);
|
||||
RUN_IOCTL(fd, BLKSSZGET, blksize);
|
||||
dasd_close_device(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get DASD block size information (in bytes) for device
|
||||
*
|
||||
* @param[in] device node device node's name
|
||||
* @param[out] blksize block size in bytes
|
||||
*
|
||||
* @retval 0 in case of success
|
||||
* @retval errno in case of failure
|
||||
*/
|
||||
int dasd_get_blocksize_in_bytes(const char *device, unsigned long long *blksize)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = dasd_open_device(device, O_RDONLY);
|
||||
RUN_IOCTL(fd, BLKGETSIZE64, blksize);
|
||||
dasd_close_device(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get DASD disk information for device
|
||||
*
|
||||
* @param[in] device node device node's name
|
||||
* @param[out] info pointer to dasd information
|
||||
*
|
||||
* @retval 0 in case of success
|
||||
* @retval errno in case of failure
|
||||
*/
|
||||
int dasd_get_info(const char *device, dasd_information2_t *info)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = dasd_open_device(device, O_RDONLY);
|
||||
RUN_IOCTL(fd, BIODASDINFO2, info);
|
||||
dasd_close_device(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get DASD disk geometry information for device
|
||||
*
|
||||
* @param[in] device node device node's name
|
||||
* @param[out] geo pointer to device geometry information
|
||||
*
|
||||
* @retval errno in case of failure
|
||||
* @retval 0 in case of success
|
||||
*/
|
||||
int dasd_get_geo(const char *device, struct hd_geometry *geo)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = dasd_open_device(device, O_RDONLY);
|
||||
RUN_IOCTL(fd, HDIO_GETGEO, geo);
|
||||
dasd_close_device(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get DASD read/write status information for device
|
||||
*
|
||||
* @param[in] device node device node's name
|
||||
* @param[out] ro read-only status (1 for ro, 0 for rw)
|
||||
*
|
||||
* @retval 0 in case of success
|
||||
* @retval errno in case of failure
|
||||
*/
|
||||
int dasd_is_ro(const char *device, bool *ro)
|
||||
{
|
||||
int fd, val;
|
||||
|
||||
fd = dasd_open_device(device, O_RDWR);
|
||||
RUN_IOCTL(fd, BLKROGET, &val);
|
||||
*ro = (val != 0) ? true : false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable DASD disk.
|
||||
*
|
||||
* @param[in] device node device node's name
|
||||
*
|
||||
* @retval 0 in case of success
|
||||
* @retval errno in case of failure
|
||||
*
|
||||
* Note: Before BIODASDFMT can be called, a DASD has to be disabled (or rather
|
||||
* put into a BASIC state) via BIODASDDISABLE. However, if you disable the DASD,
|
||||
* close the file descriptor, and then try to reopen it, it won't work as the
|
||||
* device isn't fully usable anymore. For BIODASDFMT to work, the file
|
||||
* descriptor opened for BIODASDISABLE has to be kept open until BIODASDFMT has
|
||||
* finished.
|
||||
*/
|
||||
int dasd_disk_disable(const char *device, int *fd)
|
||||
{
|
||||
*fd = dasd_open_device(device, O_RDWR);
|
||||
RUN_IOCTL(*fd, BIODASDDISABLE, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable DASD disk
|
||||
*
|
||||
* @param[in] device node device node's name
|
||||
*
|
||||
* @retval 0 in case of success
|
||||
* @retval errno in case of failure
|
||||
*/
|
||||
int dasd_disk_enable(int fd)
|
||||
{
|
||||
RUN_IOCTL(fd, BIODASDENABLE, NULL);
|
||||
dasd_close_device(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Format DASD disk
|
||||
*
|
||||
* @param[in] fd device node's file descriptor
|
||||
* @param[in] p format options
|
||||
*
|
||||
* @retval 0 in case of success
|
||||
* @retval errno in case of failure
|
||||
*/
|
||||
int dasd_format_disk(int fd, format_data_t *p)
|
||||
{
|
||||
RUN_IOCTL(fd, BIODASDFMT, p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check DASD format
|
||||
*
|
||||
* @param[in] device node device node's name
|
||||
* @param[in] p format params
|
||||
*
|
||||
* @retval 0 in case of success
|
||||
* @retval errno in case of failure
|
||||
*/
|
||||
int dasd_check_format(const char *device, format_check_t *p)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = dasd_open_device(device, O_RDONLY);
|
||||
RUN_IOCTL(fd, BIODASDCHECKFMT, p);
|
||||
dasd_close_device(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reread partition table
|
||||
*
|
||||
* @param[in] device node device node's name
|
||||
* @param[in] ntries maximum number of tries
|
||||
*
|
||||
* @retval 0 in case of success
|
||||
* @retval errno in case of failure
|
||||
*/
|
||||
int dasd_reread_partition_table(const char *device, int ntries)
|
||||
{
|
||||
int i, fd, err = 0;
|
||||
|
||||
fd = dasd_open_device(device, O_RDONLY);
|
||||
|
||||
/*
|
||||
* If the BLKRRPART ioctl fails, it is most likely due to the device
|
||||
* just being in use by udev. So it is worthwhile to retry the ioctl
|
||||
* after a second as it is likely to succeed.
|
||||
*/
|
||||
for (i = 0; i < ntries; i++) {
|
||||
if (ioctl(fd, BLKRRPART, NULL) != 0) {
|
||||
err = errno;
|
||||
sleep(1);
|
||||
} else {
|
||||
err = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
dasd_close_device(fd);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -198,3 +198,33 @@ int __util_vsprintf(const char *func, const char *file, int line,
|
||||
rc != -1, "Could not format string\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip leading and trailing spaces from string
|
||||
*
|
||||
* Remove string \a s leading and trailing spaces
|
||||
*
|
||||
* @param[in,out] s String to manipulate
|
||||
*
|
||||
* @returns Pointer to first non-space character in string \a s
|
||||
*/
|
||||
char *util_strstrip(char *s)
|
||||
{
|
||||
size_t size;
|
||||
char *end;
|
||||
|
||||
size = strlen(s);
|
||||
|
||||
if (!size)
|
||||
return s;
|
||||
|
||||
end = s + size - 1;
|
||||
while (end >= s && isspace(*end))
|
||||
end--;
|
||||
*(end + 1) = '\0';
|
||||
|
||||
while (*s && isspace(*s))
|
||||
s++;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -10,10 +10,13 @@
|
||||
//! [code]
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lib/util_libc.h"
|
||||
#include "lib/util_panic.h"
|
||||
|
||||
#define EXAMPLE_WORD " /sys/devices/system/cpu "
|
||||
|
||||
/*
|
||||
* Demonstrate that out of memory is automatically handled via panic()
|
||||
*/
|
||||
@@ -22,6 +25,12 @@ int main(void)
|
||||
unsigned long ulong_max = (unsigned long)-1;
|
||||
void *ptr;
|
||||
char *zeroes, *str;
|
||||
char buffer[sizeof(EXAMPLE_WORD)];
|
||||
|
||||
strcat(buffer, EXAMPLE_WORD);
|
||||
fprintf(stderr, "Try to remove leading and trailing spaces from "
|
||||
"\"%s\"\nresult = \"%s\"\n", EXAMPLE_WORD,
|
||||
util_strstrip(buffer));
|
||||
|
||||
/* Use util_strcat_realloc() for string concatenation */
|
||||
fprintf(stderr, "Try to concatenate \"Hello\", \", \" and \"world!\": ");
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lib/util_libc.h"
|
||||
#include "lib/util_list.h"
|
||||
|
||||
/*
|
||||
@@ -45,10 +46,8 @@ void util_list_init_offset(struct util_list *list, unsigned long offset)
|
||||
*/
|
||||
struct util_list *util_list_new_offset(unsigned long offset)
|
||||
{
|
||||
struct util_list *list = malloc(sizeof(*list));
|
||||
struct util_list *list = util_malloc(sizeof(*list));
|
||||
|
||||
if (!list)
|
||||
return NULL;
|
||||
util_list_init_offset(list, offset);
|
||||
return list;
|
||||
}
|
||||
|
||||
18
libvmcp/Makefile
Normal file
18
libvmcp/Makefile
Normal file
@@ -0,0 +1,18 @@
|
||||
include ../common.mak
|
||||
|
||||
lib = libvmcp.a
|
||||
|
||||
examples = vmcp_example
|
||||
|
||||
all: $(lib) $(examples)
|
||||
|
||||
objects = vmcp.o
|
||||
|
||||
$(lib): $(objects)
|
||||
|
||||
install: all
|
||||
|
||||
vmcp_example: vmcp_example.o $(lib) $(rootdir)/libutil/libutil.a
|
||||
|
||||
clean:
|
||||
rm -f *.o $(lib) $(examples)
|
||||
134
libvmcp/vmcp.c
Normal file
134
libvmcp/vmcp.c
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* vmcp - z/VM CP function library
|
||||
*
|
||||
* Copyright IBM Corp. 2018
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "lib/util_libc.h"
|
||||
#include "lib/vmcp.h"
|
||||
|
||||
#define VMCP_DEVICE_NODE "/dev/vmcp"
|
||||
#define VMCP_GETSIZE _IOR(0x10, 3, int)
|
||||
#define VMCP_SETBUF _IOW(0x10, 2, int)
|
||||
#define VMCP_GETCODE _IOR(0x10, 1, int)
|
||||
|
||||
/*
|
||||
* Read at most COUNT bytes from FD into memory at location BUF.
|
||||
* Return number of bytes read on success, -1 on error.
|
||||
*/
|
||||
static ssize_t read_buffer(int fd, char *buf, ssize_t count)
|
||||
{
|
||||
ssize_t ret, done;
|
||||
|
||||
for (done = 0; done < (ssize_t)count; done += ret) {
|
||||
ret = read(fd, &buf[done], count - done);
|
||||
if (ret == -1 && errno == EINTR)
|
||||
continue;
|
||||
if (ret == -1)
|
||||
return -1;
|
||||
if (ret == 0)
|
||||
break;
|
||||
}
|
||||
return done;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit a command to z/VM CP and return the response, the size in bytes
|
||||
* of the response and CP command response code.
|
||||
*
|
||||
* The member response contains the response from CP. It is a pointer
|
||||
* to a malloc'ed buffer which must be freed by the caller when the return
|
||||
* code is zero or VMCP_ERR_TOOSMALL.
|
||||
*
|
||||
* @param[in,out] cmd Pointer to struct vmcp_parm.
|
||||
* @param[in] cpcmd Pointer to CP command string.
|
||||
* @param[in] do_upper If true convert cpcmd string to upper case.
|
||||
* @param[out] cprc Return code of the CP command.
|
||||
* @param[out] response Return buffer, has been allocated via malloc()
|
||||
* must be freed by caller, see below.
|
||||
* @param[out] response_size Size of the response in bytes, can be larger
|
||||
* than buffer_size.
|
||||
*
|
||||
* @returns Zero on success or a negative error number on failure.
|
||||
* @retval VMCP_SUCCESS Success valid members: cprc, response,
|
||||
* response_size
|
||||
* @retval VMCP_ERR_OPEN Error opening VMCP device, valid members: none
|
||||
* @retval VMCP_ERR_SETBUF Error setting buffer, valid members: none
|
||||
* @retval VMCP_ERR_GETCODE Error getting cp exit code, valid members: none
|
||||
* @retval VMCP_ERR_WRITE Error write CP command, valid members: none
|
||||
* @retval VMCP_ERR_GETSIZE Error reading response size,
|
||||
* valid members: cprc
|
||||
* @retval VMCP_ERR_READ Error reading resp
|
||||
* @retval VMCP_ERR_TOOSMALL Error response buffer too small, response
|
||||
* truncated, valid members: cprc, response,
|
||||
* response_size
|
||||
*/
|
||||
int vmcp(struct vmcp_parm *cmd)
|
||||
{
|
||||
int rc = VMCP_SUCCESS, fd, len;
|
||||
char *cpcmd;
|
||||
|
||||
cmd->response = NULL;
|
||||
cmd->response_size = 0;
|
||||
cmd->cprc = 0;
|
||||
|
||||
fd = open(VMCP_DEVICE_NODE, O_RDWR);
|
||||
if (fd == -1)
|
||||
return VMCP_ERR_OPEN;
|
||||
|
||||
cpcmd = util_strdup(cmd->cpcmd); /* Exits on failure */
|
||||
if (cmd->do_upper)
|
||||
util_str_toupper(cpcmd);
|
||||
|
||||
if (ioctl(fd, VMCP_SETBUF, &cmd->buffer_size) == -1) {
|
||||
rc = VMCP_ERR_SETBUF;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (write(fd, cpcmd, strlen(cpcmd)) == -1) {
|
||||
rc = VMCP_ERR_WRITE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (ioctl(fd, VMCP_GETCODE, &cmd->cprc) == -1) {
|
||||
rc = VMCP_ERR_GETCODE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (ioctl(fd, VMCP_GETSIZE, &cmd->response_size) == -1) {
|
||||
rc = VMCP_ERR_GETSIZE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (cmd->response_size <= cmd->buffer_size) {
|
||||
len = cmd->response_size;
|
||||
} else {
|
||||
len = cmd->buffer_size;
|
||||
rc = VMCP_ERR_TOOSMALL;
|
||||
}
|
||||
|
||||
/* Exits on failure */
|
||||
cmd->response = (char *)util_zalloc(len + 1);
|
||||
|
||||
if (read_buffer(fd, cmd->response, len) == -1) {
|
||||
rc = VMCP_ERR_READ;
|
||||
free(cmd->response);
|
||||
cmd->response = NULL;
|
||||
}
|
||||
|
||||
fail:
|
||||
close(fd);
|
||||
free(cpcmd);
|
||||
return rc;
|
||||
}
|
||||
65
libvmcp/vmcp_example.c
Normal file
65
libvmcp/vmcp_example.c
Normal file
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* vmcp_example - Example program for vmcp.c
|
||||
*
|
||||
* Copyright 2018 IBM Corp.
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
//! [code]
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <err.h>
|
||||
|
||||
#include "lib/vmcp.h"
|
||||
|
||||
/*
|
||||
* Demonstrate vmcp() function usage
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
struct vmcp_parm cp;
|
||||
int rc;
|
||||
|
||||
cp.cpcmd = "q osa";
|
||||
cp.buffer_size = VMCP_DEFAULT_BUFSZ;
|
||||
cp.do_upper = true;
|
||||
|
||||
rc = vmcp(&cp);
|
||||
|
||||
switch (rc) {
|
||||
case VMCP_SUCCESS:
|
||||
printf("%s\n", cp.response);
|
||||
free(cp.response);
|
||||
break;
|
||||
case VMCP_ERR_OPEN:
|
||||
errx(EXIT_FAILURE, "Could not open device %s", VMCP_DEVICE_NODE);
|
||||
break;
|
||||
case VMCP_ERR_SETBUF:
|
||||
errx(EXIT_FAILURE, "Could not set buffer size");
|
||||
break;
|
||||
case VMCP_ERR_GETCODE:
|
||||
errx(EXIT_FAILURE, "Could not query return code");
|
||||
break;
|
||||
case VMCP_ERR_GETSIZE:
|
||||
errx(EXIT_FAILURE, "Could not query response size");
|
||||
break;
|
||||
case VMCP_ERR_WRITE:
|
||||
errx(EXIT_FAILURE, "Could not issue CP command");
|
||||
break;
|
||||
case VMCP_ERR_READ:
|
||||
errx(EXIT_FAILURE, "Could not read CP response");
|
||||
break;
|
||||
case VMCP_ERR_TOOSMALL:
|
||||
free(cp.response);
|
||||
printf("Response truncated (requires %u bytes)\n",
|
||||
cp.response_size);
|
||||
errx(EXIT_FAILURE, "Response buffer (%u bytes) too small",
|
||||
cp.buffer_size);
|
||||
break;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
//! [code]
|
||||
@@ -13,16 +13,13 @@
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/types.h>
|
||||
#include <malloc.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "lib/dasd_base.h"
|
||||
#include "lib/libzds.h"
|
||||
#include "lib/u2s.h"
|
||||
#include "lib/util_base.h"
|
||||
@@ -31,13 +28,6 @@
|
||||
|
||||
/** @cond PRIVATE */
|
||||
|
||||
/******************************************************************************/
|
||||
/* ioctl related definitions */
|
||||
/******************************************************************************/
|
||||
|
||||
/* device size in bytes (u64 *arg) */
|
||||
#define BLKGETSIZE64 _IOR(0x12, 114, size_t)
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
/* libzds structure definitions */
|
||||
@@ -415,17 +405,7 @@ int lzds_zdsroot_alloc(struct zdsroot **root)
|
||||
memset(tmproot, 0, sizeof(*tmproot));
|
||||
|
||||
tmproot->dasdlist = util_list_new(struct dasd, list);
|
||||
if (!tmproot->dasdlist) {
|
||||
free(tmproot);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
tmproot->datasetlist = util_list_new(struct dataset, list);
|
||||
if (!tmproot->dasdlist) {
|
||||
util_list_free(tmproot->dasdlist);
|
||||
free(tmproot);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
*root = tmproot;
|
||||
|
||||
@@ -480,18 +460,11 @@ void lzds_zdsroot_free(struct zdsroot *root)
|
||||
*/
|
||||
static int dasd_read_geometry(struct dasd *dasd)
|
||||
{
|
||||
int fd;
|
||||
unsigned long long size_in_bytes;
|
||||
|
||||
errorlog_clear(dasd->log);
|
||||
fd = open(dasd->device, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return errorlog_add_message(
|
||||
&dasd->log, NULL, EIO,
|
||||
"read geometry: could not open device %s\n",
|
||||
dasd->device);
|
||||
|
||||
if (ioctl(fd, BLKGETSIZE64, &size_in_bytes) != 0)
|
||||
if (dasd_get_blocksize_in_bytes(dasd->device, &size_in_bytes) != 0)
|
||||
return errorlog_add_message(
|
||||
&dasd->log, NULL, EIO,
|
||||
"read geometry: could not get size from device %s\n",
|
||||
@@ -505,7 +478,6 @@ static int dasd_read_geometry(struct dasd *dasd)
|
||||
dasd->label_block = 2;
|
||||
dasd->heads = 15;
|
||||
dasd->cylinders = (size_in_bytes / (dasd->heads * RAWTRACKSIZE));
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -822,10 +794,6 @@ static int errorlog_alloc(struct errorlog **log)
|
||||
return ENOMEM;
|
||||
memset(tmplog, 0, sizeof(*tmplog));
|
||||
tmplog->entries = util_list_new(struct errormsg, list);
|
||||
if (!tmplog->entries) {
|
||||
free(tmplog);
|
||||
return ENOMEM;
|
||||
}
|
||||
*log = tmplog;
|
||||
return 0;
|
||||
}
|
||||
@@ -2203,8 +2171,6 @@ static int dataset_member_analysis(struct dataset *ds)
|
||||
|
||||
dataset_free_memberlist(ds);
|
||||
ds->memberlist = util_list_new(struct pdsmember, list);
|
||||
if (!ds->memberlist)
|
||||
return ENOMEM;
|
||||
|
||||
/* track buffer must be page aligned for O_DIRECT */
|
||||
trackdata = memalign(4096, RAWTRACKSIZE);
|
||||
|
||||
@@ -594,17 +594,18 @@ static void cal_task_pcpu(struct task_t *task, const unsigned long long tics)
|
||||
*/
|
||||
static int read_stat(struct task_t *task)
|
||||
{
|
||||
int ppid, tty, proc;
|
||||
unsigned long flags, pri, nice;
|
||||
unsigned long long maj_flt, utime, stime, cutime, cstime;
|
||||
unsigned long long maj_flt = 0, utime = 0, stime = 0, cutime = 0,
|
||||
cstime = 0;
|
||||
unsigned long flags = 0, pri = 0, nice = 0;
|
||||
char *cmd_start, *cmd_end, *cmdlenp, *cmdp;
|
||||
int ppid = 0, tty = 0, proc = 0, rc;
|
||||
|
||||
snprintf(fname, sizeof(fname), "/proc/%u/stat", task->pid);
|
||||
if (read_file(fname, buf, sizeof(buf) - 1) == -1)
|
||||
return 0;
|
||||
|
||||
cmd_start = strchr(buf, '(') + 1;
|
||||
cmd_end = strchr(cmd_start, ')');
|
||||
cmd_end = strrchr(cmd_start, ')');
|
||||
name_lens.cmd_len = cmd_end - cmd_start;
|
||||
cmdlenp = mon_record + sizeof(struct monwrite_hdr);
|
||||
cmdlenp += sizeof(struct procd_hdr);
|
||||
@@ -625,7 +626,7 @@ static int read_stat(struct task_t *task)
|
||||
memcpy(cmdlenp, &name_lens.cmd_len, sizeof(__u16));
|
||||
|
||||
cmd_end += 2;
|
||||
sscanf(cmd_end,
|
||||
rc = sscanf(cmd_end,
|
||||
"%c %d %*d %*d %d %*d "
|
||||
"%lu %*s %*s %Lu %*s "
|
||||
"%Lu %Lu %Lu %Lu "
|
||||
@@ -642,6 +643,8 @@ static int read_stat(struct task_t *task)
|
||||
&utime, &stime, &cutime, &cstime,
|
||||
&pri, &nice,
|
||||
&proc);
|
||||
if (rc != 12)
|
||||
syslog(LOG_ERR, "bad data in %s \n", fname);
|
||||
task->ppid = (__u32)ppid;
|
||||
task->tty = (__u16)tty;
|
||||
task->flags = (__u32)flags;
|
||||
|
||||
@@ -134,8 +134,8 @@ echo "$cmd: Copying virtio modules"
|
||||
mkdir -p $builddir/$netdir
|
||||
mkdir -p $builddir/$blkdir
|
||||
set +e
|
||||
cp $netdir/virtio_net.ko $builddir/$netdir 2> /dev/null
|
||||
cp $blkdir/virtio_blk.ko $builddir/$blkdir 2> /dev/null
|
||||
cp $netdir/virtio_net.ko* $builddir/$netdir 2> /dev/null
|
||||
cp $blkdir/virtio_blk.ko* $builddir/$blkdir 2> /dev/null
|
||||
set -e
|
||||
|
||||
# Busybox (+ dependencies)
|
||||
@@ -170,7 +170,7 @@ cat <<'EOF' > $builddir/init
|
||||
/bin/mount -t tmpfs none /run
|
||||
|
||||
/sbin/modprobe virtio_net
|
||||
/sbin/udhcpc -O pxeconffile -O pxepathprefix &
|
||||
/sbin/udhcpc -O pxeconffile -O pxepathprefix -x 93:001F &
|
||||
|
||||
/sbin/pxeboot.script
|
||||
EOF
|
||||
@@ -237,6 +237,7 @@ case "$1" in
|
||||
echo " router: $router"
|
||||
echo " domain: $domain $dns"
|
||||
echo " tftp: $siaddr"
|
||||
echo " pxepathprefix: $pxepathprefix"
|
||||
# flush routes
|
||||
/sbin/ip route flush table all
|
||||
# setup if link
|
||||
@@ -272,6 +273,7 @@ case "$1" in
|
||||
echo "siaddr=$siaddr" > $PXECONF
|
||||
echo "interface=$interface" >> $PXECONF
|
||||
echo "ip=$ip" >> $PXECONF
|
||||
echo "pxepathprefix=$pxepathprefix" >> $PXECONF
|
||||
fi
|
||||
;;
|
||||
|
||||
@@ -354,7 +356,7 @@ then
|
||||
for c in $CONFIGS
|
||||
do
|
||||
echo "fetching config pxelinux.cfg/$c from $siaddr"
|
||||
if /usr/bin/tftp -g -l /tmp/config -r pxelinux.cfg/$c $siaddr
|
||||
if /usr/bin/tftp -g -l /tmp/config -r ${pxepathprefix}pxelinux.cfg/$c $siaddr
|
||||
then
|
||||
break
|
||||
fi
|
||||
@@ -371,6 +373,7 @@ fi
|
||||
kernel=$(/bin/grep -i "^[[:space:]]*kernel" /tmp/config | sed "s/^[[:space:]]*kernel[[:space:]]*//I")
|
||||
initrd=$(/bin/grep -i "^[[:space:]]*initrd" /tmp/config | sed "s/^[[:space:]]*initrd[[:space:]]*//I")
|
||||
append=$(/bin/grep -i "^[[:space:]]*append" /tmp/config | sed "s/^[[:space:]]*append[[:space:]]*//I")
|
||||
ipappend=$(/bin/grep -i "^[[:space:]]*ipappend" /tmp/config | sed "s/^[[:space:]]*ipappend[[:space:]]*//I")
|
||||
|
||||
if [ -z "$kernel" ]
|
||||
then
|
||||
@@ -378,13 +381,13 @@ then
|
||||
exit
|
||||
else
|
||||
echo fetch kernel $kernel from $siaddr
|
||||
/usr/bin/tftp -g -l /tmp/kernel -r $kernel $siaddr
|
||||
/usr/bin/tftp -g -l /tmp/kernel -r $pxepathprefix$kernel $siaddr
|
||||
fi
|
||||
|
||||
if [ -n "$initrd" ]
|
||||
then
|
||||
echo fetch initrd $initrd from $siaddr
|
||||
/usr/bin/tftp -g -l /tmp/initrd -r $initrd $siaddr
|
||||
/usr/bin/tftp -g -l /tmp/initrd -r $pxepathprefix$initrd $siaddr
|
||||
INITRD="--initrd=/tmp/initrd"
|
||||
else
|
||||
INITRD=""
|
||||
@@ -394,6 +397,9 @@ if [ -z "$append" ]; then
|
||||
echo "Kexec load: kexec -l /tmp/kernel $INITRD"
|
||||
kexec -l /tmp/kernel $INITRD
|
||||
else
|
||||
if [ "$ipappend" = "2" ]; then
|
||||
$append="$append BOOTIF=01-$ifaddr"
|
||||
fi
|
||||
echo "Kexec load: kexec -l /tmp/kernel $INITRD --append=\"$append\""
|
||||
kexec -l /tmp/kernel $INITRD --append="$append"
|
||||
fi
|
||||
|
||||
@@ -3,7 +3,7 @@ include ../common.mak
|
||||
all:
|
||||
|
||||
install: qethconf
|
||||
$(SED) -e 's+%S390_TOOLS_VERSION%+$(S390_TOOLS_RELEASE)+' \
|
||||
$(SED) -e 's/%S390_TOOLS_VERSION%/$(S390_TOOLS_RELEASE)/' \
|
||||
< qethconf >$(DESTDIR)$(BINDIR)/qethconf; \
|
||||
chown $(OWNER).$(GROUP) $(DESTDIR)$(BINDIR)/qethconf; \
|
||||
chmod 755 $(DESTDIR)$(BINDIR)/qethconf; \
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
include ../common.mak
|
||||
|
||||
SCRIPTS = dbginfo.sh zfcpdbf scsi_logging_level
|
||||
MAN_PAGES = dbginfo.sh.1 zfcpdbf.1
|
||||
SCRIPTS = dbginfo.sh zfcpdbf zipl-switch-to-blscfg scsi_logging_level
|
||||
MAN_PAGES = dbginfo.sh.1 zfcpdbf.1 zipl-switch-to-blscfg.1
|
||||
|
||||
all:
|
||||
|
||||
@@ -10,13 +10,13 @@ install:
|
||||
@for i in $(SCRIPTS); \
|
||||
do \
|
||||
cat $$i | \
|
||||
sed -e 's+%S390_TOOLS_VERSION%+$(S390_TOOLS_RELEASE)+' \
|
||||
sed -e 's/%S390_TOOLS_VERSION%/$(S390_TOOLS_RELEASE)/' \
|
||||
>$(DESTDIR)$(BINDIR)/$$i; \
|
||||
chown $(OWNER):$(GROUP) $(DESTDIR)$(BINDIR)/$$i; \
|
||||
chmod 755 $(DESTDIR)$(BINDIR)/$$i; \
|
||||
done
|
||||
|
||||
sed -e 's+%S390_TOOLS_VERSION%+$(S390_TOOLS_RELEASE)+' cpictl > \
|
||||
sed -e 's/%S390_TOOLS_VERSION%/$(S390_TOOLS_RELEASE)/' cpictl > \
|
||||
$(DESTDIR)$(TOOLS_LIBDIR)/cpictl
|
||||
chown $(OWNER):$(GROUP) $(DESTDIR)$(TOOLS_LIBDIR)/cpictl
|
||||
chmod 775 $(DESTDIR)$(TOOLS_LIBDIR)/cpictl
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# dbginfo.sh - Tool to collect runtime, configuration, and trace information
|
||||
#
|
||||
# Copyright IBM Corp. 2002, 2017
|
||||
# Copyright IBM Corp. 2002, 2018
|
||||
#
|
||||
# s390-tools is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the MIT license. See LICENSE for details.
|
||||
@@ -21,7 +21,7 @@ readonly SCRIPTNAME="${0##*/}"
|
||||
print_version() {
|
||||
cat <<EOF
|
||||
${SCRIPTNAME}: Debug information script version %S390_TOOLS_VERSION%
|
||||
Copyright IBM Corp. 2002, 2017
|
||||
Copyright IBM Corp. 2002, 2018
|
||||
EOF
|
||||
}
|
||||
|
||||
@@ -182,11 +182,14 @@ readonly OUTPUT_FILE_XML="${WORKPATH}domain_xml"
|
||||
# File that includes the docker inspect output
|
||||
readonly OUTPUT_FILE_DOCKER="${WORKPATH}docker_inspect.out"
|
||||
|
||||
# File that includes nvme related information
|
||||
readonly OUTPUT_FILE_NVME="${WORKPATH}nvme.out"
|
||||
|
||||
# Mount point of the debug file system
|
||||
readonly MOUNT_POINT_DEBUGFS="/sys/kernel/debug"
|
||||
|
||||
# The amount of steps running the whole collections
|
||||
readonly COLLECTION_COUNT=11
|
||||
readonly COLLECTION_COUNT=12
|
||||
|
||||
# The kernel version (e.g. '2' from 2.6.32 or '3' from 3.2.1)
|
||||
readonly KERNEL_VERSION=$(uname -r 2>/dev/null | cut -d'.' -f1)
|
||||
@@ -471,10 +474,13 @@ VM_CMDS="q userid\
|
||||
:q privclass\
|
||||
:q cplevel\
|
||||
:q cpservice\
|
||||
:q cpprot user\
|
||||
:q specex\
|
||||
:q ssi\
|
||||
:q cpus\
|
||||
:q srm\
|
||||
:q vtod\
|
||||
:q time full\
|
||||
:q timezone\
|
||||
:q loaddev\
|
||||
:q v osa\
|
||||
@@ -509,6 +515,7 @@ VM_CMDS="q userid\
|
||||
:q cache\
|
||||
:q nic\
|
||||
:q pav\
|
||||
:q proc\
|
||||
:q proc topology\
|
||||
:q mt\
|
||||
:q qioass\
|
||||
@@ -825,6 +832,25 @@ collect_docker() {
|
||||
pr_log_stdout " "
|
||||
}
|
||||
|
||||
########################################
|
||||
collect_nvme() {
|
||||
local NVME
|
||||
|
||||
pr_syslog_stdout "11 of ${COLLECTION_COUNT}: Collecting nvme output"
|
||||
call_run_command "nvme list" "${OUTPUT_FILE_NVME}"
|
||||
|
||||
for NVME in /dev/nvme[0-9]*; do
|
||||
if [ -c $NVME ]; then
|
||||
call_run_command "smartctl -x $NVME" "${OUTPUT_FILE_NVME}"
|
||||
call_run_command "nvme fw-log $NVME" "${OUTPUT_FILE_NVME}"
|
||||
call_run_command "nvme smart-log $NVME" "${OUTPUT_FILE_NVME}"
|
||||
call_run_command "nvme error-log $NVME" "${OUTPUT_FILE_NVME}"
|
||||
fi
|
||||
done
|
||||
|
||||
pr_log_stdout " "
|
||||
}
|
||||
|
||||
########################################
|
||||
post_processing() {
|
||||
local file_mtime
|
||||
@@ -832,7 +858,7 @@ post_processing() {
|
||||
local tmp_file
|
||||
local file_name
|
||||
|
||||
pr_syslog_stdout "11 of ${COLLECTION_COUNT}: Postprocessing"
|
||||
pr_syslog_stdout "${COLLECTION_COUNT} of ${COLLECTION_COUNT}: Postprocessing"
|
||||
|
||||
find "${WORKPATH}etc/libvirt/qemu/" -maxdepth 1 -name "*.xml" 2>/dev/null | while IFS= read -r file_name; do
|
||||
file_mtime_epoche=$(stat --format=%Y "${file_name}")
|
||||
@@ -991,25 +1017,31 @@ environment_setup()
|
||||
# create gzip-ped tar file
|
||||
create_package()
|
||||
{
|
||||
local rc_tar
|
||||
pr_stdout "Finalizing: Creating archive with collected data"
|
||||
cd "${WORKDIR_BASE}"
|
||||
|
||||
if ! tar -czf "${WORKARCHIVE}" "${WORKDIR_CURRENT}"; then
|
||||
pr_stdout " "
|
||||
pr_stdout "${SCRIPTNAME}: Error: Collection of data failed!"
|
||||
pr_stdout " The creation of \"${WORKARCHIVE}\" was not successful."
|
||||
pr_stdout " Please check the directory \"${WORKDIR_BASE}\""
|
||||
pr_stdout " to provide enough free available space."
|
||||
tar -czf "${WORKARCHIVE}" "${WORKDIR_CURRENT}"
|
||||
rc_tar=$?
|
||||
if [ $rc_tar -eq 0 ]; then
|
||||
chmod 0600 "${WORKARCHIVE}"
|
||||
pr_stdout " "
|
||||
pr_stdout "Collected data was saved to:"
|
||||
pr_stdout " >> ${WORKARCHIVE} <<"
|
||||
pr_stdout " "
|
||||
pr_stdout "Review the collected data before sending to your service organization. "
|
||||
pr_stdout " "
|
||||
elif [ $rc_tar -eq 127 ]; then
|
||||
pr_stdout " "
|
||||
pr_stdout "${SCRIPTNAME}: Error: tar command is not available!"
|
||||
pr_stdout " Please install the corresponding package!"
|
||||
else
|
||||
chmod 0600 "${WORKARCHIVE}"
|
||||
pr_stdout " "
|
||||
pr_stdout "Collected data was saved to:"
|
||||
pr_stdout " >> ${WORKARCHIVE} <<"
|
||||
pr_stdout " "
|
||||
pr_stdout "${SCRIPTNAME}: Error: Collection of data failed!"
|
||||
pr_stdout " The creation of \"${WORKARCHIVE}\" was not successful."
|
||||
pr_stdout " Please check the directory \"${WORKDIR_BASE}\""
|
||||
pr_stdout " to provide enough free available space."
|
||||
fi
|
||||
|
||||
pr_stdout " "
|
||||
pr_stdout "Review the collected data before sending to your service organization. "
|
||||
pr_stdout " "
|
||||
}
|
||||
|
||||
|
||||
@@ -1117,6 +1149,8 @@ collect_domain_xml
|
||||
|
||||
collect_docker
|
||||
|
||||
collect_nvme
|
||||
|
||||
post_processing
|
||||
|
||||
create_package
|
||||
|
||||
213
scripts/zipl-switch-to-blscfg
Executable file
213
scripts/zipl-switch-to-blscfg
Executable file
@@ -0,0 +1,213 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# zipl-switch-to-blscfg - Switch zipl to use BootLoaderSpec configuration
|
||||
#
|
||||
# Copyright 2018 Red Hat, Inc.
|
||||
#
|
||||
# s390-tools is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the MIT license. See LICENSE for details.
|
||||
#
|
||||
|
||||
readonly SCRIPTNAME="${0##*/}"
|
||||
|
||||
declare -A zipl_to_bls
|
||||
zipl_to_bls["image"]="linux"
|
||||
zipl_to_bls["ramdisk"]="initrd"
|
||||
zipl_to_bls["parameters"]="options"
|
||||
|
||||
print_error() {
|
||||
echo "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
function on_exit() {
|
||||
if ! rm -rf $TMP; then
|
||||
echo "Delete temporary files failed!" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
if ! TMP="$(mktemp -d)"; then
|
||||
print_error "Creating a temporary dir for config files failed!"
|
||||
fi
|
||||
|
||||
trap 'on_exit' EXIT
|
||||
|
||||
print_version() {
|
||||
cat <<EOF
|
||||
${SCRIPTNAME}: version %S390_TOOLS_VERSION%
|
||||
Copyright Red Hat, Inc. 2018
|
||||
EOF
|
||||
}
|
||||
|
||||
print_usage()
|
||||
{
|
||||
print_version
|
||||
|
||||
cat <<EOF
|
||||
|
||||
Usage: ${SCRIPTNAME} [OPTIONS]
|
||||
|
||||
Switches the zipl boot-loader configuration to use BootLoaderSpec files.
|
||||
|
||||
Options:
|
||||
|
||||
-h, --help print this help and exit
|
||||
-v, --version print version information and exit
|
||||
--backup-suffix=SUFFIX suffix used for backup files, defaults to .bak
|
||||
--bls-directory=DIR path to generate BLS files, defaults to /boot/loader/entries
|
||||
--config-file=FILE path to zipl configuration file, defaults to /etc/zipl.conf
|
||||
--ignore-default ignore the default option from the zipl configuration file
|
||||
--use-version-name use the section kernel version as the BLS file name
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
OPTS="$(getopt -o hv --long help,version,backup-suffix:,bls-directory:,config-file:,\
|
||||
ignore-default,use-version-name -n \'$SCRIPTNAME\' -- "$@")"
|
||||
eval set -- "$OPTS"
|
||||
|
||||
BACKUP_SUFFIX=.bak
|
||||
BLS_DIR="/boot/loader/entries"
|
||||
CMDLINE_LINUX_DEBUG=" systemd.log_level=debug systemd.log_target=kmsg"
|
||||
LINUX_DEBUG_VERSION_POSTFIX="_with_debugging"
|
||||
LINUX_DEBUG_TITLE_POSTFIX=" with debugging"
|
||||
CONFIG="/etc/zipl.conf"
|
||||
|
||||
while [ ${#} -gt 0 ]; do
|
||||
case "$1" in
|
||||
--help|-h)
|
||||
print_usage
|
||||
exit 0
|
||||
;;
|
||||
--version|-v)
|
||||
print_version
|
||||
exit 0
|
||||
;;
|
||||
--backup-suffix)
|
||||
BACKUP_SUFFIX=${2}
|
||||
shift
|
||||
;;
|
||||
--bls-directory)
|
||||
BLS_DIR=${2}
|
||||
shift
|
||||
;;
|
||||
--config-file)
|
||||
CONFIG=${2}
|
||||
shift
|
||||
;;
|
||||
--ignore-default)
|
||||
ignore_default=true
|
||||
;;
|
||||
--use-version-name)
|
||||
version_name=true
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
echo >&2
|
||||
echo "${SCRIPTNAME}: invalid option \"${1}\"" >&2
|
||||
echo "Try '${SCRIPTNAME} --help' for more information" >&2
|
||||
echo >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
TMP_CONFIG="${TMP}/${CONFIG##*/}"
|
||||
|
||||
[[ -d "$BLS_DIR" ]] || mkdir -m 0700 -p "$BLS_DIR"
|
||||
|
||||
if [ -f /etc/machine-id ]; then
|
||||
read MACHINE_ID < /etc/machine-id
|
||||
MACHINE_ID=${MACHINE_ID}-
|
||||
fi
|
||||
|
||||
count=0
|
||||
OUTPUT=""
|
||||
TARGET=""
|
||||
while IFS='= ' read key val; do
|
||||
# for BLS the default kernel is always the latest one
|
||||
if [[ $key == \#* ]] || [[ $key == "default" && $ignore_default == true ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# remove spaces
|
||||
key="$(echo $key | sed -e 's/^[ \t"]*//;s/[ \t"]*$//')"
|
||||
|
||||
if [[ $key = \[*] ]]; then
|
||||
if [[ $key == "[defaultboot]" ]]; then
|
||||
OUTPUT=${TMP_CONFIG}
|
||||
echo $key >> ${OUTPUT}
|
||||
else
|
||||
key="${key%\]}"
|
||||
key="${key#\[}"
|
||||
section=$key
|
||||
OUTPUT=${BLS_DIR}/${MACHINE_ID}${section}.conf
|
||||
if [ -f "${OUTPUT}" ]; then
|
||||
print_error "BLS file ${OUTPUT} already exists"
|
||||
fi
|
||||
fi
|
||||
elif [[ $val ]]; then
|
||||
val="$(echo $val | sed -e 's/^[ \t"]*//;s/[ \t"]*$//')"
|
||||
if [[ $key == "target" ]]; then
|
||||
if [ -z ${TARGET} ]; then
|
||||
echo $key=$val >> ${TMP_CONFIG}
|
||||
TARGET=$val
|
||||
else if [ "${TARGET}" != "${val}" ]; then
|
||||
print_error "BLS is only supported if all sections have the same target"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
if [ -n "${zipl_to_bls[$key]}" ]; then
|
||||
if [[ $key = "image" && $version_name == true ]]; then
|
||||
if [[ $val = *"vmlinuz-"* ]]; then
|
||||
version="${val##*/vmlinuz-}"
|
||||
else
|
||||
version="${val##*/}"
|
||||
fi
|
||||
echo "version $version" >> ${OUTPUT}
|
||||
if [[ $version = *"rescue"* ]]; then
|
||||
FILENAME=${BLS_DIR}/${MACHINE_ID}0-rescue.conf
|
||||
else
|
||||
FILENAME=${BLS_DIR}/${MACHINE_ID}${version}.conf
|
||||
fi
|
||||
|
||||
if [[ ${OUTPUT} != ${FILENAME} ]]; then
|
||||
if [ -f "${FILENAME}" ]; then
|
||||
print_error "BLS file ${FILENAME} already exists"
|
||||
fi
|
||||
mv ${OUTPUT} ${FILENAME}
|
||||
if [ ! $? -eq 0 ]; then
|
||||
print_error "Creating BLS file ${FILENAME} failed"
|
||||
fi
|
||||
OUTPUT=${FILENAME}
|
||||
fi
|
||||
elif [[ $key = "image" ]]; then
|
||||
echo "version $section" >> ${OUTPUT}
|
||||
fi
|
||||
|
||||
echo "${zipl_to_bls[$key]} ${val}" >> ${OUTPUT}
|
||||
else
|
||||
echo $key=$val >> ${TMP_CONFIG}
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done < "${CONFIG}"
|
||||
|
||||
if [ -f "${CONFIG}${BACKUP_SUFFIX}" ]; then
|
||||
print_error "Backup file ${CONFIG}${BACKUP_SUFFIX} already exists"
|
||||
fi
|
||||
|
||||
cp -af "${CONFIG}" "${CONFIG}${BACKUP_SUFFIX}"
|
||||
mv "${TMP_CONFIG}" "${CONFIG}"
|
||||
|
||||
zipl > /dev/null
|
||||
if [ ! $? -eq 0 ]; then
|
||||
mv "${CONFIG}${BACKUP_SUFFIX}" "${CONFIG}"
|
||||
fi
|
||||
|
||||
exit 0
|
||||
45
scripts/zipl-switch-to-blscfg.1
Normal file
45
scripts/zipl-switch-to-blscfg.1
Normal file
@@ -0,0 +1,45 @@
|
||||
.TH ZIPL-SWITCH-TO-BLSCFG 1 "April 2018" "s390-tools"
|
||||
|
||||
.SH NAME
|
||||
zipl-switch-to-blscfg \- Switch zipl to use BootLoaderSpec configuration
|
||||
|
||||
.SH SYNOPSIS
|
||||
.br
|
||||
\fBzipl-switch-to-blscfg\fP [OPTIONS]
|
||||
.br
|
||||
\fBzipl-switch-to-blscfg\fP {\-h|\-v}
|
||||
|
||||
.SH DESCRIPTION
|
||||
This script switches the zipl boot-loader configuration to use BootLoaderSpec files
|
||||
to define IPL sections. For each Linux kernel defined in the zipl.conf config file,
|
||||
a BLS fragment is generated in the BLS directory specified. Also, the zipl.conf is
|
||||
modified it only contains global configurations, all IPL sections comes from BLS.
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB\-h\fP, \fB\-\-help\fP
|
||||
Print this help and exit
|
||||
|
||||
.TP
|
||||
\fB\-v\fP, \fB\-\-version\fP
|
||||
Print version information and exit
|
||||
|
||||
.TP
|
||||
\fB\-\-backup-suffix <SUFFIX>\fP
|
||||
The suffix used for backup files, defaults to .bak.
|
||||
|
||||
.TP
|
||||
\fB\-\-bls-directory <DIRECTORY>\fP
|
||||
The DIRECTORY where the BLS fragments will be generated. The directory is created if it doesn't exists, by default /boot/loader/entries is used.
|
||||
|
||||
.TP
|
||||
\fB\-\-config-file <FILE>\fP
|
||||
The FILE used for zipl configuration file, defaults to /etc/zipl.conf.
|
||||
|
||||
.TP
|
||||
\fB\-\-ignore-default\fP
|
||||
Ignore the default option from the zipl configuration file
|
||||
|
||||
.TP
|
||||
\fB\-\-use-version-name\fP
|
||||
Use the section kernel version as the BLS file name
|
||||
@@ -2,7 +2,9 @@ include ../common.mak
|
||||
|
||||
all: vmcp
|
||||
|
||||
vmcp: vmcp.o
|
||||
libs = $(rootdir)/libvmcp/libvmcp.a $(rootdir)/libutil/libutil.a
|
||||
|
||||
vmcp: vmcp.o $(libs)
|
||||
|
||||
install: all
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man8
|
||||
|
||||
171
vmcp/vmcp.c
171
vmcp/vmcp.c
@@ -4,7 +4,7 @@
|
||||
* Tool for accessing the control program of z/VM using the
|
||||
* kernel module vmcp
|
||||
* return codes:
|
||||
* 0: everything was fine (VMCP_OK)
|
||||
* 0: everything was fine (EXIT_SUCCESS)
|
||||
* 1: CP returned a nn zero response code (VMCP_CP)
|
||||
* 2: the response buffer was not large enough (VMCP_BUF)
|
||||
* 3: an internal Linux error occurred (VMCP_LIN)
|
||||
@@ -28,33 +28,58 @@
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "vmcp.h"
|
||||
#include "lib/zt_common.h"
|
||||
#include "lib/vmcp.h"
|
||||
#include "lib/util_opt.h"
|
||||
#include "lib/util_prg.h"
|
||||
|
||||
#define MAXBUFFER 1048576
|
||||
#define MINBUFFER 4096
|
||||
#define MAXCMDLEN 240
|
||||
|
||||
#define VMCP_OK 0
|
||||
#define VMCP_CP 1
|
||||
#define VMCP_BUF 2
|
||||
#define VMCP_LIN 3
|
||||
#define VMCP_OPT 4
|
||||
|
||||
static int keep_case = 0;
|
||||
static int buffersize = 8192;
|
||||
static int buffersize = VMCP_DEFAULT_BUFSZ;
|
||||
static char command[MAXCMDLEN + 1];
|
||||
|
||||
static void print_help(const char *name)
|
||||
{
|
||||
printf("%s: z/VM CP command interface.\n%s", name, help_text);
|
||||
}
|
||||
static struct util_opt opt_vec[] = {
|
||||
UTIL_OPT_SECTION("OPTIONS"),
|
||||
{
|
||||
.option = { "keepcase", no_argument, NULL, 'k' },
|
||||
.desc = "Do not convert CP-command string to uppercase",
|
||||
},
|
||||
{
|
||||
.option = { "buffer", required_argument, NULL, 'b' },
|
||||
.argument = "SIZE",
|
||||
.desc = "Specify buffer size in bytes, kilobytes (k) "
|
||||
"or megabytes (M). SIZE range from 4096 to 1048576 "
|
||||
"bytes"
|
||||
},
|
||||
UTIL_OPT_HELP,
|
||||
UTIL_OPT_VERSION,
|
||||
UTIL_OPT_END
|
||||
};
|
||||
|
||||
static void print_version(const char *name)
|
||||
{
|
||||
printf("%s: z/VM CP command interface version %s\n"
|
||||
"Copyright IBM Corp. 2005, 2017\n",
|
||||
name, RELEASE_STRING);
|
||||
}
|
||||
|
||||
static void uppercase(char *string)
|
||||
{
|
||||
while (*string != '\0') {
|
||||
*string = toupper(*string);
|
||||
string++;
|
||||
static const struct util_prg prg = {
|
||||
.desc = "z/VM CP command interface",
|
||||
.args = "CP-command",
|
||||
.copyright_vec = {
|
||||
{
|
||||
.owner = "IBM Corp.",
|
||||
.pub_first = 2005,
|
||||
.pub_last = 2018,
|
||||
},
|
||||
UTIL_PRG_COPYRIGHT_END
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* Parse STRING for buffer size in bytes, allowing size modifier suffix 'k' and
|
||||
* 'm'. Return buffer size in bytes on success, -1 on error. */
|
||||
@@ -95,17 +120,18 @@ static int parse_args(int argc, char **argv)
|
||||
int index;
|
||||
|
||||
do {
|
||||
opt = getopt_long(argc, argv, opt_string, options, NULL);
|
||||
opt = util_opt_getopt_long(argc, argv);
|
||||
switch (opt) {
|
||||
case -1:
|
||||
/* Reached end of parameter list. */
|
||||
break;
|
||||
case 'h':
|
||||
print_help(argv[0]);
|
||||
exit(VMCP_OK);
|
||||
util_prg_print_help();
|
||||
util_opt_print_help();
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'v':
|
||||
print_version(argv[0]);
|
||||
exit(VMCP_OK);
|
||||
util_prg_print_version();
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'k':
|
||||
keep_case = 1;
|
||||
break;
|
||||
@@ -137,7 +163,8 @@ static int parse_args(int argc, char **argv)
|
||||
strcat(command, argv[index]);
|
||||
}
|
||||
if (strlen(command) == 0) {
|
||||
print_help(argv[0]);
|
||||
util_prg_print_help();
|
||||
util_opt_print_help();
|
||||
return VMCP_OPT;
|
||||
}
|
||||
return VMCP_OK;
|
||||
@@ -148,25 +175,6 @@ static inline void linux_error(const char *message)
|
||||
fprintf(stderr, "Error: %s: %s\n", message, strerror(errno));
|
||||
}
|
||||
|
||||
/* Read at most COUNT bytes from FD into memory at location BUF. Return
|
||||
* number of bytes read on success, -1 on error. */
|
||||
static ssize_t read_buffer(int fd, char *buf, size_t count)
|
||||
{
|
||||
ssize_t ret;
|
||||
ssize_t done;
|
||||
|
||||
for (done = 0; done < (ssize_t) count; done += ret) {
|
||||
ret = read(fd, &buf[done], count - done);
|
||||
if (ret == -1 && errno == EINTR)
|
||||
continue;
|
||||
if (ret == -1)
|
||||
return -1;
|
||||
if (ret == 0)
|
||||
break;
|
||||
}
|
||||
return done;
|
||||
}
|
||||
|
||||
/* Write COUNT bytes to FD from memory at location BUF. Return number of bytes
|
||||
* written on success, -1 otherwise. */
|
||||
static ssize_t write_buffer(int fd, const char *buf, size_t count)
|
||||
@@ -188,77 +196,54 @@ static ssize_t write_buffer(int fd, const char *buf, size_t count)
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct vmcp_parm cp;
|
||||
int ret;
|
||||
int fd;
|
||||
int response_code;
|
||||
int response_size;
|
||||
char *buffer;
|
||||
|
||||
util_prg_init(&prg);
|
||||
util_opt_init(opt_vec, NULL);
|
||||
|
||||
ret = parse_args(argc, argv);
|
||||
if (ret != VMCP_OK)
|
||||
return ret;
|
||||
|
||||
if (!keep_case)
|
||||
uppercase(command);
|
||||
cp.buffer_size = buffersize;
|
||||
cp.cpcmd = command;
|
||||
cp.do_upper = !keep_case;
|
||||
|
||||
buffer = malloc(buffersize);
|
||||
if (!buffer) {
|
||||
linux_error("Could not allocate return buffer");
|
||||
ret = vmcp(&cp);
|
||||
|
||||
switch (ret) {
|
||||
case VMCP_ERR_OPEN:
|
||||
linux_error("Could not open device " VMCP_DEVICE_NODE);
|
||||
return VMCP_LIN;
|
||||
}
|
||||
fd = open(DEVICE_NODE, O_RDWR);
|
||||
if (fd == -1) {
|
||||
linux_error("Could not open device " DEVICE_NODE);
|
||||
free(buffer);
|
||||
return VMCP_LIN;
|
||||
}
|
||||
if (ioctl(fd, VMCP_SETBUF, &buffersize) == -1) {
|
||||
case VMCP_ERR_SETBUF:
|
||||
linux_error("Could not set buffer size");
|
||||
free(buffer);
|
||||
close(fd);
|
||||
return VMCP_LIN;
|
||||
}
|
||||
if (write(fd, command, strlen(command)) == -1) {
|
||||
case VMCP_ERR_WRITE:
|
||||
linux_error("Could not issue CP command");
|
||||
free(buffer);
|
||||
close(fd);
|
||||
return VMCP_LIN;
|
||||
}
|
||||
if (ioctl(fd, VMCP_GETCODE, &response_code) == -1) {
|
||||
case VMCP_ERR_GETCODE:
|
||||
linux_error("Could not query return code");
|
||||
free(buffer);
|
||||
close(fd);
|
||||
return VMCP_LIN;
|
||||
}
|
||||
if (ioctl(fd, VMCP_GETSIZE, &response_size) == -1) {
|
||||
case VMCP_ERR_GETSIZE:
|
||||
linux_error("Could not query response size");
|
||||
free(buffer);
|
||||
close(fd);
|
||||
return VMCP_LIN;
|
||||
}
|
||||
ret = read_buffer(fd, buffer, buffersize);
|
||||
if (ret == -1) {
|
||||
case VMCP_ERR_READ:
|
||||
linux_error("Could not read CP response");
|
||||
free(buffer);
|
||||
close(fd);
|
||||
return VMCP_LIN;
|
||||
}
|
||||
write_buffer(STDOUT_FILENO, buffer, ret);
|
||||
if (response_size > buffersize) {
|
||||
write_buffer(STDOUT_FILENO, cp.response,
|
||||
MIN(cp.response_size, cp.buffer_size));
|
||||
free(cp.response);
|
||||
if (ret == VMCP_ERR_TOOSMALL) {
|
||||
fprintf(stderr, "Error: output (%d bytes) was truncated, try "
|
||||
"--buffer to increase size\n", response_size);
|
||||
free(buffer);
|
||||
close(fd);
|
||||
"--buffer to increase size\n", cp.response_size);
|
||||
return VMCP_BUF;
|
||||
}
|
||||
if (response_code > 0) {
|
||||
if (cp.cprc > 0) {
|
||||
fprintf(stderr, "Error: non-zero CP response for command '%s': "
|
||||
"#%d\n", command, response_code);
|
||||
free(buffer);
|
||||
close(fd);
|
||||
"#%d\n", command, cp.cprc);
|
||||
return VMCP_CP;
|
||||
}
|
||||
free(buffer);
|
||||
close(fd);
|
||||
return VMCP_OK;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
59
vmcp/vmcp.h
59
vmcp/vmcp.h
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* vmcp - Send commands to the z/VM control program
|
||||
*
|
||||
* Definitions used by vmcp
|
||||
*
|
||||
* Copyright IBM Corp. 2005, 2017
|
||||
*
|
||||
* 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 __vmcp_h__
|
||||
#define __vmcp_h__
|
||||
|
||||
#include <getopt.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "lib/zt_common.h"
|
||||
|
||||
#define DEVICE_NODE "/dev/vmcp"
|
||||
|
||||
#define VMCP_GETCODE _IOR(0x10, 1, int)
|
||||
#define VMCP_SETBUF _IOW(0x10, 2, int)
|
||||
#define VMCP_GETSIZE _IOR(0x10, 3, int)
|
||||
|
||||
#define MAXBUFFER 1048576
|
||||
#define MINBUFFER 4096
|
||||
#define MAXCMDLEN 240
|
||||
|
||||
#define VMCP_OK 0
|
||||
#define VMCP_CP 1
|
||||
#define VMCP_BUF 2
|
||||
#define VMCP_LIN 3
|
||||
#define VMCP_OPT 4
|
||||
|
||||
static struct option options[] = {
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{"version", no_argument, NULL, 'v'},
|
||||
{"keepcase", no_argument, NULL, 'k'},
|
||||
{"buffer", required_argument, NULL, 'b'},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
static const char opt_string[] = "+hvkb:";
|
||||
|
||||
static const char help_text[] =
|
||||
"Usage:\n"
|
||||
"vmcp [-k] [-b <size>] command\n"
|
||||
"vmcp [-h|-v]\n\n"
|
||||
"Options:\n"
|
||||
"-h or --help :Print usage information, then exit\n"
|
||||
"-v or --version :Print version information, then exit\n"
|
||||
"-k or --keepcase :Using this option, vmcp does not convert the command\n"
|
||||
" to uppercase. The default is to translate the command\n"
|
||||
" string.\n"
|
||||
"-b <size> or :defines the buffer size for the response\n"
|
||||
"--buffer=<size> valid values are from 4096 to 1048576 bytes\n"
|
||||
" the k and M suffixes are also supported\n";
|
||||
#endif
|
||||
@@ -5,7 +5,9 @@ LDLIBS += -lz
|
||||
|
||||
all: vmur
|
||||
|
||||
libs = $(rootdir)/libvmdump/libvmdump.a
|
||||
libs = $(rootdir)/libvmdump/libvmdump.a \
|
||||
$(rootdir)/libvmcp/libvmcp.a $(rootdir)/libutil/libutil.a
|
||||
|
||||
objects = vmur.o
|
||||
|
||||
vmur: $(objects) $(libs)
|
||||
|
||||
131
vmur/vmur.cpp
131
vmur/vmur.cpp
@@ -31,9 +31,13 @@
|
||||
|
||||
#include "lib/vmdump.h"
|
||||
#include "lib/zt_common.h"
|
||||
#include "lib/util_libc.h"
|
||||
#include "lib/vmcp.h"
|
||||
|
||||
#include "vmur.h"
|
||||
|
||||
#define CP_PREFIX_LEN 11
|
||||
|
||||
/* Program name */
|
||||
static char *prog_name;
|
||||
|
||||
@@ -243,24 +247,6 @@ fail:
|
||||
ERR_EXIT("Could not initialize signal handler (errno = %i)\n", errno);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read at most COUNT bytes from FD into memory at location BUF.
|
||||
* Return number of bytes read on success, -1 on error.
|
||||
*/
|
||||
static ssize_t read_buf(int fd, char *buf, ssize_t count)
|
||||
{
|
||||
ssize_t rc, len;
|
||||
|
||||
for (len = 0; len < count; len += rc) {
|
||||
rc = read(fd, &buf[len], count - len);
|
||||
if (rc == -1)
|
||||
return -1;
|
||||
if (rc == 0)
|
||||
break;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Strip leading CP header from error message
|
||||
*/
|
||||
@@ -293,64 +279,63 @@ static void cperr_exit(char *cpcmd, int cprc, char *buf)
|
||||
|
||||
static void _cpcmd(char *cpcmd, char **resp, int *rc, int retry, int upper)
|
||||
{
|
||||
int fd, len, cprc, bufsize = VMCP_BUFSIZE;
|
||||
char *buf;
|
||||
struct vmcp_parm cp;
|
||||
char cmd[MAXCMDLEN];
|
||||
int ret;
|
||||
|
||||
strcpy(cmd, cpcmd);
|
||||
if (upper)
|
||||
to_upper(cmd);
|
||||
cp.cpcmd = cmd;
|
||||
cp.do_upper = upper;
|
||||
cp.buffer_size = VMCP_DEFAULT_BUFSZ;
|
||||
|
||||
fd = open(VMCP_DEVICE_NODE, O_RDWR);
|
||||
if (fd == -1)
|
||||
retry:
|
||||
ret = vmcp(&cp);
|
||||
|
||||
switch (ret) {
|
||||
case VMCP_ERR_OPEN:
|
||||
ERR_EXIT("Could not issue CP command: \"%s\"\n"
|
||||
"Ensure that vmcp kernel module is loaded!\n", cmd);
|
||||
|
||||
do {
|
||||
if (ioctl(fd, VMCP_SETBUF, &bufsize) == -1)
|
||||
goto fail;
|
||||
|
||||
if (write(fd, cmd, strlen(cmd)) == -1)
|
||||
goto fail;
|
||||
|
||||
if (ioctl(fd, VMCP_GETCODE, &cprc) == -1)
|
||||
goto fail;
|
||||
|
||||
if (ioctl(fd, VMCP_GETSIZE, &len) == -1)
|
||||
goto fail;
|
||||
|
||||
if (len <= bufsize)
|
||||
break;
|
||||
else if (retry)
|
||||
bufsize = len;
|
||||
else
|
||||
ERR_EXIT("Not enough buffer space (%i/%i) for CP "
|
||||
"command '%s'.\nSorry, please issue command "
|
||||
"on your 3270 console!\n", len, bufsize, cmd);
|
||||
} while (1);
|
||||
|
||||
buf = (char *) malloc(len + 1);
|
||||
if (!buf)
|
||||
ERR_EXIT("Out of memory for CP command '%s'\n", cmd);
|
||||
|
||||
memset(buf, 0, len + 1);
|
||||
if (read_buf(fd, buf, len) == -1)
|
||||
case VMCP_ERR_SETBUF:
|
||||
goto fail;
|
||||
|
||||
case VMCP_ERR_WRITE:
|
||||
goto fail;
|
||||
|
||||
case VMCP_ERR_GETCODE:
|
||||
goto fail;
|
||||
|
||||
case VMCP_ERR_GETSIZE:
|
||||
goto fail;
|
||||
|
||||
case VMCP_ERR_READ:
|
||||
goto fail;
|
||||
|
||||
case VMCP_ERR_TOOSMALL:
|
||||
if (retry) {
|
||||
cp.buffer_size = cp.response_size;
|
||||
free(cp.response);
|
||||
goto retry;
|
||||
}
|
||||
ERR_EXIT("Not enough buffer space (%u/%u) for CP "
|
||||
"command '%s'.\nSorry, please issue command "
|
||||
" on your 3270 console!\n", cp.response_size,
|
||||
cp.buffer_size, cmd);
|
||||
}
|
||||
|
||||
if (rc == NULL) {
|
||||
if (cprc != 0) {
|
||||
if (cp.cprc != 0) {
|
||||
/* caller wants us to handle the error */
|
||||
cperr_exit(cmd, cprc, buf);
|
||||
cperr_exit(cmd, cp.cprc, cp.response);
|
||||
}
|
||||
} else {
|
||||
*rc = cprc;
|
||||
*rc = cp.cprc;
|
||||
}
|
||||
|
||||
if (resp)
|
||||
*resp = buf;
|
||||
*resp = cp.response;
|
||||
else
|
||||
free(buf);
|
||||
close(fd);
|
||||
free(cp.response);
|
||||
return;
|
||||
|
||||
fail:
|
||||
@@ -1369,30 +1354,6 @@ static void close_reader(struct vmur *info, const char *hold)
|
||||
cpcmd(cmd, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* strip leading and trailing blanks
|
||||
*/
|
||||
static char *strstrip(char *s)
|
||||
{
|
||||
size_t size;
|
||||
char *end;
|
||||
|
||||
size = strlen(s);
|
||||
|
||||
if (!size)
|
||||
return s;
|
||||
|
||||
end = s + size - 1;
|
||||
while (end >= s && isspace(*end))
|
||||
end--;
|
||||
*(end + 1) = '\0';
|
||||
|
||||
while (*s && isspace(*s))
|
||||
s++;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether reader can handle class of reader spool file
|
||||
*/
|
||||
@@ -1431,9 +1392,9 @@ static int get_filename_from_reader(struct vmur *info)
|
||||
sprintf(cmd, "QUERY RDR * %s ALL SHORTDATE", info->spoolid);
|
||||
cpcmd(cmd, &buf, NULL, 0);
|
||||
memcpy(name, &buf[130], 8);
|
||||
strstrip(name);
|
||||
util_strstrip(name);
|
||||
memcpy(type, &buf[140], 8);
|
||||
strstrip(type);
|
||||
util_strstrip(type);
|
||||
free(buf);
|
||||
if (strlen(name) == 0) {
|
||||
ERR("Please specify name to receive "
|
||||
|
||||
@@ -31,14 +31,6 @@ do { \
|
||||
ERR_EXIT(str " can only be specified once.\n"); \
|
||||
} while (0)
|
||||
|
||||
#define VMCP_DEVICE_NODE "/dev/vmcp"
|
||||
#define VMCP_BUFSIZE 0x4000
|
||||
#define VMCP_GETSIZE _IOR(0x10, 3, int)
|
||||
#define VMCP_SETBUF _IOW(0x10, 2, int)
|
||||
#define VMCP_GETCODE _IOR(0x10, 1, int)
|
||||
|
||||
#define CP_PREFIX_LEN 11
|
||||
|
||||
#define VMRDR_DEVICE_NODE "/dev/vmrdr-0.0.000c"
|
||||
#define VMPUN_DEVICE_NODE "/dev/vmpun-0.0.000d"
|
||||
#define VMPRT_DEVICE_NODE "/dev/vmprt-0.0.000e"
|
||||
|
||||
@@ -23,7 +23,7 @@ install: install-scripts install-manpages install-usrsbin-scripts $(SUB_DIRS)
|
||||
install-scripts: $(SCRIPTS)
|
||||
@for i in $^; do \
|
||||
cat $$i | \
|
||||
sed -e 's+%S390_TOOLS_VERSION%+$(S390_TOOLS_RELEASE)+' \
|
||||
sed -e 's/%S390_TOOLS_VERSION%/$(S390_TOOLS_RELEASE)/' \
|
||||
>$(DESTDIR)$(BINDIR)/$$i; \
|
||||
chown $(OWNER).$(GROUP) $(DESTDIR)$(BINDIR)/$$i; \
|
||||
chmod 755 $(DESTDIR)$(BINDIR)/$$i; \
|
||||
@@ -32,7 +32,7 @@ install-scripts: $(SCRIPTS)
|
||||
install-usrsbin-scripts: $(USRSBIN_SCRIPTS)
|
||||
@for i in $^; do \
|
||||
cat $$i | \
|
||||
sed -e 's+%S390_TOOLS_VERSION%+$(S390_TOOLS_RELEASE)+' \
|
||||
sed -e 's/%S390_TOOLS_VERSION%/$(S390_TOOLS_RELEASE)/' \
|
||||
>$(DESTDIR)$(USRSBINDIR)/$$i; \
|
||||
chown $(OWNER).$(GROUP) $(DESTDIR)$(USRSBINDIR)/$$i; \
|
||||
chmod 755 $(DESTDIR)$(USRSBINDIR)/$$i; \
|
||||
|
||||
@@ -111,6 +111,10 @@ In rare situations a device might temporarily not be accessible to
|
||||
the subchannel. Then "none" is displayed as the device identifier and the
|
||||
other device attributes are empty.
|
||||
|
||||
For subchannels bound to an alternate driver (most notably vfio_ccw) the
|
||||
device identifier may also be displayed as "none". In this case use the
|
||||
\fB--vfio\fR option to show VFIO specific subchannel information.
|
||||
|
||||
.SH AUTHOR
|
||||
.nf
|
||||
This man-page was written by Stefan Bader <shbader@de.ibm.com>.
|
||||
|
||||
@@ -649,14 +649,12 @@ static void print_defunct_devices(struct util_rec *rec, char *path)
|
||||
snprintf(buf, sizeof(buf), "%s", device);
|
||||
}
|
||||
if (cmd.opt_devrange && cmd.rng_count > 0 &&
|
||||
!id_in_ranges_list(device)) {
|
||||
util_scandir_free(de_vec, count);
|
||||
!id_in_ranges_list(device))
|
||||
continue;
|
||||
}
|
||||
if (fill_device_info(rec, path, device) != 0) {
|
||||
util_scandir_free(de_vec, count);
|
||||
|
||||
if (fill_device_info(rec, path, device) != 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cmd.opt_uppercase)
|
||||
util_str_toupper(buf);
|
||||
util_rec_set(rec, "device", "%s", buf);
|
||||
@@ -719,7 +717,7 @@ static void print_subchannels_of_type(enum sch_type type_requested,
|
||||
if (!cmd.opt_devrange && cmd.rng_count > 0)
|
||||
return;
|
||||
path = util_path_sysfs("devices");
|
||||
count = util_scandir(&de_vec, alphasort, path, "css.*/");
|
||||
count = util_scandir(&de_vec, alphasort, path, "css.*");
|
||||
free(path);
|
||||
for (i = 0; i < count; i++) {
|
||||
path = util_path_sysfs("devices/%s/defunct", de_vec[i]->d_name);
|
||||
|
||||
@@ -235,8 +235,15 @@ sub get_env_list
|
||||
my @res ;
|
||||
my %res_hash;
|
||||
|
||||
if (!</sys/bus/ccw/drivers/zfcp/*.*.*/>) {
|
||||
print "$PROGRAM_NAME: No adapter exists\n";
|
||||
return;
|
||||
}
|
||||
@res = </sys/bus/ccw/drivers/zfcp/*.*.*/0x*>;
|
||||
return () if (!@res);
|
||||
if (!@res) {
|
||||
print "$PROGRAM_NAME: No port on any adapter exists\n";
|
||||
return;
|
||||
}
|
||||
foreach my $entry (@res) {
|
||||
my $a = ${[split('/', $entry)]}[-2];
|
||||
my $p = ${[split('/', $entry)]}[-1];
|
||||
|
||||
@@ -2,7 +2,7 @@ include ../../common.mak
|
||||
|
||||
all: lsqeth
|
||||
|
||||
libs = $(rootdir)/libutil/libutil.a
|
||||
libs = $(rootdir)/libvmcp/libvmcp.a $(rootdir)/libutil/libutil.a
|
||||
|
||||
lsqeth: lsqeth.o misc.o $(libs)
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "lib/util_rec.h"
|
||||
#include "lib/util_scandir.h"
|
||||
#include "lib/zt_common.h"
|
||||
#include "lib/vmcp.h"
|
||||
|
||||
#include "misc.h"
|
||||
|
||||
@@ -44,15 +45,6 @@
|
||||
#define MAX_ID_LENGTH 10
|
||||
#define PAGE_SIZE 4096
|
||||
|
||||
/*
|
||||
* Constants for CP call (taken from vmcp.h)
|
||||
*/
|
||||
#define VMCP_DEVICE_NODE "/dev/vmcp"
|
||||
#define VMCP_GETCODE _IOR(0x10, 1, int)
|
||||
#define VMCP_SETBUF _IOW(0x10, 2, int)
|
||||
#define VMCP_GETSIZE _IOR(0x10, 3, int)
|
||||
#define CP_BUF_SIZE 8192
|
||||
|
||||
/*
|
||||
* Private data
|
||||
*/
|
||||
@@ -197,32 +189,38 @@ static void ethtool_checksumming(char *buf, const char *if_name)
|
||||
*/
|
||||
static void exec_cp(char **argz, size_t *argz_len, const char *fmt, ...)
|
||||
{
|
||||
int fd, response_code, response_size, rc;
|
||||
static const int buf_size = CP_BUF_SIZE;
|
||||
char *buf, *command;
|
||||
struct vmcp_parm cp;
|
||||
char *command;
|
||||
va_list ap;
|
||||
int rc;
|
||||
|
||||
fd = open(VMCP_DEVICE_NODE, O_RDWR);
|
||||
if (fd == -1)
|
||||
errx(EXIT_FAILURE, "Could not open device %s", VMCP_DEVICE_NODE);
|
||||
if (ioctl(fd, VMCP_SETBUF, &buf_size) == -1)
|
||||
errx(EXIT_FAILURE, "Could not set buffer size");
|
||||
UTIL_VASPRINTF(&command, fmt, ap);
|
||||
if (write(fd, command, strlen(command)) == -1)
|
||||
errx(EXIT_FAILURE, "Could not issue CP command");
|
||||
cp.cpcmd = command;
|
||||
cp.do_upper = false;
|
||||
cp.buffer_size = VMCP_DEFAULT_BUFSZ;
|
||||
rc = vmcp(&cp);
|
||||
free(command);
|
||||
if (ioctl(fd, VMCP_GETCODE, &response_code) == -1)
|
||||
|
||||
switch (rc) {
|
||||
case VMCP_ERR_OPEN:
|
||||
errx(EXIT_FAILURE, "Could not open device %s", VMCP_DEVICE_NODE);
|
||||
case VMCP_ERR_SETBUF:
|
||||
errx(EXIT_FAILURE, "Could not set buffer size");
|
||||
case VMCP_ERR_GETCODE:
|
||||
errx(EXIT_FAILURE, "Could not query return code");
|
||||
if (ioctl(fd, VMCP_GETSIZE, &response_size) == -1)
|
||||
case VMCP_ERR_GETSIZE:
|
||||
errx(EXIT_FAILURE, "Could not query response size");
|
||||
buf = util_malloc(buf_size);
|
||||
rc = misc_read_buf(fd, buf, buf_size);
|
||||
if (rc == -1)
|
||||
case VMCP_ERR_WRITE:
|
||||
errx(EXIT_FAILURE, "Could not issue CP command");
|
||||
case VMCP_ERR_READ:
|
||||
errx(EXIT_FAILURE, "Could not read CP response");
|
||||
rc = argz_create_sep(buf, '\n', argz, argz_len);
|
||||
case VMCP_ERR_TOOSMALL:
|
||||
break; /* Truncated CP response treated as good */
|
||||
}
|
||||
rc = argz_create_sep(cp.response, '\n', argz, argz_len);
|
||||
if (rc)
|
||||
errx(EXIT_FAILURE, "Memory allocation error for CP response processing");
|
||||
free(buf);
|
||||
free(cp.response);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -57,6 +57,7 @@ Set all available cryptographic device(s) online or offline.
|
||||
.B <device id>
|
||||
Specifies a cryptographic device which will be set either online or offline.
|
||||
The device can either be a card device or a queue device.
|
||||
A queue device can only get switched online when the providing card is online.
|
||||
|
||||
Please note that the card device and queue device representation are both
|
||||
in hexadecimal notation.
|
||||
@@ -95,7 +96,7 @@ Print version information and exit.
|
||||
.B chzcrypt -e 0 1 12
|
||||
Will set the cryptographic card devices 0, 1 and 12 online.
|
||||
.TP
|
||||
.B chzcrypt -e 01.0038
|
||||
.B chzcrypt -e 10.0038
|
||||
Will set the cryptographic device '10.0038' respectively card id 16
|
||||
(0x10) with domain 56 (0x38) online.
|
||||
.TP
|
||||
|
||||
@@ -8,6 +8,7 @@ install: all
|
||||
$(MAKE) -C src install
|
||||
$(MAKE) -C man install
|
||||
$(MAKE) -C dracut install
|
||||
$(MAKE) -C initramfs install
|
||||
|
||||
clean:
|
||||
$(MAKE) -C src clean
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
# 95zdev/module_setup.sh
|
||||
# This module installs configuration files (udev rules and modprobe.conf
|
||||
# files) required to enable the root device on s390. It will only work when
|
||||
# the root device was configured using the chzdev tool.
|
||||
# the root device was configured using the chzdev tool. In addition,
|
||||
# a hook is installed to parse rd.zdev= kernel parameters.
|
||||
#
|
||||
|
||||
check() {
|
||||
@@ -29,22 +30,27 @@ depends() {
|
||||
}
|
||||
|
||||
installkernel() {
|
||||
local _modules=$(lszdev --by-path / --columns MODULES --no-headings)
|
||||
|
||||
[ ! -z "$_modules" ] && instmods $_modules
|
||||
# Add modules for all device types supported by chzdev (required for
|
||||
# auto-configuration)
|
||||
instmods lcs qeth qeth_l2 qeth_l3 dasd_mod dasd_eckd_mod dasd_fba_mod \
|
||||
dasd_diag_mod zfcp
|
||||
}
|
||||
|
||||
install() {
|
||||
local _tempfile=$(mktemp --tmpdir dracut-zdev.XXXXXX)
|
||||
local _tempfile
|
||||
|
||||
if chzdev --export - --persistent --by-path / >/dev/null 2>&1 ; then
|
||||
# Use persistent configuration
|
||||
chzdev --export "$_tempfile" --persistent --by-path / --quiet --type
|
||||
else
|
||||
# Use active configuration
|
||||
chzdev --export "$_tempfile" --active --by-path / --quiet --type
|
||||
sed -i -e 's/active/persistent/g' "$_tempfile"
|
||||
fi
|
||||
# Ensure that required tools are available
|
||||
inst_multiple chzdev lszdev vmcp
|
||||
|
||||
# Hook to parse zdev kernel parameter
|
||||
inst_hook cmdline 95 "$moddir/parse-zdev.sh"
|
||||
|
||||
# Obtain early + root device configuration
|
||||
_tempfile=$(mktemp --tmpdir dracut-zdev.XXXXXX)
|
||||
chzdev --export "$_tempfile" --persistent --by-path / --quiet \
|
||||
--type 2>/dev/null
|
||||
chzdev --export - --persistent --by-attrib "zdev:early=1" --quiet \
|
||||
--type 2>/dev/null >> "$_tempfile"
|
||||
|
||||
# Apply via --import to prevent other devices from being configured
|
||||
chzdev --import "$_tempfile" --persistent --base "/etc=$initdir/etc" \
|
||||
|
||||
38
zdev/dracut/95zdev/parse-zdev.sh
Normal file
38
zdev/dracut/95zdev/parse-zdev.sh
Normal file
@@ -0,0 +1,38 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright IBM Corp. 2017
|
||||
#
|
||||
# s390-tools is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the MIT license. See LICENSE for details.
|
||||
#
|
||||
# 95zdev/parse-zdev.sh
|
||||
# Parse the kernel command line for rd.zdev kernel parameters. These
|
||||
# parameters are evaluated and used to configure z Systems specific devices.
|
||||
#
|
||||
# Format:
|
||||
# rd.zdev=no-auto
|
||||
#
|
||||
# where
|
||||
#
|
||||
# no-auto: Indicates that firmware-provided I/O configuration data
|
||||
# should not be applied.
|
||||
#
|
||||
|
||||
zdev_fw_file="/sys/firmware/sclp_sd/config/data"
|
||||
zdev_base_args="--force --yes --no-root-update --no-settle --auto-conf --quiet"
|
||||
|
||||
if [ -e "$zdev_fw_file" ] ; then
|
||||
zdev_auto=1
|
||||
else
|
||||
zdev_auto=0
|
||||
fi
|
||||
|
||||
for zdev_arg in $(getargs rd.zdev); do
|
||||
if [ "$zdev_arg" = "no-auto" ] ; then
|
||||
zdev_auto=0
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $zdev_auto -eq 1 ] ; then
|
||||
chzdev --import "$zdev_fw_file" $zdev_base_args
|
||||
fi
|
||||
@@ -11,11 +11,14 @@ ZDEVDIR := 95zdev
|
||||
# performs the following functions when dracut is run:
|
||||
#
|
||||
# - copy the persistent root device configuration to the initial ram disk
|
||||
# - install a boot-time hook to apply firmware-provided configuration data
|
||||
# to the system
|
||||
#
|
||||
ifeq ($(HAVE_DRACUT),1)
|
||||
install:
|
||||
$(INSTALL) -m 755 -d $(DESTDIR)$(MODDIR)
|
||||
$(INSTALL) -m 755 -d $(DESTDIR)$(MODDIR)/$(ZDEVDIR)
|
||||
$(INSTALL) -m 755 $(ZDEVDIR)/module-setup.sh \
|
||||
$(ZDEVDIR)/parse-zdev.sh \
|
||||
$(DESTDIR)$(MODDIR)/$(ZDEVDIR)/
|
||||
endif
|
||||
|
||||
@@ -189,6 +189,7 @@ struct value_map {
|
||||
* in the persistent configuration
|
||||
* @nounload: (Device type attributes only) This attribute can be set while
|
||||
* the corresponding kernel module remains loaded.
|
||||
* @internal: This attribute only affects internal handling
|
||||
* @order: A number indicating the order in which to apply attribute
|
||||
* @order_cmp: A function determining if a setting for this attribute should
|
||||
* be applied before (-1) or after (1) another setting, or
|
||||
@@ -216,6 +217,7 @@ struct attrib {
|
||||
unsigned int activerem :1;
|
||||
unsigned int defunset :1;
|
||||
unsigned int nounload :1;
|
||||
unsigned int internal :1;
|
||||
|
||||
/* Optional */
|
||||
int order;
|
||||
|
||||
@@ -11,7 +11,10 @@
|
||||
#define DASD_H
|
||||
|
||||
struct devtype;
|
||||
struct subtype;
|
||||
|
||||
extern struct devtype dasd_devtype;
|
||||
extern struct subtype dasd_subtype_eckd;
|
||||
extern struct subtype dasd_subtype_fba;
|
||||
|
||||
#endif /* DASD_H */
|
||||
|
||||
@@ -45,6 +45,7 @@ struct device_state {
|
||||
* @node: Node for adding this device to a list
|
||||
* @active: Device state in the active configuration
|
||||
* @persistent: Device state in the persistent configuration
|
||||
* @autoconf: Auto-configured device state
|
||||
* @errors: A strlist of error and warning messages issued for the device
|
||||
* @processed: Device has been processed
|
||||
*/
|
||||
@@ -59,6 +60,7 @@ struct device {
|
||||
|
||||
struct device_state active;
|
||||
struct device_state persistent;
|
||||
struct device_state autoconf;
|
||||
|
||||
unsigned int processed:1;
|
||||
};
|
||||
@@ -94,5 +96,9 @@ void device_list_add(struct device_list *, struct device *);
|
||||
struct device *device_list_find(struct device_list *, const char *,
|
||||
struct device *);
|
||||
void device_list_print(struct device_list *, int);
|
||||
struct setting_list *device_get_setting_list(struct device *dev,
|
||||
config_t config);
|
||||
|
||||
config_t device_get_config(struct device *dev);
|
||||
|
||||
#endif /* DEVICE_H */
|
||||
|
||||
@@ -31,6 +31,7 @@ struct export_object {
|
||||
} ptr;
|
||||
};
|
||||
|
||||
struct export_object *object_new(export_t type, void *ptr);
|
||||
exit_code_t export_write_device(FILE *, struct device *, config_t, int *);
|
||||
exit_code_t export_write_devtype(FILE *, struct devtype *, config_t, int *);
|
||||
exit_code_t export_read(FILE *, const char *, struct util_list *);
|
||||
|
||||
25
zdev/include/firmware.h
Normal file
25
zdev/include/firmware.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* zdev - Modify and display the persistent configuration of devices
|
||||
*
|
||||
* Copyright IBM Corp. 2017
|
||||
*
|
||||
* 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 FIRMWARE_H
|
||||
#define FIRMWARE_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "exit_code.h"
|
||||
#include "misc.h"
|
||||
|
||||
struct util_list;
|
||||
|
||||
bool firmware_detect(FILE *fd);
|
||||
exit_code_t firmware_read(FILE *fd, const char *filename, long skip,
|
||||
config_t config, struct util_list *objects);
|
||||
|
||||
#endif /* FIRMWARE_H */
|
||||
25
zdev/include/internal.h
Normal file
25
zdev/include/internal.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* zdev - Modify and display the persistent configuration of devices
|
||||
*
|
||||
* Copyright IBM Corp. 2017
|
||||
*
|
||||
* 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 INTERNAL_H
|
||||
#define INTERNAL_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "attrib.h"
|
||||
|
||||
#define INTERNAL_ATTR_PREFIX "zdev:"
|
||||
#define INTERNAL_ATTR_EARLY INTERNAL_ATTR_PREFIX "early"
|
||||
|
||||
extern struct attrib internal_attr_early;
|
||||
|
||||
const char *internal_get_name(const char *name);
|
||||
bool internal_by_name(const char *name);
|
||||
|
||||
#endif /* INTERNAL_H */
|
||||
@@ -19,9 +19,14 @@
|
||||
#include "exit_code.h"
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
#define SCOPE_ACTIVE(x) (((x) == config_active) || ((x) == config_all))
|
||||
#define SCOPE_PERSISTENT(x) (((x) == config_persistent) || \
|
||||
((x) == config_all))
|
||||
#define SCOPE_ACTIVE(x) ((x) & config_active ? 1 : 0)
|
||||
#define SCOPE_PERSISTENT(x) ((x) & config_persistent ? 1 : 0)
|
||||
#define SCOPE_AUTOCONF(x) ((x) & config_autoconf ? 1 : 0)
|
||||
#define SCOPE_ALL(x) ((x) == (config_active | config_persistent |\
|
||||
config_autoconf))
|
||||
#define SCOPE_SINGLE(x) ((x) == config_active || \
|
||||
(x) == config_persistent || \
|
||||
(x) == config_autoconf)
|
||||
|
||||
#define DELAY_INDENT 4
|
||||
|
||||
@@ -34,12 +39,15 @@
|
||||
|
||||
#define EVEN(x) (((x) & 1) == 0)
|
||||
|
||||
/* Enumeration of configuration sets. */
|
||||
typedef enum {
|
||||
config_active,
|
||||
config_persistent,
|
||||
config_all,
|
||||
} config_t;
|
||||
/* Enumeration of configuration sets. Multiple configuration sets can be
|
||||
* combined using bit-wise or. */
|
||||
enum {
|
||||
config_active = 1,
|
||||
config_persistent = 2,
|
||||
config_autoconf = 4,
|
||||
config_all = 7,
|
||||
};
|
||||
typedef int config_t;
|
||||
|
||||
typedef enum {
|
||||
err_ignore,
|
||||
@@ -159,6 +167,7 @@ bool misc_read_dir(const char *, struct util_list *,
|
||||
bool (*)(const char *, void *), void *);
|
||||
bool file_is_devnode(const char *);
|
||||
exit_code_t remove_file(const char *);
|
||||
exit_code_t misc_read_fd(FILE *fd, void **buffer, size_t *size_ptr);
|
||||
char *misc_read_text_file(const char *, int, err_t);
|
||||
char *misc_read_cmd_output(const char *, int, err_t);
|
||||
char *config_read_cmd_output(const char *, int, err_t);
|
||||
@@ -166,7 +175,7 @@ exit_code_t misc_write_text_file(const char *, const char *, err_t);
|
||||
exit_code_t misc_write_text_file_retry(const char *, const char *, err_t);
|
||||
exit_code_t misc_mktemp(char **, int *);
|
||||
char *misc_readlink(const char *path);
|
||||
config_t get_config(int, int);
|
||||
config_t get_config(int act, int pers, int ac);
|
||||
bool is_zvm(void);
|
||||
bool is_terminal(void);
|
||||
const char *config_to_str(config_t);
|
||||
@@ -174,6 +183,7 @@ bool str_to_config(const char *, config_t *);
|
||||
char *quote_str(const char *, int);
|
||||
char *unquote_str(const char *);
|
||||
char *shrink_str(const char *);
|
||||
char *misc_strrstr(const char *haystack, const char *needle);
|
||||
|
||||
struct util_list *strlist_new(void);
|
||||
void strlist_free(struct util_list *);
|
||||
|
||||
@@ -20,10 +20,11 @@
|
||||
#define UDEV_SUFFIX ".rules"
|
||||
|
||||
#define PATH_MODPROBE_CONF "/etc/modprobe.d"
|
||||
#define PATH_MODPROBE "/usr/sbin/modprobe"
|
||||
#define PATH_MODPROBE "/sbin/modprobe"
|
||||
#define PATH_CCW_BUS "/sys/bus/ccw"
|
||||
#define PATH_CCWGROUP_BUS "/sys/bus/ccwgroup"
|
||||
#define PATH_UDEV_RULES "/etc/udev/rules.d"
|
||||
#define PATH_UDEV_RULES_VOLATILE "/run/udev/rules.d"
|
||||
#define PATH_PROC "/proc"
|
||||
|
||||
#define PATH_UDEVADM "udevadm"
|
||||
@@ -55,8 +56,8 @@ char *path_get_ccw_device(const char *, const char *);
|
||||
char *path_get_ccw_devices(const char *);
|
||||
char *path_get_ccwgroup_device(const char *, const char *);
|
||||
char *path_get_ccwgroup_devices(const char *);
|
||||
char *path_get_udev_rule(const char *, const char *);
|
||||
char *path_get_udev_rules(void);
|
||||
char *path_get_udev_rule(const char *type, const char *id, bool vol);
|
||||
char *path_get_udev_rules(bool vol);
|
||||
char *path_get_proc(const char *);
|
||||
char *path_get_sys_bus_dev(const char *, const char *);
|
||||
char *path_get_sys_bus_drv(const char *, const char *);
|
||||
|
||||
@@ -17,9 +17,11 @@
|
||||
#define QETH_NUM_DEVS 3
|
||||
|
||||
struct devtype;
|
||||
struct subtype;
|
||||
struct namespace;
|
||||
|
||||
extern struct devtype qeth_devtype;
|
||||
extern struct subtype qeth_subtype_qeth;
|
||||
extern struct namespace qeth_namespace;
|
||||
|
||||
#endif /* QETH_H */
|
||||
|
||||
@@ -94,7 +94,8 @@ void setting_list_map_values(struct setting_list *);
|
||||
void setting_list_mark_default_derived(struct setting_list *);
|
||||
int setting_list_count_set(struct setting_list *);
|
||||
void setting_list_remove_derived(struct setting_list *);
|
||||
char *setting_get_changes(struct setting_list *, struct setting_list *);
|
||||
char *setting_get_changes(struct setting_list *act, struct setting_list *pers,
|
||||
struct setting_list *ac);
|
||||
bool setting_match_value(struct setting *, const char *);
|
||||
|
||||
#endif /* SETTING_H */
|
||||
|
||||
@@ -67,17 +67,22 @@ typedef exit_code_t (*subtype_cb_t)(struct subtype *st, const char *id,
|
||||
*
|
||||
* @exists_active: Check if device exists in active configuration
|
||||
* @exists_persistent: Check if device exists in persistent configuration
|
||||
* @exists_autoconf: Check if device exists in autoconf configuration
|
||||
*
|
||||
* @add_active_ids: Add IDs of all devices existing in active configuration to
|
||||
* specified strlist
|
||||
* @add_persistent_ids: Add IDs of all devices existing in persistent
|
||||
* configuration to specified strlist
|
||||
* @add_autoconf_ids: Add IDs of all devices existing in autoconf
|
||||
* configuration to specified strlist
|
||||
*
|
||||
* @read_active: Read device configuration from active configuration
|
||||
* @read_persistent: Read device configuration from persistent configuration
|
||||
* @read_autoconf: Read device configuration from autoconf configuration
|
||||
*
|
||||
* @configure_active: Apply configuration to active configuration
|
||||
* @configure_persistent: Apply configuration to persistent configuration
|
||||
* @configure_autoconf: Apply configuration to autoconf configuration
|
||||
*
|
||||
* @check_pre_write: Optional: Determine if the given configuration is valid
|
||||
* for the specified device. If not, emit warning messages
|
||||
@@ -150,24 +155,33 @@ struct subtype {
|
||||
|
||||
bool (*exists_active)(struct subtype *, const char *);
|
||||
bool (*exists_persistent)(struct subtype *, const char *);
|
||||
bool (*exists_autoconf)(struct subtype *, const char *);
|
||||
|
||||
void (*add_active_ids)(struct subtype *, struct util_list *);
|
||||
void (*add_persistent_ids)(struct subtype *,
|
||||
struct util_list *);
|
||||
void (*add_autoconf_ids)(struct subtype *,
|
||||
struct util_list *);
|
||||
|
||||
exit_code_t (*read_active)(struct subtype *, struct device *,
|
||||
read_scope_t);
|
||||
exit_code_t (*read_persistent)(struct subtype *, struct device *,
|
||||
read_scope_t);
|
||||
exit_code_t (*read_autoconf)(struct subtype *, struct device *,
|
||||
read_scope_t);
|
||||
|
||||
exit_code_t (*configure_active)(struct subtype *, struct device *);
|
||||
exit_code_t (*configure_persistent)(struct subtype *,
|
||||
struct device *);
|
||||
exit_code_t (*configure_autoconf)(struct subtype *,
|
||||
struct device *);
|
||||
|
||||
exit_code_t (*deconfigure_active)(struct subtype *,
|
||||
struct device *);
|
||||
exit_code_t (*deconfigure_persistent)(struct subtype *,
|
||||
struct device *);
|
||||
exit_code_t (*deconfigure_autoconf)(struct subtype *,
|
||||
struct device *);
|
||||
|
||||
exit_code_t (*check_pre_configure)(struct subtype *,
|
||||
struct device *, int, config_t);
|
||||
@@ -217,23 +231,31 @@ void subtype_exit(struct subtype *);
|
||||
|
||||
bool subtype_device_exists_active(struct subtype *, const char *);
|
||||
bool subtype_device_exists_persistent(struct subtype *, const char *);
|
||||
bool subtype_device_exists_autoconf(struct subtype *st, const char *id);
|
||||
|
||||
void subtype_add_active_ids(struct subtype *, struct util_list *);
|
||||
void subtype_add_persistent_ids(struct subtype *, struct util_list *);
|
||||
void subtype_add_autoconf_ids(struct subtype *st, struct util_list *ids);
|
||||
|
||||
exit_code_t subtype_device_read_active(struct subtype *, struct device *,
|
||||
read_scope_t);
|
||||
exit_code_t subtype_device_read_persistent(struct subtype *, struct device *,
|
||||
read_scope_t);
|
||||
exit_code_t subtype_device_read_autoconf(struct subtype *st, struct device *dev,
|
||||
read_scope_t scope);
|
||||
|
||||
exit_code_t subtype_device_configure_active(struct subtype *, struct device *);
|
||||
exit_code_t subtype_device_configure_persistent(struct subtype *,
|
||||
struct device *);
|
||||
exit_code_t subtype_device_configure_autoconf(struct subtype *st,
|
||||
struct device *dev);
|
||||
|
||||
exit_code_t subtype_device_deconfigure_active(struct subtype *,
|
||||
struct device *);
|
||||
exit_code_t subtype_device_deconfigure_persistent(struct subtype *st,
|
||||
struct device *);
|
||||
exit_code_t subtype_device_deconfigure_autoconf(struct subtype *st,
|
||||
struct device *dev);
|
||||
|
||||
exit_code_t subtype_check_pre_configure(struct subtype *, struct device *, int,
|
||||
config_t);
|
||||
|
||||
@@ -13,7 +13,11 @@
|
||||
#include "lib/util_list.h"
|
||||
#include "exit_code.h"
|
||||
|
||||
struct attrib;
|
||||
struct setting_list;
|
||||
|
||||
extern int udev_need_settle;
|
||||
extern int udev_no_settle;
|
||||
|
||||
/* Single key-operator-value entry in a udev rule line.*/
|
||||
struct udev_entry_node {
|
||||
@@ -39,9 +43,14 @@ exit_code_t udev_read_file(const char *, struct udev_file **);
|
||||
void udev_free_file(struct udev_file *);
|
||||
void udev_file_print(struct udev_file *);
|
||||
|
||||
void udev_get_device_ids(const char *, struct util_list *);
|
||||
exit_code_t udev_remove_rule(const char *, const char *);
|
||||
void udev_get_device_ids(const char *type, struct util_list *list,
|
||||
bool autoconf);
|
||||
exit_code_t udev_remove_rule(const char *type, const char *id, bool autoconf);
|
||||
|
||||
void udev_settle(void);
|
||||
|
||||
void udev_add_internal_from_entry(struct setting_list *list,
|
||||
struct udev_entry_node *entry,
|
||||
struct attrib **attribs);
|
||||
|
||||
#endif /* UDEV_H */
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
|
||||
struct device;
|
||||
|
||||
bool udev_ccw_exists(const char *, const char *);
|
||||
exit_code_t udev_ccw_read_device(struct device *);
|
||||
exit_code_t udev_ccw_write_device(struct device *);
|
||||
exit_code_t udev_ccw_write_cio_ignore(const char *);
|
||||
bool udev_ccw_exists(const char *type, const char *id, bool autoconf);
|
||||
exit_code_t udev_ccw_read_device(struct device *dev, bool autoconf);
|
||||
exit_code_t udev_ccw_write_device(struct device *dev, bool autoconf);
|
||||
exit_code_t udev_ccw_write_cio_ignore(const char *id_list, bool autoconf);
|
||||
|
||||
#endif /* UDEV_CCW_H */
|
||||
|
||||
@@ -16,10 +16,12 @@
|
||||
struct device;
|
||||
struct util_list;
|
||||
|
||||
bool udev_ccwgroup_exists(const char *, const char *);
|
||||
exit_code_t udev_ccwgroup_read_device(struct device *);
|
||||
exit_code_t udev_ccwgroup_write_device(struct device *);
|
||||
void udev_ccwgroup_add_device_ids(const char *, struct util_list *);
|
||||
exit_code_t udev_ccwgroup_remove_rule(const char *, const char *);
|
||||
bool udev_ccwgroup_exists(const char *type, const char *id, bool autoconf);
|
||||
exit_code_t udev_ccwgroup_read_device(struct device *dev, bool autoconf);
|
||||
exit_code_t udev_ccwgroup_write_device(struct device *dev, bool autoconf);
|
||||
void udev_ccwgroup_add_device_ids(const char *type, struct util_list *list,
|
||||
bool autoconf);
|
||||
exit_code_t udev_ccwgroup_remove_rule(const char *type, const char *id,
|
||||
bool autoconf);
|
||||
|
||||
#endif /* UDEV_CCWGROUP_H */
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
|
||||
struct device;
|
||||
|
||||
void udev_zfcp_lun_add_device_ids(struct util_list *);
|
||||
bool udev_zfcp_lun_exists(const char *);
|
||||
exit_code_t udev_zfcp_lun_read_device(struct device *);
|
||||
exit_code_t udev_zfcp_lun_write_device(struct device *);
|
||||
exit_code_t udev_zfcp_lun_remove_rule(const char *);
|
||||
void udev_zfcp_lun_add_device_ids(struct util_list *list, bool autoconf);
|
||||
bool udev_zfcp_lun_exists(const char *id, bool autoconf);
|
||||
exit_code_t udev_zfcp_lun_read_device(struct device *dev, bool autoconf);
|
||||
exit_code_t udev_zfcp_lun_write_device(struct device *dev, bool autoconf);
|
||||
exit_code_t udev_zfcp_lun_remove_rule(const char *id, bool autoconf);
|
||||
|
||||
#endif /* UDEV_ZFCP_LUN_H */
|
||||
|
||||
22
zdev/initramfs/Makefile
Normal file
22
zdev/initramfs/Makefile
Normal file
@@ -0,0 +1,22 @@
|
||||
# Common definitions
|
||||
include ../../common.mak
|
||||
|
||||
INITRAMFSDIR := /usr/share/initramfs-tools
|
||||
HOOKDIR := $(INITRAMFSDIR)/hooks
|
||||
INITTOP := $(INITRAMFSDIR)/scripts/init-top
|
||||
|
||||
# HAVE_INITRAMFS
|
||||
#
|
||||
# This install time parameter determines whether the zdev initramfs support is
|
||||
# installed (HAVE_INITRAMFS=1) or not (default). When installed, the module
|
||||
# performs the following functions when mkinitramfs is run:
|
||||
#
|
||||
# - install a boot-time hook to apply firmware-provided configuration data
|
||||
# to the system
|
||||
#
|
||||
ifeq ($(HAVE_INITRAMFS),1)
|
||||
install:
|
||||
$(INSTALL) -m 755 -d $(DESTDIR)/$(HOOKDIR) $(DESTDIR)/$(INITTOP)
|
||||
$(INSTALL) -m 755 hooks/zdev $(DESTDIR)/$(HOOKDIR)
|
||||
$(INSTALL) -m 755 scripts/init-top/zdev $(DESTDIR)/$(INITTOP)
|
||||
endif
|
||||
56
zdev/initramfs/hooks/zdev
Normal file
56
zdev/initramfs/hooks/zdev
Normal file
@@ -0,0 +1,56 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright IBM Corp. 2016, 2017
|
||||
#
|
||||
# s390-tools is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the MIT license. See LICENSE for details.
|
||||
#
|
||||
# hooks/zdev
|
||||
# This hook script adds files required to apply firmware-provided I/O
|
||||
# configuration data during boot.
|
||||
#
|
||||
|
||||
# Needs to run after udev or resulting udev rules could be overwritten
|
||||
PREREQ="udev"
|
||||
|
||||
prereqs()
|
||||
{
|
||||
echo "$PREREQ"
|
||||
}
|
||||
|
||||
case $1 in
|
||||
prereqs)
|
||||
prereqs
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
. /usr/share/initramfs-tools/hook-functions
|
||||
|
||||
# Add modules for all device types supported by chzdev (required for
|
||||
# auto-configuration)
|
||||
zdev_modules="lcs qeth qeth_l2 qeth_l3 dasd_mod dasd_eckd_mod dasd_fba_mod dasd_diag_mod zfcp"
|
||||
|
||||
for x in $zdev_modules ; do
|
||||
manual_add_modules ${x}
|
||||
done
|
||||
|
||||
copy_exec /sbin/chzdev
|
||||
copy_exec /sbin/lszdev
|
||||
copy_exec /sbin/vmcp
|
||||
|
||||
_tempfile=$(mktemp --tmpdir initramfs-zdev.XXXXXX)
|
||||
|
||||
# Obtain early + root device configuration
|
||||
chzdev --export "$_tempfile" --persistent --by-path / \
|
||||
--by-attrib "zdev:early=1" --quiet --type 2>/dev/null
|
||||
|
||||
# Apply via --import to prevent other devices from being configured.
|
||||
# Rename the resulting cio-ignore rule to ensure that it does not override
|
||||
# the one copied by the initramfs udev hook to /lib/udev.
|
||||
chzdev --import "$_tempfile" --persistent \
|
||||
--base "/etc/udev/rules.d/41-cio-ignore.rules=$DESTDIR/etc/udev/rules.d/41-cio-ignore-root.rules" \
|
||||
--base "/etc=$DESTDIR/etc" --yes --quiet --no-root-update --force \
|
||||
>/dev/null
|
||||
|
||||
rm -f "$_tempfile"
|
||||
67
zdev/initramfs/scripts/init-top/zdev
Normal file
67
zdev/initramfs/scripts/init-top/zdev
Normal file
@@ -0,0 +1,67 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright IBM Corp. 2017
|
||||
#
|
||||
# s390-tools is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the MIT license. See LICENSE for details.
|
||||
#
|
||||
# scripts/init-top/zdev
|
||||
# Parse the kernel command line for rd.zdev kernel parameters. These
|
||||
# parameters are evaluated and used to configure z Systems specific devices.
|
||||
#
|
||||
# Format:
|
||||
# rd.zdev=no-auto
|
||||
#
|
||||
# where
|
||||
#
|
||||
# no-auto: Indicates that firmware-provided I/O configuration data
|
||||
# should not be applied.
|
||||
#
|
||||
|
||||
PREREQ="udev"
|
||||
|
||||
prereqs()
|
||||
{
|
||||
echo "$PREREQ"
|
||||
}
|
||||
|
||||
case $1 in
|
||||
prereqs)
|
||||
prereqs
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
. /scripts/functions
|
||||
|
||||
zdev_fw_file="/sys/firmware/sclp_sd/config/data"
|
||||
zdev_base_args="--force --yes --no-root-update --no-settle --auto-conf --quiet"
|
||||
|
||||
if [ -e "$zdev_fw_file" ] ; then
|
||||
zdev_auto=1
|
||||
else
|
||||
zdev_auto=0
|
||||
fi
|
||||
|
||||
for x in $(cat /proc/cmdline); do
|
||||
case ${x} in
|
||||
rd.zdev=*)
|
||||
zdev_arg=${x#*=}
|
||||
if [ "$zdev_arg" = "no-auto" ] ; then
|
||||
zdev_auto=0
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ $zdev_auto -eq 1 ] ; then
|
||||
log_begin_msg "Starting firmware auto-configuration"
|
||||
chzdev --import "$zdev_fw_file" $zdev_base_args
|
||||
log_end_msg
|
||||
|
||||
# Repeat cold-plug after creating udev rules
|
||||
udevadm control --reload
|
||||
udevadm trigger --type=subsystems --action=add
|
||||
udevadm trigger --action=add
|
||||
udevadm settle || true
|
||||
fi
|
||||
@@ -334,6 +334,35 @@ a specific attribute.
|
||||
.PP
|
||||
.
|
||||
.
|
||||
.SS "Special settings"
|
||||
The following special settings affect how devices are handled by chzdev:
|
||||
.PP
|
||||
.
|
||||
.BR zdev:early =0|1
|
||||
.RS 4
|
||||
Control in which stage of the boot process a device is activated:
|
||||
.TP 4
|
||||
.B 0
|
||||
Device is activated normally during boot (default).
|
||||
.PP
|
||||
.TP 4
|
||||
.B 1
|
||||
Device is activated early in the boot process, by the initial RAM-disk.
|
||||
.PP
|
||||
Specify a value of 1 for this attribute in any of the following situations:
|
||||
.TP 4
|
||||
\(bu
|
||||
To ensure that your settings override auto-configuration settings.
|
||||
.PP
|
||||
.TP 4
|
||||
\(bu
|
||||
To ensure that a device required to access the root file system is correctly
|
||||
enabled during boot. An example would be a networking device, or a device that
|
||||
is intended to extend a logical volume that provides the root file system.
|
||||
.PP
|
||||
.RE
|
||||
.
|
||||
.
|
||||
.SH ACTIONS
|
||||
You can use one of the action options listed below to specify the
|
||||
.B main tool action
|
||||
@@ -409,17 +438,27 @@ default value.
|
||||
.PP
|
||||
.
|
||||
.OD import "" "FILENAME" "|-"
|
||||
Import configuration data from a text file.
|
||||
Import configuration data from a text or machine-provided file.
|
||||
|
||||
Reads configuration data from FILENAME and applies it. If a single hyphen ("-")
|
||||
is specified as FILENAME data is read from the standard input stream. The
|
||||
input format of the data read must be the same format as produced by the
|
||||
chzdev \-\-export action.
|
||||
input format must be either in the format as produced by the chzdev \-\-export
|
||||
action, or in the format of a machine-provided I/O configuration data file.
|
||||
|
||||
.B Machine-provided data:
|
||||
Some machine models provide I/O configuration data which is made available
|
||||
by the Linux kernel via a sysfs interface. While this data is intended for
|
||||
automatic consumption during the boot phase, you can also apply it manually
|
||||
using the \-\-import action like in the following example
|
||||
|
||||
.B Example:
|
||||
.CL chzdev --import /sys/firmware/sclp_sd/config/data
|
||||
|
||||
.B Note:
|
||||
By default all configuration data that is read is also applied. To reduce the
|
||||
scope of imported configuration data, you can select specific devices, a device
|
||||
type, or define whether only data for the active or persistent configuration
|
||||
should be imported.
|
||||
type, or define whether only data for the active, persistent or
|
||||
auto-configuration should be imported.
|
||||
.PP
|
||||
.
|
||||
.OD list-attributes "l" ""
|
||||
@@ -462,6 +501,18 @@ on reboot, or when a device becomes unavailable, or when a device driver is
|
||||
unloaded.
|
||||
.PP
|
||||
.
|
||||
.OD auto-conf "" ""
|
||||
Apply changes to the auto-configuration only.
|
||||
|
||||
This option is used internally to apply machine-provided I/O configuration data
|
||||
to a Linux system.
|
||||
|
||||
.B Note:
|
||||
There is typically no need for users to specify this option directly.
|
||||
In particular, user-initiated changes to this configuration will be lost
|
||||
the next time that machine-provided data is obtained (i.e. during boot).
|
||||
.PP
|
||||
.
|
||||
.OD base "" "PATH" | "KEY" = "VALUE"
|
||||
Change file system paths used to access files.
|
||||
|
||||
@@ -518,6 +569,15 @@ device configuration persistent. Typically such steps include rebuilding the
|
||||
initial RAM disk, or modifying the kernel command line.
|
||||
.PP
|
||||
.
|
||||
.OD no-settle "" ""
|
||||
Do not wait for udev processing to complete.
|
||||
|
||||
Skips all calls to the udevadm tool that are intended to wait for udev to
|
||||
finish processing before continuing. There is typically no need to use this
|
||||
option unless chzdev is run in an environment where udev is not fully
|
||||
functional (such as in the early phase of an initial RAM disk).
|
||||
.PP
|
||||
.
|
||||
.OD persistent "p" ""
|
||||
Apply changes to persistent configuration only.
|
||||
|
||||
|
||||
@@ -69,12 +69,13 @@ With no further options specified, the output format defaults to list format.
|
||||
.
|
||||
.
|
||||
.SS "Configurations"
|
||||
There are two sources for configuration information: the active configuration
|
||||
of the currently running system, and the persistent configuration stored in
|
||||
configuration files.
|
||||
There are three sources for configuration information: the active configuration
|
||||
of the currently running system, the persistent configuration stored in
|
||||
configuration files, and the auto-configuration that is provided by some
|
||||
machine types to automatically enable I/O devices.
|
||||
.PP
|
||||
By default lszdev displays information from both the active and the persistent
|
||||
configuration.
|
||||
configuration, and, if available, from the auto-configuration.
|
||||
.PP
|
||||
.
|
||||
.
|
||||
@@ -319,6 +320,19 @@ Restricts output to information obtained from the active configuration, that
|
||||
is information from the running system.
|
||||
.PP
|
||||
.
|
||||
.OD auto-conf "" ""
|
||||
List information from the auto-configuration only.
|
||||
|
||||
Restricts output to information obtained from the auto-configuration.
|
||||
The auto-configuration is the collection of configuration data obtained
|
||||
automatically on some machine models during boot.
|
||||
|
||||
.B Note:
|
||||
This data is refreshed during each boot. Also configuration directives in
|
||||
the auto-configuration only take effect if there is no directive for the
|
||||
same device in the persistent configuration.
|
||||
.PP
|
||||
.
|
||||
.OD base "" "PATH" | "KEY" = "VALUE"
|
||||
Change file system paths used to access files.
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ ALL_CPPFLAGS += -I ../include -std=gnu99 -Wno-unused-parameter \
|
||||
chzdev_objects += attrib.o chzdev.o device.o devnode.o devtype.o exit_code.o \
|
||||
export.o hash.o inuse.o misc.o namespace.o opts.o path.o \
|
||||
root.o select.o setting.o subtype.o table.o table_attribs.o \
|
||||
table_types.o net.o
|
||||
table_types.o net.o firmware.o internal.o
|
||||
|
||||
# Devtype Helpers
|
||||
chzdev_objects += blkinfo.o ccw.o ccwgroup.o findmnt.o modprobe.o module.o \
|
||||
@@ -38,7 +38,7 @@ chzdev_objects += generic_ccw.o
|
||||
lszdev_objects += attrib.o lszdev.o device.o devnode.o devtype.o exit_code.o \
|
||||
export.o hash.o inuse.o misc.o namespace.o opts.o path.o \
|
||||
root.o select.o setting.o subtype.o table.o table_types.o \
|
||||
net.o
|
||||
net.o internal.o
|
||||
|
||||
# Devtype Helpers
|
||||
lszdev_objects += blkinfo.o ccw.o ccwgroup.o findmnt.o modprobe.o module.o \
|
||||
|
||||
100
zdev/src/ccw.c
100
zdev/src/ccw.c
@@ -73,6 +73,7 @@ struct attrib ccw_attr_cmb_enable = {
|
||||
" 1: Data collection is enabled (rewrite 1 to reset data)\n",
|
||||
.rewrite = 1,
|
||||
.defval = "0",
|
||||
.order_cmp = ccw_offline_only_order_cmp,
|
||||
.accept = ACCEPT_ARRAY(ACCEPT_RANGE(0, 1)),
|
||||
};
|
||||
|
||||
@@ -892,12 +893,13 @@ static exit_code_t collect_group_cb(struct subtype *st, const char *id,
|
||||
}
|
||||
|
||||
/* Set bits for all persistently configured CCW devices. */
|
||||
static char ***id_bitmap_collect(void)
|
||||
static char ***id_bitmap_collect(bool autoconf)
|
||||
{
|
||||
char ***id_bitmap;
|
||||
int i, j;
|
||||
struct devtype *dt;
|
||||
struct subtype *st;
|
||||
config_t config = autoconf ? config_autoconf : config_persistent;
|
||||
|
||||
id_bitmap = id_bitmap_new();
|
||||
|
||||
@@ -906,14 +908,14 @@ static char ***id_bitmap_collect(void)
|
||||
for (j = 0; (st = dt->subtypes[j]); j++) {
|
||||
/* Collect CCW device IDs. */
|
||||
if (st->namespace == &ccw_namespace) {
|
||||
subtype_for_each_id(st, config_persistent,
|
||||
subtype_for_each_id(st, config,
|
||||
collect_cb, id_bitmap);
|
||||
}
|
||||
/* Collect CCWGROUP device IDs. Since there may be
|
||||
* multiple namespaces, we need to make use of this
|
||||
* hack. */
|
||||
if (ccwgroup_compatible_namespace(st->namespace)) {
|
||||
subtype_for_each_id(st, config_persistent,
|
||||
subtype_for_each_id(st, config,
|
||||
collect_group_cb,
|
||||
id_bitmap);
|
||||
}
|
||||
@@ -952,7 +954,7 @@ static void range_add(struct util_list *list, struct ccw_devid *from,
|
||||
free(f_str);
|
||||
}
|
||||
|
||||
static struct util_list *cio_ignore_get_ranges(void)
|
||||
static struct util_list *cio_ignore_get_ranges(bool autoconf)
|
||||
{
|
||||
char ***id_bitmap;
|
||||
unsigned int cssid, ssid, devno;
|
||||
@@ -962,7 +964,7 @@ static struct util_list *cio_ignore_get_ranges(void)
|
||||
|
||||
ranges = strlist_new();
|
||||
|
||||
id_bitmap = id_bitmap_collect();
|
||||
id_bitmap = id_bitmap_collect(autoconf);
|
||||
for (cssid = 0; cssid < CSSID_MAX; cssid++) {
|
||||
if (!id_bitmap[cssid])
|
||||
continue;
|
||||
@@ -1003,24 +1005,34 @@ static struct util_list *cio_ignore_get_ranges(void)
|
||||
}
|
||||
|
||||
/* Persistently configure cio_ignore. */
|
||||
exit_code_t ccw_blacklist_persist(void)
|
||||
static exit_code_t _ccw_blacklist_persist(bool autoconf)
|
||||
{
|
||||
struct util_list *ranges;
|
||||
char *id_list;
|
||||
exit_code_t rc;
|
||||
|
||||
/* Get string to write to /proc/cio_ignore. */
|
||||
ranges = cio_ignore_get_ranges();
|
||||
ranges = cio_ignore_get_ranges(autoconf);
|
||||
id_list = strlist_flatten(ranges, ",");
|
||||
strlist_free(ranges);
|
||||
|
||||
/* Write udev rule to automatically write cio_ignore. */
|
||||
rc = udev_ccw_write_cio_ignore(id_list);
|
||||
rc = udev_ccw_write_cio_ignore(id_list, autoconf);
|
||||
free(id_list);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
exit_code_t ccw_blacklist_persist(void)
|
||||
{
|
||||
exit_code_t rc1, rc2;
|
||||
|
||||
rc1 = _ccw_blacklist_persist(false);
|
||||
rc2 = _ccw_blacklist_persist(true);
|
||||
|
||||
return rc1 ? rc1 : rc2;
|
||||
}
|
||||
|
||||
/*
|
||||
* CCW device ID namespace.
|
||||
*/
|
||||
@@ -1368,7 +1380,13 @@ static bool ccw_st_exists_active(struct subtype *st, const char *id)
|
||||
/* Check if a configuration exists for a CCW device with the specified @id. */
|
||||
static bool ccw_st_exists_persistent(struct subtype *st, const char *id)
|
||||
{
|
||||
return udev_ccw_exists(st->name, id);
|
||||
return udev_ccw_exists(st->name, id, false);
|
||||
}
|
||||
|
||||
/* Check if a configuration exists for a CCW device with the specified @id. */
|
||||
static bool ccw_st_exists_autoconf(struct subtype *st, const char *id)
|
||||
{
|
||||
return udev_ccw_exists(st->name, id, true);
|
||||
}
|
||||
|
||||
static bool get_ids_cb(const char *file, void *data)
|
||||
@@ -1404,7 +1422,14 @@ static void ccw_st_add_active_ids(struct subtype *st, struct util_list *ids)
|
||||
* to strlist @ids. */
|
||||
static void ccw_st_add_persistent_ids(struct subtype *st, struct util_list *ids)
|
||||
{
|
||||
udev_get_device_ids(st->name, ids);
|
||||
udev_get_device_ids(st->name, ids, false);
|
||||
}
|
||||
|
||||
/* Add the IDs of all CCW devices for which a autoconf configuration exists
|
||||
* to strlist @ids. */
|
||||
static void ccw_st_add_autoconf_ids(struct subtype *st, struct util_list *ids)
|
||||
{
|
||||
udev_get_device_ids(st->name, ids, true);
|
||||
}
|
||||
|
||||
/* Read the configuration of the CCW device with the specified @id from the
|
||||
@@ -1440,7 +1465,16 @@ static exit_code_t ccw_st_read_persistent(struct subtype *st,
|
||||
struct device *dev,
|
||||
read_scope_t scope)
|
||||
{
|
||||
return udev_ccw_read_device(dev);
|
||||
return udev_ccw_read_device(dev, false);
|
||||
}
|
||||
|
||||
/* Read the configuration of the CCW device with the specified @id from the
|
||||
* autoconf configuration and add the resulting data to @dev. */
|
||||
static exit_code_t ccw_st_read_autoconf(struct subtype *st,
|
||||
struct device *dev,
|
||||
read_scope_t scope)
|
||||
{
|
||||
return udev_ccw_read_device(dev, true);
|
||||
}
|
||||
|
||||
static int get_online(struct setting_list *list)
|
||||
@@ -1505,7 +1539,14 @@ static exit_code_t ccw_st_configure_active(struct subtype *st,
|
||||
static exit_code_t ccw_st_configure_persistent(struct subtype *st,
|
||||
struct device *dev)
|
||||
{
|
||||
return udev_ccw_write_device(dev);
|
||||
return udev_ccw_write_device(dev, false);
|
||||
}
|
||||
|
||||
/* Create a autoconf configuration for the specified device @dev. */
|
||||
static exit_code_t ccw_st_configure_autoconf(struct subtype *st,
|
||||
struct device *dev)
|
||||
{
|
||||
return udev_ccw_write_device(dev, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -1552,7 +1593,22 @@ static exit_code_t ccw_st_deconfigure_active(struct subtype *st,
|
||||
static exit_code_t ccw_st_deconfigure_persistent(struct subtype *st,
|
||||
struct device *dev)
|
||||
{
|
||||
return udev_remove_rule(st->name, dev->id);
|
||||
return udev_remove_rule(st->name, dev->id, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* ccw_st_deconfigure_autoconf - Deconfigure device in autoconf
|
||||
* configuration set
|
||||
* @st: Subtype of target device
|
||||
* @dev: Target device
|
||||
*
|
||||
* Deconfigure device @dev in the autoconf configuration set. Return %EXIT_OK
|
||||
* on success, an error code otherwise.
|
||||
*/
|
||||
static exit_code_t ccw_st_deconfigure_autoconf(struct subtype *st,
|
||||
struct device *dev)
|
||||
{
|
||||
return udev_remove_rule(st->name, dev->id, true);
|
||||
}
|
||||
|
||||
/* Perform basic sanity checks. */
|
||||
@@ -1589,6 +1645,8 @@ static void ccw_st_online_set(struct subtype *st, struct device *dev,
|
||||
setting_list_apply(dev->active.settings, a, name, value);
|
||||
if (SCOPE_PERSISTENT(config))
|
||||
setting_list_apply(dev->persistent.settings, a, name, value);
|
||||
if (SCOPE_AUTOCONF(config))
|
||||
setting_list_apply(dev->autoconf.settings, a, name, value);
|
||||
}
|
||||
|
||||
/* Determine the online state of the specified CCW device (0=offline, 1=online,
|
||||
@@ -1596,14 +1654,16 @@ static void ccw_st_online_set(struct subtype *st, struct device *dev,
|
||||
static int ccw_st_online_get(struct subtype *st, struct device *dev,
|
||||
config_t config)
|
||||
{
|
||||
int act_online = 1, pers_online = 1;
|
||||
int act_online = 1, pers_online = 1, auto_online = 1;
|
||||
|
||||
if (SCOPE_ACTIVE(config))
|
||||
act_online = get_online(dev->active.settings);
|
||||
if (SCOPE_PERSISTENT(config))
|
||||
pers_online = get_online(dev->persistent.settings);
|
||||
if (SCOPE_AUTOCONF(config))
|
||||
auto_online = get_online(dev->autoconf.settings);
|
||||
|
||||
return MIN(act_online, pers_online);
|
||||
return MIN(MIN(act_online, pers_online), auto_online);
|
||||
}
|
||||
|
||||
/* Determine if the online state of the specified CCW device was specified */
|
||||
@@ -1622,6 +1682,11 @@ static bool ccw_st_online_specified(struct subtype *st, struct device *dev,
|
||||
if (s && s->specified)
|
||||
return true;
|
||||
}
|
||||
if (SCOPE_AUTOCONF(config) && dev->autoconf.settings) {
|
||||
s = setting_list_find(dev->autoconf.settings, "online");
|
||||
if (s && s->specified)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1769,18 +1834,23 @@ struct subtype ccw_subtype = {
|
||||
|
||||
.exists_active = &ccw_st_exists_active,
|
||||
.exists_persistent = &ccw_st_exists_persistent,
|
||||
.exists_autoconf = &ccw_st_exists_autoconf,
|
||||
|
||||
.add_active_ids = &ccw_st_add_active_ids,
|
||||
.add_persistent_ids = &ccw_st_add_persistent_ids,
|
||||
.add_autoconf_ids = &ccw_st_add_autoconf_ids,
|
||||
|
||||
.read_active = &ccw_st_read_active,
|
||||
.read_persistent = &ccw_st_read_persistent,
|
||||
.read_autoconf = &ccw_st_read_autoconf,
|
||||
|
||||
.configure_active = &ccw_st_configure_active,
|
||||
.configure_persistent = &ccw_st_configure_persistent,
|
||||
.configure_autoconf = &ccw_st_configure_autoconf,
|
||||
|
||||
.deconfigure_active = &ccw_st_deconfigure_active,
|
||||
.deconfigure_persistent = &ccw_st_deconfigure_persistent,
|
||||
.deconfigure_autoconf = &ccw_st_deconfigure_autoconf,
|
||||
|
||||
.check_pre_configure = &ccw_st_check_pre_configure,
|
||||
|
||||
|
||||
@@ -426,6 +426,8 @@ static void ccwgroup_st_online_set(struct subtype *st, struct device *dev,
|
||||
}
|
||||
if (SCOPE_PERSISTENT(config))
|
||||
setting_list_apply(dev->persistent.settings, a, name, value);
|
||||
if (SCOPE_AUTOCONF(config))
|
||||
setting_list_apply(dev->autoconf.settings, a, name, value);
|
||||
}
|
||||
|
||||
static int get_online(struct setting_list *list)
|
||||
@@ -446,18 +448,20 @@ static int get_online(struct setting_list *list)
|
||||
}
|
||||
|
||||
/* Return -1 if online state is not configured, 0 for offline and 1 for online.
|
||||
* If multiple configurations are specified, return the minimum of both. */
|
||||
* If multiple configurations are specified, return the minimum of all. */
|
||||
static int ccwgroup_st_online_get(struct subtype *st, struct device *dev,
|
||||
config_t config)
|
||||
{
|
||||
int act_online = 1, pers_online = 1;
|
||||
int act_online = 1, pers_online = 1, auto_online = 1;
|
||||
|
||||
if (SCOPE_ACTIVE(config))
|
||||
act_online = get_online(dev->active.settings);
|
||||
if (SCOPE_PERSISTENT(config))
|
||||
pers_online = get_online(dev->persistent.settings);
|
||||
if (SCOPE_AUTOCONF(config))
|
||||
auto_online = get_online(dev->autoconf.settings);
|
||||
|
||||
return MIN(act_online, pers_online);
|
||||
return MIN(MIN(act_online, pers_online), auto_online);
|
||||
}
|
||||
|
||||
/* Determine if the online state of the specified device was modified. */
|
||||
@@ -476,6 +480,11 @@ static bool ccwgroup_st_online_specified(struct subtype *st,
|
||||
if (s && s->specified)
|
||||
return true;
|
||||
}
|
||||
if (SCOPE_AUTOCONF(config) && dev->autoconf.settings) {
|
||||
s = setting_list_find(dev->autoconf.settings, "online");
|
||||
if (s && s->specified)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -682,7 +691,18 @@ static exit_code_t ccwgroup_st_read_persistent(struct subtype *st,
|
||||
|
||||
expand_id(data->ccwgroupdrv, dev);
|
||||
|
||||
return udev_ccwgroup_read_device(dev);
|
||||
return udev_ccwgroup_read_device(dev, false);
|
||||
}
|
||||
|
||||
static exit_code_t ccwgroup_st_read_autoconf(struct subtype *st,
|
||||
struct device *dev,
|
||||
read_scope_t scope)
|
||||
{
|
||||
struct ccwgroup_subtype_data *data = st->data;
|
||||
|
||||
expand_id(data->ccwgroupdrv, dev);
|
||||
|
||||
return udev_ccwgroup_read_device(dev, true);
|
||||
}
|
||||
|
||||
static exit_code_t ccwgroup_st_configure_active(struct subtype *st,
|
||||
@@ -693,8 +713,9 @@ static exit_code_t ccwgroup_st_configure_active(struct subtype *st,
|
||||
return device_write_active_settings(dev);
|
||||
}
|
||||
|
||||
static exit_code_t ccwgroup_st_configure_persistent(struct subtype *st,
|
||||
struct device *dev)
|
||||
static exit_code_t _ccwgroup_st_configure_persistent(struct subtype *st,
|
||||
struct device *dev,
|
||||
bool autoconf)
|
||||
{
|
||||
struct ccwgroup_subtype_data *data = st->data;
|
||||
struct ccwgroup_devid *devid = dev->devid;
|
||||
@@ -703,9 +724,22 @@ static exit_code_t ccwgroup_st_configure_persistent(struct subtype *st,
|
||||
delayed_err("Incomplete device ID specified\n");
|
||||
return EXIT_INCOMPLETE_ID;
|
||||
}
|
||||
return udev_ccwgroup_write_device(dev);
|
||||
return udev_ccwgroup_write_device(dev, autoconf);
|
||||
}
|
||||
|
||||
static exit_code_t ccwgroup_st_configure_persistent(struct subtype *st,
|
||||
struct device *dev)
|
||||
{
|
||||
return _ccwgroup_st_configure_persistent(st, dev, false);
|
||||
}
|
||||
|
||||
static exit_code_t ccwgroup_st_configure_autoconf(struct subtype *st,
|
||||
struct device *dev)
|
||||
{
|
||||
return _ccwgroup_st_configure_persistent(st, dev, true);
|
||||
}
|
||||
|
||||
|
||||
static char *ccwgroup_st_get_active_attrib_path(struct subtype *,
|
||||
struct device *, const char *);
|
||||
|
||||
@@ -733,7 +767,13 @@ static exit_code_t ccwgroup_st_deconfigure_active(struct subtype *st,
|
||||
static exit_code_t ccwgroup_st_deconfigure_persistent(struct subtype *st,
|
||||
struct device *dev)
|
||||
{
|
||||
return udev_ccwgroup_remove_rule(st->name, dev->id);
|
||||
return udev_ccwgroup_remove_rule(st->name, dev->id, false);
|
||||
}
|
||||
|
||||
static exit_code_t ccwgroup_st_deconfigure_autoconf(struct subtype *st,
|
||||
struct device *dev)
|
||||
{
|
||||
return udev_ccwgroup_remove_rule(st->name, dev->id, true);
|
||||
}
|
||||
|
||||
/* Check if a CCWGROUP device with the specified ID exists. */
|
||||
@@ -774,7 +814,12 @@ static bool ccwgroup_st_exists_active(struct subtype *st, const char *id)
|
||||
|
||||
static bool ccwgroup_st_exists_persistent(struct subtype *st, const char *id)
|
||||
{
|
||||
return udev_ccwgroup_exists(st->name, id);
|
||||
return udev_ccwgroup_exists(st->name, id, false);
|
||||
}
|
||||
|
||||
static bool ccwgroup_st_exists_autoconf(struct subtype *st, const char *id)
|
||||
{
|
||||
return udev_ccwgroup_exists(st->name, id, true);
|
||||
}
|
||||
|
||||
int ccwgroup_qsort_cmp(const void *a_ptr, const void *b_ptr)
|
||||
@@ -796,7 +841,13 @@ static void ccwgroup_st_add_active_ids(struct subtype *st,
|
||||
static void ccwgroup_st_add_persistent_ids(struct subtype *st,
|
||||
struct util_list *ids)
|
||||
{
|
||||
udev_ccwgroup_add_device_ids(st->name, ids);
|
||||
udev_ccwgroup_add_device_ids(st->name, ids, false);
|
||||
}
|
||||
|
||||
static void ccwgroup_st_add_autoconf_ids(struct subtype *st,
|
||||
struct util_list *ids)
|
||||
{
|
||||
udev_ccwgroup_add_device_ids(st->name, ids, true);
|
||||
}
|
||||
|
||||
/* Check if CCW device ID @b is part of CCW group device ID @a. */
|
||||
@@ -1185,18 +1236,23 @@ struct subtype ccwgroup_subtype = {
|
||||
|
||||
.exists_active = &ccwgroup_st_exists_active,
|
||||
.exists_persistent = &ccwgroup_st_exists_persistent,
|
||||
.exists_autoconf = &ccwgroup_st_exists_autoconf,
|
||||
|
||||
.add_active_ids = &ccwgroup_st_add_active_ids,
|
||||
.add_persistent_ids = &ccwgroup_st_add_persistent_ids,
|
||||
.add_autoconf_ids = &ccwgroup_st_add_autoconf_ids,
|
||||
|
||||
.read_active = &ccwgroup_st_read_active,
|
||||
.read_persistent = &ccwgroup_st_read_persistent,
|
||||
.read_autoconf = &ccwgroup_st_read_autoconf,
|
||||
|
||||
.configure_active = &ccwgroup_st_configure_active,
|
||||
.configure_persistent = &ccwgroup_st_configure_persistent,
|
||||
.configure_autoconf = &ccwgroup_st_configure_autoconf,
|
||||
|
||||
.deconfigure_active = &ccwgroup_st_deconfigure_active,
|
||||
.deconfigure_persistent = &ccwgroup_st_deconfigure_persistent,
|
||||
.deconfigure_autoconf = &ccwgroup_st_deconfigure_autoconf,
|
||||
|
||||
.online_set = &ccwgroup_st_online_set,
|
||||
.online_get = &ccwgroup_st_online_get,
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "devnode.h"
|
||||
#include "devtype.h"
|
||||
#include "export.h"
|
||||
#include "firmware.h"
|
||||
#include "inuse.h"
|
||||
#include "misc.h"
|
||||
#include "module.h"
|
||||
@@ -85,6 +86,7 @@ struct options {
|
||||
config_t config;
|
||||
unsigned int active:1;
|
||||
unsigned int persistent:1;
|
||||
unsigned int auto_conf:1;
|
||||
struct util_list *remove; /* List of struct strlist_node */
|
||||
unsigned int remove_all:1;
|
||||
unsigned int force:1;
|
||||
@@ -94,6 +96,7 @@ struct options {
|
||||
struct util_list *base; /* List of struct strlist_node */
|
||||
unsigned int verbose:1;
|
||||
unsigned int quiet:1;
|
||||
unsigned int no_settle:1;
|
||||
};
|
||||
|
||||
/* Makefile converts chzdev_usage.txt into C file which we include here. */
|
||||
@@ -135,6 +138,8 @@ enum {
|
||||
OPT_VERSION = 'v',
|
||||
OPT_VERBOSE = 'V',
|
||||
OPT_QUIET = 'q',
|
||||
OPT_NO_SETTLE = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||
OPT_AUTO_CONF = (OPT_ANONYMOUS_BASE+__COUNTER__),
|
||||
};
|
||||
|
||||
static struct opts_conflict conflict_list[] = {
|
||||
@@ -169,11 +174,13 @@ static struct opts_conflict conflict_list[] = {
|
||||
OPTS_CONFLICT(OPT_APPLY,
|
||||
OPT_DECONFIGURE, OPT_LIST_ATTRIBS, OPT_HELP_ATTRIBS,
|
||||
OPT_LIST_TYPES, OPT_EXPORT, OPT_IMPORT, OPT_REMOVE,
|
||||
OPT_REMOVE_ALL, OPT_ACTIVE, OPT_PERSISTENT, 0),
|
||||
OPT_REMOVE_ALL, OPT_ACTIVE, 0),
|
||||
OPTS_CONFLICT(OPT_ONLINE,
|
||||
OPT_OFFLINE),
|
||||
OPTS_CONFLICT(OPT_QUIET,
|
||||
OPT_VERBOSE),
|
||||
OPTS_CONFLICT(OPT_AUTO_CONF,
|
||||
OPT_TYPE, OPT_LIST_ATTRIBS, OPT_LIST_TYPES),
|
||||
OPTS_CONFLICT(0, 0),
|
||||
};
|
||||
|
||||
@@ -207,6 +214,7 @@ static const struct option opt_list[] = {
|
||||
/* Options. */
|
||||
{ "active", no_argument, NULL, OPT_ACTIVE },
|
||||
{ "persistent", no_argument, NULL, OPT_PERSISTENT },
|
||||
{ "auto-conf", no_argument, NULL, OPT_AUTO_CONF },
|
||||
{ "remove", required_argument, NULL, OPT_REMOVE },
|
||||
{ "remove-all", no_argument, NULL, OPT_REMOVE_ALL },
|
||||
{ "force", no_argument, NULL, OPT_FORCE },
|
||||
@@ -216,6 +224,7 @@ static const struct option opt_list[] = {
|
||||
{ "base", required_argument, NULL, OPT_BASE },
|
||||
{ "verbose", no_argument, NULL, OPT_VERBOSE },
|
||||
{ "quiet", no_argument, NULL, OPT_QUIET },
|
||||
{ "no-settle", no_argument, NULL, OPT_NO_SETTLE },
|
||||
{ NULL, no_argument, NULL, 0 },
|
||||
};
|
||||
|
||||
@@ -879,6 +888,11 @@ static exit_code_t parse_options(struct options *opts, int argc, char *argv[])
|
||||
opts->persistent = 1;
|
||||
break;
|
||||
|
||||
case OPT_AUTO_CONF:
|
||||
/* --auto-conf */
|
||||
opts->auto_conf = 1;
|
||||
break;
|
||||
|
||||
case OPT_REMOVE:
|
||||
/* --remove ATTRIB */
|
||||
strlist_add(opts->remove, "%s", optarg);
|
||||
@@ -936,6 +950,11 @@ static exit_code_t parse_options(struct options *opts, int argc, char *argv[])
|
||||
opts->quiet = 1;
|
||||
break;
|
||||
|
||||
case OPT_NO_SETTLE:
|
||||
/* --no-settle */
|
||||
opts->no_settle = 1;
|
||||
break;
|
||||
|
||||
case ':':
|
||||
/* Missing option argument. */
|
||||
syntax("Option '%s' requires an argument\n",
|
||||
@@ -968,7 +987,13 @@ static exit_code_t parse_options(struct options *opts, int argc, char *argv[])
|
||||
goto out;
|
||||
|
||||
/* Determine configuration set. */
|
||||
opts->config = get_config(opts->active, opts->persistent);
|
||||
if (!opts->active && !opts->persistent && !opts->auto_conf) {
|
||||
/* Default configuration targets are active + persistent */
|
||||
opts->config = config_active | config_persistent;
|
||||
} else {
|
||||
opts->config = get_config(opts->active, opts->persistent,
|
||||
opts->auto_conf);
|
||||
}
|
||||
|
||||
/* Handle positional parameters. */
|
||||
rc = parse_positional(opts, argc, argv, optind);
|
||||
@@ -1040,13 +1065,15 @@ static void remove_all_settings(struct setting_list *settings, int active)
|
||||
/* Perform --remove-all operation for specified config on device. */
|
||||
static exit_code_t device_remove_all(struct device *dev, config_t config)
|
||||
{
|
||||
int active, persistent;
|
||||
int active, persistent, autoconf;
|
||||
|
||||
active = SCOPE_ACTIVE(config) ?
|
||||
count_removable(dev->active.settings, 1) : 0;
|
||||
persistent = SCOPE_PERSISTENT(config) ?
|
||||
count_removable(dev->persistent.settings, 0) : 0;
|
||||
if (active == 0 && persistent == 0) {
|
||||
autoconf = SCOPE_AUTOCONF(config) ?
|
||||
count_removable(dev->autoconf.settings, 0) : 0;
|
||||
if (active == 0 && persistent == 0 && autoconf == 0) {
|
||||
delayed_err("No removable settings found\n");
|
||||
return EXIT_SETTING_NOT_FOUND;
|
||||
}
|
||||
@@ -1054,6 +1081,8 @@ static exit_code_t device_remove_all(struct device *dev, config_t config)
|
||||
remove_all_settings(dev->active.settings, 1);
|
||||
if (persistent)
|
||||
remove_all_settings(dev->persistent.settings, 0);
|
||||
if (autoconf)
|
||||
remove_all_settings(dev->autoconf.settings, 0);
|
||||
|
||||
return EXIT_OK;
|
||||
}
|
||||
@@ -1123,6 +1152,13 @@ static exit_code_t device_remove_settings(struct device *dev,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (SCOPE_AUTOCONF(config)) {
|
||||
rc = remove_settings(dev->autoconf.settings, names, found,
|
||||
notfound, 0);
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!util_list_is_empty(notfound)) {
|
||||
flat = strlist_flatten(notfound, " ");
|
||||
delayed_err("Setting not found: %s\n", flat);
|
||||
@@ -1190,7 +1226,8 @@ static void print_dev_config_info(struct device *dev, config_t config)
|
||||
|
||||
changes = setting_get_changes(
|
||||
SCOPE_ACTIVE(config) ? dev->active.settings : NULL,
|
||||
SCOPE_PERSISTENT(config) ? dev->persistent.settings : NULL);
|
||||
SCOPE_PERSISTENT(config) ? dev->persistent.settings : NULL,
|
||||
SCOPE_AUTOCONF(config) ? dev->autoconf.settings : NULL);
|
||||
if (changes)
|
||||
info(" Changes: %s\n", changes);
|
||||
free(changes);
|
||||
@@ -1248,6 +1285,12 @@ static exit_code_t cfg_mod_existence(struct device *dev, config_t config)
|
||||
dev->persistent.modified = 1;
|
||||
}
|
||||
|
||||
/* Create autoconf config if necessary. */
|
||||
if (SCOPE_AUTOCONF(config) && !dev->autoconf.exists) {
|
||||
dev->autoconf.exists = 1;
|
||||
dev->autoconf.modified = 1;
|
||||
}
|
||||
|
||||
return EXIT_OK;
|
||||
}
|
||||
|
||||
@@ -1287,11 +1330,14 @@ online:
|
||||
/* Make sure there's an online attribute. */
|
||||
ensure_online(dev, config_active);
|
||||
ensure_online(dev, config_persistent);
|
||||
ensure_online(dev, config_autoconf);
|
||||
|
||||
mand:
|
||||
/* Ensure default values for mandatory attributes. */
|
||||
setting_list_apply_defaults(dev->persistent.settings,
|
||||
dev->subtype->dev_attribs, true);
|
||||
setting_list_apply_defaults(dev->autoconf.settings,
|
||||
dev->subtype->dev_attribs, true);
|
||||
|
||||
return EXIT_OK;
|
||||
}
|
||||
@@ -1324,10 +1370,11 @@ static exit_code_t cfg_write(struct device *dev, int prereq, config_t config,
|
||||
struct subtype *st = dev->subtype;
|
||||
exit_code_t rc = EXIT_OK;
|
||||
|
||||
if (!device_needs_writing(dev, config))
|
||||
if (!device_needs_writing(dev, config) && !force)
|
||||
goto out;
|
||||
|
||||
if (check_active && config == config_persistent &&
|
||||
if (check_active && !SCOPE_ACTIVE(config) &&
|
||||
(SCOPE_PERSISTENT(config) || SCOPE_AUTOCONF(config)) &&
|
||||
(!dev->active.exists && !dev->active.definable)) {
|
||||
rc = handle_nonexistent(dev);
|
||||
if (rc)
|
||||
@@ -1368,7 +1415,7 @@ static exit_code_t cfg_configure(struct subtype *st, const char *id,
|
||||
if (proc_ptr)
|
||||
*proc_ptr = 0;
|
||||
|
||||
/* Read current device data. Note that we read data from both
|
||||
/* Read current device data. Note that we read data from all
|
||||
* configurations to enable QETH autodetection and subtype
|
||||
* detection (e.g. dasd -> dasd_fba).*/
|
||||
dev = NULL;
|
||||
@@ -1389,23 +1436,17 @@ static exit_code_t cfg_configure(struct subtype *st, const char *id,
|
||||
|
||||
/* Exit here if we're only trying and device cannot be configured. */
|
||||
if (try && !(dev->active.exists || dev->active.definable ||
|
||||
dev->persistent.exists)) {
|
||||
dev->persistent.exists || dev->autoconf.exists)) {
|
||||
return EXIT_DEVICE_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (config == config_persistent) {
|
||||
/* Abort if a modification action is triggered for a
|
||||
* non-existing persistent device. */
|
||||
if (!dev->persistent.exists &&
|
||||
(!util_list_is_empty(opts->remove) || opts->remove_all))
|
||||
return EXIT_DEVICE_NOT_FOUND;
|
||||
/* Create device if needed by action. */
|
||||
if (opts->enable || !util_list_is_empty(opts->settings)) {
|
||||
rc = cfg_mod_existence(dev, config);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Apply changes to device existence. */
|
||||
rc = cfg_mod_existence(dev, config);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Apply changes to device settings. */
|
||||
rc = cfg_mod_settings(dev, opts, prereq);
|
||||
if (rc)
|
||||
@@ -1417,10 +1458,12 @@ static exit_code_t cfg_configure(struct subtype *st, const char *id,
|
||||
|
||||
/* Apply persistent configuration to active configuration. */
|
||||
static exit_code_t cfg_apply(struct subtype *st, const char *id, int prereq,
|
||||
struct device **dev_ptr, int *proc_ptr)
|
||||
struct device **dev_ptr, int *proc_ptr,
|
||||
bool autoconf)
|
||||
{
|
||||
exit_code_t rc;
|
||||
struct device *dev;
|
||||
struct device_state *state;
|
||||
|
||||
/* Reset processed flag. */
|
||||
if (proc_ptr)
|
||||
@@ -1443,8 +1486,9 @@ static exit_code_t cfg_apply(struct subtype *st, const char *id, int prereq,
|
||||
*proc_ptr = 1;
|
||||
dev->processed = 1;
|
||||
|
||||
state = autoconf ? &dev->autoconf : &dev->persistent;
|
||||
/* Exit here if there is no persistent configuration. */
|
||||
if (!dev->persistent.exists)
|
||||
if (!state->exists)
|
||||
return EXIT_NO_DATA;
|
||||
|
||||
/* Apply changes to device existence. */
|
||||
@@ -1453,8 +1497,7 @@ static exit_code_t cfg_apply(struct subtype *st, const char *id, int prereq,
|
||||
return rc;
|
||||
|
||||
/* Copy persistent settings to active configuration. */
|
||||
rc = device_apply_settings(dev, config_active,
|
||||
&dev->persistent.settings->list);
|
||||
rc = device_apply_settings(dev, config_active, &state->settings->list);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
@@ -1468,7 +1511,8 @@ static exit_code_t cfg_import(struct subtype *st, const char *id,
|
||||
struct device **dev_ptr, int *proc_ptr)
|
||||
{
|
||||
exit_code_t rc;
|
||||
struct setting_list *active = NULL, *persistent = NULL;
|
||||
struct setting_list *active = NULL, *persistent = NULL,
|
||||
*autoconf = NULL;
|
||||
struct device *dev;
|
||||
|
||||
/* Reset processed flag. */
|
||||
@@ -1486,6 +1530,7 @@ static exit_code_t cfg_import(struct subtype *st, const char *id,
|
||||
return EXIT_OK;
|
||||
active = setting_list_copy(dev->active.settings);
|
||||
persistent = setting_list_copy(dev->persistent.settings);
|
||||
autoconf = setting_list_copy(dev->autoconf.settings);
|
||||
} else if (!prereq) {
|
||||
/* Should not happen. */
|
||||
return EXIT_OK;
|
||||
@@ -1515,14 +1560,20 @@ static exit_code_t cfg_import(struct subtype *st, const char *id,
|
||||
&persistent->list);
|
||||
if (rc)
|
||||
goto out;
|
||||
rc = device_apply_settings(dev, config_autoconf,
|
||||
&autoconf->list);
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
ensure_online(dev, config_active);
|
||||
ensure_online(dev, config_persistent);
|
||||
ensure_online(dev, config_autoconf);
|
||||
|
||||
/* Write resulting device data. */
|
||||
rc = cfg_write(dev, prereq, config, 0);
|
||||
|
||||
out:
|
||||
setting_list_free(autoconf);
|
||||
setting_list_free(persistent);
|
||||
setting_list_free(active);
|
||||
|
||||
@@ -1600,11 +1651,13 @@ static exit_code_t print_config_result(struct selected_dev_node *sel,
|
||||
if (opts->deconfigure) {
|
||||
op = "deconfigure";
|
||||
verb = "deconfigured";
|
||||
if (dev)
|
||||
if (dev) {
|
||||
already = !dev->active.modified &&
|
||||
!dev->persistent.modified;
|
||||
else if (rc == EXIT_DEVICE_NOT_FOUND &&
|
||||
config == config_persistent) {
|
||||
!dev->persistent.modified &&
|
||||
!dev->autoconf.modified;
|
||||
} else if (rc == EXIT_DEVICE_NOT_FOUND &&
|
||||
(!SCOPE_ACTIVE(config) && (SCOPE_PERSISTENT(config) ||
|
||||
SCOPE_AUTOCONF(config)))) {
|
||||
rc = EXIT_OK;
|
||||
already = 1;
|
||||
}
|
||||
@@ -1615,6 +1668,10 @@ static exit_code_t print_config_result(struct selected_dev_node *sel,
|
||||
already = device_needs_writing(dev, config) ? 0 : 1;
|
||||
}
|
||||
|
||||
/* Re-do actions if run with --force */
|
||||
if (force)
|
||||
already = 0;
|
||||
|
||||
if (dev) {
|
||||
devname = dev->subtype->devname;
|
||||
devid = dev->id;
|
||||
@@ -1672,9 +1729,10 @@ static exit_code_t cfg_prereqs(struct subtype *st, const char *id,
|
||||
prereqs = selected_dev_list_new();
|
||||
subtype_add_prereqs(st, id, prereqs);
|
||||
util_list_iterate(prereqs, sel) {
|
||||
if (opts->apply)
|
||||
rc = cfg_apply(sel->st, sel->id, 1, &dev, &proc);
|
||||
else if (opts->import) {
|
||||
if (opts->apply) {
|
||||
rc = cfg_apply(sel->st, sel->id, 1, &dev, &proc,
|
||||
opts->auto_conf);
|
||||
} else if (opts->import) {
|
||||
rc = cfg_import(sel->st, sel->id, config, 1, &dev,
|
||||
&proc);
|
||||
} else {
|
||||
@@ -1747,9 +1805,11 @@ static exit_code_t configure_devices(struct options *opts, int specified,
|
||||
struct namespace *ns;
|
||||
const char *param;
|
||||
struct device *dev;
|
||||
config_t config = opts->config;
|
||||
|
||||
/* Determine list of selected devices. */
|
||||
if (opts->config == config_persistent ||
|
||||
if ((!SCOPE_ACTIVE(config) &&
|
||||
(SCOPE_PERSISTENT(config) || SCOPE_AUTOCONF(config))) ||
|
||||
(opts->select->subtype && opts->select->subtype->support_definable))
|
||||
existing = 0;
|
||||
else
|
||||
@@ -1795,9 +1855,10 @@ static exit_code_t configure_devices(struct options *opts, int specified,
|
||||
goto next;
|
||||
|
||||
/* Configure actual target device. */
|
||||
if (opts->apply)
|
||||
rc = cfg_apply(sel->st, sel->id, 0, &dev, &proc);
|
||||
else {
|
||||
if (opts->apply) {
|
||||
rc = cfg_apply(sel->st, sel->id, 0, &dev, &proc,
|
||||
opts->auto_conf);
|
||||
} else {
|
||||
rc = cfg_configure(sel->st, sel->id, opts, 0,
|
||||
0, &dev, &proc);
|
||||
}
|
||||
@@ -1893,7 +1954,7 @@ static exit_code_t deconfigure_one_device(struct subtype *st, const char *id,
|
||||
dev->processed = 1;
|
||||
|
||||
if (try && !(dev->active.exists || dev->active.definable ||
|
||||
dev->persistent.exists)) {
|
||||
dev->persistent.exists || dev->autoconf.exists)) {
|
||||
/* Attempt to deconfigure this device will fail. */
|
||||
return EXIT_DEVICE_NOT_FOUND;
|
||||
}
|
||||
@@ -1903,7 +1964,8 @@ static exit_code_t deconfigure_one_device(struct subtype *st, const char *id,
|
||||
* dev. */
|
||||
if (SCOPE_ACTIVE(config) &&
|
||||
!(dev->active.exists || dev->active.definable)) {
|
||||
if (!SCOPE_PERSISTENT(config) || !dev->persistent.exists)
|
||||
if (!((SCOPE_PERSISTENT(config) && dev->persistent.exists) ||
|
||||
(SCOPE_AUTOCONF(config) && dev->autoconf.exists)))
|
||||
return EXIT_DEVICE_NOT_FOUND;
|
||||
}
|
||||
|
||||
@@ -1927,7 +1989,12 @@ static exit_code_t deconfigure_one_device(struct subtype *st, const char *id,
|
||||
dev->persistent.deconfigured = 1;
|
||||
dev->persistent.modified = 1;
|
||||
}
|
||||
if (!dev->active.modified && !dev->persistent.modified)
|
||||
if (SCOPE_AUTOCONF(config) && dev->autoconf.exists) {
|
||||
dev->autoconf.deconfigured = 1;
|
||||
dev->autoconf.modified = 1;
|
||||
}
|
||||
if (!dev->active.modified && !dev->persistent.modified &&
|
||||
!dev->autoconf.modified)
|
||||
return EXIT_OK;
|
||||
|
||||
/* Pre-write check. */
|
||||
@@ -2071,7 +2138,8 @@ static void print_type_config_info(struct devtype *dt, const char *title,
|
||||
|
||||
changes = setting_get_changes(
|
||||
SCOPE_ACTIVE(config) ? dt->active_settings : NULL,
|
||||
SCOPE_PERSISTENT(config) ? dt->persistent_settings : NULL);
|
||||
SCOPE_PERSISTENT(config) ? dt->persistent_settings : NULL,
|
||||
NULL);
|
||||
if (changes)
|
||||
info(" %s: %s\n", title, changes);
|
||||
free(changes);
|
||||
@@ -2485,6 +2553,8 @@ static void action_note(const char *msg, config_t config)
|
||||
info("%s the active configuration only\n", msg);
|
||||
else if (config == config_persistent)
|
||||
info("%s the persistent configuration only\n", msg);
|
||||
else if (config == config_autoconf)
|
||||
info("%s the auto-configuration only\n", msg);
|
||||
}
|
||||
|
||||
/* Export configuration of selected devices and/or device type to file. */
|
||||
@@ -2500,9 +2570,9 @@ static exit_code_t do_export(struct options *opts)
|
||||
/* Open output stream. */
|
||||
if (strcmp(opts->export, "-") == 0) {
|
||||
fd = stdout;
|
||||
info("Exporting configuration data to standard output\n");
|
||||
info("Exporting data to standard output\n");
|
||||
} else {
|
||||
info("Exporting configuration data to %s\n", opts->export);
|
||||
info("Exporting data to %s\n", opts->export);
|
||||
if (!util_path_exists(opts->export)) {
|
||||
rc = path_create(opts->export);
|
||||
if (rc)
|
||||
@@ -2606,7 +2676,7 @@ static exit_code_t import_device(struct device *dev, struct options *opts)
|
||||
struct subtype *st = dev->subtype;
|
||||
exit_code_t rc;
|
||||
config_t config;
|
||||
int proc = 0, active, persistent;
|
||||
int proc = 0, active, persistent, autoconf;
|
||||
|
||||
if (SCOPE_ACTIVE(opts->config))
|
||||
active = (dev->active.exists || dev->active.definable);
|
||||
@@ -2616,7 +2686,16 @@ static exit_code_t import_device(struct device *dev, struct options *opts)
|
||||
persistent = dev->persistent.exists;
|
||||
else
|
||||
persistent = 0;
|
||||
config = get_config(active, persistent);
|
||||
if (SCOPE_AUTOCONF(opts->config))
|
||||
autoconf = dev->autoconf.exists;
|
||||
else
|
||||
autoconf = 0;
|
||||
|
||||
if (!active && !persistent && !autoconf) {
|
||||
/* Nothing to import */
|
||||
return EXIT_OK;
|
||||
}
|
||||
config = get_config(active, persistent, autoconf);
|
||||
|
||||
/* First check for prerequisite devices that need to be configured. */
|
||||
rc = cfg_prereqs(st, dev->id, opts, config, 0);
|
||||
@@ -2643,17 +2722,9 @@ static bool import_device_selected(struct device *dev, struct options *opts)
|
||||
if (!select_opts_dev_specified(select))
|
||||
return false;
|
||||
|
||||
/* --active */
|
||||
if (opts->config == config_active) {
|
||||
if (!dev->active.exists && !dev->active.definable)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* --persistent */
|
||||
if (opts->config == config_persistent) {
|
||||
if (!dev->persistent.exists)
|
||||
return false;
|
||||
}
|
||||
/* Target configuration */
|
||||
if ((device_get_config(dev) & opts->config) == 0)
|
||||
return false;
|
||||
|
||||
/* Devtype */
|
||||
if (select->devtype && dt != select->devtype)
|
||||
@@ -2735,6 +2806,7 @@ static exit_code_t do_import(struct options *opts)
|
||||
exit_code_t drc = EXIT_OK;
|
||||
const char *filename;
|
||||
int found;
|
||||
bool is_firmware;
|
||||
|
||||
/* Open input stream. */
|
||||
if (strcmp(opts->import, "-") == 0) {
|
||||
@@ -2744,16 +2816,23 @@ static exit_code_t do_import(struct options *opts)
|
||||
fd = fopen(opts->import, "r");
|
||||
filename = opts->import;
|
||||
}
|
||||
info("Importing configuration data from %s\n", filename);
|
||||
|
||||
if (!fd) {
|
||||
error("Could not open file %s: %s\n", opts->import,
|
||||
strerror(errno));
|
||||
return EXIT_RUNTIME_ERROR;
|
||||
}
|
||||
|
||||
is_firmware = firmware_detect(fd);
|
||||
info("Importing data from %s%s\n", filename,
|
||||
is_firmware ? " (firmware format)" : "");
|
||||
|
||||
/* Read data. */
|
||||
objects = ptrlist_new();
|
||||
rc = export_read(fd, filename, objects);
|
||||
if (is_firmware)
|
||||
rc = firmware_read(fd, filename, -1, opts->config, objects);
|
||||
else
|
||||
rc = export_read(fd, filename, objects);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
@@ -2766,8 +2845,8 @@ static exit_code_t do_import(struct options *opts)
|
||||
"selection\n", filename);
|
||||
rc = EXIT_EMPTY_SELECTION;
|
||||
} else {
|
||||
error("%s: No settings found to import\n", filename);
|
||||
rc = EXIT_NO_DATA;
|
||||
info("%s: No settings found to import\n", filename);
|
||||
rc = EXIT_OK;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
@@ -2895,6 +2974,7 @@ int main(int argc, char *argv[])
|
||||
force = opts.force;
|
||||
yes = opts.yes;
|
||||
dryrun = opts.dryrun;
|
||||
udev_no_settle = opts.no_settle;
|
||||
path_set_base(opts.base);
|
||||
|
||||
if (dryrun)
|
||||
@@ -2945,8 +3025,8 @@ int main(int argc, char *argv[])
|
||||
|
||||
if ((pers_mod_devs || pers_mod_devtypes) && !opts.no_root_check &&
|
||||
!dryrun) {
|
||||
/* If the root device/device type has been modified, additional
|
||||
* work might be necessary. */
|
||||
/* If the root device/device type or early devices have been
|
||||
* modified, additional work might be necessary. */
|
||||
rc = root_check();
|
||||
if (rc && !drc)
|
||||
drc = rc;
|
||||
|
||||
@@ -54,5 +54,7 @@ OPTIONS
|
||||
--no-root-update Skip root device update
|
||||
--dry-run Display changes without applying
|
||||
--base PATH Use PATH as base for accessing files
|
||||
--no-settle Do not wait for udev to settle
|
||||
--auto-conf Apply changes to auto-configuration only
|
||||
-V, --verbose Print additional run-time information
|
||||
-q, --quiet Print only minimal run-time information
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "ctc_auto.h"
|
||||
#include "device.h"
|
||||
#include "devtype.h"
|
||||
#include "internal.h"
|
||||
#include "misc.h"
|
||||
#include "namespace.h"
|
||||
#include "path.h"
|
||||
@@ -425,6 +426,7 @@ static struct subtype ctc_subtype = {
|
||||
&ccw_attr_online,
|
||||
&ctc_attr_buffer,
|
||||
&ctc_attr_protocol,
|
||||
&internal_attr_early,
|
||||
),
|
||||
.unknown_dev_attribs = 1,
|
||||
.support_definable = 1,
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "dasd.h"
|
||||
#include "device.h"
|
||||
#include "devtype.h"
|
||||
#include "internal.h"
|
||||
#include "misc.h"
|
||||
#include "modprobe.h"
|
||||
#include "module.h"
|
||||
@@ -316,34 +317,34 @@ static struct attrib dasd_attr_safe_offline = {
|
||||
* DASD subtype methods.
|
||||
*/
|
||||
|
||||
static bool _check_use_diag(struct setting_list *list)
|
||||
{
|
||||
struct setting *u;
|
||||
|
||||
u = setting_list_find(list, dasd_attr_use_diag.name);
|
||||
if (u && u->modified) {
|
||||
if (u->value && atoi(u->value) == 1) {
|
||||
delayed_warn("Cannot set 'use_diag=1' on non-z/VM system\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Check if use_diag setting can be correctly applied. */
|
||||
static exit_code_t check_use_diag(struct device *dev, config_t config)
|
||||
{
|
||||
struct setting *u;
|
||||
int zvm = is_zvm();
|
||||
if (is_zvm())
|
||||
return EXIT_OK;
|
||||
|
||||
if (SCOPE_ACTIVE(config)) {
|
||||
u = setting_list_find(dev->active.settings,
|
||||
dasd_attr_use_diag.name);
|
||||
if (u && u->modified) {
|
||||
if (u->value && atoi(u->value) == 1 && !zvm) {
|
||||
delayed_warn("Cannot set 'use_diag=1' on "
|
||||
"non-z/VM system\n");
|
||||
return EXIT_INVALID_CONFIG;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (SCOPE_PERSISTENT(config)) {
|
||||
u = setting_list_find(dev->persistent.settings,
|
||||
dasd_attr_use_diag.name);
|
||||
if (u && u->modified) {
|
||||
if (u->value && atoi(u->value) == 1 && !zvm) {
|
||||
delayed_warn("Cannot set 'use_diag=1' on "
|
||||
"non-z/VM system\n");
|
||||
return EXIT_INVALID_CONFIG;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (SCOPE_ACTIVE(config) && !_check_use_diag(dev->active.settings))
|
||||
return EXIT_INVALID_CONFIG;
|
||||
if (SCOPE_PERSISTENT(config) &&
|
||||
!_check_use_diag(dev->persistent.settings))
|
||||
return EXIT_INVALID_CONFIG;
|
||||
if (SCOPE_AUTOCONF(config) &&
|
||||
!_check_use_diag(dev->autoconf.settings))
|
||||
return EXIT_INVALID_CONFIG;
|
||||
|
||||
return EXIT_OK;
|
||||
}
|
||||
@@ -376,6 +377,8 @@ static void dasd_st_add_modules(struct subtype *st, struct device *dev,
|
||||
dasd_attr_use_diag.name, &changed, &aset);
|
||||
setting_list_get_bool_state(dev->persistent.settings,
|
||||
dasd_attr_use_diag.name, &changed, &pset);
|
||||
setting_list_get_bool_state(dev->autoconf.settings,
|
||||
dasd_attr_use_diag.name, &changed, &pset);
|
||||
|
||||
if (aset || pset)
|
||||
strlist_add_unique(modules, DASD_DIAG_MOD_NAME);
|
||||
@@ -589,7 +592,7 @@ static struct ccw_subtype_data dasd_eckd_data = {
|
||||
.mod = "dasd_eckd_mod",
|
||||
};
|
||||
|
||||
static struct subtype dasd_subtype_eckd = {
|
||||
struct subtype dasd_subtype_eckd = {
|
||||
.super = &ccw_subtype,
|
||||
.devtype = &dasd_devtype,
|
||||
.name = "dasd-eckd",
|
||||
@@ -614,6 +617,7 @@ static struct subtype dasd_subtype_eckd = {
|
||||
&dasd_attr_reservation_policy,
|
||||
&dasd_attr_last_known_reservation_state,
|
||||
&dasd_attr_safe_offline,
|
||||
&internal_attr_early,
|
||||
),
|
||||
.unknown_dev_attribs = 1,
|
||||
|
||||
@@ -626,7 +630,7 @@ static struct ccw_subtype_data dasd_fba_data = {
|
||||
.mod = "dasd_fba_mod",
|
||||
};
|
||||
|
||||
static struct subtype dasd_subtype_fba = {
|
||||
struct subtype dasd_subtype_fba = {
|
||||
.super = &ccw_subtype,
|
||||
.devtype = &dasd_devtype,
|
||||
.name = "dasd-fba",
|
||||
@@ -649,6 +653,7 @@ static struct subtype dasd_subtype_fba = {
|
||||
&dasd_attr_reservation_policy,
|
||||
&dasd_attr_last_known_reservation_state,
|
||||
&dasd_attr_safe_offline,
|
||||
&internal_attr_early,
|
||||
),
|
||||
.unknown_dev_attribs = 1,
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "attrib.h"
|
||||
#include "device.h"
|
||||
#include "devtype.h"
|
||||
#include "internal.h"
|
||||
#include "misc.h"
|
||||
#include "namespace.h"
|
||||
#include "setting.h"
|
||||
@@ -40,6 +41,7 @@ struct device *device_new(struct subtype *st, const char *id)
|
||||
|
||||
dev->active.settings = setting_list_new();
|
||||
dev->persistent.settings = setting_list_new();
|
||||
dev->autoconf.settings = setting_list_new();
|
||||
|
||||
return dev;
|
||||
}
|
||||
@@ -53,6 +55,7 @@ void device_free(struct device *dev)
|
||||
free(dev->devid);
|
||||
setting_list_free(dev->active.settings);
|
||||
setting_list_free(dev->persistent.settings);
|
||||
setting_list_free(dev->autoconf.settings);
|
||||
free(dev);
|
||||
}
|
||||
|
||||
@@ -83,6 +86,15 @@ void device_print(struct device *dev, int level)
|
||||
setting_list_print(dev->persistent.settings, level + 8);
|
||||
else
|
||||
printf("%*s<none>\n", level + 8, "");
|
||||
|
||||
printf("%*sautoconf:\n", level + 4, "");
|
||||
printf("%*sexists=%d mod=%d deconf=%d\n",
|
||||
level + 8, "", dev->autoconf.exists, dev->autoconf.modified,
|
||||
dev->autoconf.deconfigured);
|
||||
if (dev->autoconf.settings)
|
||||
setting_list_print(dev->autoconf.settings, level + 8);
|
||||
else
|
||||
printf("%*s<none>\n", level + 8, "");
|
||||
}
|
||||
|
||||
static const void *device_hash_get_id(void *dev_ptr)
|
||||
@@ -182,6 +194,10 @@ bool device_needs_writing(struct device *dev, config_t config)
|
||||
(dev->persistent.modified || dev->persistent.deconfigured ||
|
||||
setting_list_modified(dev->persistent.settings)))
|
||||
return true;
|
||||
if (SCOPE_AUTOCONF(config) &&
|
||||
(dev->autoconf.modified || dev->autoconf.deconfigured ||
|
||||
setting_list_modified(dev->autoconf.settings)))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -204,6 +220,11 @@ static exit_code_t apply_setting(struct device *dev, config_t config,
|
||||
/* Check for activeonly. */
|
||||
if (!force && SCOPE_PERSISTENT(config) && a->activeonly)
|
||||
goto err_activeonly_forceable;
|
||||
if (!force && SCOPE_AUTOCONF(config) && a->activeonly)
|
||||
goto err_activeonly_forceable;
|
||||
/* Check for internal. */
|
||||
if (config == config_active && a->internal)
|
||||
goto err_int_noactive;
|
||||
/* Check for multiple values. */
|
||||
if (!force && !a->multi && strlist_find(processed, key))
|
||||
goto err_multi_forceable;
|
||||
@@ -213,6 +234,9 @@ static exit_code_t apply_setting(struct device *dev, config_t config,
|
||||
goto err_unknown;
|
||||
if (!force)
|
||||
goto err_unknown_forceable;
|
||||
/* Check for internal. */
|
||||
if (config == config_active && internal_by_name(key))
|
||||
goto err_int_noactive;
|
||||
}
|
||||
|
||||
strlist_add(processed, "%s", key);
|
||||
@@ -231,8 +255,15 @@ static exit_code_t apply_setting(struct device *dev, config_t config,
|
||||
a, key, value);
|
||||
}
|
||||
|
||||
/* Apply to autoconf config. */
|
||||
if (SCOPE_AUTOCONF(config)) {
|
||||
setting_list_apply_specified(dev->autoconf.settings,
|
||||
a, key, value);
|
||||
}
|
||||
|
||||
/* Additional warning when trying to persist read-only setting. */
|
||||
if (config == config_persistent) {
|
||||
if (!SCOPE_ACTIVE(config) && (SCOPE_PERSISTENT(config) ||
|
||||
SCOPE_AUTOCONF(config))) {
|
||||
s = setting_list_find(dev->active.settings, key);
|
||||
if (s && s->readonly)
|
||||
warn_readonly = true;
|
||||
@@ -270,6 +301,11 @@ err_activeonly_forceable:
|
||||
delayed_forceable("Attribute '%s' should only be changed in the active "
|
||||
"config\n", a->name);
|
||||
return EXIT_INVALID_SETTING;
|
||||
|
||||
err_int_noactive:
|
||||
delayed_err("Internal attribute '%s' cannot be set in the active config\n",
|
||||
key);
|
||||
return EXIT_INVALID_SETTING;
|
||||
}
|
||||
|
||||
/* Apply device settings from strlist to device. */
|
||||
@@ -341,6 +377,8 @@ void device_reset(struct device *dev, config_t config)
|
||||
reset_device_state(&dev->active);
|
||||
if (SCOPE_PERSISTENT(config))
|
||||
reset_device_state(&dev->persistent);
|
||||
if (SCOPE_AUTOCONF(config))
|
||||
reset_device_state(&dev->autoconf);
|
||||
dev->processed = 0;
|
||||
}
|
||||
|
||||
@@ -516,6 +554,9 @@ exit_code_t device_write_active_settings(struct device *dev)
|
||||
s = p->ptr;
|
||||
if (!s->modified || s->removed)
|
||||
continue;
|
||||
if ((s->attrib && s->attrib->internal) ||
|
||||
internal_by_name(s->name))
|
||||
continue;
|
||||
|
||||
path = subtype_get_active_attrib_path(st, dev, s->name);
|
||||
if (!path) {
|
||||
@@ -567,6 +608,44 @@ exit_code_t device_check_settings(struct device *dev, config_t config,
|
||||
err))
|
||||
return EXIT_INVALID_CONFIG;
|
||||
}
|
||||
if (SCOPE_AUTOCONF(config)) {
|
||||
if (!setting_list_check_conflict(dev->autoconf.settings,
|
||||
config_autoconf,
|
||||
err))
|
||||
return EXIT_INVALID_CONFIG;
|
||||
}
|
||||
|
||||
return EXIT_OK;
|
||||
}
|
||||
|
||||
struct setting_list *device_get_setting_list(struct device *dev,
|
||||
config_t config)
|
||||
{
|
||||
struct setting_list *settings = NULL;
|
||||
|
||||
if (config == config_active)
|
||||
settings = dev->active.settings;
|
||||
else if (config == config_persistent)
|
||||
settings = dev->persistent.settings;
|
||||
else if (config == config_autoconf)
|
||||
settings = dev->autoconf.settings;
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
/* Return configuration set in which device exists. */
|
||||
config_t device_get_config(struct device *dev)
|
||||
{
|
||||
config_t config = 0;
|
||||
|
||||
if (dev->active.exists || dev->active.definable)
|
||||
config |= config_active;
|
||||
|
||||
if (dev->persistent.exists)
|
||||
config |= config_persistent;
|
||||
|
||||
if (dev->autoconf.exists)
|
||||
config |= config_autoconf;
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ static bool is_exportable(struct setting *s, config_t config)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (SCOPE_PERSISTENT(config)) {
|
||||
if (SCOPE_PERSISTENT(config) || SCOPE_AUTOCONF(config)) {
|
||||
if (setting_is_set(s))
|
||||
return true;
|
||||
}
|
||||
@@ -148,10 +148,9 @@ static int count_exportable(struct device *dev, config_t config)
|
||||
struct setting *s;
|
||||
int count;
|
||||
|
||||
if (config == config_active)
|
||||
list = dev->active.settings;
|
||||
else
|
||||
list = dev->persistent.settings;
|
||||
list = device_get_setting_list(dev, config);
|
||||
if (!list)
|
||||
return 0;
|
||||
count = 0;
|
||||
|
||||
util_list_iterate(&list->list, s) {
|
||||
@@ -169,12 +168,26 @@ exit_code_t export_write_device(FILE *fd, struct device *dev, config_t config,
|
||||
exit_code_t rc;
|
||||
struct setting_list *settings;
|
||||
|
||||
if (config == config_all) {
|
||||
rc = export_write_device(fd, dev, config_active, first_ptr);
|
||||
if (rc)
|
||||
return rc;
|
||||
return export_write_device(fd, dev, config_persistent,
|
||||
first_ptr);
|
||||
if (!SCOPE_SINGLE(config)) {
|
||||
if (SCOPE_ACTIVE(config)) {
|
||||
rc = export_write_device(fd, dev, config_active,
|
||||
first_ptr);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
if (SCOPE_PERSISTENT(config)) {
|
||||
rc = export_write_device(fd, dev, config_persistent,
|
||||
first_ptr);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
if (SCOPE_AUTOCONF(config)) {
|
||||
rc = export_write_device(fd, dev, config_autoconf,
|
||||
first_ptr);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
return EXIT_OK;
|
||||
}
|
||||
|
||||
if (config == config_active) {
|
||||
@@ -185,10 +198,14 @@ exit_code_t export_write_device(FILE *fd, struct device *dev, config_t config,
|
||||
!dev->subtype->support_definable)
|
||||
return EXIT_OK;
|
||||
settings = dev->active.settings;
|
||||
} else {
|
||||
} else if (config == config_persistent) {
|
||||
if (!dev->persistent.exists)
|
||||
return EXIT_OK;
|
||||
settings = dev->persistent.settings;
|
||||
} else {
|
||||
if (!dev->autoconf.exists)
|
||||
return EXIT_OK;
|
||||
settings = dev->autoconf.settings;
|
||||
}
|
||||
|
||||
write_header(fd, config, dev->subtype->name, dev->id, first_ptr);
|
||||
@@ -204,12 +221,21 @@ exit_code_t export_write_devtype(FILE *fd, struct devtype *dt, config_t config,
|
||||
exit_code_t rc;
|
||||
struct setting_list *settings;
|
||||
|
||||
if (config == config_all) {
|
||||
rc = export_write_devtype(fd, dt, config_active, first_ptr);
|
||||
if (rc)
|
||||
return rc;
|
||||
return export_write_devtype(fd, dt, config_persistent,
|
||||
first_ptr);
|
||||
if (!SCOPE_SINGLE(config)) {
|
||||
if (SCOPE_ACTIVE(config)) {
|
||||
rc = export_write_devtype(fd, dt, config_active,
|
||||
first_ptr);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
if (SCOPE_PERSISTENT(config)) {
|
||||
rc = export_write_devtype(fd, dt, config_persistent,
|
||||
first_ptr);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
/* Scope autoconf not supported for devtype */
|
||||
return EXIT_OK;
|
||||
}
|
||||
|
||||
if (config == config_active)
|
||||
@@ -282,19 +308,6 @@ static bool parse_setting(const char *line, char **key_ptr, char **val_ptr)
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct setting_list *dev_get_setting_list(struct device *dev,
|
||||
config_t config)
|
||||
{
|
||||
struct setting_list *settings = NULL;
|
||||
|
||||
if (config == config_active)
|
||||
settings = dev->active.settings;
|
||||
else
|
||||
settings = dev->persistent.settings;
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
static struct setting_list *dt_get_setting_list(struct devtype *dt,
|
||||
config_t config)
|
||||
{
|
||||
@@ -392,6 +405,10 @@ static exit_code_t handle_header(const char *filename, int lineno,
|
||||
setting_list_clear(dev->persistent.settings);
|
||||
dev->persistent.exists = 1;
|
||||
}
|
||||
if (SCOPE_AUTOCONF(hdr->config)) {
|
||||
setting_list_clear(dev->autoconf.settings);
|
||||
dev->autoconf.exists = 1;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -410,13 +427,26 @@ static exit_code_t handle_setting(const char *filename, int lineno,
|
||||
struct attrib **attribs, *a;
|
||||
struct setting_list *list;
|
||||
|
||||
if (config == config_all) {
|
||||
rc = handle_setting(filename, lineno, key, value, dt, dev,
|
||||
config_active);
|
||||
if (rc)
|
||||
return rc;
|
||||
return handle_setting(filename, lineno, key, value, dt, dev,
|
||||
config_persistent);
|
||||
if (!SCOPE_SINGLE(config)) {
|
||||
if (SCOPE_ACTIVE(config)) {
|
||||
rc = handle_setting(filename, lineno, key, value, dt,
|
||||
dev, config_active);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
if (SCOPE_PERSISTENT(config)) {
|
||||
rc = handle_setting(filename, lineno, key, value, dt,
|
||||
dev, config_persistent);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
if (SCOPE_AUTOCONF(config)) {
|
||||
rc = handle_setting(filename, lineno, key, value, dt,
|
||||
dev, config_autoconf);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
return EXIT_OK;
|
||||
}
|
||||
|
||||
if (dt) {
|
||||
@@ -426,7 +456,7 @@ static exit_code_t handle_setting(const char *filename, int lineno,
|
||||
} else if (dev) {
|
||||
/* We're inside a device section. */
|
||||
attribs = dev->subtype->dev_attribs;
|
||||
list = dev_get_setting_list(dev, config);
|
||||
list = device_get_setting_list(dev, config);
|
||||
} else
|
||||
return EXIT_OK;
|
||||
|
||||
@@ -444,7 +474,7 @@ static exit_code_t handle_setting(const char *filename, int lineno,
|
||||
return EXIT_OK;
|
||||
}
|
||||
|
||||
static struct export_object *object_new(export_t type, void *ptr)
|
||||
struct export_object *object_new(export_t type, void *ptr)
|
||||
{
|
||||
struct export_object *obj;
|
||||
|
||||
@@ -465,7 +495,8 @@ static bool empty_device(struct device *dev)
|
||||
if (dev->subtype->support_definable)
|
||||
return false;
|
||||
if (util_list_is_empty(&dev->active.settings->list) &&
|
||||
util_list_is_empty(&dev->persistent.settings->list))
|
||||
util_list_is_empty(&dev->persistent.settings->list) &&
|
||||
util_list_is_empty(&dev->autoconf.settings->list))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
682
zdev/src/firmware.c
Normal file
682
zdev/src/firmware.c
Normal file
@@ -0,0 +1,682 @@
|
||||
/*
|
||||
* zdev - Modify and display the persistent configuration of devices
|
||||
*
|
||||
* Copyright IBM Corp. 2017
|
||||
*
|
||||
* 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 <err.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "attrib.h"
|
||||
#include "ccw.h"
|
||||
#include "ccwgroup.h"
|
||||
#include "dasd.h"
|
||||
#include "device.h"
|
||||
#include "export.h"
|
||||
#include "firmware.h"
|
||||
#include "misc.h"
|
||||
#include "qeth.h"
|
||||
#include "subtype.h"
|
||||
#include "zfcp_host.h"
|
||||
#include "zfcp_lun.h"
|
||||
|
||||
/* In-memory firmware file representation. */
|
||||
struct fw_file {
|
||||
const char *name;
|
||||
char *buffer;
|
||||
size_t size;
|
||||
char *last_access;
|
||||
size_t last_size;
|
||||
};
|
||||
|
||||
/* Record access to fields of the buffered file for use in warning messages. */
|
||||
#define fwacc(f, x) ((f)->last_access = (char *) &(x), \
|
||||
(f)->last_size = sizeof(x), x)
|
||||
|
||||
/*
|
||||
* Firmware file format definitions.
|
||||
*/
|
||||
|
||||
/* Firmware file header. */
|
||||
struct fw_filehdr {
|
||||
uint32_t magic;
|
||||
uint16_t ver;
|
||||
uint16_t hdr_len;
|
||||
uint32_t file_len;
|
||||
uint32_t seq;
|
||||
uint32_t zeroes;
|
||||
uint16_t de_count;
|
||||
char unused[10];
|
||||
} __packed;
|
||||
|
||||
#define FW_HDR_MAGIC 0x7a646576 /* ASCII "zdev" */
|
||||
#define FW_HDR_VER_Z14 0x0000
|
||||
|
||||
/* I/O device ID. */
|
||||
struct fw_iodevid {
|
||||
uint8_t cssid;
|
||||
uint8_t ssid;
|
||||
uint16_t devno;
|
||||
} __packed;
|
||||
|
||||
#define FW_IODEVID_FLAG_MCSS 0x01
|
||||
|
||||
/* Device setting. */
|
||||
struct fw_setting {
|
||||
uint16_t len;
|
||||
uint8_t key_type;
|
||||
uint8_t key_len;
|
||||
uint8_t val_type;
|
||||
uint8_t val_len;
|
||||
char data[];
|
||||
} __packed;
|
||||
|
||||
#define FW_SETTING_KEYTYPE_ASCII 0x00
|
||||
#define FW_SETTING_VALTYPE_ASCII 0x00
|
||||
#define FW_SETTING_VALTYPE_UINT 0x01
|
||||
|
||||
/* Device settings list. */
|
||||
struct fw_setlist {
|
||||
uint16_t len;
|
||||
char data[];
|
||||
} __packed;
|
||||
|
||||
/* Device entry header. */
|
||||
struct fw_dehdr {
|
||||
uint16_t type;
|
||||
uint16_t len;
|
||||
uint32_t seq;
|
||||
} __packed;
|
||||
|
||||
#define FW_DE_HDR_TYPE_DASD 0x0001
|
||||
#define FW_DE_HDR_TYPE_ZFCP_HOST 0x0002
|
||||
#define FW_DE_HDR_TYPE_ZFCP_LUN 0x0003
|
||||
#define FW_DE_HDR_TYPE_QETH 0x0004
|
||||
|
||||
/* DASD device entry. */
|
||||
struct fw_dasd {
|
||||
struct fw_dehdr hdr;
|
||||
uint8_t id_flags;
|
||||
struct fw_iodevid id;
|
||||
char settings[];
|
||||
} __packed;
|
||||
|
||||
/* zFCP host device entry. */
|
||||
struct fw_zfcp_host {
|
||||
struct fw_dehdr hdr;
|
||||
uint8_t id_flags;
|
||||
struct fw_iodevid id;
|
||||
char settings[];
|
||||
} __packed;
|
||||
|
||||
/* zFCP LUN device entry. */
|
||||
struct fw_zfcp_lun {
|
||||
struct fw_dehdr hdr;
|
||||
uint8_t id_flags;
|
||||
struct fw_iodevid id;
|
||||
uint64_t wwpn;
|
||||
uint64_t fcp_lun;
|
||||
char settings[];
|
||||
} __packed;
|
||||
|
||||
/* QETH device entry. */
|
||||
struct fw_qeth {
|
||||
struct fw_dehdr hdr;
|
||||
uint8_t id_flags;
|
||||
struct fw_iodevid read_id;
|
||||
struct fw_iodevid write_id;
|
||||
struct fw_iodevid data_id;
|
||||
char settings[];
|
||||
} __packed;
|
||||
|
||||
/* Emit a warning that refers to a position in a firmware file. */
|
||||
static void fwwarn(struct fw_file *f, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
off_t start = (off_t) (f->last_access - f->buffer),
|
||||
end = start + f->last_size - 1;
|
||||
|
||||
fprintf(stderr, "%s: ", f->name);
|
||||
if (start == end)
|
||||
fprintf(stderr, "Byte 0x%zx: ", start);
|
||||
else
|
||||
fprintf(stderr, "Bytes 0x%zx-0x%zx: ", start, end);
|
||||
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
/* Basic file format header sanity check. */
|
||||
static bool check_header(struct fw_file *f, struct fw_filehdr *hdr)
|
||||
{
|
||||
if (fwacc(f, hdr->magic) != FW_HDR_MAGIC)
|
||||
fwwarn(f, "Invalid file magic (0x%08x)", hdr->magic);
|
||||
else if (fwacc(f, hdr->ver) != FW_HDR_VER_Z14)
|
||||
fwwarn(f, "Unsupported file version (0x%04x)", hdr->ver);
|
||||
else
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#define READ_RETRY 3
|
||||
|
||||
/* Read a firmware configuration file. */
|
||||
static exit_code_t read_fw(struct fw_file *file, FILE *fd, const char *filename)
|
||||
{
|
||||
struct fw_file f = { NULL };
|
||||
struct fw_filehdr *hdr;
|
||||
char *buffer, *buffer2;
|
||||
size_t size, size2;
|
||||
int retry;
|
||||
exit_code_t rc = EXIT_OK;
|
||||
|
||||
for (retry = 0; retry < READ_RETRY; retry++) {
|
||||
/* Read complete file once */
|
||||
rc = misc_read_fd(fd, (void **) &buffer, &size);
|
||||
if (rc) {
|
||||
warn("%s: Could not read file", filename);
|
||||
return rc;
|
||||
}
|
||||
if (!buffer) {
|
||||
/* Empty file - skip silently as this is the default
|
||||
* on machines without firmware support. */
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Re-read complete file to detect in-flight modifications. */
|
||||
if (fseek(fd, 0, SEEK_SET) == -1) {
|
||||
/* Could be a pipe, socket, or FIFO - accept v1. */
|
||||
break;
|
||||
}
|
||||
rc = misc_read_fd(fd, (void **) &buffer2, &size2);
|
||||
if (rc || !buffer2) {
|
||||
/* Could not get second version - accept v1. */
|
||||
break;
|
||||
}
|
||||
|
||||
if (size == size2 && memcmp(buffer, buffer2, size) == 0) {
|
||||
/* No change */
|
||||
free(buffer2);
|
||||
break;
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
free(buffer2);
|
||||
}
|
||||
|
||||
if (retry >= READ_RETRY) {
|
||||
warnx("%s: File changed %d times while reading - aborting",
|
||||
filename, retry);
|
||||
return EXIT_RUNTIME_ERROR;
|
||||
}
|
||||
|
||||
/* Perform basic checks */
|
||||
f.name = filename;
|
||||
f.buffer = buffer;
|
||||
f.size = size;
|
||||
hdr = (void *) buffer;
|
||||
if (!check_header(&f, hdr)) {
|
||||
free(buffer);
|
||||
return EXIT_FORMAT_ERROR;
|
||||
}
|
||||
if (fwacc(&f, hdr->file_len) > size) {
|
||||
fwwarn(&f, "File length mismatch (expect %zu) - adjusting",
|
||||
size);
|
||||
hdr->file_len = size;
|
||||
}
|
||||
|
||||
*file = f;
|
||||
|
||||
return EXIT_OK;
|
||||
}
|
||||
|
||||
/* Return textual representation of a device entry type. */
|
||||
static const char *type_to_str(uint16_t type)
|
||||
{
|
||||
switch (type) {
|
||||
case FW_DE_HDR_TYPE_DASD:
|
||||
return "dasd";
|
||||
case FW_DE_HDR_TYPE_ZFCP_HOST:
|
||||
return "zfcp-host";
|
||||
case FW_DE_HDR_TYPE_ZFCP_LUN:
|
||||
return "zfcp-lun";
|
||||
case FW_DE_HDR_TYPE_QETH:
|
||||
return "qeth";
|
||||
default:
|
||||
return "<unknown>";
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert a binary format device setting of the specified length to integer. */
|
||||
static unsigned long parse_value(char *data, uint8_t len)
|
||||
{
|
||||
switch (len) {
|
||||
case 1:
|
||||
return (unsigned long) *((uint8_t *) data);
|
||||
case 2:
|
||||
return (unsigned long) *((uint16_t *) data);
|
||||
case 4:
|
||||
return (unsigned long) *((uint32_t *) data);
|
||||
case 8:
|
||||
return (unsigned long) *((uint64_t *) data);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform sanity checks on device setting. */
|
||||
static bool check_setting(struct fw_file *f, struct fw_setting *set)
|
||||
{
|
||||
/* Key sanity checks */
|
||||
if (fwacc(f, set->key_type) != FW_SETTING_KEYTYPE_ASCII) {
|
||||
fwwarn(f, "Unsupported key type: %d", set->key_type);
|
||||
return false;
|
||||
}
|
||||
if (fwacc(f, set->key_len) < 1) {
|
||||
fwwarn(f, "Unsupported key length: %d", set->key_len);
|
||||
return false;
|
||||
}
|
||||
if (sizeof(struct fw_setting) + fwacc(f, set->key_len) > set->len) {
|
||||
fwwarn(f, "Key length exceeds setting");
|
||||
return false;
|
||||
}
|
||||
if (fwacc(f, set->data[set->key_len - 1])) {
|
||||
fwwarn(f, "Key not null-terminated");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Value sanity checks */
|
||||
if (fwacc(f, set->val_type) != FW_SETTING_VALTYPE_UINT &&
|
||||
fwacc(f, set->val_type) != FW_SETTING_VALTYPE_ASCII) {
|
||||
fwwarn(f, "Unsupported value type: %d", set->val_type);
|
||||
return false;
|
||||
}
|
||||
if (fwacc(f, set->val_len) < 1) {
|
||||
fwwarn(f, "Unsupported value length: %d", set->val_len);
|
||||
return false;
|
||||
}
|
||||
if (sizeof(struct fw_setting) + set->key_len +
|
||||
fwacc(f, set->val_len) > set->len) {
|
||||
fwwarn(f, "Value length exceeds setting");
|
||||
return false;
|
||||
}
|
||||
if ((set->val_type == FW_SETTING_VALTYPE_ASCII) &&
|
||||
fwacc(f, set->data[set->key_len + set->val_len - 1])) {
|
||||
fwwarn(f, "Value not null-terminated");
|
||||
return false;
|
||||
}
|
||||
if (set->val_type == FW_SETTING_VALTYPE_UINT) {
|
||||
switch (fwacc(f, set->val_len)) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
break;
|
||||
default:
|
||||
fwwarn(f, "Unsupported integer value length: %d",
|
||||
set->val_len);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Add a setting to the device. Emit a warning if the setting is not known. */
|
||||
static void _add_setting(const char *filename, struct device *dev,
|
||||
config_t config, const char *key, const char *value)
|
||||
{
|
||||
struct attrib *a;
|
||||
struct setting_list *list;
|
||||
|
||||
list = device_get_setting_list(dev, config);
|
||||
a = attrib_find(dev->subtype->dev_attribs, key);
|
||||
if (!a) {
|
||||
warnx("%s: Applying unknown device setting %s=%s", filename,
|
||||
key, value);
|
||||
}
|
||||
setting_list_apply(list, a, key, value);
|
||||
}
|
||||
|
||||
static void add_setting(const char *filename, struct device *dev,
|
||||
config_t config, const char *key, const char *value)
|
||||
{
|
||||
if (SCOPE_ACTIVE(config))
|
||||
_add_setting(filename, dev, config_active, key, value);
|
||||
if (SCOPE_PERSISTENT(config))
|
||||
_add_setting(filename, dev, config_persistent, key, value);
|
||||
if (SCOPE_AUTOCONF(config))
|
||||
_add_setting(filename, dev, config_autoconf, key, value);
|
||||
}
|
||||
|
||||
/* Parse a single device setting in firmware format and apply it to the
|
||||
* specified device. */
|
||||
static void parse_setting(struct fw_file *f, struct fw_setting *set,
|
||||
struct device *dev, config_t config)
|
||||
{
|
||||
char *ascii_key, *ascii_val;
|
||||
unsigned long ulong_val;
|
||||
|
||||
if (!check_setting(f, set))
|
||||
return;
|
||||
|
||||
ascii_key = &set->data[0];
|
||||
if (set->val_type == FW_SETTING_VALTYPE_UINT) {
|
||||
ulong_val = parse_value(&set->data[set->key_len], set->val_len);
|
||||
ascii_val = misc_asprintf("%lu", ulong_val);
|
||||
add_setting(f->name, dev, config, ascii_key, ascii_val);
|
||||
free(ascii_val);
|
||||
} else {
|
||||
ascii_val = &set->data[set->key_len];
|
||||
add_setting(f->name, dev, config, ascii_key, ascii_val);
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse a device settings list in firmware format and apply the resulting
|
||||
* settings to the specified device. */
|
||||
static void parse_settings(struct fw_file *f, char *data, struct device *dev,
|
||||
config_t config)
|
||||
{
|
||||
struct fw_setlist *list = (struct fw_setlist *) data;
|
||||
struct fw_setting *set;
|
||||
uint16_t off;
|
||||
|
||||
for (off = sizeof(struct fw_setlist); off < list->len;
|
||||
off += set->len) {
|
||||
set = (struct fw_setting *) &data[off];
|
||||
if (fwacc(f, set->len) < sizeof(struct fw_setting)) {
|
||||
fwwarn(f, "Setting too short");
|
||||
break;
|
||||
}
|
||||
if (off + fwacc(f, set->len) > list->len) {
|
||||
fwwarn(f, "Setting too long");
|
||||
break;
|
||||
}
|
||||
parse_setting(f, set, dev, config);
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform sanity checks on an I/O device ID. */
|
||||
static bool check_iodevid(struct fw_file *f, uint8_t *flags,
|
||||
struct fw_iodevid *id)
|
||||
{
|
||||
|
||||
if (fwacc(f, *flags) & FW_IODEVID_FLAG_MCSS) {
|
||||
fwwarn(f, "Unsupported entry in non-default CSS");
|
||||
return false;
|
||||
}
|
||||
if (fwacc(f, id->cssid) != 0) {
|
||||
fwwarn(f, "Non-zero CSS-ID");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Perform sanity checks on a device entry. */
|
||||
static bool check_de_size(struct fw_file *f, struct fw_dehdr *de, size_t size)
|
||||
{
|
||||
if (fwacc(f, de->len) < size) {
|
||||
fwwarn(f, "Device entry too short (expect %zu)", size);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Convert an I/O device ID to CCW device ID format. */
|
||||
static void io_to_ccw(struct ccw_devid *c, struct fw_iodevid *i)
|
||||
{
|
||||
c->cssid = i->cssid;
|
||||
c->ssid = i->ssid;
|
||||
c->devno = i->devno;
|
||||
}
|
||||
|
||||
/* Register a new device configuration. */
|
||||
static struct device *add_device(struct fw_file *f, struct subtype *st,
|
||||
const char *id, config_t config,
|
||||
struct util_list *objects)
|
||||
{
|
||||
struct device *dev;
|
||||
|
||||
if (!st->devices)
|
||||
st->devices = device_list_new(st);
|
||||
|
||||
dev = device_list_find(st->devices, id, NULL);
|
||||
if (!dev) {
|
||||
dev = device_new(st, id);
|
||||
if (!dev) {
|
||||
warnx("%s: Skipping invalid %s device ID %s", f->name,
|
||||
st->name, id);
|
||||
return NULL;
|
||||
}
|
||||
device_list_add(st->devices, dev);
|
||||
}
|
||||
ptrlist_add(objects, object_new(export_device, dev));
|
||||
|
||||
/* Prepare device for new settings. */
|
||||
if (SCOPE_ACTIVE(config)) {
|
||||
setting_list_clear(dev->active.settings);
|
||||
if (dev->subtype->support_definable)
|
||||
dev->active.definable = 1;
|
||||
else
|
||||
dev->active.exists = 1;
|
||||
}
|
||||
if (SCOPE_PERSISTENT(config)) {
|
||||
setting_list_clear(dev->persistent.settings);
|
||||
dev->persistent.exists = 1;
|
||||
}
|
||||
if (SCOPE_AUTOCONF(config)) {
|
||||
setting_list_clear(dev->autoconf.settings);
|
||||
dev->autoconf.exists = 1;
|
||||
}
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
/* Parse a DASD device entry. */
|
||||
static void parse_dasd(struct fw_file *f, struct fw_dehdr *de, config_t config,
|
||||
struct util_list *objects)
|
||||
{
|
||||
struct fw_dasd *dasd = (struct fw_dasd *) de;
|
||||
struct ccw_devid devid;
|
||||
struct device *dev_eckd, *dev_fba;
|
||||
char *id;
|
||||
|
||||
if (!check_de_size(f, de, sizeof(struct fw_dasd)))
|
||||
return;
|
||||
if (!check_iodevid(f, &dasd->id_flags, &dasd->id))
|
||||
return;
|
||||
|
||||
/* Could be either dasd_eckd or dasd_fba - add both entries */
|
||||
io_to_ccw(&devid, &dasd->id);
|
||||
id = ccw_devid_to_str(&devid);
|
||||
dev_eckd = add_device(f, &dasd_subtype_eckd, id, config, objects);
|
||||
dev_fba = add_device(f, &dasd_subtype_fba, id, config, objects);
|
||||
free(id);
|
||||
|
||||
if (dasd->hdr.len > sizeof(struct fw_dasd)) {
|
||||
if (dev_eckd)
|
||||
parse_settings(f, dasd->settings, dev_eckd, config);
|
||||
if (dev_fba)
|
||||
parse_settings(f, dasd->settings, dev_fba, config);
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse a zFCP host device entry. */
|
||||
static void parse_zfcp_host(struct fw_file *f, struct fw_dehdr *de,
|
||||
config_t config, struct util_list *objects)
|
||||
{
|
||||
struct fw_zfcp_host *zfcp_host = (struct fw_zfcp_host *) de;
|
||||
struct ccw_devid devid;
|
||||
struct device *dev;
|
||||
char *id;
|
||||
|
||||
if (!check_de_size(f, de, sizeof(struct fw_zfcp_host)))
|
||||
return;
|
||||
if (!check_iodevid(f, &zfcp_host->id_flags, &zfcp_host->id))
|
||||
return;
|
||||
|
||||
/* Add zfcp_host entry */
|
||||
io_to_ccw(&devid, &zfcp_host->id);
|
||||
id = ccw_devid_to_str(&devid);
|
||||
dev = add_device(f, &zfcp_host_subtype, id, config, objects);
|
||||
free(id);
|
||||
|
||||
if (dev && zfcp_host->hdr.len > sizeof(struct fw_zfcp_host))
|
||||
parse_settings(f, zfcp_host->settings, dev, config);
|
||||
}
|
||||
|
||||
/* Parse a zFCP LUN device entry. */
|
||||
static void parse_zfcp_lun(struct fw_file *f, struct fw_dehdr *de,
|
||||
config_t config, struct util_list *objects)
|
||||
{
|
||||
struct fw_zfcp_lun *zfcp_lun = (struct fw_zfcp_lun *) de;
|
||||
struct zfcp_lun_devid devid;
|
||||
struct device *dev;
|
||||
char *id;
|
||||
|
||||
if (!check_de_size(f, de, sizeof(struct fw_zfcp_lun)))
|
||||
return;
|
||||
if (!check_iodevid(f, &zfcp_lun->id_flags, &zfcp_lun->id))
|
||||
return;
|
||||
|
||||
/* Add zfcp_lun entry */
|
||||
io_to_ccw(&devid.fcp_dev, &zfcp_lun->id);
|
||||
devid.wwpn = zfcp_lun->wwpn;
|
||||
devid.lun = zfcp_lun->fcp_lun;
|
||||
id = zfcp_lun_devid_to_str(&devid);
|
||||
dev = add_device(f, &zfcp_lun_subtype, id, config, objects);
|
||||
free(id);
|
||||
|
||||
if (dev && zfcp_lun->hdr.len > sizeof(struct fw_zfcp_lun))
|
||||
parse_settings(f, zfcp_lun->settings, dev, config);
|
||||
|
||||
}
|
||||
|
||||
/* Parse a QETH device entry. */
|
||||
static void parse_qeth(struct fw_file *f, struct fw_dehdr *de, config_t config,
|
||||
struct util_list *objects)
|
||||
{
|
||||
struct fw_qeth *qeth = (struct fw_qeth *) de;
|
||||
struct ccwgroup_devid devid;
|
||||
struct device *dev;
|
||||
char *id;
|
||||
|
||||
if (!check_de_size(f, de, sizeof(struct fw_qeth)))
|
||||
return;
|
||||
if (!check_iodevid(f, &qeth->id_flags, &qeth->read_id) ||
|
||||
!check_iodevid(f, &qeth->id_flags, &qeth->write_id) ||
|
||||
!check_iodevid(f, &qeth->id_flags, &qeth->data_id))
|
||||
return;
|
||||
|
||||
/* Add qeth entry */
|
||||
devid.num = 3;
|
||||
io_to_ccw(&devid.devid[0], &qeth->read_id);
|
||||
io_to_ccw(&devid.devid[1], &qeth->write_id);
|
||||
io_to_ccw(&devid.devid[2], &qeth->data_id);
|
||||
id = ccwgroup_devid_to_str(&devid);
|
||||
dev = add_device(f, &qeth_subtype_qeth, id, config, objects);
|
||||
free(id);
|
||||
|
||||
if (dev && qeth->hdr.len > sizeof(struct fw_qeth))
|
||||
parse_settings(f, qeth->settings, dev, config);
|
||||
}
|
||||
|
||||
/* Parse a firmware file. */
|
||||
static void parse_fw(struct fw_file *f, long skip, config_t config,
|
||||
struct util_list *objects)
|
||||
{
|
||||
char *data = f->buffer;
|
||||
struct fw_filehdr *hdr = (struct fw_filehdr *) data;
|
||||
struct fw_dehdr *de;
|
||||
uint16_t count = 0;
|
||||
uint32_t off;
|
||||
|
||||
for (off = hdr->hdr_len; off < hdr->file_len; off += de->len) {
|
||||
count++;
|
||||
de = (struct fw_dehdr *) &data[off];
|
||||
if (fwacc(f, de->len) == 0) {
|
||||
fwwarn(f, "Empty device entry");
|
||||
break;
|
||||
}
|
||||
if (off + fwacc(f, de->len) > hdr->file_len) {
|
||||
fwwarn(f, "Device entry too long");
|
||||
break;
|
||||
}
|
||||
if (skip >= 0 && de->seq <= skip) {
|
||||
debug("Skipping %s entry due to sequence (%08x)\n",
|
||||
type_to_str(de->type), de->seq);
|
||||
continue;
|
||||
}
|
||||
switch (fwacc(f, de->type)) {
|
||||
case FW_DE_HDR_TYPE_DASD:
|
||||
parse_dasd(f, de, config, objects);
|
||||
break;
|
||||
case FW_DE_HDR_TYPE_ZFCP_HOST:
|
||||
parse_zfcp_host(f, de, config, objects);
|
||||
break;
|
||||
case FW_DE_HDR_TYPE_ZFCP_LUN:
|
||||
parse_zfcp_lun(f, de, config, objects);
|
||||
break;
|
||||
case FW_DE_HDR_TYPE_QETH:
|
||||
parse_qeth(f, de, config, objects);
|
||||
break;
|
||||
default:
|
||||
fwwarn(f, "Unknown entry (type=%04x)", de->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (count != fwacc(f, hdr->de_count))
|
||||
fwwarn(f, "Device entry count mismatch");
|
||||
}
|
||||
|
||||
/* Read configuration objects from @fd in firmware file format. Add pointers to
|
||||
* newly allocated struct export_objects to ptrlist @objects. If @skip is a
|
||||
* positive number, skip over entries with a sequence number equal to or
|
||||
* greater than @skip. */
|
||||
exit_code_t firmware_read(FILE *fd, const char *filename, long skip,
|
||||
config_t config, struct util_list *objects)
|
||||
{
|
||||
struct fw_file file;
|
||||
exit_code_t rc;
|
||||
|
||||
rc = read_fw(&file, fd, filename);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
parse_fw(&file, skip, config, objects);
|
||||
free(file.buffer);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Check if @fd refers to a file in binary firmware format. */
|
||||
bool firmware_detect(FILE *fd)
|
||||
{
|
||||
int c;
|
||||
|
||||
c = fgetc(fd);
|
||||
ungetc(c, fd);
|
||||
|
||||
/* Note: A full check would require looking at least at the first 4
|
||||
* bytes, but fd might be non-seekable (e.g. pipe). Since there is no
|
||||
* way that a textual import file can start with a 'z', looking at
|
||||
* the first char should be enough. */
|
||||
|
||||
return c == 'z';
|
||||
}
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "devnode.h"
|
||||
#include "devtype.h"
|
||||
#include "generic_ccw.h"
|
||||
#include "internal.h"
|
||||
#include "namespace.h"
|
||||
#include "path.h"
|
||||
#include "subtype.h"
|
||||
@@ -182,6 +183,7 @@ static struct subtype generic_ccw_subtype = {
|
||||
.dev_attribs = ATTRIB_ARRAY(
|
||||
&ccw_attr_online,
|
||||
&ccw_attr_cmb_enable,
|
||||
&internal_attr_early,
|
||||
),
|
||||
.unknown_dev_attribs = 1,
|
||||
.generic = 1,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user