2019-05-27 08:55:06 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2011-07-23 06:43:04 +00:00
/*******************************************************************************
* This file contains the iSCSI Target specific utility functions .
*
2013-09-05 15:29:12 -07:00
* ( c ) Copyright 2007 - 2013 Datera , Inc .
2011-07-23 06:43:04 +00:00
*
* Author : Nicholas A . Bellinger < nab @ linux - iscsi . org >
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <linux/list.h>
2018-06-12 12:05:44 -07:00
# include <linux/sched/signal.h>
2016-11-14 15:47:14 -08:00
# include <net/ipv6.h> /* ipv6_addr_equal() */
2011-07-23 06:43:04 +00:00
# include <scsi/scsi_tcq.h>
# include <scsi/iscsi_proto.h>
# include <target/target_core_base.h>
2011-11-16 09:46:48 -05:00
# include <target/target_core_fabric.h>
2013-03-06 21:54:13 -08:00
# include <target/iscsi/iscsi_transport.h>
2011-07-23 06:43:04 +00:00
2015-01-07 14:57:31 +02:00
# include <target/iscsi/iscsi_target_core.h>
2011-07-23 06:43:04 +00:00
# include "iscsi_target_parameters.h"
# include "iscsi_target_seq_pdu_list.h"
# include "iscsi_target_datain_values.h"
# include "iscsi_target_erl0.h"
# include "iscsi_target_erl1.h"
# include "iscsi_target_erl2.h"
# include "iscsi_target_tpg.h"
# include "iscsi_target_util.h"
# include "iscsi_target.h"
# define PRINT_BUFF(buff, len) \
{ \
int zzz ; \
\
pr_debug ( " %d: \n " , __LINE__ ) ; \
for ( zzz = 0 ; zzz < len ; zzz + + ) { \
if ( zzz % 16 = = 0 ) { \
if ( zzz ) \
pr_debug ( " \n " ) ; \
pr_debug ( " %4i: " , zzz ) ; \
} \
pr_debug ( " %02x " , ( unsigned char ) ( buff ) [ zzz ] ) ; \
} \
if ( ( len + 1 ) % 16 ) \
pr_debug ( " \n " ) ; \
}
extern struct list_head g_tiqn_list ;
extern spinlock_t tiqn_lock ;
int iscsit_add_r2t_to_list (
struct iscsi_cmd * cmd ,
u32 offset ,
u32 xfer_len ,
int recovery ,
u32 r2t_sn )
{
struct iscsi_r2t * r2t ;
2019-01-25 10:34:53 -08:00
lockdep_assert_held ( & cmd - > r2t_lock ) ;
2019-04-02 12:58:12 -07:00
WARN_ON_ONCE ( ( s32 ) xfer_len < 0 ) ;
2011-07-23 06:43:04 +00:00
r2t = kmem_cache_zalloc ( lio_r2t_cache , GFP_ATOMIC ) ;
if ( ! r2t ) {
pr_err ( " Unable to allocate memory for struct iscsi_r2t. \n " ) ;
return - 1 ;
}
INIT_LIST_HEAD ( & r2t - > r2t_list ) ;
r2t - > recovery_r2t = recovery ;
r2t - > r2t_sn = ( ! r2t_sn ) ? cmd - > r2t_sn + + : r2t_sn ;
r2t - > offset = offset ;
r2t - > xfer_len = xfer_len ;
list_add_tail ( & r2t - > r2t_list , & cmd - > cmd_r2t_list ) ;
spin_unlock_bh ( & cmd - > r2t_lock ) ;
iscsit_add_cmd_to_immediate_queue ( cmd , cmd - > conn , ISTATE_SEND_R2T ) ;
spin_lock_bh ( & cmd - > r2t_lock ) ;
return 0 ;
}
struct iscsi_r2t * iscsit_get_r2t_for_eos (
struct iscsi_cmd * cmd ,
u32 offset ,
u32 length )
{
struct iscsi_r2t * r2t ;
spin_lock_bh ( & cmd - > r2t_lock ) ;
list_for_each_entry ( r2t , & cmd - > cmd_r2t_list , r2t_list ) {
if ( ( r2t - > offset < = offset ) & &
( r2t - > offset + r2t - > xfer_len ) > = ( offset + length ) ) {
spin_unlock_bh ( & cmd - > r2t_lock ) ;
return r2t ;
}
}
spin_unlock_bh ( & cmd - > r2t_lock ) ;
pr_err ( " Unable to locate R2T for Offset: %u, Length: "
" %u \n " , offset , length ) ;
return NULL ;
}
struct iscsi_r2t * iscsit_get_r2t_from_list ( struct iscsi_cmd * cmd )
{
struct iscsi_r2t * r2t ;
spin_lock_bh ( & cmd - > r2t_lock ) ;
list_for_each_entry ( r2t , & cmd - > cmd_r2t_list , r2t_list ) {
if ( ! r2t - > sent_r2t ) {
spin_unlock_bh ( & cmd - > r2t_lock ) ;
return r2t ;
}
}
spin_unlock_bh ( & cmd - > r2t_lock ) ;
pr_err ( " Unable to locate next R2T to send for ITT: "
" 0x%08x. \n " , cmd - > init_task_tag ) ;
return NULL ;
}
void iscsit_free_r2t ( struct iscsi_r2t * r2t , struct iscsi_cmd * cmd )
{
2019-01-25 10:34:53 -08:00
lockdep_assert_held ( & cmd - > r2t_lock ) ;
2011-07-23 06:43:04 +00:00
list_del ( & r2t - > r2t_list ) ;
kmem_cache_free ( lio_r2t_cache , r2t ) ;
}
void iscsit_free_r2ts_from_list ( struct iscsi_cmd * cmd )
{
struct iscsi_r2t * r2t , * r2t_tmp ;
spin_lock_bh ( & cmd - > r2t_lock ) ;
list_for_each_entry_safe ( r2t , r2t_tmp , & cmd - > cmd_r2t_list , r2t_list )
iscsit_free_r2t ( r2t , cmd ) ;
spin_unlock_bh ( & cmd - > r2t_lock ) ;
}
2018-06-12 12:05:44 -07:00
static int iscsit_wait_for_tag ( struct se_session * se_sess , int state , int * cpup )
{
int tag = - 1 ;
2018-11-29 17:36:41 -07:00
DEFINE_SBQ_WAIT ( wait ) ;
2018-06-12 12:05:44 -07:00
struct sbq_wait_state * ws ;
2018-11-29 17:36:41 -07:00
struct sbitmap_queue * sbq ;
2018-06-12 12:05:44 -07:00
if ( state = = TASK_RUNNING )
return tag ;
2018-11-29 17:36:41 -07:00
sbq = & se_sess - > sess_tag_pool ;
ws = & sbq - > ws [ 0 ] ;
2018-06-12 12:05:44 -07:00
for ( ; ; ) {
2018-11-29 17:36:41 -07:00
sbitmap_prepare_to_wait ( sbq , ws , & wait , state ) ;
2018-06-12 12:05:44 -07:00
if ( signal_pending_state ( state , current ) )
break ;
2018-11-29 17:36:41 -07:00
tag = sbitmap_queue_get ( sbq , cpup ) ;
2018-06-12 12:05:44 -07:00
if ( tag > = 0 )
break ;
schedule ( ) ;
}
2018-11-29 17:36:41 -07:00
sbitmap_finish_wait ( sbq , ws , & wait ) ;
2018-06-12 12:05:44 -07:00
return tag ;
}
2011-07-23 06:43:04 +00:00
/*
* May be called from software interrupt ( timer ) context for allocating
* iSCSI NopINs .
*/
2014-01-20 03:36:44 +00:00
struct iscsi_cmd * iscsit_allocate_cmd ( struct iscsi_conn * conn , int state )
2011-07-23 06:43:04 +00:00
{
struct iscsi_cmd * cmd ;
2013-08-17 15:49:08 -07:00
struct se_session * se_sess = conn - > sess - > se_sess ;
2018-06-12 12:05:44 -07:00
int size , tag , cpu ;
2014-01-19 08:26:37 +00:00
2018-06-12 12:05:44 -07:00
tag = sbitmap_queue_get ( & se_sess - > sess_tag_pool , & cpu ) ;
if ( tag < 0 )
tag = iscsit_wait_for_tag ( se_sess , state , & cpu ) ;
2014-01-19 08:26:37 +00:00
if ( tag < 0 )
return NULL ;
2011-07-23 06:43:04 +00:00
2013-08-17 15:49:08 -07:00
size = sizeof ( struct iscsi_cmd ) + conn - > conn_transport - > priv_size ;
cmd = ( struct iscsi_cmd * ) ( se_sess - > sess_cmd_map + ( tag * size ) ) ;
memset ( cmd , 0 , size ) ;
cmd - > se_cmd . map_tag = tag ;
2018-06-12 12:05:44 -07:00
cmd - > se_cmd . map_cpu = cpu ;
2013-03-06 22:09:17 -08:00
cmd - > conn = conn ;
2017-05-23 16:48:43 -07:00
cmd - > data_direction = DMA_NONE ;
2012-04-03 15:51:01 -07:00
INIT_LIST_HEAD ( & cmd - > i_conn_node ) ;
2011-07-23 06:43:04 +00:00
INIT_LIST_HEAD ( & cmd - > datain_list ) ;
INIT_LIST_HEAD ( & cmd - > cmd_r2t_list ) ;
spin_lock_init ( & cmd - > datain_lock ) ;
spin_lock_init ( & cmd - > dataout_timeout_lock ) ;
spin_lock_init ( & cmd - > istate_lock ) ;
spin_lock_init ( & cmd - > error_lock ) ;
spin_lock_init ( & cmd - > r2t_lock ) ;
2017-10-22 14:58:45 -07:00
timer_setup ( & cmd - > dataout_timer , iscsit_handle_dataout_timeout , 0 ) ;
2011-07-23 06:43:04 +00:00
return cmd ;
}
2013-03-06 22:09:17 -08:00
EXPORT_SYMBOL ( iscsit_allocate_cmd ) ;
2011-07-23 06:43:04 +00:00
struct iscsi_seq * iscsit_get_seq_holder_for_datain (
struct iscsi_cmd * cmd ,
u32 seq_send_order )
{
u32 i ;
for ( i = 0 ; i < cmd - > seq_count ; i + + )
if ( cmd - > seq_list [ i ] . seq_send_order = = seq_send_order )
return & cmd - > seq_list [ i ] ;
return NULL ;
}
struct iscsi_seq * iscsit_get_seq_holder_for_r2t ( struct iscsi_cmd * cmd )
{
u32 i ;
if ( ! cmd - > seq_list ) {
pr_err ( " struct iscsi_cmd->seq_list is NULL! \n " ) ;
return NULL ;
}
for ( i = 0 ; i < cmd - > seq_count ; i + + ) {
if ( cmd - > seq_list [ i ] . type ! = SEQTYPE_NORMAL )
continue ;
if ( cmd - > seq_list [ i ] . seq_send_order = = cmd - > seq_send_order ) {
cmd - > seq_send_order + + ;
return & cmd - > seq_list [ i ] ;
}
}
return NULL ;
}
struct iscsi_r2t * iscsit_get_holder_for_r2tsn (
struct iscsi_cmd * cmd ,
u32 r2t_sn )
{
struct iscsi_r2t * r2t ;
spin_lock_bh ( & cmd - > r2t_lock ) ;
list_for_each_entry ( r2t , & cmd - > cmd_r2t_list , r2t_list ) {
if ( r2t - > r2t_sn = = r2t_sn ) {
spin_unlock_bh ( & cmd - > r2t_lock ) ;
return r2t ;
}
}
spin_unlock_bh ( & cmd - > r2t_lock ) ;
return NULL ;
}
static inline int iscsit_check_received_cmdsn ( struct iscsi_session * sess , u32 cmdsn )
{
2015-07-23 14:53:32 -07:00
u32 max_cmdsn ;
2011-07-23 06:43:04 +00:00
int ret ;
/*
* This is the proper method of checking received CmdSN against
* ExpCmdSN and MaxCmdSN values , as well as accounting for out
* or order CmdSNs due to multiple connection sessions and / or
* CRC failures .
*/
2015-07-23 14:53:32 -07:00
max_cmdsn = atomic_read ( & sess - > max_cmd_sn ) ;
if ( iscsi_sna_gt ( cmdsn , max_cmdsn ) ) {
2011-07-23 06:43:04 +00:00
pr_err ( " Received CmdSN: 0x%08x is greater than "
2015-07-23 14:53:32 -07:00
" MaxCmdSN: 0x%08x, ignoring. \n " , cmdsn , max_cmdsn ) ;
2013-11-18 10:55:10 -08:00
ret = CMDSN_MAXCMDSN_OVERRUN ;
2011-07-23 06:43:04 +00:00
} else if ( cmdsn = = sess - > exp_cmd_sn ) {
sess - > exp_cmd_sn + + ;
pr_debug ( " Received CmdSN matches ExpCmdSN, "
" incremented ExpCmdSN to: 0x%08x \n " ,
sess - > exp_cmd_sn ) ;
ret = CMDSN_NORMAL_OPERATION ;
} else if ( iscsi_sna_gt ( cmdsn , sess - > exp_cmd_sn ) ) {
pr_debug ( " Received CmdSN: 0x%08x is greater "
" than ExpCmdSN: 0x%08x, not acknowledging. \n " ,
cmdsn , sess - > exp_cmd_sn ) ;
ret = CMDSN_HIGHER_THAN_EXP ;
} else {
pr_err ( " Received CmdSN: 0x%08x is less than "
" ExpCmdSN: 0x%08x, ignoring. \n " , cmdsn ,
sess - > exp_cmd_sn ) ;
ret = CMDSN_LOWER_THAN_EXP ;
}
return ret ;
}
/*
* Commands may be received out of order if MC / S is in use .
* Ensure they are executed in CmdSN order .
*/
2013-07-03 03:58:58 -07:00
int iscsit_sequence_cmd ( struct iscsi_conn * conn , struct iscsi_cmd * cmd ,
unsigned char * buf , __be32 cmdsn )
2011-07-23 06:43:04 +00:00
{
2013-07-03 03:58:58 -07:00
int ret , cmdsn_ret ;
bool reject = false ;
u8 reason = ISCSI_REASON_BOOKMARK_NO_RESOURCES ;
2011-07-23 06:43:04 +00:00
mutex_lock ( & conn - > sess - > cmdsn_mutex ) ;
2012-09-26 08:00:40 -04:00
cmdsn_ret = iscsit_check_received_cmdsn ( conn - > sess , be32_to_cpu ( cmdsn ) ) ;
2011-07-23 06:43:04 +00:00
switch ( cmdsn_ret ) {
case CMDSN_NORMAL_OPERATION :
ret = iscsit_execute_cmd ( cmd , 0 ) ;
if ( ( ret > = 0 ) & & ! list_empty ( & conn - > sess - > sess_ooo_cmdsn_list ) )
iscsit_execute_ooo_cmdsns ( conn - > sess ) ;
2013-07-03 03:58:58 -07:00
else if ( ret < 0 ) {
reject = true ;
ret = CMDSN_ERROR_CANNOT_RECOVER ;
}
2011-07-23 06:43:04 +00:00
break ;
case CMDSN_HIGHER_THAN_EXP :
2012-09-26 08:00:40 -04:00
ret = iscsit_handle_ooo_cmdsn ( conn - > sess , cmd , be32_to_cpu ( cmdsn ) ) ;
2013-07-03 03:58:58 -07:00
if ( ret < 0 ) {
reject = true ;
ret = CMDSN_ERROR_CANNOT_RECOVER ;
break ;
}
ret = CMDSN_HIGHER_THAN_EXP ;
2011-07-23 06:43:04 +00:00
break ;
case CMDSN_LOWER_THAN_EXP :
2013-11-18 10:55:10 -08:00
case CMDSN_MAXCMDSN_OVERRUN :
default :
2011-07-23 06:43:04 +00:00
cmd - > i_state = ISTATE_REMOVE ;
iscsit_add_cmd_to_immediate_queue ( cmd , conn , cmd - > i_state ) ;
2013-11-18 10:55:10 -08:00
/*
* Existing callers for iscsit_sequence_cmd ( ) will silently
* ignore commands with CMDSN_LOWER_THAN_EXP , so force this
* return for CMDSN_MAXCMDSN_OVERRUN as well . .
*/
ret = CMDSN_LOWER_THAN_EXP ;
2011-07-23 06:43:04 +00:00
break ;
}
mutex_unlock ( & conn - > sess - > cmdsn_mutex ) ;
2013-07-03 03:58:58 -07:00
if ( reject )
iscsit_reject_cmd ( cmd , reason , buf ) ;
2011-07-23 06:43:04 +00:00
return ret ;
}
2013-03-06 22:18:24 -08:00
EXPORT_SYMBOL ( iscsit_sequence_cmd ) ;
2011-07-23 06:43:04 +00:00
int iscsit_check_unsolicited_dataout ( struct iscsi_cmd * cmd , unsigned char * buf )
{
struct iscsi_conn * conn = cmd - > conn ;
struct se_cmd * se_cmd = & cmd - > se_cmd ;
struct iscsi_data * hdr = ( struct iscsi_data * ) buf ;
u32 payload_length = ntoh24 ( hdr - > dlength ) ;
if ( conn - > sess - > sess_ops - > InitialR2T ) {
pr_err ( " Received unexpected unsolicited data "
" while InitialR2T=Yes, protocol error. \n " ) ;
transport_send_check_condition_and_sense ( se_cmd ,
TCM_UNEXPECTED_UNSOLICITED_DATA , 0 ) ;
return - 1 ;
}
if ( ( cmd - > first_burst_len + payload_length ) >
conn - > sess - > sess_ops - > FirstBurstLength ) {
pr_err ( " Total %u bytes exceeds FirstBurstLength: %u "
" for this Unsolicited DataOut Burst. \n " ,
( cmd - > first_burst_len + payload_length ) ,
conn - > sess - > sess_ops - > FirstBurstLength ) ;
transport_send_check_condition_and_sense ( se_cmd ,
TCM_INCORRECT_AMOUNT_OF_DATA , 0 ) ;
return - 1 ;
}
if ( ! ( hdr - > flags & ISCSI_FLAG_CMD_FINAL ) )
return 0 ;
2012-04-03 15:51:24 -07:00
if ( ( ( cmd - > first_burst_len + payload_length ) ! = cmd - > se_cmd . data_length ) & &
2011-07-23 06:43:04 +00:00
( ( cmd - > first_burst_len + payload_length ) ! =
conn - > sess - > sess_ops - > FirstBurstLength ) ) {
pr_err ( " Unsolicited non-immediate data received %u "
" does not equal FirstBurstLength: %u, and does "
" not equal ExpXferLen %u. \n " ,
( cmd - > first_burst_len + payload_length ) ,
2012-04-03 15:51:24 -07:00
conn - > sess - > sess_ops - > FirstBurstLength , cmd - > se_cmd . data_length ) ;
2011-07-23 06:43:04 +00:00
transport_send_check_condition_and_sense ( se_cmd ,
TCM_INCORRECT_AMOUNT_OF_DATA , 0 ) ;
return - 1 ;
}
return 0 ;
}
struct iscsi_cmd * iscsit_find_cmd_from_itt (
struct iscsi_conn * conn ,
2012-09-26 08:00:39 -04:00
itt_t init_task_tag )
2011-07-23 06:43:04 +00:00
{
struct iscsi_cmd * cmd ;
spin_lock_bh ( & conn - > cmd_lock ) ;
2012-04-03 15:51:01 -07:00
list_for_each_entry ( cmd , & conn - > conn_cmd_list , i_conn_node ) {
2011-07-23 06:43:04 +00:00
if ( cmd - > init_task_tag = = init_task_tag ) {
spin_unlock_bh ( & conn - > cmd_lock ) ;
return cmd ;
}
}
spin_unlock_bh ( & conn - > cmd_lock ) ;
pr_err ( " Unable to locate ITT: 0x%08x on CID: %hu " ,
init_task_tag , conn - > cid ) ;
return NULL ;
}
2015-02-09 18:07:25 +02:00
EXPORT_SYMBOL ( iscsit_find_cmd_from_itt ) ;
2011-07-23 06:43:04 +00:00
struct iscsi_cmd * iscsit_find_cmd_from_itt_or_dump (
struct iscsi_conn * conn ,
2012-09-26 08:00:39 -04:00
itt_t init_task_tag ,
2011-07-23 06:43:04 +00:00
u32 length )
{
struct iscsi_cmd * cmd ;
spin_lock_bh ( & conn - > cmd_lock ) ;
2012-04-03 15:51:01 -07:00
list_for_each_entry ( cmd , & conn - > conn_cmd_list , i_conn_node ) {
2014-07-07 18:25:04 -07:00
if ( cmd - > cmd_flags & ICF_GOT_LAST_DATAOUT )
continue ;
2011-07-23 06:43:04 +00:00
if ( cmd - > init_task_tag = = init_task_tag ) {
spin_unlock_bh ( & conn - > cmd_lock ) ;
return cmd ;
}
}
spin_unlock_bh ( & conn - > cmd_lock ) ;
pr_err ( " Unable to locate ITT: 0x%08x on CID: %hu, "
" dumping payload \n " , init_task_tag , conn - > cid ) ;
if ( length )
iscsit_dump_data_payload ( conn , length , 1 ) ;
return NULL ;
}
2017-01-13 20:53:21 +05:30
EXPORT_SYMBOL ( iscsit_find_cmd_from_itt_or_dump ) ;
2011-07-23 06:43:04 +00:00
struct iscsi_cmd * iscsit_find_cmd_from_ttt (
struct iscsi_conn * conn ,
u32 targ_xfer_tag )
{
struct iscsi_cmd * cmd = NULL ;
spin_lock_bh ( & conn - > cmd_lock ) ;
2012-04-03 15:51:01 -07:00
list_for_each_entry ( cmd , & conn - > conn_cmd_list , i_conn_node ) {
2011-07-23 06:43:04 +00:00
if ( cmd - > targ_xfer_tag = = targ_xfer_tag ) {
spin_unlock_bh ( & conn - > cmd_lock ) ;
return cmd ;
}
}
spin_unlock_bh ( & conn - > cmd_lock ) ;
pr_err ( " Unable to locate TTT: 0x%08x on CID: %hu \n " ,
targ_xfer_tag , conn - > cid ) ;
return NULL ;
}
int iscsit_find_cmd_for_recovery (
struct iscsi_session * sess ,
struct iscsi_cmd * * cmd_ptr ,
struct iscsi_conn_recovery * * cr_ptr ,
2012-09-26 08:00:39 -04:00
itt_t init_task_tag )
2011-07-23 06:43:04 +00:00
{
struct iscsi_cmd * cmd = NULL ;
struct iscsi_conn_recovery * cr ;
/*
* Scan through the inactive connection recovery list ' s command list .
* If init_task_tag matches the command is still alligent .
*/
spin_lock ( & sess - > cr_i_lock ) ;
list_for_each_entry ( cr , & sess - > cr_inactive_list , cr_list ) {
spin_lock ( & cr - > conn_recovery_cmd_lock ) ;
2012-04-03 15:51:01 -07:00
list_for_each_entry ( cmd , & cr - > conn_recovery_cmd_list , i_conn_node ) {
2011-07-23 06:43:04 +00:00
if ( cmd - > init_task_tag = = init_task_tag ) {
spin_unlock ( & cr - > conn_recovery_cmd_lock ) ;
spin_unlock ( & sess - > cr_i_lock ) ;
* cr_ptr = cr ;
* cmd_ptr = cmd ;
return - 2 ;
}
}
spin_unlock ( & cr - > conn_recovery_cmd_lock ) ;
}
spin_unlock ( & sess - > cr_i_lock ) ;
/*
* Scan through the active connection recovery list ' s command list .
* If init_task_tag matches the command is ready to be reassigned .
*/
spin_lock ( & sess - > cr_a_lock ) ;
list_for_each_entry ( cr , & sess - > cr_active_list , cr_list ) {
spin_lock ( & cr - > conn_recovery_cmd_lock ) ;
2012-04-03 15:51:01 -07:00
list_for_each_entry ( cmd , & cr - > conn_recovery_cmd_list , i_conn_node ) {
2011-07-23 06:43:04 +00:00
if ( cmd - > init_task_tag = = init_task_tag ) {
spin_unlock ( & cr - > conn_recovery_cmd_lock ) ;
spin_unlock ( & sess - > cr_a_lock ) ;
* cr_ptr = cr ;
* cmd_ptr = cmd ;
return 0 ;
}
}
spin_unlock ( & cr - > conn_recovery_cmd_lock ) ;
}
spin_unlock ( & sess - > cr_a_lock ) ;
return - 1 ;
}
void iscsit_add_cmd_to_immediate_queue (
struct iscsi_cmd * cmd ,
struct iscsi_conn * conn ,
u8 state )
{
struct iscsi_queue_req * qr ;
qr = kmem_cache_zalloc ( lio_qr_cache , GFP_ATOMIC ) ;
if ( ! qr ) {
pr_err ( " Unable to allocate memory for "
" struct iscsi_queue_req \n " ) ;
return ;
}
INIT_LIST_HEAD ( & qr - > qr_list ) ;
qr - > cmd = cmd ;
qr - > state = state ;
spin_lock_bh ( & conn - > immed_queue_lock ) ;
list_add_tail ( & qr - > qr_list , & conn - > immed_queue_list ) ;
atomic_inc ( & cmd - > immed_queue_count ) ;
atomic_set ( & conn - > check_immediate_queue , 1 ) ;
spin_unlock_bh ( & conn - > immed_queue_lock ) ;
2012-10-31 09:16:46 -07:00
wake_up ( & conn - > queues_wq ) ;
2011-07-23 06:43:04 +00:00
}
2016-04-20 00:00:19 +05:30
EXPORT_SYMBOL ( iscsit_add_cmd_to_immediate_queue ) ;
2011-07-23 06:43:04 +00:00
struct iscsi_queue_req * iscsit_get_cmd_from_immediate_queue ( struct iscsi_conn * conn )
{
struct iscsi_queue_req * qr ;
spin_lock_bh ( & conn - > immed_queue_lock ) ;
if ( list_empty ( & conn - > immed_queue_list ) ) {
spin_unlock_bh ( & conn - > immed_queue_lock ) ;
return NULL ;
}
2012-10-31 09:16:47 -07:00
qr = list_first_entry ( & conn - > immed_queue_list ,
struct iscsi_queue_req , qr_list ) ;
2011-07-23 06:43:04 +00:00
list_del ( & qr - > qr_list ) ;
if ( qr - > cmd )
atomic_dec ( & qr - > cmd - > immed_queue_count ) ;
spin_unlock_bh ( & conn - > immed_queue_lock ) ;
return qr ;
}
static void iscsit_remove_cmd_from_immediate_queue (
struct iscsi_cmd * cmd ,
struct iscsi_conn * conn )
{
struct iscsi_queue_req * qr , * qr_tmp ;
spin_lock_bh ( & conn - > immed_queue_lock ) ;
if ( ! atomic_read ( & cmd - > immed_queue_count ) ) {
spin_unlock_bh ( & conn - > immed_queue_lock ) ;
return ;
}
list_for_each_entry_safe ( qr , qr_tmp , & conn - > immed_queue_list , qr_list ) {
if ( qr - > cmd ! = cmd )
continue ;
atomic_dec ( & qr - > cmd - > immed_queue_count ) ;
list_del ( & qr - > qr_list ) ;
kmem_cache_free ( lio_qr_cache , qr ) ;
}
spin_unlock_bh ( & conn - > immed_queue_lock ) ;
if ( atomic_read ( & cmd - > immed_queue_count ) ) {
pr_err ( " ITT: 0x%08x immed_queue_count: %d \n " ,
cmd - > init_task_tag ,
atomic_read ( & cmd - > immed_queue_count ) ) ;
}
}
2016-10-30 17:30:08 -07:00
int iscsit_add_cmd_to_response_queue (
2011-07-23 06:43:04 +00:00
struct iscsi_cmd * cmd ,
struct iscsi_conn * conn ,
u8 state )
{
struct iscsi_queue_req * qr ;
qr = kmem_cache_zalloc ( lio_qr_cache , GFP_ATOMIC ) ;
if ( ! qr ) {
pr_err ( " Unable to allocate memory for "
" struct iscsi_queue_req \n " ) ;
2016-10-30 17:30:08 -07:00
return - ENOMEM ;
2011-07-23 06:43:04 +00:00
}
INIT_LIST_HEAD ( & qr - > qr_list ) ;
qr - > cmd = cmd ;
qr - > state = state ;
spin_lock_bh ( & conn - > response_queue_lock ) ;
list_add_tail ( & qr - > qr_list , & conn - > response_queue_list ) ;
atomic_inc ( & cmd - > response_queue_count ) ;
spin_unlock_bh ( & conn - > response_queue_lock ) ;
2012-10-31 09:16:46 -07:00
wake_up ( & conn - > queues_wq ) ;
2016-10-30 17:30:08 -07:00
return 0 ;
2011-07-23 06:43:04 +00:00
}
struct iscsi_queue_req * iscsit_get_cmd_from_response_queue ( struct iscsi_conn * conn )
{
struct iscsi_queue_req * qr ;
spin_lock_bh ( & conn - > response_queue_lock ) ;
if ( list_empty ( & conn - > response_queue_list ) ) {
spin_unlock_bh ( & conn - > response_queue_lock ) ;
return NULL ;
}
2012-10-31 09:16:47 -07:00
qr = list_first_entry ( & conn - > response_queue_list ,
struct iscsi_queue_req , qr_list ) ;
2011-07-23 06:43:04 +00:00
list_del ( & qr - > qr_list ) ;
if ( qr - > cmd )
atomic_dec ( & qr - > cmd - > response_queue_count ) ;
spin_unlock_bh ( & conn - > response_queue_lock ) ;
return qr ;
}
static void iscsit_remove_cmd_from_response_queue (
struct iscsi_cmd * cmd ,
struct iscsi_conn * conn )
{
struct iscsi_queue_req * qr , * qr_tmp ;
spin_lock_bh ( & conn - > response_queue_lock ) ;
if ( ! atomic_read ( & cmd - > response_queue_count ) ) {
spin_unlock_bh ( & conn - > response_queue_lock ) ;
return ;
}
list_for_each_entry_safe ( qr , qr_tmp , & conn - > response_queue_list ,
qr_list ) {
if ( qr - > cmd ! = cmd )
continue ;
atomic_dec ( & qr - > cmd - > response_queue_count ) ;
list_del ( & qr - > qr_list ) ;
kmem_cache_free ( lio_qr_cache , qr ) ;
}
spin_unlock_bh ( & conn - > response_queue_lock ) ;
if ( atomic_read ( & cmd - > response_queue_count ) ) {
pr_err ( " ITT: 0x%08x response_queue_count: %d \n " ,
cmd - > init_task_tag ,
atomic_read ( & cmd - > response_queue_count ) ) ;
}
}
2012-10-31 09:16:46 -07:00
bool iscsit_conn_all_queues_empty ( struct iscsi_conn * conn )
{
bool empty ;
spin_lock_bh ( & conn - > immed_queue_lock ) ;
empty = list_empty ( & conn - > immed_queue_list ) ;
spin_unlock_bh ( & conn - > immed_queue_lock ) ;
if ( ! empty )
return empty ;
spin_lock_bh ( & conn - > response_queue_lock ) ;
empty = list_empty ( & conn - > response_queue_list ) ;
spin_unlock_bh ( & conn - > response_queue_lock ) ;
return empty ;
}
2011-07-23 06:43:04 +00:00
void iscsit_free_queue_reqs_for_conn ( struct iscsi_conn * conn )
{
struct iscsi_queue_req * qr , * qr_tmp ;
spin_lock_bh ( & conn - > immed_queue_lock ) ;
list_for_each_entry_safe ( qr , qr_tmp , & conn - > immed_queue_list , qr_list ) {
list_del ( & qr - > qr_list ) ;
if ( qr - > cmd )
atomic_dec ( & qr - > cmd - > immed_queue_count ) ;
kmem_cache_free ( lio_qr_cache , qr ) ;
}
spin_unlock_bh ( & conn - > immed_queue_lock ) ;
spin_lock_bh ( & conn - > response_queue_lock ) ;
list_for_each_entry_safe ( qr , qr_tmp , & conn - > response_queue_list ,
qr_list ) {
list_del ( & qr - > qr_list ) ;
if ( qr - > cmd )
atomic_dec ( & qr - > cmd - > response_queue_count ) ;
kmem_cache_free ( lio_qr_cache , qr ) ;
}
spin_unlock_bh ( & conn - > response_queue_lock ) ;
}
void iscsit_release_cmd ( struct iscsi_cmd * cmd )
{
2013-08-17 15:49:08 -07:00
struct iscsi_session * sess ;
struct se_cmd * se_cmd = & cmd - > se_cmd ;
2017-10-31 11:03:18 -07:00
WARN_ON ( ! list_empty ( & cmd - > i_conn_node ) ) ;
2013-08-17 15:49:08 -07:00
if ( cmd - > conn )
sess = cmd - > conn - > sess ;
else
sess = cmd - > sess ;
BUG_ON ( ! sess | | ! sess - > se_sess ) ;
2011-07-23 06:43:04 +00:00
kfree ( cmd - > buf_ptr ) ;
kfree ( cmd - > pdu_list ) ;
kfree ( cmd - > seq_list ) ;
kfree ( cmd - > tmr_req ) ;
2019-04-02 12:58:13 -07:00
kfree ( cmd - > overflow_buf ) ;
2011-07-23 06:43:04 +00:00
kfree ( cmd - > iov_data ) ;
2013-06-19 22:43:11 -07:00
kfree ( cmd - > text_in_ptr ) ;
2011-07-23 06:43:04 +00:00
2018-06-12 12:05:43 -07:00
target_free_tag ( sess - > se_sess , se_cmd ) ;
2013-05-31 00:49:41 -07:00
}
2013-08-17 14:27:56 -07:00
EXPORT_SYMBOL ( iscsit_release_cmd ) ;
2013-05-31 00:49:41 -07:00
2017-05-23 16:48:43 -07:00
void __iscsit_free_cmd ( struct iscsi_cmd * cmd , bool check_queues )
2013-05-31 00:49:41 -07:00
{
struct iscsi_conn * conn = cmd - > conn ;
2017-10-31 11:03:18 -07:00
WARN_ON ( ! list_empty ( & cmd - > i_conn_node ) ) ;
2017-05-23 16:48:43 -07:00
if ( cmd - > data_direction = = DMA_TO_DEVICE ) {
iscsit_stop_dataout_timer ( cmd ) ;
iscsit_free_r2ts_from_list ( cmd ) ;
2013-05-31 00:49:41 -07:00
}
2017-05-23 16:48:43 -07:00
if ( cmd - > data_direction = = DMA_FROM_DEVICE )
iscsit_free_all_datain_reqs ( cmd ) ;
2013-05-31 00:49:41 -07:00
if ( conn & & check_queues ) {
2011-07-23 06:43:04 +00:00
iscsit_remove_cmd_from_immediate_queue ( cmd , conn ) ;
iscsit_remove_cmd_from_response_queue ( cmd , conn ) ;
}
2016-04-20 00:00:09 +05:30
2019-01-25 10:34:55 -08:00
if ( conn & & conn - > conn_transport - > iscsit_unmap_cmd )
conn - > conn_transport - > iscsit_unmap_cmd ( conn , cmd ) ;
2011-07-23 06:43:04 +00:00
}
2013-05-31 00:49:41 -07:00
void iscsit_free_cmd ( struct iscsi_cmd * cmd , bool shutdown )
2011-10-09 01:48:14 -07:00
{
2017-05-23 16:48:44 -07:00
struct se_cmd * se_cmd = cmd - > se_cmd . se_tfo ? & cmd - > se_cmd : NULL ;
2013-05-31 00:49:41 -07:00
int rc ;
2017-05-23 16:48:43 -07:00
2019-04-02 12:58:11 -07:00
WARN_ON ( ! list_empty ( & cmd - > i_conn_node ) ) ;
2017-05-23 16:48:44 -07:00
__iscsit_free_cmd ( cmd , shutdown ) ;
if ( se_cmd ) {
2017-03-23 17:19:24 -07:00
rc = transport_generic_free_cmd ( se_cmd , shutdown ) ;
2018-07-26 10:20:37 -07:00
if ( ! rc & & shutdown & & se_cmd - > se_sess ) {
__iscsit_free_cmd ( cmd , shutdown ) ;
2015-04-27 13:52:36 +02:00
target_put_sess_cmd ( se_cmd ) ;
2018-07-26 10:20:37 -07:00
}
2017-05-23 16:48:44 -07:00
} else {
2013-08-17 14:27:56 -07:00
iscsit_release_cmd ( cmd ) ;
2011-10-09 01:48:14 -07:00
}
}
2016-04-20 00:00:19 +05:30
EXPORT_SYMBOL ( iscsit_free_cmd ) ;
2011-10-09 01:48:14 -07:00
2011-07-23 06:43:04 +00:00
int iscsit_check_session_usage_count ( struct iscsi_session * sess )
{
spin_lock_bh ( & sess - > session_usage_lock ) ;
if ( sess - > session_usage_count ! = 0 ) {
sess - > session_waiting_on_uc = 1 ;
spin_unlock_bh ( & sess - > session_usage_lock ) ;
if ( in_interrupt ( ) )
return 2 ;
wait_for_completion ( & sess - > session_waiting_on_uc_comp ) ;
return 1 ;
}
spin_unlock_bh ( & sess - > session_usage_lock ) ;
return 0 ;
}
void iscsit_dec_session_usage_count ( struct iscsi_session * sess )
{
spin_lock_bh ( & sess - > session_usage_lock ) ;
sess - > session_usage_count - - ;
if ( ! sess - > session_usage_count & & sess - > session_waiting_on_uc )
complete ( & sess - > session_waiting_on_uc_comp ) ;
spin_unlock_bh ( & sess - > session_usage_lock ) ;
}
void iscsit_inc_session_usage_count ( struct iscsi_session * sess )
{
spin_lock_bh ( & sess - > session_usage_lock ) ;
sess - > session_usage_count + + ;
spin_unlock_bh ( & sess - > session_usage_lock ) ;
}
struct iscsi_conn * iscsit_get_conn_from_cid ( struct iscsi_session * sess , u16 cid )
{
struct iscsi_conn * conn ;
spin_lock_bh ( & sess - > conn_lock ) ;
list_for_each_entry ( conn , & sess - > sess_conn_list , conn_list ) {
if ( ( conn - > cid = = cid ) & &
( conn - > conn_state = = TARG_CONN_STATE_LOGGED_IN ) ) {
iscsit_inc_conn_usage_count ( conn ) ;
spin_unlock_bh ( & sess - > conn_lock ) ;
return conn ;
}
}
spin_unlock_bh ( & sess - > conn_lock ) ;
return NULL ;
}
struct iscsi_conn * iscsit_get_conn_from_cid_rcfr ( struct iscsi_session * sess , u16 cid )
{
struct iscsi_conn * conn ;
spin_lock_bh ( & sess - > conn_lock ) ;
list_for_each_entry ( conn , & sess - > sess_conn_list , conn_list ) {
if ( conn - > cid = = cid ) {
iscsit_inc_conn_usage_count ( conn ) ;
spin_lock ( & conn - > state_lock ) ;
atomic_set ( & conn - > connection_wait_rcfr , 1 ) ;
spin_unlock ( & conn - > state_lock ) ;
spin_unlock_bh ( & sess - > conn_lock ) ;
return conn ;
}
}
spin_unlock_bh ( & sess - > conn_lock ) ;
return NULL ;
}
void iscsit_check_conn_usage_count ( struct iscsi_conn * conn )
{
spin_lock_bh ( & conn - > conn_usage_lock ) ;
if ( conn - > conn_usage_count ! = 0 ) {
conn - > conn_waiting_on_uc = 1 ;
spin_unlock_bh ( & conn - > conn_usage_lock ) ;
wait_for_completion ( & conn - > conn_waiting_on_uc_comp ) ;
return ;
}
spin_unlock_bh ( & conn - > conn_usage_lock ) ;
}
void iscsit_dec_conn_usage_count ( struct iscsi_conn * conn )
{
spin_lock_bh ( & conn - > conn_usage_lock ) ;
conn - > conn_usage_count - - ;
if ( ! conn - > conn_usage_count & & conn - > conn_waiting_on_uc )
complete ( & conn - > conn_waiting_on_uc_comp ) ;
spin_unlock_bh ( & conn - > conn_usage_lock ) ;
}
void iscsit_inc_conn_usage_count ( struct iscsi_conn * conn )
{
spin_lock_bh ( & conn - > conn_usage_lock ) ;
conn - > conn_usage_count + + ;
spin_unlock_bh ( & conn - > conn_usage_lock ) ;
}
static int iscsit_add_nopin ( struct iscsi_conn * conn , int want_response )
{
u8 state ;
struct iscsi_cmd * cmd ;
2014-01-20 03:36:44 +00:00
cmd = iscsit_allocate_cmd ( conn , TASK_RUNNING ) ;
2011-07-23 06:43:04 +00:00
if ( ! cmd )
return - 1 ;
cmd - > iscsi_opcode = ISCSI_OP_NOOP_IN ;
state = ( want_response ) ? ISTATE_SEND_NOPIN_WANT_RESPONSE :
ISTATE_SEND_NOPIN_NO_RESPONSE ;
2012-09-26 08:00:39 -04:00
cmd - > init_task_tag = RESERVED_ITT ;
2015-01-26 12:49:05 +02:00
cmd - > targ_xfer_tag = ( want_response ) ?
session_get_next_ttt ( conn - > sess ) : 0xFFFFFFFF ;
2011-07-23 06:43:04 +00:00
spin_lock_bh ( & conn - > cmd_lock ) ;
2012-04-03 15:51:01 -07:00
list_add_tail ( & cmd - > i_conn_node , & conn - > conn_cmd_list ) ;
2011-07-23 06:43:04 +00:00
spin_unlock_bh ( & conn - > cmd_lock ) ;
if ( want_response )
iscsit_start_nopin_response_timer ( conn ) ;
iscsit_add_cmd_to_immediate_queue ( cmd , conn , state ) ;
return 0 ;
}
2017-10-22 14:58:45 -07:00
void iscsit_handle_nopin_response_timeout ( struct timer_list * t )
2011-07-23 06:43:04 +00:00
{
2017-10-22 14:58:45 -07:00
struct iscsi_conn * conn = from_timer ( conn , t , nopin_response_timer ) ;
2018-10-12 12:01:18 +02:00
struct iscsi_session * sess = conn - > sess ;
2011-07-23 06:43:04 +00:00
iscsit_inc_conn_usage_count ( conn ) ;
spin_lock_bh ( & conn - > nopin_timer_lock ) ;
if ( conn - > nopin_response_timer_flags & ISCSI_TF_STOP ) {
spin_unlock_bh ( & conn - > nopin_timer_lock ) ;
iscsit_dec_conn_usage_count ( conn ) ;
return ;
}
2018-10-12 12:01:18 +02:00
pr_err ( " Did not receive response to NOPIN on CID: %hu, failing "
" connection for I_T Nexus %s,i,0x%6phN,%s,t,0x%02x \n " ,
conn - > cid , sess - > sess_ops - > InitiatorName , sess - > isid ,
sess - > tpg - > tpg_tiqn - > tiqn , ( u32 ) sess - > tpg - > tpgt ) ;
2011-07-23 06:43:04 +00:00
conn - > nopin_response_timer_flags & = ~ ISCSI_TF_RUNNING ;
spin_unlock_bh ( & conn - > nopin_timer_lock ) ;
2018-10-14 01:13:54 +02:00
iscsit_fill_cxn_timeout_err_stats ( sess ) ;
2011-07-23 06:43:04 +00:00
iscsit_cause_connection_reinstatement ( conn , 0 ) ;
iscsit_dec_conn_usage_count ( conn ) ;
}
void iscsit_mod_nopin_response_timer ( struct iscsi_conn * conn )
{
struct iscsi_session * sess = conn - > sess ;
struct iscsi_node_attrib * na = iscsit_tpg_get_node_attrib ( sess ) ;
spin_lock_bh ( & conn - > nopin_timer_lock ) ;
if ( ! ( conn - > nopin_response_timer_flags & ISCSI_TF_RUNNING ) ) {
spin_unlock_bh ( & conn - > nopin_timer_lock ) ;
return ;
}
mod_timer ( & conn - > nopin_response_timer ,
( get_jiffies_64 ( ) + na - > nopin_response_timeout * HZ ) ) ;
spin_unlock_bh ( & conn - > nopin_timer_lock ) ;
}
void iscsit_start_nopin_response_timer ( struct iscsi_conn * conn )
{
struct iscsi_session * sess = conn - > sess ;
struct iscsi_node_attrib * na = iscsit_tpg_get_node_attrib ( sess ) ;
spin_lock_bh ( & conn - > nopin_timer_lock ) ;
if ( conn - > nopin_response_timer_flags & ISCSI_TF_RUNNING ) {
spin_unlock_bh ( & conn - > nopin_timer_lock ) ;
return ;
}
conn - > nopin_response_timer_flags & = ~ ISCSI_TF_STOP ;
conn - > nopin_response_timer_flags | = ISCSI_TF_RUNNING ;
2017-05-23 16:48:50 -07:00
mod_timer ( & conn - > nopin_response_timer ,
jiffies + na - > nopin_response_timeout * HZ ) ;
2011-07-23 06:43:04 +00:00
pr_debug ( " Started NOPIN Response Timer on CID: %d to %u "
" seconds \n " , conn - > cid , na - > nopin_response_timeout ) ;
spin_unlock_bh ( & conn - > nopin_timer_lock ) ;
}
void iscsit_stop_nopin_response_timer ( struct iscsi_conn * conn )
{
spin_lock_bh ( & conn - > nopin_timer_lock ) ;
if ( ! ( conn - > nopin_response_timer_flags & ISCSI_TF_RUNNING ) ) {
spin_unlock_bh ( & conn - > nopin_timer_lock ) ;
return ;
}
conn - > nopin_response_timer_flags | = ISCSI_TF_STOP ;
spin_unlock_bh ( & conn - > nopin_timer_lock ) ;
del_timer_sync ( & conn - > nopin_response_timer ) ;
spin_lock_bh ( & conn - > nopin_timer_lock ) ;
conn - > nopin_response_timer_flags & = ~ ISCSI_TF_RUNNING ;
spin_unlock_bh ( & conn - > nopin_timer_lock ) ;
}
2017-10-22 14:58:45 -07:00
void iscsit_handle_nopin_timeout ( struct timer_list * t )
2011-07-23 06:43:04 +00:00
{
2017-10-22 14:58:45 -07:00
struct iscsi_conn * conn = from_timer ( conn , t , nopin_timer ) ;
2011-07-23 06:43:04 +00:00
iscsit_inc_conn_usage_count ( conn ) ;
spin_lock_bh ( & conn - > nopin_timer_lock ) ;
if ( conn - > nopin_timer_flags & ISCSI_TF_STOP ) {
spin_unlock_bh ( & conn - > nopin_timer_lock ) ;
iscsit_dec_conn_usage_count ( conn ) ;
return ;
}
conn - > nopin_timer_flags & = ~ ISCSI_TF_RUNNING ;
spin_unlock_bh ( & conn - > nopin_timer_lock ) ;
iscsit_add_nopin ( conn , 1 ) ;
iscsit_dec_conn_usage_count ( conn ) ;
}
void __iscsit_start_nopin_timer ( struct iscsi_conn * conn )
{
struct iscsi_session * sess = conn - > sess ;
struct iscsi_node_attrib * na = iscsit_tpg_get_node_attrib ( sess ) ;
2019-01-25 10:34:53 -08:00
lockdep_assert_held ( & conn - > nopin_timer_lock ) ;
2011-07-23 06:43:04 +00:00
/*
* NOPIN timeout is disabled .
*/
if ( ! na - > nopin_timeout )
return ;
if ( conn - > nopin_timer_flags & ISCSI_TF_RUNNING )
return ;
conn - > nopin_timer_flags & = ~ ISCSI_TF_STOP ;
conn - > nopin_timer_flags | = ISCSI_TF_RUNNING ;
2017-05-23 16:48:50 -07:00
mod_timer ( & conn - > nopin_timer , jiffies + na - > nopin_timeout * HZ ) ;
2011-07-23 06:43:04 +00:00
pr_debug ( " Started NOPIN Timer on CID: %d at %u second "
" interval \n " , conn - > cid , na - > nopin_timeout ) ;
}
void iscsit_start_nopin_timer ( struct iscsi_conn * conn )
{
spin_lock_bh ( & conn - > nopin_timer_lock ) ;
2018-08-02 12:12:21 -05:00
__iscsit_start_nopin_timer ( conn ) ;
2011-07-23 06:43:04 +00:00
spin_unlock_bh ( & conn - > nopin_timer_lock ) ;
}
void iscsit_stop_nopin_timer ( struct iscsi_conn * conn )
{
spin_lock_bh ( & conn - > nopin_timer_lock ) ;
if ( ! ( conn - > nopin_timer_flags & ISCSI_TF_RUNNING ) ) {
spin_unlock_bh ( & conn - > nopin_timer_lock ) ;
return ;
}
conn - > nopin_timer_flags | = ISCSI_TF_STOP ;
spin_unlock_bh ( & conn - > nopin_timer_lock ) ;
del_timer_sync ( & conn - > nopin_timer ) ;
spin_lock_bh ( & conn - > nopin_timer_lock ) ;
conn - > nopin_timer_flags & = ~ ISCSI_TF_RUNNING ;
spin_unlock_bh ( & conn - > nopin_timer_lock ) ;
}
int iscsit_send_tx_data (
struct iscsi_cmd * cmd ,
struct iscsi_conn * conn ,
int use_misc )
{
int tx_sent , tx_size ;
u32 iov_count ;
struct kvec * iov ;
send_data :
tx_size = cmd - > tx_size ;
if ( ! use_misc ) {
iov = & cmd - > iov_data [ 0 ] ;
iov_count = cmd - > iov_data_count ;
} else {
iov = & cmd - > iov_misc [ 0 ] ;
iov_count = cmd - > iov_misc_count ;
}
tx_sent = tx_data ( conn , & iov [ 0 ] , iov_count , tx_size ) ;
if ( tx_size ! = tx_sent ) {
if ( tx_sent = = - EAGAIN ) {
pr_err ( " tx_data() returned -EAGAIN \n " ) ;
goto send_data ;
} else
return - 1 ;
}
cmd - > tx_size = 0 ;
return 0 ;
}
int iscsit_fe_sendpage_sg (
struct iscsi_cmd * cmd ,
struct iscsi_conn * conn )
{
struct scatterlist * sg = cmd - > first_data_sg ;
struct kvec iov ;
u32 tx_hdr_size , data_len ;
u32 offset = cmd - > first_data_sg_off ;
2011-09-16 16:55:47 -07:00
int tx_sent , iov_off ;
2011-07-23 06:43:04 +00:00
send_hdr :
tx_hdr_size = ISCSI_HDR_LEN ;
if ( conn - > conn_ops - > HeaderDigest )
tx_hdr_size + = ISCSI_CRC_LEN ;
iov . iov_base = cmd - > pdu ;
iov . iov_len = tx_hdr_size ;
tx_sent = tx_data ( conn , & iov , 1 , tx_hdr_size ) ;
if ( tx_hdr_size ! = tx_sent ) {
if ( tx_sent = = - EAGAIN ) {
pr_err ( " tx_data() returned -EAGAIN \n " ) ;
goto send_hdr ;
}
return - 1 ;
}
data_len = cmd - > tx_size - tx_hdr_size - cmd - > padding ;
2011-09-16 16:55:47 -07:00
/*
* Set iov_off used by padding and data digest tx_data ( ) calls below
* in order to determine proper offset into cmd - > iov_data [ ]
*/
if ( conn - > conn_ops - > DataDigest ) {
2011-07-23 06:43:04 +00:00
data_len - = ISCSI_CRC_LEN ;
2011-09-16 16:55:47 -07:00
if ( cmd - > padding )
iov_off = ( cmd - > iov_data_count - 2 ) ;
else
iov_off = ( cmd - > iov_data_count - 1 ) ;
} else {
iov_off = ( cmd - > iov_data_count - 1 ) ;
}
2011-07-23 06:43:04 +00:00
/*
* Perform sendpage ( ) for each page in the scatterlist
*/
while ( data_len ) {
u32 space = ( sg - > length - offset ) ;
u32 sub_len = min_t ( u32 , data_len , space ) ;
send_pg :
tx_sent = conn - > sock - > ops - > sendpage ( conn - > sock ,
sg_page ( sg ) , sg - > offset + offset , sub_len , 0 ) ;
if ( tx_sent ! = sub_len ) {
if ( tx_sent = = - EAGAIN ) {
pr_err ( " tcp_sendpage() returned "
" -EAGAIN \n " ) ;
goto send_pg ;
}
pr_err ( " tcp_sendpage() failure: %d \n " ,
tx_sent ) ;
return - 1 ;
}
data_len - = sub_len ;
offset = 0 ;
sg = sg_next ( sg ) ;
}
send_padding :
if ( cmd - > padding ) {
2011-09-16 16:55:47 -07:00
struct kvec * iov_p = & cmd - > iov_data [ iov_off + + ] ;
2011-07-23 06:43:04 +00:00
tx_sent = tx_data ( conn , iov_p , 1 , cmd - > padding ) ;
if ( cmd - > padding ! = tx_sent ) {
if ( tx_sent = = - EAGAIN ) {
pr_err ( " tx_data() returned -EAGAIN \n " ) ;
goto send_padding ;
}
return - 1 ;
}
}
send_datacrc :
if ( conn - > conn_ops - > DataDigest ) {
2011-09-16 16:55:47 -07:00
struct kvec * iov_d = & cmd - > iov_data [ iov_off ] ;
2011-07-23 06:43:04 +00:00
tx_sent = tx_data ( conn , iov_d , 1 , ISCSI_CRC_LEN ) ;
if ( ISCSI_CRC_LEN ! = tx_sent ) {
if ( tx_sent = = - EAGAIN ) {
pr_err ( " tx_data() returned -EAGAIN \n " ) ;
goto send_datacrc ;
}
return - 1 ;
}
}
return 0 ;
}
/*
* This function is used for mainly sending a ISCSI_TARG_LOGIN_RSP PDU
* back to the Initiator when an expection condition occurs with the
* errors set in status_class and status_detail .
*
* Parameters : iSCSI Connection , Status Class , Status Detail .
* Returns : 0 on success , - 1 on error .
*/
int iscsit_tx_login_rsp ( struct iscsi_conn * conn , u8 status_class , u8 status_detail )
{
struct iscsi_login_rsp * hdr ;
2013-03-06 21:54:13 -08:00
struct iscsi_login * login = conn - > conn_login ;
2011-07-23 06:43:04 +00:00
2013-03-06 21:54:13 -08:00
login - > login_failed = 1 ;
2011-07-23 06:43:04 +00:00
iscsit_collect_login_stats ( conn , status_class , status_detail ) ;
2014-06-17 21:54:38 +00:00
memset ( & login - > rsp [ 0 ] , 0 , ISCSI_HDR_LEN ) ;
2013-03-06 21:54:13 -08:00
hdr = ( struct iscsi_login_rsp * ) & login - > rsp [ 0 ] ;
2011-07-23 06:43:04 +00:00
hdr - > opcode = ISCSI_OP_LOGIN_RSP ;
hdr - > status_class = status_class ;
hdr - > status_detail = status_detail ;
2012-09-26 08:00:39 -04:00
hdr - > itt = conn - > login_itt ;
2011-07-23 06:43:04 +00:00
2013-03-06 21:54:13 -08:00
return conn - > conn_transport - > iscsit_put_login_tx ( conn , login , 0 ) ;
2011-07-23 06:43:04 +00:00
}
void iscsit_print_session_params ( struct iscsi_session * sess )
{
struct iscsi_conn * conn ;
pr_debug ( " -----------------------------[Session Params for "
" SID: %u]----------------------------- \n " , sess - > sid ) ;
spin_lock_bh ( & sess - > conn_lock ) ;
list_for_each_entry ( conn , & sess - > sess_conn_list , conn_list )
iscsi_dump_conn_ops ( conn - > conn_ops ) ;
spin_unlock_bh ( & sess - > conn_lock ) ;
iscsi_dump_sess_ops ( sess - > sess_ops ) ;
}
2020-04-24 13:39:13 +02:00
int rx_data (
2011-07-23 06:43:04 +00:00
struct iscsi_conn * conn ,
2020-04-24 13:39:13 +02:00
struct kvec * iov ,
int iov_count ,
int data )
2011-07-23 06:43:04 +00:00
{
2020-04-24 13:39:13 +02:00
int rx_loop = 0 , total_rx = 0 ;
2011-07-23 06:43:04 +00:00
struct msghdr msg ;
if ( ! conn | | ! conn - > sock | | ! conn - > conn_ops )
return - 1 ;
memset ( & msg , 0 , sizeof ( struct msghdr ) ) ;
2020-04-24 13:39:13 +02:00
iov_iter_kvec ( & msg . msg_iter , READ , iov , iov_count , data ) ;
2011-07-23 06:43:04 +00:00
2015-03-14 21:13:46 -04:00
while ( msg_data_left ( & msg ) ) {
rx_loop = sock_recvmsg ( conn - > sock , & msg , MSG_WAITALL ) ;
2011-07-23 06:43:04 +00:00
if ( rx_loop < = 0 ) {
pr_debug ( " rx_loop: %d total_rx: %d \n " ,
rx_loop , total_rx ) ;
return rx_loop ;
}
total_rx + = rx_loop ;
pr_debug ( " rx_loop: %d, total_rx: %d, data: %d \n " ,
rx_loop , total_rx , data ) ;
}
return total_rx ;
}
int tx_data (
struct iscsi_conn * conn ,
struct kvec * iov ,
int iov_count ,
int data )
{
2014-12-21 02:14:47 -05:00
struct msghdr msg ;
int total_tx = 0 ;
2011-07-23 06:43:04 +00:00
if ( ! conn | | ! conn - > sock | | ! conn - > conn_ops )
return - 1 ;
2014-12-21 02:14:47 -05:00
if ( data < = 0 ) {
pr_err ( " Data length is: %d \n " , data ) ;
return - 1 ;
}
memset ( & msg , 0 , sizeof ( struct msghdr ) ) ;
2018-10-20 00:57:56 +01:00
iov_iter_kvec ( & msg . msg_iter , WRITE , iov , iov_count , data ) ;
2014-12-21 02:14:47 -05:00
while ( msg_data_left ( & msg ) ) {
int tx_loop = sock_sendmsg ( conn - > sock , & msg ) ;
if ( tx_loop < = 0 ) {
pr_debug ( " tx_loop: %d total_tx %d \n " ,
tx_loop , total_tx ) ;
return tx_loop ;
}
total_tx + = tx_loop ;
pr_debug ( " tx_loop: %d, total_tx: %d, data: %d \n " ,
tx_loop , total_tx , data ) ;
}
2011-07-23 06:43:04 +00:00
2014-12-21 02:14:47 -05:00
return total_tx ;
2011-07-23 06:43:04 +00:00
}
void iscsit_collect_login_stats (
struct iscsi_conn * conn ,
u8 status_class ,
u8 status_detail )
{
struct iscsi_param * intrname = NULL ;
struct iscsi_tiqn * tiqn ;
struct iscsi_login_stats * ls ;
tiqn = iscsit_snmp_get_tiqn ( conn ) ;
if ( ! tiqn )
return ;
ls = & tiqn - > login_stats ;
spin_lock ( & ls - > lock ) ;
if ( status_class = = ISCSI_STATUS_CLS_SUCCESS )
ls - > accepts + + ;
else if ( status_class = = ISCSI_STATUS_CLS_REDIRECT ) {
ls - > redirects + + ;
ls - > last_fail_type = ISCSI_LOGIN_FAIL_REDIRECT ;
} else if ( ( status_class = = ISCSI_STATUS_CLS_INITIATOR_ERR ) & &
( status_detail = = ISCSI_LOGIN_STATUS_AUTH_FAILED ) ) {
ls - > authenticate_fails + + ;
ls - > last_fail_type = ISCSI_LOGIN_FAIL_AUTHENTICATE ;
} else if ( ( status_class = = ISCSI_STATUS_CLS_INITIATOR_ERR ) & &
( status_detail = = ISCSI_LOGIN_STATUS_TGT_FORBIDDEN ) ) {
ls - > authorize_fails + + ;
ls - > last_fail_type = ISCSI_LOGIN_FAIL_AUTHORIZE ;
} else if ( ( status_class = = ISCSI_STATUS_CLS_INITIATOR_ERR ) & &
( status_detail = = ISCSI_LOGIN_STATUS_INIT_ERR ) ) {
ls - > negotiate_fails + + ;
ls - > last_fail_type = ISCSI_LOGIN_FAIL_NEGOTIATE ;
} else {
ls - > other_fails + + ;
ls - > last_fail_type = ISCSI_LOGIN_FAIL_OTHER ;
}
/* Save initiator name, ip address and time, if it is a failed login */
if ( status_class ! = ISCSI_STATUS_CLS_SUCCESS ) {
if ( conn - > param_list )
intrname = iscsi_find_param_from_key ( INITIATORNAME ,
conn - > param_list ) ;
2014-09-02 17:49:55 -04:00
strlcpy ( ls - > last_intr_fail_name ,
( intrname ? intrname - > value : " Unknown " ) ,
sizeof ( ls - > last_intr_fail_name ) ) ;
2011-07-23 06:43:04 +00:00
2013-03-06 21:54:13 -08:00
ls - > last_intr_fail_ip_family = conn - > login_family ;
2015-08-24 10:26:05 -07:00
ls - > last_intr_fail_sockaddr = conn - > login_sockaddr ;
2011-07-23 06:43:04 +00:00
ls - > last_fail_time = get_jiffies_64 ( ) ;
}
spin_unlock ( & ls - > lock ) ;
}
struct iscsi_tiqn * iscsit_snmp_get_tiqn ( struct iscsi_conn * conn )
{
struct iscsi_portal_group * tpg ;
2017-02-23 21:26:31 -08:00
if ( ! conn )
2011-07-23 06:43:04 +00:00
return NULL ;
2017-02-23 21:26:31 -08:00
tpg = conn - > tpg ;
2011-07-23 06:43:04 +00:00
if ( ! tpg )
return NULL ;
if ( ! tpg - > tpg_tiqn )
return NULL ;
return tpg - > tpg_tiqn ;
}
2018-10-14 01:13:54 +02:00
void iscsit_fill_cxn_timeout_err_stats ( struct iscsi_session * sess )
{
struct iscsi_portal_group * tpg = sess - > tpg ;
struct iscsi_tiqn * tiqn = tpg - > tpg_tiqn ;
if ( ! tiqn )
return ;
spin_lock_bh ( & tiqn - > sess_err_stats . lock ) ;
strlcpy ( tiqn - > sess_err_stats . last_sess_fail_rem_name ,
sess - > sess_ops - > InitiatorName ,
sizeof ( tiqn - > sess_err_stats . last_sess_fail_rem_name ) ) ;
tiqn - > sess_err_stats . last_sess_failure_type =
ISCSI_SESS_ERR_CXN_TIMEOUT ;
tiqn - > sess_err_stats . cxn_timeout_errors + + ;
atomic_long_inc ( & sess - > conn_timeout_errors ) ;
spin_unlock_bh ( & tiqn - > sess_err_stats . lock ) ;
}