2005-04-16 15:20:36 -07:00
/*
2009-06-16 10:30:20 +02:00
* Copyright IBM Corp . 2002 , 2009
2005-04-16 15:20:36 -07:00
*
2009-06-16 10:30:20 +02:00
* Author ( s ) : Martin Schwidefsky ( schwidefsky @ de . ibm . com )
* Cornelia Huck ( cornelia . huck @ de . ibm . com )
2016-10-30 16:37:24 -04:00
*
* License : GPL
2005-04-16 15:20:36 -07:00
*/
2016-10-30 16:37:24 -04:00
# include <linux/export.h>
2005-04-16 15:20:36 -07:00
# include <linux/init.h>
# include <linux/errno.h>
# include <linux/slab.h>
# include <linux/list.h>
# include <linux/device.h>
# include <linux/delay.h>
2009-12-07 12:51:32 +01:00
# include <linux/completion.h>
2005-04-16 15:20:36 -07:00
# include <asm/ccwdev.h>
# include <asm/idals.h>
2007-04-27 16:01:31 +02:00
# include <asm/chpid.h>
2008-07-14 09:58:51 +02:00
# include <asm/fcx.h>
2005-04-16 15:20:36 -07:00
# include "cio.h"
# include "cio_debug.h"
# include "css.h"
# include "chsc.h"
# include "device.h"
2007-04-27 16:01:28 +02:00
# include "chp.h"
2005-04-16 15:20:36 -07:00
2007-10-12 16:11:17 +02: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 15:47:18 +01:00
int ccw_device_set_options_mask ( struct ccw_device * cdev , unsigned long flags )
2005-04-16 15:20:36 -07: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 ;
2009-12-07 12:51:30 +01:00
cdev - > private - > options . mpath = ( flags & CCWDEV_DO_MULTIPATH ) ! = 0 ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2007-10-12 16:11:17 +02: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 15:47:18 +01: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 ;
2009-12-07 12:51:30 +01:00
cdev - > private - > options . mpath | = ( flags & CCWDEV_DO_MULTIPATH ) ! = 0 ;
2007-02-12 15:47:18 +01:00
return 0 ;
}
2007-10-12 16:11:17 +02: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 15:47:18 +01: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 ;
2009-12-07 12:51:30 +01:00
cdev - > private - > options . mpath & = ( flags & CCWDEV_DO_MULTIPATH ) = = 0 ;
2007-02-12 15:47:18 +01:00
}
2009-12-07 12:51:30 +01:00
/**
2016-06-23 11:09:26 +02:00
* ccw_device_is_pathgroup ( ) - determine if paths to this device are grouped
2009-12-07 12:51:30 +01:00
* @ cdev : ccw device
*
* Return non - zero if there is a path group , zero otherwise .
*/
int ccw_device_is_pathgroup ( struct ccw_device * cdev )
{
return cdev - > private - > flags . pgroup ;
}
EXPORT_SYMBOL ( ccw_device_is_pathgroup ) ;
/**
2016-06-23 11:09:26 +02:00
* ccw_device_is_multipath ( ) - determine if device is operating in multipath mode
2009-12-07 12:51:30 +01:00
* @ cdev : ccw device
*
* Return non - zero if device is operating in multipath mode , zero otherwise .
*/
int ccw_device_is_multipath ( struct ccw_device * cdev )
{
return cdev - > private - > flags . mpath ;
}
EXPORT_SYMBOL ( ccw_device_is_multipath ) ;
2007-10-12 16:11:17 +02: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-16 15:20:36 -07:00
{
struct subchannel * sch ;
int ret ;
2009-06-12 10:26:27 +02:00
if ( ! cdev | | ! cdev - > dev . parent )
2005-04-16 15:20:36 -07:00
return - ENODEV ;
2009-06-16 10:30:20 +02:00
sch = to_subchannel ( cdev - > dev . parent ) ;
if ( ! sch - > schib . pmcw . ena )
return - EINVAL ;
2005-04-16 15:20:36 -07:00
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 ;
2009-06-16 10:30:20 +02:00
2005-04-16 15:20:36 -07:00
ret = cio_clear ( sch ) ;
if ( ret = = 0 )
cdev - > private - > intparm = intparm ;
return ret ;
}
2007-10-12 16:11:17 +02: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-16 15:20:36 -07:00
{
struct subchannel * sch ;
int ret ;
2009-06-12 10:26:27 +02:00
if ( ! cdev | | ! cdev - > dev . parent )
2005-04-16 15:20:36 -07:00
return - ENODEV ;
sch = to_subchannel ( cdev - > dev . parent ) ;
2009-06-16 10:30:20 +02:00
if ( ! sch - > schib . pmcw . ena )
return - EINVAL ;
2005-04-16 15:20:36 -07:00
if ( cdev - > private - > state = = DEV_STATE_NOT_OPER )
return - ENODEV ;
2009-12-07 12:51:29 +01:00
if ( cdev - > private - > state = = DEV_STATE_VERIFY ) {
2005-04-16 15:20:36 -07:00
/* Remember to fake irb when finished. */
if ( ! cdev - > private - > flags . fake_irb ) {
2011-12-01 13:32:21 +01:00
cdev - > private - > flags . fake_irb = FAKE_CMD_IRB ;
2005-04-16 15:20:36 -07:00
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 09:58:50 +02:00
( ( sch - > schib . scsw . cmd . stctl & SCSW_STCTL_PRIM_STATUS ) & &
! ( sch - > schib . scsw . cmd . stctl & SCSW_STCTL_SEC_STATUS ) ) | |
2005-04-16 15:20:36 -07:00
cdev - > private - > flags . doverify )
return - EBUSY ;
ret = cio_set_options ( sch , flags ) ;
if ( ret )
return ret ;
2011-12-01 13:32:20 +01:00
/* Adjust requested path mask to exclude unusable paths. */
2006-09-20 15:59:57 +02:00
if ( lpm ) {
2011-12-01 13:32:20 +01:00
lpm & = sch - > lpm ;
2006-09-20 15:59:57 +02:00
if ( lpm = = 0 )
return - EACCES ;
}
2005-04-16 15:20:36 -07:00
ret = cio_start_key ( sch , cpa , lpm , key ) ;
2008-04-17 07:46:00 +02:00
switch ( ret ) {
case 0 :
2005-04-16 15:20:36 -07:00
cdev - > private - > intparm = intparm ;
2008-04-17 07:46:00 +02:00
break ;
case - EACCES :
case - ENODEV :
dev_fsm_event ( cdev , DEV_EVENT_VERIFY ) ;
break ;
}
2005-04-16 15:20:36 -07:00
return ret ;
}
2007-10-12 16:11:17 +02: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-16 15:20:36 -07: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 16:11:17 +02: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-16 15:20:36 -07:00
{
return ccw_device_start_key ( cdev , cpa , intparm , lpm ,
2005-05-01 08:58:58 -07:00
PAGE_DEFAULT_KEY , flags ) ;
2005-04-16 15:20:36 -07:00
}
2007-10-12 16:11:17 +02: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-16 15:20:36 -07:00
{
return ccw_device_start_timeout_key ( cdev , cpa , intparm , lpm ,
2005-05-01 08:58:58 -07:00
PAGE_DEFAULT_KEY , flags ,
2005-04-16 15:20:36 -07:00
expires ) ;
}
2007-10-12 16:11:17 +02: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-16 15:20:36 -07:00
{
struct subchannel * sch ;
int ret ;
2009-06-12 10:26:27 +02:00
if ( ! cdev | | ! cdev - > dev . parent )
2005-04-16 15:20:36 -07:00
return - ENODEV ;
2009-06-16 10:30:20 +02:00
sch = to_subchannel ( cdev - > dev . parent ) ;
if ( ! sch - > schib . pmcw . ena )
return - EINVAL ;
2005-04-16 15:20:36 -07:00
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 ;
2009-06-16 10:30:20 +02:00
2005-04-16 15:20:36 -07:00
ret = cio_halt ( sch ) ;
if ( ret = = 0 )
cdev - > private - > intparm = intparm ;
return ret ;
}
2007-10-12 16:11:17 +02: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-16 15:20:36 -07:00
{
struct subchannel * sch ;
2009-06-12 10:26:27 +02:00
if ( ! cdev | | ! cdev - > dev . parent )
2005-04-16 15:20:36 -07:00
return - ENODEV ;
sch = to_subchannel ( cdev - > dev . parent ) ;
2009-06-16 10:30:20 +02:00
if ( ! sch - > schib . pmcw . ena )
return - EINVAL ;
2005-04-16 15:20:36 -07:00
if ( cdev - > private - > state = = DEV_STATE_NOT_OPER )
return - ENODEV ;
if ( cdev - > private - > state ! = DEV_STATE_ONLINE | |
2008-07-14 09:58:50 +02:00
! ( sch - > schib . scsw . cmd . actl & SCSW_ACTL_SUSPENDED ) )
2005-04-16 15:20:36 -07:00
return - EINVAL ;
return cio_resume ( sch ) ;
}
2007-10-12 16:11:17 +02: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-16 15:20:36 -07:00
*/
2007-10-12 16:11:17 +02:00
struct ciw * ccw_device_get_ciw ( struct ccw_device * cdev , __u32 ct )
2005-04-16 15:20:36 -07: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 16:11:17 +02: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-16 15:20:36 -07:00
{
struct subchannel * sch ;
2009-06-12 10:26:27 +02:00
if ( ! cdev - > dev . parent )
2005-04-16 15:20:36 -07:00
return 0 ;
2009-06-12 10:26:27 +02:00
sch = to_subchannel ( cdev - > dev . parent ) ;
return sch - > lpm ;
2005-04-16 15:20:36 -07:00
}
2014-05-07 13:27:21 +02:00
/**
2016-06-23 11:09:26 +02:00
* ccw_device_get_chp_desc ( ) - return newly allocated channel - path descriptor
2014-05-07 13:27:21 +02:00
* @ cdev : device to obtain the descriptor for
* @ chp_idx : index of the channel path
*
* On success return a newly allocated copy of the channel - path description
* data associated with the given channel path . Return % NULL on error .
*/
struct channel_path_desc * ccw_device_get_chp_desc ( struct ccw_device * cdev ,
int chp_idx )
2005-04-16 15:20:36 -07:00
{
struct subchannel * sch ;
2007-04-27 16:01:28 +02:00
struct chp_id chpid ;
2005-04-16 15:20:36 -07:00
sch = to_subchannel ( cdev - > dev . parent ) ;
2007-04-27 16:01:28 +02:00
chp_id_init ( & chpid ) ;
2014-05-07 13:27:21 +02:00
chpid . id = sch - > schib . pmcw . chpid [ chp_idx ] ;
2007-04-27 16:01:28 +02:00
return chp_get_chp_desc ( chpid ) ;
2005-04-16 15:20:36 -07:00
}
2007-05-10 15:45:42 +02:00
/**
2016-06-23 11:09:26 +02:00
* ccw_device_get_id ( ) - obtain a ccw device id
2007-05-10 15:45:42 +02:00
* @ 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 09:58:51 +02:00
/**
2016-06-23 11:09:26 +02:00
* ccw_device_tm_start_key ( ) - perform start function
2008-07-14 09:58:51 +02:00
* @ 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 ) ;
2009-06-16 10:30:20 +02:00
if ( ! sch - > schib . pmcw . ena )
return - EINVAL ;
2011-12-01 13:32:21 +01:00
if ( cdev - > private - > state = = DEV_STATE_VERIFY ) {
/* Remember to fake irb when finished. */
if ( ! cdev - > private - > flags . fake_irb ) {
cdev - > private - > flags . fake_irb = FAKE_TM_IRB ;
cdev - > private - > intparm = intparm ;
return 0 ;
} else
/* There's already a fake I/O around. */
return - EBUSY ;
}
2008-07-14 09:58:51 +02:00
if ( cdev - > private - > state ! = DEV_STATE_ONLINE )
return - EIO ;
2011-12-01 13:32:20 +01:00
/* Adjust requested path mask to exclude unusable paths. */
2008-07-14 09:58:51 +02:00
if ( lpm ) {
2011-12-01 13:32:20 +01:00
lpm & = sch - > lpm ;
2008-07-14 09:58:51 +02:00
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 ) ;
/**
2016-06-23 11:09:26 +02:00
* ccw_device_tm_start_timeout_key ( ) - perform start function
2008-07-14 09:58:51 +02:00
* @ 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 ) ;
/**
2016-06-23 11:09:26 +02:00
* ccw_device_tm_start ( ) - perform start function
2008-07-14 09:58:51 +02:00
* @ 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 ) ;
/**
2016-06-23 11:09:26 +02:00
* ccw_device_tm_start_timeout ( ) - perform start function
2008-07-14 09:58:51 +02:00
* @ 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 ) ;
2011-01-05 12:47:56 +01:00
/**
2016-06-23 11:09:26 +02:00
* ccw_device_get_mdc ( ) - accumulate max data count
2011-01-05 12:47:56 +01:00
* @ cdev : ccw device for which the max data count is accumulated
* @ mask : mask of paths to use
*
* Return the number of 64 K - bytes blocks all paths at least support
* for a transport command . Return values < = 0 indicate failures .
*/
int ccw_device_get_mdc ( struct ccw_device * cdev , u8 mask )
{
struct subchannel * sch = to_subchannel ( cdev - > dev . parent ) ;
2013-03-11 13:01:08 +01:00
struct channel_path * chp ;
2011-01-05 12:47:56 +01:00
struct chp_id chpid ;
2013-03-11 13:01:08 +01:00
int mdc = 0 , i ;
2011-01-05 12:47:56 +01:00
/* Adjust requested path mask to excluded varied off paths. */
if ( mask )
mask & = sch - > lpm ;
else
mask = sch - > lpm ;
chp_id_init ( & chpid ) ;
for ( i = 0 ; i < 8 ; i + + ) {
if ( ! ( mask & ( 0x80 > > i ) ) )
continue ;
chpid . id = sch - > schib . pmcw . chpid [ i ] ;
2013-03-11 13:01:08 +01:00
chp = chpid_to_chp ( chpid ) ;
if ( ! chp )
continue ;
mutex_lock ( & chp - > lock ) ;
if ( ! chp - > desc_fmt1 . f ) {
mutex_unlock ( & chp - > lock ) ;
2011-01-05 12:47:56 +01:00
return 0 ;
2013-03-11 13:01:08 +01:00
}
if ( ! chp - > desc_fmt1 . r )
2011-01-05 12:47:56 +01:00
mdc = 1 ;
2013-03-11 13:01:08 +01:00
mdc = mdc ? min_t ( int , mdc , chp - > desc_fmt1 . mdc ) :
chp - > desc_fmt1 . mdc ;
mutex_unlock ( & chp - > lock ) ;
2011-01-05 12:47:56 +01:00
}
return mdc ;
}
EXPORT_SYMBOL ( ccw_device_get_mdc ) ;
2008-07-14 09:58:51 +02:00
/**
2016-06-23 11:09:26 +02:00
* ccw_device_tm_intrg ( ) - perform interrogate function
2008-07-14 09:58:51 +02:00
* @ 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 ) ;
2009-06-16 10:30:20 +02:00
if ( ! sch - > schib . pmcw . ena )
return - EINVAL ;
2008-07-14 09:58:51 +02:00
if ( cdev - > private - > state ! = DEV_STATE_ONLINE )
return - EIO ;
if ( ! scsw_is_tm ( & sch - > schib . scsw ) | |
2009-03-26 15:24:18 +01:00
! ( scsw_actl ( & sch - > schib . scsw ) & SCSW_ACTL_START_PEND ) )
2008-07-14 09:58:51 +02:00
return - EINVAL ;
return cio_tm_intrg ( sch ) ;
}
EXPORT_SYMBOL ( ccw_device_tm_intrg ) ;
2012-05-30 16:03:22 +02:00
/**
2016-06-23 11:09:26 +02:00
* ccw_device_get_schid ( ) - obtain a subchannel id
2012-05-30 16:03:22 +02:00
* @ cdev : device to obtain the id for
* @ schid : where to fill in the values
*/
void ccw_device_get_schid ( struct ccw_device * cdev , struct subchannel_id * schid )
{
struct subchannel * sch = to_subchannel ( cdev - > dev . parent ) ;
* schid = sch - > schid ;
}
EXPORT_SYMBOL_GPL ( ccw_device_get_schid ) ;
2005-04-16 15:20:36 -07:00
2007-02-12 15:47:18 +01:00
EXPORT_SYMBOL ( ccw_device_set_options_mask ) ;
2005-04-16 15:20:36 -07:00
EXPORT_SYMBOL ( ccw_device_set_options ) ;
2007-02-12 15:47:18 +01:00
EXPORT_SYMBOL ( ccw_device_clear_options ) ;
2005-04-16 15:20:36 -07: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_GPL ( ccw_device_get_chp_desc ) ;