2005-04-17 02:20:36 +04:00
/*
* drivers / s390 / cio / device_ops . c
*
* Copyright ( C ) 2002 IBM Deutschland Entwicklung GmbH ,
* IBM Corporation
* Author ( s ) : Martin Schwidefsky ( schwidefsky @ de . ibm . com )
2006-01-15 00:21:04 +03:00
* Cornelia Huck ( cornelia . huck @ de . ibm . com )
2005-04-17 02:20:36 +04:00
*/
# include <linux/module.h>
# include <linux/init.h>
# include <linux/errno.h>
# include <linux/slab.h>
# include <linux/list.h>
# include <linux/device.h>
# include <linux/delay.h>
# include <asm/ccwdev.h>
# include <asm/idals.h>
2007-04-27 18:01:31 +04:00
# include <asm/chpid.h>
2008-07-14 11:58:51 +04:00
# include <asm/fcx.h>
2005-04-17 02:20:36 +04:00
# include "cio.h"
# include "cio_debug.h"
# include "css.h"
# include "chsc.h"
# include "device.h"
2007-04-27 18:01:28 +04:00
# include "chp.h"
2005-04-17 02:20:36 +04:00
2007-10-12 18:11:17 +04:00
/**
* ccw_device_set_options_mask ( ) - set some options and unset the rest
* @ cdev : device for which the options are to be set
* @ flags : options to be set
*
* All flags specified in @ flags are set , all flags not specified in @ flags
* are cleared .
* Returns :
* % 0 on success , - % EINVAL on an invalid flag combination .
*/
2007-02-12 17:47:18 +03:00
int ccw_device_set_options_mask ( struct ccw_device * cdev , unsigned long flags )
2005-04-17 02:20:36 +04:00
{
/*
* The flag usage is mutal exclusive . . .
*/
if ( ( flags & CCWDEV_EARLY_NOTIFICATION ) & &
( flags & CCWDEV_REPORT_ALL ) )
return - EINVAL ;
cdev - > private - > options . fast = ( flags & CCWDEV_EARLY_NOTIFICATION ) ! = 0 ;
cdev - > private - > options . repall = ( flags & CCWDEV_REPORT_ALL ) ! = 0 ;
cdev - > private - > options . pgroup = ( flags & CCWDEV_DO_PATHGROUP ) ! = 0 ;
cdev - > private - > options . force = ( flags & CCWDEV_ALLOW_FORCE ) ! = 0 ;
return 0 ;
}
2007-10-12 18:11:17 +04:00
/**
* ccw_device_set_options ( ) - set some options
* @ cdev : device for which the options are to be set
* @ flags : options to be set
*
* All flags specified in @ flags are set , the remainder is left untouched .
* Returns :
* % 0 on success , - % EINVAL if an invalid flag combination would ensue .
*/
2007-02-12 17:47:18 +03:00
int ccw_device_set_options ( struct ccw_device * cdev , unsigned long flags )
{
/*
* The flag usage is mutal exclusive . . .
*/
if ( ( ( flags & CCWDEV_EARLY_NOTIFICATION ) & &
( flags & CCWDEV_REPORT_ALL ) ) | |
( ( flags & CCWDEV_EARLY_NOTIFICATION ) & &
cdev - > private - > options . repall ) | |
( ( flags & CCWDEV_REPORT_ALL ) & &
cdev - > private - > options . fast ) )
return - EINVAL ;
cdev - > private - > options . fast | = ( flags & CCWDEV_EARLY_NOTIFICATION ) ! = 0 ;
cdev - > private - > options . repall | = ( flags & CCWDEV_REPORT_ALL ) ! = 0 ;
cdev - > private - > options . pgroup | = ( flags & CCWDEV_DO_PATHGROUP ) ! = 0 ;
cdev - > private - > options . force | = ( flags & CCWDEV_ALLOW_FORCE ) ! = 0 ;
return 0 ;
}
2007-10-12 18:11:17 +04:00
/**
* ccw_device_clear_options ( ) - clear some options
* @ cdev : device for which the options are to be cleared
* @ flags : options to be cleared
*
* All flags specified in @ flags are cleared , the remainder is left untouched .
*/
2007-02-12 17:47:18 +03:00
void ccw_device_clear_options ( struct ccw_device * cdev , unsigned long flags )
{
cdev - > private - > options . fast & = ( flags & CCWDEV_EARLY_NOTIFICATION ) = = 0 ;
cdev - > private - > options . repall & = ( flags & CCWDEV_REPORT_ALL ) = = 0 ;
cdev - > private - > options . pgroup & = ( flags & CCWDEV_DO_PATHGROUP ) = = 0 ;
cdev - > private - > options . force & = ( flags & CCWDEV_ALLOW_FORCE ) = = 0 ;
}
2007-10-12 18:11:17 +04:00
/**
* ccw_device_clear ( ) - terminate I / O request processing
* @ 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_clear ( ) calls csch on @ cdev ' s subchannel .
* Returns :
* % 0 on success ,
* - % ENODEV on device not operational ,
* - % EINVAL on invalid device state .
* Context :
* Interrupts disabled , ccw device lock held
*/
int ccw_device_clear ( struct ccw_device * cdev , unsigned long intparm )
2005-04-17 02:20:36 +04:00
{
struct subchannel * sch ;
int ret ;
if ( ! cdev )
return - ENODEV ;
if ( cdev - > private - > state = = DEV_STATE_NOT_OPER )
return - ENODEV ;
if ( cdev - > private - > state ! = DEV_STATE_ONLINE & &
cdev - > private - > state ! = DEV_STATE_W4SENSE )
return - EINVAL ;
sch = to_subchannel ( cdev - > dev . parent ) ;
if ( ! sch )
return - ENODEV ;
ret = cio_clear ( sch ) ;
if ( ret = = 0 )
cdev - > private - > intparm = intparm ;
return ret ;
}
2007-10-12 18:11:17 +04:00
/**
* ccw_device_start_key ( ) - start a s390 channel program with key
* @ 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 ) .
* Returns :
* % 0 , if the operation was successful ;
* - % EBUSY , if the device is busy , or status pending ;
* - % EACCES , if no path specified in @ lpm is operational ;
* - % ENODEV , if the device is not operational .
* Context :
* Interrupts disabled , ccw device lock held
*/
int ccw_device_start_key ( struct ccw_device * cdev , struct ccw1 * cpa ,
unsigned long intparm , __u8 lpm , __u8 key ,
unsigned long flags )
2005-04-17 02:20:36 +04:00
{
struct subchannel * sch ;
int ret ;
if ( ! cdev )
return - ENODEV ;
sch = to_subchannel ( cdev - > dev . parent ) ;
if ( ! sch )
return - ENODEV ;
if ( cdev - > private - > state = = DEV_STATE_NOT_OPER )
return - ENODEV ;
2006-06-29 17:03:35 +04:00
if ( cdev - > private - > state = = DEV_STATE_VERIFY | |
cdev - > private - > state = = DEV_STATE_CLEAR_VERIFY ) {
2005-04-17 02:20:36 +04:00
/* Remember to fake irb when finished. */
if ( ! cdev - > private - > flags . fake_irb ) {
cdev - > private - > flags . fake_irb = 1 ;
cdev - > private - > intparm = intparm ;
return 0 ;
} else
/* There's already a fake I/O around. */
return - EBUSY ;
}
if ( cdev - > private - > state ! = DEV_STATE_ONLINE | |
2008-07-14 11:58:50 +04:00
( ( sch - > schib . scsw . cmd . stctl & SCSW_STCTL_PRIM_STATUS ) & &
! ( sch - > schib . scsw . cmd . stctl & SCSW_STCTL_SEC_STATUS ) ) | |
2005-04-17 02:20:36 +04:00
cdev - > private - > flags . doverify )
return - EBUSY ;
ret = cio_set_options ( sch , flags ) ;
if ( ret )
return ret ;
2006-09-20 17:59:57 +04:00
/* Adjust requested path mask to excluded varied off paths. */
if ( lpm ) {
lpm & = sch - > opm ;
if ( lpm = = 0 )
return - EACCES ;
}
2005-04-17 02:20:36 +04:00
ret = cio_start_key ( sch , cpa , lpm , key ) ;
2008-04-17 09:46:00 +04:00
switch ( ret ) {
case 0 :
2005-04-17 02:20:36 +04:00
cdev - > private - > intparm = intparm ;
2008-04-17 09:46:00 +04:00
break ;
case - EACCES :
case - ENODEV :
dev_fsm_event ( cdev , DEV_EVENT_VERIFY ) ;
break ;
}
2005-04-17 02:20:36 +04:00
return ret ;
}
2007-10-12 18:11:17 +04:00
/**
* ccw_device_start_timeout_key ( ) - start a s390 channel program with timeout and key
* @ 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 ) .
* Returns :
* % 0 , if the operation was successful ;
* - % EBUSY , if the device is busy , or status pending ;
* - % EACCES , if no path specified in @ lpm is operational ;
* - % ENODEV , if the device is not operational .
* Context :
* Interrupts disabled , ccw device lock held
*/
int ccw_device_start_timeout_key ( struct ccw_device * cdev , struct ccw1 * cpa ,
unsigned long intparm , __u8 lpm , __u8 key ,
unsigned long flags , int expires )
2005-04-17 02:20:36 +04:00
{
int ret ;
if ( ! cdev )
return - ENODEV ;
ccw_device_set_timeout ( cdev , expires ) ;
ret = ccw_device_start_key ( cdev , cpa , intparm , lpm , key , flags ) ;
if ( ret ! = 0 )
ccw_device_set_timeout ( cdev , 0 ) ;
return ret ;
}
2007-10-12 18:11:17 +04:00
/**
* ccw_device_start ( ) - start a s390 channel program
* @ 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 ) .
* Returns :
* % 0 , if the operation was successful ;
* - % EBUSY , if the device is busy , or status pending ;
* - % EACCES , if no path specified in @ lpm is operational ;
* - % ENODEV , if the device is not operational .
* Context :
* Interrupts disabled , ccw device lock held
*/
int ccw_device_start ( struct ccw_device * cdev , struct ccw1 * cpa ,
unsigned long intparm , __u8 lpm , unsigned long flags )
2005-04-17 02:20:36 +04:00
{
return ccw_device_start_key ( cdev , cpa , intparm , lpm ,
2005-05-01 19:58:58 +04:00
PAGE_DEFAULT_KEY , flags ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-12 18:11:17 +04:00
/**
* ccw_device_start_timeout ( ) - start a s390 channel program with timeout
* @ 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 ) .
* Returns :
* % 0 , if the operation was successful ;
* - % EBUSY , if the device is busy , or status pending ;
* - % EACCES , if no path specified in @ lpm is operational ;
* - % ENODEV , if the device is not operational .
* Context :
* Interrupts disabled , ccw device lock held
*/
int ccw_device_start_timeout ( struct ccw_device * cdev , struct ccw1 * cpa ,
unsigned long intparm , __u8 lpm ,
unsigned long flags , int expires )
2005-04-17 02:20:36 +04:00
{
return ccw_device_start_timeout_key ( cdev , cpa , intparm , lpm ,
2005-05-01 19:58:58 +04:00
PAGE_DEFAULT_KEY , flags ,
2005-04-17 02:20:36 +04:00
expires ) ;
}
2007-10-12 18:11:17 +04:00
/**
* ccw_device_halt ( ) - halt I / O request processing
* @ 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_halt ( ) calls hsch on @ cdev ' s subchannel .
* Returns :
* % 0 on success ,
* - % ENODEV on device not operational ,
* - % EINVAL on invalid device state ,
* - % EBUSY on device busy or interrupt pending .
* Context :
* Interrupts disabled , ccw device lock held
*/
int ccw_device_halt ( struct ccw_device * cdev , unsigned long intparm )
2005-04-17 02:20:36 +04:00
{
struct subchannel * sch ;
int ret ;
if ( ! cdev )
return - ENODEV ;
if ( cdev - > private - > state = = DEV_STATE_NOT_OPER )
return - ENODEV ;
if ( cdev - > private - > state ! = DEV_STATE_ONLINE & &
cdev - > private - > state ! = DEV_STATE_W4SENSE )
return - EINVAL ;
sch = to_subchannel ( cdev - > dev . parent ) ;
if ( ! sch )
return - ENODEV ;
ret = cio_halt ( sch ) ;
if ( ret = = 0 )
cdev - > private - > intparm = intparm ;
return ret ;
}
2007-10-12 18:11:17 +04:00
/**
* ccw_device_resume ( ) - resume channel program execution
* @ cdev : target ccw device
*
* ccw_device_resume ( ) calls rsch on @ cdev ' s subchannel .
* Returns :
* % 0 on success ,
* - % ENODEV on device not operational ,
* - % EINVAL on invalid device state ,
* - % EBUSY on device busy or interrupt pending .
* Context :
* Interrupts disabled , ccw device lock held
*/
int ccw_device_resume ( struct ccw_device * cdev )
2005-04-17 02:20:36 +04:00
{
struct subchannel * sch ;
if ( ! cdev )
return - ENODEV ;
sch = to_subchannel ( cdev - > dev . parent ) ;
if ( ! sch )
return - ENODEV ;
if ( cdev - > private - > state = = DEV_STATE_NOT_OPER )
return - ENODEV ;
if ( cdev - > private - > state ! = DEV_STATE_ONLINE | |
2008-07-14 11:58:50 +04:00
! ( sch - > schib . scsw . cmd . actl & SCSW_ACTL_SUSPENDED ) )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
return cio_resume ( sch ) ;
}
/*
* Pass interrupt to device driver .
*/
int
ccw_device_call_handler ( struct ccw_device * cdev )
{
struct subchannel * sch ;
unsigned int stctl ;
int ending_status ;
sch = to_subchannel ( cdev - > dev . parent ) ;
/*
* we allow for the device action handler if .
* - we received ending status
* - the action handler requested to see all interrupts
* - we received an intermediate status
* - fast notification was requested ( primary status )
* - unsolicited interrupts
*/
2008-07-14 11:58:50 +04:00
stctl = scsw_stctl ( & cdev - > private - > irb . scsw ) ;
2005-04-17 02:20:36 +04:00
ending_status = ( stctl & SCSW_STCTL_SEC_STATUS ) | |
( stctl = = ( SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND ) ) | |
( stctl = = SCSW_STCTL_STATUS_PEND ) ;
if ( ! ending_status & &
! cdev - > private - > options . repall & &
! ( stctl & SCSW_STCTL_INTER_STATUS ) & &
! ( cdev - > private - > options . fast & &
( stctl & SCSW_STCTL_PRIM_STATUS ) ) )
return 0 ;
2006-10-04 22:02:02 +04:00
/* Clear pending timers for device driver initiated I/O. */
if ( ending_status )
ccw_device_set_timeout ( cdev , 0 ) ;
2005-04-17 02:20:36 +04:00
/*
* Now we are ready to call the device driver interrupt handler .
*/
if ( cdev - > handler )
cdev - > handler ( cdev , cdev - > private - > intparm ,
& cdev - > private - > irb ) ;
/*
* Clear the old and now useless interrupt response block .
*/
memset ( & cdev - > private - > irb , 0 , sizeof ( struct irb ) ) ;
return 1 ;
}
2007-10-12 18:11:17 +04:00
/**
* ccw_device_get_ciw ( ) - Search for CIW command in extended sense data .
* @ cdev : ccw device to inspect
* @ ct : command type to look for
*
* During SenseID , command information words ( CIWs ) describing special
* commands available to the device may have been stored in the extended
* sense data . This function searches for CIWs of a specified command
* type in the extended sense data .
* Returns :
* % NULL if no extended sense data has been stored or if no CIW of the
* specified command type could be found ,
* else a pointer to the CIW of the specified command type .
2005-04-17 02:20:36 +04:00
*/
2007-10-12 18:11:17 +04:00
struct ciw * ccw_device_get_ciw ( struct ccw_device * cdev , __u32 ct )
2005-04-17 02:20:36 +04:00
{
int ciw_cnt ;
if ( cdev - > private - > flags . esid = = 0 )
return NULL ;
for ( ciw_cnt = 0 ; ciw_cnt < MAX_CIWS ; ciw_cnt + + )
if ( cdev - > private - > senseid . ciw [ ciw_cnt ] . ct = = ct )
return cdev - > private - > senseid . ciw + ciw_cnt ;
return NULL ;
}
2007-10-12 18:11:17 +04:00
/**
* ccw_device_get_path_mask ( ) - get currently available paths
* @ cdev : ccw device to be queried
* Returns :
* % 0 if no subchannel for the device is available ,
* else the mask of currently available paths for the ccw device ' s subchannel .
*/
__u8 ccw_device_get_path_mask ( struct ccw_device * cdev )
2005-04-17 02:20:36 +04:00
{
struct subchannel * sch ;
sch = to_subchannel ( cdev - > dev . parent ) ;
if ( ! sch )
return 0 ;
else
2006-09-20 17:59:59 +04:00
return sch - > lpm ;
2005-04-17 02:20:36 +04:00
}
/*
* Try to break the lock on a boxed device .
*/
int
ccw_device_stlck ( struct ccw_device * cdev )
{
void * buf , * buf2 ;
unsigned long flags ;
struct subchannel * sch ;
int ret ;
if ( ! cdev )
return - ENODEV ;
if ( cdev - > drv & & ! cdev - > private - > options . force )
return - EINVAL ;
sch = to_subchannel ( cdev - > dev . parent ) ;
CIO_TRACE_EVENT ( 2 , " stl lock " ) ;
CIO_TRACE_EVENT ( 2 , cdev - > dev . bus_id ) ;
buf = kmalloc ( 32 * sizeof ( char ) , GFP_DMA | GFP_KERNEL ) ;
if ( ! buf )
return - ENOMEM ;
buf2 = kmalloc ( 32 * sizeof ( char ) , GFP_DMA | GFP_KERNEL ) ;
if ( ! buf2 ) {
kfree ( buf ) ;
return - ENOMEM ;
}
2006-12-08 17:54:26 +03:00
spin_lock_irqsave ( sch - > lock , flags ) ;
2008-04-30 15:38:39 +04:00
ret = cio_enable_subchannel ( sch , ( u32 ) ( addr_t ) sch ) ;
2005-04-17 02:20:36 +04:00
if ( ret )
goto out_unlock ;
/*
* Setup ccw . We chain an unconditional reserve and a release so we
* only break the lock .
*/
cdev - > private - > iccws [ 0 ] . cmd_code = CCW_CMD_STLCK ;
cdev - > private - > iccws [ 0 ] . cda = ( __u32 ) __pa ( buf ) ;
cdev - > private - > iccws [ 0 ] . count = 32 ;
cdev - > private - > iccws [ 0 ] . flags = CCW_FLAG_CC ;
cdev - > private - > iccws [ 1 ] . cmd_code = CCW_CMD_RELEASE ;
cdev - > private - > iccws [ 1 ] . cda = ( __u32 ) __pa ( buf2 ) ;
cdev - > private - > iccws [ 1 ] . count = 32 ;
cdev - > private - > iccws [ 1 ] . flags = 0 ;
ret = cio_start ( sch , cdev - > private - > iccws , 0 ) ;
if ( ret ) {
cio_disable_subchannel ( sch ) ; //FIXME: return code?
goto out_unlock ;
}
2008-07-14 11:58:50 +04:00
cdev - > private - > irb . scsw . cmd . actl | = SCSW_ACTL_START_PEND ;
2006-12-08 17:54:26 +03:00
spin_unlock_irqrestore ( sch - > lock , flags ) ;
2008-07-14 11:58:50 +04:00
wait_event ( cdev - > private - > wait_q ,
cdev - > private - > irb . scsw . cmd . actl = = 0 ) ;
2006-12-08 17:54:26 +03:00
spin_lock_irqsave ( sch - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
cio_disable_subchannel ( sch ) ; //FIXME: return code?
2008-07-14 11:58:50 +04:00
if ( ( cdev - > private - > irb . scsw . cmd . dstat ! =
2005-04-17 02:20:36 +04:00
( DEV_STAT_CHN_END | DEV_STAT_DEV_END ) ) | |
2008-07-14 11:58:50 +04:00
( cdev - > private - > irb . scsw . cmd . cstat ! = 0 ) )
2005-04-17 02:20:36 +04:00
ret = - EIO ;
/* Clear irb. */
memset ( & cdev - > private - > irb , 0 , sizeof ( struct irb ) ) ;
out_unlock :
2005-11-07 12:01:30 +03:00
kfree ( buf ) ;
kfree ( buf2 ) ;
2006-12-08 17:54:26 +03:00
spin_unlock_irqrestore ( sch - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
2007-10-12 18:11:17 +04:00
void * ccw_device_get_chp_desc ( struct ccw_device * cdev , int chp_no )
2005-04-17 02:20:36 +04:00
{
struct subchannel * sch ;
2007-04-27 18:01:28 +04:00
struct chp_id chpid ;
2005-04-17 02:20:36 +04:00
sch = to_subchannel ( cdev - > dev . parent ) ;
2007-04-27 18:01:28 +04:00
chp_id_init ( & chpid ) ;
chpid . id = sch - > schib . pmcw . chpid [ chp_no ] ;
return chp_get_chp_desc ( chpid ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-10 17:45:42 +04:00
/**
* ccw_device_get_id - obtain a ccw device id
* @ cdev : device to obtain the id for
* @ dev_id : where to fill in the values
*/
void ccw_device_get_id ( struct ccw_device * cdev , struct ccw_dev_id * dev_id )
{
* dev_id = cdev - > private - > dev_id ;
}
EXPORT_SYMBOL ( ccw_device_get_id ) ;
2008-07-14 11:58:51 +04:00
/**
* ccw_device_tm_start_key - perform start function
* @ cdev : ccw device on which to perform the start function
* @ tcw : transport - command word to be started
* @ intparm : user defined parameter to be passed to the interrupt handler
* @ lpm : mask of paths to use
* @ key : storage key to use for storage access
*
* Start the tcw on the given ccw device . Return zero on success , non - zero
* otherwise .
*/
int ccw_device_tm_start_key ( struct ccw_device * cdev , struct tcw * tcw ,
unsigned long intparm , u8 lpm , u8 key )
{
struct subchannel * sch ;
int rc ;
sch = to_subchannel ( cdev - > dev . parent ) ;
if ( cdev - > private - > state ! = DEV_STATE_ONLINE )
return - EIO ;
/* Adjust requested path mask to excluded varied off paths. */
if ( lpm ) {
lpm & = sch - > opm ;
if ( lpm = = 0 )
return - EACCES ;
}
rc = cio_tm_start_key ( sch , tcw , lpm , key ) ;
if ( rc = = 0 )
cdev - > private - > intparm = intparm ;
return rc ;
}
EXPORT_SYMBOL ( ccw_device_tm_start_key ) ;
/**
* ccw_device_tm_start_timeout_key - perform start function
* @ cdev : ccw device on which to perform the start function
* @ tcw : transport - command word to be started
* @ intparm : user defined parameter to be passed to the interrupt handler
* @ lpm : mask of paths to use
* @ key : storage key to use for storage access
* @ expires : time span in jiffies after which to abort request
*
* Start the tcw on the given ccw device . Return zero on success , non - zero
* otherwise .
*/
int ccw_device_tm_start_timeout_key ( struct ccw_device * cdev , struct tcw * tcw ,
unsigned long intparm , u8 lpm , u8 key ,
int expires )
{
int ret ;
ccw_device_set_timeout ( cdev , expires ) ;
ret = ccw_device_tm_start_key ( cdev , tcw , intparm , lpm , key ) ;
if ( ret ! = 0 )
ccw_device_set_timeout ( cdev , 0 ) ;
return ret ;
}
EXPORT_SYMBOL ( ccw_device_tm_start_timeout_key ) ;
/**
* ccw_device_tm_start - perform start function
* @ cdev : ccw device on which to perform the start function
* @ tcw : transport - command word to be started
* @ intparm : user defined parameter to be passed to the interrupt handler
* @ lpm : mask of paths to use
*
* Start the tcw on the given ccw device . Return zero on success , non - zero
* otherwise .
*/
int ccw_device_tm_start ( struct ccw_device * cdev , struct tcw * tcw ,
unsigned long intparm , u8 lpm )
{
return ccw_device_tm_start_key ( cdev , tcw , intparm , lpm ,
PAGE_DEFAULT_KEY ) ;
}
EXPORT_SYMBOL ( ccw_device_tm_start ) ;
/**
* ccw_device_tm_start_timeout - perform start function
* @ cdev : ccw device on which to perform the start function
* @ tcw : transport - command word to be started
* @ intparm : user defined parameter to be passed to the interrupt handler
* @ lpm : mask of paths to use
* @ expires : time span in jiffies after which to abort request
*
* Start the tcw on the given ccw device . Return zero on success , non - zero
* otherwise .
*/
int ccw_device_tm_start_timeout ( struct ccw_device * cdev , struct tcw * tcw ,
unsigned long intparm , u8 lpm , int expires )
{
return ccw_device_tm_start_timeout_key ( cdev , tcw , intparm , lpm ,
PAGE_DEFAULT_KEY , expires ) ;
}
EXPORT_SYMBOL ( ccw_device_tm_start_timeout ) ;
/**
* ccw_device_tm_intrg - perform interrogate function
* @ cdev : ccw device on which to perform the interrogate function
*
* Perform an interrogate function on the given ccw device . Return zero on
* success , non - zero otherwise .
*/
int ccw_device_tm_intrg ( struct ccw_device * cdev )
{
struct subchannel * sch = to_subchannel ( cdev - > dev . parent ) ;
if ( cdev - > private - > state ! = DEV_STATE_ONLINE )
return - EIO ;
if ( ! scsw_is_tm ( & sch - > schib . scsw ) | |
! ( scsw_actl ( & sch - > schib . scsw ) | SCSW_ACTL_START_PEND ) )
return - EINVAL ;
return cio_tm_intrg ( sch ) ;
}
EXPORT_SYMBOL ( ccw_device_tm_intrg ) ;
2005-04-17 02:20:36 +04:00
// FIXME: these have to go:
int
_ccw_device_get_subchannel_number ( struct ccw_device * cdev )
{
2006-10-11 17:31:38 +04:00
return cdev - > private - > schid . sch_no ;
2005-04-17 02:20:36 +04:00
}
MODULE_LICENSE ( " GPL " ) ;
2007-02-12 17:47:18 +03:00
EXPORT_SYMBOL ( ccw_device_set_options_mask ) ;
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL ( ccw_device_set_options ) ;
2007-02-12 17:47:18 +03:00
EXPORT_SYMBOL ( ccw_device_clear_options ) ;
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL ( ccw_device_clear ) ;
EXPORT_SYMBOL ( ccw_device_halt ) ;
EXPORT_SYMBOL ( ccw_device_resume ) ;
EXPORT_SYMBOL ( ccw_device_start_timeout ) ;
EXPORT_SYMBOL ( ccw_device_start ) ;
EXPORT_SYMBOL ( ccw_device_start_timeout_key ) ;
EXPORT_SYMBOL ( ccw_device_start_key ) ;
EXPORT_SYMBOL ( ccw_device_get_ciw ) ;
EXPORT_SYMBOL ( ccw_device_get_path_mask ) ;
EXPORT_SYMBOL ( _ccw_device_get_subchannel_number ) ;
EXPORT_SYMBOL_GPL ( ccw_device_get_chp_desc ) ;