mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-01 03:22:08 +00:00
docs: s390: convert docs to ReST and rename to *.rst
Convert all text files with s390 documentation to ReST format. Tried to preserve as much as possible the original document format. Still, some of the files required some work in order for it to be visible on both plain text and after converted to html. The conversion is actually: - add blank lines and identation in order to identify paragraphs; - fix tables markups; - add some lists markups; - mark literal blocks; - adjust title markups. At its new index.rst, let's add a :orphan: while this is not linked to the main index.rst file, in order to avoid build warnings. Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org> Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
This commit is contained in:
parent
dc3988f40f
commit
8b4a503d65
@ -478,7 +478,7 @@
|
||||
others).
|
||||
|
||||
ccw_timeout_log [S390]
|
||||
See Documentation/s390/CommonIO for details.
|
||||
See Documentation/s390/common_io.rst for details.
|
||||
|
||||
cgroup_disable= [KNL] Disable a particular controller
|
||||
Format: {name of the controller(s) to disable}
|
||||
@ -516,7 +516,7 @@
|
||||
/selinux/checkreqprot.
|
||||
|
||||
cio_ignore= [S390]
|
||||
See Documentation/s390/CommonIO for details.
|
||||
See Documentation/s390/common_io.rst for details.
|
||||
clk_ignore_unused
|
||||
[CLK]
|
||||
Prevents the clock framework from automatically gating
|
||||
|
@ -27,7 +27,7 @@ not strictly considered I/O devices. They are considered here as well,
|
||||
although they are not the focus of this document.
|
||||
|
||||
Some additional information can also be found in the kernel source under
|
||||
Documentation/s390/driver-model.txt.
|
||||
Documentation/s390/driver-model.rst.
|
||||
|
||||
The css bus
|
||||
===========
|
||||
@ -38,7 +38,7 @@ into several categories:
|
||||
* Standard I/O subchannels, for use by the system. They have a child
|
||||
device on the ccw bus and are described below.
|
||||
* I/O subchannels bound to the vfio-ccw driver. See
|
||||
Documentation/s390/vfio-ccw.txt.
|
||||
Documentation/s390/vfio-ccw.rst.
|
||||
* Message subchannels. No Linux driver currently exists.
|
||||
* CHSC subchannels (at most one). The chsc subchannel driver can be used
|
||||
to send asynchronous chsc commands.
|
||||
|
@ -1,13 +1,17 @@
|
||||
===============================
|
||||
IBM 3270 Display System support
|
||||
===============================
|
||||
|
||||
This file describes the driver that supports local channel attachment
|
||||
of IBM 3270 devices. It consists of three sections:
|
||||
|
||||
* Introduction
|
||||
* Installation
|
||||
* Operation
|
||||
|
||||
|
||||
INTRODUCTION.
|
||||
Introduction
|
||||
============
|
||||
|
||||
This paper describes installing and operating 3270 devices under
|
||||
Linux/390. A 3270 device is a block-mode rows-and-columns terminal of
|
||||
@ -17,12 +21,12 @@ twenty and thirty years ago.
|
||||
You may have 3270s in-house and not know it. If you're using the
|
||||
VM-ESA operating system, define a 3270 to your virtual machine by using
|
||||
the command "DEF GRAF <hex-address>" This paper presumes you will be
|
||||
defining four 3270s with the CP/CMS commands
|
||||
defining four 3270s with the CP/CMS commands:
|
||||
|
||||
DEF GRAF 620
|
||||
DEF GRAF 621
|
||||
DEF GRAF 622
|
||||
DEF GRAF 623
|
||||
- DEF GRAF 620
|
||||
- DEF GRAF 621
|
||||
- DEF GRAF 622
|
||||
- DEF GRAF 623
|
||||
|
||||
Your network connection from VM-ESA allows you to use x3270, tn3270, or
|
||||
another 3270 emulator, started from an xterm window on your PC or
|
||||
@ -34,7 +38,8 @@ This paper covers installation of the driver and operation of a
|
||||
dialed-in x3270.
|
||||
|
||||
|
||||
INSTALLATION.
|
||||
Installation
|
||||
============
|
||||
|
||||
You install the driver by installing a patch, doing a kernel build, and
|
||||
running the configuration script (config3270.sh, in this directory).
|
||||
@ -59,13 +64,15 @@ Use #CP TERM CONMODE 3270 to change it to 3270. If you generate only
|
||||
at boot time to a 3270 if it is a 3215.
|
||||
|
||||
In brief, these are the steps:
|
||||
|
||||
1. Install the tub3270 patch
|
||||
2. (If a module) add a line to a file in /etc/modprobe.d/*.conf
|
||||
2. (If a module) add a line to a file in `/etc/modprobe.d/*.conf`
|
||||
3. (If VM) define devices with DEF GRAF
|
||||
4. Reboot
|
||||
5. Configure
|
||||
|
||||
To test that everything works, assuming VM and x3270,
|
||||
|
||||
1. Bring up an x3270 window.
|
||||
2. Use the DIAL command in that window.
|
||||
3. You should immediately see a Linux login screen.
|
||||
@ -74,7 +81,8 @@ Here are the installation steps in detail:
|
||||
|
||||
1. The 3270 driver is a part of the official Linux kernel
|
||||
source. Build a tree with the kernel source and any necessary
|
||||
patches. Then do
|
||||
patches. Then do::
|
||||
|
||||
make oldconfig
|
||||
(If you wish to disable 3215 console support, edit
|
||||
.config; change CONFIG_TN3215's value to "n";
|
||||
@ -84,20 +92,22 @@ Here are the installation steps in detail:
|
||||
make modules_install
|
||||
|
||||
2. (Perform this step only if you have configured tub3270 as a
|
||||
module.) Add a line to a file /etc/modprobe.d/*.conf to automatically
|
||||
module.) Add a line to a file `/etc/modprobe.d/*.conf` to automatically
|
||||
load the driver when it's needed. With this line added, you will see
|
||||
login prompts appear on your 3270s as soon as boot is complete (or
|
||||
with emulated 3270s, as soon as you dial into your vm guest using the
|
||||
command "DIAL <vmguestname>"). Since the line-mode major number is
|
||||
227, the line to add should be:
|
||||
227, the line to add should be::
|
||||
|
||||
alias char-major-227 tub3270
|
||||
|
||||
3. Define graphic devices to your vm guest machine, if you
|
||||
haven't already. Define them before you reboot (reipl):
|
||||
DEFINE GRAF 620
|
||||
DEFINE GRAF 621
|
||||
DEFINE GRAF 622
|
||||
DEFINE GRAF 623
|
||||
|
||||
- DEFINE GRAF 620
|
||||
- DEFINE GRAF 621
|
||||
- DEFINE GRAF 622
|
||||
- DEFINE GRAF 623
|
||||
|
||||
4. Reboot. The reboot process scans hardware devices, including
|
||||
3270s, and this enables the tub3270 driver once loaded to respond
|
||||
@ -107,21 +117,23 @@ Here are the installation steps in detail:
|
||||
|
||||
5. Run the 3270 configuration script config3270. It is
|
||||
distributed in this same directory, Documentation/s390, as
|
||||
config3270.sh. Inspect the output script it produces,
|
||||
config3270.sh. Inspect the output script it produces,
|
||||
/tmp/mkdev3270, and then run that script. This will create the
|
||||
necessary character special device files and make the necessary
|
||||
changes to /etc/inittab.
|
||||
|
||||
Then notify /sbin/init that /etc/inittab has changed, by issuing
|
||||
the telinit command with the q operand:
|
||||
the telinit command with the q operand::
|
||||
|
||||
cd Documentation/s390
|
||||
sh config3270.sh
|
||||
sh /tmp/mkdev3270
|
||||
telinit q
|
||||
|
||||
This should be sufficient for your first time. If your 3270
|
||||
This should be sufficient for your first time. If your 3270
|
||||
configuration has changed and you're reusing config3270, you
|
||||
should follow these steps:
|
||||
should follow these steps::
|
||||
|
||||
Change 3270 configuration
|
||||
Reboot
|
||||
Run config3270 and /tmp/mkdev3270
|
||||
@ -132,8 +144,10 @@ Here are the testing steps in detail:
|
||||
1. Bring up an x3270 window, or use an actual hardware 3278 or
|
||||
3279, or use the 3270 emulator of your choice. You would be
|
||||
running the emulator on your PC or workstation. You would use
|
||||
the command, for example,
|
||||
the command, for example::
|
||||
|
||||
x3270 vm-esa-domain-name &
|
||||
|
||||
if you wanted a 3278 Model 4 with 43 rows of 80 columns, the
|
||||
default model number. The driver does not take advantage of
|
||||
extended attributes.
|
||||
@ -144,7 +158,8 @@ Here are the testing steps in detail:
|
||||
|
||||
2. Use the DIAL command instead of the LOGIN command to connect
|
||||
to one of the virtual 3270s you defined with the DEF GRAF
|
||||
commands:
|
||||
commands::
|
||||
|
||||
dial my-vm-guest-name
|
||||
|
||||
3. You should immediately see a login prompt from your
|
||||
@ -171,14 +186,17 @@ Here are the testing steps in detail:
|
||||
Wrong major number? Wrong minor number? There's your
|
||||
problem!
|
||||
|
||||
D. Do you get the message
|
||||
D. Do you get the message::
|
||||
|
||||
"HCPDIA047E my-vm-guest-name 0620 does not exist"?
|
||||
|
||||
If so, you must issue the command "DEF GRAF 620" from your VM
|
||||
3215 console and then reboot the system.
|
||||
|
||||
|
||||
|
||||
OPERATION.
|
||||
==========
|
||||
|
||||
The driver defines three areas on the 3270 screen: the log area, the
|
||||
input area, and the status area.
|
||||
@ -203,8 +221,10 @@ which indicates no scrolling will occur. (If you hit ENTER with "Linux
|
||||
Running" and nothing typed, the application receives a newline.)
|
||||
|
||||
You may change the scrolling timeout value. For example, the following
|
||||
command line:
|
||||
command line::
|
||||
|
||||
echo scrolltime=60 > /proc/tty/driver/tty3270
|
||||
|
||||
changes the scrolling timeout value to 60 sec. Set scrolltime to 0 if
|
||||
you wish to prevent scrolling entirely.
|
||||
|
||||
@ -228,7 +248,8 @@ cause an EOF also by typing "^D" and hitting ENTER.
|
||||
No PF key is preassigned to cause a job suspension, but you may cause a
|
||||
job suspension by typing "^Z" and hitting ENTER. You may wish to
|
||||
assign this function to a PF key. To make PF7 cause job suspension,
|
||||
execute the command:
|
||||
execute the command::
|
||||
|
||||
echo pf7=^z > /proc/tty/driver/tty3270
|
||||
|
||||
If the input you type does not end with the two characters "^n", the
|
||||
@ -243,8 +264,10 @@ command is entered into the stack only when the input area is not made
|
||||
invisible (such as for password entry) and it is not identical to the
|
||||
current top entry. PF10 rotates backward through the command stack;
|
||||
PF11 rotates forward. You may assign the backward function to any PF
|
||||
key (or PA key, for that matter), say, PA3, with the command:
|
||||
key (or PA key, for that matter), say, PA3, with the command::
|
||||
|
||||
echo -e pa3=\\033k > /proc/tty/driver/tty3270
|
||||
|
||||
This assigns the string ESC-k to PA3. Similarly, the string ESC-j
|
||||
performs the forward function. (Rationale: In bash with vi-mode line
|
||||
editing, ESC-k and ESC-j retrieve backward and forward history.
|
||||
@ -252,15 +275,19 @@ Suggestions welcome.)
|
||||
|
||||
Is a stack size of twenty commands not to your liking? Change it on
|
||||
the fly. To change to saving the last 100 commands, execute the
|
||||
command:
|
||||
command::
|
||||
|
||||
echo recallsize=100 > /proc/tty/driver/tty3270
|
||||
|
||||
Have a command you issue frequently? Assign it to a PF or PA key! Use
|
||||
the command
|
||||
echo pf24="mkdir foobar; cd foobar" > /proc/tty/driver/tty3270
|
||||
the command::
|
||||
|
||||
echo pf24="mkdir foobar; cd foobar" > /proc/tty/driver/tty3270
|
||||
|
||||
to execute the commands mkdir foobar and cd foobar immediately when you
|
||||
hit PF24. Want to see the command line first, before you execute it?
|
||||
Use the -n option of the echo command:
|
||||
Use the -n option of the echo command::
|
||||
|
||||
echo -n pf24="mkdir foo; cd foo" > /proc/tty/driver/tty3270
|
||||
|
||||
|
@ -1,14 +1,18 @@
|
||||
===========================
|
||||
Linux for S/390 and zSeries
|
||||
===========================
|
||||
|
||||
Common Device Support (CDS)
|
||||
Device Driver I/O Support Routines
|
||||
|
||||
Authors : Ingo Adlung
|
||||
Cornelia Huck
|
||||
Authors:
|
||||
- Ingo Adlung
|
||||
- Cornelia Huck
|
||||
|
||||
Copyright, IBM Corp. 1999-2002
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
This document describes the common device support routines for Linux/390.
|
||||
Different than other hardware architectures, ESA/390 has defined a unified
|
||||
@ -27,18 +31,20 @@ Operation manual (IBM Form. No. SA22-7201).
|
||||
|
||||
In order to build common device support for ESA/390 I/O interfaces, a
|
||||
functional layer was introduced that provides generic I/O access methods to
|
||||
the hardware.
|
||||
the hardware.
|
||||
|
||||
The common device support layer comprises the I/O support routines defined
|
||||
below. Some of them implement common Linux device driver interfaces, while
|
||||
The common device support layer comprises the I/O support routines defined
|
||||
below. Some of them implement common Linux device driver interfaces, while
|
||||
some of them are ESA/390 platform specific.
|
||||
|
||||
Note:
|
||||
In order to write a driver for S/390, you also need to look into the interface
|
||||
described in Documentation/s390/driver-model.txt.
|
||||
In order to write a driver for S/390, you also need to look into the interface
|
||||
described in Documentation/s390/driver-model.rst.
|
||||
|
||||
Note for porting drivers from 2.4:
|
||||
|
||||
The major changes are:
|
||||
|
||||
* The functions use a ccw_device instead of an irq (subchannel).
|
||||
* All drivers must define a ccw_driver (see driver-model.txt) and the associated
|
||||
functions.
|
||||
@ -57,19 +63,16 @@ The major changes are:
|
||||
ccw_device_get_ciw()
|
||||
get commands from extended sense data.
|
||||
|
||||
ccw_device_start()
|
||||
ccw_device_start_timeout()
|
||||
ccw_device_start_key()
|
||||
ccw_device_start_key_timeout()
|
||||
ccw_device_start(), ccw_device_start_timeout(), ccw_device_start_key(), ccw_device_start_key_timeout()
|
||||
initiate an I/O request.
|
||||
|
||||
ccw_device_resume()
|
||||
resume channel program execution.
|
||||
|
||||
ccw_device_halt()
|
||||
ccw_device_halt()
|
||||
terminate the current I/O request processed on the device.
|
||||
|
||||
do_IRQ()
|
||||
do_IRQ()
|
||||
generic interrupt routine. This function is called by the interrupt entry
|
||||
routine whenever an I/O interrupt is presented to the system. The do_IRQ()
|
||||
routine determines the interrupt status and calls the device specific
|
||||
@ -82,12 +85,15 @@ first level interrupt handler only and does not comprise a device driver
|
||||
callable interface. Instead, the functional description of do_IO() also
|
||||
describes the input to the device specific interrupt handler.
|
||||
|
||||
Note: All explanations apply also to the 64 bit architecture s390x.
|
||||
Note:
|
||||
All explanations apply also to the 64 bit architecture s390x.
|
||||
|
||||
|
||||
Common Device Support (CDS) for Linux/390 Device Drivers
|
||||
========================================================
|
||||
|
||||
General Information
|
||||
-------------------
|
||||
|
||||
The following chapters describe the I/O related interface routines the
|
||||
Linux/390 common device support (CDS) provides to allow for device specific
|
||||
@ -101,6 +107,7 @@ can be found in the architecture specific C header file
|
||||
linux/arch/s390/include/asm/irq.h.
|
||||
|
||||
Overview of CDS interface concepts
|
||||
----------------------------------
|
||||
|
||||
Different to other hardware platforms, the ESA/390 architecture doesn't define
|
||||
interrupt lines managed by a specific interrupt controller and bus systems
|
||||
@ -126,7 +133,7 @@ has to call every single device driver registered on this IRQ in order to
|
||||
determine the device driver owning the device that raised the interrupt.
|
||||
|
||||
Up to kernel 2.4, Linux/390 used to provide interfaces via the IRQ (subchannel).
|
||||
For internal use of the common I/O layer, these are still there. However,
|
||||
For internal use of the common I/O layer, these are still there. However,
|
||||
device drivers should use the new calling interface via the ccw_device only.
|
||||
|
||||
During its startup the Linux/390 system checks for peripheral devices. Each
|
||||
@ -134,7 +141,7 @@ of those devices is uniquely defined by a so called subchannel by the ESA/390
|
||||
channel subsystem. While the subchannel numbers are system generated, each
|
||||
subchannel also takes a user defined attribute, the so called device number.
|
||||
Both subchannel number and device number cannot exceed 65535. During sysfs
|
||||
initialisation, the information about control unit type and device types that
|
||||
initialisation, the information about control unit type and device types that
|
||||
imply specific I/O commands (channel command words - CCWs) in order to operate
|
||||
the device are gathered. Device drivers can retrieve this set of hardware
|
||||
information during their initialization step to recognize the devices they
|
||||
@ -164,18 +171,26 @@ get_ciw() - get command information word
|
||||
This call enables a device driver to get information about supported commands
|
||||
from the extended SenseID data.
|
||||
|
||||
struct ciw *
|
||||
ccw_device_get_ciw(struct ccw_device *cdev, __u32 cmd);
|
||||
::
|
||||
|
||||
cdev - The ccw_device for which the command is to be retrieved.
|
||||
cmd - The command type to be retrieved.
|
||||
struct ciw *
|
||||
ccw_device_get_ciw(struct ccw_device *cdev, __u32 cmd);
|
||||
|
||||
==== ========================================================
|
||||
cdev The ccw_device for which the command is to be retrieved.
|
||||
cmd The command type to be retrieved.
|
||||
==== ========================================================
|
||||
|
||||
ccw_device_get_ciw() returns:
|
||||
NULL - No extended data available, invalid device or command not found.
|
||||
!NULL - The command requested.
|
||||
|
||||
===== ================================================================
|
||||
NULL No extended data available, invalid device or command not found.
|
||||
!NULL The command requested.
|
||||
===== ================================================================
|
||||
|
||||
ccw_device_start() - Initiate I/O Request
|
||||
::
|
||||
|
||||
ccw_device_start() - Initiate I/O Request
|
||||
|
||||
The ccw_device_start() routines is the I/O request front-end processor. All
|
||||
device driver I/O requests must be issued using this routine. A device driver
|
||||
@ -186,93 +201,105 @@ This description also covers the status information passed to the device
|
||||
driver's interrupt handler as this is related to the rules (flags) defined
|
||||
with the associated I/O request when calling ccw_device_start().
|
||||
|
||||
int ccw_device_start(struct ccw_device *cdev,
|
||||
struct ccw1 *cpa,
|
||||
unsigned long intparm,
|
||||
__u8 lpm,
|
||||
unsigned long flags);
|
||||
int ccw_device_start_timeout(struct ccw_device *cdev,
|
||||
struct ccw1 *cpa,
|
||||
unsigned long intparm,
|
||||
__u8 lpm,
|
||||
unsigned long flags,
|
||||
int expires);
|
||||
int ccw_device_start_key(struct ccw_device *cdev,
|
||||
struct ccw1 *cpa,
|
||||
unsigned long intparm,
|
||||
__u8 lpm,
|
||||
__u8 key,
|
||||
unsigned long flags);
|
||||
int ccw_device_start_key_timeout(struct ccw_device *cdev,
|
||||
struct ccw1 *cpa,
|
||||
unsigned long intparm,
|
||||
__u8 lpm,
|
||||
__u8 key,
|
||||
unsigned long flags,
|
||||
int expires);
|
||||
::
|
||||
|
||||
cdev : ccw_device the I/O is destined for
|
||||
cpa : logical start address of channel program
|
||||
user_intparm : user specific interrupt information; will be presented
|
||||
back to the device driver's interrupt handler. Allows a
|
||||
device driver to associate the interrupt with a
|
||||
particular I/O request.
|
||||
lpm : defines the channel path to be used for a specific I/O
|
||||
request. A value of 0 will make cio use the opm.
|
||||
key : the storage key to use for the I/O (useful for operating on a
|
||||
storage with a storage key != default key)
|
||||
flag : defines the action to be performed for I/O processing
|
||||
expires : timeout value in jiffies. The common I/O layer will terminate
|
||||
the running program after this and call the interrupt handler
|
||||
with ERR_PTR(-ETIMEDOUT) as irb.
|
||||
int ccw_device_start(struct ccw_device *cdev,
|
||||
struct ccw1 *cpa,
|
||||
unsigned long intparm,
|
||||
__u8 lpm,
|
||||
unsigned long flags);
|
||||
int ccw_device_start_timeout(struct ccw_device *cdev,
|
||||
struct ccw1 *cpa,
|
||||
unsigned long intparm,
|
||||
__u8 lpm,
|
||||
unsigned long flags,
|
||||
int expires);
|
||||
int ccw_device_start_key(struct ccw_device *cdev,
|
||||
struct ccw1 *cpa,
|
||||
unsigned long intparm,
|
||||
__u8 lpm,
|
||||
__u8 key,
|
||||
unsigned long flags);
|
||||
int ccw_device_start_key_timeout(struct ccw_device *cdev,
|
||||
struct ccw1 *cpa,
|
||||
unsigned long intparm,
|
||||
__u8 lpm,
|
||||
__u8 key,
|
||||
unsigned long flags,
|
||||
int expires);
|
||||
|
||||
Possible flag values are :
|
||||
============= =============================================================
|
||||
cdev ccw_device the I/O is destined for
|
||||
cpa logical start address of channel program
|
||||
user_intparm user specific interrupt information; will be presented
|
||||
back to the device driver's interrupt handler. Allows a
|
||||
device driver to associate the interrupt with a
|
||||
particular I/O request.
|
||||
lpm defines the channel path to be used for a specific I/O
|
||||
request. A value of 0 will make cio use the opm.
|
||||
key the storage key to use for the I/O (useful for operating on a
|
||||
storage with a storage key != default key)
|
||||
flag defines the action to be performed for I/O processing
|
||||
expires timeout value in jiffies. The common I/O layer will terminate
|
||||
the running program after this and call the interrupt handler
|
||||
with ERR_PTR(-ETIMEDOUT) as irb.
|
||||
============= =============================================================
|
||||
|
||||
DOIO_ALLOW_SUSPEND - channel program may become suspended
|
||||
DOIO_DENY_PREFETCH - don't allow for CCW prefetch; usually
|
||||
this implies the channel program might
|
||||
become modified
|
||||
DOIO_SUPPRESS_INTER - don't call the handler on intermediate status
|
||||
Possible flag values are:
|
||||
|
||||
The cpa parameter points to the first format 1 CCW of a channel program :
|
||||
========================= =============================================
|
||||
DOIO_ALLOW_SUSPEND channel program may become suspended
|
||||
DOIO_DENY_PREFETCH don't allow for CCW prefetch; usually
|
||||
this implies the channel program might
|
||||
become modified
|
||||
DOIO_SUPPRESS_INTER don't call the handler on intermediate status
|
||||
========================= =============================================
|
||||
|
||||
struct ccw1 {
|
||||
__u8 cmd_code;/* command code */
|
||||
__u8 flags; /* flags, like IDA addressing, etc. */
|
||||
__u16 count; /* byte count */
|
||||
__u32 cda; /* data address */
|
||||
} __attribute__ ((packed,aligned(8)));
|
||||
The cpa parameter points to the first format 1 CCW of a channel program::
|
||||
|
||||
with the following CCW flags values defined :
|
||||
struct ccw1 {
|
||||
__u8 cmd_code;/* command code */
|
||||
__u8 flags; /* flags, like IDA addressing, etc. */
|
||||
__u16 count; /* byte count */
|
||||
__u32 cda; /* data address */
|
||||
} __attribute__ ((packed,aligned(8)));
|
||||
|
||||
CCW_FLAG_DC - data chaining
|
||||
CCW_FLAG_CC - command chaining
|
||||
CCW_FLAG_SLI - suppress incorrect length
|
||||
CCW_FLAG_SKIP - skip
|
||||
CCW_FLAG_PCI - PCI
|
||||
CCW_FLAG_IDA - indirect addressing
|
||||
CCW_FLAG_SUSPEND - suspend
|
||||
with the following CCW flags values defined:
|
||||
|
||||
=================== =========================
|
||||
CCW_FLAG_DC data chaining
|
||||
CCW_FLAG_CC command chaining
|
||||
CCW_FLAG_SLI suppress incorrect length
|
||||
CCW_FLAG_SKIP skip
|
||||
CCW_FLAG_PCI PCI
|
||||
CCW_FLAG_IDA indirect addressing
|
||||
CCW_FLAG_SUSPEND suspend
|
||||
=================== =========================
|
||||
|
||||
|
||||
Via ccw_device_set_options(), the device driver may specify the following
|
||||
options for the device:
|
||||
|
||||
DOIO_EARLY_NOTIFICATION - allow for early interrupt notification
|
||||
DOIO_REPORT_ALL - report all interrupt conditions
|
||||
========================= ======================================
|
||||
DOIO_EARLY_NOTIFICATION allow for early interrupt notification
|
||||
DOIO_REPORT_ALL report all interrupt conditions
|
||||
========================= ======================================
|
||||
|
||||
|
||||
The ccw_device_start() function returns :
|
||||
The ccw_device_start() function returns:
|
||||
|
||||
0 - successful completion or request successfully initiated
|
||||
-EBUSY - The device is currently processing a previous I/O request, or there is
|
||||
a status pending at the device.
|
||||
-ENODEV - cdev is invalid, the device is not operational or the ccw_device is
|
||||
not online.
|
||||
======== ======================================================================
|
||||
0 successful completion or request successfully initiated
|
||||
-EBUSY The device is currently processing a previous I/O request, or there is
|
||||
a status pending at the device.
|
||||
-ENODEV cdev is invalid, the device is not operational or the ccw_device is
|
||||
not online.
|
||||
======== ======================================================================
|
||||
|
||||
When the I/O request completes, the CDS first level interrupt handler will
|
||||
accumulate the status in a struct irb and then call the device interrupt handler.
|
||||
The intparm field will contain the value the device driver has associated with a
|
||||
particular I/O request. If a pending device status was recognized,
|
||||
The intparm field will contain the value the device driver has associated with a
|
||||
particular I/O request. If a pending device status was recognized,
|
||||
intparm will be set to 0 (zero). This may happen during I/O initiation or delayed
|
||||
by an alert status notification. In any case this status is not related to the
|
||||
current (last) I/O request. In case of a delayed status notification no special
|
||||
@ -282,9 +309,11 @@ never started, even though ccw_device_start() returned with successful completio
|
||||
The irb may contain an error value, and the device driver should check for this
|
||||
first:
|
||||
|
||||
-ETIMEDOUT: the common I/O layer terminated the request after the specified
|
||||
timeout value
|
||||
-EIO: the common I/O layer terminated the request due to an error state
|
||||
========== =================================================================
|
||||
-ETIMEDOUT the common I/O layer terminated the request after the specified
|
||||
timeout value
|
||||
-EIO the common I/O layer terminated the request due to an error state
|
||||
========== =================================================================
|
||||
|
||||
If the concurrent sense flag in the extended status word (esw) in the irb is
|
||||
set, the field erw.scnt in the esw describes the number of device specific
|
||||
@ -294,6 +323,7 @@ sensing by the device driver itself is required.
|
||||
The device interrupt handler can use the following definitions to investigate
|
||||
the primary unit check source coded in sense byte 0 :
|
||||
|
||||
======================= ====
|
||||
SNS0_CMD_REJECT 0x80
|
||||
SNS0_INTERVENTION_REQ 0x40
|
||||
SNS0_BUS_OUT_CHECK 0x20
|
||||
@ -301,36 +331,41 @@ SNS0_EQUIPMENT_CHECK 0x10
|
||||
SNS0_DATA_CHECK 0x08
|
||||
SNS0_OVERRUN 0x04
|
||||
SNS0_INCOMPL_DOMAIN 0x01
|
||||
======================= ====
|
||||
|
||||
Depending on the device status, multiple of those values may be set together.
|
||||
Please refer to the device specific documentation for details.
|
||||
|
||||
The irb->scsw.cstat field provides the (accumulated) subchannel status :
|
||||
|
||||
SCHN_STAT_PCI - program controlled interrupt
|
||||
SCHN_STAT_INCORR_LEN - incorrect length
|
||||
SCHN_STAT_PROG_CHECK - program check
|
||||
SCHN_STAT_PROT_CHECK - protection check
|
||||
SCHN_STAT_CHN_DATA_CHK - channel data check
|
||||
SCHN_STAT_CHN_CTRL_CHK - channel control check
|
||||
SCHN_STAT_INTF_CTRL_CHK - interface control check
|
||||
SCHN_STAT_CHAIN_CHECK - chaining check
|
||||
========================= ============================
|
||||
SCHN_STAT_PCI program controlled interrupt
|
||||
SCHN_STAT_INCORR_LEN incorrect length
|
||||
SCHN_STAT_PROG_CHECK program check
|
||||
SCHN_STAT_PROT_CHECK protection check
|
||||
SCHN_STAT_CHN_DATA_CHK channel data check
|
||||
SCHN_STAT_CHN_CTRL_CHK channel control check
|
||||
SCHN_STAT_INTF_CTRL_CHK interface control check
|
||||
SCHN_STAT_CHAIN_CHECK chaining check
|
||||
========================= ============================
|
||||
|
||||
The irb->scsw.dstat field provides the (accumulated) device status :
|
||||
|
||||
DEV_STAT_ATTENTION - attention
|
||||
DEV_STAT_STAT_MOD - status modifier
|
||||
DEV_STAT_CU_END - control unit end
|
||||
DEV_STAT_BUSY - busy
|
||||
DEV_STAT_CHN_END - channel end
|
||||
DEV_STAT_DEV_END - device end
|
||||
DEV_STAT_UNIT_CHECK - unit check
|
||||
DEV_STAT_UNIT_EXCEP - unit exception
|
||||
===================== =================
|
||||
DEV_STAT_ATTENTION attention
|
||||
DEV_STAT_STAT_MOD status modifier
|
||||
DEV_STAT_CU_END control unit end
|
||||
DEV_STAT_BUSY busy
|
||||
DEV_STAT_CHN_END channel end
|
||||
DEV_STAT_DEV_END device end
|
||||
DEV_STAT_UNIT_CHECK unit check
|
||||
DEV_STAT_UNIT_EXCEP unit exception
|
||||
===================== =================
|
||||
|
||||
Please see the ESA/390 Principles of Operation manual for details on the
|
||||
individual flag meanings.
|
||||
|
||||
Usage Notes :
|
||||
Usage Notes:
|
||||
|
||||
ccw_device_start() must be called disabled and with the ccw device lock held.
|
||||
|
||||
@ -374,32 +409,39 @@ secondary status without error (alert status) is presented, this indicates
|
||||
successful completion for all overlapping ccw_device_start() requests that have
|
||||
been issued since the last secondary (final) status.
|
||||
|
||||
Channel programs that intend to set the suspend flag on a channel command word
|
||||
(CCW) must start the I/O operation with the DOIO_ALLOW_SUSPEND option or the
|
||||
suspend flag will cause a channel program check. At the time the channel program
|
||||
becomes suspended an intermediate interrupt will be generated by the channel
|
||||
Channel programs that intend to set the suspend flag on a channel command word
|
||||
(CCW) must start the I/O operation with the DOIO_ALLOW_SUSPEND option or the
|
||||
suspend flag will cause a channel program check. At the time the channel program
|
||||
becomes suspended an intermediate interrupt will be generated by the channel
|
||||
subsystem.
|
||||
|
||||
ccw_device_resume() - Resume Channel Program Execution
|
||||
ccw_device_resume() - Resume Channel Program Execution
|
||||
|
||||
If a device driver chooses to suspend the current channel program execution by
|
||||
setting the CCW suspend flag on a particular CCW, the channel program execution
|
||||
is suspended. In order to resume channel program execution the CIO layer
|
||||
provides the ccw_device_resume() routine.
|
||||
If a device driver chooses to suspend the current channel program execution by
|
||||
setting the CCW suspend flag on a particular CCW, the channel program execution
|
||||
is suspended. In order to resume channel program execution the CIO layer
|
||||
provides the ccw_device_resume() routine.
|
||||
|
||||
int ccw_device_resume(struct ccw_device *cdev);
|
||||
::
|
||||
|
||||
cdev - ccw_device the resume operation is requested for
|
||||
int ccw_device_resume(struct ccw_device *cdev);
|
||||
|
||||
==== ================================================
|
||||
cdev ccw_device the resume operation is requested for
|
||||
==== ================================================
|
||||
|
||||
The ccw_device_resume() function returns:
|
||||
|
||||
0 - suspended channel program is resumed
|
||||
-EBUSY - status pending
|
||||
-ENODEV - cdev invalid or not-operational subchannel
|
||||
-EINVAL - resume function not applicable
|
||||
-ENOTCONN - there is no I/O request pending for completion
|
||||
========= ==============================================
|
||||
0 suspended channel program is resumed
|
||||
-EBUSY status pending
|
||||
-ENODEV cdev invalid or not-operational subchannel
|
||||
-EINVAL resume function not applicable
|
||||
-ENOTCONN there is no I/O request pending for completion
|
||||
========= ==============================================
|
||||
|
||||
Usage Notes:
|
||||
|
||||
Please have a look at the ccw_device_start() usage notes for more details on
|
||||
suspended channel programs.
|
||||
|
||||
@ -412,22 +454,28 @@ command is provided.
|
||||
|
||||
ccw_device_halt() must be called disabled and with the ccw device lock held.
|
||||
|
||||
int ccw_device_halt(struct ccw_device *cdev,
|
||||
unsigned long intparm);
|
||||
::
|
||||
|
||||
cdev : ccw_device the halt operation is requested for
|
||||
intparm : interruption parameter; value is only used if no I/O
|
||||
is outstanding, otherwise the intparm associated with
|
||||
the I/O request is returned
|
||||
int ccw_device_halt(struct ccw_device *cdev,
|
||||
unsigned long intparm);
|
||||
|
||||
The ccw_device_halt() function returns :
|
||||
======= =====================================================
|
||||
cdev ccw_device the halt operation is requested for
|
||||
intparm interruption parameter; value is only used if no I/O
|
||||
is outstanding, otherwise the intparm associated with
|
||||
the I/O request is returned
|
||||
======= =====================================================
|
||||
|
||||
0 - request successfully initiated
|
||||
-EBUSY - the device is currently busy, or status pending.
|
||||
-ENODEV - cdev invalid.
|
||||
-EINVAL - The device is not operational or the ccw device is not online.
|
||||
The ccw_device_halt() function returns:
|
||||
|
||||
Usage Notes :
|
||||
======= ==============================================================
|
||||
0 request successfully initiated
|
||||
-EBUSY the device is currently busy, or status pending.
|
||||
-ENODEV cdev invalid.
|
||||
-EINVAL The device is not operational or the ccw device is not online.
|
||||
======= ==============================================================
|
||||
|
||||
Usage Notes:
|
||||
|
||||
A device driver may write a never-ending channel program by writing a channel
|
||||
program that at its end loops back to its beginning by means of a transfer in
|
||||
@ -438,25 +486,34 @@ can then perform an appropriate action. Prior to interrupt of an outstanding
|
||||
read to a network device (with or without PCI flag) a ccw_device_halt()
|
||||
is required to end the pending operation.
|
||||
|
||||
ccw_device_clear() - Terminage I/O Request Processing
|
||||
::
|
||||
|
||||
ccw_device_clear() - Terminage I/O Request Processing
|
||||
|
||||
In order to terminate all I/O processing at the subchannel, the clear subchannel
|
||||
(CSCH) command is used. It can be issued via ccw_device_clear().
|
||||
|
||||
ccw_device_clear() must be called disabled and with the ccw device lock held.
|
||||
|
||||
int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm);
|
||||
::
|
||||
|
||||
cdev: ccw_device the clear operation is requested for
|
||||
intparm: interruption parameter (see ccw_device_halt())
|
||||
int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm);
|
||||
|
||||
======= ===============================================
|
||||
cdev ccw_device the clear operation is requested for
|
||||
intparm interruption parameter (see ccw_device_halt())
|
||||
======= ===============================================
|
||||
|
||||
The ccw_device_clear() function returns:
|
||||
|
||||
0 - request successfully initiated
|
||||
-ENODEV - cdev invalid
|
||||
-EINVAL - The device is not operational or the ccw device is not online.
|
||||
======= ==============================================================
|
||||
0 request successfully initiated
|
||||
-ENODEV cdev invalid
|
||||
-EINVAL The device is not operational or the ccw device is not online.
|
||||
======= ==============================================================
|
||||
|
||||
Miscellaneous Support Routines
|
||||
------------------------------
|
||||
|
||||
This chapter describes various routines to be used in a Linux/390 device
|
||||
driver programming environment.
|
||||
@ -466,7 +523,8 @@ get_ccwdev_lock()
|
||||
Get the address of the device specific lock. This is then used in
|
||||
spin_lock() / spin_unlock() calls.
|
||||
|
||||
::
|
||||
|
||||
__u8 ccw_device_get_path_mask(struct ccw_device *cdev);
|
||||
__u8 ccw_device_get_path_mask(struct ccw_device *cdev);
|
||||
|
||||
Get the mask of the path currently available for cdev.
|
@ -1,5 +1,9 @@
|
||||
S/390 common I/O-Layer - command line parameters, procfs and debugfs entries
|
||||
============================================================================
|
||||
======================
|
||||
S/390 common I/O-Layer
|
||||
======================
|
||||
|
||||
command line parameters, procfs and debugfs entries
|
||||
===================================================
|
||||
|
||||
Command line parameters
|
||||
-----------------------
|
||||
@ -13,7 +17,7 @@ Command line parameters
|
||||
device := {all | [!]ipldev | [!]condev | [!]<devno> | [!]<devno>-<devno>}
|
||||
|
||||
The given devices will be ignored by the common I/O-layer; no detection
|
||||
and device sensing will be done on any of those devices. The subchannel to
|
||||
and device sensing will be done on any of those devices. The subchannel to
|
||||
which the device in question is attached will be treated as if no device was
|
||||
attached.
|
||||
|
||||
@ -28,14 +32,20 @@ Command line parameters
|
||||
keywords can be used to refer to the CCW based boot device and CCW console
|
||||
device respectively (these are probably useful only when combined with the '!'
|
||||
operator). The '!' operator will cause the I/O-layer to _not_ ignore a device.
|
||||
The command line is parsed from left to right.
|
||||
The command line
|
||||
is parsed from left to right.
|
||||
|
||||
For example::
|
||||
|
||||
For example,
|
||||
cio_ignore=0.0.0023-0.0.0042,0.0.4711
|
||||
|
||||
will ignore all devices ranging from 0.0.0023 to 0.0.0042 and the device
|
||||
0.0.4711, if detected.
|
||||
As another example,
|
||||
|
||||
As another example::
|
||||
|
||||
cio_ignore=all,!0.0.4711,!0.0.fd00-0.0.fd02
|
||||
|
||||
will ignore all devices but 0.0.4711, 0.0.fd00, 0.0.fd01, 0.0.fd02.
|
||||
|
||||
By default, no devices are ignored.
|
||||
@ -48,40 +58,45 @@ Command line parameters
|
||||
|
||||
Lists the ranges of devices (by bus id) which are ignored by common I/O.
|
||||
|
||||
You can un-ignore certain or all devices by piping to /proc/cio_ignore.
|
||||
"free all" will un-ignore all ignored devices,
|
||||
You can un-ignore certain or all devices by piping to /proc/cio_ignore.
|
||||
"free all" will un-ignore all ignored devices,
|
||||
"free <device range>, <device range>, ..." will un-ignore the specified
|
||||
devices.
|
||||
|
||||
For example, if devices 0.0.0023 to 0.0.0042 and 0.0.4711 are ignored,
|
||||
|
||||
- echo free 0.0.0030-0.0.0032 > /proc/cio_ignore
|
||||
will un-ignore devices 0.0.0030 to 0.0.0032 and will leave devices 0.0.0023
|
||||
to 0.0.002f, 0.0.0033 to 0.0.0042 and 0.0.4711 ignored;
|
||||
- echo free 0.0.0041 > /proc/cio_ignore will furthermore un-ignore device
|
||||
0.0.0041;
|
||||
- echo free all > /proc/cio_ignore will un-ignore all remaining ignored
|
||||
- echo free all > /proc/cio_ignore will un-ignore all remaining ignored
|
||||
devices.
|
||||
|
||||
When a device is un-ignored, device recognition and sensing is performed and
|
||||
When a device is un-ignored, device recognition and sensing is performed and
|
||||
the device driver will be notified if possible, so the device will become
|
||||
available to the system. Note that un-ignoring is performed asynchronously.
|
||||
|
||||
You can also add ranges of devices to be ignored by piping to
|
||||
You can also add ranges of devices to be ignored by piping to
|
||||
/proc/cio_ignore; "add <device range>, <device range>, ..." will ignore the
|
||||
specified devices.
|
||||
|
||||
Note: While already known devices can be added to the list of devices to be
|
||||
ignored, there will be no effect on then. However, if such a device
|
||||
ignored, there will be no effect on then. However, if such a device
|
||||
disappears and then reappears, it will then be ignored. To make
|
||||
known devices go away, you need the "purge" command (see below).
|
||||
|
||||
For example,
|
||||
For example::
|
||||
|
||||
"echo add 0.0.a000-0.0.accc, 0.0.af00-0.0.afff > /proc/cio_ignore"
|
||||
|
||||
will add 0.0.a000-0.0.accc and 0.0.af00-0.0.afff to the list of ignored
|
||||
devices.
|
||||
|
||||
You can remove already known but now ignored devices via
|
||||
You can remove already known but now ignored devices via::
|
||||
|
||||
"echo purge > /proc/cio_ignore"
|
||||
|
||||
All devices ignored but still registered and not online (= not in use)
|
||||
will be deregistered and thus removed from the system.
|
||||
|
||||
@ -115,11 +130,11 @@ debugfs entries
|
||||
Various debug messages from the common I/O-layer.
|
||||
|
||||
- /sys/kernel/debug/s390dbf/cio_trace/hex_ascii
|
||||
Logs the calling of functions in the common I/O-layer and, if applicable,
|
||||
Logs the calling of functions in the common I/O-layer and, if applicable,
|
||||
which subchannel they were called for, as well as dumps of some data
|
||||
structures (like irb in an error case).
|
||||
|
||||
The level of logging can be changed to be more or less verbose by piping to
|
||||
The level of logging can be changed to be more or less verbose by piping to
|
||||
/sys/kernel/debug/s390dbf/cio_*/level a number between 0 and 6; see the
|
||||
documentation on the S/390 debug feature (Documentation/s390/s390dbf.txt)
|
||||
documentation on the S/390 debug feature (Documentation/s390/s390dbf.rst)
|
||||
for details.
|
@ -1,4 +1,6 @@
|
||||
==================
|
||||
DASD device driver
|
||||
==================
|
||||
|
||||
S/390's disk devices (DASDs) are managed by Linux via the DASD device
|
||||
driver. It is valid for all types of DASDs and represents them to
|
||||
@ -14,14 +16,14 @@ parameters are to be given in hexadecimal notation without a leading
|
||||
If you supply kernel parameters the different instances are processed
|
||||
in order of appearance and a minor number is reserved for any device
|
||||
covered by the supplied range up to 64 volumes. Additional DASDs are
|
||||
ignored. If you do not supply the 'dasd=' kernel parameter at all, the
|
||||
ignored. If you do not supply the 'dasd=' kernel parameter at all, the
|
||||
DASD driver registers all supported DASDs of your system to a minor
|
||||
number in ascending order of the subchannel number.
|
||||
|
||||
The driver currently supports ECKD-devices and there are stubs for
|
||||
support of the FBA and CKD architectures. For the FBA architecture
|
||||
only some smart data structures are missing to make the support
|
||||
complete.
|
||||
complete.
|
||||
We performed our testing on 3380 and 3390 type disks of different
|
||||
sizes, under VM and on the bare hardware (LPAR), using internal disks
|
||||
of the multiprise as well as a RAMAC virtual array. Disks exported by
|
||||
@ -34,19 +36,22 @@ accessibility of the DASD from other OSs. In a later stage we will
|
||||
provide support of partitions, maybe VTOC oriented or using a kind of
|
||||
partition table in the label record.
|
||||
|
||||
USAGE
|
||||
Usage
|
||||
=====
|
||||
|
||||
-Low-level format (?CKD only)
|
||||
For using an ECKD-DASD as a Linux harddisk you have to low-level
|
||||
format the tracks by issuing the BLKDASDFORMAT-ioctl on that
|
||||
device. This will erase any data on that volume including IBM volume
|
||||
labels, VTOCs etc. The ioctl may take a 'struct format_data *' or
|
||||
'NULL' as an argument.
|
||||
typedef struct {
|
||||
labels, VTOCs etc. The ioctl may take a `struct format_data *` or
|
||||
'NULL' as an argument::
|
||||
|
||||
typedef struct {
|
||||
int start_unit;
|
||||
int stop_unit;
|
||||
int blksize;
|
||||
} format_data_t;
|
||||
} format_data_t;
|
||||
|
||||
When a NULL argument is passed to the BLKDASDFORMAT ioctl the whole
|
||||
disk is formatted to a blocksize of 1024 bytes. Otherwise start_unit
|
||||
and stop_unit are the first and last track to be formatted. If
|
||||
@ -56,17 +61,23 @@ up to the last track. blksize can be any power of two between 512 and
|
||||
1kB blocks anyway and you gain approx. 50% of capacity increasing your
|
||||
blksize from 512 byte to 1kB.
|
||||
|
||||
-Make a filesystem
|
||||
Make a filesystem
|
||||
=================
|
||||
|
||||
Then you can mk??fs the filesystem of your choice on that volume or
|
||||
partition. For reasons of sanity you should build your filesystem on
|
||||
the partition /dev/dd?1 instead of the whole volume. You only lose 3kB
|
||||
the partition /dev/dd?1 instead of the whole volume. You only lose 3kB
|
||||
but may be sure that you can reuse your data after introduction of a
|
||||
real partition table.
|
||||
|
||||
BUGS:
|
||||
Bugs
|
||||
====
|
||||
|
||||
- Performance sometimes is rather low because we don't fully exploit clustering
|
||||
|
||||
TODO-List:
|
||||
TODO-List
|
||||
=========
|
||||
|
||||
- Add IBM'S Disk layout to genhd
|
||||
- Enhance driver to use more than one major number
|
||||
- Enable usage as a module
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,6 @@
|
||||
=============================
|
||||
S/390 driver model interfaces
|
||||
-----------------------------
|
||||
=============================
|
||||
|
||||
1. CCW devices
|
||||
--------------
|
||||
@ -7,13 +8,13 @@ S/390 driver model interfaces
|
||||
All devices which can be addressed by means of ccws are called 'CCW devices' -
|
||||
even if they aren't actually driven by ccws.
|
||||
|
||||
All ccw devices are accessed via a subchannel, this is reflected in the
|
||||
structures under devices/:
|
||||
All ccw devices are accessed via a subchannel, this is reflected in the
|
||||
structures under devices/::
|
||||
|
||||
devices/
|
||||
devices/
|
||||
- system/
|
||||
- css0/
|
||||
- 0.0.0000/0.0.0815/
|
||||
- 0.0.0000/0.0.0815/
|
||||
- 0.0.0001/0.0.4711/
|
||||
- 0.0.0002/
|
||||
- 0.1.0000/0.1.1234/
|
||||
@ -35,14 +36,18 @@ be found under bus/ccw/devices/.
|
||||
|
||||
All ccw devices export some data via sysfs.
|
||||
|
||||
cutype: The control unit type / model.
|
||||
cutype:
|
||||
The control unit type / model.
|
||||
|
||||
devtype: The device type / model, if applicable.
|
||||
devtype:
|
||||
The device type / model, if applicable.
|
||||
|
||||
availability: Can be 'good' or 'boxed'; 'no path' or 'no device' for
|
||||
availability:
|
||||
Can be 'good' or 'boxed'; 'no path' or 'no device' for
|
||||
disconnected devices.
|
||||
|
||||
online: An interface to set the device online and offline.
|
||||
online:
|
||||
An interface to set the device online and offline.
|
||||
In the special case of the device being disconnected (see the
|
||||
notify function under 1.2), piping 0 to online will forcibly delete
|
||||
the device.
|
||||
@ -52,9 +57,11 @@ The device drivers can add entries to export per-device data and interfaces.
|
||||
There is also some data exported on a per-subchannel basis (see under
|
||||
bus/css/devices/):
|
||||
|
||||
chpids: Via which chpids the device is connected.
|
||||
chpids:
|
||||
Via which chpids the device is connected.
|
||||
|
||||
pimpampom: The path installed, path available and path operational masks.
|
||||
pimpampom:
|
||||
The path installed, path available and path operational masks.
|
||||
|
||||
There also might be additional data, for example for block devices.
|
||||
|
||||
@ -74,77 +81,93 @@ b. After a. has been performed, if necessary, the device is finally brought up
|
||||
------------------------------------
|
||||
|
||||
The basic struct ccw_device and struct ccw_driver data structures can be found
|
||||
under include/asm/ccwdev.h.
|
||||
under include/asm/ccwdev.h::
|
||||
|
||||
struct ccw_device {
|
||||
spinlock_t *ccwlock;
|
||||
struct ccw_device_private *private;
|
||||
struct ccw_device_id id;
|
||||
struct ccw_device {
|
||||
spinlock_t *ccwlock;
|
||||
struct ccw_device_private *private;
|
||||
struct ccw_device_id id;
|
||||
|
||||
struct ccw_driver *drv;
|
||||
struct device dev;
|
||||
struct ccw_driver *drv;
|
||||
struct device dev;
|
||||
int online;
|
||||
|
||||
void (*handler) (struct ccw_device *dev, unsigned long intparm,
|
||||
struct irb *irb);
|
||||
};
|
||||
struct irb *irb);
|
||||
};
|
||||
|
||||
struct ccw_driver {
|
||||
struct module *owner;
|
||||
struct ccw_device_id *ids;
|
||||
int (*probe) (struct ccw_device *);
|
||||
struct ccw_driver {
|
||||
struct module *owner;
|
||||
struct ccw_device_id *ids;
|
||||
int (*probe) (struct ccw_device *);
|
||||
int (*remove) (struct ccw_device *);
|
||||
int (*set_online) (struct ccw_device *);
|
||||
int (*set_offline) (struct ccw_device *);
|
||||
int (*notify) (struct ccw_device *, int);
|
||||
struct device_driver driver;
|
||||
char *name;
|
||||
};
|
||||
};
|
||||
|
||||
The 'private' field contains data needed for internal i/o operation only, and
|
||||
is not available to the device driver.
|
||||
|
||||
Each driver should declare in a MODULE_DEVICE_TABLE into which CU types/models
|
||||
and/or device types/models it is interested. This information can later be found
|
||||
in the struct ccw_device_id fields:
|
||||
in the struct ccw_device_id fields::
|
||||
|
||||
struct ccw_device_id {
|
||||
__u16 match_flags;
|
||||
struct ccw_device_id {
|
||||
__u16 match_flags;
|
||||
|
||||
__u16 cu_type;
|
||||
__u16 dev_type;
|
||||
__u8 cu_model;
|
||||
__u8 dev_model;
|
||||
__u16 cu_type;
|
||||
__u16 dev_type;
|
||||
__u8 cu_model;
|
||||
__u8 dev_model;
|
||||
|
||||
unsigned long driver_info;
|
||||
};
|
||||
};
|
||||
|
||||
The functions in ccw_driver should be used in the following way:
|
||||
probe: This function is called by the device layer for each device the driver
|
||||
|
||||
probe:
|
||||
This function is called by the device layer for each device the driver
|
||||
is interested in. The driver should only allocate private structures
|
||||
to put in dev->driver_data and create attributes (if needed). Also,
|
||||
the interrupt handler (see below) should be set here.
|
||||
|
||||
int (*probe) (struct ccw_device *cdev);
|
||||
::
|
||||
|
||||
Parameters: cdev - the device to be probed.
|
||||
int (*probe) (struct ccw_device *cdev);
|
||||
|
||||
Parameters:
|
||||
cdev
|
||||
- the device to be probed.
|
||||
|
||||
|
||||
remove: This function is called by the device layer upon removal of the driver,
|
||||
remove:
|
||||
This function is called by the device layer upon removal of the driver,
|
||||
the device or the module. The driver should perform cleanups here.
|
||||
|
||||
int (*remove) (struct ccw_device *cdev);
|
||||
::
|
||||
|
||||
Parameters: cdev - the device to be removed.
|
||||
int (*remove) (struct ccw_device *cdev);
|
||||
|
||||
Parameters:
|
||||
cdev
|
||||
- the device to be removed.
|
||||
|
||||
|
||||
set_online: This function is called by the common I/O layer when the device is
|
||||
set_online:
|
||||
This function is called by the common I/O layer when the device is
|
||||
activated via the 'online' attribute. The driver should finally
|
||||
setup and activate the device here.
|
||||
|
||||
int (*set_online) (struct ccw_device *);
|
||||
::
|
||||
|
||||
Parameters: cdev - the device to be activated. The common layer has
|
||||
int (*set_online) (struct ccw_device *);
|
||||
|
||||
Parameters:
|
||||
cdev
|
||||
- the device to be activated. The common layer has
|
||||
verified that the device is not already online.
|
||||
|
||||
|
||||
@ -152,15 +175,22 @@ set_offline: This function is called by the common I/O layer when the device is
|
||||
de-activated via the 'online' attribute. The driver should shut
|
||||
down the device, but not de-allocate its private data.
|
||||
|
||||
int (*set_offline) (struct ccw_device *);
|
||||
::
|
||||
|
||||
Parameters: cdev - the device to be deactivated. The common layer has
|
||||
int (*set_offline) (struct ccw_device *);
|
||||
|
||||
Parameters:
|
||||
cdev
|
||||
- the device to be deactivated. The common layer has
|
||||
verified that the device is online.
|
||||
|
||||
|
||||
notify: This function is called by the common I/O layer for some state changes
|
||||
notify:
|
||||
This function is called by the common I/O layer for some state changes
|
||||
of the device.
|
||||
|
||||
Signalled to the driver are:
|
||||
|
||||
* In online state, device detached (CIO_GONE) or last path gone
|
||||
(CIO_NO_PATH). The driver must return !0 to keep the device; for
|
||||
return code 0, the device will be deleted as usual (also when no
|
||||
@ -173,32 +203,40 @@ notify: This function is called by the common I/O layer for some state changes
|
||||
return code of the notify function the device driver signals if it
|
||||
wants the device back: !0 for keeping, 0 to make the device being
|
||||
removed and re-registered.
|
||||
|
||||
int (*notify) (struct ccw_device *, int);
|
||||
|
||||
Parameters: cdev - the device whose state changed.
|
||||
event - the event that happened. This can be one of CIO_GONE,
|
||||
CIO_NO_PATH or CIO_OPER.
|
||||
::
|
||||
|
||||
int (*notify) (struct ccw_device *, int);
|
||||
|
||||
Parameters:
|
||||
cdev
|
||||
- the device whose state changed.
|
||||
|
||||
event
|
||||
- the event that happened. This can be one of CIO_GONE,
|
||||
CIO_NO_PATH or CIO_OPER.
|
||||
|
||||
The handler field of the struct ccw_device is meant to be set to the interrupt
|
||||
handler for the device. In order to accommodate drivers which use several
|
||||
handler for the device. In order to accommodate drivers which use several
|
||||
distinct handlers (e.g. multi subchannel devices), this is a member of ccw_device
|
||||
instead of ccw_driver.
|
||||
The handler is registered with the common layer during set_online() processing
|
||||
before the driver is called, and is deregistered during set_offline() after the
|
||||
driver has been called. Also, after registering / before deregistering, path
|
||||
driver has been called. Also, after registering / before deregistering, path
|
||||
grouping resp. disbanding of the path group (if applicable) are performed.
|
||||
|
||||
void (*handler) (struct ccw_device *dev, unsigned long intparm, struct irb *irb);
|
||||
::
|
||||
|
||||
Parameters: dev - the device the handler is called for
|
||||
void (*handler) (struct ccw_device *dev, unsigned long intparm, struct irb *irb);
|
||||
|
||||
Parameters: dev - the device the handler is called for
|
||||
intparm - the intparm which allows the device driver to identify
|
||||
the i/o the interrupt is associated with, or to recognize
|
||||
the interrupt as unsolicited.
|
||||
irb - interruption response block which contains the accumulated
|
||||
status.
|
||||
the i/o the interrupt is associated with, or to recognize
|
||||
the interrupt as unsolicited.
|
||||
irb - interruption response block which contains the accumulated
|
||||
status.
|
||||
|
||||
The device driver is called from the common ccw_device layer and can retrieve
|
||||
The device driver is called from the common ccw_device layer and can retrieve
|
||||
information about the interrupt from the irb parameter.
|
||||
|
||||
|
||||
@ -237,23 +275,27 @@ only the logical state and not the physical state, since we cannot track the
|
||||
latter consistently due to lacking machine support (we don't need to be aware
|
||||
of it anyway).
|
||||
|
||||
status - Can be 'online' or 'offline'.
|
||||
status
|
||||
- Can be 'online' or 'offline'.
|
||||
Piping 'on' or 'off' sets the chpid logically online/offline.
|
||||
Piping 'on' to an online chpid triggers path reprobing for all devices
|
||||
the chpid connects to. This can be used to force the kernel to re-use
|
||||
a channel path the user knows to be online, but the machine hasn't
|
||||
created a machine check for.
|
||||
|
||||
type - The physical type of the channel path.
|
||||
type
|
||||
- The physical type of the channel path.
|
||||
|
||||
shared - Whether the channel path is shared.
|
||||
shared
|
||||
- Whether the channel path is shared.
|
||||
|
||||
cmg - The channel measurement group.
|
||||
cmg
|
||||
- The channel measurement group.
|
||||
|
||||
3. System devices
|
||||
-----------------
|
||||
|
||||
3.1 xpram
|
||||
3.1 xpram
|
||||
---------
|
||||
|
||||
xpram shows up under devices/system/ as 'xpram'.
|
||||
@ -279,9 +321,8 @@ Netiucv connections show up under devices/iucv/ as "netiucv<ifnum>". The interfa
|
||||
number is assigned sequentially to the connections defined via the 'connection'
|
||||
attribute.
|
||||
|
||||
user - shows the connection partner.
|
||||
|
||||
buffer - maximum buffer size.
|
||||
Pipe to it to change buffer size.
|
||||
|
||||
user
|
||||
- shows the connection partner.
|
||||
|
||||
buffer
|
||||
- maximum buffer size. Pipe to it to change buffer size.
|
30
Documentation/s390/index.rst
Normal file
30
Documentation/s390/index.rst
Normal file
@ -0,0 +1,30 @@
|
||||
:orphan:
|
||||
|
||||
=================
|
||||
s390 Architecture
|
||||
=================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
cds
|
||||
3270
|
||||
debugging390
|
||||
driver-model
|
||||
monreader
|
||||
qeth
|
||||
s390dbf
|
||||
vfio-ap
|
||||
vfio-ccw
|
||||
zfcpdump
|
||||
dasd
|
||||
common_io
|
||||
|
||||
text_files
|
||||
|
||||
.. only:: subproject and html
|
||||
|
||||
Indices
|
||||
=======
|
||||
|
||||
* :ref:`genindex`
|
@ -1,24 +1,26 @@
|
||||
=================================================
|
||||
Linux API for read access to z/VM Monitor Records
|
||||
=================================================
|
||||
|
||||
Date : 2004-Nov-26
|
||||
|
||||
Author: Gerald Schaefer (geraldsc@de.ibm.com)
|
||||
|
||||
|
||||
Linux API for read access to z/VM Monitor Records
|
||||
=================================================
|
||||
|
||||
|
||||
Description
|
||||
===========
|
||||
This item delivers a new Linux API in the form of a misc char device that is
|
||||
usable from user space and allows read access to the z/VM Monitor Records
|
||||
collected by the *MONITOR System Service of z/VM.
|
||||
collected by the `*MONITOR` System Service of z/VM.
|
||||
|
||||
|
||||
User Requirements
|
||||
=================
|
||||
The z/VM guest on which you want to access this API needs to be configured in
|
||||
order to allow IUCV connections to the *MONITOR service, i.e. it needs the
|
||||
IUCV *MONITOR statement in its user entry. If the monitor DCSS to be used is
|
||||
order to allow IUCV connections to the `*MONITOR` service, i.e. it needs the
|
||||
IUCV `*MONITOR` statement in its user entry. If the monitor DCSS to be used is
|
||||
restricted (likely), you also need the NAMESAVE <DCSS NAME> statement.
|
||||
This item will use the IUCV device driver to access the z/VM services, so you
|
||||
need a kernel with IUCV support. You also need z/VM version 4.4 or 5.1.
|
||||
@ -50,7 +52,9 @@ Your guest virtual storage has to end below the starting address of the DCSS
|
||||
and you have to specify the "mem=" kernel parameter in your parmfile with a
|
||||
value greater than the ending address of the DCSS.
|
||||
|
||||
Example: DEF STOR 140M
|
||||
Example::
|
||||
|
||||
DEF STOR 140M
|
||||
|
||||
This defines 140MB storage size for your guest, the parameter "mem=160M" is
|
||||
added to the parmfile.
|
||||
@ -66,24 +70,27 @@ kernel, the kernel parameter "monreader.mondcss=<DCSS NAME>" can be specified
|
||||
in the parmfile.
|
||||
|
||||
The default name for the DCSS is "MONDCSS" if none is specified. In case that
|
||||
there are other users already connected to the *MONITOR service (e.g.
|
||||
there are other users already connected to the `*MONITOR` service (e.g.
|
||||
Performance Toolkit), the monitor DCSS is already defined and you have to use
|
||||
the same DCSS. The CP command Q MONITOR (Class E privileged) shows the name
|
||||
of the monitor DCSS, if already defined, and the users connected to the
|
||||
*MONITOR service.
|
||||
`*MONITOR` service.
|
||||
Refer to the "z/VM Performance" book (SC24-6109-00) on how to create a monitor
|
||||
DCSS if your z/VM doesn't have one already, you need Class E privileges to
|
||||
define and save a DCSS.
|
||||
|
||||
Example:
|
||||
--------
|
||||
modprobe monreader mondcss=MYDCSS
|
||||
|
||||
::
|
||||
|
||||
modprobe monreader mondcss=MYDCSS
|
||||
|
||||
This loads the module and sets the DCSS name to "MYDCSS".
|
||||
|
||||
NOTE:
|
||||
-----
|
||||
This API provides no interface to control the *MONITOR service, e.g. specify
|
||||
This API provides no interface to control the `*MONITOR` service, e.g. specify
|
||||
which data should be collected. This can be done by the CP command MONITOR
|
||||
(Class E privileged), see "CP Command and Utility Reference".
|
||||
|
||||
@ -98,6 +105,7 @@ If your distribution does not support udev, a device node will not be created
|
||||
automatically and you have to create it manually after loading the module.
|
||||
Therefore you need to know the major and minor numbers of the device. These
|
||||
numbers can be found in /sys/class/misc/monreader/dev.
|
||||
|
||||
Typing cat /sys/class/misc/monreader/dev will give an output of the form
|
||||
<major>:<minor>. The device node can be created via the mknod command, enter
|
||||
mknod <name> c <major> <minor>, where <name> is the name of the device node
|
||||
@ -105,10 +113,13 @@ to be created.
|
||||
|
||||
Example:
|
||||
--------
|
||||
# modprobe monreader
|
||||
# cat /sys/class/misc/monreader/dev
|
||||
10:63
|
||||
# mknod /dev/monreader c 10 63
|
||||
|
||||
::
|
||||
|
||||
# modprobe monreader
|
||||
# cat /sys/class/misc/monreader/dev
|
||||
10:63
|
||||
# mknod /dev/monreader c 10 63
|
||||
|
||||
This loads the module with the default monitor DCSS (MONDCSS) and creates a
|
||||
device node.
|
||||
@ -133,20 +144,21 @@ last byte of data. The start address is needed to handle "end-of-frame" records
|
||||
correctly (domain 1, record 13), i.e. it can be used to determine the record
|
||||
start offset relative to a 4K page (frame) boundary.
|
||||
|
||||
See "Appendix A: *MONITOR" in the "z/VM Performance" document for a description
|
||||
See "Appendix A: `*MONITOR`" in the "z/VM Performance" document for a description
|
||||
of the monitor control element layout. The layout of the monitor records can
|
||||
be found here (z/VM 5.1): http://www.vm.ibm.com/pubs/mon510/index.html
|
||||
|
||||
The layout of the data stream provided by the monreader device is as follows:
|
||||
...
|
||||
<0 byte read>
|
||||
<first MCE> \
|
||||
<first set of records> |
|
||||
... |- data set
|
||||
<last MCE> |
|
||||
<last set of records> /
|
||||
<0 byte read>
|
||||
...
|
||||
The layout of the data stream provided by the monreader device is as follows::
|
||||
|
||||
...
|
||||
<0 byte read>
|
||||
<first MCE> \
|
||||
<first set of records> |
|
||||
... |- data set
|
||||
<last MCE> |
|
||||
<last set of records> /
|
||||
<0 byte read>
|
||||
...
|
||||
|
||||
There may be more than one combination of MCE and corresponding record set
|
||||
within one data set and the end of each data set is indicated by a successful
|
||||
@ -165,15 +177,19 @@ As with most char devices, error conditions are indicated by returning a
|
||||
negative value for the number of bytes read. In this case, the errno variable
|
||||
indicates the error condition:
|
||||
|
||||
EIO: reply failed, read data is invalid and the application
|
||||
EIO:
|
||||
reply failed, read data is invalid and the application
|
||||
should discard the data read since the last successful read with 0 size.
|
||||
EFAULT: copy_to_user failed, read data is invalid and the application should
|
||||
discard the data read since the last successful read with 0 size.
|
||||
EAGAIN: occurs on a non-blocking read if there is no data available at the
|
||||
moment. There is no data missing or corrupted, just try again or rather
|
||||
use polling for non-blocking reads.
|
||||
EOVERFLOW: message limit reached, the data read since the last successful
|
||||
read with 0 size is valid but subsequent records may be missing.
|
||||
EFAULT:
|
||||
copy_to_user failed, read data is invalid and the application should
|
||||
discard the data read since the last successful read with 0 size.
|
||||
EAGAIN:
|
||||
occurs on a non-blocking read if there is no data available at the
|
||||
moment. There is no data missing or corrupted, just try again or rather
|
||||
use polling for non-blocking reads.
|
||||
EOVERFLOW:
|
||||
message limit reached, the data read since the last successful
|
||||
read with 0 size is valid but subsequent records may be missing.
|
||||
|
||||
In the last case (EOVERFLOW) there may be missing data, in the first two cases
|
||||
(EIO, EFAULT) there will be missing data. It's up to the application if it will
|
||||
@ -183,7 +199,7 @@ Open:
|
||||
-----
|
||||
Only one user is allowed to open the char device. If it is already in use, the
|
||||
open function will fail (return a negative value) and set errno to EBUSY.
|
||||
The open function may also fail if an IUCV connection to the *MONITOR service
|
||||
The open function may also fail if an IUCV connection to the `*MONITOR` service
|
||||
cannot be established. In this case errno will be set to EIO and an error
|
||||
message with an IPUSER SEVER code will be printed into syslog. The IPUSER SEVER
|
||||
codes are described in the "z/VM Performance" book, Appendix A.
|
||||
@ -194,4 +210,3 @@ As soon as the device is opened, incoming messages will be accepted and they
|
||||
will account for the message limit, i.e. opening the device without reading
|
||||
from it will provoke the "message limit reached" error (EOVERFLOW error code)
|
||||
eventually.
|
||||
|
@ -1,8 +1,12 @@
|
||||
=============================
|
||||
IBM s390 QDIO Ethernet Driver
|
||||
=============================
|
||||
|
||||
OSA and HiperSockets Bridge Port Support
|
||||
========================================
|
||||
|
||||
Uevents
|
||||
-------
|
||||
|
||||
To generate the events the device must be assigned a role of either
|
||||
a primary or a secondary Bridge Port. For more information, see
|
||||
@ -13,12 +17,15 @@ of some configured Bridge Port device on the channel changes, a udev
|
||||
event with ACTION=CHANGE is emitted on behalf of the corresponding
|
||||
ccwgroup device. The event has the following attributes:
|
||||
|
||||
BRIDGEPORT=statechange - indicates that the Bridge Port device changed
|
||||
BRIDGEPORT=statechange
|
||||
indicates that the Bridge Port device changed
|
||||
its state.
|
||||
|
||||
ROLE={primary|secondary|none} - the role assigned to the port.
|
||||
ROLE={primary|secondary|none}
|
||||
the role assigned to the port.
|
||||
|
||||
STATE={active|standby|inactive} - the newly assumed state of the port.
|
||||
STATE={active|standby|inactive}
|
||||
the newly assumed state of the port.
|
||||
|
||||
When run on HiperSockets Bridge Capable Port hardware with host address
|
||||
notifications enabled, a udev event with ACTION=CHANGE is emitted.
|
||||
@ -26,25 +33,32 @@ It is emitted on behalf of the corresponding ccwgroup device when a host
|
||||
or a VLAN is registered or unregistered on the network served by the device.
|
||||
The event has the following attributes:
|
||||
|
||||
BRIDGEDHOST={reset|register|deregister|abort} - host address
|
||||
BRIDGEDHOST={reset|register|deregister|abort}
|
||||
host address
|
||||
notifications are started afresh, a new host or VLAN is registered or
|
||||
deregistered on the Bridge Port HiperSockets channel, or address
|
||||
notifications are aborted.
|
||||
|
||||
VLAN=numeric-vlan-id - VLAN ID on which the event occurred. Not included
|
||||
VLAN=numeric-vlan-id
|
||||
VLAN ID on which the event occurred. Not included
|
||||
if no VLAN is involved in the event.
|
||||
|
||||
MAC=xx:xx:xx:xx:xx:xx - MAC address of the host that is being registered
|
||||
MAC=xx:xx:xx:xx:xx:xx
|
||||
MAC address of the host that is being registered
|
||||
or deregistered from the HiperSockets channel. Not reported if the
|
||||
event reports the creation or destruction of a VLAN.
|
||||
|
||||
NTOK_BUSID=x.y.zzzz - device bus ID (CSSID, SSID and device number).
|
||||
NTOK_BUSID=x.y.zzzz
|
||||
device bus ID (CSSID, SSID and device number).
|
||||
|
||||
NTOK_IID=xx - device IID.
|
||||
NTOK_IID=xx
|
||||
device IID.
|
||||
|
||||
NTOK_CHPID=xx - device CHPID.
|
||||
NTOK_CHPID=xx
|
||||
device CHPID.
|
||||
|
||||
NTOK_CHID=xxxx - device channel ID.
|
||||
NTOK_CHID=xxxx
|
||||
device channel ID.
|
||||
|
||||
Note that the NTOK_* attributes refer to devices other than the one
|
||||
Note that the `NTOK_*` attributes refer to devices other than the one
|
||||
connected to the system on which the OS is running.
|
803
Documentation/s390/s390dbf.rst
Normal file
803
Documentation/s390/s390dbf.rst
Normal file
@ -0,0 +1,803 @@
|
||||
==================
|
||||
S390 Debug Feature
|
||||
==================
|
||||
|
||||
files:
|
||||
- arch/s390/kernel/debug.c
|
||||
- arch/s390/include/asm/debug.h
|
||||
|
||||
Description:
|
||||
------------
|
||||
The goal of this feature is to provide a kernel debug logging API
|
||||
where log records can be stored efficiently in memory, where each component
|
||||
(e.g. device drivers) can have one separate debug log.
|
||||
One purpose of this is to inspect the debug logs after a production system crash
|
||||
in order to analyze the reason for the crash.
|
||||
|
||||
If the system still runs but only a subcomponent which uses dbf fails,
|
||||
it is possible to look at the debug logs on a live system via the Linux
|
||||
debugfs filesystem.
|
||||
|
||||
The debug feature may also very useful for kernel and driver development.
|
||||
|
||||
Design:
|
||||
-------
|
||||
Kernel components (e.g. device drivers) can register themselves at the debug
|
||||
feature with the function call debug_register(). This function initializes a
|
||||
debug log for the caller. For each debug log exists a number of debug areas
|
||||
where exactly one is active at one time. Each debug area consists of contiguous
|
||||
pages in memory. In the debug areas there are stored debug entries (log records)
|
||||
which are written by event- and exception-calls.
|
||||
|
||||
An event-call writes the specified debug entry to the active debug
|
||||
area and updates the log pointer for the active area. If the end
|
||||
of the active debug area is reached, a wrap around is done (ring buffer)
|
||||
and the next debug entry will be written at the beginning of the active
|
||||
debug area.
|
||||
|
||||
An exception-call writes the specified debug entry to the log and
|
||||
switches to the next debug area. This is done in order to be sure
|
||||
that the records which describe the origin of the exception are not
|
||||
overwritten when a wrap around for the current area occurs.
|
||||
|
||||
The debug areas themselves are also ordered in form of a ring buffer.
|
||||
When an exception is thrown in the last debug area, the following debug
|
||||
entries are then written again in the very first area.
|
||||
|
||||
There are three versions for the event- and exception-calls: One for
|
||||
logging raw data, one for text and one for numbers.
|
||||
|
||||
Each debug entry contains the following data:
|
||||
|
||||
- Timestamp
|
||||
- Cpu-Number of calling task
|
||||
- Level of debug entry (0...6)
|
||||
- Return Address to caller
|
||||
- Flag, if entry is an exception or not
|
||||
|
||||
The debug logs can be inspected in a live system through entries in
|
||||
the debugfs-filesystem. Under the toplevel directory "s390dbf" there is
|
||||
a directory for each registered component, which is named like the
|
||||
corresponding component. The debugfs normally should be mounted to
|
||||
/sys/kernel/debug therefore the debug feature can be accessed under
|
||||
/sys/kernel/debug/s390dbf.
|
||||
|
||||
The content of the directories are files which represent different views
|
||||
to the debug log. Each component can decide which views should be
|
||||
used through registering them with the function debug_register_view().
|
||||
Predefined views for hex/ascii, sprintf and raw binary data are provided.
|
||||
It is also possible to define other views. The content of
|
||||
a view can be inspected simply by reading the corresponding debugfs file.
|
||||
|
||||
All debug logs have an actual debug level (range from 0 to 6).
|
||||
The default level is 3. Event and Exception functions have a 'level'
|
||||
parameter. Only debug entries with a level that is lower or equal
|
||||
than the actual level are written to the log. This means, when
|
||||
writing events, high priority log entries should have a low level
|
||||
value whereas low priority entries should have a high one.
|
||||
The actual debug level can be changed with the help of the debugfs-filesystem
|
||||
through writing a number string "x" to the 'level' debugfs file which is
|
||||
provided for every debug log. Debugging can be switched off completely
|
||||
by using "-" on the 'level' debugfs file.
|
||||
|
||||
Example::
|
||||
|
||||
> echo "-" > /sys/kernel/debug/s390dbf/dasd/level
|
||||
|
||||
It is also possible to deactivate the debug feature globally for every
|
||||
debug log. You can change the behavior using 2 sysctl parameters in
|
||||
/proc/sys/s390dbf:
|
||||
|
||||
There are currently 2 possible triggers, which stop the debug feature
|
||||
globally. The first possibility is to use the "debug_active" sysctl. If
|
||||
set to 1 the debug feature is running. If "debug_active" is set to 0 the
|
||||
debug feature is turned off.
|
||||
|
||||
The second trigger which stops the debug feature is a kernel oops.
|
||||
That prevents the debug feature from overwriting debug information that
|
||||
happened before the oops. After an oops you can reactivate the debug feature
|
||||
by piping 1 to /proc/sys/s390dbf/debug_active. Nevertheless, its not
|
||||
suggested to use an oopsed kernel in a production environment.
|
||||
|
||||
If you want to disallow the deactivation of the debug feature, you can use
|
||||
the "debug_stoppable" sysctl. If you set "debug_stoppable" to 0 the debug
|
||||
feature cannot be stopped. If the debug feature is already stopped, it
|
||||
will stay deactivated.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Kernel Interfaces:
|
||||
------------------
|
||||
|
||||
::
|
||||
|
||||
debug_info_t *debug_register(char *name, int pages, int nr_areas,
|
||||
int buf_size);
|
||||
|
||||
Parameter:
|
||||
name:
|
||||
Name of debug log (e.g. used for debugfs entry)
|
||||
pages:
|
||||
Number of pages, which will be allocated per area
|
||||
nr_areas:
|
||||
Number of debug areas
|
||||
buf_size:
|
||||
Size of data area in each debug entry
|
||||
|
||||
Return Value:
|
||||
Handle for generated debug area
|
||||
|
||||
NULL if register failed
|
||||
|
||||
Description: Allocates memory for a debug log
|
||||
Must not be called within an interrupt handler
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
::
|
||||
|
||||
debug_info_t *debug_register_mode(char *name, int pages, int nr_areas,
|
||||
int buf_size, mode_t mode, uid_t uid,
|
||||
gid_t gid);
|
||||
|
||||
Parameter:
|
||||
name:
|
||||
Name of debug log (e.g. used for debugfs entry)
|
||||
pages:
|
||||
Number of pages, which will be allocated per area
|
||||
nr_areas:
|
||||
Number of debug areas
|
||||
buf_size:
|
||||
Size of data area in each debug entry
|
||||
mode:
|
||||
File mode for debugfs files. E.g. S_IRWXUGO
|
||||
uid:
|
||||
User ID for debugfs files. Currently only 0 is
|
||||
supported.
|
||||
gid:
|
||||
Group ID for debugfs files. Currently only 0 is
|
||||
supported.
|
||||
|
||||
Return Value:
|
||||
Handle for generated debug area
|
||||
|
||||
NULL if register failed
|
||||
|
||||
Description:
|
||||
Allocates memory for a debug log
|
||||
Must not be called within an interrupt handler
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
::
|
||||
|
||||
void debug_unregister (debug_info_t * id);
|
||||
|
||||
Parameter:
|
||||
id:
|
||||
handle for debug log
|
||||
|
||||
Return Value:
|
||||
none
|
||||
|
||||
Description:
|
||||
frees memory for a debug log and removes all registered debug
|
||||
views.
|
||||
|
||||
Must not be called within an interrupt handler
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
::
|
||||
|
||||
void debug_set_level (debug_info_t * id, int new_level);
|
||||
|
||||
Parameter: id: handle for debug log
|
||||
new_level: new debug level
|
||||
|
||||
Return Value:
|
||||
none
|
||||
|
||||
Description:
|
||||
Sets new actual debug level if new_level is valid.
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
::
|
||||
|
||||
bool debug_level_enabled (debug_info_t * id, int level);
|
||||
|
||||
Parameter:
|
||||
id:
|
||||
handle for debug log
|
||||
level:
|
||||
debug level
|
||||
|
||||
Return Value:
|
||||
True if level is less or equal to the current debug level.
|
||||
|
||||
Description:
|
||||
Returns true if debug events for the specified level would be
|
||||
logged. Otherwise returns false.
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
::
|
||||
|
||||
void debug_stop_all(void);
|
||||
|
||||
Parameter:
|
||||
none
|
||||
|
||||
Return Value:
|
||||
none
|
||||
|
||||
Description:
|
||||
stops the debug feature if stopping is allowed. Currently
|
||||
used in case of a kernel oops.
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
::
|
||||
|
||||
debug_entry_t* debug_event (debug_info_t* id, int level, void* data,
|
||||
int length);
|
||||
|
||||
Parameter:
|
||||
id:
|
||||
handle for debug log
|
||||
level:
|
||||
debug level
|
||||
data:
|
||||
pointer to data for debug entry
|
||||
length:
|
||||
length of data in bytes
|
||||
|
||||
Return Value:
|
||||
Address of written debug entry
|
||||
|
||||
Description:
|
||||
writes debug entry to active debug area (if level <= actual
|
||||
debug level)
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
::
|
||||
|
||||
debug_entry_t* debug_int_event (debug_info_t * id, int level,
|
||||
unsigned int data);
|
||||
debug_entry_t* debug_long_event(debug_info_t * id, int level,
|
||||
unsigned long data);
|
||||
|
||||
Parameter:
|
||||
id:
|
||||
handle for debug log
|
||||
level:
|
||||
debug level
|
||||
data:
|
||||
integer value for debug entry
|
||||
|
||||
Return Value:
|
||||
Address of written debug entry
|
||||
|
||||
Description:
|
||||
writes debug entry to active debug area (if level <= actual
|
||||
debug level)
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
::
|
||||
|
||||
debug_entry_t* debug_text_event (debug_info_t * id, int level,
|
||||
const char* data);
|
||||
|
||||
Parameter:
|
||||
id:
|
||||
handle for debug log
|
||||
level:
|
||||
debug level
|
||||
data:
|
||||
string for debug entry
|
||||
|
||||
Return Value:
|
||||
Address of written debug entry
|
||||
|
||||
Description:
|
||||
writes debug entry in ascii format to active debug area
|
||||
(if level <= actual debug level)
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
::
|
||||
|
||||
debug_entry_t* debug_sprintf_event (debug_info_t * id, int level,
|
||||
char* string,...);
|
||||
|
||||
Parameter:
|
||||
id:
|
||||
handle for debug log
|
||||
level:
|
||||
debug level
|
||||
string:
|
||||
format string for debug entry
|
||||
...:
|
||||
varargs used as in sprintf()
|
||||
|
||||
Return Value: Address of written debug entry
|
||||
|
||||
Description:
|
||||
writes debug entry with format string and varargs (longs) to
|
||||
active debug area (if level $<=$ actual debug level).
|
||||
floats and long long datatypes cannot be used as varargs.
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
::
|
||||
|
||||
debug_entry_t* debug_exception (debug_info_t* id, int level, void* data,
|
||||
int length);
|
||||
|
||||
Parameter:
|
||||
id:
|
||||
handle for debug log
|
||||
level:
|
||||
debug level
|
||||
data:
|
||||
pointer to data for debug entry
|
||||
length:
|
||||
length of data in bytes
|
||||
|
||||
Return Value:
|
||||
Address of written debug entry
|
||||
|
||||
Description:
|
||||
writes debug entry to active debug area (if level <= actual
|
||||
debug level) and switches to next debug area
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
::
|
||||
|
||||
debug_entry_t* debug_int_exception (debug_info_t * id, int level,
|
||||
unsigned int data);
|
||||
debug_entry_t* debug_long_exception(debug_info_t * id, int level,
|
||||
unsigned long data);
|
||||
|
||||
Parameter: id: handle for debug log
|
||||
level: debug level
|
||||
data: integer value for debug entry
|
||||
|
||||
Return Value: Address of written debug entry
|
||||
|
||||
Description: writes debug entry to active debug area (if level <= actual
|
||||
debug level) and switches to next debug area
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
::
|
||||
|
||||
debug_entry_t* debug_text_exception (debug_info_t * id, int level,
|
||||
const char* data);
|
||||
|
||||
Parameter: id: handle for debug log
|
||||
level: debug level
|
||||
data: string for debug entry
|
||||
|
||||
Return Value: Address of written debug entry
|
||||
|
||||
Description: writes debug entry in ascii format to active debug area
|
||||
(if level <= actual debug level) and switches to next debug
|
||||
area
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
::
|
||||
|
||||
debug_entry_t* debug_sprintf_exception (debug_info_t * id, int level,
|
||||
char* string,...);
|
||||
|
||||
Parameter: id: handle for debug log
|
||||
level: debug level
|
||||
string: format string for debug entry
|
||||
...: varargs used as in sprintf()
|
||||
|
||||
Return Value: Address of written debug entry
|
||||
|
||||
Description: writes debug entry with format string and varargs (longs) to
|
||||
active debug area (if level $<=$ actual debug level) and
|
||||
switches to next debug area.
|
||||
floats and long long datatypes cannot be used as varargs.
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
::
|
||||
|
||||
int debug_register_view (debug_info_t * id, struct debug_view *view);
|
||||
|
||||
Parameter: id: handle for debug log
|
||||
view: pointer to debug view struct
|
||||
|
||||
Return Value: 0 : ok
|
||||
< 0: Error
|
||||
|
||||
Description: registers new debug view and creates debugfs dir entry
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
::
|
||||
|
||||
int debug_unregister_view (debug_info_t * id, struct debug_view *view);
|
||||
|
||||
Parameter: id: handle for debug log
|
||||
view: pointer to debug view struct
|
||||
|
||||
Return Value: 0 : ok
|
||||
< 0: Error
|
||||
|
||||
Description: unregisters debug view and removes debugfs dir entry
|
||||
|
||||
|
||||
|
||||
Predefined views:
|
||||
-----------------
|
||||
|
||||
extern struct debug_view debug_hex_ascii_view;
|
||||
|
||||
extern struct debug_view debug_raw_view;
|
||||
|
||||
extern struct debug_view debug_sprintf_view;
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
::
|
||||
|
||||
/*
|
||||
* hex_ascii- + raw-view Example
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <asm/debug.h>
|
||||
|
||||
static debug_info_t* debug_info;
|
||||
|
||||
static int init(void)
|
||||
{
|
||||
/* register 4 debug areas with one page each and 4 byte data field */
|
||||
|
||||
debug_info = debug_register ("test", 1, 4, 4 );
|
||||
debug_register_view(debug_info,&debug_hex_ascii_view);
|
||||
debug_register_view(debug_info,&debug_raw_view);
|
||||
|
||||
debug_text_event(debug_info, 4 , "one ");
|
||||
debug_int_exception(debug_info, 4, 4711);
|
||||
debug_event(debug_info, 3, &debug_info, 4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cleanup(void)
|
||||
{
|
||||
debug_unregister (debug_info);
|
||||
}
|
||||
|
||||
module_init(init);
|
||||
module_exit(cleanup);
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
::
|
||||
|
||||
/*
|
||||
* sprintf-view Example
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <asm/debug.h>
|
||||
|
||||
static debug_info_t* debug_info;
|
||||
|
||||
static int init(void)
|
||||
{
|
||||
/* register 4 debug areas with one page each and data field for */
|
||||
/* format string pointer + 2 varargs (= 3 * sizeof(long)) */
|
||||
|
||||
debug_info = debug_register ("test", 1, 4, sizeof(long) * 3);
|
||||
debug_register_view(debug_info,&debug_sprintf_view);
|
||||
|
||||
debug_sprintf_event(debug_info, 2 , "first event in %s:%i\n",__FILE__,__LINE__);
|
||||
debug_sprintf_exception(debug_info, 1, "pointer to debug info: %p\n",&debug_info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cleanup(void)
|
||||
{
|
||||
debug_unregister (debug_info);
|
||||
}
|
||||
|
||||
module_init(init);
|
||||
module_exit(cleanup);
|
||||
|
||||
Debugfs Interface
|
||||
-----------------
|
||||
Views to the debug logs can be investigated through reading the corresponding
|
||||
debugfs-files:
|
||||
|
||||
Example::
|
||||
|
||||
> ls /sys/kernel/debug/s390dbf/dasd
|
||||
flush hex_ascii level pages raw
|
||||
> cat /sys/kernel/debug/s390dbf/dasd/hex_ascii | sort -k2,2 -s
|
||||
00 00974733272:680099 2 - 02 0006ad7e 07 ea 4a 90 | ....
|
||||
00 00974733272:682210 2 - 02 0006ade6 46 52 45 45 | FREE
|
||||
00 00974733272:682213 2 - 02 0006adf6 07 ea 4a 90 | ....
|
||||
00 00974733272:682281 1 * 02 0006ab08 41 4c 4c 43 | EXCP
|
||||
01 00974733272:682284 2 - 02 0006ab16 45 43 4b 44 | ECKD
|
||||
01 00974733272:682287 2 - 02 0006ab28 00 00 00 04 | ....
|
||||
01 00974733272:682289 2 - 02 0006ab3e 00 00 00 20 | ...
|
||||
01 00974733272:682297 2 - 02 0006ad7e 07 ea 4a 90 | ....
|
||||
01 00974733272:684384 2 - 00 0006ade6 46 52 45 45 | FREE
|
||||
01 00974733272:684388 2 - 00 0006adf6 07 ea 4a 90 | ....
|
||||
|
||||
See section about predefined views for explanation of the above output!
|
||||
|
||||
Changing the debug level
|
||||
------------------------
|
||||
|
||||
Example::
|
||||
|
||||
|
||||
> cat /sys/kernel/debug/s390dbf/dasd/level
|
||||
3
|
||||
> echo "5" > /sys/kernel/debug/s390dbf/dasd/level
|
||||
> cat /sys/kernel/debug/s390dbf/dasd/level
|
||||
5
|
||||
|
||||
Flushing debug areas
|
||||
--------------------
|
||||
Debug areas can be flushed with piping the number of the desired
|
||||
area (0...n) to the debugfs file "flush". When using "-" all debug areas
|
||||
are flushed.
|
||||
|
||||
Examples:
|
||||
|
||||
1. Flush debug area 0::
|
||||
|
||||
> echo "0" > /sys/kernel/debug/s390dbf/dasd/flush
|
||||
|
||||
2. Flush all debug areas::
|
||||
|
||||
> echo "-" > /sys/kernel/debug/s390dbf/dasd/flush
|
||||
|
||||
Changing the size of debug areas
|
||||
------------------------------------
|
||||
It is possible the change the size of debug areas through piping
|
||||
the number of pages to the debugfs file "pages". The resize request will
|
||||
also flush the debug areas.
|
||||
|
||||
Example:
|
||||
|
||||
Define 4 pages for the debug areas of debug feature "dasd"::
|
||||
|
||||
> echo "4" > /sys/kernel/debug/s390dbf/dasd/pages
|
||||
|
||||
Stooping the debug feature
|
||||
--------------------------
|
||||
Example:
|
||||
|
||||
1. Check if stopping is allowed::
|
||||
|
||||
> cat /proc/sys/s390dbf/debug_stoppable
|
||||
|
||||
2. Stop debug feature::
|
||||
|
||||
> echo 0 > /proc/sys/s390dbf/debug_active
|
||||
|
||||
lcrash Interface
|
||||
----------------
|
||||
It is planned that the dump analysis tool lcrash gets an additional command
|
||||
's390dbf' to display all the debug logs. With this tool it will be possible
|
||||
to investigate the debug logs on a live system and with a memory dump after
|
||||
a system crash.
|
||||
|
||||
Investigating raw memory
|
||||
------------------------
|
||||
One last possibility to investigate the debug logs at a live
|
||||
system and after a system crash is to look at the raw memory
|
||||
under VM or at the Service Element.
|
||||
It is possible to find the anker of the debug-logs through
|
||||
the 'debug_area_first' symbol in the System map. Then one has
|
||||
to follow the correct pointers of the data-structures defined
|
||||
in debug.h and find the debug-areas in memory.
|
||||
Normally modules which use the debug feature will also have
|
||||
a global variable with the pointer to the debug-logs. Following
|
||||
this pointer it will also be possible to find the debug logs in
|
||||
memory.
|
||||
|
||||
For this method it is recommended to use '16 * x + 4' byte (x = 0..n)
|
||||
for the length of the data field in debug_register() in
|
||||
order to see the debug entries well formatted.
|
||||
|
||||
|
||||
Predefined Views
|
||||
----------------
|
||||
|
||||
There are three predefined views: hex_ascii, raw and sprintf.
|
||||
The hex_ascii view shows the data field in hex and ascii representation
|
||||
(e.g. '45 43 4b 44 | ECKD').
|
||||
The raw view returns a bytestream as the debug areas are stored in memory.
|
||||
|
||||
The sprintf view formats the debug entries in the same way as the sprintf
|
||||
function would do. The sprintf event/exception functions write to the
|
||||
debug entry a pointer to the format string (size = sizeof(long))
|
||||
and for each vararg a long value. So e.g. for a debug entry with a format
|
||||
string plus two varargs one would need to allocate a (3 * sizeof(long))
|
||||
byte data area in the debug_register() function.
|
||||
|
||||
IMPORTANT:
|
||||
Using "%s" in sprintf event functions is dangerous. You can only
|
||||
use "%s" in the sprintf event functions, if the memory for the passed string
|
||||
is available as long as the debug feature exists. The reason behind this is
|
||||
that due to performance considerations only a pointer to the string is stored
|
||||
in the debug feature. If you log a string that is freed afterwards, you will
|
||||
get an OOPS when inspecting the debug feature, because then the debug feature
|
||||
will access the already freed memory.
|
||||
|
||||
NOTE:
|
||||
If using the sprintf view do NOT use other event/exception functions
|
||||
than the sprintf-event and -exception functions.
|
||||
|
||||
The format of the hex_ascii and sprintf view is as follows:
|
||||
|
||||
- Number of area
|
||||
- Timestamp (formatted as seconds and microseconds since 00:00:00 Coordinated
|
||||
Universal Time (UTC), January 1, 1970)
|
||||
- level of debug entry
|
||||
- Exception flag (* = Exception)
|
||||
- Cpu-Number of calling task
|
||||
- Return Address to caller
|
||||
- data field
|
||||
|
||||
The format of the raw view is:
|
||||
|
||||
- Header as described in debug.h
|
||||
- datafield
|
||||
|
||||
A typical line of the hex_ascii view will look like the following (first line
|
||||
is only for explanation and will not be displayed when 'cating' the view):
|
||||
|
||||
area time level exception cpu caller data (hex + ascii)
|
||||
--------------------------------------------------------------------------
|
||||
00 00964419409:440690 1 - 00 88023fe
|
||||
|
||||
|
||||
Defining views
|
||||
--------------
|
||||
|
||||
Views are specified with the 'debug_view' structure. There are defined
|
||||
callback functions which are used for reading and writing the debugfs files::
|
||||
|
||||
struct debug_view {
|
||||
char name[DEBUG_MAX_PROCF_LEN];
|
||||
debug_prolog_proc_t* prolog_proc;
|
||||
debug_header_proc_t* header_proc;
|
||||
debug_format_proc_t* format_proc;
|
||||
debug_input_proc_t* input_proc;
|
||||
void* private_data;
|
||||
};
|
||||
|
||||
where::
|
||||
|
||||
typedef int (debug_header_proc_t) (debug_info_t* id,
|
||||
struct debug_view* view,
|
||||
int area,
|
||||
debug_entry_t* entry,
|
||||
char* out_buf);
|
||||
|
||||
typedef int (debug_format_proc_t) (debug_info_t* id,
|
||||
struct debug_view* view, char* out_buf,
|
||||
const char* in_buf);
|
||||
typedef int (debug_prolog_proc_t) (debug_info_t* id,
|
||||
struct debug_view* view,
|
||||
char* out_buf);
|
||||
typedef int (debug_input_proc_t) (debug_info_t* id,
|
||||
struct debug_view* view,
|
||||
struct file* file, const char* user_buf,
|
||||
size_t in_buf_size, loff_t* offset);
|
||||
|
||||
|
||||
The "private_data" member can be used as pointer to view specific data.
|
||||
It is not used by the debug feature itself.
|
||||
|
||||
The output when reading a debugfs file is structured like this::
|
||||
|
||||
"prolog_proc output"
|
||||
|
||||
"header_proc output 1" "format_proc output 1"
|
||||
"header_proc output 2" "format_proc output 2"
|
||||
"header_proc output 3" "format_proc output 3"
|
||||
...
|
||||
|
||||
When a view is read from the debugfs, the Debug Feature calls the
|
||||
'prolog_proc' once for writing the prolog.
|
||||
Then 'header_proc' and 'format_proc' are called for each
|
||||
existing debug entry.
|
||||
|
||||
The input_proc can be used to implement functionality when it is written to
|
||||
the view (e.g. like with 'echo "0" > /sys/kernel/debug/s390dbf/dasd/level).
|
||||
|
||||
For header_proc there can be used the default function
|
||||
debug_dflt_header_fn() which is defined in debug.h.
|
||||
and which produces the same header output as the predefined views.
|
||||
E.g::
|
||||
|
||||
00 00964419409:440761 2 - 00 88023ec
|
||||
|
||||
In order to see how to use the callback functions check the implementation
|
||||
of the default views!
|
||||
|
||||
Example::
|
||||
|
||||
#include <asm/debug.h>
|
||||
|
||||
#define UNKNOWNSTR "data: %08x"
|
||||
|
||||
const char* messages[] =
|
||||
{"This error...........\n",
|
||||
"That error...........\n",
|
||||
"Problem..............\n",
|
||||
"Something went wrong.\n",
|
||||
"Everything ok........\n",
|
||||
NULL
|
||||
};
|
||||
|
||||
static int debug_test_format_fn(
|
||||
debug_info_t * id, struct debug_view *view,
|
||||
char *out_buf, const char *in_buf
|
||||
)
|
||||
{
|
||||
int i, rc = 0;
|
||||
|
||||
if(id->buf_size >= 4) {
|
||||
int msg_nr = *((int*)in_buf);
|
||||
if(msg_nr < sizeof(messages)/sizeof(char*) - 1)
|
||||
rc += sprintf(out_buf, "%s", messages[msg_nr]);
|
||||
else
|
||||
rc += sprintf(out_buf, UNKNOWNSTR, msg_nr);
|
||||
}
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
struct debug_view debug_test_view = {
|
||||
"myview", /* name of view */
|
||||
NULL, /* no prolog */
|
||||
&debug_dflt_header_fn, /* default header for each entry */
|
||||
&debug_test_format_fn, /* our own format function */
|
||||
NULL, /* no input function */
|
||||
NULL /* no private data */
|
||||
};
|
||||
|
||||
test:
|
||||
=====
|
||||
|
||||
::
|
||||
|
||||
debug_info_t *debug_info;
|
||||
...
|
||||
debug_info = debug_register ("test", 0, 4, 4 ));
|
||||
debug_register_view(debug_info, &debug_test_view);
|
||||
for(i = 0; i < 10; i ++) debug_int_event(debug_info, 1, i);
|
||||
|
||||
> cat /sys/kernel/debug/s390dbf/test/myview
|
||||
00 00964419734:611402 1 - 00 88042ca This error...........
|
||||
00 00964419734:611405 1 - 00 88042ca That error...........
|
||||
00 00964419734:611408 1 - 00 88042ca Problem..............
|
||||
00 00964419734:611411 1 - 00 88042ca Something went wrong.
|
||||
00 00964419734:611414 1 - 00 88042ca Everything ok........
|
||||
00 00964419734:611417 1 - 00 88042ca data: 00000005
|
||||
00 00964419734:611419 1 - 00 88042ca data: 00000006
|
||||
00 00964419734:611422 1 - 00 88042ca data: 00000007
|
||||
00 00964419734:611425 1 - 00 88042ca data: 00000008
|
||||
00 00964419734:611428 1 - 00 88042ca data: 00000009
|
@ -1,667 +0,0 @@
|
||||
S390 Debug Feature
|
||||
==================
|
||||
|
||||
files: arch/s390/kernel/debug.c
|
||||
arch/s390/include/asm/debug.h
|
||||
|
||||
Description:
|
||||
------------
|
||||
The goal of this feature is to provide a kernel debug logging API
|
||||
where log records can be stored efficiently in memory, where each component
|
||||
(e.g. device drivers) can have one separate debug log.
|
||||
One purpose of this is to inspect the debug logs after a production system crash
|
||||
in order to analyze the reason for the crash.
|
||||
If the system still runs but only a subcomponent which uses dbf fails,
|
||||
it is possible to look at the debug logs on a live system via the Linux
|
||||
debugfs filesystem.
|
||||
The debug feature may also very useful for kernel and driver development.
|
||||
|
||||
Design:
|
||||
-------
|
||||
Kernel components (e.g. device drivers) can register themselves at the debug
|
||||
feature with the function call debug_register(). This function initializes a
|
||||
debug log for the caller. For each debug log exists a number of debug areas
|
||||
where exactly one is active at one time. Each debug area consists of contiguous
|
||||
pages in memory. In the debug areas there are stored debug entries (log records)
|
||||
which are written by event- and exception-calls.
|
||||
|
||||
An event-call writes the specified debug entry to the active debug
|
||||
area and updates the log pointer for the active area. If the end
|
||||
of the active debug area is reached, a wrap around is done (ring buffer)
|
||||
and the next debug entry will be written at the beginning of the active
|
||||
debug area.
|
||||
|
||||
An exception-call writes the specified debug entry to the log and
|
||||
switches to the next debug area. This is done in order to be sure
|
||||
that the records which describe the origin of the exception are not
|
||||
overwritten when a wrap around for the current area occurs.
|
||||
|
||||
The debug areas themselves are also ordered in form of a ring buffer.
|
||||
When an exception is thrown in the last debug area, the following debug
|
||||
entries are then written again in the very first area.
|
||||
|
||||
There are three versions for the event- and exception-calls: One for
|
||||
logging raw data, one for text and one for numbers.
|
||||
|
||||
Each debug entry contains the following data:
|
||||
|
||||
- Timestamp
|
||||
- Cpu-Number of calling task
|
||||
- Level of debug entry (0...6)
|
||||
- Return Address to caller
|
||||
- Flag, if entry is an exception or not
|
||||
|
||||
The debug logs can be inspected in a live system through entries in
|
||||
the debugfs-filesystem. Under the toplevel directory "s390dbf" there is
|
||||
a directory for each registered component, which is named like the
|
||||
corresponding component. The debugfs normally should be mounted to
|
||||
/sys/kernel/debug therefore the debug feature can be accessed under
|
||||
/sys/kernel/debug/s390dbf.
|
||||
|
||||
The content of the directories are files which represent different views
|
||||
to the debug log. Each component can decide which views should be
|
||||
used through registering them with the function debug_register_view().
|
||||
Predefined views for hex/ascii, sprintf and raw binary data are provided.
|
||||
It is also possible to define other views. The content of
|
||||
a view can be inspected simply by reading the corresponding debugfs file.
|
||||
|
||||
All debug logs have an actual debug level (range from 0 to 6).
|
||||
The default level is 3. Event and Exception functions have a 'level'
|
||||
parameter. Only debug entries with a level that is lower or equal
|
||||
than the actual level are written to the log. This means, when
|
||||
writing events, high priority log entries should have a low level
|
||||
value whereas low priority entries should have a high one.
|
||||
The actual debug level can be changed with the help of the debugfs-filesystem
|
||||
through writing a number string "x" to the 'level' debugfs file which is
|
||||
provided for every debug log. Debugging can be switched off completely
|
||||
by using "-" on the 'level' debugfs file.
|
||||
|
||||
Example:
|
||||
|
||||
> echo "-" > /sys/kernel/debug/s390dbf/dasd/level
|
||||
|
||||
It is also possible to deactivate the debug feature globally for every
|
||||
debug log. You can change the behavior using 2 sysctl parameters in
|
||||
/proc/sys/s390dbf:
|
||||
There are currently 2 possible triggers, which stop the debug feature
|
||||
globally. The first possibility is to use the "debug_active" sysctl. If
|
||||
set to 1 the debug feature is running. If "debug_active" is set to 0 the
|
||||
debug feature is turned off.
|
||||
The second trigger which stops the debug feature is a kernel oops.
|
||||
That prevents the debug feature from overwriting debug information that
|
||||
happened before the oops. After an oops you can reactivate the debug feature
|
||||
by piping 1 to /proc/sys/s390dbf/debug_active. Nevertheless, its not
|
||||
suggested to use an oopsed kernel in a production environment.
|
||||
If you want to disallow the deactivation of the debug feature, you can use
|
||||
the "debug_stoppable" sysctl. If you set "debug_stoppable" to 0 the debug
|
||||
feature cannot be stopped. If the debug feature is already stopped, it
|
||||
will stay deactivated.
|
||||
|
||||
Kernel Interfaces:
|
||||
------------------
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
debug_info_t *debug_register(char *name, int pages, int nr_areas,
|
||||
int buf_size);
|
||||
|
||||
Parameter: name: Name of debug log (e.g. used for debugfs entry)
|
||||
pages: number of pages, which will be allocated per area
|
||||
nr_areas: number of debug areas
|
||||
buf_size: size of data area in each debug entry
|
||||
|
||||
Return Value: Handle for generated debug area
|
||||
NULL if register failed
|
||||
|
||||
Description: Allocates memory for a debug log
|
||||
Must not be called within an interrupt handler
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
debug_info_t *debug_register_mode(char *name, int pages, int nr_areas,
|
||||
int buf_size, mode_t mode, uid_t uid,
|
||||
gid_t gid);
|
||||
|
||||
Parameter: name: Name of debug log (e.g. used for debugfs entry)
|
||||
pages: Number of pages, which will be allocated per area
|
||||
nr_areas: Number of debug areas
|
||||
buf_size: Size of data area in each debug entry
|
||||
mode: File mode for debugfs files. E.g. S_IRWXUGO
|
||||
uid: User ID for debugfs files. Currently only 0 is
|
||||
supported.
|
||||
gid: Group ID for debugfs files. Currently only 0 is
|
||||
supported.
|
||||
|
||||
Return Value: Handle for generated debug area
|
||||
NULL if register failed
|
||||
|
||||
Description: Allocates memory for a debug log
|
||||
Must not be called within an interrupt handler
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
void debug_unregister (debug_info_t * id);
|
||||
|
||||
Parameter: id: handle for debug log
|
||||
|
||||
Return Value: none
|
||||
|
||||
Description: frees memory for a debug log and removes all registered debug
|
||||
views.
|
||||
Must not be called within an interrupt handler
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
void debug_set_level (debug_info_t * id, int new_level);
|
||||
|
||||
Parameter: id: handle for debug log
|
||||
new_level: new debug level
|
||||
|
||||
Return Value: none
|
||||
|
||||
Description: Sets new actual debug level if new_level is valid.
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
bool debug_level_enabled (debug_info_t * id, int level);
|
||||
|
||||
Parameter: id: handle for debug log
|
||||
level: debug level
|
||||
|
||||
Return Value: True if level is less or equal to the current debug level.
|
||||
|
||||
Description: Returns true if debug events for the specified level would be
|
||||
logged. Otherwise returns false.
|
||||
---------------------------------------------------------------------------
|
||||
void debug_stop_all(void);
|
||||
|
||||
Parameter: none
|
||||
|
||||
Return Value: none
|
||||
|
||||
Description: stops the debug feature if stopping is allowed. Currently
|
||||
used in case of a kernel oops.
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
debug_entry_t* debug_event (debug_info_t* id, int level, void* data,
|
||||
int length);
|
||||
|
||||
Parameter: id: handle for debug log
|
||||
level: debug level
|
||||
data: pointer to data for debug entry
|
||||
length: length of data in bytes
|
||||
|
||||
Return Value: Address of written debug entry
|
||||
|
||||
Description: writes debug entry to active debug area (if level <= actual
|
||||
debug level)
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
debug_entry_t* debug_int_event (debug_info_t * id, int level,
|
||||
unsigned int data);
|
||||
debug_entry_t* debug_long_event(debug_info_t * id, int level,
|
||||
unsigned long data);
|
||||
|
||||
Parameter: id: handle for debug log
|
||||
level: debug level
|
||||
data: integer value for debug entry
|
||||
|
||||
Return Value: Address of written debug entry
|
||||
|
||||
Description: writes debug entry to active debug area (if level <= actual
|
||||
debug level)
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
debug_entry_t* debug_text_event (debug_info_t * id, int level,
|
||||
const char* data);
|
||||
|
||||
Parameter: id: handle for debug log
|
||||
level: debug level
|
||||
data: string for debug entry
|
||||
|
||||
Return Value: Address of written debug entry
|
||||
|
||||
Description: writes debug entry in ascii format to active debug area
|
||||
(if level <= actual debug level)
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
debug_entry_t* debug_sprintf_event (debug_info_t * id, int level,
|
||||
char* string,...);
|
||||
|
||||
Parameter: id: handle for debug log
|
||||
level: debug level
|
||||
string: format string for debug entry
|
||||
...: varargs used as in sprintf()
|
||||
|
||||
Return Value: Address of written debug entry
|
||||
|
||||
Description: writes debug entry with format string and varargs (longs) to
|
||||
active debug area (if level $<=$ actual debug level).
|
||||
floats and long long datatypes cannot be used as varargs.
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
debug_entry_t* debug_exception (debug_info_t* id, int level, void* data,
|
||||
int length);
|
||||
|
||||
Parameter: id: handle for debug log
|
||||
level: debug level
|
||||
data: pointer to data for debug entry
|
||||
length: length of data in bytes
|
||||
|
||||
Return Value: Address of written debug entry
|
||||
|
||||
Description: writes debug entry to active debug area (if level <= actual
|
||||
debug level) and switches to next debug area
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
debug_entry_t* debug_int_exception (debug_info_t * id, int level,
|
||||
unsigned int data);
|
||||
debug_entry_t* debug_long_exception(debug_info_t * id, int level,
|
||||
unsigned long data);
|
||||
|
||||
Parameter: id: handle for debug log
|
||||
level: debug level
|
||||
data: integer value for debug entry
|
||||
|
||||
Return Value: Address of written debug entry
|
||||
|
||||
Description: writes debug entry to active debug area (if level <= actual
|
||||
debug level) and switches to next debug area
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
debug_entry_t* debug_text_exception (debug_info_t * id, int level,
|
||||
const char* data);
|
||||
|
||||
Parameter: id: handle for debug log
|
||||
level: debug level
|
||||
data: string for debug entry
|
||||
|
||||
Return Value: Address of written debug entry
|
||||
|
||||
Description: writes debug entry in ascii format to active debug area
|
||||
(if level <= actual debug level) and switches to next debug
|
||||
area
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
debug_entry_t* debug_sprintf_exception (debug_info_t * id, int level,
|
||||
char* string,...);
|
||||
|
||||
Parameter: id: handle for debug log
|
||||
level: debug level
|
||||
string: format string for debug entry
|
||||
...: varargs used as in sprintf()
|
||||
|
||||
Return Value: Address of written debug entry
|
||||
|
||||
Description: writes debug entry with format string and varargs (longs) to
|
||||
active debug area (if level $<=$ actual debug level) and
|
||||
switches to next debug area.
|
||||
floats and long long datatypes cannot be used as varargs.
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
int debug_register_view (debug_info_t * id, struct debug_view *view);
|
||||
|
||||
Parameter: id: handle for debug log
|
||||
view: pointer to debug view struct
|
||||
|
||||
Return Value: 0 : ok
|
||||
< 0: Error
|
||||
|
||||
Description: registers new debug view and creates debugfs dir entry
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
int debug_unregister_view (debug_info_t * id, struct debug_view *view);
|
||||
|
||||
Parameter: id: handle for debug log
|
||||
view: pointer to debug view struct
|
||||
|
||||
Return Value: 0 : ok
|
||||
< 0: Error
|
||||
|
||||
Description: unregisters debug view and removes debugfs dir entry
|
||||
|
||||
|
||||
|
||||
Predefined views:
|
||||
-----------------
|
||||
|
||||
extern struct debug_view debug_hex_ascii_view;
|
||||
extern struct debug_view debug_raw_view;
|
||||
extern struct debug_view debug_sprintf_view;
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
/*
|
||||
* hex_ascii- + raw-view Example
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <asm/debug.h>
|
||||
|
||||
static debug_info_t* debug_info;
|
||||
|
||||
static int init(void)
|
||||
{
|
||||
/* register 4 debug areas with one page each and 4 byte data field */
|
||||
|
||||
debug_info = debug_register ("test", 1, 4, 4 );
|
||||
debug_register_view(debug_info,&debug_hex_ascii_view);
|
||||
debug_register_view(debug_info,&debug_raw_view);
|
||||
|
||||
debug_text_event(debug_info, 4 , "one ");
|
||||
debug_int_exception(debug_info, 4, 4711);
|
||||
debug_event(debug_info, 3, &debug_info, 4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cleanup(void)
|
||||
{
|
||||
debug_unregister (debug_info);
|
||||
}
|
||||
|
||||
module_init(init);
|
||||
module_exit(cleanup);
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* sprintf-view Example
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <asm/debug.h>
|
||||
|
||||
static debug_info_t* debug_info;
|
||||
|
||||
static int init(void)
|
||||
{
|
||||
/* register 4 debug areas with one page each and data field for */
|
||||
/* format string pointer + 2 varargs (= 3 * sizeof(long)) */
|
||||
|
||||
debug_info = debug_register ("test", 1, 4, sizeof(long) * 3);
|
||||
debug_register_view(debug_info,&debug_sprintf_view);
|
||||
|
||||
debug_sprintf_event(debug_info, 2 , "first event in %s:%i\n",__FILE__,__LINE__);
|
||||
debug_sprintf_exception(debug_info, 1, "pointer to debug info: %p\n",&debug_info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cleanup(void)
|
||||
{
|
||||
debug_unregister (debug_info);
|
||||
}
|
||||
|
||||
module_init(init);
|
||||
module_exit(cleanup);
|
||||
|
||||
|
||||
|
||||
Debugfs Interface
|
||||
----------------
|
||||
Views to the debug logs can be investigated through reading the corresponding
|
||||
debugfs-files:
|
||||
|
||||
Example:
|
||||
|
||||
> ls /sys/kernel/debug/s390dbf/dasd
|
||||
flush hex_ascii level pages raw
|
||||
> cat /sys/kernel/debug/s390dbf/dasd/hex_ascii | sort -k2,2 -s
|
||||
00 00974733272:680099 2 - 02 0006ad7e 07 ea 4a 90 | ....
|
||||
00 00974733272:682210 2 - 02 0006ade6 46 52 45 45 | FREE
|
||||
00 00974733272:682213 2 - 02 0006adf6 07 ea 4a 90 | ....
|
||||
00 00974733272:682281 1 * 02 0006ab08 41 4c 4c 43 | EXCP
|
||||
01 00974733272:682284 2 - 02 0006ab16 45 43 4b 44 | ECKD
|
||||
01 00974733272:682287 2 - 02 0006ab28 00 00 00 04 | ....
|
||||
01 00974733272:682289 2 - 02 0006ab3e 00 00 00 20 | ...
|
||||
01 00974733272:682297 2 - 02 0006ad7e 07 ea 4a 90 | ....
|
||||
01 00974733272:684384 2 - 00 0006ade6 46 52 45 45 | FREE
|
||||
01 00974733272:684388 2 - 00 0006adf6 07 ea 4a 90 | ....
|
||||
|
||||
See section about predefined views for explanation of the above output!
|
||||
|
||||
Changing the debug level
|
||||
------------------------
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
> cat /sys/kernel/debug/s390dbf/dasd/level
|
||||
3
|
||||
> echo "5" > /sys/kernel/debug/s390dbf/dasd/level
|
||||
> cat /sys/kernel/debug/s390dbf/dasd/level
|
||||
5
|
||||
|
||||
Flushing debug areas
|
||||
--------------------
|
||||
Debug areas can be flushed with piping the number of the desired
|
||||
area (0...n) to the debugfs file "flush". When using "-" all debug areas
|
||||
are flushed.
|
||||
|
||||
Examples:
|
||||
|
||||
1. Flush debug area 0:
|
||||
> echo "0" > /sys/kernel/debug/s390dbf/dasd/flush
|
||||
|
||||
2. Flush all debug areas:
|
||||
> echo "-" > /sys/kernel/debug/s390dbf/dasd/flush
|
||||
|
||||
Changing the size of debug areas
|
||||
------------------------------------
|
||||
It is possible the change the size of debug areas through piping
|
||||
the number of pages to the debugfs file "pages". The resize request will
|
||||
also flush the debug areas.
|
||||
|
||||
Example:
|
||||
|
||||
Define 4 pages for the debug areas of debug feature "dasd":
|
||||
> echo "4" > /sys/kernel/debug/s390dbf/dasd/pages
|
||||
|
||||
Stooping the debug feature
|
||||
--------------------------
|
||||
Example:
|
||||
|
||||
1. Check if stopping is allowed
|
||||
> cat /proc/sys/s390dbf/debug_stoppable
|
||||
2. Stop debug feature
|
||||
> echo 0 > /proc/sys/s390dbf/debug_active
|
||||
|
||||
lcrash Interface
|
||||
----------------
|
||||
It is planned that the dump analysis tool lcrash gets an additional command
|
||||
's390dbf' to display all the debug logs. With this tool it will be possible
|
||||
to investigate the debug logs on a live system and with a memory dump after
|
||||
a system crash.
|
||||
|
||||
Investigating raw memory
|
||||
------------------------
|
||||
One last possibility to investigate the debug logs at a live
|
||||
system and after a system crash is to look at the raw memory
|
||||
under VM or at the Service Element.
|
||||
It is possible to find the anker of the debug-logs through
|
||||
the 'debug_area_first' symbol in the System map. Then one has
|
||||
to follow the correct pointers of the data-structures defined
|
||||
in debug.h and find the debug-areas in memory.
|
||||
Normally modules which use the debug feature will also have
|
||||
a global variable with the pointer to the debug-logs. Following
|
||||
this pointer it will also be possible to find the debug logs in
|
||||
memory.
|
||||
|
||||
For this method it is recommended to use '16 * x + 4' byte (x = 0..n)
|
||||
for the length of the data field in debug_register() in
|
||||
order to see the debug entries well formatted.
|
||||
|
||||
|
||||
Predefined Views
|
||||
----------------
|
||||
|
||||
There are three predefined views: hex_ascii, raw and sprintf.
|
||||
The hex_ascii view shows the data field in hex and ascii representation
|
||||
(e.g. '45 43 4b 44 | ECKD').
|
||||
The raw view returns a bytestream as the debug areas are stored in memory.
|
||||
|
||||
The sprintf view formats the debug entries in the same way as the sprintf
|
||||
function would do. The sprintf event/exception functions write to the
|
||||
debug entry a pointer to the format string (size = sizeof(long))
|
||||
and for each vararg a long value. So e.g. for a debug entry with a format
|
||||
string plus two varargs one would need to allocate a (3 * sizeof(long))
|
||||
byte data area in the debug_register() function.
|
||||
|
||||
IMPORTANT: Using "%s" in sprintf event functions is dangerous. You can only
|
||||
use "%s" in the sprintf event functions, if the memory for the passed string is
|
||||
available as long as the debug feature exists. The reason behind this is that
|
||||
due to performance considerations only a pointer to the string is stored in
|
||||
the debug feature. If you log a string that is freed afterwards, you will get
|
||||
an OOPS when inspecting the debug feature, because then the debug feature will
|
||||
access the already freed memory.
|
||||
|
||||
NOTE: If using the sprintf view do NOT use other event/exception functions
|
||||
than the sprintf-event and -exception functions.
|
||||
|
||||
The format of the hex_ascii and sprintf view is as follows:
|
||||
- Number of area
|
||||
- Timestamp (formatted as seconds and microseconds since 00:00:00 Coordinated
|
||||
Universal Time (UTC), January 1, 1970)
|
||||
- level of debug entry
|
||||
- Exception flag (* = Exception)
|
||||
- Cpu-Number of calling task
|
||||
- Return Address to caller
|
||||
- data field
|
||||
|
||||
The format of the raw view is:
|
||||
- Header as described in debug.h
|
||||
- datafield
|
||||
|
||||
A typical line of the hex_ascii view will look like the following (first line
|
||||
is only for explanation and will not be displayed when 'cating' the view):
|
||||
|
||||
area time level exception cpu caller data (hex + ascii)
|
||||
--------------------------------------------------------------------------
|
||||
00 00964419409:440690 1 - 00 88023fe
|
||||
|
||||
|
||||
Defining views
|
||||
--------------
|
||||
|
||||
Views are specified with the 'debug_view' structure. There are defined
|
||||
callback functions which are used for reading and writing the debugfs files:
|
||||
|
||||
struct debug_view {
|
||||
char name[DEBUG_MAX_PROCF_LEN];
|
||||
debug_prolog_proc_t* prolog_proc;
|
||||
debug_header_proc_t* header_proc;
|
||||
debug_format_proc_t* format_proc;
|
||||
debug_input_proc_t* input_proc;
|
||||
void* private_data;
|
||||
};
|
||||
|
||||
where
|
||||
|
||||
typedef int (debug_header_proc_t) (debug_info_t* id,
|
||||
struct debug_view* view,
|
||||
int area,
|
||||
debug_entry_t* entry,
|
||||
char* out_buf);
|
||||
|
||||
typedef int (debug_format_proc_t) (debug_info_t* id,
|
||||
struct debug_view* view, char* out_buf,
|
||||
const char* in_buf);
|
||||
typedef int (debug_prolog_proc_t) (debug_info_t* id,
|
||||
struct debug_view* view,
|
||||
char* out_buf);
|
||||
typedef int (debug_input_proc_t) (debug_info_t* id,
|
||||
struct debug_view* view,
|
||||
struct file* file, const char* user_buf,
|
||||
size_t in_buf_size, loff_t* offset);
|
||||
|
||||
|
||||
The "private_data" member can be used as pointer to view specific data.
|
||||
It is not used by the debug feature itself.
|
||||
|
||||
The output when reading a debugfs file is structured like this:
|
||||
|
||||
"prolog_proc output"
|
||||
|
||||
"header_proc output 1" "format_proc output 1"
|
||||
"header_proc output 2" "format_proc output 2"
|
||||
"header_proc output 3" "format_proc output 3"
|
||||
...
|
||||
|
||||
When a view is read from the debugfs, the Debug Feature calls the
|
||||
'prolog_proc' once for writing the prolog.
|
||||
Then 'header_proc' and 'format_proc' are called for each
|
||||
existing debug entry.
|
||||
|
||||
The input_proc can be used to implement functionality when it is written to
|
||||
the view (e.g. like with 'echo "0" > /sys/kernel/debug/s390dbf/dasd/level).
|
||||
|
||||
For header_proc there can be used the default function
|
||||
debug_dflt_header_fn() which is defined in debug.h.
|
||||
and which produces the same header output as the predefined views.
|
||||
E.g:
|
||||
00 00964419409:440761 2 - 00 88023ec
|
||||
|
||||
In order to see how to use the callback functions check the implementation
|
||||
of the default views!
|
||||
|
||||
Example
|
||||
|
||||
#include <asm/debug.h>
|
||||
|
||||
#define UNKNOWNSTR "data: %08x"
|
||||
|
||||
const char* messages[] =
|
||||
{"This error...........\n",
|
||||
"That error...........\n",
|
||||
"Problem..............\n",
|
||||
"Something went wrong.\n",
|
||||
"Everything ok........\n",
|
||||
NULL
|
||||
};
|
||||
|
||||
static int debug_test_format_fn(
|
||||
debug_info_t * id, struct debug_view *view,
|
||||
char *out_buf, const char *in_buf
|
||||
)
|
||||
{
|
||||
int i, rc = 0;
|
||||
|
||||
if(id->buf_size >= 4) {
|
||||
int msg_nr = *((int*)in_buf);
|
||||
if(msg_nr < sizeof(messages)/sizeof(char*) - 1)
|
||||
rc += sprintf(out_buf, "%s", messages[msg_nr]);
|
||||
else
|
||||
rc += sprintf(out_buf, UNKNOWNSTR, msg_nr);
|
||||
}
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
struct debug_view debug_test_view = {
|
||||
"myview", /* name of view */
|
||||
NULL, /* no prolog */
|
||||
&debug_dflt_header_fn, /* default header for each entry */
|
||||
&debug_test_format_fn, /* our own format function */
|
||||
NULL, /* no input function */
|
||||
NULL /* no private data */
|
||||
};
|
||||
|
||||
=====
|
||||
test:
|
||||
=====
|
||||
debug_info_t *debug_info;
|
||||
...
|
||||
debug_info = debug_register ("test", 0, 4, 4 ));
|
||||
debug_register_view(debug_info, &debug_test_view);
|
||||
for(i = 0; i < 10; i ++) debug_int_event(debug_info, 1, i);
|
||||
|
||||
> cat /sys/kernel/debug/s390dbf/test/myview
|
||||
00 00964419734:611402 1 - 00 88042ca This error...........
|
||||
00 00964419734:611405 1 - 00 88042ca That error...........
|
||||
00 00964419734:611408 1 - 00 88042ca Problem..............
|
||||
00 00964419734:611411 1 - 00 88042ca Something went wrong.
|
||||
00 00964419734:611414 1 - 00 88042ca Everything ok........
|
||||
00 00964419734:611417 1 - 00 88042ca data: 00000005
|
||||
00 00964419734:611419 1 - 00 88042ca data: 00000006
|
||||
00 00964419734:611422 1 - 00 88042ca data: 00000007
|
||||
00 00964419734:611425 1 - 00 88042ca data: 00000008
|
||||
00 00964419734:611428 1 - 00 88042ca data: 00000009
|
11
Documentation/s390/text_files.rst
Normal file
11
Documentation/s390/text_files.rst
Normal file
@ -0,0 +1,11 @@
|
||||
ibm 3270 changelog
|
||||
------------------
|
||||
|
||||
.. include:: 3270.ChangeLog
|
||||
:literal:
|
||||
|
||||
ibm 3270 config3270.sh
|
||||
----------------------
|
||||
|
||||
.. literalinclude:: config3270.sh
|
||||
:language: shell
|
@ -1,4 +1,9 @@
|
||||
Introduction:
|
||||
===============================
|
||||
Adjunct Processor (AP) facility
|
||||
===============================
|
||||
|
||||
|
||||
Introduction
|
||||
============
|
||||
The Adjunct Processor (AP) facility is an IBM Z cryptographic facility comprised
|
||||
of three AP instructions and from 1 up to 256 PCIe cryptographic adapter cards.
|
||||
@ -11,7 +16,7 @@ framework. This implementation relies considerably on the s390 virtualization
|
||||
facilities which do most of the hard work of providing direct access to AP
|
||||
devices.
|
||||
|
||||
AP Architectural Overview:
|
||||
AP Architectural Overview
|
||||
=========================
|
||||
To facilitate the comprehension of the design, let's start with some
|
||||
definitions:
|
||||
@ -31,13 +36,13 @@ definitions:
|
||||
in the LPAR, the AP bus detects the AP adapter cards assigned to the LPAR and
|
||||
creates a sysfs device for each assigned adapter. For example, if AP adapters
|
||||
4 and 10 (0x0a) are assigned to the LPAR, the AP bus will create the following
|
||||
sysfs device entries:
|
||||
sysfs device entries::
|
||||
|
||||
/sys/devices/ap/card04
|
||||
/sys/devices/ap/card0a
|
||||
|
||||
Symbolic links to these devices will also be created in the AP bus devices
|
||||
sub-directory:
|
||||
sub-directory::
|
||||
|
||||
/sys/bus/ap/devices/[card04]
|
||||
/sys/bus/ap/devices/[card04]
|
||||
@ -84,7 +89,7 @@ definitions:
|
||||
the cross product of the AP adapter and usage domain numbers detected when the
|
||||
AP bus module is loaded. For example, if adapters 4 and 10 (0x0a) and usage
|
||||
domains 6 and 71 (0x47) are assigned to the LPAR, the AP bus will create the
|
||||
following sysfs entries:
|
||||
following sysfs entries::
|
||||
|
||||
/sys/devices/ap/card04/04.0006
|
||||
/sys/devices/ap/card04/04.0047
|
||||
@ -92,7 +97,7 @@ definitions:
|
||||
/sys/devices/ap/card0a/0a.0047
|
||||
|
||||
The following symbolic links to these devices will be created in the AP bus
|
||||
devices subdirectory:
|
||||
devices subdirectory::
|
||||
|
||||
/sys/bus/ap/devices/[04.0006]
|
||||
/sys/bus/ap/devices/[04.0047]
|
||||
@ -112,7 +117,7 @@ definitions:
|
||||
domain that is not one of the usage domains, but the modified domain
|
||||
must be one of the control domains.
|
||||
|
||||
AP and SIE:
|
||||
AP and SIE
|
||||
==========
|
||||
Let's now take a look at how AP instructions executed on a guest are interpreted
|
||||
by the hardware.
|
||||
@ -153,7 +158,7 @@ and 2 and usage domains 5 and 6 are assigned to a guest, the APQNs (1,5), (1,6),
|
||||
|
||||
The APQNs can provide secure key functionality - i.e., a private key is stored
|
||||
on the adapter card for each of its domains - so each APQN must be assigned to
|
||||
at most one guest or to the linux host.
|
||||
at most one guest or to the linux host::
|
||||
|
||||
Example 1: Valid configuration:
|
||||
------------------------------
|
||||
@ -181,8 +186,8 @@ at most one guest or to the linux host.
|
||||
This is an invalid configuration because both guests have access to
|
||||
APQN (1,6).
|
||||
|
||||
The Design:
|
||||
===========
|
||||
The Design
|
||||
==========
|
||||
The design introduces three new objects:
|
||||
|
||||
1. AP matrix device
|
||||
@ -205,43 +210,43 @@ The VFIO AP (vfio_ap) device driver serves the following purposes:
|
||||
Reserve APQNs for exclusive use of KVM guests
|
||||
---------------------------------------------
|
||||
The following block diagram illustrates the mechanism by which APQNs are
|
||||
reserved:
|
||||
reserved::
|
||||
|
||||
+------------------+
|
||||
7 remove | |
|
||||
+--------------------> cex4queue driver |
|
||||
| | |
|
||||
| +------------------+
|
||||
|
|
||||
|
|
||||
| +------------------+ +-----------------+
|
||||
| 5 register driver | | 3 create | |
|
||||
| +----------------> Device core +----------> matrix device |
|
||||
| | | | | |
|
||||
| | +--------^---------+ +-----------------+
|
||||
| | |
|
||||
| | +-------------------+
|
||||
| | +-----------------------------------+ |
|
||||
| | | 4 register AP driver | | 2 register device
|
||||
| | | | |
|
||||
+--------+---+-v---+ +--------+-------+-+
|
||||
| | | |
|
||||
| ap_bus +--------------------- > vfio_ap driver |
|
||||
| | 8 probe | |
|
||||
+--------^---------+ +--^--^------------+
|
||||
6 edit | | |
|
||||
apmask | +-----------------------------+ | 9 mdev create
|
||||
aqmask | | 1 modprobe |
|
||||
+--------+-----+---+ +----------------+-+ +------------------+
|
||||
| | | |8 create | mediated |
|
||||
| admin | | VFIO device core |---------> matrix |
|
||||
| + | | | device |
|
||||
+------+-+---------+ +--------^---------+ +--------^---------+
|
||||
| | | |
|
||||
| | 9 create vfio_ap-passthrough | |
|
||||
| +------------------------------+ |
|
||||
+-------------------------------------------------------------+
|
||||
10 assign adapter/domain/control domain
|
||||
+------------------+
|
||||
7 remove | |
|
||||
+--------------------> cex4queue driver |
|
||||
| | |
|
||||
| +------------------+
|
||||
|
|
||||
|
|
||||
| +------------------+ +----------------+
|
||||
| 5 register driver | | 3 create | |
|
||||
| +----------------> Device core +----------> matrix device |
|
||||
| | | | | |
|
||||
| | +--------^---------+ +----------------+
|
||||
| | |
|
||||
| | +-------------------+
|
||||
| | +-----------------------------------+ |
|
||||
| | | 4 register AP driver | | 2 register device
|
||||
| | | | |
|
||||
+--------+---+-v---+ +--------+-------+-+
|
||||
| | | |
|
||||
| ap_bus +--------------------- > vfio_ap driver |
|
||||
| | 8 probe | |
|
||||
+--------^---------+ +--^--^------------+
|
||||
6 edit | | |
|
||||
apmask | +-----------------------------+ | 9 mdev create
|
||||
aqmask | | 1 modprobe |
|
||||
+--------+-----+---+ +----------------+-+ +----------------+
|
||||
| | | |8 create | mediated |
|
||||
| admin | | VFIO device core |---------> matrix |
|
||||
| + | | | device |
|
||||
+------+-+---------+ +--------^---------+ +--------^-------+
|
||||
| | | |
|
||||
| | 9 create vfio_ap-passthrough | |
|
||||
| +------------------------------+ |
|
||||
+-------------------------------------------------------------+
|
||||
10 assign adapter/domain/control domain
|
||||
|
||||
The process for reserving an AP queue for use by a KVM guest is:
|
||||
|
||||
@ -250,7 +255,7 @@ The process for reserving an AP queue for use by a KVM guest is:
|
||||
device with the device core. This will serve as the parent device for
|
||||
all mediated matrix devices used to configure an AP matrix for a guest.
|
||||
3. The /sys/devices/vfio_ap/matrix device is created by the device core
|
||||
4 The vfio_ap device driver will register with the AP bus for AP queue devices
|
||||
4. The vfio_ap device driver will register with the AP bus for AP queue devices
|
||||
of type 10 and higher (CEX4 and newer). The driver will provide the vfio_ap
|
||||
driver's probe and remove callback interfaces. Devices older than CEX4 queues
|
||||
are not supported to simplify the implementation by not needlessly
|
||||
@ -266,13 +271,14 @@ The process for reserving an AP queue for use by a KVM guest is:
|
||||
it.
|
||||
9. The administrator creates a passthrough type mediated matrix device to be
|
||||
used by a guest
|
||||
10 The administrator assigns the adapters, usage domains and control domains
|
||||
to be exclusively used by a guest.
|
||||
10. The administrator assigns the adapters, usage domains and control domains
|
||||
to be exclusively used by a guest.
|
||||
|
||||
Set up the VFIO mediated device interfaces
|
||||
------------------------------------------
|
||||
The VFIO AP device driver utilizes the common interface of the VFIO mediated
|
||||
device core driver to:
|
||||
|
||||
* Register an AP mediated bus driver to add a mediated matrix device to and
|
||||
remove it from a VFIO group.
|
||||
* Create and destroy a mediated matrix device
|
||||
@ -280,25 +286,25 @@ device core driver to:
|
||||
* Add a mediated matrix device to and remove it from an IOMMU group
|
||||
|
||||
The following high-level block diagram shows the main components and interfaces
|
||||
of the VFIO AP mediated matrix device driver:
|
||||
of the VFIO AP mediated matrix device driver::
|
||||
|
||||
+-------------+
|
||||
| |
|
||||
| +---------+ | mdev_register_driver() +--------------+
|
||||
| | Mdev | +<-----------------------+ |
|
||||
| | bus | | | vfio_mdev.ko |
|
||||
| | driver | +----------------------->+ |<-> VFIO user
|
||||
| +---------+ | probe()/remove() +--------------+ APIs
|
||||
| |
|
||||
| MDEV CORE |
|
||||
| MODULE |
|
||||
| mdev.ko |
|
||||
| +---------+ | mdev_register_device() +--------------+
|
||||
| |Physical | +<-----------------------+ |
|
||||
| | device | | | vfio_ap.ko |<-> matrix
|
||||
| |interface| +----------------------->+ | device
|
||||
| +---------+ | callback +--------------+
|
||||
+-------------+
|
||||
+-------------+
|
||||
| |
|
||||
| +---------+ | mdev_register_driver() +--------------+
|
||||
| | Mdev | +<-----------------------+ |
|
||||
| | bus | | | vfio_mdev.ko |
|
||||
| | driver | +----------------------->+ |<-> VFIO user
|
||||
| +---------+ | probe()/remove() +--------------+ APIs
|
||||
| |
|
||||
| MDEV CORE |
|
||||
| MODULE |
|
||||
| mdev.ko |
|
||||
| +---------+ | mdev_register_device() +--------------+
|
||||
| |Physical | +<-----------------------+ |
|
||||
| | device | | | vfio_ap.ko |<-> matrix
|
||||
| |interface| +----------------------->+ | device
|
||||
| +---------+ | callback +--------------+
|
||||
+-------------+
|
||||
|
||||
During initialization of the vfio_ap module, the matrix device is registered
|
||||
with an 'mdev_parent_ops' structure that provides the sysfs attribute
|
||||
@ -306,7 +312,8 @@ structures, mdev functions and callback interfaces for managing the mediated
|
||||
matrix device.
|
||||
|
||||
* sysfs attribute structures:
|
||||
* supported_type_groups
|
||||
|
||||
supported_type_groups
|
||||
The VFIO mediated device framework supports creation of user-defined
|
||||
mediated device types. These mediated device types are specified
|
||||
via the 'supported_type_groups' structure when a device is registered
|
||||
@ -318,61 +325,72 @@ matrix device.
|
||||
|
||||
The VFIO AP device driver will register one mediated device type for
|
||||
passthrough devices:
|
||||
|
||||
/sys/devices/vfio_ap/matrix/mdev_supported_types/vfio_ap-passthrough
|
||||
|
||||
Only the read-only attributes required by the VFIO mdev framework will
|
||||
be provided:
|
||||
... name
|
||||
... device_api
|
||||
... available_instances
|
||||
... device_api
|
||||
Where:
|
||||
* name: specifies the name of the mediated device type
|
||||
* device_api: the mediated device type's API
|
||||
* available_instances: the number of mediated matrix passthrough devices
|
||||
that can be created
|
||||
* device_api: specifies the VFIO API
|
||||
* mdev_attr_groups
|
||||
be provided::
|
||||
|
||||
... name
|
||||
... device_api
|
||||
... available_instances
|
||||
... device_api
|
||||
|
||||
Where:
|
||||
|
||||
* name:
|
||||
specifies the name of the mediated device type
|
||||
* device_api:
|
||||
the mediated device type's API
|
||||
* available_instances:
|
||||
the number of mediated matrix passthrough devices
|
||||
that can be created
|
||||
* device_api:
|
||||
specifies the VFIO API
|
||||
mdev_attr_groups
|
||||
This attribute group identifies the user-defined sysfs attributes of the
|
||||
mediated device. When a device is registered with the VFIO mediated device
|
||||
framework, the sysfs attribute files identified in the 'mdev_attr_groups'
|
||||
structure will be created in the mediated matrix device's directory. The
|
||||
sysfs attributes for a mediated matrix device are:
|
||||
* assign_adapter:
|
||||
* unassign_adapter:
|
||||
|
||||
assign_adapter / unassign_adapter:
|
||||
Write-only attributes for assigning/unassigning an AP adapter to/from the
|
||||
mediated matrix device. To assign/unassign an adapter, the APID of the
|
||||
adapter is echoed to the respective attribute file.
|
||||
* assign_domain:
|
||||
* unassign_domain:
|
||||
assign_domain / unassign_domain:
|
||||
Write-only attributes for assigning/unassigning an AP usage domain to/from
|
||||
the mediated matrix device. To assign/unassign a domain, the domain
|
||||
number of the the usage domain is echoed to the respective attribute
|
||||
file.
|
||||
* matrix:
|
||||
matrix:
|
||||
A read-only file for displaying the APQNs derived from the cross product
|
||||
of the adapter and domain numbers assigned to the mediated matrix device.
|
||||
* assign_control_domain:
|
||||
* unassign_control_domain:
|
||||
assign_control_domain / unassign_control_domain:
|
||||
Write-only attributes for assigning/unassigning an AP control domain
|
||||
to/from the mediated matrix device. To assign/unassign a control domain,
|
||||
the ID of the domain to be assigned/unassigned is echoed to the respective
|
||||
attribute file.
|
||||
* control_domains:
|
||||
control_domains:
|
||||
A read-only file for displaying the control domain numbers assigned to the
|
||||
mediated matrix device.
|
||||
|
||||
* functions:
|
||||
* create:
|
||||
|
||||
create:
|
||||
allocates the ap_matrix_mdev structure used by the vfio_ap driver to:
|
||||
|
||||
* Store the reference to the KVM structure for the guest using the mdev
|
||||
* Store the AP matrix configuration for the adapters, domains, and control
|
||||
domains assigned via the corresponding sysfs attributes files
|
||||
* remove:
|
||||
|
||||
remove:
|
||||
deallocates the mediated matrix device's ap_matrix_mdev structure. This will
|
||||
be allowed only if a running guest is not using the mdev.
|
||||
|
||||
* callback interfaces
|
||||
* open:
|
||||
|
||||
open:
|
||||
The vfio_ap driver uses this callback to register a
|
||||
VFIO_GROUP_NOTIFY_SET_KVM notifier callback function for the mdev matrix
|
||||
device. The open is invoked when QEMU connects the VFIO iommu group
|
||||
@ -380,16 +398,17 @@ matrix device.
|
||||
to configure the KVM guest is provided via this callback. The KVM structure,
|
||||
is used to configure the guest's access to the AP matrix defined via the
|
||||
mediated matrix device's sysfs attribute files.
|
||||
* release:
|
||||
release:
|
||||
unregisters the VFIO_GROUP_NOTIFY_SET_KVM notifier callback function for the
|
||||
mdev matrix device and deconfigures the guest's AP matrix.
|
||||
|
||||
Configure the APM, AQM and ADM in the CRYCB:
|
||||
Configure the APM, AQM and ADM in the CRYCB
|
||||
-------------------------------------------
|
||||
Configuring the AP matrix for a KVM guest will be performed when the
|
||||
VFIO_GROUP_NOTIFY_SET_KVM notifier callback is invoked. The notifier
|
||||
function is called when QEMU connects to KVM. The guest's AP matrix is
|
||||
configured via it's CRYCB by:
|
||||
|
||||
* Setting the bits in the APM corresponding to the APIDs assigned to the
|
||||
mediated matrix device via its 'assign_adapter' interface.
|
||||
* Setting the bits in the AQM corresponding to the domains assigned to the
|
||||
@ -418,12 +437,12 @@ available to a KVM guest via the following CPU model features:
|
||||
|
||||
Note: If the user chooses to specify a CPU model different than the 'host'
|
||||
model to QEMU, the CPU model features and facilities need to be turned on
|
||||
explicitly; for example:
|
||||
explicitly; for example::
|
||||
|
||||
/usr/bin/qemu-system-s390x ... -cpu z13,ap=on,apqci=on,apft=on
|
||||
|
||||
A guest can be precluded from using AP features/facilities by turning them off
|
||||
explicitly; for example:
|
||||
explicitly; for example::
|
||||
|
||||
/usr/bin/qemu-system-s390x ... -cpu host,ap=off,apqci=off,apft=off
|
||||
|
||||
@ -435,7 +454,7 @@ the APFT facility is not installed on the guest, then the probe of device
|
||||
drivers will fail since only type 10 and newer devices can be configured for
|
||||
guest use.
|
||||
|
||||
Example:
|
||||
Example
|
||||
=======
|
||||
Let's now provide an example to illustrate how KVM guests may be given
|
||||
access to AP facilities. For this example, we will show how to configure
|
||||
@ -444,30 +463,36 @@ look like this:
|
||||
|
||||
Guest1
|
||||
------
|
||||
=========== ===== ============
|
||||
CARD.DOMAIN TYPE MODE
|
||||
------------------------------
|
||||
=========== ===== ============
|
||||
05 CEX5C CCA-Coproc
|
||||
05.0004 CEX5C CCA-Coproc
|
||||
05.00ab CEX5C CCA-Coproc
|
||||
06 CEX5A Accelerator
|
||||
06.0004 CEX5A Accelerator
|
||||
06.00ab CEX5C CCA-Coproc
|
||||
=========== ===== ============
|
||||
|
||||
Guest2
|
||||
------
|
||||
=========== ===== ============
|
||||
CARD.DOMAIN TYPE MODE
|
||||
------------------------------
|
||||
=========== ===== ============
|
||||
05 CEX5A Accelerator
|
||||
05.0047 CEX5A Accelerator
|
||||
05.00ff CEX5A Accelerator
|
||||
=========== ===== ============
|
||||
|
||||
Guest2
|
||||
------
|
||||
=========== ===== ============
|
||||
CARD.DOMAIN TYPE MODE
|
||||
------------------------------
|
||||
=========== ===== ============
|
||||
06 CEX5A Accelerator
|
||||
06.0047 CEX5A Accelerator
|
||||
06.00ff CEX5A Accelerator
|
||||
=========== ===== ============
|
||||
|
||||
These are the steps:
|
||||
|
||||
@ -492,25 +517,26 @@ These are the steps:
|
||||
* VFIO_MDEV_DEVICE
|
||||
* KVM
|
||||
|
||||
If using make menuconfig select the following to build the vfio_ap module:
|
||||
-> Device Drivers
|
||||
-> IOMMU Hardware Support
|
||||
select S390 AP IOMMU Support
|
||||
-> VFIO Non-Privileged userspace driver framework
|
||||
-> Mediated device driver frramework
|
||||
-> VFIO driver for Mediated devices
|
||||
-> I/O subsystem
|
||||
-> VFIO support for AP devices
|
||||
If using make menuconfig select the following to build the vfio_ap module::
|
||||
|
||||
-> Device Drivers
|
||||
-> IOMMU Hardware Support
|
||||
select S390 AP IOMMU Support
|
||||
-> VFIO Non-Privileged userspace driver framework
|
||||
-> Mediated device driver frramework
|
||||
-> VFIO driver for Mediated devices
|
||||
-> I/O subsystem
|
||||
-> VFIO support for AP devices
|
||||
|
||||
2. Secure the AP queues to be used by the three guests so that the host can not
|
||||
access them. To secure them, there are two sysfs files that specify
|
||||
bitmasks marking a subset of the APQN range as 'usable by the default AP
|
||||
queue device drivers' or 'not usable by the default device drivers' and thus
|
||||
available for use by the vfio_ap device driver'. The location of the sysfs
|
||||
files containing the masks are:
|
||||
files containing the masks are::
|
||||
|
||||
/sys/bus/ap/apmask
|
||||
/sys/bus/ap/aqmask
|
||||
/sys/bus/ap/apmask
|
||||
/sys/bus/ap/aqmask
|
||||
|
||||
The 'apmask' is a 256-bit mask that identifies a set of AP adapter IDs
|
||||
(APID). Each bit in the mask, from left to right (i.e., from most significant
|
||||
@ -526,7 +552,7 @@ These are the steps:
|
||||
queue device drivers; otherwise, the APQI is usable by the vfio_ap device
|
||||
driver.
|
||||
|
||||
Take, for example, the following mask:
|
||||
Take, for example, the following mask::
|
||||
|
||||
0x7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
|
||||
@ -548,68 +574,70 @@ These are the steps:
|
||||
respective sysfs mask file in one of two formats:
|
||||
|
||||
* An absolute hex string starting with 0x - like "0x12345678" - sets
|
||||
the mask. If the given string is shorter than the mask, it is padded
|
||||
with 0s on the right; for example, specifying a mask value of 0x41 is
|
||||
the same as specifying:
|
||||
the mask. If the given string is shorter than the mask, it is padded
|
||||
with 0s on the right; for example, specifying a mask value of 0x41 is
|
||||
the same as specifying::
|
||||
|
||||
0x4100000000000000000000000000000000000000000000000000000000000000
|
||||
0x4100000000000000000000000000000000000000000000000000000000000000
|
||||
|
||||
Keep in mind that the mask reads from left to right (i.e., most
|
||||
significant to least significant bit in big endian order), so the mask
|
||||
above identifies device numbers 1 and 7 (01000001).
|
||||
Keep in mind that the mask reads from left to right (i.e., most
|
||||
significant to least significant bit in big endian order), so the mask
|
||||
above identifies device numbers 1 and 7 (01000001).
|
||||
|
||||
If the string is longer than the mask, the operation is terminated with
|
||||
an error (EINVAL).
|
||||
If the string is longer than the mask, the operation is terminated with
|
||||
an error (EINVAL).
|
||||
|
||||
* Individual bits in the mask can be switched on and off by specifying
|
||||
each bit number to be switched in a comma separated list. Each bit
|
||||
number string must be prepended with a ('+') or minus ('-') to indicate
|
||||
the corresponding bit is to be switched on ('+') or off ('-'). Some
|
||||
valid values are:
|
||||
each bit number to be switched in a comma separated list. Each bit
|
||||
number string must be prepended with a ('+') or minus ('-') to indicate
|
||||
the corresponding bit is to be switched on ('+') or off ('-'). Some
|
||||
valid values are:
|
||||
|
||||
"+0" switches bit 0 on
|
||||
"-13" switches bit 13 off
|
||||
"+0x41" switches bit 65 on
|
||||
"-0xff" switches bit 255 off
|
||||
- "+0" switches bit 0 on
|
||||
- "-13" switches bit 13 off
|
||||
- "+0x41" switches bit 65 on
|
||||
- "-0xff" switches bit 255 off
|
||||
|
||||
The following example:
|
||||
+0,-6,+0x47,-0xf0
|
||||
The following example:
|
||||
|
||||
Switches bits 0 and 71 (0x47) on
|
||||
Switches bits 6 and 240 (0xf0) off
|
||||
+0,-6,+0x47,-0xf0
|
||||
|
||||
Note that the bits not specified in the list remain as they were before
|
||||
the operation.
|
||||
Switches bits 0 and 71 (0x47) on
|
||||
|
||||
Switches bits 6 and 240 (0xf0) off
|
||||
|
||||
Note that the bits not specified in the list remain as they were before
|
||||
the operation.
|
||||
|
||||
2. The masks can also be changed at boot time via parameters on the kernel
|
||||
command line like this:
|
||||
|
||||
ap.apmask=0xffff ap.aqmask=0x40
|
||||
ap.apmask=0xffff ap.aqmask=0x40
|
||||
|
||||
This would create the following masks:
|
||||
This would create the following masks::
|
||||
|
||||
apmask:
|
||||
0xffff000000000000000000000000000000000000000000000000000000000000
|
||||
apmask:
|
||||
0xffff000000000000000000000000000000000000000000000000000000000000
|
||||
|
||||
aqmask:
|
||||
0x4000000000000000000000000000000000000000000000000000000000000000
|
||||
aqmask:
|
||||
0x4000000000000000000000000000000000000000000000000000000000000000
|
||||
|
||||
Resulting in these two pools:
|
||||
Resulting in these two pools::
|
||||
|
||||
default drivers pool: adapter 0-15, domain 1
|
||||
alternate drivers pool: adapter 16-255, domains 0, 2-255
|
||||
default drivers pool: adapter 0-15, domain 1
|
||||
alternate drivers pool: adapter 16-255, domains 0, 2-255
|
||||
|
||||
Securing the APQNs for our example:
|
||||
----------------------------------
|
||||
Securing the APQNs for our example
|
||||
----------------------------------
|
||||
To secure the AP queues 05.0004, 05.0047, 05.00ab, 05.00ff, 06.0004, 06.0047,
|
||||
06.00ab, and 06.00ff for use by the vfio_ap device driver, the corresponding
|
||||
APQNs can either be removed from the default masks:
|
||||
APQNs can either be removed from the default masks::
|
||||
|
||||
echo -5,-6 > /sys/bus/ap/apmask
|
||||
|
||||
echo -4,-0x47,-0xab,-0xff > /sys/bus/ap/aqmask
|
||||
|
||||
Or the masks can be set as follows:
|
||||
Or the masks can be set as follows::
|
||||
|
||||
echo 0xf9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff \
|
||||
> apmask
|
||||
@ -620,19 +648,19 @@ These are the steps:
|
||||
This will result in AP queues 05.0004, 05.0047, 05.00ab, 05.00ff, 06.0004,
|
||||
06.0047, 06.00ab, and 06.00ff getting bound to the vfio_ap device driver. The
|
||||
sysfs directory for the vfio_ap device driver will now contain symbolic links
|
||||
to the AP queue devices bound to it:
|
||||
to the AP queue devices bound to it::
|
||||
|
||||
/sys/bus/ap
|
||||
... [drivers]
|
||||
...... [vfio_ap]
|
||||
......... [05.0004]
|
||||
......... [05.0047]
|
||||
......... [05.00ab]
|
||||
......... [05.00ff]
|
||||
......... [06.0004]
|
||||
......... [06.0047]
|
||||
......... [06.00ab]
|
||||
......... [06.00ff]
|
||||
/sys/bus/ap
|
||||
... [drivers]
|
||||
...... [vfio_ap]
|
||||
......... [05.0004]
|
||||
......... [05.0047]
|
||||
......... [05.00ab]
|
||||
......... [05.00ff]
|
||||
......... [06.0004]
|
||||
......... [06.0047]
|
||||
......... [06.00ab]
|
||||
......... [06.00ff]
|
||||
|
||||
Keep in mind that only type 10 and newer adapters (i.e., CEX4 and later)
|
||||
can be bound to the vfio_ap device driver. The reason for this is to
|
||||
@ -645,96 +673,96 @@ These are the steps:
|
||||
queue device can be read from the parent card's sysfs directory. For example,
|
||||
to see the hardware type of the queue 05.0004:
|
||||
|
||||
cat /sys/bus/ap/devices/card05/hwtype
|
||||
cat /sys/bus/ap/devices/card05/hwtype
|
||||
|
||||
The hwtype must be 10 or higher (CEX4 or newer) in order to be bound to the
|
||||
vfio_ap device driver.
|
||||
|
||||
3. Create the mediated devices needed to configure the AP matrixes for the
|
||||
three guests and to provide an interface to the vfio_ap driver for
|
||||
use by the guests:
|
||||
use by the guests::
|
||||
|
||||
/sys/devices/vfio_ap/matrix/
|
||||
--- [mdev_supported_types]
|
||||
------ [vfio_ap-passthrough] (passthrough mediated matrix device type)
|
||||
--------- create
|
||||
--------- [devices]
|
||||
/sys/devices/vfio_ap/matrix/
|
||||
--- [mdev_supported_types]
|
||||
------ [vfio_ap-passthrough] (passthrough mediated matrix device type)
|
||||
--------- create
|
||||
--------- [devices]
|
||||
|
||||
To create the mediated devices for the three guests:
|
||||
To create the mediated devices for the three guests::
|
||||
|
||||
uuidgen > create
|
||||
uuidgen > create
|
||||
uuidgen > create
|
||||
|
||||
or
|
||||
or
|
||||
|
||||
echo $uuid1 > create
|
||||
echo $uuid2 > create
|
||||
echo $uuid3 > create
|
||||
echo $uuid1 > create
|
||||
echo $uuid2 > create
|
||||
echo $uuid3 > create
|
||||
|
||||
This will create three mediated devices in the [devices] subdirectory named
|
||||
after the UUID written to the create attribute file. We call them $uuid1,
|
||||
$uuid2 and $uuid3 and this is the sysfs directory structure after creation:
|
||||
$uuid2 and $uuid3 and this is the sysfs directory structure after creation::
|
||||
|
||||
/sys/devices/vfio_ap/matrix/
|
||||
--- [mdev_supported_types]
|
||||
------ [vfio_ap-passthrough]
|
||||
--------- [devices]
|
||||
------------ [$uuid1]
|
||||
--------------- assign_adapter
|
||||
--------------- assign_control_domain
|
||||
--------------- assign_domain
|
||||
--------------- matrix
|
||||
--------------- unassign_adapter
|
||||
--------------- unassign_control_domain
|
||||
--------------- unassign_domain
|
||||
/sys/devices/vfio_ap/matrix/
|
||||
--- [mdev_supported_types]
|
||||
------ [vfio_ap-passthrough]
|
||||
--------- [devices]
|
||||
------------ [$uuid1]
|
||||
--------------- assign_adapter
|
||||
--------------- assign_control_domain
|
||||
--------------- assign_domain
|
||||
--------------- matrix
|
||||
--------------- unassign_adapter
|
||||
--------------- unassign_control_domain
|
||||
--------------- unassign_domain
|
||||
|
||||
------------ [$uuid2]
|
||||
--------------- assign_adapter
|
||||
--------------- assign_control_domain
|
||||
--------------- assign_domain
|
||||
--------------- matrix
|
||||
--------------- unassign_adapter
|
||||
----------------unassign_control_domain
|
||||
----------------unassign_domain
|
||||
------------ [$uuid2]
|
||||
--------------- assign_adapter
|
||||
--------------- assign_control_domain
|
||||
--------------- assign_domain
|
||||
--------------- matrix
|
||||
--------------- unassign_adapter
|
||||
----------------unassign_control_domain
|
||||
----------------unassign_domain
|
||||
|
||||
------------ [$uuid3]
|
||||
--------------- assign_adapter
|
||||
--------------- assign_control_domain
|
||||
--------------- assign_domain
|
||||
--------------- matrix
|
||||
--------------- unassign_adapter
|
||||
----------------unassign_control_domain
|
||||
----------------unassign_domain
|
||||
------------ [$uuid3]
|
||||
--------------- assign_adapter
|
||||
--------------- assign_control_domain
|
||||
--------------- assign_domain
|
||||
--------------- matrix
|
||||
--------------- unassign_adapter
|
||||
----------------unassign_control_domain
|
||||
----------------unassign_domain
|
||||
|
||||
4. The administrator now needs to configure the matrixes for the mediated
|
||||
devices $uuid1 (for Guest1), $uuid2 (for Guest2) and $uuid3 (for Guest3).
|
||||
|
||||
This is how the matrix is configured for Guest1:
|
||||
This is how the matrix is configured for Guest1::
|
||||
|
||||
echo 5 > assign_adapter
|
||||
echo 6 > assign_adapter
|
||||
echo 4 > assign_domain
|
||||
echo 0xab > assign_domain
|
||||
|
||||
Control domains can similarly be assigned using the assign_control_domain
|
||||
sysfs file.
|
||||
Control domains can similarly be assigned using the assign_control_domain
|
||||
sysfs file.
|
||||
|
||||
If a mistake is made configuring an adapter, domain or control domain,
|
||||
you can use the unassign_xxx files to unassign the adapter, domain or
|
||||
control domain.
|
||||
If a mistake is made configuring an adapter, domain or control domain,
|
||||
you can use the unassign_xxx files to unassign the adapter, domain or
|
||||
control domain.
|
||||
|
||||
To display the matrix configuration for Guest1:
|
||||
To display the matrix configuration for Guest1::
|
||||
|
||||
cat matrix
|
||||
cat matrix
|
||||
|
||||
This is how the matrix is configured for Guest2:
|
||||
This is how the matrix is configured for Guest2::
|
||||
|
||||
echo 5 > assign_adapter
|
||||
echo 0x47 > assign_domain
|
||||
echo 0xff > assign_domain
|
||||
|
||||
This is how the matrix is configured for Guest3:
|
||||
This is how the matrix is configured for Guest3::
|
||||
|
||||
echo 6 > assign_adapter
|
||||
echo 0x47 > assign_domain
|
||||
@ -783,24 +811,24 @@ These are the steps:
|
||||
configured for the system. If a control domain number higher than the maximum
|
||||
is specified, the operation will terminate with an error (ENODEV).
|
||||
|
||||
5. Start Guest1:
|
||||
5. Start Guest1::
|
||||
|
||||
/usr/bin/qemu-system-s390x ... -cpu host,ap=on,apqci=on,apft=on \
|
||||
-device vfio-ap,sysfsdev=/sys/devices/vfio_ap/matrix/$uuid1 ...
|
||||
/usr/bin/qemu-system-s390x ... -cpu host,ap=on,apqci=on,apft=on \
|
||||
-device vfio-ap,sysfsdev=/sys/devices/vfio_ap/matrix/$uuid1 ...
|
||||
|
||||
7. Start Guest2:
|
||||
7. Start Guest2::
|
||||
|
||||
/usr/bin/qemu-system-s390x ... -cpu host,ap=on,apqci=on,apft=on \
|
||||
-device vfio-ap,sysfsdev=/sys/devices/vfio_ap/matrix/$uuid2 ...
|
||||
/usr/bin/qemu-system-s390x ... -cpu host,ap=on,apqci=on,apft=on \
|
||||
-device vfio-ap,sysfsdev=/sys/devices/vfio_ap/matrix/$uuid2 ...
|
||||
|
||||
7. Start Guest3:
|
||||
7. Start Guest3::
|
||||
|
||||
/usr/bin/qemu-system-s390x ... -cpu host,ap=on,apqci=on,apft=on \
|
||||
-device vfio-ap,sysfsdev=/sys/devices/vfio_ap/matrix/$uuid3 ...
|
||||
/usr/bin/qemu-system-s390x ... -cpu host,ap=on,apqci=on,apft=on \
|
||||
-device vfio-ap,sysfsdev=/sys/devices/vfio_ap/matrix/$uuid3 ...
|
||||
|
||||
When the guest is shut down, the mediated matrix devices may be removed.
|
||||
|
||||
Using our example again, to remove the mediated matrix device $uuid1:
|
||||
Using our example again, to remove the mediated matrix device $uuid1::
|
||||
|
||||
/sys/devices/vfio_ap/matrix/
|
||||
--- [mdev_supported_types]
|
||||
@ -809,18 +837,19 @@ Using our example again, to remove the mediated matrix device $uuid1:
|
||||
------------ [$uuid1]
|
||||
--------------- remove
|
||||
|
||||
::
|
||||
|
||||
echo 1 > remove
|
||||
|
||||
This will remove all of the mdev matrix device's sysfs structures including
|
||||
the mdev device itself. To recreate and reconfigure the mdev matrix device,
|
||||
all of the steps starting with step 3 will have to be performed again. Note
|
||||
that the remove will fail if a guest using the mdev is still running.
|
||||
This will remove all of the mdev matrix device's sysfs structures including
|
||||
the mdev device itself. To recreate and reconfigure the mdev matrix device,
|
||||
all of the steps starting with step 3 will have to be performed again. Note
|
||||
that the remove will fail if a guest using the mdev is still running.
|
||||
|
||||
It is not necessary to remove an mdev matrix device, but one may want to
|
||||
remove it if no guest will use it during the remaining lifetime of the linux
|
||||
host. If the mdev matrix device is removed, one may want to also reconfigure
|
||||
the pool of adapters and queues reserved for use by the default drivers.
|
||||
It is not necessary to remove an mdev matrix device, but one may want to
|
||||
remove it if no guest will use it during the remaining lifetime of the linux
|
||||
host. If the mdev matrix device is removed, one may want to also reconfigure
|
||||
the pool of adapters and queues reserved for use by the default drivers.
|
||||
|
||||
Limitations
|
||||
===========
|
@ -1,3 +1,4 @@
|
||||
==================================
|
||||
vfio-ccw: the basic infrastructure
|
||||
==================================
|
||||
|
||||
@ -11,9 +12,11 @@ virtual machine, while vfio is the means.
|
||||
Different than other hardware architectures, s390 has defined a unified
|
||||
I/O access method, which is so called Channel I/O. It has its own access
|
||||
patterns:
|
||||
|
||||
- Channel programs run asynchronously on a separate (co)processor.
|
||||
- The channel subsystem will access any memory designated by the caller
|
||||
in the channel program directly, i.e. there is no iommu involved.
|
||||
|
||||
Thus when we introduce vfio support for these devices, we realize it
|
||||
with a mediated device (mdev) implementation. The vfio mdev will be
|
||||
added to an iommu group, so as to make itself able to be managed by the
|
||||
@ -24,6 +27,7 @@ to perform I/O instructions.
|
||||
|
||||
This document does not intend to explain the s390 I/O architecture in
|
||||
every detail. More information/reference could be found here:
|
||||
|
||||
- A good start to know Channel I/O in general:
|
||||
https://en.wikipedia.org/wiki/Channel_I/O
|
||||
- s390 architecture:
|
||||
@ -80,6 +84,7 @@ until interrupted. The I/O completion result is received by the
|
||||
interrupt handler in the form of interrupt response block (IRB).
|
||||
|
||||
Back to vfio-ccw, in short:
|
||||
|
||||
- ORBs and channel programs are built in guest kernel (with guest
|
||||
physical addresses).
|
||||
- ORBs and channel programs are passed to the host kernel.
|
||||
@ -106,6 +111,7 @@ it gets sent to hardware.
|
||||
|
||||
Within this implementation, we have two drivers for two types of
|
||||
devices:
|
||||
|
||||
- The vfio_ccw driver for the physical subchannel device.
|
||||
This is an I/O subchannel driver for the real subchannel device. It
|
||||
realizes a group of callbacks and registers to the mdev framework as a
|
||||
@ -137,7 +143,7 @@ devices:
|
||||
vfio_pin_pages and a vfio_unpin_pages interfaces from the vfio iommu
|
||||
backend for the physical devices to pin and unpin pages by demand.
|
||||
|
||||
Below is a high Level block diagram.
|
||||
Below is a high Level block diagram::
|
||||
|
||||
+-------------+
|
||||
| |
|
||||
@ -158,6 +164,7 @@ Below is a high Level block diagram.
|
||||
+-------------+
|
||||
|
||||
The process of how these work together.
|
||||
|
||||
1. vfio_ccw.ko drives the physical I/O subchannel, and registers the
|
||||
physical device (with callbacks) to mdev framework.
|
||||
When vfio_ccw probing the subchannel device, it registers device
|
||||
@ -178,17 +185,17 @@ vfio-ccw I/O region
|
||||
|
||||
An I/O region is used to accept channel program request from user
|
||||
space and store I/O interrupt result for user space to retrieve. The
|
||||
definition of the region is:
|
||||
definition of the region is::
|
||||
|
||||
struct ccw_io_region {
|
||||
#define ORB_AREA_SIZE 12
|
||||
__u8 orb_area[ORB_AREA_SIZE];
|
||||
#define SCSW_AREA_SIZE 12
|
||||
__u8 scsw_area[SCSW_AREA_SIZE];
|
||||
#define IRB_AREA_SIZE 96
|
||||
__u8 irb_area[IRB_AREA_SIZE];
|
||||
__u32 ret_code;
|
||||
} __packed;
|
||||
struct ccw_io_region {
|
||||
#define ORB_AREA_SIZE 12
|
||||
__u8 orb_area[ORB_AREA_SIZE];
|
||||
#define SCSW_AREA_SIZE 12
|
||||
__u8 scsw_area[SCSW_AREA_SIZE];
|
||||
#define IRB_AREA_SIZE 96
|
||||
__u8 irb_area[IRB_AREA_SIZE];
|
||||
__u32 ret_code;
|
||||
} __packed;
|
||||
|
||||
While starting an I/O request, orb_area should be filled with the
|
||||
guest ORB, and scsw_area should be filled with the SCSW of the Virtual
|
||||
@ -205,7 +212,7 @@ vfio-ccw follows what vfio-pci did on the s390 platform and uses
|
||||
vfio-iommu-type1 as the vfio iommu backend.
|
||||
|
||||
* CCW translation APIs
|
||||
A group of APIs (start with 'cp_') to do CCW translation. The CCWs
|
||||
A group of APIs (start with `cp_`) to do CCW translation. The CCWs
|
||||
passed in by a user space program are organized with their guest
|
||||
physical memory addresses. These APIs will copy the CCWs into kernel
|
||||
space, and assemble a runnable kernel channel program by updating the
|
||||
@ -217,12 +224,14 @@ vfio-iommu-type1 as the vfio iommu backend.
|
||||
This driver utilizes the CCW translation APIs and introduces
|
||||
vfio_ccw, which is the driver for the I/O subchannel devices you want
|
||||
to pass through.
|
||||
vfio_ccw implements the following vfio ioctls:
|
||||
vfio_ccw implements the following vfio ioctls::
|
||||
|
||||
VFIO_DEVICE_GET_INFO
|
||||
VFIO_DEVICE_GET_IRQ_INFO
|
||||
VFIO_DEVICE_GET_REGION_INFO
|
||||
VFIO_DEVICE_RESET
|
||||
VFIO_DEVICE_SET_IRQS
|
||||
|
||||
This provides an I/O region, so that the user space program can pass a
|
||||
channel program to the kernel, to do further CCW translation before
|
||||
issuing them to a real device.
|
||||
@ -236,32 +245,49 @@ bit more detail how an I/O request triggered by the QEMU guest will be
|
||||
handled (without error handling).
|
||||
|
||||
Explanation:
|
||||
Q1-Q7: QEMU side process.
|
||||
K1-K5: Kernel side process.
|
||||
|
||||
Q1. Get I/O region info during initialization.
|
||||
Q2. Setup event notifier and handler to handle I/O completion.
|
||||
- Q1-Q7: QEMU side process.
|
||||
- K1-K5: Kernel side process.
|
||||
|
||||
Q1.
|
||||
Get I/O region info during initialization.
|
||||
|
||||
Q2.
|
||||
Setup event notifier and handler to handle I/O completion.
|
||||
|
||||
... ...
|
||||
|
||||
Q3. Intercept a ssch instruction.
|
||||
Q4. Write the guest channel program and ORB to the I/O region.
|
||||
K1. Copy from guest to kernel.
|
||||
K2. Translate the guest channel program to a host kernel space
|
||||
channel program, which becomes runnable for a real device.
|
||||
K3. With the necessary information contained in the orb passed in
|
||||
by QEMU, issue the ccwchain to the device.
|
||||
K4. Return the ssch CC code.
|
||||
Q5. Return the CC code to the guest.
|
||||
Q3.
|
||||
Intercept a ssch instruction.
|
||||
Q4.
|
||||
Write the guest channel program and ORB to the I/O region.
|
||||
|
||||
K1.
|
||||
Copy from guest to kernel.
|
||||
K2.
|
||||
Translate the guest channel program to a host kernel space
|
||||
channel program, which becomes runnable for a real device.
|
||||
K3.
|
||||
With the necessary information contained in the orb passed in
|
||||
by QEMU, issue the ccwchain to the device.
|
||||
K4.
|
||||
Return the ssch CC code.
|
||||
Q5.
|
||||
Return the CC code to the guest.
|
||||
|
||||
... ...
|
||||
|
||||
K5. Interrupt handler gets the I/O result and write the result to
|
||||
the I/O region.
|
||||
K6. Signal QEMU to retrieve the result.
|
||||
Q6. Get the signal and event handler reads out the result from the I/O
|
||||
K5.
|
||||
Interrupt handler gets the I/O result and write the result to
|
||||
the I/O region.
|
||||
K6.
|
||||
Signal QEMU to retrieve the result.
|
||||
|
||||
Q6.
|
||||
Get the signal and event handler reads out the result from the I/O
|
||||
region.
|
||||
Q7. Update the irb for the guest.
|
||||
Q7.
|
||||
Update the irb for the guest.
|
||||
|
||||
Limitations
|
||||
-----------
|
||||
@ -295,6 +321,6 @@ Reference
|
||||
1. ESA/s390 Principles of Operation manual (IBM Form. No. SA22-7832)
|
||||
2. ESA/390 Common I/O Device Commands manual (IBM Form. No. SA22-7204)
|
||||
3. https://en.wikipedia.org/wiki/Channel_I/O
|
||||
4. Documentation/s390/cds.txt
|
||||
4. Documentation/s390/cds.rst
|
||||
5. Documentation/vfio.txt
|
||||
6. Documentation/vfio-mediated-device.txt
|
@ -1,4 +1,6 @@
|
||||
==================================
|
||||
The s390 SCSI dump tool (zfcpdump)
|
||||
==================================
|
||||
|
||||
System z machines (z900 or higher) provide hardware support for creating system
|
||||
dumps on SCSI disks. The dump process is initiated by booting a dump tool, which
|
@ -13703,7 +13703,7 @@ L: linux-s390@vger.kernel.org
|
||||
L: kvm@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/s390/cio/vfio_ccw*
|
||||
F: Documentation/s390/vfio-ccw.txt
|
||||
F: Documentation/s390/vfio-ccw.rst
|
||||
F: include/uapi/linux/vfio_ccw.h
|
||||
|
||||
S390 ZCRYPT DRIVER
|
||||
@ -13723,7 +13723,7 @@ S: Supported
|
||||
F: drivers/s390/crypto/vfio_ap_drv.c
|
||||
F: drivers/s390/crypto/vfio_ap_private.h
|
||||
F: drivers/s390/crypto/vfio_ap_ops.c
|
||||
F: Documentation/s390/vfio-ap.txt
|
||||
F: Documentation/s390/vfio-ap.rst
|
||||
|
||||
S390 ZFCP DRIVER
|
||||
M: Steffen Maier <maier@linux.ibm.com>
|
||||
|
@ -810,9 +810,9 @@ config CRASH_DUMP
|
||||
Crash dump kernels are loaded in the main kernel with kexec-tools
|
||||
into a specially reserved region and then later executed after
|
||||
a crash by kdump/kexec.
|
||||
Refer to <file:Documentation/s390/zfcpdump.txt> for more details on this.
|
||||
Refer to <file:Documentation/s390/zfcpdump.rst> for more details on this.
|
||||
This option also enables s390 zfcpdump.
|
||||
See also <file:Documentation/s390/zfcpdump.txt>
|
||||
See also <file:Documentation/s390/zfcpdump.rst>
|
||||
|
||||
endmenu
|
||||
|
||||
|
@ -152,7 +152,7 @@ static inline debug_entry_t *debug_text_event(debug_info_t *id, int level,
|
||||
|
||||
/*
|
||||
* IMPORTANT: Use "%s" in sprintf format strings with care! Only pointers are
|
||||
* stored in the s390dbf. See Documentation/s390/s390dbf.txt for more details!
|
||||
* stored in the s390dbf. See Documentation/s390/s390dbf.rst for more details!
|
||||
*/
|
||||
extern debug_entry_t *
|
||||
__debug_sprintf_event(debug_info_t *id, int level, char *string, ...)
|
||||
@ -210,7 +210,7 @@ static inline debug_entry_t *debug_text_exception(debug_info_t *id, int level,
|
||||
|
||||
/*
|
||||
* IMPORTANT: Use "%s" in sprintf format strings with care! Only pointers are
|
||||
* stored in the s390dbf. See Documentation/s390/s390dbf.txt for more details!
|
||||
* stored in the s390dbf. See Documentation/s390/s390dbf.rst for more details!
|
||||
*/
|
||||
extern debug_entry_t *
|
||||
__debug_sprintf_exception(debug_info_t *id, int level, char *string, ...)
|
||||
|
@ -4,7 +4,7 @@
|
||||
* dumps on SCSI disks (zfcpdump). The "zcore/mem" debugfs file shows the same
|
||||
* dump format as s390 standalone dumps.
|
||||
*
|
||||
* For more information please refer to Documentation/s390/zfcpdump.txt
|
||||
* For more information please refer to Documentation/s390/zfcpdump.rst
|
||||
*
|
||||
* Copyright IBM Corp. 2003, 2008
|
||||
* Author(s): Michael Holzheu
|
||||
|
Loading…
Reference in New Issue
Block a user