2005-04-17 02:20:36 +04:00
/*
2006-05-22 20:14:08 +04:00
* This file is part of the zfcp device driver for
* FCP adapters for IBM System z9 and zSeries .
2005-04-17 02:20:36 +04:00
*
2006-05-22 20:14:08 +04:00
* ( C ) Copyright IBM Corp . 2002 , 2006
2005-04-17 02:20:36 +04:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 , or ( at your option )
* any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "zfcp_ext.h"
static int zfcp_fsf_exchange_config_data_handler ( struct zfcp_fsf_req * ) ;
static void zfcp_fsf_exchange_port_data_handler ( struct zfcp_fsf_req * ) ;
static int zfcp_fsf_open_port_handler ( struct zfcp_fsf_req * ) ;
static int zfcp_fsf_close_port_handler ( struct zfcp_fsf_req * ) ;
static int zfcp_fsf_close_physical_port_handler ( struct zfcp_fsf_req * ) ;
static int zfcp_fsf_open_unit_handler ( struct zfcp_fsf_req * ) ;
static int zfcp_fsf_close_unit_handler ( struct zfcp_fsf_req * ) ;
static int zfcp_fsf_send_fcp_command_handler ( struct zfcp_fsf_req * ) ;
static int zfcp_fsf_send_fcp_command_task_handler ( struct zfcp_fsf_req * ) ;
static int zfcp_fsf_send_fcp_command_task_management_handler (
struct zfcp_fsf_req * ) ;
static int zfcp_fsf_abort_fcp_command_handler ( struct zfcp_fsf_req * ) ;
static int zfcp_fsf_status_read_handler ( struct zfcp_fsf_req * ) ;
static int zfcp_fsf_send_ct_handler ( struct zfcp_fsf_req * ) ;
static int zfcp_fsf_send_els_handler ( struct zfcp_fsf_req * ) ;
static int zfcp_fsf_control_file_handler ( struct zfcp_fsf_req * ) ;
static inline int zfcp_fsf_req_sbal_check (
unsigned long * , struct zfcp_qdio_queue * , int ) ;
static inline int zfcp_use_one_sbal (
struct scatterlist * , int , struct scatterlist * , int ) ;
static struct zfcp_fsf_req * zfcp_fsf_req_alloc ( mempool_t * , int ) ;
2006-09-19 00:29:56 +04:00
static int zfcp_fsf_req_send ( struct zfcp_fsf_req * ) ;
2005-04-17 02:20:36 +04:00
static int zfcp_fsf_protstatus_eval ( struct zfcp_fsf_req * ) ;
static int zfcp_fsf_fsfstatus_eval ( struct zfcp_fsf_req * ) ;
static int zfcp_fsf_fsfstatus_qual_eval ( struct zfcp_fsf_req * ) ;
2005-09-13 23:51:16 +04:00
static void zfcp_fsf_link_down_info_eval ( struct zfcp_adapter * ,
struct fsf_link_down_info * ) ;
2005-04-17 02:20:36 +04:00
static int zfcp_fsf_req_dispatch ( struct zfcp_fsf_req * ) ;
/* association between FSF command and FSF QTCB type */
static u32 fsf_qtcb_type [ ] = {
[ FSF_QTCB_FCP_CMND ] = FSF_IO_COMMAND ,
[ FSF_QTCB_ABORT_FCP_CMND ] = FSF_SUPPORT_COMMAND ,
[ FSF_QTCB_OPEN_PORT_WITH_DID ] = FSF_SUPPORT_COMMAND ,
[ FSF_QTCB_OPEN_LUN ] = FSF_SUPPORT_COMMAND ,
[ FSF_QTCB_CLOSE_LUN ] = FSF_SUPPORT_COMMAND ,
[ FSF_QTCB_CLOSE_PORT ] = FSF_SUPPORT_COMMAND ,
[ FSF_QTCB_CLOSE_PHYSICAL_PORT ] = FSF_SUPPORT_COMMAND ,
[ FSF_QTCB_SEND_ELS ] = FSF_SUPPORT_COMMAND ,
[ FSF_QTCB_SEND_GENERIC ] = FSF_SUPPORT_COMMAND ,
[ FSF_QTCB_EXCHANGE_CONFIG_DATA ] = FSF_CONFIG_COMMAND ,
[ FSF_QTCB_EXCHANGE_PORT_DATA ] = FSF_PORT_COMMAND ,
[ FSF_QTCB_DOWNLOAD_CONTROL_FILE ] = FSF_SUPPORT_COMMAND ,
[ FSF_QTCB_UPLOAD_CONTROL_FILE ] = FSF_SUPPORT_COMMAND
} ;
static const char zfcp_act_subtable_type [ 5 ] [ 8 ] = {
" unknown " , " OS " , " WWPN " , " DID " , " LUN "
} ;
/****************************************************************/
/*************** FSF related Functions *************************/
/****************************************************************/
# define ZFCP_LOG_AREA ZFCP_LOG_AREA_FSF
/*
* function : zfcp_fsf_req_alloc
*
* purpose : Obtains an fsf_req and potentially a qtcb ( for all but
* unsolicited requests ) via helper functions
* Does some initial fsf request set - up .
*
* returns : pointer to allocated fsf_req if successfull
* NULL otherwise
*
* locks : none
*
*/
static struct zfcp_fsf_req *
zfcp_fsf_req_alloc ( mempool_t * pool , int req_flags )
{
size_t size ;
void * ptr ;
struct zfcp_fsf_req * fsf_req = NULL ;
if ( req_flags & ZFCP_REQ_NO_QTCB )
size = sizeof ( struct zfcp_fsf_req ) ;
else
2006-09-19 00:28:49 +04:00
size = sizeof ( struct zfcp_fsf_req_qtcb ) ;
2005-04-17 02:20:36 +04:00
2006-09-19 00:28:49 +04:00
if ( likely ( pool ) )
2005-04-17 02:20:36 +04:00
ptr = mempool_alloc ( pool , GFP_ATOMIC ) ;
2006-09-19 00:28:49 +04:00
else {
if ( req_flags & ZFCP_REQ_NO_QTCB )
ptr = kmalloc ( size , GFP_ATOMIC ) ;
else
ptr = kmem_cache_alloc ( zfcp_data . fsf_req_qtcb_cache ,
2006-12-07 07:33:16 +03:00
GFP_ATOMIC ) ;
2006-09-19 00:28:49 +04:00
}
2005-04-17 02:20:36 +04:00
2006-09-19 00:28:49 +04:00
if ( unlikely ( ! ptr ) )
2005-04-17 02:20:36 +04:00
goto out ;
memset ( ptr , 0 , size ) ;
if ( req_flags & ZFCP_REQ_NO_QTCB ) {
fsf_req = ( struct zfcp_fsf_req * ) ptr ;
} else {
2006-09-19 00:28:49 +04:00
fsf_req = & ( ( struct zfcp_fsf_req_qtcb * ) ptr ) - > fsf_req ;
fsf_req - > qtcb = & ( ( struct zfcp_fsf_req_qtcb * ) ptr ) - > qtcb ;
2005-04-17 02:20:36 +04:00
}
fsf_req - > pool = pool ;
out :
return fsf_req ;
}
/*
* function : zfcp_fsf_req_free
*
* purpose : Frees the memory of an fsf_req ( and potentially a qtcb ) or
* returns it into the pool via helper functions .
*
* returns : sod all
*
* locks : none
*/
2005-06-13 15:20:35 +04:00
void
2005-04-17 02:20:36 +04:00
zfcp_fsf_req_free ( struct zfcp_fsf_req * fsf_req )
{
2006-09-19 00:28:49 +04:00
if ( likely ( fsf_req - > pool ) ) {
2005-04-17 02:20:36 +04:00
mempool_free ( fsf_req , fsf_req - > pool ) ;
2006-09-19 00:28:49 +04:00
return ;
}
if ( fsf_req - > qtcb ) {
kmem_cache_free ( zfcp_data . fsf_req_qtcb_cache , fsf_req ) ;
return ;
}
kfree ( fsf_req ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-09 13:01:20 +04:00
/*
* Never ever call this without shutting down the adapter first .
* Otherwise the adapter would continue using and corrupting s390 storage .
* Included BUG_ON ( ) call to ensure this is done .
* ERP is supposed to be the only user of this function .
2005-04-17 02:20:36 +04:00
*/
2007-02-07 15:17:57 +03:00
void zfcp_fsf_req_dismiss_all ( struct zfcp_adapter * adapter )
2005-04-17 02:20:36 +04:00
{
2007-05-09 13:01:20 +04:00
struct zfcp_fsf_req * fsf_req , * tmp ;
2006-08-02 13:05:16 +04:00
unsigned long flags ;
2007-02-07 15:17:57 +03:00
LIST_HEAD ( remove_queue ) ;
2007-05-09 13:01:20 +04:00
unsigned int i ;
2006-08-02 13:05:16 +04:00
2007-05-09 13:01:20 +04:00
BUG_ON ( atomic_test_mask ( ZFCP_STATUS_ADAPTER_QDIOUP , & adapter - > status ) ) ;
2006-08-02 13:05:16 +04:00
spin_lock_irqsave ( & adapter - > req_list_lock , flags ) ;
atomic_set ( & adapter - > reqs_active , 0 ) ;
2007-05-09 13:01:20 +04:00
for ( i = 0 ; i < REQUEST_LIST_SIZE ; i + + )
2007-02-07 15:17:57 +03:00
list_splice_init ( & adapter - > req_list [ i ] , & remove_queue ) ;
2006-08-02 13:05:16 +04:00
spin_unlock_irqrestore ( & adapter - > req_list_lock , flags ) ;
2007-05-09 13:01:20 +04:00
list_for_each_entry_safe ( fsf_req , tmp , & remove_queue , list ) {
list_del ( & fsf_req - > list ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_DISMISSED ;
zfcp_fsf_req_complete ( fsf_req ) ;
2007-02-07 15:17:57 +03:00
}
2005-04-17 02:20:36 +04:00
}
/*
* function : zfcp_fsf_req_complete
*
* purpose : Updates active counts and timers for openfcp - reqs
* May cleanup request after req_eval returns
*
* returns : 0 - success
* ! 0 - failure
*
* context :
*/
int
zfcp_fsf_req_complete ( struct zfcp_fsf_req * fsf_req )
{
int retval = 0 ;
int cleanup ;
if ( unlikely ( fsf_req - > fsf_command = = FSF_QTCB_UNSOLICITED_STATUS ) ) {
ZFCP_LOG_DEBUG ( " Status read response received \n " ) ;
/*
* Note : all cleanup handling is done in the callchain of
* the function call - chain below .
*/
zfcp_fsf_status_read_handler ( fsf_req ) ;
goto out ;
2006-09-19 00:29:56 +04:00
} else {
del_timer ( & fsf_req - > timer ) ;
2005-04-17 02:20:36 +04:00
zfcp_fsf_protstatus_eval ( fsf_req ) ;
2006-09-19 00:29:56 +04:00
}
2005-04-17 02:20:36 +04:00
/*
* fsf_req may be deleted due to waking up functions , so
* cleanup is saved here and used later
*/
if ( likely ( fsf_req - > status & ZFCP_STATUS_FSFREQ_CLEANUP ) )
cleanup = 1 ;
else
cleanup = 0 ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_COMPLETED ;
/* cleanup request if requested by initiator */
if ( likely ( cleanup ) ) {
ZFCP_LOG_TRACE ( " removing FSF request %p \n " , fsf_req ) ;
/*
* lock must not be held here since it will be
* grabed by the called routine , too
*/
2005-06-13 15:20:35 +04:00
zfcp_fsf_req_free ( fsf_req ) ;
2005-04-17 02:20:36 +04:00
} else {
/* notify initiator waiting for the requests completion */
ZFCP_LOG_TRACE ( " waking initiator of FSF request %p \n " , fsf_req ) ;
/*
* FIXME : Race ! We must not access fsf_req here as it might have been
* cleaned up already due to the set ZFCP_STATUS_FSFREQ_COMPLETED
* flag . It ' s an improbable case . But , we have the same paranoia for
* the cleanup flag already .
* Might better be handled using complete ( ) ?
* ( setting the flag and doing wakeup ought to be atomic
* with regard to checking the flag as long as waitqueue is
* part of the to be released structure )
*/
wake_up ( & fsf_req - > completion_wq ) ;
}
out :
return retval ;
}
/*
* function : zfcp_fsf_protstatus_eval
*
* purpose : evaluates the QTCB of the finished FSF request
* and initiates appropriate actions
* ( usually calling FSF command specific handlers )
*
* returns :
*
* context :
*
* locks :
*/
static int
zfcp_fsf_protstatus_eval ( struct zfcp_fsf_req * fsf_req )
{
int retval = 0 ;
struct zfcp_adapter * adapter = fsf_req - > adapter ;
2005-09-13 23:50:38 +04:00
struct fsf_qtcb * qtcb = fsf_req - > qtcb ;
union fsf_prot_status_qual * prot_status_qual =
& qtcb - > prefix . prot_status_qual ;
2005-04-17 02:20:36 +04:00
2005-09-13 23:50:38 +04:00
zfcp_hba_dbf_event_fsf_response ( fsf_req ) ;
2005-04-17 02:20:36 +04:00
if ( fsf_req - > status & ZFCP_STATUS_FSFREQ_DISMISSED ) {
ZFCP_LOG_DEBUG ( " fsf_req 0x%lx has been dismissed \n " ,
( unsigned long ) fsf_req ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR |
ZFCP_STATUS_FSFREQ_RETRY ; /* only for SCSI cmnds. */
goto skip_protstatus ;
}
/* log additional information provided by FSF (if any) */
2007-02-21 11:28:00 +03:00
if ( likely ( qtcb - > header . log_length ) ) {
2005-04-17 02:20:36 +04:00
/* do not trust them ;-) */
2007-02-21 11:28:00 +03:00
if ( unlikely ( qtcb - > header . log_start >
sizeof ( struct fsf_qtcb ) ) ) {
2005-04-17 02:20:36 +04:00
ZFCP_LOG_NORMAL
( " bug: ULP (FSF logging) log data starts "
" beyond end of packet header. Ignored. "
" (start=%i, size=%li) \n " ,
2005-09-13 23:50:38 +04:00
qtcb - > header . log_start ,
2005-04-17 02:20:36 +04:00
sizeof ( struct fsf_qtcb ) ) ;
goto forget_log ;
}
2007-02-21 11:28:00 +03:00
if ( unlikely ( ( size_t ) ( qtcb - > header . log_start +
qtcb - > header . log_length ) >
sizeof ( struct fsf_qtcb ) ) ) {
2005-04-17 02:20:36 +04:00
ZFCP_LOG_NORMAL ( " bug: ULP (FSF logging) log data ends "
" beyond end of packet header. Ignored. "
" (start=%i, length=%i, size=%li) \n " ,
2005-09-13 23:50:38 +04:00
qtcb - > header . log_start ,
qtcb - > header . log_length ,
2005-04-17 02:20:36 +04:00
sizeof ( struct fsf_qtcb ) ) ;
goto forget_log ;
}
ZFCP_LOG_TRACE ( " ULP log data: \n " ) ;
ZFCP_HEX_DUMP ( ZFCP_LOG_LEVEL_TRACE ,
2005-09-13 23:50:38 +04:00
( char * ) qtcb + qtcb - > header . log_start ,
qtcb - > header . log_length ) ;
2005-04-17 02:20:36 +04:00
}
forget_log :
/* evaluate FSF Protocol Status */
2005-09-13 23:50:38 +04:00
switch ( qtcb - > prefix . prot_status ) {
2005-04-17 02:20:36 +04:00
case FSF_PROT_GOOD :
case FSF_PROT_FSF_STATUS_PRESENTED :
break ;
case FSF_PROT_QTCB_VERSION_ERROR :
ZFCP_LOG_NORMAL ( " error: The adapter %s contains "
" microcode of version 0x%x, the device driver "
" only supports 0x%x. Aborting. \n " ,
zfcp_get_busid_by_adapter ( adapter ) ,
2005-09-13 23:50:38 +04:00
prot_status_qual - > version_error . fsf_version ,
ZFCP_QTCB_VERSION ) ;
2005-04-17 02:20:36 +04:00
zfcp_erp_adapter_shutdown ( adapter , 0 ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_PROT_SEQ_NUMB_ERROR :
ZFCP_LOG_NORMAL ( " bug: Sequence number mismatch between "
" driver (0x%x) and adapter %s (0x%x). "
" Restarting all operations on this adapter. \n " ,
2005-09-13 23:50:38 +04:00
qtcb - > prefix . req_seq_no ,
2005-04-17 02:20:36 +04:00
zfcp_get_busid_by_adapter ( adapter ) ,
2005-09-13 23:50:38 +04:00
prot_status_qual - > sequence_error . exp_req_seq_no ) ;
2005-04-17 02:20:36 +04:00
zfcp_erp_adapter_reopen ( adapter , 0 ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_RETRY ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_PROT_UNSUPP_QTCB_TYPE :
ZFCP_LOG_NORMAL ( " error: Packet header type used by the "
" device driver is incompatible with "
" that used on adapter %s. "
" Stopping all operations on this adapter. \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
zfcp_erp_adapter_shutdown ( adapter , 0 ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_PROT_HOST_CONNECTION_INITIALIZING :
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
atomic_set_mask ( ZFCP_STATUS_ADAPTER_HOST_CON_INIT ,
& ( adapter - > status ) ) ;
break ;
case FSF_PROT_DUPLICATE_REQUEST_ID :
ZFCP_LOG_NORMAL ( " bug: The request identifier 0x%Lx "
" to the adapter %s is ambiguous. "
2005-09-13 23:51:16 +04:00
" Stopping all operations on this adapter. \n " ,
* ( unsigned long long * )
( & qtcb - > bottom . support . req_handle ) ,
2005-04-17 02:20:36 +04:00
zfcp_get_busid_by_adapter ( adapter ) ) ;
zfcp_erp_adapter_shutdown ( adapter , 0 ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_PROT_LINK_DOWN :
2005-09-13 23:51:16 +04:00
zfcp_fsf_link_down_info_eval ( adapter ,
& prot_status_qual - > link_down_info ) ;
2006-02-11 03:41:50 +03:00
zfcp_erp_adapter_reopen ( adapter , 0 ) ;
2005-04-17 02:20:36 +04:00
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_PROT_REEST_QUEUE :
2005-09-13 23:50:38 +04:00
ZFCP_LOG_NORMAL ( " The local link to adapter with "
2005-04-17 02:20:36 +04:00
" %s was re-plugged. "
" Re-starting operations on this adapter. \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
/* All ports should be marked as ready to run again */
zfcp_erp_modify_adapter_status ( adapter ,
ZFCP_STATUS_COMMON_RUNNING ,
ZFCP_SET ) ;
zfcp_erp_adapter_reopen ( adapter ,
ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED
| ZFCP_STATUS_COMMON_ERP_FAILED ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_PROT_ERROR_STATE :
ZFCP_LOG_NORMAL ( " error: The adapter %s "
" has entered the error state. "
" Restarting all operations on this "
" adapter. \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
zfcp_erp_adapter_reopen ( adapter , 0 ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_RETRY ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
default :
ZFCP_LOG_NORMAL ( " bug: Transfer protocol status information "
" provided by the adapter %s "
" is not compatible with the device driver. "
" Stopping all operations on this adapter. "
" (debug info 0x%x). \n " ,
zfcp_get_busid_by_adapter ( adapter ) ,
2005-09-13 23:50:38 +04:00
qtcb - > prefix . prot_status ) ;
2005-04-17 02:20:36 +04:00
zfcp_erp_adapter_shutdown ( adapter , 0 ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
}
skip_protstatus :
/*
* always call specific handlers to give them a chance to do
* something meaningful even in error cases
*/
zfcp_fsf_fsfstatus_eval ( fsf_req ) ;
return retval ;
}
/*
* function : zfcp_fsf_fsfstatus_eval
*
* purpose : evaluates FSF status of completed FSF request
* and acts accordingly
*
* returns :
*/
static int
zfcp_fsf_fsfstatus_eval ( struct zfcp_fsf_req * fsf_req )
{
int retval = 0 ;
if ( unlikely ( fsf_req - > status & ZFCP_STATUS_FSFREQ_ERROR ) ) {
goto skip_fsfstatus ;
}
/* evaluate FSF Status */
switch ( fsf_req - > qtcb - > header . fsf_status ) {
case FSF_UNKNOWN_COMMAND :
ZFCP_LOG_NORMAL ( " bug: Command issued by the device driver is "
" not known by the adapter %s "
" Stopping all operations on this adapter. "
" (debug info 0x%x). \n " ,
zfcp_get_busid_by_adapter ( fsf_req - > adapter ) ,
fsf_req - > qtcb - > header . fsf_command ) ;
zfcp_erp_adapter_shutdown ( fsf_req - > adapter , 0 ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_FCP_RSP_AVAILABLE :
ZFCP_LOG_DEBUG ( " FCP Sense data will be presented to the "
" SCSI stack. \n " ) ;
break ;
case FSF_ADAPTER_STATUS_AVAILABLE :
zfcp_fsf_fsfstatus_qual_eval ( fsf_req ) ;
break ;
}
skip_fsfstatus :
/*
* always call specific handlers to give them a chance to do
* something meaningful even in error cases
*/
zfcp_fsf_req_dispatch ( fsf_req ) ;
return retval ;
}
/*
* function : zfcp_fsf_fsfstatus_qual_eval
*
* purpose : evaluates FSF status - qualifier of completed FSF request
* and acts accordingly
*
* returns :
*/
static int
zfcp_fsf_fsfstatus_qual_eval ( struct zfcp_fsf_req * fsf_req )
{
int retval = 0 ;
switch ( fsf_req - > qtcb - > header . fsf_status_qual . word [ 0 ] ) {
case FSF_SQ_FCP_RSP_AVAILABLE :
break ;
case FSF_SQ_RETRY_IF_POSSIBLE :
/* The SCSI-stack may now issue retries or escalate */
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_SQ_COMMAND_ABORTED :
/* Carry the aborted state on to upper layer */
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ABORTED ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_SQ_NO_RECOM :
ZFCP_LOG_NORMAL ( " bug: No recommendation could be given for a "
" problem on the adapter %s "
" Stopping all operations on this adapter. " ,
zfcp_get_busid_by_adapter ( fsf_req - > adapter ) ) ;
zfcp_erp_adapter_shutdown ( fsf_req - > adapter , 0 ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_SQ_ULP_PROGRAMMING_ERROR :
ZFCP_LOG_NORMAL ( " error: not enough SBALs for data transfer "
" (adapter %s) \n " ,
zfcp_get_busid_by_adapter ( fsf_req - > adapter ) ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE :
case FSF_SQ_NO_RETRY_POSSIBLE :
case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED :
/* dealt with in the respective functions */
break ;
default :
ZFCP_LOG_NORMAL ( " bug: Additional status info could "
" not be interpreted properly. \n " ) ;
ZFCP_HEX_DUMP ( ZFCP_LOG_LEVEL_NORMAL ,
( char * ) & fsf_req - > qtcb - > header . fsf_status_qual ,
sizeof ( union fsf_status_qual ) ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
}
return retval ;
}
2005-09-13 23:51:16 +04:00
/**
* zfcp_fsf_link_down_info_eval - evaluate link down information block
*/
static void
zfcp_fsf_link_down_info_eval ( struct zfcp_adapter * adapter ,
struct fsf_link_down_info * link_down )
{
2005-12-01 04:48:41 +03:00
if ( atomic_test_mask ( ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED ,
& adapter - > status ) )
return ;
atomic_set_mask ( ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED , & adapter - > status ) ;
2006-02-11 03:41:50 +03:00
if ( link_down = = NULL )
goto out ;
2005-12-01 04:48:41 +03:00
2005-09-13 23:51:16 +04:00
switch ( link_down - > error_code ) {
case FSF_PSQ_LINK_NO_LIGHT :
ZFCP_LOG_NORMAL ( " The local link to adapter %s is down "
" (no light detected) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
break ;
case FSF_PSQ_LINK_WRAP_PLUG :
ZFCP_LOG_NORMAL ( " The local link to adapter %s is down "
" (wrap plug detected) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
break ;
case FSF_PSQ_LINK_NO_FCP :
ZFCP_LOG_NORMAL ( " The local link to adapter %s is down "
" (adjacent node on link does not support FCP) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
break ;
case FSF_PSQ_LINK_FIRMWARE_UPDATE :
ZFCP_LOG_NORMAL ( " The local link to adapter %s is down "
" (firmware update in progress) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
break ;
case FSF_PSQ_LINK_INVALID_WWPN :
ZFCP_LOG_NORMAL ( " The local link to adapter %s is down "
" (duplicate or invalid WWPN detected) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
break ;
case FSF_PSQ_LINK_NO_NPIV_SUPPORT :
ZFCP_LOG_NORMAL ( " The local link to adapter %s is down "
" (no support for NPIV by Fabric) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
break ;
case FSF_PSQ_LINK_NO_FCP_RESOURCES :
ZFCP_LOG_NORMAL ( " The local link to adapter %s is down "
" (out of resource in FCP daughtercard) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
break ;
case FSF_PSQ_LINK_NO_FABRIC_RESOURCES :
ZFCP_LOG_NORMAL ( " The local link to adapter %s is down "
" (out of resource in Fabric) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
break ;
case FSF_PSQ_LINK_FABRIC_LOGIN_UNABLE :
ZFCP_LOG_NORMAL ( " The local link to adapter %s is down "
" (unable to Fabric login) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
break ;
case FSF_PSQ_LINK_WWPN_ASSIGNMENT_CORRUPTED :
ZFCP_LOG_NORMAL ( " WWPN assignment file corrupted on adapter %s \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
break ;
case FSF_PSQ_LINK_MODE_TABLE_CURRUPTED :
ZFCP_LOG_NORMAL ( " Mode table corrupted on adapter %s \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
break ;
case FSF_PSQ_LINK_NO_WWPN_ASSIGNMENT :
ZFCP_LOG_NORMAL ( " No WWPN for assignment table on adapter %s \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
break ;
default :
ZFCP_LOG_NORMAL ( " The local link to adapter %s is down "
" (warning: unknown reason code %d) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ,
link_down - > error_code ) ;
}
if ( adapter - > connection_features & FSF_FEATURE_NPIV_MODE )
ZFCP_LOG_DEBUG ( " Debug information to link down: "
" primary_status=0x%02x "
" ioerr_code=0x%02x "
" action_code=0x%02x "
" reason_code=0x%02x "
" explanation_code=0x%02x "
" vendor_specific_code=0x%02x \n " ,
link_down - > primary_status ,
link_down - > ioerr_code ,
link_down - > action_code ,
link_down - > reason_code ,
link_down - > explanation_code ,
link_down - > vendor_specific_code ) ;
2006-02-11 03:41:50 +03:00
out :
zfcp_erp_adapter_failed ( adapter ) ;
2005-09-13 23:51:16 +04:00
}
2005-04-17 02:20:36 +04:00
/*
* function : zfcp_fsf_req_dispatch
*
* purpose : calls the appropriate command specific handler
*
* returns :
*/
static int
zfcp_fsf_req_dispatch ( struct zfcp_fsf_req * fsf_req )
{
struct zfcp_erp_action * erp_action = fsf_req - > erp_action ;
struct zfcp_adapter * adapter = fsf_req - > adapter ;
int retval = 0 ;
switch ( fsf_req - > fsf_command ) {
case FSF_QTCB_FCP_CMND :
zfcp_fsf_send_fcp_command_handler ( fsf_req ) ;
break ;
case FSF_QTCB_ABORT_FCP_CMND :
zfcp_fsf_abort_fcp_command_handler ( fsf_req ) ;
break ;
case FSF_QTCB_SEND_GENERIC :
zfcp_fsf_send_ct_handler ( fsf_req ) ;
break ;
case FSF_QTCB_OPEN_PORT_WITH_DID :
zfcp_fsf_open_port_handler ( fsf_req ) ;
break ;
case FSF_QTCB_OPEN_LUN :
zfcp_fsf_open_unit_handler ( fsf_req ) ;
break ;
case FSF_QTCB_CLOSE_LUN :
zfcp_fsf_close_unit_handler ( fsf_req ) ;
break ;
case FSF_QTCB_CLOSE_PORT :
zfcp_fsf_close_port_handler ( fsf_req ) ;
break ;
case FSF_QTCB_CLOSE_PHYSICAL_PORT :
zfcp_fsf_close_physical_port_handler ( fsf_req ) ;
break ;
case FSF_QTCB_EXCHANGE_CONFIG_DATA :
zfcp_fsf_exchange_config_data_handler ( fsf_req ) ;
break ;
case FSF_QTCB_EXCHANGE_PORT_DATA :
zfcp_fsf_exchange_port_data_handler ( fsf_req ) ;
break ;
case FSF_QTCB_SEND_ELS :
zfcp_fsf_send_els_handler ( fsf_req ) ;
break ;
case FSF_QTCB_DOWNLOAD_CONTROL_FILE :
zfcp_fsf_control_file_handler ( fsf_req ) ;
break ;
case FSF_QTCB_UPLOAD_CONTROL_FILE :
zfcp_fsf_control_file_handler ( fsf_req ) ;
break ;
default :
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
ZFCP_LOG_NORMAL ( " bug: Command issued by the device driver is "
" not supported by the adapter %s \n " ,
2005-09-13 23:50:38 +04:00
zfcp_get_busid_by_adapter ( adapter ) ) ;
2005-04-17 02:20:36 +04:00
if ( fsf_req - > fsf_command ! = fsf_req - > qtcb - > header . fsf_command )
ZFCP_LOG_NORMAL
( " bug: Command issued by the device driver differs "
" from the command returned by the adapter %s "
" (debug info 0x%x, 0x%x). \n " ,
2005-09-13 23:50:38 +04:00
zfcp_get_busid_by_adapter ( adapter ) ,
2005-04-17 02:20:36 +04:00
fsf_req - > fsf_command ,
fsf_req - > qtcb - > header . fsf_command ) ;
}
if ( ! erp_action )
return retval ;
zfcp_erp_async_handler ( erp_action , 0 ) ;
return retval ;
}
/*
* function : zfcp_fsf_status_read
*
* purpose : initiates a Status Read command at the specified adapter
*
* returns :
*/
int
zfcp_fsf_status_read ( struct zfcp_adapter * adapter , int req_flags )
{
struct zfcp_fsf_req * fsf_req ;
struct fsf_status_read_buffer * status_buffer ;
unsigned long lock_flags ;
volatile struct qdio_buffer_element * sbale ;
int retval = 0 ;
/* setup new FSF request */
retval = zfcp_fsf_req_create ( adapter , FSF_QTCB_UNSOLICITED_STATUS ,
req_flags | ZFCP_REQ_NO_QTCB ,
adapter - > pool . fsf_req_status_read ,
& lock_flags , & fsf_req ) ;
if ( retval < 0 ) {
ZFCP_LOG_INFO ( " error: Could not create unsolicited status "
" buffer for adapter %s. \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
goto failed_req_create ;
}
sbale = zfcp_qdio_sbale_req ( fsf_req , fsf_req - > sbal_curr , 0 ) ;
sbale [ 0 ] . flags | = SBAL_FLAGS0_TYPE_STATUS ;
sbale [ 2 ] . flags | = SBAL_FLAGS_LAST_ENTRY ;
fsf_req - > sbale_curr = 2 ;
status_buffer =
mempool_alloc ( adapter - > pool . data_status_read , GFP_ATOMIC ) ;
if ( ! status_buffer ) {
ZFCP_LOG_NORMAL ( " bug: could not get some buffer \n " ) ;
goto failed_buf ;
}
memset ( status_buffer , 0 , sizeof ( struct fsf_status_read_buffer ) ) ;
2005-09-13 23:47:52 +04:00
fsf_req - > data = ( unsigned long ) status_buffer ;
2005-04-17 02:20:36 +04:00
/* insert pointer to respective buffer */
sbale = zfcp_qdio_sbale_curr ( fsf_req ) ;
sbale - > addr = ( void * ) status_buffer ;
sbale - > length = sizeof ( struct fsf_status_read_buffer ) ;
2006-09-19 00:29:56 +04:00
retval = zfcp_fsf_req_send ( fsf_req ) ;
2005-04-17 02:20:36 +04:00
if ( retval ) {
ZFCP_LOG_DEBUG ( " error: Could not set-up unsolicited status "
" environment. \n " ) ;
goto failed_req_send ;
}
ZFCP_LOG_TRACE ( " Status Read request initiated (adapter%s) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
goto out ;
failed_req_send :
mempool_free ( status_buffer , adapter - > pool . data_status_read ) ;
failed_buf :
zfcp_fsf_req_free ( fsf_req ) ;
failed_req_create :
2005-09-13 23:50:38 +04:00
zfcp_hba_dbf_event_fsf_unsol ( " fail " , adapter , NULL ) ;
2005-04-17 02:20:36 +04:00
out :
write_unlock_irqrestore ( & adapter - > request_queue . queue_lock , lock_flags ) ;
return retval ;
}
static int
zfcp_fsf_status_read_port_closed ( struct zfcp_fsf_req * fsf_req )
{
struct fsf_status_read_buffer * status_buffer ;
struct zfcp_adapter * adapter ;
struct zfcp_port * port ;
unsigned long flags ;
2005-09-13 23:47:52 +04:00
status_buffer = ( struct fsf_status_read_buffer * ) fsf_req - > data ;
2005-04-17 02:20:36 +04:00
adapter = fsf_req - > adapter ;
read_lock_irqsave ( & zfcp_data . config_lock , flags ) ;
list_for_each_entry ( port , & adapter - > port_list_head , list )
if ( port - > d_id = = ( status_buffer - > d_id & ZFCP_DID_MASK ) )
break ;
read_unlock_irqrestore ( & zfcp_data . config_lock , flags ) ;
if ( ! port | | ( port - > d_id ! = ( status_buffer - > d_id & ZFCP_DID_MASK ) ) ) {
ZFCP_LOG_NORMAL ( " bug: Reopen port indication received for "
2007-05-08 13:14:41 +04:00
" nonexisting port with d_id 0x%06x on "
2005-04-17 02:20:36 +04:00
" adapter %s. Ignored. \n " ,
status_buffer - > d_id & ZFCP_DID_MASK ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
goto out ;
}
switch ( status_buffer - > status_subtype ) {
case FSF_STATUS_READ_SUB_CLOSE_PHYS_PORT :
debug_text_event ( adapter - > erp_dbf , 3 , " unsol_pc_phys: " ) ;
zfcp_erp_port_reopen ( port , 0 ) ;
break ;
case FSF_STATUS_READ_SUB_ERROR_PORT :
debug_text_event ( adapter - > erp_dbf , 1 , " unsol_pc_err: " ) ;
zfcp_erp_port_shutdown ( port , 0 ) ;
break ;
default :
debug_text_event ( adapter - > erp_dbf , 0 , " unsol_unk_sub: " ) ;
debug_exception ( adapter - > erp_dbf , 0 ,
& status_buffer - > status_subtype , sizeof ( u32 ) ) ;
ZFCP_LOG_NORMAL ( " bug: Undefined status subtype received "
" for a reopen indication on port with "
2007-05-08 13:14:41 +04:00
" d_id 0x%06x on the adapter %s. "
2005-04-17 02:20:36 +04:00
" Ignored. (debug info 0x%x) \n " ,
status_buffer - > d_id ,
zfcp_get_busid_by_adapter ( adapter ) ,
status_buffer - > status_subtype ) ;
}
out :
return 0 ;
}
/*
* function : zfcp_fsf_status_read_handler
*
* purpose : is called for finished Open Port command
*
* returns :
*/
static int
zfcp_fsf_status_read_handler ( struct zfcp_fsf_req * fsf_req )
{
int retval = 0 ;
struct zfcp_adapter * adapter = fsf_req - > adapter ;
struct fsf_status_read_buffer * status_buffer =
2005-09-13 23:47:52 +04:00
( struct fsf_status_read_buffer * ) fsf_req - > data ;
2006-05-22 20:21:28 +04:00
struct fsf_bit_error_payload * fsf_bit_error ;
2005-04-17 02:20:36 +04:00
if ( fsf_req - > status & ZFCP_STATUS_FSFREQ_DISMISSED ) {
2005-09-13 23:50:38 +04:00
zfcp_hba_dbf_event_fsf_unsol ( " dism " , adapter , status_buffer ) ;
2005-04-17 02:20:36 +04:00
mempool_free ( status_buffer , adapter - > pool . data_status_read ) ;
2005-06-13 15:20:35 +04:00
zfcp_fsf_req_free ( fsf_req ) ;
2005-04-17 02:20:36 +04:00
goto out ;
}
2005-09-13 23:50:38 +04:00
zfcp_hba_dbf_event_fsf_unsol ( " read " , adapter , status_buffer ) ;
2005-04-17 02:20:36 +04:00
switch ( status_buffer - > status_type ) {
case FSF_STATUS_READ_PORT_CLOSED :
zfcp_fsf_status_read_port_closed ( fsf_req ) ;
break ;
case FSF_STATUS_READ_INCOMING_ELS :
zfcp_fsf_incoming_els ( fsf_req ) ;
break ;
case FSF_STATUS_READ_SENSE_DATA_AVAIL :
ZFCP_LOG_INFO ( " unsolicited sense data received (adapter %s) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
break ;
case FSF_STATUS_READ_BIT_ERROR_THRESHOLD :
2006-05-22 20:21:28 +04:00
fsf_bit_error = ( struct fsf_bit_error_payload * )
status_buffer - > payload ;
ZFCP_LOG_NORMAL ( " Warning: bit error threshold data "
" received (adapter %s, "
" link failures = %i, loss of sync errors = %i, "
" loss of signal errors = %i, "
" primitive sequence errors = %i, "
" invalid transmission word errors = %i, "
" CRC errors = %i) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ,
fsf_bit_error - > link_failure_error_count ,
fsf_bit_error - > loss_of_sync_error_count ,
fsf_bit_error - > loss_of_signal_error_count ,
fsf_bit_error - > primitive_sequence_error_count ,
fsf_bit_error - > invalid_transmission_word_error_count ,
fsf_bit_error - > crc_error_count ) ;
ZFCP_LOG_INFO ( " Additional bit error threshold data "
" (adapter %s, "
" primitive sequence event time-outs = %i, "
" elastic buffer overrun errors = %i, "
" advertised receive buffer-to-buffer credit = %i, "
" current receice buffer-to-buffer credit = %i, "
" advertised transmit buffer-to-buffer credit = %i, "
" current transmit buffer-to-buffer credit = %i) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ,
fsf_bit_error - > primitive_sequence_event_timeout_count ,
fsf_bit_error - > elastic_buffer_overrun_error_count ,
fsf_bit_error - > advertised_receive_b2b_credit ,
fsf_bit_error - > current_receive_b2b_credit ,
fsf_bit_error - > advertised_transmit_b2b_credit ,
fsf_bit_error - > current_transmit_b2b_credit ) ;
2005-04-17 02:20:36 +04:00
break ;
case FSF_STATUS_READ_LINK_DOWN :
2005-09-13 23:51:16 +04:00
switch ( status_buffer - > status_subtype ) {
case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK :
ZFCP_LOG_INFO ( " Physical link to adapter %s is down \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
2005-12-01 04:48:41 +03:00
zfcp_fsf_link_down_info_eval ( adapter ,
( struct fsf_link_down_info * )
& status_buffer - > payload ) ;
2005-09-13 23:51:16 +04:00
break ;
case FSF_STATUS_READ_SUB_FDISC_FAILED :
ZFCP_LOG_INFO ( " Local link to adapter %s is down "
" due to failed FDISC login \n " ,
2005-12-01 04:48:41 +03:00
zfcp_get_busid_by_adapter ( adapter ) ) ;
zfcp_fsf_link_down_info_eval ( adapter ,
( struct fsf_link_down_info * )
& status_buffer - > payload ) ;
2005-09-13 23:51:16 +04:00
break ;
case FSF_STATUS_READ_SUB_FIRMWARE_UPDATE :
ZFCP_LOG_INFO ( " Local link to adapter %s is down "
" due to firmware update on adapter \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
2005-12-01 04:48:41 +03:00
zfcp_fsf_link_down_info_eval ( adapter , NULL ) ;
2005-09-13 23:51:16 +04:00
break ;
default :
ZFCP_LOG_INFO ( " Local link to adapter %s is down "
" due to unknown reason \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
2005-12-01 04:48:41 +03:00
zfcp_fsf_link_down_info_eval ( adapter , NULL ) ;
2005-09-13 23:51:16 +04:00
} ;
2005-04-17 02:20:36 +04:00
break ;
case FSF_STATUS_READ_LINK_UP :
2005-09-13 23:51:16 +04:00
ZFCP_LOG_NORMAL ( " Local link to adapter %s was replugged. "
2005-12-01 04:48:41 +03:00
" Restarting operations on this adapter \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
2005-04-17 02:20:36 +04:00
/* All ports should be marked as ready to run again */
zfcp_erp_modify_adapter_status ( adapter ,
ZFCP_STATUS_COMMON_RUNNING ,
ZFCP_SET ) ;
zfcp_erp_adapter_reopen ( adapter ,
ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED
| ZFCP_STATUS_COMMON_ERP_FAILED ) ;
break ;
2006-01-05 11:56:47 +03:00
case FSF_STATUS_READ_NOTIFICATION_LOST :
ZFCP_LOG_NORMAL ( " Unsolicited status notification(s) lost: "
" adapter %s%s%s%s%s%s%s%s%s \n " ,
zfcp_get_busid_by_adapter ( adapter ) ,
( status_buffer - > status_subtype &
FSF_STATUS_READ_SUB_INCOMING_ELS ) ?
" , incoming ELS " : " " ,
( status_buffer - > status_subtype &
FSF_STATUS_READ_SUB_SENSE_DATA ) ?
" , sense data " : " " ,
( status_buffer - > status_subtype &
FSF_STATUS_READ_SUB_LINK_STATUS ) ?
" , link status change " : " " ,
( status_buffer - > status_subtype &
FSF_STATUS_READ_SUB_PORT_CLOSED ) ?
" , port close " : " " ,
( status_buffer - > status_subtype &
FSF_STATUS_READ_SUB_BIT_ERROR_THRESHOLD ) ?
" , bit error exception " : " " ,
( status_buffer - > status_subtype &
FSF_STATUS_READ_SUB_ACT_UPDATED ) ?
" , ACT update " : " " ,
( status_buffer - > status_subtype &
FSF_STATUS_READ_SUB_ACT_HARDENED ) ?
" , ACT hardening " : " " ,
( status_buffer - > status_subtype &
FSF_STATUS_READ_SUB_FEATURE_UPDATE_ALERT ) ?
" , adapter feature change " : " " ) ;
if ( status_buffer - > status_subtype &
FSF_STATUS_READ_SUB_ACT_UPDATED )
zfcp_erp_adapter_access_changed ( adapter ) ;
break ;
2005-04-17 02:20:36 +04:00
case FSF_STATUS_READ_CFDC_UPDATED :
2005-09-13 23:50:38 +04:00
ZFCP_LOG_NORMAL ( " CFDC has been updated on the adapter %s \n " ,
2005-04-17 02:20:36 +04:00
zfcp_get_busid_by_adapter ( adapter ) ) ;
zfcp_erp_adapter_access_changed ( adapter ) ;
break ;
case FSF_STATUS_READ_CFDC_HARDENED :
switch ( status_buffer - > status_subtype ) {
case FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE :
2005-09-13 23:50:38 +04:00
ZFCP_LOG_NORMAL ( " CFDC of adapter %s saved on SE \n " ,
2005-04-17 02:20:36 +04:00
zfcp_get_busid_by_adapter ( adapter ) ) ;
break ;
case FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE2 :
2005-09-13 23:50:38 +04:00
ZFCP_LOG_NORMAL ( " CFDC of adapter %s has been copied "
2005-04-17 02:20:36 +04:00
" to the secondary SE \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
break ;
default :
2005-09-13 23:50:38 +04:00
ZFCP_LOG_NORMAL ( " CFDC of adapter %s has been hardened \n " ,
2005-04-17 02:20:36 +04:00
zfcp_get_busid_by_adapter ( adapter ) ) ;
}
break ;
2005-09-13 23:51:16 +04:00
case FSF_STATUS_READ_FEATURE_UPDATE_ALERT :
debug_text_event ( adapter - > erp_dbf , 2 , " unsol_features: " ) ;
ZFCP_LOG_INFO ( " List of supported features on adapter %s has "
" been changed from 0x%08X to 0x%08X \n " ,
zfcp_get_busid_by_adapter ( adapter ) ,
* ( u32 * ) ( status_buffer - > payload + 4 ) ,
* ( u32 * ) ( status_buffer - > payload ) ) ;
adapter - > adapter_features = * ( u32 * ) status_buffer - > payload ;
break ;
2005-04-17 02:20:36 +04:00
default :
2005-09-13 23:50:38 +04:00
ZFCP_LOG_NORMAL ( " warning: An unsolicited status packet of unknown "
2005-04-17 02:20:36 +04:00
" type was received (debug info 0x%x) \n " ,
status_buffer - > status_type ) ;
ZFCP_LOG_DEBUG ( " Dump of status_read_buffer %p: \n " ,
status_buffer ) ;
ZFCP_HEX_DUMP ( ZFCP_LOG_LEVEL_DEBUG ,
( char * ) status_buffer ,
sizeof ( struct fsf_status_read_buffer ) ) ;
break ;
}
mempool_free ( status_buffer , adapter - > pool . data_status_read ) ;
2005-06-13 15:20:35 +04:00
zfcp_fsf_req_free ( fsf_req ) ;
2005-04-17 02:20:36 +04:00
/*
* recycle buffer and start new request repeat until outbound
* queue is empty or adapter shutdown is requested
*/
/*
* FIXME ( qdio ) :
* we may wait in the req_create for 5 s during shutdown , so
* qdio_cleanup will have to wait at least that long before returning
* with failure to allow us a proper cleanup under all circumstances
*/
/*
* FIXME :
* allocation failure possible ? ( Is this code needed ? )
*/
retval = zfcp_fsf_status_read ( adapter , 0 ) ;
if ( retval < 0 ) {
ZFCP_LOG_INFO ( " Failed to create unsolicited status read "
" request for the adapter %s. \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
/* temporary fix to avoid status read buffer shortage */
adapter - > status_read_failed + + ;
if ( ( ZFCP_STATUS_READS_RECOM - adapter - > status_read_failed )
< ZFCP_STATUS_READ_FAILED_THRESHOLD ) {
ZFCP_LOG_INFO ( " restart adapter %s due to status read "
" buffer shortage \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
zfcp_erp_adapter_reopen ( adapter , 0 ) ;
}
}
out :
return retval ;
}
/*
* function : zfcp_fsf_abort_fcp_command
*
* purpose : tells FSF to abort a running SCSI command
*
* returns : address of initiated FSF request
* NULL - request could not be initiated
*
* FIXME ( design ) : should be watched by a timeout ! ! !
* FIXME ( design ) shouldn ' t this be modified to return an int
* also . . . don ' t know how though
*/
struct zfcp_fsf_req *
zfcp_fsf_abort_fcp_command ( unsigned long old_req_id ,
struct zfcp_adapter * adapter ,
struct zfcp_unit * unit , int req_flags )
{
volatile struct qdio_buffer_element * sbale ;
struct zfcp_fsf_req * fsf_req = NULL ;
2006-09-19 00:29:56 +04:00
unsigned long lock_flags ;
2005-04-17 02:20:36 +04:00
int retval = 0 ;
/* setup new FSF request */
retval = zfcp_fsf_req_create ( adapter , FSF_QTCB_ABORT_FCP_CMND ,
req_flags , adapter - > pool . fsf_req_abort ,
& lock_flags , & fsf_req ) ;
if ( retval < 0 ) {
ZFCP_LOG_INFO ( " error: Failed to create an abort command "
" request for lun 0x%016Lx on port 0x%016Lx "
" on adapter %s. \n " ,
unit - > fcp_lun ,
unit - > port - > wwpn ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
goto out ;
}
sbale = zfcp_qdio_sbale_req ( fsf_req , fsf_req - > sbal_curr , 0 ) ;
sbale [ 0 ] . flags | = SBAL_FLAGS0_TYPE_READ ;
sbale [ 1 ] . flags | = SBAL_FLAGS_LAST_ENTRY ;
2005-09-13 23:47:52 +04:00
fsf_req - > data = ( unsigned long ) unit ;
2005-04-17 02:20:36 +04:00
/* set handles of unit and its parent port in QTCB */
fsf_req - > qtcb - > header . lun_handle = unit - > handle ;
fsf_req - > qtcb - > header . port_handle = unit - > port - > handle ;
/* set handle of request which should be aborted */
fsf_req - > qtcb - > bottom . support . req_handle = ( u64 ) old_req_id ;
2006-09-19 00:29:56 +04:00
zfcp_fsf_start_timer ( fsf_req , ZFCP_SCSI_ER_TIMEOUT ) ;
retval = zfcp_fsf_req_send ( fsf_req ) ;
2005-04-17 02:20:36 +04:00
if ( retval ) {
ZFCP_LOG_INFO ( " error: Failed to send abort command request "
" on adapter %s, port 0x%016Lx, unit 0x%016Lx \n " ,
zfcp_get_busid_by_adapter ( adapter ) ,
unit - > port - > wwpn , unit - > fcp_lun ) ;
zfcp_fsf_req_free ( fsf_req ) ;
fsf_req = NULL ;
goto out ;
}
ZFCP_LOG_DEBUG ( " Abort FCP Command request initiated "
2007-05-08 13:14:41 +04:00
" (adapter%s, port d_id=0x%06x, "
2005-04-17 02:20:36 +04:00
" unit x%016Lx, old_req_id=0x%lx) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ,
unit - > port - > d_id ,
unit - > fcp_lun , old_req_id ) ;
out :
write_unlock_irqrestore ( & adapter - > request_queue . queue_lock , lock_flags ) ;
return fsf_req ;
}
/*
* function : zfcp_fsf_abort_fcp_command_handler
*
* purpose : is called for finished Abort FCP Command request
*
* returns :
*/
static int
zfcp_fsf_abort_fcp_command_handler ( struct zfcp_fsf_req * new_fsf_req )
{
int retval = - EINVAL ;
2005-09-13 23:47:52 +04:00
struct zfcp_unit * unit ;
2005-04-17 02:20:36 +04:00
unsigned char status_qual =
new_fsf_req - > qtcb - > header . fsf_status_qual . word [ 0 ] ;
if ( new_fsf_req - > status & ZFCP_STATUS_FSFREQ_ERROR ) {
/* do not set ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED */
goto skip_fsfstatus ;
}
2005-09-13 23:47:52 +04:00
unit = ( struct zfcp_unit * ) new_fsf_req - > data ;
2005-04-17 02:20:36 +04:00
/* evaluate FSF status in QTCB */
switch ( new_fsf_req - > qtcb - > header . fsf_status ) {
case FSF_PORT_HANDLE_NOT_VALID :
if ( status_qual > > 4 ! = status_qual % 0xf ) {
debug_text_event ( new_fsf_req - > adapter - > erp_dbf , 3 ,
" fsf_s_phand_nv0 " ) ;
/*
* In this case a command that was sent prior to a port
* reopen was aborted ( handles are different ) . This is
* fine .
*/
} else {
ZFCP_LOG_INFO ( " Temporary port identifier 0x%x for "
" port 0x%016Lx on adapter %s invalid. "
" This may happen occasionally. \n " ,
unit - > port - > handle ,
unit - > port - > wwpn ,
zfcp_get_busid_by_unit ( unit ) ) ;
ZFCP_LOG_INFO ( " status qualifier: \n " ) ;
ZFCP_HEX_DUMP ( ZFCP_LOG_LEVEL_INFO ,
( char * ) & new_fsf_req - > qtcb - > header .
fsf_status_qual ,
sizeof ( union fsf_status_qual ) ) ;
/* Let's hope this sorts out the mess */
debug_text_event ( new_fsf_req - > adapter - > erp_dbf , 1 ,
" fsf_s_phand_nv1 " ) ;
zfcp_erp_adapter_reopen ( unit - > port - > adapter , 0 ) ;
new_fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
}
break ;
case FSF_LUN_HANDLE_NOT_VALID :
if ( status_qual > > 4 ! = status_qual % 0xf ) {
/* 2 */
debug_text_event ( new_fsf_req - > adapter - > erp_dbf , 3 ,
" fsf_s_lhand_nv0 " ) ;
/*
* In this case a command that was sent prior to a unit
* reopen was aborted ( handles are different ) .
* This is fine .
*/
} else {
ZFCP_LOG_INFO
( " Warning: Temporary LUN identifier 0x%x of LUN "
" 0x%016Lx on port 0x%016Lx on adapter %s is "
" invalid. This may happen in rare cases. "
" Trying to re-establish link. \n " ,
unit - > handle ,
unit - > fcp_lun ,
unit - > port - > wwpn ,
zfcp_get_busid_by_unit ( unit ) ) ;
ZFCP_LOG_DEBUG ( " Status qualifier data: \n " ) ;
ZFCP_HEX_DUMP ( ZFCP_LOG_LEVEL_DEBUG ,
( char * ) & new_fsf_req - > qtcb - > header .
fsf_status_qual ,
sizeof ( union fsf_status_qual ) ) ;
/* Let's hope this sorts out the mess */
debug_text_event ( new_fsf_req - > adapter - > erp_dbf , 1 ,
" fsf_s_lhand_nv1 " ) ;
zfcp_erp_port_reopen ( unit - > port , 0 ) ;
new_fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
}
break ;
case FSF_FCP_COMMAND_DOES_NOT_EXIST :
retval = 0 ;
debug_text_event ( new_fsf_req - > adapter - > erp_dbf , 3 ,
" fsf_s_no_exist " ) ;
new_fsf_req - > status | = ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED ;
break ;
case FSF_PORT_BOXED :
ZFCP_LOG_INFO ( " Remote port 0x%016Lx on adapter %s needs to "
" be reopened \n " , unit - > port - > wwpn ,
zfcp_get_busid_by_unit ( unit ) ) ;
debug_text_event ( new_fsf_req - > adapter - > erp_dbf , 2 ,
" fsf_s_pboxed " ) ;
2005-06-13 15:23:57 +04:00
zfcp_erp_port_boxed ( unit - > port ) ;
2005-04-17 02:20:36 +04:00
new_fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR
| ZFCP_STATUS_FSFREQ_RETRY ;
break ;
case FSF_LUN_BOXED :
ZFCP_LOG_INFO (
" unit 0x%016Lx on port 0x%016Lx on adapter %s needs "
" to be reopened \n " ,
unit - > fcp_lun , unit - > port - > wwpn ,
zfcp_get_busid_by_unit ( unit ) ) ;
debug_text_event ( new_fsf_req - > adapter - > erp_dbf , 1 , " fsf_s_lboxed " ) ;
2005-06-13 15:23:57 +04:00
zfcp_erp_unit_boxed ( unit ) ;
2005-04-17 02:20:36 +04:00
new_fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR
| ZFCP_STATUS_FSFREQ_RETRY ;
break ;
case FSF_ADAPTER_STATUS_AVAILABLE :
switch ( new_fsf_req - > qtcb - > header . fsf_status_qual . word [ 0 ] ) {
case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE :
debug_text_event ( new_fsf_req - > adapter - > erp_dbf , 1 ,
" fsf_sq_ltest " ) ;
2005-06-13 15:16:27 +04:00
zfcp_test_link ( unit - > port ) ;
2005-04-17 02:20:36 +04:00
new_fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED :
/* SCSI stack will escalate */
debug_text_event ( new_fsf_req - > adapter - > erp_dbf , 1 ,
" fsf_sq_ulp " ) ;
new_fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
default :
ZFCP_LOG_NORMAL
( " bug: Wrong status qualifier 0x%x arrived. \n " ,
new_fsf_req - > qtcb - > header . fsf_status_qual . word [ 0 ] ) ;
debug_text_event ( new_fsf_req - > adapter - > erp_dbf , 0 ,
" fsf_sq_inval: " ) ;
debug_exception ( new_fsf_req - > adapter - > erp_dbf , 0 ,
& new_fsf_req - > qtcb - > header .
fsf_status_qual . word [ 0 ] , sizeof ( u32 ) ) ;
break ;
}
break ;
case FSF_GOOD :
retval = 0 ;
new_fsf_req - > status | = ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED ;
break ;
default :
ZFCP_LOG_NORMAL ( " bug: An unknown FSF Status was presented "
" (debug info 0x%x) \n " ,
new_fsf_req - > qtcb - > header . fsf_status ) ;
debug_text_event ( new_fsf_req - > adapter - > erp_dbf , 0 ,
" fsf_s_inval: " ) ;
debug_exception ( new_fsf_req - > adapter - > erp_dbf , 0 ,
& new_fsf_req - > qtcb - > header . fsf_status ,
sizeof ( u32 ) ) ;
break ;
}
skip_fsfstatus :
return retval ;
}
/**
* zfcp_use_one_sbal - checks whether req buffer and resp bother each fit into
* one SBALE
* Two scatter - gather lists are passed , one for the reqeust and one for the
* response .
*/
static inline int
zfcp_use_one_sbal ( struct scatterlist * req , int req_count ,
struct scatterlist * resp , int resp_count )
{
return ( ( req_count = = 1 ) & &
( resp_count = = 1 ) & &
( ( ( unsigned long ) zfcp_sg_to_address ( & req [ 0 ] ) &
PAGE_MASK ) = =
( ( unsigned long ) ( zfcp_sg_to_address ( & req [ 0 ] ) +
req [ 0 ] . length - 1 ) & PAGE_MASK ) ) & &
( ( ( unsigned long ) zfcp_sg_to_address ( & resp [ 0 ] ) &
PAGE_MASK ) = =
( ( unsigned long ) ( zfcp_sg_to_address ( & resp [ 0 ] ) +
resp [ 0 ] . length - 1 ) & PAGE_MASK ) ) ) ;
}
/**
* zfcp_fsf_send_ct - initiate a Generic Service request ( FC - GS )
* @ ct : pointer to struct zfcp_send_ct which conatins all needed data for
* the request
* @ pool : pointer to memory pool , if non - null this pool is used to allocate
* a struct zfcp_fsf_req
* @ erp_action : pointer to erp_action , if non - null the Generic Service request
* is sent within error recovery
*/
int
zfcp_fsf_send_ct ( struct zfcp_send_ct * ct , mempool_t * pool ,
struct zfcp_erp_action * erp_action )
{
volatile struct qdio_buffer_element * sbale ;
struct zfcp_port * port ;
struct zfcp_adapter * adapter ;
struct zfcp_fsf_req * fsf_req ;
unsigned long lock_flags ;
int bytes ;
int ret = 0 ;
port = ct - > port ;
adapter = port - > adapter ;
ret = zfcp_fsf_req_create ( adapter , FSF_QTCB_SEND_GENERIC ,
ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP ,
pool , & lock_flags , & fsf_req ) ;
if ( ret < 0 ) {
ZFCP_LOG_INFO ( " error: Could not create CT request (FC-GS) for "
" adapter: %s \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
goto failed_req ;
}
sbale = zfcp_qdio_sbale_req ( fsf_req , fsf_req - > sbal_curr , 0 ) ;
if ( zfcp_use_one_sbal ( ct - > req , ct - > req_count ,
ct - > resp , ct - > resp_count ) ) {
/* both request buffer and response buffer
fit into one sbale each */
sbale [ 0 ] . flags | = SBAL_FLAGS0_TYPE_WRITE_READ ;
sbale [ 2 ] . addr = zfcp_sg_to_address ( & ct - > req [ 0 ] ) ;
sbale [ 2 ] . length = ct - > req [ 0 ] . length ;
sbale [ 3 ] . addr = zfcp_sg_to_address ( & ct - > resp [ 0 ] ) ;
sbale [ 3 ] . length = ct - > resp [ 0 ] . length ;
sbale [ 3 ] . flags | = SBAL_FLAGS_LAST_ENTRY ;
2005-09-13 23:51:16 +04:00
} else if ( adapter - > adapter_features &
2005-04-17 02:20:36 +04:00
FSF_FEATURE_ELS_CT_CHAINED_SBALS ) {
/* try to use chained SBALs */
bytes = zfcp_qdio_sbals_from_sg ( fsf_req ,
SBAL_FLAGS0_TYPE_WRITE_READ ,
ct - > req , ct - > req_count ,
ZFCP_MAX_SBALS_PER_CT_REQ ) ;
if ( bytes < = 0 ) {
ZFCP_LOG_INFO ( " error: creation of CT request failed "
" on adapter %s \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
if ( bytes = = 0 )
ret = - ENOMEM ;
else
ret = bytes ;
goto failed_send ;
}
fsf_req - > qtcb - > bottom . support . req_buf_length = bytes ;
fsf_req - > sbale_curr = ZFCP_LAST_SBALE_PER_SBAL ;
bytes = zfcp_qdio_sbals_from_sg ( fsf_req ,
SBAL_FLAGS0_TYPE_WRITE_READ ,
ct - > resp , ct - > resp_count ,
ZFCP_MAX_SBALS_PER_CT_REQ ) ;
if ( bytes < = 0 ) {
ZFCP_LOG_INFO ( " error: creation of CT request failed "
" on adapter %s \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
if ( bytes = = 0 )
ret = - ENOMEM ;
else
ret = bytes ;
goto failed_send ;
}
fsf_req - > qtcb - > bottom . support . resp_buf_length = bytes ;
} else {
/* reject send generic request */
ZFCP_LOG_INFO (
" error: microcode does not support chained SBALs, "
" CT request too big (adapter %s) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
ret = - EOPNOTSUPP ;
goto failed_send ;
}
/* settings in QTCB */
fsf_req - > qtcb - > header . port_handle = port - > handle ;
2006-05-22 20:18:19 +04:00
fsf_req - > qtcb - > bottom . support . service_class =
ZFCP_FC_SERVICE_CLASS_DEFAULT ;
2005-04-17 02:20:36 +04:00
fsf_req - > qtcb - > bottom . support . timeout = ct - > timeout ;
2005-09-13 23:47:52 +04:00
fsf_req - > data = ( unsigned long ) ct ;
2005-04-17 02:20:36 +04:00
2005-09-13 23:50:38 +04:00
zfcp_san_dbf_event_ct_request ( fsf_req ) ;
2006-09-19 00:29:56 +04:00
if ( erp_action ) {
erp_action - > fsf_req = fsf_req ;
fsf_req - > erp_action = erp_action ;
zfcp_erp_start_timer ( fsf_req ) ;
} else
zfcp_fsf_start_timer ( fsf_req , ZFCP_FSF_REQUEST_TIMEOUT ) ;
ret = zfcp_fsf_req_send ( fsf_req ) ;
2005-04-17 02:20:36 +04:00
if ( ret ) {
ZFCP_LOG_DEBUG ( " error: initiation of CT request failed "
" (adapter %s, port 0x%016Lx) \n " ,
zfcp_get_busid_by_adapter ( adapter ) , port - > wwpn ) ;
goto failed_send ;
}
ZFCP_LOG_DEBUG ( " CT request initiated (adapter %s, port 0x%016Lx) \n " ,
zfcp_get_busid_by_adapter ( adapter ) , port - > wwpn ) ;
goto out ;
failed_send :
zfcp_fsf_req_free ( fsf_req ) ;
if ( erp_action ! = NULL ) {
erp_action - > fsf_req = NULL ;
}
failed_req :
out :
write_unlock_irqrestore ( & adapter - > request_queue . queue_lock ,
lock_flags ) ;
return ret ;
}
/**
* zfcp_fsf_send_ct_handler - handler for Generic Service requests
* @ fsf_req : pointer to struct zfcp_fsf_req
*
2005-09-13 23:47:52 +04:00
* Data specific for the Generic Service request is passed using
* fsf_req - > data . There we find the pointer to struct zfcp_send_ct .
* Usually a specific handler for the CT request is called which is
* found in this structure .
2005-04-17 02:20:36 +04:00
*/
static int
zfcp_fsf_send_ct_handler ( struct zfcp_fsf_req * fsf_req )
{
struct zfcp_port * port ;
struct zfcp_adapter * adapter ;
struct zfcp_send_ct * send_ct ;
struct fsf_qtcb_header * header ;
struct fsf_qtcb_bottom_support * bottom ;
int retval = - EINVAL ;
u16 subtable , rule , counter ;
adapter = fsf_req - > adapter ;
2005-09-13 23:47:52 +04:00
send_ct = ( struct zfcp_send_ct * ) fsf_req - > data ;
2005-04-17 02:20:36 +04:00
port = send_ct - > port ;
header = & fsf_req - > qtcb - > header ;
bottom = & fsf_req - > qtcb - > bottom . support ;
if ( fsf_req - > status & ZFCP_STATUS_FSFREQ_ERROR )
goto skip_fsfstatus ;
/* evaluate FSF status in QTCB */
switch ( header - > fsf_status ) {
case FSF_GOOD :
2005-09-13 23:50:38 +04:00
zfcp_san_dbf_event_ct_response ( fsf_req ) ;
2005-04-17 02:20:36 +04:00
retval = 0 ;
break ;
case FSF_SERVICE_CLASS_NOT_SUPPORTED :
2006-05-22 20:18:19 +04:00
ZFCP_LOG_INFO ( " error: adapter %s does not support fc "
" class %d. \n " ,
zfcp_get_busid_by_port ( port ) ,
ZFCP_FC_SERVICE_CLASS_DEFAULT ) ;
2005-04-17 02:20:36 +04:00
/* stop operation for this adapter */
debug_text_exception ( adapter - > erp_dbf , 0 , " fsf_s_class_nsup " ) ;
zfcp_erp_adapter_shutdown ( adapter , 0 ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_ADAPTER_STATUS_AVAILABLE :
switch ( header - > fsf_status_qual . word [ 0 ] ) {
case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE :
/* reopening link to port */
debug_text_event ( adapter - > erp_dbf , 1 , " fsf_sq_ltest " ) ;
zfcp_test_link ( port ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED :
/* ERP strategy will escalate */
debug_text_event ( adapter - > erp_dbf , 1 , " fsf_sq_ulp " ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
default :
ZFCP_LOG_INFO ( " bug: Wrong status qualifier 0x%x "
" arrived. \n " ,
header - > fsf_status_qual . word [ 0 ] ) ;
break ;
}
break ;
case FSF_ACCESS_DENIED :
ZFCP_LOG_NORMAL ( " access denied, cannot send generic service "
2007-05-08 13:14:41 +04:00
" command (adapter %s, port d_id=0x%06x) \n " ,
2005-04-17 02:20:36 +04:00
zfcp_get_busid_by_port ( port ) , port - > d_id ) ;
for ( counter = 0 ; counter < 2 ; counter + + ) {
subtable = header - > fsf_status_qual . halfword [ counter * 2 ] ;
rule = header - > fsf_status_qual . halfword [ counter * 2 + 1 ] ;
switch ( subtable ) {
case FSF_SQ_CFDC_SUBTABLE_OS :
case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN :
case FSF_SQ_CFDC_SUBTABLE_PORT_DID :
case FSF_SQ_CFDC_SUBTABLE_LUN :
ZFCP_LOG_INFO ( " Access denied (%s rule %d) \n " ,
zfcp_act_subtable_type [ subtable ] , rule ) ;
break ;
}
}
debug_text_event ( adapter - > erp_dbf , 1 , " fsf_s_access " ) ;
zfcp_erp_port_access_denied ( port ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_GENERIC_COMMAND_REJECTED :
ZFCP_LOG_INFO ( " generic service command rejected "
2007-05-08 13:14:41 +04:00
" (adapter %s, port d_id=0x%06x) \n " ,
2005-04-17 02:20:36 +04:00
zfcp_get_busid_by_port ( port ) , port - > d_id ) ;
ZFCP_LOG_INFO ( " status qualifier: \n " ) ;
ZFCP_HEX_DUMP ( ZFCP_LOG_LEVEL_INFO ,
( char * ) & header - > fsf_status_qual ,
sizeof ( union fsf_status_qual ) ) ;
debug_text_event ( adapter - > erp_dbf , 1 , " fsf_s_gcom_rej " ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_PORT_HANDLE_NOT_VALID :
ZFCP_LOG_DEBUG ( " Temporary port identifier 0x%x for port "
" 0x%016Lx on adapter %s invalid. This may "
" happen occasionally. \n " , port - > handle ,
port - > wwpn , zfcp_get_busid_by_port ( port ) ) ;
ZFCP_LOG_INFO ( " status qualifier: \n " ) ;
ZFCP_HEX_DUMP ( ZFCP_LOG_LEVEL_INFO ,
( char * ) & header - > fsf_status_qual ,
sizeof ( union fsf_status_qual ) ) ;
debug_text_event ( adapter - > erp_dbf , 1 , " fsf_s_phandle_nv " ) ;
zfcp_erp_adapter_reopen ( adapter , 0 ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_PORT_BOXED :
ZFCP_LOG_INFO ( " port needs to be reopened "
2007-05-08 13:14:41 +04:00
" (adapter %s, port d_id=0x%06x) \n " ,
2005-04-17 02:20:36 +04:00
zfcp_get_busid_by_port ( port ) , port - > d_id ) ;
debug_text_event ( adapter - > erp_dbf , 2 , " fsf_s_pboxed " ) ;
2005-06-13 15:23:57 +04:00
zfcp_erp_port_boxed ( port ) ;
2005-04-17 02:20:36 +04:00
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR
| ZFCP_STATUS_FSFREQ_RETRY ;
break ;
/* following states should never occure, all cases avoided
in zfcp_fsf_send_ct - but who knows . . . */
case FSF_PAYLOAD_SIZE_MISMATCH :
ZFCP_LOG_INFO ( " payload size mismatch (adapter: %s, "
" req_buf_length=%d, resp_buf_length=%d) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ,
bottom - > req_buf_length , bottom - > resp_buf_length ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_REQUEST_SIZE_TOO_LARGE :
ZFCP_LOG_INFO ( " request size too large (adapter: %s, "
" req_buf_length=%d) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ,
bottom - > req_buf_length ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_RESPONSE_SIZE_TOO_LARGE :
ZFCP_LOG_INFO ( " response size too large (adapter: %s, "
" resp_buf_length=%d) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ,
bottom - > resp_buf_length ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_SBAL_MISMATCH :
ZFCP_LOG_INFO ( " SBAL mismatch (adapter: %s, req_buf_length=%d, "
" resp_buf_length=%d) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ,
bottom - > req_buf_length , bottom - > resp_buf_length ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
default :
ZFCP_LOG_NORMAL ( " bug: An unknown FSF Status was presented "
" (debug info 0x%x) \n " , header - > fsf_status ) ;
debug_text_event ( adapter - > erp_dbf , 0 , " fsf_sq_inval: " ) ;
debug_exception ( adapter - > erp_dbf , 0 ,
& header - > fsf_status_qual . word [ 0 ] , sizeof ( u32 ) ) ;
break ;
}
skip_fsfstatus :
send_ct - > status = retval ;
if ( send_ct - > handler ! = NULL )
send_ct - > handler ( send_ct - > handler_data ) ;
return retval ;
}
/**
* zfcp_fsf_send_els - initiate an ELS command ( FC - FS )
* @ els : pointer to struct zfcp_send_els which contains all needed data for
* the command .
*/
int
zfcp_fsf_send_els ( struct zfcp_send_els * els )
{
volatile struct qdio_buffer_element * sbale ;
struct zfcp_fsf_req * fsf_req ;
2005-09-19 18:56:17 +04:00
u32 d_id ;
2005-04-17 02:20:36 +04:00
struct zfcp_adapter * adapter ;
unsigned long lock_flags ;
int bytes ;
int ret = 0 ;
d_id = els - > d_id ;
adapter = els - > adapter ;
ret = zfcp_fsf_req_create ( adapter , FSF_QTCB_SEND_ELS ,
ZFCP_REQ_AUTO_CLEANUP ,
NULL , & lock_flags , & fsf_req ) ;
if ( ret < 0 ) {
ZFCP_LOG_INFO ( " error: creation of ELS request failed "
2007-05-08 13:14:41 +04:00
" (adapter %s, port d_id: 0x%06x) \n " ,
2005-04-17 02:20:36 +04:00
zfcp_get_busid_by_adapter ( adapter ) , d_id ) ;
goto failed_req ;
}
sbale = zfcp_qdio_sbale_req ( fsf_req , fsf_req - > sbal_curr , 0 ) ;
if ( zfcp_use_one_sbal ( els - > req , els - > req_count ,
els - > resp , els - > resp_count ) ) {
/* both request buffer and response buffer
fit into one sbale each */
sbale [ 0 ] . flags | = SBAL_FLAGS0_TYPE_WRITE_READ ;
sbale [ 2 ] . addr = zfcp_sg_to_address ( & els - > req [ 0 ] ) ;
sbale [ 2 ] . length = els - > req [ 0 ] . length ;
sbale [ 3 ] . addr = zfcp_sg_to_address ( & els - > resp [ 0 ] ) ;
sbale [ 3 ] . length = els - > resp [ 0 ] . length ;
sbale [ 3 ] . flags | = SBAL_FLAGS_LAST_ENTRY ;
2005-09-13 23:51:16 +04:00
} else if ( adapter - > adapter_features &
2005-04-17 02:20:36 +04:00
FSF_FEATURE_ELS_CT_CHAINED_SBALS ) {
/* try to use chained SBALs */
bytes = zfcp_qdio_sbals_from_sg ( fsf_req ,
SBAL_FLAGS0_TYPE_WRITE_READ ,
els - > req , els - > req_count ,
ZFCP_MAX_SBALS_PER_ELS_REQ ) ;
if ( bytes < = 0 ) {
ZFCP_LOG_INFO ( " error: creation of ELS request failed "
2007-05-08 13:14:41 +04:00
" (adapter %s, port d_id: 0x%06x) \n " ,
2005-04-17 02:20:36 +04:00
zfcp_get_busid_by_adapter ( adapter ) , d_id ) ;
if ( bytes = = 0 ) {
ret = - ENOMEM ;
} else {
ret = bytes ;
}
goto failed_send ;
}
fsf_req - > qtcb - > bottom . support . req_buf_length = bytes ;
fsf_req - > sbale_curr = ZFCP_LAST_SBALE_PER_SBAL ;
bytes = zfcp_qdio_sbals_from_sg ( fsf_req ,
SBAL_FLAGS0_TYPE_WRITE_READ ,
els - > resp , els - > resp_count ,
ZFCP_MAX_SBALS_PER_ELS_REQ ) ;
if ( bytes < = 0 ) {
ZFCP_LOG_INFO ( " error: creation of ELS request failed "
2007-05-08 13:14:41 +04:00
" (adapter %s, port d_id: 0x%06x) \n " ,
2005-04-17 02:20:36 +04:00
zfcp_get_busid_by_adapter ( adapter ) , d_id ) ;
if ( bytes = = 0 ) {
ret = - ENOMEM ;
} else {
ret = bytes ;
}
goto failed_send ;
}
fsf_req - > qtcb - > bottom . support . resp_buf_length = bytes ;
} else {
/* reject request */
ZFCP_LOG_INFO ( " error: microcode does not support chained SBALs "
" , ELS request too big (adapter %s, "
2007-05-08 13:14:41 +04:00
" port d_id: 0x%06x) \n " ,
2005-04-17 02:20:36 +04:00
zfcp_get_busid_by_adapter ( adapter ) , d_id ) ;
ret = - EOPNOTSUPP ;
goto failed_send ;
}
/* settings in QTCB */
fsf_req - > qtcb - > bottom . support . d_id = d_id ;
2006-05-22 20:18:19 +04:00
fsf_req - > qtcb - > bottom . support . service_class =
ZFCP_FC_SERVICE_CLASS_DEFAULT ;
2005-04-17 02:20:36 +04:00
fsf_req - > qtcb - > bottom . support . timeout = ZFCP_ELS_TIMEOUT ;
2005-09-13 23:47:52 +04:00
fsf_req - > data = ( unsigned long ) els ;
2005-04-17 02:20:36 +04:00
sbale = zfcp_qdio_sbale_req ( fsf_req , fsf_req - > sbal_curr , 0 ) ;
2005-09-13 23:50:38 +04:00
zfcp_san_dbf_event_els_request ( fsf_req ) ;
2006-09-19 00:29:56 +04:00
zfcp_fsf_start_timer ( fsf_req , ZFCP_FSF_REQUEST_TIMEOUT ) ;
ret = zfcp_fsf_req_send ( fsf_req ) ;
2005-04-17 02:20:36 +04:00
if ( ret ) {
ZFCP_LOG_DEBUG ( " error: initiation of ELS request failed "
2007-05-08 13:14:41 +04:00
" (adapter %s, port d_id: 0x%06x) \n " ,
2005-04-17 02:20:36 +04:00
zfcp_get_busid_by_adapter ( adapter ) , d_id ) ;
goto failed_send ;
}
ZFCP_LOG_DEBUG ( " ELS request initiated (adapter %s, port d_id: "
2007-05-08 13:14:41 +04:00
" 0x%06x) \n " , zfcp_get_busid_by_adapter ( adapter ) , d_id ) ;
2005-04-17 02:20:36 +04:00
goto out ;
failed_send :
zfcp_fsf_req_free ( fsf_req ) ;
failed_req :
out :
write_unlock_irqrestore ( & adapter - > request_queue . queue_lock ,
lock_flags ) ;
return ret ;
}
/**
* zfcp_fsf_send_els_handler - handler for ELS commands
* @ fsf_req : pointer to struct zfcp_fsf_req
*
2005-09-13 23:47:52 +04:00
* Data specific for the ELS command is passed using
* fsf_req - > data . There we find the pointer to struct zfcp_send_els .
* Usually a specific handler for the ELS command is called which is
* found in this structure .
2005-04-17 02:20:36 +04:00
*/
static int zfcp_fsf_send_els_handler ( struct zfcp_fsf_req * fsf_req )
{
struct zfcp_adapter * adapter ;
struct zfcp_port * port ;
2005-09-19 18:56:17 +04:00
u32 d_id ;
2005-04-17 02:20:36 +04:00
struct fsf_qtcb_header * header ;
struct fsf_qtcb_bottom_support * bottom ;
struct zfcp_send_els * send_els ;
int retval = - EINVAL ;
u16 subtable , rule , counter ;
2005-09-13 23:47:52 +04:00
send_els = ( struct zfcp_send_els * ) fsf_req - > data ;
2005-04-17 02:20:36 +04:00
adapter = send_els - > adapter ;
2005-06-13 15:18:56 +04:00
port = send_els - > port ;
2005-04-17 02:20:36 +04:00
d_id = send_els - > d_id ;
header = & fsf_req - > qtcb - > header ;
bottom = & fsf_req - > qtcb - > bottom . support ;
if ( fsf_req - > status & ZFCP_STATUS_FSFREQ_ERROR )
goto skip_fsfstatus ;
switch ( header - > fsf_status ) {
case FSF_GOOD :
2005-09-13 23:50:38 +04:00
zfcp_san_dbf_event_els_response ( fsf_req ) ;
2005-04-17 02:20:36 +04:00
retval = 0 ;
break ;
case FSF_SERVICE_CLASS_NOT_SUPPORTED :
2006-05-22 20:18:19 +04:00
ZFCP_LOG_INFO ( " error: adapter %s does not support fc "
" class %d. \n " ,
zfcp_get_busid_by_adapter ( adapter ) ,
ZFCP_FC_SERVICE_CLASS_DEFAULT ) ;
2005-04-17 02:20:36 +04:00
/* stop operation for this adapter */
debug_text_exception ( adapter - > erp_dbf , 0 , " fsf_s_class_nsup " ) ;
zfcp_erp_adapter_shutdown ( adapter , 0 ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_ADAPTER_STATUS_AVAILABLE :
switch ( header - > fsf_status_qual . word [ 0 ] ) {
case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE :
debug_text_event ( adapter - > erp_dbf , 1 , " fsf_sq_ltest " ) ;
2005-06-13 15:18:56 +04:00
if ( port & & ( send_els - > ls_code ! = ZFCP_LS_ADISC ) )
zfcp_test_link ( port ) ;
2005-04-17 02:20:36 +04:00
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED :
debug_text_event ( adapter - > erp_dbf , 1 , " fsf_sq_ulp " ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
retval =
zfcp_handle_els_rjt ( header - > fsf_status_qual . word [ 1 ] ,
( struct zfcp_ls_rjt_par * )
& header - > fsf_status_qual . word [ 2 ] ) ;
break ;
case FSF_SQ_RETRY_IF_POSSIBLE :
debug_text_event ( adapter - > erp_dbf , 1 , " fsf_sq_retry " ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
default :
ZFCP_LOG_INFO ( " bug: Wrong status qualifier 0x%x \n " ,
header - > fsf_status_qual . word [ 0 ] ) ;
ZFCP_HEX_DUMP ( ZFCP_LOG_LEVEL_INFO ,
( char * ) header - > fsf_status_qual . word , 16 ) ;
}
break ;
case FSF_ELS_COMMAND_REJECTED :
ZFCP_LOG_INFO ( " ELS has been rejected because command filter "
" prohibited sending "
2007-05-08 13:14:41 +04:00
" (adapter: %s, port d_id: 0x%06x) \n " ,
2005-04-17 02:20:36 +04:00
zfcp_get_busid_by_adapter ( adapter ) , d_id ) ;
break ;
case FSF_PAYLOAD_SIZE_MISMATCH :
ZFCP_LOG_INFO (
" ELS request size and ELS response size must be either "
" both 0, or both greater than 0 "
" (adapter: %s, req_buf_length=%d resp_buf_length=%d) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ,
bottom - > req_buf_length ,
bottom - > resp_buf_length ) ;
break ;
case FSF_REQUEST_SIZE_TOO_LARGE :
ZFCP_LOG_INFO (
" Length of the ELS request buffer, "
" specified in QTCB bottom, "
" exceeds the size of the buffers "
" that have been allocated for ELS request data "
" (adapter: %s, req_buf_length=%d) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ,
bottom - > req_buf_length ) ;
break ;
case FSF_RESPONSE_SIZE_TOO_LARGE :
ZFCP_LOG_INFO (
" Length of the ELS response buffer, "
" specified in QTCB bottom, "
" exceeds the size of the buffers "
" that have been allocated for ELS response data "
" (adapter: %s, resp_buf_length=%d) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ,
bottom - > resp_buf_length ) ;
break ;
case FSF_SBAL_MISMATCH :
/* should never occure, avoided in zfcp_fsf_send_els */
ZFCP_LOG_INFO ( " SBAL mismatch (adapter: %s, req_buf_length=%d, "
" resp_buf_length=%d) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ,
bottom - > req_buf_length , bottom - > resp_buf_length ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_ACCESS_DENIED :
ZFCP_LOG_NORMAL ( " access denied, cannot send ELS command "
2007-05-08 13:14:41 +04:00
" (adapter %s, port d_id=0x%06x) \n " ,
2005-04-17 02:20:36 +04:00
zfcp_get_busid_by_adapter ( adapter ) , d_id ) ;
for ( counter = 0 ; counter < 2 ; counter + + ) {
subtable = header - > fsf_status_qual . halfword [ counter * 2 ] ;
rule = header - > fsf_status_qual . halfword [ counter * 2 + 1 ] ;
switch ( subtable ) {
case FSF_SQ_CFDC_SUBTABLE_OS :
case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN :
case FSF_SQ_CFDC_SUBTABLE_PORT_DID :
case FSF_SQ_CFDC_SUBTABLE_LUN :
ZFCP_LOG_INFO ( " Access denied (%s rule %d) \n " ,
zfcp_act_subtable_type [ subtable ] , rule ) ;
break ;
}
}
debug_text_event ( adapter - > erp_dbf , 1 , " fsf_s_access " ) ;
if ( port ! = NULL )
zfcp_erp_port_access_denied ( port ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
default :
ZFCP_LOG_NORMAL (
" bug: An unknown FSF Status was presented "
" (adapter: %s, fsf_status=0x%08x) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ,
header - > fsf_status ) ;
debug_text_event ( adapter - > erp_dbf , 0 , " fsf_sq_inval " ) ;
debug_exception ( adapter - > erp_dbf , 0 ,
& header - > fsf_status_qual . word [ 0 ] , sizeof ( u32 ) ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
}
skip_fsfstatus :
send_els - > status = retval ;
2007-07-18 12:55:10 +04:00
if ( send_els - > handler )
2005-04-17 02:20:36 +04:00
send_els - > handler ( send_els - > handler_data ) ;
return retval ;
}
int
zfcp_fsf_exchange_config_data ( struct zfcp_erp_action * erp_action )
{
volatile struct qdio_buffer_element * sbale ;
2006-09-19 00:29:56 +04:00
struct zfcp_fsf_req * fsf_req ;
2005-04-17 02:20:36 +04:00
unsigned long lock_flags ;
int retval = 0 ;
/* setup new FSF request */
retval = zfcp_fsf_req_create ( erp_action - > adapter ,
FSF_QTCB_EXCHANGE_CONFIG_DATA ,
ZFCP_REQ_AUTO_CLEANUP ,
erp_action - > adapter - > pool . fsf_req_erp ,
2006-09-19 00:29:56 +04:00
& lock_flags , & fsf_req ) ;
2005-04-17 02:20:36 +04:00
if ( retval < 0 ) {
ZFCP_LOG_INFO ( " error: Could not create exchange configuration "
" data request for adapter %s. \n " ,
zfcp_get_busid_by_adapter ( erp_action - > adapter ) ) ;
goto out ;
}
2006-09-19 00:29:56 +04:00
sbale = zfcp_qdio_sbale_req ( fsf_req , fsf_req - > sbal_curr , 0 ) ;
2005-04-17 02:20:36 +04:00
sbale [ 0 ] . flags | = SBAL_FLAGS0_TYPE_READ ;
sbale [ 1 ] . flags | = SBAL_FLAGS_LAST_ENTRY ;
2006-09-19 00:29:56 +04:00
fsf_req - > qtcb - > bottom . config . feature_selection =
2005-09-13 23:51:16 +04:00
FSF_FEATURE_CFDC |
FSF_FEATURE_LUN_SHARING |
2006-01-05 11:56:47 +03:00
FSF_FEATURE_NOTIFICATION_LOST |
2005-09-13 23:51:16 +04:00
FSF_FEATURE_UPDATE_ALERT ;
2006-09-19 00:29:56 +04:00
fsf_req - > erp_action = erp_action ;
erp_action - > fsf_req = fsf_req ;
2005-04-17 02:20:36 +04:00
2006-09-19 00:29:56 +04:00
zfcp_erp_start_timer ( fsf_req ) ;
retval = zfcp_fsf_req_send ( fsf_req ) ;
2005-04-17 02:20:36 +04:00
if ( retval ) {
ZFCP_LOG_INFO
( " error: Could not send exchange configuration data "
" command on the adapter %s \n " ,
zfcp_get_busid_by_adapter ( erp_action - > adapter ) ) ;
2006-09-19 00:29:56 +04:00
zfcp_fsf_req_free ( fsf_req ) ;
2005-04-17 02:20:36 +04:00
erp_action - > fsf_req = NULL ;
goto out ;
}
ZFCP_LOG_DEBUG ( " exchange configuration data request initiated "
" (adapter %s) \n " ,
zfcp_get_busid_by_adapter ( erp_action - > adapter ) ) ;
out :
write_unlock_irqrestore ( & erp_action - > adapter - > request_queue . queue_lock ,
lock_flags ) ;
return retval ;
}
/**
* zfcp_fsf_exchange_config_evaluate
* @ fsf_req : fsf_req which belongs to xchg config data request
* @ xchg_ok : specifies if xchg config data was incomplete or complete ( 0 / 1 )
*
* returns : - EIO on error , 0 otherwise
*/
static int
zfcp_fsf_exchange_config_evaluate ( struct zfcp_fsf_req * fsf_req , int xchg_ok )
{
struct fsf_qtcb_bottom_config * bottom ;
struct zfcp_adapter * adapter = fsf_req - > adapter ;
2005-09-19 18:56:17 +04:00
struct Scsi_Host * shost = adapter - > scsi_host ;
2005-04-17 02:20:36 +04:00
bottom = & fsf_req - > qtcb - > bottom . config ;
ZFCP_LOG_DEBUG ( " low/high QTCB version 0x%x/0x%x of FSF \n " ,
bottom - > low_qtcb_version , bottom - > high_qtcb_version ) ;
adapter - > fsf_lic_version = bottom - > lic_version ;
2005-09-13 23:51:16 +04:00
adapter - > adapter_features = bottom - > adapter_features ;
adapter - > connection_features = bottom - > connection_features ;
2005-04-11 08:04:28 +04:00
adapter - > peer_wwpn = 0 ;
adapter - > peer_wwnn = 0 ;
adapter - > peer_d_id = 0 ;
2005-04-17 02:20:36 +04:00
if ( xchg_ok ) {
2005-09-19 18:56:17 +04:00
fc_host_node_name ( shost ) = bottom - > nport_serv_param . wwnn ;
fc_host_port_name ( shost ) = bottom - > nport_serv_param . wwpn ;
fc_host_port_id ( shost ) = bottom - > s_id & ZFCP_DID_MASK ;
fc_host_speed ( shost ) = bottom - > fc_link_speed ;
fc_host_supported_classes ( shost ) = FC_COS_CLASS2 | FC_COS_CLASS3 ;
2005-04-17 02:20:36 +04:00
adapter - > hydra_version = bottom - > adapter_type ;
2006-01-13 04:26:11 +03:00
if ( fc_host_permanent_port_name ( shost ) = = - 1 )
fc_host_permanent_port_name ( shost ) =
fc_host_port_name ( shost ) ;
if ( bottom - > fc_topology = = FSF_TOPO_P2P ) {
adapter - > peer_d_id = bottom - > peer_d_id & ZFCP_DID_MASK ;
adapter - > peer_wwpn = bottom - > plogi_payload . wwpn ;
adapter - > peer_wwnn = bottom - > plogi_payload . wwnn ;
fc_host_port_type ( shost ) = FC_PORTTYPE_PTP ;
} else if ( bottom - > fc_topology = = FSF_TOPO_FABRIC )
fc_host_port_type ( shost ) = FC_PORTTYPE_NPORT ;
else if ( bottom - > fc_topology = = FSF_TOPO_AL )
fc_host_port_type ( shost ) = FC_PORTTYPE_NLPORT ;
else
fc_host_port_type ( shost ) = FC_PORTTYPE_UNKNOWN ;
2005-04-17 02:20:36 +04:00
} else {
2005-09-19 18:56:17 +04:00
fc_host_node_name ( shost ) = 0 ;
fc_host_port_name ( shost ) = 0 ;
fc_host_port_id ( shost ) = 0 ;
fc_host_speed ( shost ) = FC_PORTSPEED_UNKNOWN ;
2006-01-13 04:26:11 +03:00
fc_host_port_type ( shost ) = FC_PORTTYPE_UNKNOWN ;
2005-04-17 02:20:36 +04:00
adapter - > hydra_version = 0 ;
}
2005-09-13 23:51:16 +04:00
if ( adapter - > adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT ) {
2005-04-17 02:20:36 +04:00
adapter - > hardware_version = bottom - > hardware_version ;
2005-09-19 18:56:17 +04:00
memcpy ( fc_host_serial_number ( shost ) , bottom - > serial_number ,
min ( FC_SERIAL_NUMBER_SIZE , 17 ) ) ;
EBCASC ( fc_host_serial_number ( shost ) ,
min ( FC_SERIAL_NUMBER_SIZE , 17 ) ) ;
2005-04-17 02:20:36 +04:00
}
2005-04-11 08:04:28 +04:00
ZFCP_LOG_NORMAL ( " The adapter %s reported the following characteristics: \n "
2005-09-19 18:56:17 +04:00
" WWNN 0x%016Lx, "
" WWPN 0x%016Lx, "
2007-05-08 13:14:41 +04:00
" S_ID 0x%06x, \n "
2005-09-19 18:56:17 +04:00
" adapter version 0x%x, "
" LIC version 0x%x, "
" FC link speed %d Gb/s \n " ,
zfcp_get_busid_by_adapter ( adapter ) ,
( wwn_t ) fc_host_node_name ( shost ) ,
( wwn_t ) fc_host_port_name ( shost ) ,
fc_host_port_id ( shost ) ,
adapter - > hydra_version ,
adapter - > fsf_lic_version ,
fc_host_speed ( shost ) ) ;
2005-04-17 02:20:36 +04:00
if ( ZFCP_QTCB_VERSION < bottom - > low_qtcb_version ) {
ZFCP_LOG_NORMAL ( " error: the adapter %s "
" only supports newer control block "
" versions in comparison to this device "
" driver (try updated device driver) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
debug_text_event ( adapter - > erp_dbf , 0 , " low_qtcb_ver " ) ;
zfcp_erp_adapter_shutdown ( adapter , 0 ) ;
return - EIO ;
}
if ( ZFCP_QTCB_VERSION > bottom - > high_qtcb_version ) {
ZFCP_LOG_NORMAL ( " error: the adapter %s "
" only supports older control block "
" versions than this device driver uses "
" (consider a microcode upgrade) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
debug_text_event ( adapter - > erp_dbf , 0 , " high_qtcb_ver " ) ;
zfcp_erp_adapter_shutdown ( adapter , 0 ) ;
return - EIO ;
}
return 0 ;
}
/*
* function : zfcp_fsf_exchange_config_data_handler
*
* purpose : is called for finished Exchange Configuration Data command
*
* returns :
*/
static int
zfcp_fsf_exchange_config_data_handler ( struct zfcp_fsf_req * fsf_req )
{
struct fsf_qtcb_bottom_config * bottom ;
struct zfcp_adapter * adapter = fsf_req - > adapter ;
2005-09-13 23:51:16 +04:00
struct fsf_qtcb * qtcb = fsf_req - > qtcb ;
2005-04-17 02:20:36 +04:00
if ( fsf_req - > status & ZFCP_STATUS_FSFREQ_ERROR )
return - EIO ;
2005-09-13 23:51:16 +04:00
switch ( qtcb - > header . fsf_status ) {
2005-04-17 02:20:36 +04:00
case FSF_GOOD :
if ( zfcp_fsf_exchange_config_evaluate ( fsf_req , 1 ) )
return - EIO ;
2006-01-13 04:26:11 +03:00
switch ( fc_host_port_type ( adapter - > scsi_host ) ) {
case FC_PORTTYPE_PTP :
2005-04-11 08:04:28 +04:00
ZFCP_LOG_NORMAL ( " Point-to-Point fibrechannel "
" configuration detected at adapter %s \n "
" Peer WWNN 0x%016llx, "
" peer WWPN 0x%016llx, "
" peer d_id 0x%06x \n " ,
zfcp_get_busid_by_adapter ( adapter ) ,
adapter - > peer_wwnn ,
adapter - > peer_wwpn ,
adapter - > peer_d_id ) ;
2005-04-17 02:20:36 +04:00
debug_text_event ( fsf_req - > adapter - > erp_dbf , 0 ,
" top-p-to-p " ) ;
2005-04-11 08:04:28 +04:00
break ;
2006-01-13 04:26:11 +03:00
case FC_PORTTYPE_NLPORT :
2005-04-17 02:20:36 +04:00
ZFCP_LOG_NORMAL ( " error: Arbitrated loop fibrechannel "
" topology detected at adapter %s "
" unsupported, shutting down adapter \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
debug_text_event ( fsf_req - > adapter - > erp_dbf , 0 ,
" top-al " ) ;
zfcp_erp_adapter_shutdown ( adapter , 0 ) ;
return - EIO ;
2006-01-13 04:26:11 +03:00
case FC_PORTTYPE_NPORT :
2005-09-13 23:51:16 +04:00
ZFCP_LOG_NORMAL ( " Switched fabric fibrechannel "
2005-04-17 02:20:36 +04:00
" network detected at adapter %s. \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
break ;
default :
ZFCP_LOG_NORMAL ( " bug: The fibrechannel topology "
" reported by the exchange "
" configuration command for "
" the adapter %s is not "
" of a type known to the zfcp "
" driver, shutting down adapter \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
debug_text_exception ( fsf_req - > adapter - > erp_dbf , 0 ,
" unknown-topo " ) ;
zfcp_erp_adapter_shutdown ( adapter , 0 ) ;
return - EIO ;
}
2005-09-13 23:51:16 +04:00
bottom = & qtcb - > bottom . config ;
2005-04-17 02:20:36 +04:00
if ( bottom - > max_qtcb_size < sizeof ( struct fsf_qtcb ) ) {
ZFCP_LOG_NORMAL ( " bug: Maximum QTCB size (%d bytes) "
" allowed by the adapter %s "
" is lower than the minimum "
" required by the driver (%ld bytes). \n " ,
bottom - > max_qtcb_size ,
zfcp_get_busid_by_adapter ( adapter ) ,
sizeof ( struct fsf_qtcb ) ) ;
debug_text_event ( fsf_req - > adapter - > erp_dbf , 0 ,
" qtcb-size " ) ;
debug_event ( fsf_req - > adapter - > erp_dbf , 0 ,
& bottom - > max_qtcb_size , sizeof ( u32 ) ) ;
zfcp_erp_adapter_shutdown ( adapter , 0 ) ;
return - EIO ;
}
atomic_set_mask ( ZFCP_STATUS_ADAPTER_XCONFIG_OK ,
& adapter - > status ) ;
break ;
case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE :
debug_text_event ( adapter - > erp_dbf , 0 , " xchg-inco " ) ;
if ( zfcp_fsf_exchange_config_evaluate ( fsf_req , 0 ) )
return - EIO ;
2005-09-13 23:51:16 +04:00
atomic_set_mask ( ZFCP_STATUS_ADAPTER_XCONFIG_OK , & adapter - > status ) ;
zfcp_fsf_link_down_info_eval ( adapter ,
& qtcb - > header . fsf_status_qual . link_down_info ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
debug_text_event ( fsf_req - > adapter - > erp_dbf , 0 , " fsf-stat-ng " ) ;
debug_event ( fsf_req - > adapter - > erp_dbf , 0 ,
& fsf_req - > qtcb - > header . fsf_status , sizeof ( u32 ) ) ;
zfcp_erp_adapter_shutdown ( adapter , 0 ) ;
return - EIO ;
}
return 0 ;
}
/**
* zfcp_fsf_exchange_port_data - request information about local port
2005-09-13 23:51:16 +04:00
* @ erp_action : ERP action for the adapter for which port data is requested
2005-04-17 02:20:36 +04:00
* @ adapter : for which port data is requested
* @ data : response to exchange port data request
*/
int
2005-09-13 23:51:16 +04:00
zfcp_fsf_exchange_port_data ( struct zfcp_erp_action * erp_action ,
struct zfcp_adapter * adapter ,
2005-04-17 02:20:36 +04:00
struct fsf_qtcb_bottom_port * data )
{
volatile struct qdio_buffer_element * sbale ;
struct zfcp_fsf_req * fsf_req ;
2006-09-19 00:29:56 +04:00
unsigned long lock_flags ;
int retval = 0 ;
2005-04-17 02:20:36 +04:00
2005-09-13 23:51:16 +04:00
if ( ! ( adapter - > adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT ) ) {
2005-04-17 02:20:36 +04:00
ZFCP_LOG_INFO ( " error: exchange port data "
" command not supported by adapter %s \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
return - EOPNOTSUPP ;
}
/* setup new FSF request */
retval = zfcp_fsf_req_create ( adapter , FSF_QTCB_EXCHANGE_PORT_DATA ,
2005-12-01 04:50:36 +03:00
erp_action ? ZFCP_REQ_AUTO_CLEANUP : 0 ,
2006-07-12 18:41:55 +04:00
NULL , & lock_flags , & fsf_req ) ;
2005-04-17 02:20:36 +04:00
if ( retval < 0 ) {
ZFCP_LOG_INFO ( " error: Out of resources. Could not create an "
" exchange port data request for "
" the adapter %s. \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
write_unlock_irqrestore ( & adapter - > request_queue . queue_lock ,
lock_flags ) ;
2005-12-01 04:50:36 +03:00
return retval ;
2005-09-13 23:51:16 +04:00
}
if ( data )
2005-12-01 04:50:36 +03:00
fsf_req - > data = ( unsigned long ) data ;
2005-09-13 23:47:52 +04:00
2005-04-17 02:20:36 +04:00
sbale = zfcp_qdio_sbale_req ( fsf_req , fsf_req - > sbal_curr , 0 ) ;
sbale [ 0 ] . flags | = SBAL_FLAGS0_TYPE_READ ;
sbale [ 1 ] . flags | = SBAL_FLAGS_LAST_ENTRY ;
2005-12-01 04:50:36 +03:00
if ( erp_action ) {
erp_action - > fsf_req = fsf_req ;
fsf_req - > erp_action = erp_action ;
2006-09-19 00:29:56 +04:00
zfcp_erp_start_timer ( fsf_req ) ;
} else
zfcp_fsf_start_timer ( fsf_req , ZFCP_FSF_REQUEST_TIMEOUT ) ;
2005-04-17 02:20:36 +04:00
2006-09-19 00:29:56 +04:00
retval = zfcp_fsf_req_send ( fsf_req ) ;
2005-04-17 02:20:36 +04:00
if ( retval ) {
ZFCP_LOG_INFO ( " error: Could not send an exchange port data "
" command on the adapter %s \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
zfcp_fsf_req_free ( fsf_req ) ;
2005-09-13 23:51:16 +04:00
if ( erp_action )
erp_action - > fsf_req = NULL ;
2005-04-17 02:20:36 +04:00
write_unlock_irqrestore ( & adapter - > request_queue . queue_lock ,
lock_flags ) ;
2005-12-01 04:50:36 +03:00
return retval ;
2005-04-17 02:20:36 +04:00
}
2005-12-01 04:50:36 +03:00
write_unlock_irqrestore ( & adapter - > request_queue . queue_lock , lock_flags ) ;
2005-04-17 02:20:36 +04:00
2005-12-01 04:50:36 +03:00
if ( ! erp_action ) {
wait_event ( fsf_req - > completion_wq ,
fsf_req - > status & ZFCP_STATUS_FSFREQ_COMPLETED ) ;
zfcp_fsf_req_free ( fsf_req ) ;
}
2005-04-17 02:20:36 +04:00
return retval ;
}
2006-02-11 03:41:50 +03:00
/**
* zfcp_fsf_exchange_port_evaluate
* @ fsf_req : fsf_req which belongs to xchg port data request
* @ xchg_ok : specifies if xchg port data was incomplete or complete ( 0 / 1 )
*/
static void
zfcp_fsf_exchange_port_evaluate ( struct zfcp_fsf_req * fsf_req , int xchg_ok )
{
struct zfcp_adapter * adapter ;
struct fsf_qtcb * qtcb ;
struct fsf_qtcb_bottom_port * bottom , * data ;
struct Scsi_Host * shost ;
adapter = fsf_req - > adapter ;
qtcb = fsf_req - > qtcb ;
bottom = & qtcb - > bottom . port ;
shost = adapter - > scsi_host ;
data = ( struct fsf_qtcb_bottom_port * ) fsf_req - > data ;
if ( data )
memcpy ( data , bottom , sizeof ( struct fsf_qtcb_bottom_port ) ) ;
if ( adapter - > connection_features & FSF_FEATURE_NPIV_MODE )
fc_host_permanent_port_name ( shost ) = bottom - > wwpn ;
else
fc_host_permanent_port_name ( shost ) = fc_host_port_name ( shost ) ;
fc_host_maxframe_size ( shost ) = bottom - > maximum_frame_size ;
fc_host_supported_speeds ( shost ) = bottom - > supported_speed ;
}
2005-04-17 02:20:36 +04:00
/**
* zfcp_fsf_exchange_port_data_handler - handler for exchange_port_data request
* @ fsf_req : pointer to struct zfcp_fsf_req
*/
static void
zfcp_fsf_exchange_port_data_handler ( struct zfcp_fsf_req * fsf_req )
{
2006-02-11 03:41:50 +03:00
struct zfcp_adapter * adapter ;
struct fsf_qtcb * qtcb ;
adapter = fsf_req - > adapter ;
qtcb = fsf_req - > qtcb ;
2005-04-17 02:20:36 +04:00
if ( fsf_req - > status & ZFCP_STATUS_FSFREQ_ERROR )
return ;
2005-09-13 23:51:16 +04:00
switch ( qtcb - > header . fsf_status ) {
2005-04-17 02:20:36 +04:00
case FSF_GOOD :
2006-02-11 03:41:50 +03:00
zfcp_fsf_exchange_port_evaluate ( fsf_req , 1 ) ;
2005-09-13 23:51:16 +04:00
atomic_set_mask ( ZFCP_STATUS_ADAPTER_XPORT_OK , & adapter - > status ) ;
break ;
case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE :
2006-02-11 03:41:50 +03:00
zfcp_fsf_exchange_port_evaluate ( fsf_req , 0 ) ;
2005-09-13 23:51:16 +04:00
atomic_set_mask ( ZFCP_STATUS_ADAPTER_XPORT_OK , & adapter - > status ) ;
zfcp_fsf_link_down_info_eval ( adapter ,
& qtcb - > header . fsf_status_qual . link_down_info ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
2005-09-13 23:51:16 +04:00
debug_text_event ( adapter - > erp_dbf , 0 , " xchg-port-ng " ) ;
debug_event ( adapter - > erp_dbf , 0 ,
2005-04-17 02:20:36 +04:00
& fsf_req - > qtcb - > header . fsf_status , sizeof ( u32 ) ) ;
}
}
/*
* function : zfcp_fsf_open_port
*
* purpose :
*
* returns : address of initiated FSF request
* NULL - request could not be initiated
*/
int
zfcp_fsf_open_port ( struct zfcp_erp_action * erp_action )
{
volatile struct qdio_buffer_element * sbale ;
2006-09-19 00:29:56 +04:00
struct zfcp_fsf_req * fsf_req ;
2005-04-17 02:20:36 +04:00
unsigned long lock_flags ;
int retval = 0 ;
/* setup new FSF request */
retval = zfcp_fsf_req_create ( erp_action - > adapter ,
FSF_QTCB_OPEN_PORT_WITH_DID ,
ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP ,
erp_action - > adapter - > pool . fsf_req_erp ,
2006-09-19 00:29:56 +04:00
& lock_flags , & fsf_req ) ;
2005-04-17 02:20:36 +04:00
if ( retval < 0 ) {
ZFCP_LOG_INFO ( " error: Could not create open port request "
" for port 0x%016Lx on adapter %s. \n " ,
erp_action - > port - > wwpn ,
zfcp_get_busid_by_adapter ( erp_action - > adapter ) ) ;
goto out ;
}
2006-09-19 00:29:56 +04:00
sbale = zfcp_qdio_sbale_req ( fsf_req , fsf_req - > sbal_curr , 0 ) ;
2005-04-17 02:20:36 +04:00
sbale [ 0 ] . flags | = SBAL_FLAGS0_TYPE_READ ;
sbale [ 1 ] . flags | = SBAL_FLAGS_LAST_ENTRY ;
2006-09-19 00:29:56 +04:00
fsf_req - > qtcb - > bottom . support . d_id = erp_action - > port - > d_id ;
2005-04-17 02:20:36 +04:00
atomic_set_mask ( ZFCP_STATUS_COMMON_OPENING , & erp_action - > port - > status ) ;
2006-09-19 00:29:56 +04:00
fsf_req - > data = ( unsigned long ) erp_action - > port ;
fsf_req - > erp_action = erp_action ;
erp_action - > fsf_req = fsf_req ;
2005-04-17 02:20:36 +04:00
2006-09-19 00:29:56 +04:00
zfcp_erp_start_timer ( fsf_req ) ;
retval = zfcp_fsf_req_send ( fsf_req ) ;
2005-04-17 02:20:36 +04:00
if ( retval ) {
ZFCP_LOG_INFO ( " error: Could not send open port request for "
" port 0x%016Lx on adapter %s. \n " ,
erp_action - > port - > wwpn ,
zfcp_get_busid_by_adapter ( erp_action - > adapter ) ) ;
2006-09-19 00:29:56 +04:00
zfcp_fsf_req_free ( fsf_req ) ;
2005-04-17 02:20:36 +04:00
erp_action - > fsf_req = NULL ;
goto out ;
}
ZFCP_LOG_DEBUG ( " open port request initiated "
" (adapter %s, port 0x%016Lx) \n " ,
zfcp_get_busid_by_adapter ( erp_action - > adapter ) ,
erp_action - > port - > wwpn ) ;
out :
write_unlock_irqrestore ( & erp_action - > adapter - > request_queue . queue_lock ,
lock_flags ) ;
return retval ;
}
/*
* function : zfcp_fsf_open_port_handler
*
* purpose : is called for finished Open Port command
*
* returns :
*/
static int
zfcp_fsf_open_port_handler ( struct zfcp_fsf_req * fsf_req )
{
int retval = - EINVAL ;
struct zfcp_port * port ;
struct fsf_plogi * plogi ;
struct fsf_qtcb_header * header ;
u16 subtable , rule , counter ;
2005-09-13 23:47:52 +04:00
port = ( struct zfcp_port * ) fsf_req - > data ;
2005-04-17 02:20:36 +04:00
header = & fsf_req - > qtcb - > header ;
if ( fsf_req - > status & ZFCP_STATUS_FSFREQ_ERROR ) {
/* don't change port status in our bookkeeping */
goto skip_fsfstatus ;
}
/* evaluate FSF status in QTCB */
switch ( header - > fsf_status ) {
case FSF_PORT_ALREADY_OPEN :
ZFCP_LOG_NORMAL ( " bug: remote port 0x%016Lx on adapter %s "
" is already open. \n " ,
port - > wwpn , zfcp_get_busid_by_port ( port ) ) ;
debug_text_exception ( fsf_req - > adapter - > erp_dbf , 0 ,
" fsf_s_popen " ) ;
/*
* This is a bug , however operation should continue normally
* if it is simply ignored
*/
break ;
case FSF_ACCESS_DENIED :
ZFCP_LOG_NORMAL ( " Access denied, cannot open port 0x%016Lx "
" on adapter %s \n " ,
port - > wwpn , zfcp_get_busid_by_port ( port ) ) ;
for ( counter = 0 ; counter < 2 ; counter + + ) {
subtable = header - > fsf_status_qual . halfword [ counter * 2 ] ;
rule = header - > fsf_status_qual . halfword [ counter * 2 + 1 ] ;
switch ( subtable ) {
case FSF_SQ_CFDC_SUBTABLE_OS :
case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN :
case FSF_SQ_CFDC_SUBTABLE_PORT_DID :
case FSF_SQ_CFDC_SUBTABLE_LUN :
ZFCP_LOG_INFO ( " Access denied (%s rule %d) \n " ,
zfcp_act_subtable_type [ subtable ] , rule ) ;
break ;
}
}
debug_text_event ( fsf_req - > adapter - > erp_dbf , 1 , " fsf_s_access " ) ;
zfcp_erp_port_access_denied ( port ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED :
ZFCP_LOG_INFO ( " error: The FSF adapter is out of resources. "
" The remote port 0x%016Lx on adapter %s "
" could not be opened. Disabling it. \n " ,
port - > wwpn , zfcp_get_busid_by_port ( port ) ) ;
debug_text_event ( fsf_req - > adapter - > erp_dbf , 1 ,
" fsf_s_max_ports " ) ;
zfcp_erp_port_failed ( port ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_ADAPTER_STATUS_AVAILABLE :
switch ( header - > fsf_status_qual . word [ 0 ] ) {
case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE :
debug_text_event ( fsf_req - > adapter - > erp_dbf , 1 ,
" fsf_sq_ltest " ) ;
/* ERP strategy will escalate */
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED :
/* ERP strategy will escalate */
debug_text_event ( fsf_req - > adapter - > erp_dbf , 1 ,
" fsf_sq_ulp " ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_SQ_NO_RETRY_POSSIBLE :
ZFCP_LOG_NORMAL ( " The remote port 0x%016Lx on "
" adapter %s could not be opened. "
" Disabling it. \n " ,
port - > wwpn ,
zfcp_get_busid_by_port ( port ) ) ;
debug_text_exception ( fsf_req - > adapter - > erp_dbf , 0 ,
" fsf_sq_no_retry " ) ;
zfcp_erp_port_failed ( port ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
default :
ZFCP_LOG_NORMAL
( " bug: Wrong status qualifier 0x%x arrived. \n " ,
header - > fsf_status_qual . word [ 0 ] ) ;
debug_text_event ( fsf_req - > adapter - > erp_dbf , 0 ,
" fsf_sq_inval: " ) ;
debug_exception (
fsf_req - > adapter - > erp_dbf , 0 ,
& header - > fsf_status_qual . word [ 0 ] ,
sizeof ( u32 ) ) ;
break ;
}
break ;
case FSF_GOOD :
/* save port handle assigned by FSF */
port - > handle = header - > port_handle ;
ZFCP_LOG_INFO ( " The remote port 0x%016Lx via adapter %s "
" was opened, it's port handle is 0x%x \n " ,
port - > wwpn , zfcp_get_busid_by_port ( port ) ,
port - > handle ) ;
/* mark port as open */
atomic_set_mask ( ZFCP_STATUS_COMMON_OPEN |
ZFCP_STATUS_PORT_PHYS_OPEN , & port - > status ) ;
2005-06-13 15:23:57 +04:00
atomic_clear_mask ( ZFCP_STATUS_COMMON_ACCESS_DENIED |
ZFCP_STATUS_COMMON_ACCESS_BOXED ,
& port - > status ) ;
2005-04-17 02:20:36 +04:00
retval = 0 ;
/* check whether D_ID has changed during open */
/*
* FIXME : This check is not airtight , as the FCP channel does
* not monitor closures of target port connections caused on
* the remote side . Thus , they might miss out on invalidating
* locally cached WWPNs ( and other N_Port parameters ) of gone
* target ports . So , our heroic attempt to make things safe
* could be undermined by ' open port ' response data tagged with
* obsolete WWPNs . Another reason to monitor potential
* connection closures ourself at least ( by interpreting
* incoming ELS ' and unsolicited status ) . It just crosses my
* mind that one should be able to cross - check by means of
* another GID_PN straight after a port has been opened .
* Alternately , an ADISC / PDISC ELS should suffice , as well .
*/
plogi = ( struct fsf_plogi * ) fsf_req - > qtcb - > bottom . support . els ;
if ( ! atomic_test_mask ( ZFCP_STATUS_PORT_NO_WWPN , & port - > status ) )
{
if ( fsf_req - > qtcb - > bottom . support . els1_length <
2006-05-22 20:24:33 +04:00
sizeof ( struct fsf_plogi ) ) {
2005-04-17 02:20:36 +04:00
ZFCP_LOG_INFO (
" warning: insufficient length of "
" PLOGI payload (%i) \n " ,
fsf_req - > qtcb - > bottom . support . els1_length ) ;
debug_text_event ( fsf_req - > adapter - > erp_dbf , 0 ,
" fsf_s_short_plogi: " ) ;
/* skip sanity check and assume wwpn is ok */
} else {
if ( plogi - > serv_param . wwpn ! = port - > wwpn ) {
ZFCP_LOG_INFO ( " warning: d_id of port "
" 0x%016Lx changed during "
" open \n " , port - > wwpn ) ;
debug_text_event (
fsf_req - > adapter - > erp_dbf , 0 ,
" fsf_s_did_change: " ) ;
atomic_clear_mask (
ZFCP_STATUS_PORT_DID_DID ,
& port - > status ) ;
2006-05-22 20:24:33 +04:00
} else {
2005-04-17 02:20:36 +04:00
port - > wwnn = plogi - > serv_param . wwnn ;
2006-05-22 20:24:33 +04:00
zfcp_plogi_evaluate ( port , plogi ) ;
}
2005-04-17 02:20:36 +04:00
}
}
break ;
case FSF_UNKNOWN_OP_SUBTYPE :
/* should never occure, subtype not set in zfcp_fsf_open_port */
ZFCP_LOG_INFO ( " unknown operation subtype (adapter: %s, "
" op_subtype=0x%x) \n " ,
zfcp_get_busid_by_port ( port ) ,
fsf_req - > qtcb - > bottom . support . operation_subtype ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
default :
ZFCP_LOG_NORMAL ( " bug: An unknown FSF Status was presented "
" (debug info 0x%x) \n " ,
header - > fsf_status ) ;
debug_text_event ( fsf_req - > adapter - > erp_dbf , 0 , " fsf_s_inval: " ) ;
debug_exception ( fsf_req - > adapter - > erp_dbf , 0 ,
& header - > fsf_status , sizeof ( u32 ) ) ;
break ;
}
skip_fsfstatus :
atomic_clear_mask ( ZFCP_STATUS_COMMON_OPENING , & port - > status ) ;
return retval ;
}
/*
* function : zfcp_fsf_close_port
*
* purpose : submit FSF command " close port "
*
* returns : address of initiated FSF request
* NULL - request could not be initiated
*/
int
zfcp_fsf_close_port ( struct zfcp_erp_action * erp_action )
{
volatile struct qdio_buffer_element * sbale ;
2006-09-19 00:29:56 +04:00
struct zfcp_fsf_req * fsf_req ;
2005-04-17 02:20:36 +04:00
unsigned long lock_flags ;
int retval = 0 ;
/* setup new FSF request */
retval = zfcp_fsf_req_create ( erp_action - > adapter ,
FSF_QTCB_CLOSE_PORT ,
ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP ,
erp_action - > adapter - > pool . fsf_req_erp ,
2006-09-19 00:29:56 +04:00
& lock_flags , & fsf_req ) ;
2005-04-17 02:20:36 +04:00
if ( retval < 0 ) {
ZFCP_LOG_INFO ( " error: Could not create a close port request "
" for port 0x%016Lx on adapter %s. \n " ,
erp_action - > port - > wwpn ,
zfcp_get_busid_by_adapter ( erp_action - > adapter ) ) ;
goto out ;
}
2006-09-19 00:29:56 +04:00
sbale = zfcp_qdio_sbale_req ( fsf_req , fsf_req - > sbal_curr , 0 ) ;
2005-04-17 02:20:36 +04:00
sbale [ 0 ] . flags | = SBAL_FLAGS0_TYPE_READ ;
sbale [ 1 ] . flags | = SBAL_FLAGS_LAST_ENTRY ;
atomic_set_mask ( ZFCP_STATUS_COMMON_CLOSING , & erp_action - > port - > status ) ;
2006-09-19 00:29:56 +04:00
fsf_req - > data = ( unsigned long ) erp_action - > port ;
fsf_req - > erp_action = erp_action ;
fsf_req - > qtcb - > header . port_handle = erp_action - > port - > handle ;
fsf_req - > erp_action = erp_action ;
erp_action - > fsf_req = fsf_req ;
zfcp_erp_start_timer ( fsf_req ) ;
retval = zfcp_fsf_req_send ( fsf_req ) ;
2005-04-17 02:20:36 +04:00
if ( retval ) {
ZFCP_LOG_INFO ( " error: Could not send a close port request for "
" port 0x%016Lx on adapter %s. \n " ,
erp_action - > port - > wwpn ,
zfcp_get_busid_by_adapter ( erp_action - > adapter ) ) ;
2006-09-19 00:29:56 +04:00
zfcp_fsf_req_free ( fsf_req ) ;
2005-04-17 02:20:36 +04:00
erp_action - > fsf_req = NULL ;
goto out ;
}
ZFCP_LOG_TRACE ( " close port request initiated "
" (adapter %s, port 0x%016Lx) \n " ,
zfcp_get_busid_by_adapter ( erp_action - > adapter ) ,
erp_action - > port - > wwpn ) ;
out :
write_unlock_irqrestore ( & erp_action - > adapter - > request_queue . queue_lock ,
lock_flags ) ;
return retval ;
}
/*
* function : zfcp_fsf_close_port_handler
*
* purpose : is called for finished Close Port FSF command
*
* returns :
*/
static int
zfcp_fsf_close_port_handler ( struct zfcp_fsf_req * fsf_req )
{
int retval = - EINVAL ;
struct zfcp_port * port ;
2005-09-13 23:47:52 +04:00
port = ( struct zfcp_port * ) fsf_req - > data ;
2005-04-17 02:20:36 +04:00
if ( fsf_req - > status & ZFCP_STATUS_FSFREQ_ERROR ) {
/* don't change port status in our bookkeeping */
goto skip_fsfstatus ;
}
/* evaluate FSF status in QTCB */
switch ( fsf_req - > qtcb - > header . fsf_status ) {
case FSF_PORT_HANDLE_NOT_VALID :
ZFCP_LOG_INFO ( " Temporary port identifier 0x%x for port "
" 0x%016Lx on adapter %s invalid. This may happen "
" occasionally. \n " , port - > handle ,
port - > wwpn , zfcp_get_busid_by_port ( port ) ) ;
ZFCP_LOG_DEBUG ( " status qualifier: \n " ) ;
ZFCP_HEX_DUMP ( ZFCP_LOG_LEVEL_DEBUG ,
( char * ) & fsf_req - > qtcb - > header . fsf_status_qual ,
sizeof ( union fsf_status_qual ) ) ;
debug_text_event ( fsf_req - > adapter - > erp_dbf , 1 ,
" fsf_s_phand_nv " ) ;
zfcp_erp_adapter_reopen ( port - > adapter , 0 ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_ADAPTER_STATUS_AVAILABLE :
/* Note: FSF has actually closed the port in this case.
* The status code is just daft . Fingers crossed for a change
*/
retval = 0 ;
break ;
case FSF_GOOD :
ZFCP_LOG_TRACE ( " remote port 0x016%Lx on adapter %s closed, "
" port handle 0x%x \n " , port - > wwpn ,
zfcp_get_busid_by_port ( port ) , port - > handle ) ;
zfcp_erp_modify_port_status ( port ,
ZFCP_STATUS_COMMON_OPEN ,
ZFCP_CLEAR ) ;
retval = 0 ;
break ;
default :
ZFCP_LOG_NORMAL ( " bug: An unknown FSF Status was presented "
" (debug info 0x%x) \n " ,
fsf_req - > qtcb - > header . fsf_status ) ;
debug_text_event ( fsf_req - > adapter - > erp_dbf , 0 , " fsf_s_inval: " ) ;
debug_exception ( fsf_req - > adapter - > erp_dbf , 0 ,
& fsf_req - > qtcb - > header . fsf_status ,
sizeof ( u32 ) ) ;
break ;
}
skip_fsfstatus :
atomic_clear_mask ( ZFCP_STATUS_COMMON_CLOSING , & port - > status ) ;
return retval ;
}
/*
* function : zfcp_fsf_close_physical_port
*
* purpose : submit FSF command " close physical port "
*
* returns : address of initiated FSF request
* NULL - request could not be initiated
*/
int
zfcp_fsf_close_physical_port ( struct zfcp_erp_action * erp_action )
{
volatile struct qdio_buffer_element * sbale ;
2006-09-19 00:29:56 +04:00
struct zfcp_fsf_req * fsf_req ;
unsigned long lock_flags ;
int retval = 0 ;
2005-04-17 02:20:36 +04:00
/* setup new FSF request */
retval = zfcp_fsf_req_create ( erp_action - > adapter ,
FSF_QTCB_CLOSE_PHYSICAL_PORT ,
ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP ,
erp_action - > adapter - > pool . fsf_req_erp ,
2006-09-19 00:29:56 +04:00
& lock_flags , & fsf_req ) ;
2005-04-17 02:20:36 +04:00
if ( retval < 0 ) {
ZFCP_LOG_INFO ( " error: Could not create close physical port "
" request (adapter %s, port 0x%016Lx) \n " ,
zfcp_get_busid_by_adapter ( erp_action - > adapter ) ,
erp_action - > port - > wwpn ) ;
goto out ;
}
2006-09-19 00:29:56 +04:00
sbale = zfcp_qdio_sbale_req ( fsf_req , fsf_req - > sbal_curr , 0 ) ;
2005-04-17 02:20:36 +04:00
sbale [ 0 ] . flags | = SBAL_FLAGS0_TYPE_READ ;
sbale [ 1 ] . flags | = SBAL_FLAGS_LAST_ENTRY ;
/* mark port as being closed */
atomic_set_mask ( ZFCP_STATUS_PORT_PHYS_CLOSING ,
& erp_action - > port - > status ) ;
/* save a pointer to this port */
2006-09-19 00:29:56 +04:00
fsf_req - > data = ( unsigned long ) erp_action - > port ;
fsf_req - > qtcb - > header . port_handle = erp_action - > port - > handle ;
fsf_req - > erp_action = erp_action ;
erp_action - > fsf_req = fsf_req ;
zfcp_erp_start_timer ( fsf_req ) ;
retval = zfcp_fsf_req_send ( fsf_req ) ;
2005-04-17 02:20:36 +04:00
if ( retval ) {
ZFCP_LOG_INFO ( " error: Could not send close physical port "
" request (adapter %s, port 0x%016Lx) \n " ,
zfcp_get_busid_by_adapter ( erp_action - > adapter ) ,
erp_action - > port - > wwpn ) ;
2006-09-19 00:29:56 +04:00
zfcp_fsf_req_free ( fsf_req ) ;
2005-04-17 02:20:36 +04:00
erp_action - > fsf_req = NULL ;
goto out ;
}
ZFCP_LOG_TRACE ( " close physical port request initiated "
" (adapter %s, port 0x%016Lx) \n " ,
zfcp_get_busid_by_adapter ( erp_action - > adapter ) ,
erp_action - > port - > wwpn ) ;
out :
write_unlock_irqrestore ( & erp_action - > adapter - > request_queue . queue_lock ,
lock_flags ) ;
return retval ;
}
/*
* function : zfcp_fsf_close_physical_port_handler
*
* purpose : is called for finished Close Physical Port FSF command
*
* returns :
*/
static int
zfcp_fsf_close_physical_port_handler ( struct zfcp_fsf_req * fsf_req )
{
int retval = - EINVAL ;
struct zfcp_port * port ;
struct zfcp_unit * unit ;
struct fsf_qtcb_header * header ;
u16 subtable , rule , counter ;
2005-09-13 23:47:52 +04:00
port = ( struct zfcp_port * ) fsf_req - > data ;
2005-04-17 02:20:36 +04:00
header = & fsf_req - > qtcb - > header ;
if ( fsf_req - > status & ZFCP_STATUS_FSFREQ_ERROR ) {
/* don't change port status in our bookkeeping */
goto skip_fsfstatus ;
}
/* evaluate FSF status in QTCB */
switch ( header - > fsf_status ) {
case FSF_PORT_HANDLE_NOT_VALID :
ZFCP_LOG_INFO ( " Temporary port identifier 0x%x invalid "
" (adapter %s, port 0x%016Lx). "
" This may happen occasionally. \n " ,
port - > handle ,
zfcp_get_busid_by_port ( port ) ,
port - > wwpn ) ;
ZFCP_LOG_DEBUG ( " status qualifier: \n " ) ;
ZFCP_HEX_DUMP ( ZFCP_LOG_LEVEL_DEBUG ,
( char * ) & header - > fsf_status_qual ,
sizeof ( union fsf_status_qual ) ) ;
debug_text_event ( fsf_req - > adapter - > erp_dbf , 1 ,
" fsf_s_phand_nv " ) ;
zfcp_erp_adapter_reopen ( port - > adapter , 0 ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_ACCESS_DENIED :
ZFCP_LOG_NORMAL ( " Access denied, cannot close "
" physical port 0x%016Lx on adapter %s \n " ,
port - > wwpn , zfcp_get_busid_by_port ( port ) ) ;
for ( counter = 0 ; counter < 2 ; counter + + ) {
subtable = header - > fsf_status_qual . halfword [ counter * 2 ] ;
rule = header - > fsf_status_qual . halfword [ counter * 2 + 1 ] ;
switch ( subtable ) {
case FSF_SQ_CFDC_SUBTABLE_OS :
case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN :
case FSF_SQ_CFDC_SUBTABLE_PORT_DID :
case FSF_SQ_CFDC_SUBTABLE_LUN :
ZFCP_LOG_INFO ( " Access denied (%s rule %d) \n " ,
zfcp_act_subtable_type [ subtable ] , rule ) ;
break ;
}
}
debug_text_event ( fsf_req - > adapter - > erp_dbf , 1 , " fsf_s_access " ) ;
zfcp_erp_port_access_denied ( port ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_PORT_BOXED :
ZFCP_LOG_DEBUG ( " The remote port 0x%016Lx on adapter "
" %s needs to be reopened but it was attempted "
" to close it physically. \n " ,
port - > wwpn ,
zfcp_get_busid_by_port ( port ) ) ;
debug_text_event ( fsf_req - > adapter - > erp_dbf , 1 , " fsf_s_pboxed " ) ;
2005-06-13 15:23:57 +04:00
zfcp_erp_port_boxed ( port ) ;
2005-04-17 02:20:36 +04:00
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR |
ZFCP_STATUS_FSFREQ_RETRY ;
break ;
case FSF_ADAPTER_STATUS_AVAILABLE :
switch ( header - > fsf_status_qual . word [ 0 ] ) {
case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE :
debug_text_event ( fsf_req - > adapter - > erp_dbf , 1 ,
" fsf_sq_ltest " ) ;
/* This will now be escalated by ERP */
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED :
/* ERP strategy will escalate */
debug_text_event ( fsf_req - > adapter - > erp_dbf , 1 ,
" fsf_sq_ulp " ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
default :
ZFCP_LOG_NORMAL
( " bug: Wrong status qualifier 0x%x arrived. \n " ,
header - > fsf_status_qual . word [ 0 ] ) ;
debug_text_event ( fsf_req - > adapter - > erp_dbf , 0 ,
" fsf_sq_inval: " ) ;
debug_exception (
fsf_req - > adapter - > erp_dbf , 0 ,
& header - > fsf_status_qual . word [ 0 ] , sizeof ( u32 ) ) ;
break ;
}
break ;
case FSF_GOOD :
ZFCP_LOG_DEBUG ( " Remote port 0x%016Lx via adapter %s "
" physically closed, port handle 0x%x \n " ,
port - > wwpn ,
zfcp_get_busid_by_port ( port ) , port - > handle ) ;
/* can't use generic zfcp_erp_modify_port_status because
* ZFCP_STATUS_COMMON_OPEN must not be reset for the port
*/
atomic_clear_mask ( ZFCP_STATUS_PORT_PHYS_OPEN , & port - > status ) ;
list_for_each_entry ( unit , & port - > unit_list_head , list )
atomic_clear_mask ( ZFCP_STATUS_COMMON_OPEN , & unit - > status ) ;
retval = 0 ;
break ;
default :
ZFCP_LOG_NORMAL ( " bug: An unknown FSF Status was presented "
" (debug info 0x%x) \n " ,
header - > fsf_status ) ;
debug_text_event ( fsf_req - > adapter - > erp_dbf , 0 , " fsf_s_inval: " ) ;
debug_exception ( fsf_req - > adapter - > erp_dbf , 0 ,
& header - > fsf_status , sizeof ( u32 ) ) ;
break ;
}
skip_fsfstatus :
atomic_clear_mask ( ZFCP_STATUS_PORT_PHYS_CLOSING , & port - > status ) ;
return retval ;
}
/*
* function : zfcp_fsf_open_unit
*
* purpose :
*
* returns :
*
* assumptions : This routine does not check whether the associated
* remote port has already been opened . This should be
* done by calling routines . Otherwise some status
* may be presented by FSF
*/
int
zfcp_fsf_open_unit ( struct zfcp_erp_action * erp_action )
{
volatile struct qdio_buffer_element * sbale ;
2006-09-19 00:29:56 +04:00
struct zfcp_fsf_req * fsf_req ;
2005-04-17 02:20:36 +04:00
unsigned long lock_flags ;
int retval = 0 ;
/* setup new FSF request */
retval = zfcp_fsf_req_create ( erp_action - > adapter ,
FSF_QTCB_OPEN_LUN ,
ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP ,
erp_action - > adapter - > pool . fsf_req_erp ,
2006-09-19 00:29:56 +04:00
& lock_flags , & fsf_req ) ;
2005-04-17 02:20:36 +04:00
if ( retval < 0 ) {
ZFCP_LOG_INFO ( " error: Could not create open unit request for "
" unit 0x%016Lx on port 0x%016Lx on adapter %s. \n " ,
erp_action - > unit - > fcp_lun ,
erp_action - > unit - > port - > wwpn ,
zfcp_get_busid_by_adapter ( erp_action - > adapter ) ) ;
goto out ;
}
2006-09-19 00:29:56 +04:00
sbale = zfcp_qdio_sbale_req ( fsf_req , fsf_req - > sbal_curr , 0 ) ;
2005-04-17 02:20:36 +04:00
sbale [ 0 ] . flags | = SBAL_FLAGS0_TYPE_READ ;
sbale [ 1 ] . flags | = SBAL_FLAGS_LAST_ENTRY ;
2006-09-19 00:29:56 +04:00
fsf_req - > qtcb - > header . port_handle = erp_action - > port - > handle ;
fsf_req - > qtcb - > bottom . support . fcp_lun = erp_action - > unit - > fcp_lun ;
2005-09-13 23:51:16 +04:00
if ( ! ( erp_action - > adapter - > connection_features & FSF_FEATURE_NPIV_MODE ) )
2006-09-19 00:29:56 +04:00
fsf_req - > qtcb - > bottom . support . option =
2006-05-22 20:18:19 +04:00
FSF_OPEN_LUN_SUPPRESS_BOXING ;
2005-04-17 02:20:36 +04:00
atomic_set_mask ( ZFCP_STATUS_COMMON_OPENING , & erp_action - > unit - > status ) ;
2006-09-19 00:29:56 +04:00
fsf_req - > data = ( unsigned long ) erp_action - > unit ;
fsf_req - > erp_action = erp_action ;
erp_action - > fsf_req = fsf_req ;
2005-04-17 02:20:36 +04:00
2006-09-19 00:29:56 +04:00
zfcp_erp_start_timer ( fsf_req ) ;
retval = zfcp_fsf_req_send ( erp_action - > fsf_req ) ;
2005-04-17 02:20:36 +04:00
if ( retval ) {
ZFCP_LOG_INFO ( " error: Could not send an open unit request "
" on the adapter %s, port 0x%016Lx for "
" unit 0x%016Lx \n " ,
zfcp_get_busid_by_adapter ( erp_action - > adapter ) ,
erp_action - > port - > wwpn ,
erp_action - > unit - > fcp_lun ) ;
2006-09-19 00:29:56 +04:00
zfcp_fsf_req_free ( fsf_req ) ;
2005-04-17 02:20:36 +04:00
erp_action - > fsf_req = NULL ;
goto out ;
}
ZFCP_LOG_TRACE ( " Open LUN request initiated (adapter %s, "
" port 0x%016Lx, unit 0x%016Lx) \n " ,
zfcp_get_busid_by_adapter ( erp_action - > adapter ) ,
erp_action - > port - > wwpn , erp_action - > unit - > fcp_lun ) ;
out :
write_unlock_irqrestore ( & erp_action - > adapter - > request_queue . queue_lock ,
lock_flags ) ;
return retval ;
}
/*
* function : zfcp_fsf_open_unit_handler
*
* purpose : is called for finished Open LUN command
*
* returns :
*/
static int
zfcp_fsf_open_unit_handler ( struct zfcp_fsf_req * fsf_req )
{
int retval = - EINVAL ;
struct zfcp_adapter * adapter ;
struct zfcp_unit * unit ;
struct fsf_qtcb_header * header ;
struct fsf_qtcb_bottom_support * bottom ;
struct fsf_queue_designator * queue_designator ;
u16 subtable , rule , counter ;
2005-09-13 23:51:16 +04:00
int exclusive , readwrite ;
2005-04-17 02:20:36 +04:00
2005-09-13 23:47:52 +04:00
unit = ( struct zfcp_unit * ) fsf_req - > data ;
2005-04-17 02:20:36 +04:00
if ( fsf_req - > status & ZFCP_STATUS_FSFREQ_ERROR ) {
/* don't change unit status in our bookkeeping */
goto skip_fsfstatus ;
}
adapter = fsf_req - > adapter ;
header = & fsf_req - > qtcb - > header ;
bottom = & fsf_req - > qtcb - > bottom . support ;
queue_designator = & header - > fsf_status_qual . fsf_queue_designator ;
atomic_clear_mask ( ZFCP_STATUS_COMMON_ACCESS_DENIED |
2007-05-08 13:19:57 +04:00
ZFCP_STATUS_COMMON_ACCESS_BOXED |
2005-04-17 02:20:36 +04:00
ZFCP_STATUS_UNIT_SHARED |
ZFCP_STATUS_UNIT_READONLY ,
& unit - > status ) ;
/* evaluate FSF status in QTCB */
switch ( header - > fsf_status ) {
case FSF_PORT_HANDLE_NOT_VALID :
ZFCP_LOG_INFO ( " Temporary port identifier 0x%x "
" for port 0x%016Lx on adapter %s invalid "
" This may happen occasionally \n " ,
unit - > port - > handle ,
unit - > port - > wwpn , zfcp_get_busid_by_unit ( unit ) ) ;
ZFCP_LOG_DEBUG ( " status qualifier: \n " ) ;
ZFCP_HEX_DUMP ( ZFCP_LOG_LEVEL_DEBUG ,
( char * ) & header - > fsf_status_qual ,
sizeof ( union fsf_status_qual ) ) ;
debug_text_event ( adapter - > erp_dbf , 1 , " fsf_s_ph_nv " ) ;
zfcp_erp_adapter_reopen ( unit - > port - > adapter , 0 ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_LUN_ALREADY_OPEN :
ZFCP_LOG_NORMAL ( " bug: Attempted to open unit 0x%016Lx on "
" remote port 0x%016Lx on adapter %s twice. \n " ,
unit - > fcp_lun ,
unit - > port - > wwpn , zfcp_get_busid_by_unit ( unit ) ) ;
debug_text_exception ( adapter - > erp_dbf , 0 ,
" fsf_s_uopen " ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_ACCESS_DENIED :
ZFCP_LOG_NORMAL ( " Access denied, cannot open unit 0x%016Lx on "
" remote port 0x%016Lx on adapter %s \n " ,
unit - > fcp_lun , unit - > port - > wwpn ,
zfcp_get_busid_by_unit ( unit ) ) ;
for ( counter = 0 ; counter < 2 ; counter + + ) {
subtable = header - > fsf_status_qual . halfword [ counter * 2 ] ;
rule = header - > fsf_status_qual . halfword [ counter * 2 + 1 ] ;
switch ( subtable ) {
case FSF_SQ_CFDC_SUBTABLE_OS :
case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN :
case FSF_SQ_CFDC_SUBTABLE_PORT_DID :
case FSF_SQ_CFDC_SUBTABLE_LUN :
ZFCP_LOG_INFO ( " Access denied (%s rule %d) \n " ,
zfcp_act_subtable_type [ subtable ] , rule ) ;
break ;
}
}
debug_text_event ( adapter - > erp_dbf , 1 , " fsf_s_access " ) ;
zfcp_erp_unit_access_denied ( unit ) ;
atomic_clear_mask ( ZFCP_STATUS_UNIT_SHARED , & unit - > status ) ;
atomic_clear_mask ( ZFCP_STATUS_UNIT_READONLY , & unit - > status ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_PORT_BOXED :
ZFCP_LOG_DEBUG ( " The remote port 0x%016Lx on adapter %s "
" needs to be reopened \n " ,
unit - > port - > wwpn , zfcp_get_busid_by_unit ( unit ) ) ;
debug_text_event ( adapter - > erp_dbf , 2 , " fsf_s_pboxed " ) ;
2005-06-13 15:23:57 +04:00
zfcp_erp_port_boxed ( unit - > port ) ;
2005-04-17 02:20:36 +04:00
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR |
ZFCP_STATUS_FSFREQ_RETRY ;
break ;
case FSF_LUN_SHARING_VIOLATION :
if ( header - > fsf_status_qual . word [ 0 ] ! = 0 ) {
ZFCP_LOG_NORMAL ( " FCP-LUN 0x%Lx at the remote port "
" with WWPN 0x%Lx "
" connected to the adapter %s "
" is already in use in LPAR%d, CSS%d \n " ,
unit - > fcp_lun ,
unit - > port - > wwpn ,
zfcp_get_busid_by_unit ( unit ) ,
queue_designator - > hla ,
queue_designator - > cssid ) ;
} else {
subtable = header - > fsf_status_qual . halfword [ 4 ] ;
rule = header - > fsf_status_qual . halfword [ 5 ] ;
switch ( subtable ) {
case FSF_SQ_CFDC_SUBTABLE_OS :
case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN :
case FSF_SQ_CFDC_SUBTABLE_PORT_DID :
case FSF_SQ_CFDC_SUBTABLE_LUN :
ZFCP_LOG_NORMAL ( " Access to FCP-LUN 0x%Lx at the "
" remote port with WWPN 0x%Lx "
" connected to the adapter %s "
" is denied (%s rule %d) \n " ,
unit - > fcp_lun ,
unit - > port - > wwpn ,
zfcp_get_busid_by_unit ( unit ) ,
zfcp_act_subtable_type [ subtable ] ,
rule ) ;
break ;
}
}
ZFCP_LOG_DEBUG ( " status qualifier: \n " ) ;
ZFCP_HEX_DUMP ( ZFCP_LOG_LEVEL_DEBUG ,
( char * ) & header - > fsf_status_qual ,
sizeof ( union fsf_status_qual ) ) ;
debug_text_event ( adapter - > erp_dbf , 2 ,
" fsf_s_l_sh_vio " ) ;
zfcp_erp_unit_access_denied ( unit ) ;
atomic_clear_mask ( ZFCP_STATUS_UNIT_SHARED , & unit - > status ) ;
atomic_clear_mask ( ZFCP_STATUS_UNIT_READONLY , & unit - > status ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_MAXIMUM_NUMBER_OF_LUNS_EXCEEDED :
ZFCP_LOG_INFO ( " error: The adapter ran out of resources. "
" There is no handle (temporary port identifier) "
" available for unit 0x%016Lx on port 0x%016Lx "
" on adapter %s \n " ,
unit - > fcp_lun ,
unit - > port - > wwpn ,
zfcp_get_busid_by_unit ( unit ) ) ;
debug_text_event ( adapter - > erp_dbf , 1 ,
" fsf_s_max_units " ) ;
zfcp_erp_unit_failed ( unit ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_ADAPTER_STATUS_AVAILABLE :
switch ( header - > fsf_status_qual . word [ 0 ] ) {
case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE :
/* Re-establish link to port */
debug_text_event ( adapter - > erp_dbf , 1 ,
" fsf_sq_ltest " ) ;
2005-06-13 15:16:27 +04:00
zfcp_test_link ( unit - > port ) ;
2005-04-17 02:20:36 +04:00
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED :
/* ERP strategy will escalate */
debug_text_event ( adapter - > erp_dbf , 1 ,
" fsf_sq_ulp " ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
default :
ZFCP_LOG_NORMAL
( " bug: Wrong status qualifier 0x%x arrived. \n " ,
header - > fsf_status_qual . word [ 0 ] ) ;
debug_text_event ( adapter - > erp_dbf , 0 ,
" fsf_sq_inval: " ) ;
debug_exception ( adapter - > erp_dbf , 0 ,
& header - > fsf_status_qual . word [ 0 ] ,
sizeof ( u32 ) ) ;
}
break ;
case FSF_INVALID_COMMAND_OPTION :
ZFCP_LOG_NORMAL (
" Invalid option 0x%x has been specified "
" in QTCB bottom sent to the adapter %s \n " ,
bottom - > option ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
retval = - EINVAL ;
break ;
case FSF_GOOD :
/* save LUN handle assigned by FSF */
unit - > handle = header - > lun_handle ;
ZFCP_LOG_TRACE ( " unit 0x%016Lx on remote port 0x%016Lx on "
" adapter %s opened, port handle 0x%x \n " ,
unit - > fcp_lun ,
unit - > port - > wwpn ,
zfcp_get_busid_by_unit ( unit ) ,
unit - > handle ) ;
/* mark unit as open */
atomic_set_mask ( ZFCP_STATUS_COMMON_OPEN , & unit - > status ) ;
2005-09-13 23:51:16 +04:00
if ( ! ( adapter - > connection_features & FSF_FEATURE_NPIV_MODE ) & &
( adapter - > adapter_features & FSF_FEATURE_LUN_SHARING ) & &
( adapter - > ccw_device - > id . dev_model ! = ZFCP_DEVICE_MODEL_PRIV ) ) {
exclusive = ( bottom - > lun_access_info &
FSF_UNIT_ACCESS_EXCLUSIVE ) ;
readwrite = ( bottom - > lun_access_info &
FSF_UNIT_ACCESS_OUTBOUND_TRANSFER ) ;
2005-04-17 02:20:36 +04:00
if ( ! exclusive )
atomic_set_mask ( ZFCP_STATUS_UNIT_SHARED ,
& unit - > status ) ;
if ( ! readwrite ) {
atomic_set_mask ( ZFCP_STATUS_UNIT_READONLY ,
& unit - > status ) ;
ZFCP_LOG_NORMAL ( " read-only access for unit "
" (adapter %s, wwpn=0x%016Lx, "
" fcp_lun=0x%016Lx) \n " ,
zfcp_get_busid_by_unit ( unit ) ,
unit - > port - > wwpn ,
unit - > fcp_lun ) ;
}
if ( exclusive & & ! readwrite ) {
ZFCP_LOG_NORMAL ( " exclusive access of read-only "
" unit not supported \n " ) ;
zfcp_erp_unit_failed ( unit ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
zfcp_erp_unit_shutdown ( unit , 0 ) ;
} else if ( ! exclusive & & readwrite ) {
ZFCP_LOG_NORMAL ( " shared access of read-write "
" unit not supported \n " ) ;
zfcp_erp_unit_failed ( unit ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
zfcp_erp_unit_shutdown ( unit , 0 ) ;
}
}
retval = 0 ;
break ;
default :
ZFCP_LOG_NORMAL ( " bug: An unknown FSF Status was presented "
" (debug info 0x%x) \n " ,
header - > fsf_status ) ;
debug_text_event ( adapter - > erp_dbf , 0 , " fsf_s_inval: " ) ;
debug_exception ( adapter - > erp_dbf , 0 ,
& header - > fsf_status , sizeof ( u32 ) ) ;
break ;
}
skip_fsfstatus :
atomic_clear_mask ( ZFCP_STATUS_COMMON_OPENING , & unit - > status ) ;
return retval ;
}
/*
* function : zfcp_fsf_close_unit
*
* purpose :
*
* returns : address of fsf_req - request successfully initiated
* NULL -
*
* assumptions : This routine does not check whether the associated
* remote port / lun has already been opened . This should be
* done by calling routines . Otherwise some status
* may be presented by FSF
*/
int
zfcp_fsf_close_unit ( struct zfcp_erp_action * erp_action )
{
volatile struct qdio_buffer_element * sbale ;
2006-09-19 00:29:56 +04:00
struct zfcp_fsf_req * fsf_req ;
2005-04-17 02:20:36 +04:00
unsigned long lock_flags ;
int retval = 0 ;
/* setup new FSF request */
retval = zfcp_fsf_req_create ( erp_action - > adapter ,
FSF_QTCB_CLOSE_LUN ,
ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP ,
erp_action - > adapter - > pool . fsf_req_erp ,
2006-09-19 00:29:56 +04:00
& lock_flags , & fsf_req ) ;
2005-04-17 02:20:36 +04:00
if ( retval < 0 ) {
ZFCP_LOG_INFO ( " error: Could not create close unit request for "
" unit 0x%016Lx on port 0x%016Lx on adapter %s. \n " ,
erp_action - > unit - > fcp_lun ,
erp_action - > port - > wwpn ,
zfcp_get_busid_by_adapter ( erp_action - > adapter ) ) ;
goto out ;
}
2006-09-19 00:29:56 +04:00
sbale = zfcp_qdio_sbale_req ( fsf_req , fsf_req - > sbal_curr , 0 ) ;
2005-04-17 02:20:36 +04:00
sbale [ 0 ] . flags | = SBAL_FLAGS0_TYPE_READ ;
sbale [ 1 ] . flags | = SBAL_FLAGS_LAST_ENTRY ;
2006-09-19 00:29:56 +04:00
fsf_req - > qtcb - > header . port_handle = erp_action - > port - > handle ;
fsf_req - > qtcb - > header . lun_handle = erp_action - > unit - > handle ;
2005-04-17 02:20:36 +04:00
atomic_set_mask ( ZFCP_STATUS_COMMON_CLOSING , & erp_action - > unit - > status ) ;
2006-09-19 00:29:56 +04:00
fsf_req - > data = ( unsigned long ) erp_action - > unit ;
fsf_req - > erp_action = erp_action ;
erp_action - > fsf_req = fsf_req ;
2005-04-17 02:20:36 +04:00
2006-09-19 00:29:56 +04:00
zfcp_erp_start_timer ( fsf_req ) ;
retval = zfcp_fsf_req_send ( erp_action - > fsf_req ) ;
2005-04-17 02:20:36 +04:00
if ( retval ) {
ZFCP_LOG_INFO ( " error: Could not send a close unit request for "
" unit 0x%016Lx on port 0x%016Lx onadapter %s. \n " ,
erp_action - > unit - > fcp_lun ,
erp_action - > port - > wwpn ,
zfcp_get_busid_by_adapter ( erp_action - > adapter ) ) ;
2006-09-19 00:29:56 +04:00
zfcp_fsf_req_free ( fsf_req ) ;
2005-04-17 02:20:36 +04:00
erp_action - > fsf_req = NULL ;
goto out ;
}
ZFCP_LOG_TRACE ( " Close LUN request initiated (adapter %s, "
" port 0x%016Lx, unit 0x%016Lx) \n " ,
zfcp_get_busid_by_adapter ( erp_action - > adapter ) ,
erp_action - > port - > wwpn , erp_action - > unit - > fcp_lun ) ;
out :
write_unlock_irqrestore ( & erp_action - > adapter - > request_queue . queue_lock ,
lock_flags ) ;
return retval ;
}
/*
* function : zfcp_fsf_close_unit_handler
*
* purpose : is called for finished Close LUN FSF command
*
* returns :
*/
static int
zfcp_fsf_close_unit_handler ( struct zfcp_fsf_req * fsf_req )
{
int retval = - EINVAL ;
struct zfcp_unit * unit ;
2005-09-13 23:47:52 +04:00
unit = ( struct zfcp_unit * ) fsf_req - > data ;
2005-04-17 02:20:36 +04:00
if ( fsf_req - > status & ZFCP_STATUS_FSFREQ_ERROR ) {
/* don't change unit status in our bookkeeping */
goto skip_fsfstatus ;
}
/* evaluate FSF status in QTCB */
switch ( fsf_req - > qtcb - > header . fsf_status ) {
case FSF_PORT_HANDLE_NOT_VALID :
ZFCP_LOG_INFO ( " Temporary port identifier 0x%x for port "
" 0x%016Lx on adapter %s invalid. This may "
" happen in rare circumstances \n " ,
unit - > port - > handle ,
unit - > port - > wwpn ,
zfcp_get_busid_by_unit ( unit ) ) ;
ZFCP_LOG_DEBUG ( " status qualifier: \n " ) ;
ZFCP_HEX_DUMP ( ZFCP_LOG_LEVEL_DEBUG ,
( char * ) & fsf_req - > qtcb - > header . fsf_status_qual ,
sizeof ( union fsf_status_qual ) ) ;
debug_text_event ( fsf_req - > adapter - > erp_dbf , 1 ,
" fsf_s_phand_nv " ) ;
zfcp_erp_adapter_reopen ( unit - > port - > adapter , 0 ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_LUN_HANDLE_NOT_VALID :
ZFCP_LOG_INFO ( " Temporary LUN identifier 0x%x of unit "
" 0x%016Lx on port 0x%016Lx on adapter %s is "
" invalid. This may happen occasionally. \n " ,
unit - > handle ,
unit - > fcp_lun ,
unit - > port - > wwpn ,
zfcp_get_busid_by_unit ( unit ) ) ;
ZFCP_LOG_DEBUG ( " Status qualifier data: \n " ) ;
ZFCP_HEX_DUMP ( ZFCP_LOG_LEVEL_DEBUG ,
( char * ) & fsf_req - > qtcb - > header . fsf_status_qual ,
sizeof ( union fsf_status_qual ) ) ;
debug_text_event ( fsf_req - > adapter - > erp_dbf , 1 ,
" fsf_s_lhand_nv " ) ;
zfcp_erp_port_reopen ( unit - > port , 0 ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_PORT_BOXED :
ZFCP_LOG_DEBUG ( " The remote port 0x%016Lx on adapter %s "
" needs to be reopened \n " ,
unit - > port - > wwpn ,
zfcp_get_busid_by_unit ( unit ) ) ;
debug_text_event ( fsf_req - > adapter - > erp_dbf , 2 , " fsf_s_pboxed " ) ;
2005-06-13 15:23:57 +04:00
zfcp_erp_port_boxed ( unit - > port ) ;
2005-04-17 02:20:36 +04:00
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR |
ZFCP_STATUS_FSFREQ_RETRY ;
break ;
case FSF_ADAPTER_STATUS_AVAILABLE :
switch ( fsf_req - > qtcb - > header . fsf_status_qual . word [ 0 ] ) {
case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE :
/* re-establish link to port */
debug_text_event ( fsf_req - > adapter - > erp_dbf , 1 ,
" fsf_sq_ltest " ) ;
2005-06-13 15:16:27 +04:00
zfcp_test_link ( unit - > port ) ;
2005-04-17 02:20:36 +04:00
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED :
/* ERP strategy will escalate */
debug_text_event ( fsf_req - > adapter - > erp_dbf , 1 ,
" fsf_sq_ulp " ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
default :
ZFCP_LOG_NORMAL
( " bug: Wrong status qualifier 0x%x arrived. \n " ,
fsf_req - > qtcb - > header . fsf_status_qual . word [ 0 ] ) ;
debug_text_event ( fsf_req - > adapter - > erp_dbf , 0 ,
" fsf_sq_inval: " ) ;
debug_exception (
fsf_req - > adapter - > erp_dbf , 0 ,
& fsf_req - > qtcb - > header . fsf_status_qual . word [ 0 ] ,
sizeof ( u32 ) ) ;
break ;
}
break ;
case FSF_GOOD :
ZFCP_LOG_TRACE ( " unit 0x%016Lx on port 0x%016Lx on adapter %s "
" closed, port handle 0x%x \n " ,
unit - > fcp_lun ,
unit - > port - > wwpn ,
zfcp_get_busid_by_unit ( unit ) ,
unit - > handle ) ;
/* mark unit as closed */
atomic_clear_mask ( ZFCP_STATUS_COMMON_OPEN , & unit - > status ) ;
retval = 0 ;
break ;
default :
ZFCP_LOG_NORMAL ( " bug: An unknown FSF Status was presented "
" (debug info 0x%x) \n " ,
fsf_req - > qtcb - > header . fsf_status ) ;
debug_text_event ( fsf_req - > adapter - > erp_dbf , 0 , " fsf_s_inval: " ) ;
debug_exception ( fsf_req - > adapter - > erp_dbf , 0 ,
& fsf_req - > qtcb - > header . fsf_status ,
sizeof ( u32 ) ) ;
break ;
}
skip_fsfstatus :
atomic_clear_mask ( ZFCP_STATUS_COMMON_CLOSING , & unit - > status ) ;
return retval ;
}
/**
* zfcp_fsf_send_fcp_command_task - initiate an FCP command ( for a SCSI command )
* @ adapter : adapter where scsi command is issued
* @ unit : unit where command is sent to
* @ scsi_cmnd : scsi command to be sent
* @ timer : timer to be started when request is initiated
* @ req_flags : flags for fsf_request
*/
int
zfcp_fsf_send_fcp_command_task ( struct zfcp_adapter * adapter ,
struct zfcp_unit * unit ,
struct scsi_cmnd * scsi_cmnd ,
2006-09-19 00:29:56 +04:00
int use_timer , int req_flags )
2005-04-17 02:20:36 +04:00
{
struct zfcp_fsf_req * fsf_req = NULL ;
struct fcp_cmnd_iu * fcp_cmnd_iu ;
unsigned int sbtype ;
unsigned long lock_flags ;
int real_bytes = 0 ;
int retval = 0 ;
int mask ;
/* setup new FSF request */
retval = zfcp_fsf_req_create ( adapter , FSF_QTCB_FCP_CMND , req_flags ,
adapter - > pool . fsf_req_scsi ,
& lock_flags , & fsf_req ) ;
if ( unlikely ( retval < 0 ) ) {
ZFCP_LOG_DEBUG ( " error: Could not create FCP command request "
" for unit 0x%016Lx on port 0x%016Lx on "
" adapter %s \n " ,
unit - > fcp_lun ,
unit - > port - > wwpn ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
goto failed_req_create ;
}
2005-09-13 23:47:52 +04:00
zfcp_unit_get ( unit ) ;
fsf_req - > unit = unit ;
2005-04-17 02:20:36 +04:00
2005-09-13 23:47:52 +04:00
/* associate FSF request with SCSI request (for look up on abort) */
2006-09-19 00:29:20 +04:00
scsi_cmnd - > host_scribble = ( unsigned char * ) fsf_req - > req_id ;
2005-09-13 23:47:52 +04:00
/* associate SCSI command with FSF request */
fsf_req - > data = ( unsigned long ) scsi_cmnd ;
2005-04-17 02:20:36 +04:00
/* set handles of unit and its parent port in QTCB */
fsf_req - > qtcb - > header . lun_handle = unit - > handle ;
fsf_req - > qtcb - > header . port_handle = unit - > port - > handle ;
/* FSF does not define the structure of the FCP_CMND IU */
fcp_cmnd_iu = ( struct fcp_cmnd_iu * )
& ( fsf_req - > qtcb - > bottom . io . fcp_cmnd ) ;
/*
* set depending on data direction :
* data direction bits in SBALE ( SB Type )
* data direction bits in QTCB
* data direction bits in FCP_CMND IU
*/
switch ( scsi_cmnd - > sc_data_direction ) {
case DMA_NONE :
fsf_req - > qtcb - > bottom . io . data_direction = FSF_DATADIR_CMND ;
/*
* FIXME ( qdio ) :
* what is the correct type for commands
* without ' real ' data buffers ?
*/
sbtype = SBAL_FLAGS0_TYPE_READ ;
break ;
case DMA_FROM_DEVICE :
fsf_req - > qtcb - > bottom . io . data_direction = FSF_DATADIR_READ ;
sbtype = SBAL_FLAGS0_TYPE_READ ;
fcp_cmnd_iu - > rddata = 1 ;
break ;
case DMA_TO_DEVICE :
fsf_req - > qtcb - > bottom . io . data_direction = FSF_DATADIR_WRITE ;
sbtype = SBAL_FLAGS0_TYPE_WRITE ;
fcp_cmnd_iu - > wddata = 1 ;
break ;
case DMA_BIDIRECTIONAL :
default :
/*
* dummy , catch this condition earlier
* in zfcp_scsi_queuecommand
*/
goto failed_scsi_cmnd ;
}
/* set FC service class in QTCB (3 per default) */
2006-05-22 20:18:19 +04:00
fsf_req - > qtcb - > bottom . io . service_class = ZFCP_FC_SERVICE_CLASS_DEFAULT ;
2005-04-17 02:20:36 +04:00
/* set FCP_LUN in FCP_CMND IU in QTCB */
fcp_cmnd_iu - > fcp_lun = unit - > fcp_lun ;
mask = ZFCP_STATUS_UNIT_READONLY | ZFCP_STATUS_UNIT_SHARED ;
/* set task attributes in FCP_CMND IU in QTCB */
if ( likely ( ( scsi_cmnd - > device - > simple_tags ) | |
( atomic_test_mask ( mask , & unit - > status ) ) ) )
fcp_cmnd_iu - > task_attribute = SIMPLE_Q ;
else
fcp_cmnd_iu - > task_attribute = UNTAGGED ;
/* set additional length of FCP_CDB in FCP_CMND IU in QTCB, if needed */
if ( unlikely ( scsi_cmnd - > cmd_len > FCP_CDB_LENGTH ) ) {
fcp_cmnd_iu - > add_fcp_cdb_length
= ( scsi_cmnd - > cmd_len - FCP_CDB_LENGTH ) > > 2 ;
ZFCP_LOG_TRACE ( " SCSI CDB length is 0x%x, "
" additional FCP_CDB length is 0x%x "
" (shifted right 2 bits) \n " ,
scsi_cmnd - > cmd_len ,
fcp_cmnd_iu - > add_fcp_cdb_length ) ;
}
/*
* copy SCSI CDB ( including additional length , if any ) to
* FCP_CDB in FCP_CMND IU in QTCB
*/
memcpy ( fcp_cmnd_iu - > fcp_cdb , scsi_cmnd - > cmnd , scsi_cmnd - > cmd_len ) ;
/* FCP CMND IU length in QTCB */
fsf_req - > qtcb - > bottom . io . fcp_cmnd_length =
sizeof ( struct fcp_cmnd_iu ) +
fcp_cmnd_iu - > add_fcp_cdb_length + sizeof ( fcp_dl_t ) ;
/* generate SBALEs from data buffer */
real_bytes = zfcp_qdio_sbals_from_scsicmnd ( fsf_req , sbtype , scsi_cmnd ) ;
if ( unlikely ( real_bytes < 0 ) ) {
if ( fsf_req - > sbal_number < ZFCP_MAX_SBALS_PER_REQ ) {
ZFCP_LOG_DEBUG (
" Data did not fit into available buffer(s), "
" waiting for more... \n " ) ;
retval = - EIO ;
} else {
ZFCP_LOG_NORMAL ( " error: No truncation implemented but "
" required. Shutting down unit "
" (adapter %s, port 0x%016Lx, "
" unit 0x%016Lx) \n " ,
zfcp_get_busid_by_unit ( unit ) ,
unit - > port - > wwpn ,
unit - > fcp_lun ) ;
zfcp_erp_unit_shutdown ( unit , 0 ) ;
retval = - EINVAL ;
}
goto no_fit ;
}
/* set length of FCP data length in FCP_CMND IU in QTCB */
zfcp_set_fcp_dl ( fcp_cmnd_iu , real_bytes ) ;
ZFCP_LOG_DEBUG ( " Sending SCSI command: \n " ) ;
ZFCP_HEX_DUMP ( ZFCP_LOG_LEVEL_DEBUG ,
( char * ) scsi_cmnd - > cmnd , scsi_cmnd - > cmd_len ) ;
2006-09-19 00:29:56 +04:00
if ( use_timer )
zfcp_fsf_start_timer ( fsf_req , ZFCP_FSF_REQUEST_TIMEOUT ) ;
retval = zfcp_fsf_req_send ( fsf_req ) ;
2005-04-17 02:20:36 +04:00
if ( unlikely ( retval < 0 ) ) {
ZFCP_LOG_INFO ( " error: Could not send FCP command request "
" on adapter %s, port 0x%016Lx, unit 0x%016Lx \n " ,
zfcp_get_busid_by_adapter ( adapter ) ,
unit - > port - > wwpn ,
unit - > fcp_lun ) ;
goto send_failed ;
}
ZFCP_LOG_TRACE ( " Send FCP Command initiated (adapter %s, "
" port 0x%016Lx, unit 0x%016Lx) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ,
unit - > port - > wwpn ,
unit - > fcp_lun ) ;
goto success ;
send_failed :
no_fit :
failed_scsi_cmnd :
2005-09-13 23:47:52 +04:00
zfcp_unit_put ( unit ) ;
2005-04-17 02:20:36 +04:00
zfcp_fsf_req_free ( fsf_req ) ;
fsf_req = NULL ;
scsi_cmnd - > host_scribble = NULL ;
success :
failed_req_create :
write_unlock_irqrestore ( & adapter - > request_queue . queue_lock , lock_flags ) ;
return retval ;
}
struct zfcp_fsf_req *
zfcp_fsf_send_fcp_command_task_management ( struct zfcp_adapter * adapter ,
struct zfcp_unit * unit ,
u8 tm_flags , int req_flags )
{
struct zfcp_fsf_req * fsf_req = NULL ;
int retval = 0 ;
struct fcp_cmnd_iu * fcp_cmnd_iu ;
unsigned long lock_flags ;
volatile struct qdio_buffer_element * sbale ;
/* setup new FSF request */
retval = zfcp_fsf_req_create ( adapter , FSF_QTCB_FCP_CMND , req_flags ,
adapter - > pool . fsf_req_scsi ,
& lock_flags , & fsf_req ) ;
if ( retval < 0 ) {
ZFCP_LOG_INFO ( " error: Could not create FCP command (task "
" management) request for adapter %s, port "
" 0x%016Lx, unit 0x%016Lx. \n " ,
zfcp_get_busid_by_adapter ( adapter ) ,
unit - > port - > wwpn , unit - > fcp_lun ) ;
goto out ;
}
/*
* Used to decide on proper handler in the return path ,
* could be either zfcp_fsf_send_fcp_command_task_handler or
* zfcp_fsf_send_fcp_command_task_management_handler */
fsf_req - > status | = ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT ;
/*
* hold a pointer to the unit being target of this
* task management request
*/
2005-09-13 23:47:52 +04:00
fsf_req - > data = ( unsigned long ) unit ;
2005-04-17 02:20:36 +04:00
/* set FSF related fields in QTCB */
fsf_req - > qtcb - > header . lun_handle = unit - > handle ;
fsf_req - > qtcb - > header . port_handle = unit - > port - > handle ;
fsf_req - > qtcb - > bottom . io . data_direction = FSF_DATADIR_CMND ;
2006-05-22 20:18:19 +04:00
fsf_req - > qtcb - > bottom . io . service_class = ZFCP_FC_SERVICE_CLASS_DEFAULT ;
2005-04-17 02:20:36 +04:00
fsf_req - > qtcb - > bottom . io . fcp_cmnd_length =
sizeof ( struct fcp_cmnd_iu ) + sizeof ( fcp_dl_t ) ;
sbale = zfcp_qdio_sbale_req ( fsf_req , fsf_req - > sbal_curr , 0 ) ;
sbale [ 0 ] . flags | = SBAL_FLAGS0_TYPE_WRITE ;
sbale [ 1 ] . flags | = SBAL_FLAGS_LAST_ENTRY ;
/* set FCP related fields in FCP_CMND IU in QTCB */
fcp_cmnd_iu = ( struct fcp_cmnd_iu * )
& ( fsf_req - > qtcb - > bottom . io . fcp_cmnd ) ;
fcp_cmnd_iu - > fcp_lun = unit - > fcp_lun ;
fcp_cmnd_iu - > task_management_flags = tm_flags ;
2006-09-19 00:29:56 +04:00
zfcp_fsf_start_timer ( fsf_req , ZFCP_SCSI_ER_TIMEOUT ) ;
retval = zfcp_fsf_req_send ( fsf_req ) ;
2005-04-17 02:20:36 +04:00
if ( retval ) {
ZFCP_LOG_INFO ( " error: Could not send an FCP-command (task "
" management) on adapter %s, port 0x%016Lx for "
" unit LUN 0x%016Lx \n " ,
zfcp_get_busid_by_adapter ( adapter ) ,
unit - > port - > wwpn ,
unit - > fcp_lun ) ;
zfcp_fsf_req_free ( fsf_req ) ;
fsf_req = NULL ;
goto out ;
}
ZFCP_LOG_TRACE ( " Send FCP Command (task management function) initiated "
" (adapter %s, port 0x%016Lx, unit 0x%016Lx, "
" tm_flags=0x%x) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ,
unit - > port - > wwpn ,
unit - > fcp_lun ,
tm_flags ) ;
out :
write_unlock_irqrestore ( & adapter - > request_queue . queue_lock , lock_flags ) ;
return fsf_req ;
}
/*
* function : zfcp_fsf_send_fcp_command_handler
*
* purpose : is called for finished Send FCP Command
*
* returns :
*/
static int
zfcp_fsf_send_fcp_command_handler ( struct zfcp_fsf_req * fsf_req )
{
int retval = - EINVAL ;
struct zfcp_unit * unit ;
struct fsf_qtcb_header * header ;
u16 subtable , rule , counter ;
header = & fsf_req - > qtcb - > header ;
if ( unlikely ( fsf_req - > status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT ) )
2005-09-13 23:47:52 +04:00
unit = ( struct zfcp_unit * ) fsf_req - > data ;
2005-04-17 02:20:36 +04:00
else
2005-09-13 23:47:52 +04:00
unit = fsf_req - > unit ;
2005-04-17 02:20:36 +04:00
if ( unlikely ( fsf_req - > status & ZFCP_STATUS_FSFREQ_ERROR ) ) {
/* go directly to calls of special handlers */
goto skip_fsfstatus ;
}
/* evaluate FSF status in QTCB */
switch ( header - > fsf_status ) {
case FSF_PORT_HANDLE_NOT_VALID :
ZFCP_LOG_INFO ( " Temporary port identifier 0x%x for port "
" 0x%016Lx on adapter %s invalid \n " ,
unit - > port - > handle ,
unit - > port - > wwpn , zfcp_get_busid_by_unit ( unit ) ) ;
ZFCP_HEX_DUMP ( ZFCP_LOG_LEVEL_DEBUG ,
( char * ) & header - > fsf_status_qual ,
sizeof ( union fsf_status_qual ) ) ;
debug_text_event ( fsf_req - > adapter - > erp_dbf , 1 ,
" fsf_s_phand_nv " ) ;
zfcp_erp_adapter_reopen ( unit - > port - > adapter , 0 ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_LUN_HANDLE_NOT_VALID :
ZFCP_LOG_INFO ( " Temporary LUN identifier 0x%x for unit "
" 0x%016Lx on port 0x%016Lx on adapter %s is "
" invalid. This may happen occasionally. \n " ,
unit - > handle ,
unit - > fcp_lun ,
unit - > port - > wwpn ,
zfcp_get_busid_by_unit ( unit ) ) ;
ZFCP_LOG_NORMAL ( " Status qualifier data: \n " ) ;
ZFCP_HEX_DUMP ( ZFCP_LOG_LEVEL_NORMAL ,
( char * ) & header - > fsf_status_qual ,
sizeof ( union fsf_status_qual ) ) ;
debug_text_event ( fsf_req - > adapter - > erp_dbf , 1 ,
" fsf_s_uhand_nv " ) ;
zfcp_erp_port_reopen ( unit - > port , 0 ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_HANDLE_MISMATCH :
ZFCP_LOG_NORMAL ( " bug: The port handle 0x%x has changed "
" unexpectedly. (adapter %s, port 0x%016Lx, "
" unit 0x%016Lx) \n " ,
unit - > port - > handle ,
zfcp_get_busid_by_unit ( unit ) ,
unit - > port - > wwpn ,
unit - > fcp_lun ) ;
ZFCP_LOG_NORMAL ( " status qualifier: \n " ) ;
ZFCP_HEX_DUMP ( ZFCP_LOG_LEVEL_NORMAL ,
( char * ) & header - > fsf_status_qual ,
sizeof ( union fsf_status_qual ) ) ;
debug_text_event ( fsf_req - > adapter - > erp_dbf , 1 ,
" fsf_s_hand_mis " ) ;
zfcp_erp_adapter_reopen ( unit - > port - > adapter , 0 ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_SERVICE_CLASS_NOT_SUPPORTED :
2006-05-22 20:18:19 +04:00
ZFCP_LOG_INFO ( " error: adapter %s does not support fc "
" class %d. \n " ,
zfcp_get_busid_by_unit ( unit ) ,
ZFCP_FC_SERVICE_CLASS_DEFAULT ) ;
2005-04-17 02:20:36 +04:00
/* stop operation for this adapter */
debug_text_exception ( fsf_req - > adapter - > erp_dbf , 0 ,
" fsf_s_class_nsup " ) ;
zfcp_erp_adapter_shutdown ( unit - > port - > adapter , 0 ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_FCPLUN_NOT_VALID :
ZFCP_LOG_NORMAL ( " bug: unit 0x%016Lx on port 0x%016Lx on "
" adapter %s does not have correct unit "
" handle 0x%x \n " ,
unit - > fcp_lun ,
unit - > port - > wwpn ,
zfcp_get_busid_by_unit ( unit ) ,
unit - > handle ) ;
ZFCP_LOG_DEBUG ( " status qualifier: \n " ) ;
ZFCP_HEX_DUMP ( ZFCP_LOG_LEVEL_DEBUG ,
( char * ) & header - > fsf_status_qual ,
sizeof ( union fsf_status_qual ) ) ;
debug_text_event ( fsf_req - > adapter - > erp_dbf , 1 ,
" fsf_s_fcp_lun_nv " ) ;
zfcp_erp_port_reopen ( unit - > port , 0 ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_ACCESS_DENIED :
ZFCP_LOG_NORMAL ( " Access denied, cannot send FCP command to "
" unit 0x%016Lx on port 0x%016Lx on "
" adapter %s \n " , unit - > fcp_lun , unit - > port - > wwpn ,
zfcp_get_busid_by_unit ( unit ) ) ;
for ( counter = 0 ; counter < 2 ; counter + + ) {
subtable = header - > fsf_status_qual . halfword [ counter * 2 ] ;
rule = header - > fsf_status_qual . halfword [ counter * 2 + 1 ] ;
switch ( subtable ) {
case FSF_SQ_CFDC_SUBTABLE_OS :
case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN :
case FSF_SQ_CFDC_SUBTABLE_PORT_DID :
case FSF_SQ_CFDC_SUBTABLE_LUN :
ZFCP_LOG_INFO ( " Access denied (%s rule %d) \n " ,
zfcp_act_subtable_type [ subtable ] , rule ) ;
break ;
}
}
debug_text_event ( fsf_req - > adapter - > erp_dbf , 1 , " fsf_s_access " ) ;
zfcp_erp_unit_access_denied ( unit ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_DIRECTION_INDICATOR_NOT_VALID :
ZFCP_LOG_INFO ( " bug: Invalid data direction given for unit "
" 0x%016Lx on port 0x%016Lx on adapter %s "
" (debug info %d) \n " ,
unit - > fcp_lun ,
unit - > port - > wwpn ,
zfcp_get_busid_by_unit ( unit ) ,
fsf_req - > qtcb - > bottom . io . data_direction ) ;
/* stop operation for this adapter */
debug_text_event ( fsf_req - > adapter - > erp_dbf , 0 ,
" fsf_s_dir_ind_nv " ) ;
zfcp_erp_adapter_shutdown ( unit - > port - > adapter , 0 ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_CMND_LENGTH_NOT_VALID :
ZFCP_LOG_NORMAL
( " bug: An invalid control-data-block length field "
" was found in a command for unit 0x%016Lx on port "
" 0x%016Lx on adapter %s " " (debug info %d) \n " ,
unit - > fcp_lun , unit - > port - > wwpn ,
zfcp_get_busid_by_unit ( unit ) ,
fsf_req - > qtcb - > bottom . io . fcp_cmnd_length ) ;
/* stop operation for this adapter */
debug_text_event ( fsf_req - > adapter - > erp_dbf , 0 ,
" fsf_s_cmd_len_nv " ) ;
zfcp_erp_adapter_shutdown ( unit - > port - > adapter , 0 ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
break ;
case FSF_PORT_BOXED :
ZFCP_LOG_DEBUG ( " The remote port 0x%016Lx on adapter %s "
" needs to be reopened \n " ,
unit - > port - > wwpn , zfcp_get_busid_by_unit ( unit ) ) ;
debug_text_event ( fsf_req - > adapter - > erp_dbf , 2 , " fsf_s_pboxed " ) ;
2005-06-13 15:23:57 +04:00
zfcp_erp_port_boxed ( unit - > port ) ;
2005-04-17 02:20:36 +04:00
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR |
ZFCP_STATUS_FSFREQ_RETRY ;
break ;
case FSF_LUN_BOXED :
ZFCP_LOG_NORMAL ( " unit needs to be reopened (adapter %s, "
" wwpn=0x%016Lx, fcp_lun=0x%016Lx) \n " ,
zfcp_get_busid_by_unit ( unit ) ,
unit - > port - > wwpn , unit - > fcp_lun ) ;
debug_text_event ( fsf_req - > adapter - > erp_dbf , 1 , " fsf_s_lboxed " ) ;
2005-06-13 15:23:57 +04:00
zfcp_erp_unit_boxed ( unit ) ;
2005-04-17 02:20:36 +04:00
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR
| ZFCP_STATUS_FSFREQ_RETRY ;
break ;
case FSF_ADAPTER_STATUS_AVAILABLE :
switch ( header - > fsf_status_qual . word [ 0 ] ) {
case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE :
/* re-establish link to port */
debug_text_event ( fsf_req - > adapter - > erp_dbf , 1 ,
" fsf_sq_ltest " ) ;
2005-06-13 15:16:27 +04:00
zfcp_test_link ( unit - > port ) ;
2005-04-17 02:20:36 +04:00
break ;
case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED :
/* FIXME(hw) need proper specs for proper action */
/* let scsi stack deal with retries and escalation */
debug_text_event ( fsf_req - > adapter - > erp_dbf , 1 ,
" fsf_sq_ulp " ) ;
break ;
default :
ZFCP_LOG_NORMAL
2005-06-13 15:17:44 +04:00
( " Unknown status qualifier 0x%x arrived. \n " ,
2005-04-17 02:20:36 +04:00
header - > fsf_status_qual . word [ 0 ] ) ;
debug_text_event ( fsf_req - > adapter - > erp_dbf , 0 ,
" fsf_sq_inval: " ) ;
debug_exception ( fsf_req - > adapter - > erp_dbf , 0 ,
& header - > fsf_status_qual . word [ 0 ] ,
sizeof ( u32 ) ) ;
break ;
}
2005-06-13 15:17:44 +04:00
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
2005-04-17 02:20:36 +04:00
break ;
case FSF_GOOD :
break ;
case FSF_FCP_RSP_AVAILABLE :
break ;
default :
debug_text_event ( fsf_req - > adapter - > erp_dbf , 0 , " fsf_s_inval: " ) ;
debug_exception ( fsf_req - > adapter - > erp_dbf , 0 ,
& header - > fsf_status , sizeof ( u32 ) ) ;
break ;
}
skip_fsfstatus :
if ( fsf_req - > status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT ) {
retval =
zfcp_fsf_send_fcp_command_task_management_handler ( fsf_req ) ;
} else {
retval = zfcp_fsf_send_fcp_command_task_handler ( fsf_req ) ;
2005-09-13 23:47:52 +04:00
fsf_req - > unit = NULL ;
zfcp_unit_put ( unit ) ;
2005-04-17 02:20:36 +04:00
}
return retval ;
}
/*
* function : zfcp_fsf_send_fcp_command_task_handler
*
* purpose : evaluates FCP_RSP IU
*
* returns :
*/
static int
zfcp_fsf_send_fcp_command_task_handler ( struct zfcp_fsf_req * fsf_req )
{
int retval = 0 ;
struct scsi_cmnd * scpnt ;
struct fcp_rsp_iu * fcp_rsp_iu = ( struct fcp_rsp_iu * )
& ( fsf_req - > qtcb - > bottom . io . fcp_rsp ) ;
struct fcp_cmnd_iu * fcp_cmnd_iu = ( struct fcp_cmnd_iu * )
& ( fsf_req - > qtcb - > bottom . io . fcp_cmnd ) ;
u32 sns_len ;
char * fcp_rsp_info = zfcp_get_fcp_rsp_info_ptr ( fcp_rsp_iu ) ;
unsigned long flags ;
2005-09-13 23:47:52 +04:00
struct zfcp_unit * unit = fsf_req - > unit ;
2005-04-17 02:20:36 +04:00
read_lock_irqsave ( & fsf_req - > adapter - > abort_lock , flags ) ;
2005-09-13 23:47:52 +04:00
scpnt = ( struct scsi_cmnd * ) fsf_req - > data ;
2005-04-17 02:20:36 +04:00
if ( unlikely ( ! scpnt ) ) {
ZFCP_LOG_DEBUG
( " Command with fsf_req %p is not associated to "
" a scsi command anymore. Aborted? \n " , fsf_req ) ;
goto out ;
}
if ( unlikely ( fsf_req - > status & ZFCP_STATUS_FSFREQ_ABORTED ) ) {
/* FIXME: (design) mid-layer should handle DID_ABORT like
* DID_SOFT_ERROR by retrying the request for devices
* that allow retries .
*/
ZFCP_LOG_DEBUG ( " Setting DID_SOFT_ERROR and SUGGEST_RETRY \n " ) ;
set_host_byte ( & scpnt - > result , DID_SOFT_ERROR ) ;
set_driver_byte ( & scpnt - > result , SUGGEST_RETRY ) ;
goto skip_fsfstatus ;
}
if ( unlikely ( fsf_req - > status & ZFCP_STATUS_FSFREQ_ERROR ) ) {
ZFCP_LOG_DEBUG ( " Setting DID_ERROR \n " ) ;
set_host_byte ( & scpnt - > result , DID_ERROR ) ;
goto skip_fsfstatus ;
}
/* set message byte of result in SCSI command */
scpnt - > result | = COMMAND_COMPLETE < < 8 ;
/*
* copy SCSI status code of FCP_STATUS of FCP_RSP IU to status byte
* of result in SCSI command
*/
scpnt - > result | = fcp_rsp_iu - > scsi_status ;
if ( unlikely ( fcp_rsp_iu - > scsi_status ) ) {
/* DEBUG */
ZFCP_LOG_DEBUG ( " status for SCSI Command: \n " ) ;
ZFCP_HEX_DUMP ( ZFCP_LOG_LEVEL_DEBUG ,
scpnt - > cmnd , scpnt - > cmd_len ) ;
ZFCP_LOG_DEBUG ( " SCSI status code 0x%x \n " ,
fcp_rsp_iu - > scsi_status ) ;
ZFCP_HEX_DUMP ( ZFCP_LOG_LEVEL_DEBUG ,
( void * ) fcp_rsp_iu , sizeof ( struct fcp_rsp_iu ) ) ;
ZFCP_HEX_DUMP ( ZFCP_LOG_LEVEL_DEBUG ,
zfcp_get_fcp_sns_info_ptr ( fcp_rsp_iu ) ,
fcp_rsp_iu - > fcp_sns_len ) ;
}
/* check FCP_RSP_INFO */
if ( unlikely ( fcp_rsp_iu - > validity . bits . fcp_rsp_len_valid ) ) {
ZFCP_LOG_DEBUG ( " rsp_len is valid \n " ) ;
switch ( fcp_rsp_info [ 3 ] ) {
case RSP_CODE_GOOD :
/* ok, continue */
ZFCP_LOG_TRACE ( " no failure or Task Management "
" Function complete \n " ) ;
set_host_byte ( & scpnt - > result , DID_OK ) ;
break ;
case RSP_CODE_LENGTH_MISMATCH :
/* hardware bug */
ZFCP_LOG_NORMAL ( " bug: FCP response code indictates "
" that the fibrechannel protocol data "
" length differs from the burst length. "
" The problem occured on unit 0x%016Lx "
" on port 0x%016Lx on adapter %s " ,
unit - > fcp_lun ,
unit - > port - > wwpn ,
zfcp_get_busid_by_unit ( unit ) ) ;
/* dump SCSI CDB as prepared by zfcp */
ZFCP_HEX_DUMP ( ZFCP_LOG_LEVEL_DEBUG ,
( char * ) & fsf_req - > qtcb - >
bottom . io . fcp_cmnd , FSF_FCP_CMND_SIZE ) ;
set_host_byte ( & scpnt - > result , DID_ERROR ) ;
goto skip_fsfstatus ;
case RSP_CODE_FIELD_INVALID :
/* driver or hardware bug */
ZFCP_LOG_NORMAL ( " bug: FCP response code indictates "
" that the fibrechannel protocol data "
" fields were incorrectly set up. "
" The problem occured on the unit "
" 0x%016Lx on port 0x%016Lx on "
" adapter %s " ,
unit - > fcp_lun ,
unit - > port - > wwpn ,
zfcp_get_busid_by_unit ( unit ) ) ;
/* dump SCSI CDB as prepared by zfcp */
ZFCP_HEX_DUMP ( ZFCP_LOG_LEVEL_DEBUG ,
( char * ) & fsf_req - > qtcb - >
bottom . io . fcp_cmnd , FSF_FCP_CMND_SIZE ) ;
set_host_byte ( & scpnt - > result , DID_ERROR ) ;
goto skip_fsfstatus ;
case RSP_CODE_RO_MISMATCH :
/* hardware bug */
ZFCP_LOG_NORMAL ( " bug: The FCP response code indicates "
" that conflicting values for the "
" fibrechannel payload offset from the "
" header were found. "
" The problem occured on unit 0x%016Lx "
" on port 0x%016Lx on adapter %s. \n " ,
unit - > fcp_lun ,
unit - > port - > wwpn ,
zfcp_get_busid_by_unit ( unit ) ) ;
/* dump SCSI CDB as prepared by zfcp */
ZFCP_HEX_DUMP ( ZFCP_LOG_LEVEL_DEBUG ,
( char * ) & fsf_req - > qtcb - >
bottom . io . fcp_cmnd , FSF_FCP_CMND_SIZE ) ;
set_host_byte ( & scpnt - > result , DID_ERROR ) ;
goto skip_fsfstatus ;
default :
ZFCP_LOG_NORMAL ( " bug: An invalid FCP response "
" code was detected for a command. "
" The problem occured on the unit "
" 0x%016Lx on port 0x%016Lx on "
" adapter %s (debug info 0x%x) \n " ,
unit - > fcp_lun ,
unit - > port - > wwpn ,
zfcp_get_busid_by_unit ( unit ) ,
fcp_rsp_info [ 3 ] ) ;
/* dump SCSI CDB as prepared by zfcp */
ZFCP_HEX_DUMP ( ZFCP_LOG_LEVEL_DEBUG ,
( char * ) & fsf_req - > qtcb - >
bottom . io . fcp_cmnd , FSF_FCP_CMND_SIZE ) ;
set_host_byte ( & scpnt - > result , DID_ERROR ) ;
2005-04-11 08:04:28 +04:00
goto skip_fsfstatus ;
2005-04-17 02:20:36 +04:00
}
}
/* check for sense data */
if ( unlikely ( fcp_rsp_iu - > validity . bits . fcp_sns_len_valid ) ) {
sns_len = FSF_FCP_RSP_SIZE -
sizeof ( struct fcp_rsp_iu ) + fcp_rsp_iu - > fcp_rsp_len ;
ZFCP_LOG_TRACE ( " room for %i bytes sense data in QTCB \n " ,
sns_len ) ;
sns_len = min ( sns_len , ( u32 ) SCSI_SENSE_BUFFERSIZE ) ;
ZFCP_LOG_TRACE ( " room for %i bytes sense data in SCSI command \n " ,
SCSI_SENSE_BUFFERSIZE ) ;
sns_len = min ( sns_len , fcp_rsp_iu - > fcp_sns_len ) ;
ZFCP_LOG_TRACE ( " scpnt->result =0x%x, command was: \n " ,
scpnt - > result ) ;
ZFCP_HEX_DUMP ( ZFCP_LOG_LEVEL_TRACE ,
( void * ) & scpnt - > cmnd , scpnt - > cmd_len ) ;
ZFCP_LOG_TRACE ( " %i bytes sense data provided by FCP \n " ,
fcp_rsp_iu - > fcp_sns_len ) ;
memcpy ( & scpnt - > sense_buffer ,
zfcp_get_fcp_sns_info_ptr ( fcp_rsp_iu ) , sns_len ) ;
ZFCP_HEX_DUMP ( ZFCP_LOG_LEVEL_TRACE ,
( void * ) & scpnt - > sense_buffer , sns_len ) ;
}
/* check for overrun */
if ( unlikely ( fcp_rsp_iu - > validity . bits . fcp_resid_over ) ) {
ZFCP_LOG_INFO ( " A data overrun was detected for a command. "
" unit 0x%016Lx, port 0x%016Lx, adapter %s. "
" The response data length is "
" %d, the original length was %d. \n " ,
unit - > fcp_lun ,
unit - > port - > wwpn ,
zfcp_get_busid_by_unit ( unit ) ,
fcp_rsp_iu - > fcp_resid ,
( int ) zfcp_get_fcp_dl ( fcp_cmnd_iu ) ) ;
}
/* check for underrun */
if ( unlikely ( fcp_rsp_iu - > validity . bits . fcp_resid_under ) ) {
ZFCP_LOG_INFO ( " A data underrun was detected for a command. "
" unit 0x%016Lx, port 0x%016Lx, adapter %s. "
" The response data length is "
" %d, the original length was %d. \n " ,
unit - > fcp_lun ,
unit - > port - > wwpn ,
zfcp_get_busid_by_unit ( unit ) ,
fcp_rsp_iu - > fcp_resid ,
( int ) zfcp_get_fcp_dl ( fcp_cmnd_iu ) ) ;
scpnt - > resid = fcp_rsp_iu - > fcp_resid ;
if ( scpnt - > request_bufflen - scpnt - > resid < scpnt - > underflow )
2005-04-11 08:04:28 +04:00
set_host_byte ( & scpnt - > result , DID_ERROR ) ;
2005-04-17 02:20:36 +04:00
}
skip_fsfstatus :
ZFCP_LOG_DEBUG ( " scpnt->result =0x%x \n " , scpnt - > result ) ;
2005-09-13 23:50:38 +04:00
if ( scpnt - > result ! = 0 )
2006-02-11 03:42:58 +03:00
zfcp_scsi_dbf_event_result ( " erro " , 3 , fsf_req - > adapter , scpnt , fsf_req ) ;
2005-09-13 23:50:38 +04:00
else if ( scpnt - > retries > 0 )
2006-02-11 03:42:58 +03:00
zfcp_scsi_dbf_event_result ( " retr " , 4 , fsf_req - > adapter , scpnt , fsf_req ) ;
2005-09-13 23:50:38 +04:00
else
2006-02-11 03:42:58 +03:00
zfcp_scsi_dbf_event_result ( " norm " , 6 , fsf_req - > adapter , scpnt , fsf_req ) ;
2005-04-17 02:20:36 +04:00
/* cleanup pointer (need this especially for abort) */
scpnt - > host_scribble = NULL ;
/* always call back */
( scpnt - > scsi_done ) ( scpnt ) ;
/*
* We must hold this lock until scsi_done has been called .
* Otherwise we may call scsi_done after abort regarding this
* command has completed .
* Note : scsi_done must not block !
*/
out :
read_unlock_irqrestore ( & fsf_req - > adapter - > abort_lock , flags ) ;
return retval ;
}
/*
* function : zfcp_fsf_send_fcp_command_task_management_handler
*
* purpose : evaluates FCP_RSP IU
*
* returns :
*/
static int
zfcp_fsf_send_fcp_command_task_management_handler ( struct zfcp_fsf_req * fsf_req )
{
int retval = 0 ;
struct fcp_rsp_iu * fcp_rsp_iu = ( struct fcp_rsp_iu * )
& ( fsf_req - > qtcb - > bottom . io . fcp_rsp ) ;
char * fcp_rsp_info = zfcp_get_fcp_rsp_info_ptr ( fcp_rsp_iu ) ;
2005-09-13 23:47:52 +04:00
struct zfcp_unit * unit = ( struct zfcp_unit * ) fsf_req - > data ;
2005-04-17 02:20:36 +04:00
if ( fsf_req - > status & ZFCP_STATUS_FSFREQ_ERROR ) {
fsf_req - > status | = ZFCP_STATUS_FSFREQ_TMFUNCFAILED ;
goto skip_fsfstatus ;
}
/* check FCP_RSP_INFO */
switch ( fcp_rsp_info [ 3 ] ) {
case RSP_CODE_GOOD :
/* ok, continue */
ZFCP_LOG_DEBUG ( " no failure or Task Management "
" Function complete \n " ) ;
break ;
case RSP_CODE_TASKMAN_UNSUPP :
ZFCP_LOG_NORMAL ( " bug: A reuested task management function "
" is not supported on the target device "
" unit 0x%016Lx, port 0x%016Lx, adapter %s \n " ,
unit - > fcp_lun ,
unit - > port - > wwpn ,
zfcp_get_busid_by_unit ( unit ) ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP ;
break ;
case RSP_CODE_TASKMAN_FAILED :
ZFCP_LOG_NORMAL ( " bug: A reuested task management function "
" failed to complete successfully. "
" unit 0x%016Lx, port 0x%016Lx, adapter %s. \n " ,
unit - > fcp_lun ,
unit - > port - > wwpn ,
zfcp_get_busid_by_unit ( unit ) ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_TMFUNCFAILED ;
break ;
default :
ZFCP_LOG_NORMAL ( " bug: An invalid FCP response "
" code was detected for a command. "
" unit 0x%016Lx, port 0x%016Lx, adapter %s "
" (debug info 0x%x) \n " ,
unit - > fcp_lun ,
unit - > port - > wwpn ,
zfcp_get_busid_by_unit ( unit ) ,
fcp_rsp_info [ 3 ] ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_TMFUNCFAILED ;
}
skip_fsfstatus :
return retval ;
}
/*
* function : zfcp_fsf_control_file
*
* purpose : Initiator of the control file upload / download FSF requests
*
* returns : 0 - FSF request is successfuly created and queued
* - EOPNOTSUPP - The FCP adapter does not have Control File support
* - EINVAL - Invalid direction specified
* - ENOMEM - Insufficient memory
* - EPERM - Cannot create FSF request or place it in QDIO queue
*/
int
zfcp_fsf_control_file ( struct zfcp_adapter * adapter ,
struct zfcp_fsf_req * * fsf_req_ptr ,
u32 fsf_command ,
u32 option ,
struct zfcp_sg_list * sg_list )
{
struct zfcp_fsf_req * fsf_req ;
struct fsf_qtcb_bottom_support * bottom ;
volatile struct qdio_buffer_element * sbale ;
unsigned long lock_flags ;
int req_flags = 0 ;
int direction ;
int retval = 0 ;
2005-09-13 23:51:16 +04:00
if ( ! ( adapter - > adapter_features & FSF_FEATURE_CFDC ) ) {
2005-04-17 02:20:36 +04:00
ZFCP_LOG_INFO ( " cfdc not supported (adapter %s) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
retval = - EOPNOTSUPP ;
goto out ;
}
switch ( fsf_command ) {
case FSF_QTCB_DOWNLOAD_CONTROL_FILE :
direction = SBAL_FLAGS0_TYPE_WRITE ;
if ( ( option ! = FSF_CFDC_OPTION_FULL_ACCESS ) & &
( option ! = FSF_CFDC_OPTION_RESTRICTED_ACCESS ) )
req_flags = ZFCP_WAIT_FOR_SBAL ;
break ;
case FSF_QTCB_UPLOAD_CONTROL_FILE :
direction = SBAL_FLAGS0_TYPE_READ ;
break ;
default :
ZFCP_LOG_INFO ( " Invalid FSF command code 0x%08x \n " , fsf_command ) ;
retval = - EINVAL ;
goto out ;
}
retval = zfcp_fsf_req_create ( adapter , fsf_command , req_flags ,
NULL , & lock_flags , & fsf_req ) ;
if ( retval < 0 ) {
ZFCP_LOG_INFO ( " error: Could not create FSF request for the "
" adapter %s \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
retval = - EPERM ;
goto unlock_queue_lock ;
}
sbale = zfcp_qdio_sbale_req ( fsf_req , fsf_req - > sbal_curr , 0 ) ;
sbale [ 0 ] . flags | = direction ;
bottom = & fsf_req - > qtcb - > bottom . support ;
bottom - > operation_subtype = FSF_CFDC_OPERATION_SUBTYPE ;
bottom - > option = option ;
if ( sg_list - > count > 0 ) {
int bytes ;
bytes = zfcp_qdio_sbals_from_sg ( fsf_req , direction ,
sg_list - > sg , sg_list - > count ,
ZFCP_MAX_SBALS_PER_REQ ) ;
if ( bytes ! = ZFCP_CFDC_MAX_CONTROL_FILE_SIZE ) {
ZFCP_LOG_INFO (
" error: Could not create sufficient number of "
" SBALS for an FSF request to the adapter %s \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
retval = - ENOMEM ;
goto free_fsf_req ;
}
} else
sbale [ 1 ] . flags | = SBAL_FLAGS_LAST_ENTRY ;
2006-09-19 00:29:56 +04:00
zfcp_fsf_start_timer ( fsf_req , ZFCP_FSF_REQUEST_TIMEOUT ) ;
retval = zfcp_fsf_req_send ( fsf_req ) ;
2005-04-17 02:20:36 +04:00
if ( retval < 0 ) {
ZFCP_LOG_INFO ( " initiation of cfdc up/download failed "
" (adapter %s) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
retval = - EPERM ;
goto free_fsf_req ;
}
write_unlock_irqrestore ( & adapter - > request_queue . queue_lock , lock_flags ) ;
ZFCP_LOG_NORMAL ( " Control file %s FSF request has been sent to the "
" adapter %s \n " ,
fsf_command = = FSF_QTCB_DOWNLOAD_CONTROL_FILE ?
" download " : " upload " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
wait_event ( fsf_req - > completion_wq ,
fsf_req - > status & ZFCP_STATUS_FSFREQ_COMPLETED ) ;
* fsf_req_ptr = fsf_req ;
2006-09-19 00:29:56 +04:00
goto out ;
2005-04-17 02:20:36 +04:00
free_fsf_req :
zfcp_fsf_req_free ( fsf_req ) ;
unlock_queue_lock :
write_unlock_irqrestore ( & adapter - > request_queue . queue_lock , lock_flags ) ;
out :
return retval ;
}
/*
* function : zfcp_fsf_control_file_handler
*
* purpose : Handler of the control file upload / download FSF requests
*
* returns : 0 - FSF request successfuly processed
* - EAGAIN - Operation has to be repeated because of a temporary problem
* - EACCES - There is no permission to execute an operation
* - EPERM - The control file is not in a right format
* - EIO - There is a problem with the FCP adapter
* - EINVAL - Invalid operation
* - EFAULT - User space memory I / O operation fault
*/
static int
zfcp_fsf_control_file_handler ( struct zfcp_fsf_req * fsf_req )
{
struct zfcp_adapter * adapter = fsf_req - > adapter ;
struct fsf_qtcb_header * header = & fsf_req - > qtcb - > header ;
struct fsf_qtcb_bottom_support * bottom = & fsf_req - > qtcb - > bottom . support ;
int retval = 0 ;
if ( fsf_req - > status & ZFCP_STATUS_FSFREQ_ERROR ) {
retval = - EINVAL ;
goto skip_fsfstatus ;
}
switch ( header - > fsf_status ) {
case FSF_GOOD :
ZFCP_LOG_NORMAL (
" The FSF request has been successfully completed "
" on the adapter %s \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
break ;
case FSF_OPERATION_PARTIALLY_SUCCESSFUL :
if ( bottom - > operation_subtype = = FSF_CFDC_OPERATION_SUBTYPE ) {
switch ( header - > fsf_status_qual . word [ 0 ] ) {
2005-04-11 08:04:28 +04:00
case FSF_SQ_CFDC_HARDENED_ON_SE :
ZFCP_LOG_NORMAL (
" CFDC on the adapter %s has being "
" hardened on primary and secondary SE \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
break ;
2005-04-17 02:20:36 +04:00
case FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE :
ZFCP_LOG_NORMAL (
" CFDC of the adapter %s could not "
" be saved on the SE \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
break ;
case FSF_SQ_CFDC_COULD_NOT_HARDEN_ON_SE2 :
ZFCP_LOG_NORMAL (
" CFDC of the adapter %s could not "
" be copied to the secondary SE \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
break ;
default :
ZFCP_LOG_NORMAL (
" CFDC could not be hardened "
" on the adapter %s \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
}
}
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
retval = - EAGAIN ;
break ;
case FSF_AUTHORIZATION_FAILURE :
ZFCP_LOG_NORMAL (
" Adapter %s does not accept privileged commands \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
retval = - EACCES ;
break ;
case FSF_CFDC_ERROR_DETECTED :
ZFCP_LOG_NORMAL (
" Error at position %d in the CFDC, "
" CFDC is discarded by the adapter %s \n " ,
header - > fsf_status_qual . word [ 0 ] ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
retval = - EPERM ;
break ;
case FSF_CONTROL_FILE_UPDATE_ERROR :
ZFCP_LOG_NORMAL (
" Adapter %s cannot harden the control file, "
" file is discarded \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
retval = - EIO ;
break ;
case FSF_CONTROL_FILE_TOO_LARGE :
ZFCP_LOG_NORMAL (
" Control file is too large, file is discarded "
" by the adapter %s \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
retval = - EIO ;
break ;
case FSF_ACCESS_CONFLICT_DETECTED :
if ( bottom - > operation_subtype = = FSF_CFDC_OPERATION_SUBTYPE )
ZFCP_LOG_NORMAL (
" CFDC has been discarded by the adapter %s, "
" because activation would impact "
" %d active connection(s) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ,
header - > fsf_status_qual . word [ 0 ] ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
retval = - EIO ;
break ;
case FSF_CONFLICTS_OVERRULED :
if ( bottom - > operation_subtype = = FSF_CFDC_OPERATION_SUBTYPE )
ZFCP_LOG_NORMAL (
" CFDC has been activated on the adapter %s, "
" but activation has impacted "
" %d active connection(s) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ,
header - > fsf_status_qual . word [ 0 ] ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
retval = - EIO ;
break ;
case FSF_UNKNOWN_OP_SUBTYPE :
ZFCP_LOG_NORMAL ( " unknown operation subtype (adapter: %s, "
" op_subtype=0x%x) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ,
bottom - > operation_subtype ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
retval = - EINVAL ;
break ;
case FSF_INVALID_COMMAND_OPTION :
ZFCP_LOG_NORMAL (
" Invalid option 0x%x has been specified "
" in QTCB bottom sent to the adapter %s \n " ,
bottom - > option ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
retval = - EINVAL ;
break ;
default :
ZFCP_LOG_NORMAL (
" bug: An unknown/unexpected FSF status 0x%08x "
" was presented on the adapter %s \n " ,
header - > fsf_status ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
debug_text_event ( fsf_req - > adapter - > erp_dbf , 0 , " fsf_sq_inval " ) ;
debug_exception ( fsf_req - > adapter - > erp_dbf , 0 ,
& header - > fsf_status_qual . word [ 0 ] , sizeof ( u32 ) ) ;
fsf_req - > status | = ZFCP_STATUS_FSFREQ_ERROR ;
retval = - EINVAL ;
break ;
}
skip_fsfstatus :
return retval ;
}
static inline int
zfcp_fsf_req_sbal_check ( unsigned long * flags ,
struct zfcp_qdio_queue * queue , int needed )
{
write_lock_irqsave ( & queue - > queue_lock , * flags ) ;
if ( likely ( atomic_read ( & queue - > free_count ) > = needed ) )
return 1 ;
write_unlock_irqrestore ( & queue - > queue_lock , * flags ) ;
return 0 ;
}
/*
* set qtcb pointer in fsf_req and initialize QTCB
*/
2007-02-05 23:18:53 +03:00
static void
2005-09-13 23:50:38 +04:00
zfcp_fsf_req_qtcb_init ( struct zfcp_fsf_req * fsf_req )
2005-04-17 02:20:36 +04:00
{
if ( likely ( fsf_req - > qtcb ! = NULL ) ) {
2006-08-02 13:05:16 +04:00
fsf_req - > qtcb - > prefix . req_seq_no =
fsf_req - > adapter - > fsf_req_seq_no ;
fsf_req - > qtcb - > prefix . req_id = fsf_req - > req_id ;
2005-04-17 02:20:36 +04:00
fsf_req - > qtcb - > prefix . ulp_info = ZFCP_ULP_INFO_VERSION ;
2006-08-02 13:05:16 +04:00
fsf_req - > qtcb - > prefix . qtcb_type =
fsf_qtcb_type [ fsf_req - > fsf_command ] ;
2005-04-17 02:20:36 +04:00
fsf_req - > qtcb - > prefix . qtcb_version = ZFCP_QTCB_VERSION ;
2006-08-02 13:05:16 +04:00
fsf_req - > qtcb - > header . req_handle = fsf_req - > req_id ;
2005-09-13 23:50:38 +04:00
fsf_req - > qtcb - > header . fsf_command = fsf_req - > fsf_command ;
2005-04-17 02:20:36 +04:00
}
}
/**
* zfcp_fsf_req_sbal_get - try to get one SBAL in the request queue
* @ adapter : adapter for which request queue is examined
* @ req_flags : flags indicating whether to wait for needed SBAL or not
* @ lock_flags : lock_flags if queue_lock is taken
* Return : 0 on success , otherwise - EIO , or - ERESTARTSYS
* Locks : lock adapter - > request_queue - > queue_lock on success
*/
static int
zfcp_fsf_req_sbal_get ( struct zfcp_adapter * adapter , int req_flags ,
unsigned long * lock_flags )
{
long ret ;
struct zfcp_qdio_queue * req_queue = & adapter - > request_queue ;
if ( unlikely ( req_flags & ZFCP_WAIT_FOR_SBAL ) ) {
ret = wait_event_interruptible_timeout ( adapter - > request_wq ,
zfcp_fsf_req_sbal_check ( lock_flags , req_queue , 1 ) ,
ZFCP_SBAL_TIMEOUT ) ;
if ( ret < 0 )
return ret ;
if ( ! ret )
return - EIO ;
} else if ( ! zfcp_fsf_req_sbal_check ( lock_flags , req_queue , 1 ) )
return - EIO ;
return 0 ;
}
/*
* function : zfcp_fsf_req_create
*
* purpose : create an FSF request at the specified adapter and
* setup common fields
*
* returns : - ENOMEM if there was insufficient memory for a request
* - EIO if no qdio buffers could be allocate to the request
* - EINVAL / - EPERM on bug conditions in req_dequeue
* 0 in success
*
* note : The created request is returned by reference .
*
* locks : lock of concerned request queue must not be held ,
* but is held on completion ( write , irqsave )
*/
int
zfcp_fsf_req_create ( struct zfcp_adapter * adapter , u32 fsf_cmd , int req_flags ,
mempool_t * pool , unsigned long * lock_flags ,
struct zfcp_fsf_req * * fsf_req_p )
{
volatile struct qdio_buffer_element * sbale ;
struct zfcp_fsf_req * fsf_req = NULL ;
int ret = 0 ;
struct zfcp_qdio_queue * req_queue = & adapter - > request_queue ;
/* allocate new FSF request */
fsf_req = zfcp_fsf_req_alloc ( pool , req_flags ) ;
if ( unlikely ( NULL = = fsf_req ) ) {
ZFCP_LOG_DEBUG ( " error: Could not put an FSF request into "
" the outbound (send) queue. \n " ) ;
ret = - ENOMEM ;
goto failed_fsf_req ;
}
2005-09-13 23:50:38 +04:00
fsf_req - > adapter = adapter ;
fsf_req - > fsf_command = fsf_cmd ;
2006-08-02 13:05:16 +04:00
INIT_LIST_HEAD ( & fsf_req - > list ) ;
2006-09-19 00:29:56 +04:00
init_timer ( & fsf_req - > timer ) ;
2005-04-17 02:20:36 +04:00
/* initialize waitqueue which may be used to wait on
this request completion */
init_waitqueue_head ( & fsf_req - > completion_wq ) ;
ret = zfcp_fsf_req_sbal_get ( adapter , req_flags , lock_flags ) ;
2007-05-08 13:15:48 +04:00
if ( ret < 0 )
2005-04-17 02:20:36 +04:00
goto failed_sbals ;
2007-05-08 13:15:48 +04:00
/* this is serialized (we are holding req_queue-lock of adapter) */
if ( adapter - > req_no = = 0 )
adapter - > req_no + + ;
fsf_req - > req_id = adapter - > req_no + + ;
zfcp_fsf_req_qtcb_init ( fsf_req ) ;
2005-04-17 02:20:36 +04:00
/*
* We hold queue_lock here . Check if QDIOUP is set and let request fail
* if it is not set ( see also * _open_qdio and * _close_qdio ) .
*/
if ( ! atomic_test_mask ( ZFCP_STATUS_ADAPTER_QDIOUP , & adapter - > status ) ) {
write_unlock_irqrestore ( & req_queue - > queue_lock , * lock_flags ) ;
ret = - EIO ;
goto failed_sbals ;
}
2005-09-13 23:50:38 +04:00
if ( fsf_req - > qtcb ) {
fsf_req - > seq_no = adapter - > fsf_req_seq_no ;
fsf_req - > qtcb - > prefix . req_seq_no = adapter - > fsf_req_seq_no ;
}
2005-04-17 02:20:36 +04:00
fsf_req - > sbal_number = 1 ;
fsf_req - > sbal_first = req_queue - > free_index ;
fsf_req - > sbal_curr = req_queue - > free_index ;
fsf_req - > sbale_curr = 1 ;
if ( likely ( req_flags & ZFCP_REQ_AUTO_CLEANUP ) ) {
fsf_req - > status | = ZFCP_STATUS_FSFREQ_CLEANUP ;
}
sbale = zfcp_qdio_sbale_req ( fsf_req , fsf_req - > sbal_curr , 0 ) ;
/* setup common SBALE fields */
2006-08-02 13:05:16 +04:00
sbale [ 0 ] . addr = ( void * ) fsf_req - > req_id ;
2005-04-17 02:20:36 +04:00
sbale [ 0 ] . flags | = SBAL_FLAGS0_COMMAND ;
if ( likely ( fsf_req - > qtcb ! = NULL ) ) {
sbale [ 1 ] . addr = ( void * ) fsf_req - > qtcb ;
sbale [ 1 ] . length = sizeof ( struct fsf_qtcb ) ;
}
ZFCP_LOG_TRACE ( " got %i free BUFFERs starting at index %i \n " ,
fsf_req - > sbal_number , fsf_req - > sbal_first ) ;
goto success ;
failed_sbals :
/* dequeue new FSF request previously enqueued */
zfcp_fsf_req_free ( fsf_req ) ;
fsf_req = NULL ;
failed_fsf_req :
write_lock_irqsave ( & req_queue - > queue_lock , * lock_flags ) ;
success :
* fsf_req_p = fsf_req ;
return ret ;
}
/*
* function : zfcp_fsf_req_send
*
* purpose : start transfer of FSF request via QDIO
*
* returns : 0 - request transfer succesfully started
* ! 0 - start of request transfer failed
*/
2006-09-19 00:29:56 +04:00
static int zfcp_fsf_req_send ( struct zfcp_fsf_req * fsf_req )
2005-04-17 02:20:36 +04:00
{
struct zfcp_adapter * adapter ;
struct zfcp_qdio_queue * req_queue ;
volatile struct qdio_buffer_element * sbale ;
2005-09-13 23:50:38 +04:00
int inc_seq_no ;
2005-04-17 02:20:36 +04:00
int new_distance_from_int ;
2006-08-02 13:05:16 +04:00
u64 dbg_tmp [ 2 ] ;
2005-04-17 02:20:36 +04:00
int retval = 0 ;
adapter = fsf_req - > adapter ;
req_queue = & adapter - > request_queue ,
/* FIXME(debug): remove it later */
sbale = zfcp_qdio_sbale_req ( fsf_req , fsf_req - > sbal_first , 0 ) ;
ZFCP_LOG_DEBUG ( " SBALE0 flags=0x%x \n " , sbale [ 0 ] . flags ) ;
ZFCP_LOG_TRACE ( " HEX DUMP OF SBALE1 PAYLOAD: \n " ) ;
ZFCP_HEX_DUMP ( ZFCP_LOG_LEVEL_TRACE , ( char * ) sbale [ 1 ] . addr ,
sbale [ 1 ] . length ) ;
2006-08-02 13:05:16 +04:00
/* put allocated FSF request into hash table */
spin_lock ( & adapter - > req_list_lock ) ;
zfcp_reqlist_add ( adapter , fsf_req ) ;
spin_unlock ( & adapter - > req_list_lock ) ;
2005-04-17 02:20:36 +04:00
2005-09-13 23:50:38 +04:00
inc_seq_no = ( fsf_req - > qtcb ! = NULL ) ;
2005-04-17 02:20:36 +04:00
ZFCP_LOG_TRACE ( " request queue of adapter %s: "
" next free SBAL is %i, %i free SBALs \n " ,
zfcp_get_busid_by_adapter ( adapter ) ,
req_queue - > free_index ,
atomic_read ( & req_queue - > free_count ) ) ;
ZFCP_LOG_DEBUG ( " calling do_QDIO adapter %s, flags=0x%x, queue_no=%i, "
" index_in_queue=%i, count=%i, buffers=%p \n " ,
zfcp_get_busid_by_adapter ( adapter ) ,
QDIO_FLAG_SYNC_OUTPUT ,
0 , fsf_req - > sbal_first , fsf_req - > sbal_number ,
& req_queue - > buffer [ fsf_req - > sbal_first ] ) ;
/*
* adjust the number of free SBALs in request queue as well as
* position of first one
*/
atomic_sub ( fsf_req - > sbal_number , & req_queue - > free_count ) ;
ZFCP_LOG_TRACE ( " free_count=%d \n " , atomic_read ( & req_queue - > free_count ) ) ;
req_queue - > free_index + = fsf_req - > sbal_number ; /* increase */
req_queue - > free_index % = QDIO_MAX_BUFFERS_PER_Q ; /* wrap if needed */
new_distance_from_int = zfcp_qdio_determine_pci ( req_queue , fsf_req ) ;
2005-09-13 23:50:38 +04:00
fsf_req - > issued = get_clock ( ) ;
2005-04-17 02:20:36 +04:00
retval = do_QDIO ( adapter - > ccw_device ,
QDIO_FLAG_SYNC_OUTPUT ,
0 , fsf_req - > sbal_first , fsf_req - > sbal_number , NULL ) ;
2006-08-02 13:05:16 +04:00
dbg_tmp [ 0 ] = ( unsigned long ) sbale [ 0 ] . addr ;
dbg_tmp [ 1 ] = ( u64 ) retval ;
debug_event ( adapter - > erp_dbf , 4 , ( void * ) dbg_tmp , 16 ) ;
2005-04-17 02:20:36 +04:00
if ( unlikely ( retval ) ) {
/* Queues are down..... */
retval = - EIO ;
2006-09-19 00:29:56 +04:00
del_timer ( & fsf_req - > timer ) ;
2006-08-02 13:05:16 +04:00
spin_lock ( & adapter - > req_list_lock ) ;
2007-05-08 13:17:54 +04:00
zfcp_reqlist_remove ( adapter , fsf_req ) ;
2006-08-02 13:05:16 +04:00
spin_unlock ( & adapter - > req_list_lock ) ;
/* undo changes in request queue made for this request */
2005-04-17 02:20:36 +04:00
zfcp_qdio_zero_sbals ( req_queue - > buffer ,
fsf_req - > sbal_first , fsf_req - > sbal_number ) ;
atomic_add ( fsf_req - > sbal_number , & req_queue - > free_count ) ;
2006-08-02 13:05:16 +04:00
req_queue - > free_index - = fsf_req - > sbal_number ;
2005-04-17 02:20:36 +04:00
req_queue - > free_index + = QDIO_MAX_BUFFERS_PER_Q ;
req_queue - > free_index % = QDIO_MAX_BUFFERS_PER_Q ; /* wrap */
2006-08-02 13:05:16 +04:00
zfcp_erp_adapter_reopen ( adapter , 0 ) ;
2005-04-17 02:20:36 +04:00
} else {
req_queue - > distance_from_int = new_distance_from_int ;
/*
* increase FSF sequence counter -
* this must only be done for request successfully enqueued to
* QDIO this rejected requests may be cleaned up by calling
* routines resulting in missing sequence counter values
* otherwise ,
*/
2005-09-13 23:50:38 +04:00
2005-04-17 02:20:36 +04:00
/* Don't increase for unsolicited status */
2005-09-13 23:50:38 +04:00
if ( inc_seq_no )
2005-04-17 02:20:36 +04:00
adapter - > fsf_req_seq_no + + ;
2005-09-13 23:50:38 +04:00
2005-04-17 02:20:36 +04:00
/* count FSF requests pending */
2006-08-02 13:05:16 +04:00
atomic_inc ( & adapter - > reqs_active ) ;
2005-04-17 02:20:36 +04:00
}
return retval ;
}
# undef ZFCP_LOG_AREA