patch-2.3.99-pre8 linux/Documentation/s390/cds.txt

Next file: linux/Makefile
Previous file: linux/Documentation/s390/DASD
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.99-pre7/linux/Documentation/s390/cds.txt linux/Documentation/s390/cds.txt
@@ -0,0 +1,912 @@
+Linux/390
+
+Common Device Support (CDS)
+Device Driver I/O Support Routines
+
+Author : Ingo Adlung
+
+Copyright, IBM Corp. 1999
+
+Introduction
+
+This document describes the common device support routines for Linux/390.
+Different than other hardware architectures, ESA/390 hasdefined a unified
+I/O access method. This gives relief to the device drivers as they don't
+have to deal with different bus types, polling versus interrupt
+processing, shared versus non-shared interrupt processing, DMA versus port
+I/O (PIO), and other hardware features more. However, this implies that
+either every single device driver needs to implement the hardware I/O
+attachment functionality itself, or the operating system provides for a
+unified method to access the hardware, providing all the functionality that
+every single device driver would have to provide itself.
+
+The document does not intend to explain the ESA/390 hardware architecture in
+every detail.This information can be obtained from the ESA/390 Principles of
+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 following figure shows the usage of the common device support
+of Linux/390 using a TbCP/IP driven device access an example. Similar figures
+could be drawn for other access methods, e.g. file system access to disk
+devices.
+
+The common device support layer shown above 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.
+
+get_dev_info_by_irq() / get_dev_info_by_devno()	
+   allow a device driver to determine the devices attached (visible) to the
+   system and their current status.
+
+get_irq_by_devno() / get_devno_by_irq()	
+   get irq (subchannel) from device number and vice versa.
+
+read_dev_chars()	
+   read device characteristics
+
+request_irq()	
+   obtain ownership for a specific device.
+
+free_irq()	
+   release ownership for a specific device.
+
+disable_irq()	
+   disable a device from presenting interrupts.
+
+enable_irq()	
+   enable a device, allowing for I/O interrupts.
+
+do_IO()	
+   initiate an I/O request.
+
+halt_IO()	
+   terminate the current I/O request processed on the device.
+
+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
+   interrupt handler according to the rules (flags) defined during I/O request
+   initiation with do_IO().
+
+The next chapters describe the functions, other than do_IRQ() in more details.
+The do_IRQ() interface is not described, as it is called from the Linux/390
+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.
+
+
+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
+driver implementations on the IBM ESA/390 hardware platform. Those interfaces
+intend to provide the functionality required by every device driver
+implementaion to allow to drive a specific hardware device on the ESA/390
+platform. Some of the interface routines are specific to Linux/390 and some
+of them can be found on other Linux platforms implementations too.
+Miscellaneous function prototypes, data declarations, and macro definitions
+can be found in the architecture specific C header file
+linux/arch/s390/kernel/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
+that may or may not allow for shared interrupts, DMA processing, etc.. Instead,
+the ESA/390 architecture has implemented a so called channel subsystem, that
+provides a unified view of the devices physically attached to the systems.
+Though the ESA/390 hardware platform knows about a huge variety of different
+peripheral attachments like disk devices (aka. DASDs), tapes, communication
+controllers, etc. they can all by accessed by a well defined access method and
+they are presenting I/O completion a unified way : I/O interruptions. Every
+single device is uniquely identified to the system by a so called subchannel,
+where the ESA/390 architecture allows for 64k devices be attached.
+
+Linux, however was first built on the Intel PC architecture, with its two
+cascaded 8259 programmable interrupt controllers (PICs), that allow for a
+maximum of 15 different interrupt lines. All devices attached to such a system
+share those 15 interrupt levels. Devices attached to the ISA bus system must
+not share interrupt levels (aka. IRQs), as the ISA bus bases on edge triggered
+interrupts. MCA, EISA, PCI and other bus systems base on level triggered
+interrupts, and therewith allow for shared IRQs. However, if multiple devices
+present their hardware status by the same (shared) IRQ, the operating system
+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.
+
+In order to not introduce a new I/O concept to the common Linux code,
+Linux/390 preserves the IRQ concept and semantically maps the ESA/390
+subchannels to Linux as IRQs. This allows Linux/390 to support up to 64k
+different IRQs, uniquely representig a single device each.
+
+During its startup the Linux/390 system checks for peripheral devices. Each
+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 can not exceed 65535. The
+init_IRQ() routine gathers 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. Device drivers can retrieve this set of hardware
+information during their initialization step to recognize the devices they
+support using get_dev_info_by_irq() or get_dev_info_by_devno() respectively.
+This methods implies that Linux/390 doesn't require to probe for free (not
+armed) interrupt request lines (IRQs) to drive its devices with. Where
+applicable, the device drivers can use the read_dev_chars() to retrieve device
+characteristics. This can be done without having to request device ownership
+previously.
+
+When a device driver has recognized a device it wants to claim ownership for,
+it calls request_irq() with the device's subchannel id serving as pseudo irq
+line. One of the required parameters it has to specify is dev_id, defining a
+device status block, the CDS layer will use to notify the device driver's
+interrupt handler about interrupt information observed. It depends on the
+device driver to properly handle those interrupts.
+
+In order to allow for easy I/O initiation the CDS layer provides a do_IO()
+interface that takes a device specific channel program (one or more CCWs) as
+input sets up the required architecture specific control blocks and initiates
+an I/O request on behalf of the device driver. The do_IO() routine allows for
+different I/O methods, synchronous and asynchronous, and allows to specify
+whether it expects the CDS layer to notify the device driver for every
+interrupt it observes, or with final status only. It also provides a scheme
+to allow for overlapped I/O processing. See do_IO() for more details. A device
+driver must never issue ESA/390 I/O commands itself, but must use the
+Linux/390 CDS interfaces instead.
+
+For long running I/O request to be canceled, the CDS layer provides the
+halt_IO() function. Some devices require to initially issue a HALT SUBCHANNEL
+(HSCH) command without having pending I/O requests. This function is also
+covered by halt_IO().
+
+When done with a device, the device driver calls free_irq() to release its
+ownership for the device. During free_irq() processing the CDS layer also
+disables the device from presenting further interrupts - the device driver
+doesn't need to assure it. The device will be reenabled for interrupts with
+the next call to request_irq().
+
+
+
+get_dev_info_by_irq() / get_dev_info_by_devno() - Retrieve Device Information
+
+During system startup - init_IRQ() processing - the generic I/O device support
+checks for the devices available. For all devices found it collects the
+SenseID information. For those devices supporting the command it also obtains
+extended SenseID information.
+
+int get_dev_info_by_irq( int         irq,
+                         dev_info_t *devinfo);
+
+int get_dev_info_by_devno( unsigned int  irq,
+                           dev_info_t   *devinfo);
+
+irq     - defines the subchannel, status information is to be
+          returned for.
+devno   - device number.
+devinfo - pointer to a user buffer of type dev_info_t that should
+          be filled with device specific information.
+
+typedef struct {
+     unsigned int devno;     /* device number */
+     unsigned int status;    /* device status */
+     senseid_t    sid_data;  /* senseID data  */
+} dev_info_t;
+
+devno     - device number as configured in the IOCDS.
+status    - device status
+sid_data  - data obtained by a SenseID call
+
+Possible status values are :
+
+DEVSTAT_NOT_OPER - device was found not-operational. In this case
+                   the caller should disregard the sid_data
+                   buffer content.
+
+//
+// SenseID response buffer layout
+//
+typedef struct {
+  /* common part */
+      unsigned char  reserved;     /* always 0x'FF' */
+      unsigned short cu_type;      /* control unit type */
+      unsigned char  cu_model;     /* control unit model */
+      unsigned short dev_type;     /* device type */
+      unsigned char  dev_model;    /* device model */
+      unsigned char  unused;       /* padding byte */
+  /* extended part */
+      ciw_t    ciw[62];            /* variable # of CIWs */
+} senseid_t;
+
+The ESA/390 I/O architecture defines certain device specific I/O functions.
+The device returns the device specific command code together with the SenseID
+data in so called Command Information Words (CIW) :
+
+typedef struct _ciw {
+   unsigned int et       :  2;    // entry type
+   unsigned int reserved :  2;    // reserved
+   unsigned int ct       :  4;    // command type
+   unsigned int cmd      :  8;    // command
+   unsigned int count    : 16;    // count
+} ciw_t;
+
+Possible CIW entry types are :
+
+#define CIW_TYPE_RDC    0x0;      // read configuration data
+#define CIW_TYPE_SII    0x1;      // set interface identifier
+#define CIW_TYPE_RNI    0x2;      // read node identifier
+
+The device driver may use these commands as appropriate.
+
+The get_dev_info_by_irq() / get_dev_info_by_devno() functions return:
+
+      0 - sucessful completion
+-ENODEV - irq or devno don't specify a known subchannel or device
+          number.
+-EINVAL - invalid devinfo value.
+
+Usage Notes :
+
+In order to scan for known devices a device driver should scan all irqs by
+calling     get_dev_info() until it returns -ENODEV as there aren't any more
+available devices.
+
+If a device driver wants to request ownership for a specific device it must
+call request_irq() prior to be able to issue any I/O request for it, including
+above mentioned   device dependent commands.
+
+Please see the "ESA/390 Common I/O-Commandss and Self Description" manual,
+with IBM form number SA22-7204 for more details on how to read the Sense-ID
+output, CIWs and device independent commands.
+
+
+
+get_irq_by_devno() / get_devno_by_irq() - Convert device identifiers
+
+While some device drivers act on the irq (subchannel) only, others take user
+defined device configurations on device number base, according to the device
+numbers configured in the IOCDS. The following routines serve the purpose to
+convert irq values into device numbers and vice versa.
+
+int get_irq_by_devno( unsigned int devno );
+
+unsigned int get_devno_by_irq( int irq );
+
+The functions return :
+
+the requested irq/devno values
+-1 if the requested conversion can't be accomplished.
+
+This could either be caused by irq/devno be outside the valid range
+( value > 0xffff or value < 0 ) or not identifying a known device.
+
+
+read_dev_chars() - Read Device Characteristics
+
+This routine returns the characteristics for the device specified.
+
+The function is meant to be called without an irq handler be in place.
+However, the irq for the requested device must not be locked or this will
+cause a deadlock situation ! Further, the driver must assure that nobody
+else has claimed ownership for the requested irq yet or the owning device
+driver's internal accounting may be affected.
+
+In case of a registered interrupt handler, the interrupt handler must be
+able to properly react on interrupts related to the read_dev_chars() I/O
+commands. While the request is procesed synchronously, the device interrupt
+handler is called for final ending status. In case of error situations the
+interrupt handler may recover appropriately. The device irq handler can
+recognize the corresponding interrupts by the interruption parameter be
+0x00524443. If using the function with an existing device interrupt handler
+in place, the irq must be locked prior to call read_dev_chars().
+
+The function may be called enabled or disabled.
+
+int read_dev_chars( int irq, void **buffer, int length );
+
+irq    - specifies the subchannel the device characteristic
+         retrieval is requested for
+buffer - pointer to a buffer pointer. The buffer pointer itself
+         may be NULL to have the function allocate a buffer or
+         must contain a valid buffer area.
+length - length of the buffer provided or to be allocated.
+
+The read_dev_chars() function returns :
+
+      0 - successful completion
+-ENODEV - irq doesn't specify a valid subchannel number
+-EINVAL - an invalid parameter was detected
+-EBUSY  - an irrecoverable I/O error occured or the device is not
+          operational.
+
+Usage Notes :
+
+The function can be used in two ways :
+
+If the caller doesn't provide a data buffer, read_dev_chars() allocates a
+data buffer and provides the device characteristics together. It's the
+caller's responsability to release the kernel memory if not longer needed.
+This behaviour is triggered by specifying a NULL buffer area (*buffer == NULL).
+
+Alternatively, if the user specifies a buffer area himself, nothing is
+allocated.
+
+In either case the caller must provide the data area length - for the buffer
+he specifies, or the buffer he wants to be allocated.
+
+
+request_irq() - Request Device Ownership
+
+As previously discussed a device driver will scan for the devices its supports
+by calling get_dev_info(). Once it has found a device it will call
+request_irq() to request ownership for it. This call causes the subchannel to
+be enabled for interrupts if it was found operational.
+
+int request_irq( unsigned int   irq,
+                 int          (*handler)( int,
+                                          void *,
+                                          struct pt_regs *),
+                 unsigned long  irqflags,
+                 const char    *devname,
+                 void          *dev_id);
+
+irq      : specifies the subchannel the ownership is requested for
+handler  : specifies the device driver's interrupt handler to be
+           called for interrupt processing
+irqflags : IRQ flags, must be 0 (zero) or SA_SAMPLE_RANDOM
+devname  : device name
+dev_id   : required pointer to a device specific buffer of type
+           devstat_t
+
+typedef struct {
+     unsigned int  devno;   /* device number from irb */
+     unsigned int  intparm; /* interrupt parameter */
+     unsigned char cstat;   /* channel status - accumulated */
+     unsigned char dstat;   /* device status - accumulated */
+     unsigned char lpum;    /* last path used mask from irb */
+     unsigned char unused;  /* not used - reserved */
+     unsigned int  flag;    /* flag : see below */
+     unsigned long cpa;     /* CCW addr from irb at prim. status */
+     unsigned int  rescnt;  /* count from irb at primary status */
+     unsigned int  scnt;    /* sense count, if available */
+     union {
+        irb_t   irb;        /* interruption response block */
+        sense_t sense;      /* sense information */
+        } ii;               /* interrupt information */
+  } devstat_t;
+
+During request_irq() processing, the devstat_t layout does not matter as it
+won't be used during request_irq() processing. See do_IO() for a functional
+description of its usage.
+
+The request_irq() function returns :
+
+      0 - successful completion
+-EINVAL - an invalid parameter was detected
+-EBUSY  - device (subchannel) already owned
+-ENODEV - the device is not-operational
+-ENOMEM - not enough kernel memory to process request
+
+Usage Notes :
+
+While Linux for Intel defines dev_id as a unique identifier for shared
+interrupt lines it has a totally different purpose on Linux/390. Here it
+serves as a shared interrupt status area between the generic device support
+layer, and the device specific driver. The value passed to request_irq()
+must therefore point to a valid devstat_t type buffer area the device driver
+must preserve for later usage. I.e. it must not be released prior to a call
+to free_irq()
+
+The only value parameter irqflags supports is SA_SAMPLE_RANDOM if appropriate.
+The Linux/390 kernel does neither know about "fast" interrupt handlers, nor
+does it allow for interrupt sharing. Remember, the term interrupt level (irq),
+device, and subchannel are used interchangeably in Linux/390.
+
+If request_irq() was called in enabled state, or if multiple CPUs are present,
+the device may present an interrupt to the specified handler prior to
+request_irq() return to the caller  already ! This includes the possibility
+of unsolicited interrupts or a pending interrupt status from an earlier
+solicited I/O request. The device driver must be able to handle this situation
+properly or the device may become unoperational otherwise !
+
+Although the interrupt handler is defined to be called with a pointer to a
+struct pt_regs buffer area, this is not implemented by the Linux/390 generic
+I/O device driver support layer. The device driver's interrupt handler must
+therefore not rely on this parameter on function entry.
+
+
+free_irq() - Release Device Ownership
+
+A device driver may call free_irq() to release ownership of a previously
+aquired device.
+
+void free_irq( unsigned int  irq,
+               void         *dev_id);
+
+irq      : specifies the subchannel the ownership is requested for
+dev_id   : required pointer to a device specific buffer of type
+           devstat_t. This must be the same as the one specified
+           during a previous call to request_irq().
+
+Usage Notes :
+
+Unfortunately the free_irq() is defined not to return error codes. I.e. if
+called with wrong  parameters a device may still be operational although there
+is no device driver available to handle its interrupts. Further, during
+free_irq() processing we may possibly find pending interrupt conditions. As
+those need to be processed, we have to delay free_irq() returning until a
+clean device status is found by synchronously handling them.
+
+The call to free_irq() will also cause the device (subchannel) be disabled for
+interrupts. The device driver must not release any data areas required for
+interrupt processing prior to free_irq() return to the caller as interrupts
+can occur prior to free_irq() returning. This is also true when called in
+disabled state if either multiple CPUs are presents or a pending interrupt
+status was found during free_irq() processing.
+
+
+disable_irq() - Disable Interrupts for a given Device
+
+This function may be called at any time to disable interrupt processing for
+the specified irq. However, as Linux/390 maps irqs to the device (subchannel)
+one-to-one, this may require more extensive I/O processing than anticipated,
+especially if an interrupt status is found pending on the subchannel that
+requires synchronous error processing.
+
+int disable_irq( unsigned int irq );
+
+irq : specifies the subchannel to be disabled
+
+The disable-irq() routine may return :
+
+      0 - successful completion
+-EBUSY  - device (subchannel) is currently processing an I/O
+          request
+-ENODEV - the device is not-operational or irq doesn't specify a
+          valid subchannel
+
+Usage Notes :
+
+Unlike the Intel based hardware architecture the ESA/390 architecture does
+not have a programmable interrupt controller (PIC) where a specific interrupt
+line can be disabled. Instead the subchannel logically representing the device
+in the channel subsystem must be disabled for interrupts. However, if there
+are still inetrrupt conditions pending they must   be processed first in order
+to allow for proper processing after reenabling the device at a later time.
+This may lead to delayed disable processing.
+
+As described above the disable processing may require extensive processing.
+Therefore    disabling and re-enabling the device using disable_irq() /
+enable_irq() should be avoided and is not suitable for high frequency
+operations.
+
+Linux for Intel defines this function
+
+void disable_irq( int irq);
+
+This is suitable for the Intel PC architecture as this only causes to mask
+the requested irq line in the PIC which is not applicable for the ESA/390
+architecture. Therefore we allow   for returning error codes.
+
+
+enable_irq() - Enable Interrupts for a given Device
+
+This function is used to enable a previously disabled device (subchannel).
+See disable_irq() for more details.
+
+int enable_irq( unsigned int irq );
+
+irq : specifies the subchannel to be enabled
+
+The enable-irq() routine may return :
+
+      0 - successful completion
+-EBUSY  - device (subchannel) is currently processing an I/O
+          request. This implies the device is already in enabled
+          state
+-ENODEV - the device is not-operational or irq doesn't specify a
+          valid subchannel
+
+
+
+do_IO() - Initiate I/O Request
+
+The do_IO() routines is the I/O request front-end processor. All device driver
+I/O requests must be issued using this routine. A device driver must not issue
+ESA/390 I/O commands itself. Instead the do_IO() routine provides all
+interfaces required to drive arbitrary devices.
+
+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 do_IO().
+
+int do_IO( int            irq,
+           ccw1_t        *cpa,
+           unsigned long  intparm,
+           unsigned int   lpm,
+           unsigned long  flag);
+
+irq     : irq (subchannel) the I/O request is destined for
+cpa     : logical start address of channel program
+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. Valid with flag value DOIO_VALID_LPM only.
+flag    : defines the action to e parformed for I/O processing
+
+Possible flag values are :
+
+DOIO_EARLY_NOTIFICATION  - allow for early interupt notification
+DOIO_VALID_LPM           - LPM input parameter is valid (see usage
+                           notes below for details)
+DOIO_WAIT_FOR_INTERRUPT  - wait synchronously for final status
+DOIO_REPORT_ALL          - report all interrupt conditions
+
+The cpa parameter points to the first format 1 CCW of a channel program :
+
+typedef struct {
+   char            cmd_code; /* command code */
+   char            flags;    /* flags, like IDA adressing, etc. */
+   unsigned short  count;    /* byte count */
+   void           *cda;      /* data address */
+} ccw1_t __attribute__ ((aligned(8)));
+
+with the following CCW flags values defined :
+
+CCW_FLAG_DC        - data chaining
+CCW_FLAG_CC        - command chaining
+CCW_FLAG_SLI       - suppress incorrct length
+CCW_FLAG_SKIP      - skip
+CCW_FLAG_PCI       - PCI
+CCW_FLAG_IDA       - indirect addressing
+CCW_FLAG_SUSPEND   - suspend
+
+
+
+The do_IO() function returns :
+
+      0 - successful completion or request successfuly initiated
+-EBUSY  - the do_io() function was caled out of sequence. The
+          device is currently processing a previous I/O request
+-ENODEV - irq doesn't specify a valid subchannel, the device is
+          not operational (check dev_id.flags) or the irq is not
+          owned.
+-EINVAL - both, DOIO_EARLY_NOTIFICATION and DOIO_REORT_ALL flags
+          have been specified. The usage of those flags is mutual
+          exclusive.
+
+When the I/O request completes, the CDS first level interrupt handler will
+setup the dev_id buffer of type devstat_t defined during request_irq()
+processing. See request_irq() for the devstat_t data layout. The
+dev_id->intparm field in the device status area will contain the value the
+device driver has associated with a particular I/O request. If a pending
+device status was recognized dev_id->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 interrupt will be presented
+to indicate I/O completion as the I/O request was never started, even though
+do_IO() returned with successful completion.
+
+Possible dev_id->flag values are :
+
+DEVSTAT_FLAG_SENSE_AVAIL - sense data is available
+DEVSTAT_NOT_OPER         - device is not-operational
+DEVSTAT_START_FUNCTION   - interrupt is presented as result of a
+                           call to do_IO()
+DEVSTAT_HALT_FUNCTION    - interrupt is presented as result of a
+                           call to halt_IO()
+DEVSTAT_STATUS_PENDING   - a pending status was found. The I/O
+                           resquest (if any) was not initiated.
+                           This status might have been presented
+                           delayed, after do_IO() or halt_IO() have
+                           successfully be started previously.
+DEVSTAT_FINAL_STATUS     - This is a final interrupt status for the
+                           I/O requst identified by intparm.
+
+If device status DEVSTAT_FLAG_SENSE_AVAIL is indicated in field dev_id->flag,
+field dev_id->scnt describes the numer of device specific sense bytes
+available in the sense area dev_id->ii.sense. No device sensing by the device
+driver itself is required.
+
+typedef struct {
+   unsigned char res[32];       /* reserved   */
+   unsigned char data[32];      /* sense data */
+} sense_t;
+
+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
+SNS0_EQUIPMENT_CHECK    0x10
+SNS0_DATA_CHECK         0x08
+SNS0_OVERRUN            0x04
+
+Depending on the device status, multiple of those values may be set together.
+Please refer to the device specific documentation for details.
+
+The devi_id->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
+
+The dev_id->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
+
+Please see the ESA/390 Principles of Operation manual for details on the
+individual flag meanings.
+
+In rare error situations the device driver may require access to the original
+hardware interrupt data beyond the scope of above mentioned infromation. For
+those situations the Linux/390 common device support provides the interrupt
+response block (IRB) as part of the device status block in dev_id->ii.irb.
+
+Usage Notes :
+
+Prior to call do_IO() the device driver must
+
+assure disabled state, i.e. the I/O mask value in the PSW must be disabled.
+This can be accomplished by calling __save_flags( flags). The current PSW
+flags are preserved and can be restored by __restore_flags( flags) at a
+later time.
+
+If the device driver violates this rule while running in a uni-processor
+environment an interrupt might be presented prior to the do_IO() routine
+returning to the device driver main path. In this case we will end in a
+deadlock situation as the interrupt handler will try to obtain the irq
+lock the device driver still owns (see below) !
+
+the driver must assure to hold the device specific lock. This can be
+accomplished by
+
+(i)  s390irq_spin_lock( irq), or
+(ii) s390irq_spin_lock_irqsave(irq, flags)
+
+Option (i) should be used if the calling routine is running disabled for
+I/O interrupts (see above) already. Option (ii) obtains the device gate und
+puts the CPU into I/O disabled state by preserving the current PSW flags.
+See the descriptions of s390irq_spin_lock() or s390irq_spin_lock_irqsave()
+for more details.
+
+The device driver is allowed to issue the next do_IO() call from within its
+interrupt handler already. It is not required to schedule a bottom-half,
+unless an non deterministicly long running error recovery procedure or
+similar needs to be scheduled. During I/O processing the Linux/390 generic
+I/O device driver support has already obtained the IRQ lock, i.e. the handler
+must not try to obtain it again when calling do_IO() or we end in a deadlock
+situation ! Anyway, the device driver's interrupt handler must only call
+do_IO() if the handler itself can be entered recursively if do_IO() e.g. finds
+a status pending and needs to all the interrupt handler itself.
+
+Device drivers shouldn't heavily rely on DOIO_WAIT_FOR_INTERRUPT synchronous
+I/O request processing. All I/O devices, but the console device are driven
+using a single shared interrupt subclass (ISC). For sync. processing the
+device is temporarily mapped to a special ISC while the calling CPU waits for
+I/O completion. As this special ISC is gated, all sync. requests in a SMP
+environment are serialized which may cause other CPUs to spin. This service
+is therewith primarily meant to be used during device driver initialization
+for ease of device setup.
+
+The lpm input parameter might be used for multipath devices shared among
+multiple systems as the Linux/390 CDS isn't grouping channel paths. Therefore
+its use might be required if multiple access paths to a device are available
+and the device was reserved by means of a reserve device command (for devices
+supporting this technique). When issuing this command the device driver needs
+needs to extract the dev_id->lpum value and restrict all subsequent channel
+programs to this channel path until the device is released by a device release
+command. Otherwise a deadlock may occur.
+
+If a device driver relies on an I/O request to be completed prior to start the
+next it can reduce I/O processing overhead by chaining a NoOp I/O command
+CCW_CMD_NOOP to the end of the submitted CCW chain. This will force Channel-End
+and Device-End status to be presented together, with a single interrupt.
+However, this should be used with care as it implies the channel will remain
+busy, not being able to process I/O requests for other devices on the same
+channel. Therefore e.g. read commands should never use this technique, as the
+result will be presented by a single interrupt anyway.
+
+In order to minimize I/O overhead, a device driver should use the
+DOIO_REPORT_ALL  only if the device can report intermediate interrupt
+information prior to device-end the device driver urgently relies on. In this
+case all I/O interruptions are presented to the device driver until final
+status is recognized.
+
+If a device is able to recover from asynchronosly presented I/O errors, it can
+perform overlapping I/O using the DOIO_EARLY_NOTIFICATION flag. While some
+devices always report channel-end and device-end together, with a single
+interrupt, others present primary status (channel-end) when the channel is
+ready for the next I/O request and secondary status (device-end) when the data
+transmission has been completed at the device.
+
+Above flag allows to exploit this feature, e.g. for communication devices that
+can handle lost data on the network to allow for enhanced I/O processing.
+
+Unless the channel subsystem at any time presents a secondary status interrupt,
+exploiting this feature will cause only primary status interrups to be
+presented to the device driver while overlapping I/O is performed. When a
+secondary status without error (alert status) is presented, this indicates
+successful completion for all overlapping do_IO() requests that have been
+issued since the last secondary (final) status.
+
+During interrupt processing the device specific interrupt handler should avoid
+basing its processing decisions on the interruption response block (IRB) that
+is part of the dev_id buffer area. The IRB area represents the interruption
+parameters from the last interrupt received. Unless the device driver has
+specified DOIO_REPORT_ALL or is called with a pending status
+(DEVSTAT_STATUS_PENDING), the IRB information may or may not show the complete
+interruption status, but the last interrupt only. Therefore the device driver
+should usually base its processing decisions on the values of dev_id->cstat
+and dev_id->dstat that represent the accumulated subchannel and device status
+information gathered since do_IO() request initiation.
+
+
+halt_IO() - Halt I/O Request Processing
+
+Sometimes a device driver might need a possibility to stop the processing of
+a long-running channel program or the device might require to initially issue
+a halt subchannel (HSCH) I/O command. For those purposes the halt_IO() command
+is provided.
+
+int halt_IO( int          irq,     /* subchannel number */
+             int          intparm, /* dummy intparm */
+             unsigned int flag);   /* operation mode */
+
+irq     : irq (subchannel) 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
+flag    : 0 (zero) or DOIO_WAIT_FOR_INTERRUPT
+
+The halt_IO() function returns :
+
+      0 - successful completion or request successfuly initiated
+-EBUSY  - the device is currently performing a sysnchonous I/O
+          operation : do_IO() with flag DOIO_WAIT_FOR_INTERRUPT
+          or an error was encountered and the device is currently
+          be sensed
+-ENODEV - the irq specified doesn't specify a valid subchannel, the
+          device is not operational (check dev_id.flags) or the irq
+          is not owned.
+
+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
+channel (TIC)   command (CCW_CMD_TIC). Usually this is performed by network
+device drivers by setting the PCI CCW flag (CCW_FLAG_PCI). Once this CCW is
+executed a program controlled interrupt (PCI) is generated. The device driver
+can then perform an appropriate action. Prior to interrupt of an outstanding
+read to a network device (with or   without PCI flag) a halt_IO() is required
+to end the pending operation.
+
+We don't allow to stop sync. I/O requests by means of a halt_IO() call. The
+function will return -EBUSY instead.
+
+
+Miscellaneous Support Routines
+
+This chapter describes various routines to be used in a Linux/390 device
+driver programming environment.
+
+s390irq_spin_lock() / s390irq_spin_unlock()
+
+Those two macro definitions are required to obtain the device specific IRQ
+lock. The lock needs to be obtained if the device driver intends to call
+do_IO() or halt_IO() from anywhere but the device interrupt handler (where
+the lock is already owned). Those routines must only be used if running
+disabled for interrupts already. Otherwise use s390irq_spin_lock_irqsave()
+and the corresponding unlock routine instead (see below).
+
+s390irq_spin_lock( int irq);
+s390irq_spin_unlock( int irq);
+
+
+s390irq_spin_lock_irqsave() / s390_irq_spin_unlock_irqrestore()
+
+Those two macro definitions are required to obtain the device specific IRQ
+lock. The lock needs to be obtained if the device driver intends to call
+do_IO() or halt_IO() from anywhere but the device interrupt handler (where
+the lock is already owned). Those routines should only be used if running
+enabled for interrupts. If running disabled already, the driver should use
+s390irq_spin_lock() and the corresponding unlock routine instead (see above).
+
+s390irq_spin_lock_irqsave( int irq, unsigned long flags);
+s390irq_spin_unlock_irqrestore( int irq, unsigned long flags);
+
+
+
+
+Special Console Interface Routines
+
+This chapter describes the special interface routines required for system
+console processing. Though they are an extension to the Linux/390 device
+driver interface concept, they base on the same principles. It was necessary
+to build those extensions to assure a deterministic behaviour in critical
+situations e.g. printk() messages by other device drivers running disabled
+for interrupts during I/O interrupt handling or in case of a panic() message
+being raised.
+
+set_cons_dev - Set Console Device
+
+This routine allows to specify the system console device. This is necessary
+as the console isn't driven by the same ESA/390 interrupt subclass as are
+other devices, but it is assigned ist own interrupt subclass. Only one device
+can act as system console. See wait_cons_dev() for details.
+
+int set_cons_dev( int irq);
+
+irq : subchannel identifying the system console device
+
+The set_cons_dev() function returns
+
+      0 - successful completion
+-EIO    - an unhandled interrupt condition is pending for the
+          specified subchannel (irq) - status pending
+-ENODEV - irq doesn't specify a valid subchannel or the devive is
+          not operational
+-EBUSY  - the console device is already defined
+
+reset_cons_dev - Reset Console Device
+
+This routine allows for resetting the console device specification. See
+set_cons_dev() for details.
+
+int reset_cons_dev( int irq);
+
+irq : subchannel identifying the system console device
+
+The reset_cons_dev() function returns
+
+      0 - successful completion
+-EIO    - an unhandled interrupt condition is pending for the
+          specified subchannel (irq) - status pending
+-ENODEV - irq doesn't specify a valid subchannel or the devive is
+          not operational
+
+wait_cons_dev - Synchronously Wait for Console Processing
+
+The wait_cons_dev() routine is used by the console device driver when its
+buffer pool for intermediate request queuing is exhausted and a new output
+request is received. In this case the console driver uses the wait_cons_dev()
+routine to synchronously wait until enough buffer space is gained to enqueue
+the current request. Any pending interrupt condition for the console device
+found during wait_cons_dev() processing causes its interrupt handler to be
+called.
+
+int wait_cons_dev( int irq);
+
+irq : subchannel identifying the system console device
+
+The wait_cons_dev() function  returns :
+
+      0 - successful completion
+-EINVAL - the irq specified doesn't match the irq configured for
+          the console device by set_cons_dev()
+
+Usage Notes :
+
+The function should be used carefully. Especially in a SMP environment the
+wait_cons_dev() processing requires that all but the special console ISC are
+disabled. In a SMP system this requires the other CPUs to be signaled to
+disable/enable those ISCs.
+
+
+

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)