Copyright © 2007 IBM Corp.
This documentation is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
For more details see the file COPYING in the source distribution of Linux.
Table of Contents
This document describes the interfaces available for device drivers that drive s390 based channel attached I/O devices. This includes interfaces for interaction with the hardware and interfaces for interacting with the common driver core. Those interfaces are provided by the s390 common I/O layer.
The document assumes a familarity with the technical terms associated with the s390 channel I/O architecture. For a description of this architecture, please refer to the "z/Architecture: Principles of Operation", IBM publication no. SA22-7832.
While most I/O devices on a s390 system are typically driven through the channel I/O mechanism described here, there are various other methods (like the diag interface). These are out of the scope of this document.
Some additional information can also be found in the kernel source under Documentation/s390/driver-model.txt.
Table of Contents
The ccw bus typically contains the majority of devices available to a s390 system. Named after the channel command word (ccw), the basic command structure used to address its devices, the ccw bus contains so-called channel attached devices. They are addressed via I/O subchannels, visible on the css bus. A device driver for channel-attached devices, however, will never interact with the subchannel directly, but only via the I/O device on the ccw bus, the ccw device.
Some hardware structures have been translated into C structures for use by the common I/O layer and device drivers. For more information on the hardware structures represented here, please consult the Principles of Operation.
struct ccw1 — channel command word
struct ccw1 { __u8 cmd_code; __u8 flags; __u16 count; __u32 cda; };
struct erw — extended report word
struct erw { __u32 res0:3; __u32 auth:1; __u32 pvrf:1; __u32 cpt:1; __u32 fsavf:1; __u32 cons:1; __u32 scavf:1; __u32 fsaf:1; __u32 scnt:6; __u32 res16:16; };
struct erw_eadm — EADM Subchannel extended report word
struct erw_eadm { __u32 b:1; __u32 r:1; };
struct sublog — subchannel logout area
struct sublog { __u32 res0:1; __u32 esf:7; __u32 lpum:8; __u32 arep:1; __u32 fvf:5; __u32 sacc:2; __u32 termc:2; __u32 devsc:1; __u32 serr:1; __u32 ioerr:1; __u32 seqc:3; };
struct esw0 — Format 0 Extended Status Word (ESW)
struct esw0 { struct sublog sublog; struct erw erw; __u32 faddr[2]; __u32 saddr; };
struct esw1 — Format 1 Extended Status Word (ESW)
struct esw1 { __u8 zero0; __u8 lpum; __u16 zero16; struct erw erw; __u32 zeros[3]; };
struct esw2 — Format 2 Extended Status Word (ESW)
struct esw2 { __u8 zero0; __u8 lpum; __u16 dcti; struct erw erw; __u32 zeros[3]; };
struct esw3 — Format 3 Extended Status Word (ESW)
struct esw3 { __u8 zero0; __u8 lpum; __u16 res; struct erw erw; __u32 zeros[3]; };
struct esw_eadm — EADM Subchannel Extended Status Word (ESW)
struct esw_eadm { __u32 sublog; struct erw_eadm erw; };
struct irb — interruption response block
struct irb { union scsw scsw; union esw; __u8 ecw[32]; };
The irb that is handed to the device driver when an interrupt occurs. For
solicited interrupts, the common I/O layer already performs checks whether
a field is valid; a field not being valid is always passed as 0
.
If a unit check occurred, ecw
may contain sense data; this is retrieved
by the common I/O layer itself if the device doesn't support concurrent
sense (so that the device driver never needs to perform basic sene itself).
For unsolicited interrupts, the irb is passed as-is (expect for sense data,
if applicable).
struct ciw — command information word (CIW) layout
struct ciw { __u32 et:2; __u32 reserved:2; __u32 ct:4; __u32 cmd:8; __u32 count:16; };
struct ccw_dev_id — unique identifier for ccw devices
struct ccw_dev_id { u8 ssid; u16 devno; };
This structure is not directly based on any hardware structure. The
hardware identifies a device by its device number and its subchannel,
which is in turn identified by its id. In order to get a unique identifier
for ccw devices across subchannel sets, struct
ccw_dev_id has been
introduced.
Devices that want to initiate channel I/O need to attach to the ccw bus. Interaction with the driver core is done via the common I/O layer, which provides the abstractions of ccw devices and ccw device drivers.
The functions that initiate or terminate channel I/O all act upon a ccw device structure. Device drivers must not bypass those functions or strange side effects may happen.
struct ccw_device — channel attached device
struct ccw_device { spinlock_t * ccwlock; struct ccw_device_id id; struct ccw_driver * drv; struct device dev; int online; void (* handler) (struct ccw_device *, unsigned long, struct irb *); };
struct ccw_driver — device driver for channel attached devices
struct ccw_driver { struct ccw_device_id * ids; int (* probe) (struct ccw_device *); void (* remove) (struct ccw_device *); int (* set_online) (struct ccw_device *); int (* set_offline) (struct ccw_device *); int (* notify) (struct ccw_device *, int); void (* path_event) (struct ccw_device *, int *); void (* shutdown) (struct ccw_device *); int (* prepare) (struct ccw_device *); void (* complete) (struct ccw_device *); int (* freeze) (struct ccw_device *); int (* thaw) (struct ccw_device *); int (* restore) (struct ccw_device *); enum uc_todo (* uc_handler) (struct ccw_device *, struct irb *); struct device_driver driver; enum interruption_class int_class; };
ids supported by this driver
function called on probe
function called on remove
called when setting device online
called when setting device offline
notify driver of device state changes
notify driver of channel path events
called at device shutdown
prepare for pm state transition
undo work done in prepare
callback for freezing during hibernation snapshotting
undo work done in freeze
callback for restoring after hibernation
callback for unit check handler
embedded device driver structure
interruption class to use for accounting interrupts
ccw_device_set_offline — disable a ccw device for I/O
int fsfuncccw_device_set_offline ( | cdev) ; |
struct ccw_device * cdev
;ccw_device_set_online — enable a ccw device for I/O
int fsfuncccw_device_set_online ( | cdev) ; |
struct ccw_device * cdev
;get_ccwdev_by_dev_id — obtain device from a ccw device id
struct ccw_device * fsfuncget_ccwdev_by_dev_id ( | dev_id) ; |
struct ccw_dev_id * dev_id
;get_ccwdev_by_busid — obtain device from a bus id
struct ccw_device * fsfuncget_ccwdev_by_busid ( | cdrv, | |
bus_id) ; |
struct ccw_driver * cdrv
;const char * bus_id
;ccw_driver_register — register a ccw driver
int fsfuncccw_driver_register ( | cdriver) ; |
struct ccw_driver * cdriver
;ccw_driver_unregister — deregister a ccw driver
void fsfuncccw_driver_unregister ( | cdriver) ; |
struct ccw_driver * cdriver
;ccw_device_siosl — initiate logging
int fsfuncccw_device_siosl ( | cdev) ; |
struct ccw_device * cdev
;ccw_device_set_options_mask — set some options and unset the rest
int fsfuncccw_device_set_options_mask ( | cdev, | |
flags) ; |
struct ccw_device * cdev
;unsigned long flags
;ccw_device_set_options — set some options
int fsfuncccw_device_set_options ( | cdev, | |
flags) ; |
struct ccw_device * cdev
;unsigned long flags
;ccw_device_clear_options — clear some options
void fsfuncccw_device_clear_options ( | cdev, | |
flags) ; |
struct ccw_device * cdev
;unsigned long flags
;ccw_device_is_pathgroup — determine if paths to this device are grouped
int fsfuncccw_device_is_pathgroup ( | cdev) ; |
struct ccw_device * cdev
;ccw_device_is_multipath — determine if device is operating in multipath mode
int fsfuncccw_device_is_multipath ( | cdev) ; |
struct ccw_device * cdev
;ccw_device_clear — terminate I/O request processing
int fsfuncccw_device_clear ( | cdev, | |
intparm) ; |
struct ccw_device * cdev
;unsigned long intparm
;ccw_device_start_key — start a s390 channel program with key
int fsfuncccw_device_start_key ( | cdev, | |
cpa, | ||
intparm, | ||
lpm, | ||
key, | ||
flags) ; |
struct ccw_device * cdev
;struct ccw1 * cpa
;unsigned long intparm
;__u8 lpm
;__u8 key
;unsigned long flags
;cdev
target ccw device
cpa
logical start address of channel program
intparm
user specific interruption parameter; will be presented back to
cdev
'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
storage key to be used for the I/O
flags
additional flags; defines the action to be performed for I/O processing.
Start a S/390 channel program. When the interrupt arrives, the IRQ handler is called, either immediately, delayed (dev-end missing, or sense required) or never (no IRQ handler registered).
ccw_device_start_timeout_key — start a s390 channel program with timeout and key
int fsfuncccw_device_start_timeout_key ( | cdev, | |
cpa, | ||
intparm, | ||
lpm, | ||
key, | ||
flags, | ||
expires) ; |
struct ccw_device * cdev
;struct ccw1 * cpa
;unsigned long intparm
;__u8 lpm
;__u8 key
;unsigned long flags
;int expires
;cdev
target ccw device
cpa
logical start address of channel program
intparm
user specific interruption parameter; will be presented back to
cdev
'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
storage key to be used for the I/O
flags
additional flags; defines the action to be performed for I/O processing.
expires
timeout value in jiffies
Start a S/390 channel program. When the interrupt arrives, the
IRQ handler is called, either immediately, delayed (dev-end missing,
or sense required) or never (no IRQ handler registered).
This function notifies the device driver if the channel program has not
completed during the time specified by expires
. If a timeout occurs, the
channel program is terminated via xsch, hsch or csch, and the device's
interrupt handler will be called with an irb containing ERR_PTR(-ETIMEDOUT
).
ccw_device_start — start a s390 channel program
int fsfuncccw_device_start ( | cdev, | |
cpa, | ||
intparm, | ||
lpm, | ||
flags) ; |
struct ccw_device * cdev
;struct ccw1 * cpa
;unsigned long intparm
;__u8 lpm
;unsigned long flags
;cdev
target ccw device
cpa
logical start address of channel program
intparm
user specific interruption parameter; will be presented back to
cdev
'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.
flags
additional flags; defines the action to be performed for I/O processing.
Start a S/390 channel program. When the interrupt arrives, the IRQ handler is called, either immediately, delayed (dev-end missing, or sense required) or never (no IRQ handler registered).
ccw_device_start_timeout — start a s390 channel program with timeout
int fsfuncccw_device_start_timeout ( | cdev, | |
cpa, | ||
intparm, | ||
lpm, | ||
flags, | ||
expires) ; |
struct ccw_device * cdev
;struct ccw1 * cpa
;unsigned long intparm
;__u8 lpm
;unsigned long flags
;int expires
;cdev
target ccw device
cpa
logical start address of channel program
intparm
user specific interruption parameter; will be presented back to
cdev
'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.
flags
additional flags; defines the action to be performed for I/O processing.
expires
timeout value in jiffies
Start a S/390 channel program. When the interrupt arrives, the
IRQ handler is called, either immediately, delayed (dev-end missing,
or sense required) or never (no IRQ handler registered).
This function notifies the device driver if the channel program has not
completed during the time specified by expires
. If a timeout occurs, the
channel program is terminated via xsch, hsch or csch, and the device's
interrupt handler will be called with an irb containing ERR_PTR(-ETIMEDOUT
).
ccw_device_halt — halt I/O request processing
int fsfuncccw_device_halt ( | cdev, | |
intparm) ; |
struct ccw_device * cdev
;unsigned long intparm
;cdev
target ccw device
intparm
interruption parameter; value is only used if no I/O is outstanding, otherwise the intparm associated with the I/O request is returned
ccw_device_resume — resume channel program execution
int fsfuncccw_device_resume ( | cdev) ; |
struct ccw_device * cdev
;ccw_device_get_ciw — Search for CIW command in extended sense data.
struct ciw * fsfuncccw_device_get_ciw ( | cdev, | |
ct) ; |
struct ccw_device * cdev
;__u32 ct
;ccw_device_get_path_mask — get currently available paths
__u8 fsfuncccw_device_get_path_mask ( | cdev) ; |
struct ccw_device * cdev
;ccw_device_get_id — obtain a ccw device id
void fsfuncccw_device_get_id ( | cdev, | |
dev_id) ; |
struct ccw_device * cdev
;struct ccw_dev_id * dev_id
;ccw_device_tm_start_key — perform start function
int fsfuncccw_device_tm_start_key ( | cdev, | |
tcw, | ||
intparm, | ||
lpm, | ||
key) ; |
struct ccw_device * cdev
;struct tcw * tcw
;unsigned long intparm
;u8 lpm
;u8 key
;ccw_device_tm_start_timeout_key — perform start function
int fsfuncccw_device_tm_start_timeout_key ( | cdev, | |
tcw, | ||
intparm, | ||
lpm, | ||
key, | ||
expires) ; |
struct ccw_device * cdev
;struct tcw * tcw
;unsigned long intparm
;u8 lpm
;u8 key
;int expires
;ccw_device_tm_start — perform start function
int fsfuncccw_device_tm_start ( | cdev, | |
tcw, | ||
intparm, | ||
lpm) ; |
struct ccw_device * cdev
;struct tcw * tcw
;unsigned long intparm
;u8 lpm
;ccw_device_tm_start_timeout — perform start function
int fsfuncccw_device_tm_start_timeout ( | cdev, | |
tcw, | ||
intparm, | ||
lpm, | ||
expires) ; |
struct ccw_device * cdev
;struct tcw * tcw
;unsigned long intparm
;u8 lpm
;int expires
;ccw_device_get_mdc — accumulate max data count
int fsfuncccw_device_get_mdc ( | cdev, | |
mask) ; |
struct ccw_device * cdev
;u8 mask
;The channel-measurement facility provides a means to collect measurement data which is made available by the channel subsystem for each channel attached device.
enable_cmf — switch on the channel measurement for a specific device
int fsfuncenable_cmf ( | cdev) ; |
struct ccw_device * cdev
;disable_cmf — switch off the channel measurement for a specific device
int fsfuncdisable_cmf ( | cdev) ; |
struct ccw_device * cdev
;cmf_read — read one value from the current channel measurement block
u64 fsfunccmf_read ( | cdev, | |
index) ; |
struct ccw_device * cdev
;int index
;Table of Contents
The ccwgroup bus only contains artificial devices, created by the user. Many networking devices (e.g. qeth) are in fact composed of several ccw devices (like read, write and data channel for qeth). The ccwgroup bus provides a mechanism to create a meta-device which contains those ccw devices as slave devices and can be associated with the netdevice.
struct ccwgroup_device — ccw group device
struct ccwgroup_device { enum state; unsigned int count; struct device dev; struct ccw_device * cdev[0]; };
struct ccwgroup_driver — driver for ccw group devices
struct ccwgroup_driver { int (* setup) (struct ccwgroup_device *); void (* remove) (struct ccwgroup_device *); int (* set_online) (struct ccwgroup_device *); int (* set_offline) (struct ccwgroup_device *); void (* shutdown) (struct ccwgroup_device *); int (* prepare) (struct ccwgroup_device *); void (* complete) (struct ccwgroup_device *); int (* freeze) (struct ccwgroup_device *); int (* thaw) (struct ccwgroup_device *); int (* restore) (struct ccwgroup_device *); struct device_driver driver; };
function called during device creation to setup the device
function called on remove
function called when device is set online
function called when device is set offline
function called when device is shut down
prepare for pm state transition
undo work done in prepare
callback for freezing during hibernation snapshotting
undo work done in freeze
callback for restoring after hibernation
embedded driver structure
ccwgroup_set_online — enable a ccwgroup device
int fsfuncccwgroup_set_online ( | gdev) ; |
struct ccwgroup_device * gdev
;ccwgroup_set_offline — disable a ccwgroup device
int fsfuncccwgroup_set_offline ( | gdev) ; |
struct ccwgroup_device * gdev
;ccwgroup_create_dev — create and register a ccw group device
int fsfuncccwgroup_create_dev ( | parent, | |
gdrv, | ||
num_devices, | ||
buf) ; |
struct device * parent
;struct ccwgroup_driver * gdrv
;int num_devices
;const char * buf
;parent
parent device for the new device
gdrv
driver for the new group device
num_devices
number of slave devices
buf
buffer containing comma separated bus ids of slave devices
ccwgroup_driver_register — register a ccw group driver
int fsfuncccwgroup_driver_register ( | cdriver) ; |
struct ccwgroup_driver * cdriver
;ccwgroup_driver_unregister — deregister a ccw group driver
void fsfuncccwgroup_driver_unregister ( | cdriver) ; |
struct ccwgroup_driver * cdriver
;ccwgroup_probe_ccwdev — probe function for slave devices
int fsfuncccwgroup_probe_ccwdev ( | cdev) ; |
struct ccw_device * cdev
;Table of Contents
Some interfaces are available to other drivers that do not necessarily have anything to do with the busses described above, but still are indirectly using basic infrastructure in the common I/O layer. One example is the support for adapter interrupts.
register_adapter_interrupt — register adapter interrupt handler
int fsfuncregister_adapter_interrupt ( | airq) ; |
struct airq_struct * airq
;unregister_adapter_interrupt — unregister adapter interrupt handler
void fsfuncunregister_adapter_interrupt ( | airq) ; |
struct airq_struct * airq
;airq_iv_create — create an interrupt vector
struct airq_iv * fsfuncairq_iv_create ( | bits, | |
flags) ; |
unsigned long bits
;unsigned long flags
;airq_iv_release — release an interrupt vector
void fsfuncairq_iv_release ( | iv) ; |
struct airq_iv * iv
;airq_iv_alloc_bit — allocate an irq bit from an interrupt vector
unsigned long fsfuncairq_iv_alloc_bit ( | iv) ; |
struct airq_iv * iv
;airq_iv_free_bit — free an irq bit of an interrupt vector
void fsfuncairq_iv_free_bit ( | iv, | |
bit) ; |
struct airq_iv * iv
;unsigned long bit
;