2005-04-17 02:20:36 +04:00
/*
2008-06-10 20:20:57 +04:00
* zfcp device driver
2005-04-17 02:20:36 +04:00
*
2008-06-10 20:20:57 +04:00
* Setup and helper functions to access QDIO .
2005-04-17 02:20:36 +04:00
*
2009-08-18 17:43:18 +04:00
* Copyright IBM Corporation 2002 , 2009
2005-04-17 02:20:36 +04:00
*/
2008-12-25 15:39:53 +03:00
# define KMSG_COMPONENT "zfcp"
# define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
2005-04-17 02:20:36 +04:00
# include "zfcp_ext.h"
2010-02-17 13:18:59 +03:00
# include "zfcp_qdio.h"
2005-04-17 02:20:36 +04:00
2008-07-02 12:56:34 +04:00
# define QBUFF_PER_PAGE (PAGE_SIZE / sizeof(struct qdio_buffer))
2005-04-17 02:20:36 +04:00
2008-06-10 20:20:57 +04:00
static int zfcp_qdio_buffers_enqueue ( struct qdio_buffer * * sbal )
2005-04-17 02:20:36 +04:00
{
2007-07-18 12:55:13 +04:00
int pos ;
2005-04-17 02:20:36 +04:00
2007-07-18 12:55:13 +04:00
for ( pos = 0 ; pos < QDIO_MAX_BUFFERS_PER_Q ; pos + = QBUFF_PER_PAGE ) {
2008-06-10 20:20:57 +04:00
sbal [ pos ] = ( struct qdio_buffer * ) get_zeroed_page ( GFP_KERNEL ) ;
if ( ! sbal [ pos ] )
2007-07-18 12:55:13 +04:00
return - ENOMEM ;
}
for ( pos = 0 ; pos < QDIO_MAX_BUFFERS_PER_Q ; pos + + )
if ( pos % QBUFF_PER_PAGE )
2008-06-10 20:20:57 +04:00
sbal [ pos ] = sbal [ pos - 1 ] + 1 ;
2007-07-18 12:55:13 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2009-08-18 17:43:19 +04:00
static void zfcp_qdio_handler_error ( struct zfcp_qdio * qdio , char * id )
2005-04-17 02:20:36 +04:00
{
2009-08-18 17:43:19 +04:00
struct zfcp_adapter * adapter = qdio - > adapter ;
2008-10-01 14:42:15 +04:00
dev_warn ( & adapter - > ccw_device - > dev , " A QDIO problem occurred \n " ) ;
2005-04-17 02:20:36 +04:00
2008-06-10 20:20:57 +04:00
zfcp_erp_adapter_reopen ( adapter ,
ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
ZFCP_STATUS_COMMON_ERP_FAILED , id , NULL ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-02 12:56:34 +04:00
static void zfcp_qdio_zero_sbals ( struct qdio_buffer * sbal [ ] , int first , int cnt )
{
int i , sbal_idx ;
for ( i = first ; i < first + cnt ; i + + ) {
sbal_idx = i % QDIO_MAX_BUFFERS_PER_Q ;
memset ( sbal [ sbal_idx ] , 0 , sizeof ( struct qdio_buffer ) ) ;
}
}
2009-03-02 15:08:56 +03:00
/* this needs to be called prior to updating the queue fill level */
2009-08-18 17:43:32 +04:00
static inline void zfcp_qdio_account ( struct zfcp_qdio * qdio )
2009-03-02 15:08:56 +03:00
{
2009-08-18 17:43:32 +04:00
unsigned long long now , span ;
2009-03-02 15:08:56 +03:00
int free , used ;
2009-08-18 17:43:19 +04:00
spin_lock ( & qdio - > stat_lock ) ;
2009-08-18 17:43:32 +04:00
now = get_clock_monotonic ( ) ;
span = ( now - qdio - > req_q_time ) > > 12 ;
free = atomic_read ( & qdio - > req_q . count ) ;
2009-03-02 15:08:56 +03:00
used = QDIO_MAX_BUFFERS_PER_Q - free ;
2009-08-18 17:43:19 +04:00
qdio - > req_q_util + = used * span ;
qdio - > req_q_time = now ;
spin_unlock ( & qdio - > stat_lock ) ;
2009-03-02 15:08:56 +03:00
}
2008-07-17 19:16:48 +04:00
static void zfcp_qdio_int_req ( struct ccw_device * cdev , unsigned int qdio_err ,
int queue_no , int first , int count ,
2008-06-10 20:20:57 +04:00
unsigned long parm )
2005-04-17 02:20:36 +04:00
{
2009-08-18 17:43:19 +04:00
struct zfcp_qdio * qdio = ( struct zfcp_qdio * ) parm ;
struct zfcp_qdio_queue * queue = & qdio - > req_q ;
2005-04-17 02:20:36 +04:00
2008-07-17 19:16:48 +04:00
if ( unlikely ( qdio_err ) ) {
2009-08-18 17:43:21 +04:00
zfcp_dbf_hba_qdio ( qdio - > adapter - > dbf , qdio_err , first ,
count ) ;
2009-08-18 17:43:19 +04:00
zfcp_qdio_handler_error ( qdio , " qdireq1 " ) ;
2008-06-10 20:20:57 +04:00
return ;
}
2005-04-17 02:20:36 +04:00
/* cleanup all SBALs being program-owned now */
2008-06-10 20:20:57 +04:00
zfcp_qdio_zero_sbals ( queue - > sbal , first , count ) ;
2005-04-17 02:20:36 +04:00
2009-08-18 17:43:19 +04:00
zfcp_qdio_account ( qdio ) ;
2008-06-10 20:20:57 +04:00
atomic_add ( count , & queue - > count ) ;
2009-08-18 17:43:19 +04:00
wake_up ( & qdio - > req_q_wq ) ;
2005-04-17 02:20:36 +04:00
}
2009-08-18 17:43:19 +04:00
static void zfcp_qdio_resp_put_back ( struct zfcp_qdio * qdio , int processed )
2005-04-17 02:20:36 +04:00
{
2009-08-18 17:43:19 +04:00
struct zfcp_qdio_queue * queue = & qdio - > resp_q ;
struct ccw_device * cdev = qdio - > adapter - > ccw_device ;
2008-06-10 20:20:57 +04:00
u8 count , start = queue - > first ;
unsigned int retval ;
2005-04-17 02:20:36 +04:00
2008-06-10 20:20:57 +04:00
count = atomic_read ( & queue - > count ) + processed ;
2008-07-17 19:16:48 +04:00
retval = do_QDIO ( cdev , QDIO_FLAG_SYNC_INPUT , 0 , start , count ) ;
2008-06-10 20:20:57 +04:00
if ( unlikely ( retval ) ) {
atomic_set ( & queue - > count , count ) ;
2010-02-17 13:18:51 +03:00
zfcp_erp_adapter_reopen ( qdio - > adapter , 0 , " qdrpb_1 " , NULL ) ;
2008-06-10 20:20:57 +04:00
} else {
queue - > first + = count ;
queue - > first % = QDIO_MAX_BUFFERS_PER_Q ;
atomic_set ( & queue - > count , 0 ) ;
}
}
2008-07-17 19:16:48 +04:00
static void zfcp_qdio_int_resp ( struct ccw_device * cdev , unsigned int qdio_err ,
int queue_no , int first , int count ,
2008-06-10 20:20:57 +04:00
unsigned long parm )
{
2009-08-18 17:43:19 +04:00
struct zfcp_qdio * qdio = ( struct zfcp_qdio * ) parm ;
2009-08-18 17:43:13 +04:00
int sbal_idx , sbal_no ;
2008-06-10 20:20:57 +04:00
2008-07-17 19:16:48 +04:00
if ( unlikely ( qdio_err ) ) {
2009-08-18 17:43:21 +04:00
zfcp_dbf_hba_qdio ( qdio - > adapter - > dbf , qdio_err , first ,
count ) ;
2009-08-18 17:43:19 +04:00
zfcp_qdio_handler_error ( qdio , " qdires1 " ) ;
2008-06-10 20:20:57 +04:00
return ;
}
2005-04-17 02:20:36 +04:00
/*
* go through all SBALs from input queue currently
* returned by QDIO layer
*/
2008-06-10 20:20:57 +04:00
for ( sbal_no = 0 ; sbal_no < count ; sbal_no + + ) {
sbal_idx = ( first + sbal_no ) % QDIO_MAX_BUFFERS_PER_Q ;
2005-04-17 02:20:36 +04:00
/* go through all SBALEs of SBAL */
2009-08-18 17:43:19 +04:00
zfcp_fsf_reqid_check ( qdio , sbal_idx ) ;
2005-04-17 02:20:36 +04:00
}
/*
* put range of SBALs back to response queue
* ( including SBALs which have already been free before )
*/
2009-08-18 17:43:19 +04:00
zfcp_qdio_resp_put_back ( qdio , count ) ;
2005-04-17 02:20:36 +04:00
}
2009-08-18 17:43:19 +04:00
static void zfcp_qdio_sbal_limit ( struct zfcp_qdio * qdio ,
2010-02-17 13:18:59 +03:00
struct zfcp_qdio_req * q_req , int max_sbals )
2005-04-17 02:20:36 +04:00
{
2009-08-18 17:43:19 +04:00
int count = atomic_read ( & qdio - > req_q . count ) ;
2005-04-17 02:20:36 +04:00
count = min ( count , max_sbals ) ;
2009-08-18 17:43:18 +04:00
q_req - > sbal_limit = ( q_req - > sbal_first + count - 1 )
2008-06-10 20:20:57 +04:00
% QDIO_MAX_BUFFERS_PER_Q ;
2005-04-17 02:20:36 +04:00
}
2008-10-01 14:42:16 +04:00
static struct qdio_buffer_element *
2010-02-17 13:18:59 +03:00
zfcp_qdio_sbal_chain ( struct zfcp_qdio * qdio , struct zfcp_qdio_req * q_req ,
2009-08-18 17:43:18 +04:00
unsigned long sbtype )
2005-04-17 02:20:36 +04:00
{
2008-10-01 14:42:16 +04:00
struct qdio_buffer_element * sbale ;
2005-04-17 02:20:36 +04:00
/* set last entry flag in current SBALE of current SBAL */
2009-08-18 17:43:19 +04:00
sbale = zfcp_qdio_sbale_curr ( qdio , q_req ) ;
2005-04-17 02:20:36 +04:00
sbale - > flags | = SBAL_FLAGS_LAST_ENTRY ;
/* don't exceed last allowed SBAL */
2009-08-18 17:43:18 +04:00
if ( q_req - > sbal_last = = q_req - > sbal_limit )
2005-04-17 02:20:36 +04:00
return NULL ;
/* set chaining flag in first SBALE of current SBAL */
2009-08-18 17:43:19 +04:00
sbale = zfcp_qdio_sbale_req ( qdio , q_req ) ;
2005-04-17 02:20:36 +04:00
sbale - > flags | = SBAL_FLAGS0_MORE_SBALS ;
/* calculate index of next SBAL */
2009-08-18 17:43:18 +04:00
q_req - > sbal_last + + ;
q_req - > sbal_last % = QDIO_MAX_BUFFERS_PER_Q ;
2005-04-17 02:20:36 +04:00
/* keep this requests number of SBALs up-to-date */
2009-08-18 17:43:18 +04:00
q_req - > sbal_number + + ;
2005-04-17 02:20:36 +04:00
/* start at first SBALE of new SBAL */
2009-08-18 17:43:18 +04:00
q_req - > sbale_curr = 0 ;
2005-04-17 02:20:36 +04:00
/* set storage-block type for new SBAL */
2009-08-18 17:43:19 +04:00
sbale = zfcp_qdio_sbale_curr ( qdio , q_req ) ;
2005-04-17 02:20:36 +04:00
sbale - > flags | = sbtype ;
return sbale ;
}
2008-10-01 14:42:16 +04:00
static struct qdio_buffer_element *
2010-02-17 13:18:59 +03:00
zfcp_qdio_sbale_next ( struct zfcp_qdio * qdio , struct zfcp_qdio_req * q_req ,
2009-08-18 17:43:18 +04:00
unsigned int sbtype )
2005-04-17 02:20:36 +04:00
{
2009-08-18 17:43:18 +04:00
if ( q_req - > sbale_curr = = ZFCP_LAST_SBALE_PER_SBAL )
2009-08-18 17:43:19 +04:00
return zfcp_qdio_sbal_chain ( qdio , q_req , sbtype ) ;
2009-08-18 17:43:18 +04:00
q_req - > sbale_curr + + ;
2009-08-18 17:43:19 +04:00
return zfcp_qdio_sbale_curr ( qdio , q_req ) ;
2005-04-17 02:20:36 +04:00
}
2009-08-18 17:43:19 +04:00
static void zfcp_qdio_undo_sbals ( struct zfcp_qdio * qdio ,
2010-02-17 13:18:59 +03:00
struct zfcp_qdio_req * q_req )
2005-04-17 02:20:36 +04:00
{
2009-08-18 17:43:19 +04:00
struct qdio_buffer * * sbal = qdio - > req_q . sbal ;
2009-08-18 17:43:18 +04:00
int first = q_req - > sbal_first ;
int last = q_req - > sbal_last ;
2008-06-10 20:20:57 +04:00
int count = ( last - first + QDIO_MAX_BUFFERS_PER_Q ) %
QDIO_MAX_BUFFERS_PER_Q + 1 ;
zfcp_qdio_zero_sbals ( sbal , first , count ) ;
2005-04-17 02:20:36 +04:00
}
2009-08-18 17:43:19 +04:00
static int zfcp_qdio_fill_sbals ( struct zfcp_qdio * qdio ,
2010-02-17 13:18:59 +03:00
struct zfcp_qdio_req * q_req ,
2008-06-10 20:20:57 +04:00
unsigned int sbtype , void * start_addr ,
unsigned int total_length )
2005-04-17 02:20:36 +04:00
{
2008-10-01 14:42:16 +04:00
struct qdio_buffer_element * sbale ;
2005-04-17 02:20:36 +04:00
unsigned long remaining , length ;
void * addr ;
2008-06-10 20:20:57 +04:00
/* split segment up */
2005-04-17 02:20:36 +04:00
for ( addr = start_addr , remaining = total_length ; remaining > 0 ;
addr + = length , remaining - = length ) {
2009-08-18 17:43:19 +04:00
sbale = zfcp_qdio_sbale_next ( qdio , q_req , sbtype ) ;
2008-06-10 20:20:57 +04:00
if ( ! sbale ) {
2009-08-18 17:43:19 +04:00
atomic_inc ( & qdio - > req_q_full ) ;
zfcp_qdio_undo_sbals ( qdio , q_req ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
2008-06-10 20:20:57 +04:00
/* new piece must not exceed next page boundary */
2005-04-17 02:20:36 +04:00
length = min ( remaining ,
2008-06-10 20:20:57 +04:00
( PAGE_SIZE - ( ( unsigned long ) addr &
2005-04-17 02:20:36 +04:00
( PAGE_SIZE - 1 ) ) ) ) ;
2008-06-10 20:20:57 +04:00
sbale - > addr = addr ;
sbale - > length = length ;
2005-04-17 02:20:36 +04:00
}
2008-06-10 20:20:57 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
/**
* zfcp_qdio_sbals_from_sg - fill SBALs from scatter - gather list
* @ fsf_req : request to be processed
* @ sbtype : SBALE flags
* @ sg : scatter - gather list
* @ max_sbals : upper bound for number of SBALs to be used
2008-06-10 20:20:57 +04:00
* Returns : number of bytes , or error ( negativ )
2005-04-17 02:20:36 +04:00
*/
2010-02-17 13:18:59 +03:00
int zfcp_qdio_sbals_from_sg ( struct zfcp_qdio * qdio , struct zfcp_qdio_req * q_req ,
2009-08-18 17:43:18 +04:00
unsigned long sbtype , struct scatterlist * sg ,
int max_sbals )
2005-04-17 02:20:36 +04:00
{
2008-10-01 14:42:16 +04:00
struct qdio_buffer_element * sbale ;
2008-06-10 20:20:57 +04:00
int retval , bytes = 0 ;
2005-04-17 02:20:36 +04:00
/* figure out last allowed SBAL */
2009-08-18 17:43:19 +04:00
zfcp_qdio_sbal_limit ( qdio , q_req , max_sbals ) ;
2005-04-17 02:20:36 +04:00
2008-06-10 20:20:57 +04:00
/* set storage-block type for this request */
2009-08-18 17:43:19 +04:00
sbale = zfcp_qdio_sbale_req ( qdio , q_req ) ;
2005-04-17 02:20:36 +04:00
sbale - > flags | = sbtype ;
2008-06-10 20:20:57 +04:00
for ( ; sg ; sg = sg_next ( sg ) ) {
2009-08-18 17:43:19 +04:00
retval = zfcp_qdio_fill_sbals ( qdio , q_req , sbtype ,
2009-08-18 17:43:18 +04:00
sg_virt ( sg ) , sg - > length ) ;
2008-06-10 20:20:57 +04:00
if ( retval < 0 )
return retval ;
bytes + = sg - > length ;
2005-04-17 02:20:36 +04:00
}
2008-06-10 20:20:57 +04:00
2005-04-17 02:20:36 +04:00
/* assume that no other SBALEs are to follow in the same SBAL */
2009-08-18 17:43:19 +04:00
sbale = zfcp_qdio_sbale_curr ( qdio , q_req ) ;
2005-04-17 02:20:36 +04:00
sbale - > flags | = SBAL_FLAGS_LAST_ENTRY ;
2008-06-10 20:20:57 +04:00
2005-04-17 02:20:36 +04:00
return bytes ;
}
/**
2008-06-10 20:20:57 +04:00
* zfcp_qdio_send - set PCI flag in first SBALE and send req to QDIO
2009-08-18 17:43:19 +04:00
* @ qdio : pointer to struct zfcp_qdio
2010-02-17 13:18:59 +03:00
* @ q_req : pointer to struct zfcp_qdio_req
2008-06-10 20:20:57 +04:00
* Returns : 0 on success , error otherwise
2005-04-17 02:20:36 +04:00
*/
2010-02-17 13:18:59 +03:00
int zfcp_qdio_send ( struct zfcp_qdio * qdio , struct zfcp_qdio_req * q_req )
2005-04-17 02:20:36 +04:00
{
2009-08-18 17:43:19 +04:00
struct zfcp_qdio_queue * req_q = & qdio - > req_q ;
2009-08-18 17:43:18 +04:00
int first = q_req - > sbal_first ;
int count = q_req - > sbal_number ;
2009-03-02 15:09:05 +03:00
int retval ;
unsigned int qdio_flags = QDIO_FLAG_SYNC_OUTPUT ;
2008-06-10 20:20:57 +04:00
2009-08-18 17:43:19 +04:00
zfcp_qdio_account ( qdio ) ;
2009-03-02 15:08:56 +03:00
2009-08-18 17:43:19 +04:00
retval = do_QDIO ( qdio - > adapter - > ccw_device , qdio_flags , 0 , first ,
count ) ;
2008-06-10 20:20:57 +04:00
if ( unlikely ( retval ) ) {
zfcp_qdio_zero_sbals ( req_q - > sbal , first , count ) ;
return retval ;
}
/* account for transferred buffers */
atomic_sub ( count , & req_q - > count ) ;
req_q - > first + = count ;
req_q - > first % = QDIO_MAX_BUFFERS_PER_Q ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2009-08-18 17:43:19 +04:00
static void zfcp_qdio_setup_init_data ( struct qdio_initialize * id ,
struct zfcp_qdio * qdio )
{
id - > cdev = qdio - > adapter - > ccw_device ;
id - > q_format = QDIO_ZFCP_QFMT ;
memcpy ( id - > adapter_name , dev_name ( & id - > cdev - > dev ) , 8 ) ;
ASCEBC ( id - > adapter_name , 8 ) ;
id - > qib_param_field_format = 0 ;
id - > qib_param_field = NULL ;
id - > input_slib_elements = NULL ;
id - > output_slib_elements = NULL ;
id - > no_input_qs = 1 ;
id - > no_output_qs = 1 ;
id - > input_handler = zfcp_qdio_int_resp ;
id - > output_handler = zfcp_qdio_int_req ;
id - > int_parm = ( unsigned long ) qdio ;
id - > input_sbal_addr_array = ( void * * ) ( qdio - > resp_q . sbal ) ;
id - > output_sbal_addr_array = ( void * * ) ( qdio - > req_q . sbal ) ;
}
2008-06-10 20:20:57 +04:00
/**
* zfcp_qdio_allocate - allocate queue memory and initialize QDIO data
* @ adapter : pointer to struct zfcp_adapter
* Returns : - ENOMEM on memory allocation error or return value from
* qdio_allocate
*/
2009-08-18 17:43:22 +04:00
static int zfcp_qdio_allocate ( struct zfcp_qdio * qdio )
2008-06-10 20:20:57 +04:00
{
2009-08-18 17:43:19 +04:00
struct qdio_initialize init_data ;
2008-06-10 20:20:57 +04:00
2009-08-18 17:43:19 +04:00
if ( zfcp_qdio_buffers_enqueue ( qdio - > req_q . sbal ) | |
zfcp_qdio_buffers_enqueue ( qdio - > resp_q . sbal ) )
2008-06-10 20:20:57 +04:00
return - ENOMEM ;
2009-08-18 17:43:19 +04:00
zfcp_qdio_setup_init_data ( & init_data , qdio ) ;
return qdio_allocate ( & init_data ) ;
2008-06-10 20:20:57 +04:00
}
/**
* zfcp_close_qdio - close qdio queues for an adapter
2009-08-18 17:43:19 +04:00
* @ qdio : pointer to structure zfcp_qdio
2005-04-17 02:20:36 +04:00
*/
2009-08-18 17:43:19 +04:00
void zfcp_qdio_close ( struct zfcp_qdio * qdio )
2005-04-17 02:20:36 +04:00
{
2008-06-10 20:20:57 +04:00
struct zfcp_qdio_queue * req_q ;
int first , count ;
2009-08-18 17:43:19 +04:00
if ( ! ( atomic_read ( & qdio - > adapter - > status ) & ZFCP_STATUS_ADAPTER_QDIOUP ) )
2008-06-10 20:20:57 +04:00
return ;
/* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */
2009-08-18 17:43:19 +04:00
req_q = & qdio - > req_q ;
spin_lock_bh ( & qdio - > req_q_lock ) ;
atomic_clear_mask ( ZFCP_STATUS_ADAPTER_QDIOUP , & qdio - > adapter - > status ) ;
spin_unlock_bh ( & qdio - > req_q_lock ) ;
2008-06-10 20:20:57 +04:00
2009-08-18 17:43:19 +04:00
qdio_shutdown ( qdio - > adapter - > ccw_device ,
QDIO_FLAG_CLEANUP_USING_CLEAR ) ;
2008-06-10 20:20:57 +04:00
/* cleanup used outbound sbals */
count = atomic_read ( & req_q - > count ) ;
if ( count < QDIO_MAX_BUFFERS_PER_Q ) {
first = ( req_q - > first + count ) % QDIO_MAX_BUFFERS_PER_Q ;
count = QDIO_MAX_BUFFERS_PER_Q - count ;
zfcp_qdio_zero_sbals ( req_q - > sbal , first , count ) ;
2005-04-17 02:20:36 +04:00
}
2008-06-10 20:20:57 +04:00
req_q - > first = 0 ;
atomic_set ( & req_q - > count , 0 ) ;
2009-08-18 17:43:19 +04:00
qdio - > resp_q . first = 0 ;
atomic_set ( & qdio - > resp_q . count , 0 ) ;
2005-04-17 02:20:36 +04:00
}
2008-06-10 20:20:57 +04:00
/**
* zfcp_qdio_open - prepare and initialize response queue
2009-08-18 17:43:19 +04:00
* @ qdio : pointer to struct zfcp_qdio
2008-06-10 20:20:57 +04:00
* Returns : 0 on success , otherwise - EIO
*/
2009-08-18 17:43:19 +04:00
int zfcp_qdio_open ( struct zfcp_qdio * qdio )
2008-06-10 20:20:57 +04:00
{
2008-10-01 14:42:16 +04:00
struct qdio_buffer_element * sbale ;
2009-08-18 17:43:19 +04:00
struct qdio_initialize init_data ;
struct ccw_device * cdev = qdio - > adapter - > ccw_device ;
2008-06-10 20:20:57 +04:00
int cc ;
2009-08-18 17:43:19 +04:00
if ( atomic_read ( & qdio - > adapter - > status ) & ZFCP_STATUS_ADAPTER_QDIOUP )
2008-06-10 20:20:57 +04:00
return - EIO ;
2009-08-18 17:43:19 +04:00
zfcp_qdio_setup_init_data ( & init_data , qdio ) ;
if ( qdio_establish ( & init_data ) )
2008-10-01 14:42:15 +04:00
goto failed_establish ;
2008-06-10 20:20:57 +04:00
2009-08-18 17:43:19 +04:00
if ( qdio_activate ( cdev ) )
2008-06-10 20:20:57 +04:00
goto failed_qdio ;
for ( cc = 0 ; cc < QDIO_MAX_BUFFERS_PER_Q ; cc + + ) {
2009-08-18 17:43:19 +04:00
sbale = & ( qdio - > resp_q . sbal [ cc ] - > element [ 0 ] ) ;
2008-06-10 20:20:57 +04:00
sbale - > length = 0 ;
sbale - > flags = SBAL_FLAGS_LAST_ENTRY ;
sbale - > addr = NULL ;
}
2009-08-18 17:43:19 +04:00
if ( do_QDIO ( cdev , QDIO_FLAG_SYNC_INPUT , 0 , 0 ,
2008-10-01 14:42:15 +04:00
QDIO_MAX_BUFFERS_PER_Q ) )
2008-06-10 20:20:57 +04:00
goto failed_qdio ;
/* set index of first avalable SBALS / number of available SBALS */
2009-08-18 17:43:19 +04:00
qdio - > req_q . first = 0 ;
atomic_set ( & qdio - > req_q . count , QDIO_MAX_BUFFERS_PER_Q ) ;
2008-06-10 20:20:57 +04:00
return 0 ;
failed_qdio :
2009-08-18 17:43:19 +04:00
qdio_shutdown ( cdev , QDIO_FLAG_CLEANUP_USING_CLEAR ) ;
2008-10-01 14:42:15 +04:00
failed_establish :
2009-08-18 17:43:19 +04:00
dev_err ( & cdev - > dev ,
2008-10-01 14:42:15 +04:00
" Setting up the QDIO connection to the FCP adapter failed \n " ) ;
2008-06-10 20:20:57 +04:00
return - EIO ;
}
2009-08-18 17:43:22 +04:00
void zfcp_qdio_destroy ( struct zfcp_qdio * qdio )
{
struct qdio_buffer * * sbal_req , * * sbal_resp ;
int p ;
if ( ! qdio )
return ;
if ( qdio - > adapter - > ccw_device )
qdio_free ( qdio - > adapter - > ccw_device ) ;
sbal_req = qdio - > req_q . sbal ;
sbal_resp = qdio - > resp_q . sbal ;
for ( p = 0 ; p < QDIO_MAX_BUFFERS_PER_Q ; p + = QBUFF_PER_PAGE ) {
free_page ( ( unsigned long ) sbal_req [ p ] ) ;
free_page ( ( unsigned long ) sbal_resp [ p ] ) ;
}
kfree ( qdio ) ;
}
int zfcp_qdio_setup ( struct zfcp_adapter * adapter )
{
struct zfcp_qdio * qdio ;
qdio = kzalloc ( sizeof ( struct zfcp_qdio ) , GFP_KERNEL ) ;
if ( ! qdio )
return - ENOMEM ;
qdio - > adapter = adapter ;
if ( zfcp_qdio_allocate ( qdio ) ) {
zfcp_qdio_destroy ( qdio ) ;
return - ENOMEM ;
}
spin_lock_init ( & qdio - > req_q_lock ) ;
spin_lock_init ( & qdio - > stat_lock ) ;
adapter - > qdio = qdio ;
return 0 ;
}