2008-01-26 14:10:43 +01:00
# ifndef S390_IO_SCH_H
# define S390_IO_SCH_H
2009-12-07 12:51:25 +01:00
# include <linux/types.h>
2008-07-14 09:59:05 +02:00
# include <asm/schid.h>
2009-12-07 12:51:25 +01:00
# include <asm/ccwdev.h>
# include "css.h"
2011-03-15 17:08:23 +01:00
# include "orb.h"
2008-07-14 09:58:51 +02:00
2008-01-26 14:10:43 +01:00
struct io_subchannel_private {
2008-07-14 09:58:51 +02:00
union orb orb ; /* operation request block */
2008-01-26 14:10:43 +01:00
struct ccw1 sense_ccw ; /* static ccw for sense command */
2011-03-15 17:08:26 +01:00
struct ccw_device * cdev ; /* pointer to the child ccw device */
2011-03-15 17:08:25 +01:00
struct {
unsigned int suspend : 1 ; /* allow suspend */
unsigned int prefetch : 1 ; /* deny prefetch */
unsigned int inter : 1 ; /* suppress intermediate interrupts */
} __packed options ;
} __aligned ( 8 ) ;
2008-01-26 14:10:43 +01:00
2011-03-15 17:08:27 +01:00
# define to_io_private(n) ((struct io_subchannel_private *) \
dev_get_drvdata ( & ( n ) - > dev ) )
# define set_io_private(n, p) (dev_set_drvdata(&(n)->dev, p))
2011-03-15 17:08:26 +01:00
static inline struct ccw_device * sch_get_cdev ( struct subchannel * sch )
{
struct io_subchannel_private * priv = to_io_private ( sch ) ;
return priv ? priv - > cdev : NULL ;
}
static inline void sch_set_cdev ( struct subchannel * sch ,
struct ccw_device * cdev )
{
struct io_subchannel_private * priv = to_io_private ( sch ) ;
if ( priv )
priv - > cdev = cdev ;
}
2008-01-26 14:10:43 +01:00
# define MAX_CIWS 8
2009-12-07 12:51:25 +01:00
/*
* Possible status values for a CCW request ' s I / O .
*/
enum io_status {
IO_DONE ,
IO_RUNNING ,
IO_STATUS_ERROR ,
IO_PATH_ERROR ,
IO_REJECTED ,
IO_KILLED
} ;
/**
* ccw_request - Internal CCW request .
* @ cp : channel program to start
* @ timeout : maximum allowable time in jiffies between start I / O and interrupt
* @ maxretries : number of retries per I / O operation and path
* @ lpm : mask of paths to use
* @ check : optional callback that determines if results are final
* @ filter : optional callback to adjust request status based on IRB data
* @ callback : final callback
* @ data : user - defined pointer passed to all callbacks
2010-08-09 18:12:53 +02:00
* @ singlepath : if set , use only one path from @ lpm per start I / O
* @ cancel : non - zero if request was cancelled
* @ done : non - zero if request was finished
2009-12-07 12:51:25 +01:00
* @ mask : current path mask
* @ retries : current number of retries
* @ drc : delayed return code
*/
struct ccw_request {
struct ccw1 * cp ;
unsigned long timeout ;
u16 maxretries ;
u8 lpm ;
int ( * check ) ( struct ccw_device * , void * ) ;
enum io_status ( * filter ) ( struct ccw_device * , void * , struct irb * ,
enum io_status ) ;
void ( * callback ) ( struct ccw_device * , void * , int ) ;
void * data ;
2010-08-09 18:12:53 +02:00
unsigned int singlepath : 1 ;
2009-12-07 12:51:25 +01:00
/* These fields are used internally. */
2010-08-09 18:12:53 +02:00
unsigned int cancel : 1 ;
unsigned int done : 1 ;
2009-12-07 12:51:40 +01:00
u16 mask ;
2009-12-07 12:51:25 +01:00
u16 retries ;
int drc ;
} __attribute__ ( ( packed ) ) ;
2008-01-26 14:10:43 +01:00
/*
* sense - id response buffer layout
*/
struct senseid {
/* common part */
u8 reserved ; /* always 0x'FF' */
u16 cu_type ; /* control unit type */
u8 cu_model ; /* control unit model */
u16 dev_type ; /* device type */
u8 dev_model ; /* device model */
u8 unused ; /* padding byte */
/* extended part */
struct ciw ciw [ MAX_CIWS ] ; /* variable # of CIWs */
} __attribute__ ( ( packed , aligned ( 4 ) ) ) ;
2009-12-07 12:51:19 +01:00
enum cdev_todo {
CDEV_TODO_NOTHING ,
CDEV_TODO_ENABLE_CMF ,
CDEV_TODO_REBIND ,
CDEV_TODO_REGISTER ,
CDEV_TODO_UNREG ,
CDEV_TODO_UNREG_EVAL ,
} ;
2008-01-26 14:10:43 +01:00
struct ccw_device_private {
struct ccw_device * cdev ;
struct subchannel * sch ;
int state ; /* device state */
atomic_t onoff ;
struct ccw_dev_id dev_id ; /* device id */
struct subchannel_id schid ; /* subchannel number */
2009-12-07 12:51:25 +01:00
struct ccw_request req ; /* internal I/O request */
2009-12-07 12:51:27 +01:00
int iretry ;
2010-10-25 16:10:34 +02:00
u8 pgid_valid_mask ; /* mask of valid PGIDs */
u8 pgid_todo_mask ; /* mask of PGIDs to be adjusted */
u8 pgid_reset_mask ; /* mask of PGIDs which were reset */
u8 path_gone_mask ; /* mask of paths, that became unavailable */
u8 path_new_mask ; /* mask of paths, that became available */
2008-01-26 14:10:43 +01:00
struct {
unsigned int fast : 1 ; /* post with "channel end" */
unsigned int repall : 1 ; /* report every interrupt status */
unsigned int pgroup : 1 ; /* do path grouping */
unsigned int force : 1 ; /* allow forced online */
2009-12-07 12:51:30 +01:00
unsigned int mpath : 1 ; /* do multipathing */
2008-01-26 14:10:43 +01:00
} __attribute__ ( ( packed ) ) options ;
struct {
unsigned int esid : 1 ; /* Ext. SenseID supported by HW */
unsigned int dosense : 1 ; /* delayed SENSE required */
unsigned int doverify : 1 ; /* delayed path verification */
unsigned int donotify : 1 ; /* call notify function */
unsigned int recog_done : 1 ; /* dev. recog. complete */
unsigned int fake_irb : 1 ; /* deliver faked irb */
2009-06-16 10:30:20 +02:00
unsigned int resuming : 1 ; /* recognition while resume */
2009-12-07 12:51:30 +01:00
unsigned int pgroup : 1 ; /* pathgroup is set up */
unsigned int mpath : 1 ; /* multipathing is set up */
2009-12-07 12:51:34 +01:00
unsigned int initialized : 1 ; /* set if initial reference held */
2008-01-26 14:10:43 +01:00
} __attribute__ ( ( packed ) ) flags ;
unsigned long intparm ; /* user interruption parameter */
struct qdio_irq * qdio_data ;
struct irb irb ; /* device status */
struct senseid senseid ; /* SenseID info */
struct pgid pgid [ 8 ] ; /* path group IDs per chpid*/
struct ccw1 iccws [ 2 ] ; /* ccws for SNID/SID/SPGID commands */
2009-12-07 12:51:19 +01:00
struct work_struct todo_work ;
enum cdev_todo todo ;
2008-01-26 14:10:43 +01:00
wait_queue_head_t wait_q ;
struct timer_list timer ;
void * cmb ; /* measurement information */
struct list_head cmb_list ; /* list of measured devices */
u64 cmb_start_time ; /* clock value of cmb reset */
void * cmb_wait ; /* deferred cmb enable/disable */
} ;
static inline int rsch ( struct subchannel_id schid )
{
register struct subchannel_id reg1 asm ( " 1 " ) = schid ;
int ccode ;
asm volatile (
" rsch \n "
" ipm %0 \n "
" srl %0,28 "
2008-10-10 21:33:15 +02:00
: " =d " ( ccode )
: " d " ( reg1 )
: " cc " , " memory " ) ;
2008-01-26 14:10:43 +01:00
return ccode ;
}
static inline int hsch ( struct subchannel_id schid )
{
register struct subchannel_id reg1 asm ( " 1 " ) = schid ;
int ccode ;
asm volatile (
" hsch \n "
" ipm %0 \n "
" srl %0,28 "
2008-10-10 21:33:15 +02:00
: " =d " ( ccode )
: " d " ( reg1 )
: " cc " ) ;
2008-01-26 14:10:43 +01:00
return ccode ;
}
static inline int xsch ( struct subchannel_id schid )
{
register struct subchannel_id reg1 asm ( " 1 " ) = schid ;
int ccode ;
asm volatile (
" .insn rre,0xb2760000,%1,0 \n "
" ipm %0 \n "
" srl %0,28 "
2008-10-10 21:33:15 +02:00
: " =d " ( ccode )
: " d " ( reg1 )
: " cc " ) ;
2008-01-26 14:10:43 +01:00
return ccode ;
}
# endif