2006-05-11 10:02:19 +03:00
/*
* Copyright ( c ) 2004 , 2005 , 2006 Voltaire , Inc . All rights reserved .
*
* This software is available to you under a choice of one of two
* licenses . You may choose to be licensed under the terms of the GNU
* General Public License ( GPL ) Version 2 , available from the file
* COPYING in the main directory of this source tree , or the
* OpenIB . org BSD license below :
*
* Redistribution and use in source and binary forms , with or
* without modification , are permitted provided that the following
* conditions are met :
*
* - Redistributions of source code must retain the above
* copyright notice , this list of conditions and the following
* disclaimer .
*
* - Redistributions in binary form must reproduce the above
* copyright notice , this list of conditions and the following
* disclaimer in the documentation and / or other materials
* provided with the distribution .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND ,
* EXPRESS OR IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY , FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT . IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY , WHETHER IN AN
* ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM , OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE .
*/
# include <linux/kernel.h>
# include <linux/slab.h>
# include <linux/mm.h>
# include <linux/scatterlist.h>
# include <linux/kfifo.h>
# include <scsi/scsi_cmnd.h>
# include <scsi/scsi_host.h>
# include "iscsi_iser.h"
/* Register user buffer memory and initialize passive rdma
* dto descriptor . Total data size is stored in
2008-05-21 15:54:11 -05:00
* iser_task - > data [ ISER_DIR_IN ] . data_len
2006-05-11 10:02:19 +03:00
*/
2008-05-21 15:54:11 -05:00
static int iser_prepare_read_cmd ( struct iscsi_task * task ,
2006-05-11 10:02:19 +03:00
unsigned int edtl )
{
2008-05-21 15:54:11 -05:00
struct iscsi_iser_task * iser_task = task - > dd_data ;
2006-05-11 10:02:19 +03:00
struct iser_regd_buf * regd_buf ;
int err ;
2008-05-21 15:54:11 -05:00
struct iser_hdr * hdr = & iser_task - > desc . iser_header ;
struct iser_data_buf * buf_in = & iser_task - > data [ ISER_DIR_IN ] ;
2006-05-11 10:02:19 +03:00
2008-05-21 15:54:11 -05:00
err = iser_dma_map_task_data ( iser_task ,
2006-05-11 10:02:19 +03:00
buf_in ,
ISER_DIR_IN ,
DMA_FROM_DEVICE ) ;
if ( err )
return err ;
2008-05-21 15:54:11 -05:00
if ( edtl > iser_task - > data [ ISER_DIR_IN ] . data_len ) {
2006-05-11 10:02:19 +03:00
iser_err ( " Total data length: %ld, less than EDTL: "
" %d, in READ cmd BHS itt: %d, conn: 0x%p \n " ,
2008-05-21 15:54:11 -05:00
iser_task - > data [ ISER_DIR_IN ] . data_len , edtl ,
task - > itt , iser_task - > iser_conn ) ;
2006-05-11 10:02:19 +03:00
return - EINVAL ;
}
2008-05-21 15:54:11 -05:00
err = iser_reg_rdma_mem ( iser_task , ISER_DIR_IN ) ;
2006-05-11 10:02:19 +03:00
if ( err ) {
iser_err ( " Failed to set up Data-IN RDMA \n " ) ;
return err ;
}
2008-05-21 15:54:11 -05:00
regd_buf = & iser_task - > rdma_regd [ ISER_DIR_IN ] ;
2006-05-11 10:02:19 +03:00
hdr - > flags | = ISER_RSV ;
hdr - > read_stag = cpu_to_be32 ( regd_buf - > reg . rkey ) ;
hdr - > read_va = cpu_to_be64 ( regd_buf - > reg . va ) ;
iser_dbg ( " Cmd itt:%d READ tags RKEY:%#.4X VA:%#llX \n " ,
2008-05-21 15:54:11 -05:00
task - > itt , regd_buf - > reg . rkey ,
2006-05-11 10:02:19 +03:00
( unsigned long long ) regd_buf - > reg . va ) ;
return 0 ;
}
/* Register user buffer memory and initialize passive rdma
* dto descriptor . Total data size is stored in
2008-05-21 15:54:11 -05:00
* task - > data [ ISER_DIR_OUT ] . data_len
2006-05-11 10:02:19 +03:00
*/
static int
2008-05-21 15:54:11 -05:00
iser_prepare_write_cmd ( struct iscsi_task * task ,
2006-05-11 10:02:19 +03:00
unsigned int imm_sz ,
unsigned int unsol_sz ,
unsigned int edtl )
{
2008-05-21 15:54:11 -05:00
struct iscsi_iser_task * iser_task = task - > dd_data ;
2006-05-11 10:02:19 +03:00
struct iser_regd_buf * regd_buf ;
int err ;
2008-05-21 15:54:11 -05:00
struct iser_hdr * hdr = & iser_task - > desc . iser_header ;
struct iser_data_buf * buf_out = & iser_task - > data [ ISER_DIR_OUT ] ;
2010-02-08 13:19:56 +00:00
struct ib_sge * tx_dsg = & iser_task - > desc . tx_sg [ 1 ] ;
2006-05-11 10:02:19 +03:00
2008-05-21 15:54:11 -05:00
err = iser_dma_map_task_data ( iser_task ,
2006-05-11 10:02:19 +03:00
buf_out ,
ISER_DIR_OUT ,
DMA_TO_DEVICE ) ;
if ( err )
return err ;
2008-05-21 15:54:11 -05:00
if ( edtl > iser_task - > data [ ISER_DIR_OUT ] . data_len ) {
2006-05-11 10:02:19 +03:00
iser_err ( " Total data length: %ld, less than EDTL: %d, "
" in WRITE cmd BHS itt: %d, conn: 0x%p \n " ,
2008-05-21 15:54:11 -05:00
iser_task - > data [ ISER_DIR_OUT ] . data_len ,
edtl , task - > itt , task - > conn ) ;
2006-05-11 10:02:19 +03:00
return - EINVAL ;
}
2008-05-21 15:54:11 -05:00
err = iser_reg_rdma_mem ( iser_task , ISER_DIR_OUT ) ;
2006-05-11 10:02:19 +03:00
if ( err ! = 0 ) {
iser_err ( " Failed to register write cmd RDMA mem \n " ) ;
return err ;
}
2008-05-21 15:54:11 -05:00
regd_buf = & iser_task - > rdma_regd [ ISER_DIR_OUT ] ;
2006-05-11 10:02:19 +03:00
if ( unsol_sz < edtl ) {
hdr - > flags | = ISER_WSV ;
hdr - > write_stag = cpu_to_be32 ( regd_buf - > reg . rkey ) ;
hdr - > write_va = cpu_to_be64 ( regd_buf - > reg . va + unsol_sz ) ;
iser_dbg ( " Cmd itt:%d, WRITE tags, RKEY:%#.4X "
" VA:%#llX + unsol:%d \n " ,
2008-05-21 15:54:11 -05:00
task - > itt , regd_buf - > reg . rkey ,
2006-05-11 10:02:19 +03:00
( unsigned long long ) regd_buf - > reg . va , unsol_sz ) ;
}
if ( imm_sz > 0 ) {
iser_dbg ( " Cmd itt:%d, WRITE, adding imm.data sz: %d \n " ,
2008-05-21 15:54:11 -05:00
task - > itt , imm_sz ) ;
2010-02-08 13:19:56 +00:00
tx_dsg - > addr = regd_buf - > reg . va ;
tx_dsg - > length = imm_sz ;
tx_dsg - > lkey = regd_buf - > reg . lkey ;
iser_task - > desc . num_sge = 2 ;
2006-05-11 10:02:19 +03:00
}
return 0 ;
}
/* creates a new tx descriptor and adds header regd buffer */
2010-02-08 13:19:56 +00:00
static void iser_create_send_desc ( struct iser_conn * ib_conn ,
struct iser_tx_desc * tx_desc )
2006-05-11 10:02:19 +03:00
{
2010-02-08 13:19:56 +00:00
struct iser_device * device = ib_conn - > device ;
2006-05-11 10:02:19 +03:00
2010-02-08 13:19:56 +00:00
ib_dma_sync_single_for_cpu ( device - > ib_device ,
tx_desc - > dma_addr , ISER_HEADERS_LEN , DMA_TO_DEVICE ) ;
2006-05-11 10:02:19 +03:00
memset ( & tx_desc - > iser_header , 0 , sizeof ( struct iser_hdr ) ) ;
tx_desc - > iser_header . flags = ISER_VER ;
2010-02-08 13:19:56 +00:00
tx_desc - > num_sge = 1 ;
if ( tx_desc - > tx_sg [ 0 ] . lkey ! = device - > mr - > lkey ) {
tx_desc - > tx_sg [ 0 ] . lkey = device - > mr - > lkey ;
iser_dbg ( " sdesc %p lkey mismatch, fixing \n " , tx_desc ) ;
}
2006-05-11 10:02:19 +03:00
}
2010-02-08 13:19:56 +00:00
2012-03-05 18:21:44 +02:00
int iser_alloc_rx_descriptors ( struct iser_conn * ib_conn )
2010-02-08 13:17:42 +00:00
{
int i , j ;
u64 dma_addr ;
struct iser_rx_desc * rx_desc ;
struct ib_sge * rx_sg ;
struct iser_device * device = ib_conn - > device ;
ib_conn - > rx_descs = kmalloc ( ISER_QP_MAX_RECV_DTOS *
sizeof ( struct iser_rx_desc ) , GFP_KERNEL ) ;
if ( ! ib_conn - > rx_descs )
goto rx_desc_alloc_fail ;
rx_desc = ib_conn - > rx_descs ;
for ( i = 0 ; i < ISER_QP_MAX_RECV_DTOS ; i + + , rx_desc + + ) {
dma_addr = ib_dma_map_single ( device - > ib_device , ( void * ) rx_desc ,
ISER_RX_PAYLOAD_SIZE , DMA_FROM_DEVICE ) ;
if ( ib_dma_mapping_error ( device - > ib_device , dma_addr ) )
goto rx_desc_dma_map_failed ;
rx_desc - > dma_addr = dma_addr ;
rx_sg = & rx_desc - > rx_sg ;
rx_sg - > addr = rx_desc - > dma_addr ;
rx_sg - > length = ISER_RX_PAYLOAD_SIZE ;
rx_sg - > lkey = device - > mr - > lkey ;
}
ib_conn - > rx_desc_head = 0 ;
return 0 ;
rx_desc_dma_map_failed :
rx_desc = ib_conn - > rx_descs ;
for ( j = 0 ; j < i ; j + + , rx_desc + + )
ib_dma_unmap_single ( device - > ib_device , rx_desc - > dma_addr ,
ISER_RX_PAYLOAD_SIZE , DMA_FROM_DEVICE ) ;
kfree ( ib_conn - > rx_descs ) ;
ib_conn - > rx_descs = NULL ;
rx_desc_alloc_fail :
iser_err ( " failed allocating rx descriptors / data buffers \n " ) ;
return - ENOMEM ;
}
void iser_free_rx_descriptors ( struct iser_conn * ib_conn )
{
int i ;
struct iser_rx_desc * rx_desc ;
struct iser_device * device = ib_conn - > device ;
if ( ! ib_conn - > rx_descs )
return ;
rx_desc = ib_conn - > rx_descs ;
for ( i = 0 ; i < ISER_QP_MAX_RECV_DTOS ; i + + , rx_desc + + )
ib_dma_unmap_single ( device - > ib_device , rx_desc - > dma_addr ,
ISER_RX_PAYLOAD_SIZE , DMA_FROM_DEVICE ) ;
kfree ( ib_conn - > rx_descs ) ;
}
2012-03-05 18:21:44 +02:00
static int iser_post_rx_bufs ( struct iscsi_conn * conn , struct iscsi_hdr * req )
2006-05-11 10:02:19 +03:00
{
struct iscsi_iser_conn * iser_conn = conn - > dd_data ;
2012-03-05 18:21:44 +02:00
iser_dbg ( " req op %x flags %x \n " , req - > opcode , req - > flags ) ;
/* check if this is the last login - going to full feature phase */
if ( ( req - > flags & ISCSI_FULL_FEATURE_PHASE ) ! = ISCSI_FULL_FEATURE_PHASE )
return 0 ;
2006-05-11 10:02:19 +03:00
2012-03-05 18:21:44 +02:00
/*
* Check that there is one posted recv buffer ( for the last login
* response ) and no posted send buffers left - they must have been
* consumed during previous login phases .
*/
WARN_ON ( iser_conn - > ib_conn - > post_recv_buf_count ! = 1 ) ;
WARN_ON ( atomic_read ( & iser_conn - > ib_conn - > post_send_buf_count ) ! = 0 ) ;
2010-02-08 13:17:42 +00:00
2012-03-05 18:21:44 +02:00
iser_dbg ( " Initially post: %d \n " , ISER_MIN_POSTED_RX ) ;
2006-05-11 10:02:19 +03:00
/* Initial post receive buffers */
2010-02-08 13:17:42 +00:00
if ( iser_post_recvm ( iser_conn - > ib_conn , ISER_MIN_POSTED_RX ) )
return - ENOMEM ;
2006-05-11 10:02:19 +03:00
return 0 ;
}
/**
* iser_send_command - send command PDU
*/
2008-05-21 15:54:08 -05:00
int iser_send_command ( struct iscsi_conn * conn ,
2008-05-21 15:54:11 -05:00
struct iscsi_task * task )
2006-05-11 10:02:19 +03:00
{
struct iscsi_iser_conn * iser_conn = conn - > dd_data ;
2008-05-21 15:54:11 -05:00
struct iscsi_iser_task * iser_task = task - > dd_data ;
2006-05-11 10:02:19 +03:00
unsigned long edtl ;
2010-02-08 13:17:42 +00:00
int err ;
2006-05-11 10:02:19 +03:00
struct iser_data_buf * data_buf ;
2011-05-27 11:16:33 +00:00
struct iscsi_scsi_req * hdr = ( struct iscsi_scsi_req * ) task - > hdr ;
2008-05-21 15:54:11 -05:00
struct scsi_cmnd * sc = task - > sc ;
2010-02-08 13:19:56 +00:00
struct iser_tx_desc * tx_desc = & iser_task - > desc ;
2006-05-11 10:02:19 +03:00
edtl = ntohl ( hdr - > data_length ) ;
/* build the tx desc regd header and add it to the tx desc dto */
2010-02-08 13:19:56 +00:00
tx_desc - > type = ISCSI_TX_SCSI_COMMAND ;
iser_create_send_desc ( iser_conn - > ib_conn , tx_desc ) ;
2006-05-11 10:02:19 +03:00
if ( hdr - > flags & ISCSI_FLAG_CMD_READ )
2008-05-21 15:54:11 -05:00
data_buf = & iser_task - > data [ ISER_DIR_IN ] ;
2006-05-11 10:02:19 +03:00
else
2008-05-21 15:54:11 -05:00
data_buf = & iser_task - > data [ ISER_DIR_OUT ] ;
2006-05-11 10:02:19 +03:00
2007-06-01 18:56:21 +09:00
if ( scsi_sg_count ( sc ) ) { /* using a scatter list */
data_buf - > buf = scsi_sglist ( sc ) ;
data_buf - > size = scsi_sg_count ( sc ) ;
2006-05-11 10:02:19 +03:00
}
2007-06-01 18:56:21 +09:00
data_buf - > data_len = scsi_bufflen ( sc ) ;
2006-05-11 10:02:19 +03:00
if ( hdr - > flags & ISCSI_FLAG_CMD_READ ) {
2008-05-21 15:54:11 -05:00
err = iser_prepare_read_cmd ( task , edtl ) ;
2006-05-11 10:02:19 +03:00
if ( err )
goto send_command_error ;
}
if ( hdr - > flags & ISCSI_FLAG_CMD_WRITE ) {
2008-05-21 15:54:11 -05:00
err = iser_prepare_write_cmd ( task ,
task - > imm_count ,
task - > imm_count +
2008-12-02 00:32:06 -06:00
task - > unsol_r2t . data_length ,
2006-05-11 10:02:19 +03:00
edtl ) ;
if ( err )
goto send_command_error ;
}
2008-05-21 15:54:11 -05:00
iser_task - > status = ISER_TASK_STATUS_STARTED ;
2006-05-11 10:02:19 +03:00
2010-02-08 13:19:56 +00:00
err = iser_post_send ( iser_conn - > ib_conn , tx_desc ) ;
2006-05-11 10:02:19 +03:00
if ( ! err )
return 0 ;
send_command_error :
2008-05-21 15:54:11 -05:00
iser_err ( " conn %p failed task->itt %d err %d \n " , conn , task - > itt , err ) ;
2006-05-11 10:02:19 +03:00
return err ;
}
/**
* iser_send_data_out - send data out PDU
*/
2008-05-21 15:54:08 -05:00
int iser_send_data_out ( struct iscsi_conn * conn ,
2008-05-21 15:54:11 -05:00
struct iscsi_task * task ,
2006-05-11 10:02:19 +03:00
struct iscsi_data * hdr )
{
struct iscsi_iser_conn * iser_conn = conn - > dd_data ;
2008-05-21 15:54:11 -05:00
struct iscsi_iser_task * iser_task = task - > dd_data ;
2010-02-08 13:19:56 +00:00
struct iser_tx_desc * tx_desc = NULL ;
struct iser_regd_buf * regd_buf ;
2006-05-11 10:02:19 +03:00
unsigned long buf_offset ;
unsigned long data_seg_len ;
2008-04-16 21:09:35 -07:00
uint32_t itt ;
2006-05-11 10:02:19 +03:00
int err = 0 ;
2010-02-08 13:19:56 +00:00
struct ib_sge * tx_dsg ;
2008-04-16 21:09:35 -07:00
itt = ( __force uint32_t ) hdr - > itt ;
2006-05-11 10:02:19 +03:00
data_seg_len = ntoh24 ( hdr - > dlength ) ;
buf_offset = ntohl ( hdr - > offset ) ;
iser_dbg ( " %s itt %d dseg_len %d offset %d \n " ,
__func__ , ( int ) itt , ( int ) data_seg_len , ( int ) buf_offset ) ;
2010-02-08 13:20:43 +00:00
tx_desc = kmem_cache_zalloc ( ig . desc_cache , GFP_ATOMIC ) ;
2006-05-11 10:02:19 +03:00
if ( tx_desc = = NULL ) {
iser_err ( " Failed to alloc desc for post dataout \n " ) ;
return - ENOMEM ;
}
tx_desc - > type = ISCSI_TX_DATAOUT ;
2010-02-08 13:19:56 +00:00
tx_desc - > iser_header . flags = ISER_VER ;
2006-05-11 10:02:19 +03:00
memcpy ( & tx_desc - > iscsi_header , hdr , sizeof ( struct iscsi_hdr ) ) ;
2010-02-08 13:19:56 +00:00
/* build the tx desc */
iser_initialize_task_headers ( task , tx_desc ) ;
2006-05-11 10:02:19 +03:00
2010-02-08 13:19:56 +00:00
regd_buf = & iser_task - > rdma_regd [ ISER_DIR_OUT ] ;
tx_dsg = & tx_desc - > tx_sg [ 1 ] ;
tx_dsg - > addr = regd_buf - > reg . va + buf_offset ;
tx_dsg - > length = data_seg_len ;
tx_dsg - > lkey = regd_buf - > reg . lkey ;
tx_desc - > num_sge = 2 ;
2006-05-11 10:02:19 +03:00
2008-05-21 15:54:11 -05:00
if ( buf_offset + data_seg_len > iser_task - > data [ ISER_DIR_OUT ] . data_len ) {
2006-05-11 10:02:19 +03:00
iser_err ( " Offset:%ld & DSL:%ld in Data-Out "
" inconsistent with total len:%ld, itt:%d \n " ,
buf_offset , data_seg_len ,
2008-05-21 15:54:11 -05:00
iser_task - > data [ ISER_DIR_OUT ] . data_len , itt ) ;
2006-05-11 10:02:19 +03:00
err = - EINVAL ;
goto send_data_out_error ;
}
iser_dbg ( " data-out itt: %d, offset: %ld, sz: %ld \n " ,
itt , buf_offset , data_seg_len ) ;
2010-02-08 13:19:56 +00:00
err = iser_post_send ( iser_conn - > ib_conn , tx_desc ) ;
2006-05-11 10:02:19 +03:00
if ( ! err )
return 0 ;
send_data_out_error :
kmem_cache_free ( ig . desc_cache , tx_desc ) ;
iser_err ( " conn %p failed err %d \n " , conn , err ) ;
return err ;
}
int iser_send_control ( struct iscsi_conn * conn ,
2008-05-21 15:54:11 -05:00
struct iscsi_task * task )
2006-05-11 10:02:19 +03:00
{
struct iscsi_iser_conn * iser_conn = conn - > dd_data ;
2008-05-21 15:54:11 -05:00
struct iscsi_iser_task * iser_task = task - > dd_data ;
2010-02-08 13:19:56 +00:00
struct iser_tx_desc * mdesc = & iser_task - > desc ;
2006-05-11 10:02:19 +03:00
unsigned long data_seg_len ;
2010-02-08 13:19:56 +00:00
int err = 0 ;
2006-05-11 10:02:19 +03:00
struct iser_device * device ;
2011-11-04 00:19:46 +02:00
struct iser_conn * ib_conn = iser_conn - > ib_conn ;
2006-05-11 10:02:19 +03:00
/* build the tx desc regd header and add it to the tx desc dto */
mdesc - > type = ISCSI_TX_CONTROL ;
2010-02-08 13:19:56 +00:00
iser_create_send_desc ( iser_conn - > ib_conn , mdesc ) ;
2006-05-11 10:02:19 +03:00
device = iser_conn - > ib_conn - > device ;
2008-05-21 15:54:11 -05:00
data_seg_len = ntoh24 ( task - > hdr - > dlength ) ;
2006-05-11 10:02:19 +03:00
if ( data_seg_len > 0 ) {
2010-02-08 13:19:56 +00:00
struct ib_sge * tx_dsg = & mdesc - > tx_sg [ 1 ] ;
if ( task ! = conn - > login_task ) {
iser_err ( " data present on non login task!!! \n " ) ;
goto send_control_error ;
}
2011-11-04 00:19:46 +02:00
ib_dma_sync_single_for_cpu ( device - > ib_device ,
ib_conn - > login_req_dma , task - > data_count ,
DMA_TO_DEVICE ) ;
memcpy ( iser_conn - > ib_conn - > login_req_buf , task - > data ,
2010-02-08 13:19:56 +00:00
task - > data_count ) ;
2011-11-04 00:19:46 +02:00
ib_dma_sync_single_for_device ( device - > ib_device ,
ib_conn - > login_req_dma , task - > data_count ,
DMA_TO_DEVICE ) ;
tx_dsg - > addr = iser_conn - > ib_conn - > login_req_dma ;
2011-08-01 21:14:09 +00:00
tx_dsg - > length = task - > data_count ;
2010-02-08 13:19:56 +00:00
tx_dsg - > lkey = device - > mr - > lkey ;
mdesc - > num_sge = 2 ;
2006-05-11 10:02:19 +03:00
}
2010-02-08 13:17:42 +00:00
if ( task = = conn - > login_task ) {
err = iser_post_recvl ( iser_conn - > ib_conn ) ;
if ( err )
goto send_control_error ;
2012-03-05 18:21:44 +02:00
err = iser_post_rx_bufs ( conn , task - > hdr ) ;
if ( err )
goto send_control_error ;
2006-05-11 10:02:19 +03:00
}
2010-02-08 13:19:56 +00:00
err = iser_post_send ( iser_conn - > ib_conn , mdesc ) ;
2006-05-11 10:02:19 +03:00
if ( ! err )
return 0 ;
send_control_error :
iser_err ( " conn %p failed err %d \n " , conn , err ) ;
return err ;
}
/**
* iser_rcv_dto_completion - recv DTO completion
*/
2010-02-08 13:17:42 +00:00
void iser_rcv_completion ( struct iser_rx_desc * rx_desc ,
unsigned long rx_xfer_len ,
struct iser_conn * ib_conn )
2006-05-11 10:02:19 +03:00
{
2010-02-08 13:17:42 +00:00
struct iscsi_iser_conn * conn = ib_conn - > iser_conn ;
2006-05-11 10:02:19 +03:00
struct iscsi_hdr * hdr ;
2010-02-08 13:17:42 +00:00
u64 rx_dma ;
int rx_buflen , outstanding , count , err ;
/* differentiate between login to all other PDUs */
2011-11-04 00:19:46 +02:00
if ( ( char * ) rx_desc = = ib_conn - > login_resp_buf ) {
rx_dma = ib_conn - > login_resp_dma ;
2010-02-08 13:17:42 +00:00
rx_buflen = ISER_RX_LOGIN_SIZE ;
} else {
rx_dma = rx_desc - > dma_addr ;
rx_buflen = ISER_RX_PAYLOAD_SIZE ;
}
2006-05-11 10:02:19 +03:00
2010-02-08 13:17:42 +00:00
ib_dma_sync_single_for_cpu ( ib_conn - > device - > ib_device , rx_dma ,
rx_buflen , DMA_FROM_DEVICE ) ;
2006-05-11 10:02:19 +03:00
2010-02-08 13:17:42 +00:00
hdr = & rx_desc - > iscsi_header ;
2006-05-11 10:02:19 +03:00
2010-02-08 13:17:42 +00:00
iser_dbg ( " op 0x%x itt 0x%x dlen %d \n " , hdr - > opcode ,
hdr - > itt , ( int ) ( rx_xfer_len - ISER_HEADERS_LEN ) ) ;
2006-05-11 10:02:19 +03:00
2010-02-08 13:17:42 +00:00
iscsi_iser_recv ( conn - > iscsi_conn , hdr ,
rx_desc - > data , rx_xfer_len - ISER_HEADERS_LEN ) ;
2006-05-11 10:02:19 +03:00
2010-02-08 13:17:42 +00:00
ib_dma_sync_single_for_device ( ib_conn - > device - > ib_device , rx_dma ,
rx_buflen , DMA_FROM_DEVICE ) ;
2006-05-11 10:02:19 +03:00
/* decrementing conn->post_recv_buf_count only --after-- freeing the *
* task eliminates the need to worry on tasks which are completed in *
* parallel to the execution of iser_conn_term . So the code that waits *
* for the posted rx bufs refcount to become zero handles everything */
2010-02-08 13:18:39 +00:00
conn - > ib_conn - > post_recv_buf_count - - ;
2010-02-08 13:17:42 +00:00
2011-11-04 00:19:46 +02:00
if ( rx_dma = = ib_conn - > login_resp_dma )
2010-02-08 13:17:42 +00:00
return ;
2010-02-08 13:18:39 +00:00
outstanding = ib_conn - > post_recv_buf_count ;
2010-02-08 13:17:42 +00:00
if ( outstanding + ISER_MIN_POSTED_RX < = ISER_QP_MAX_RECV_DTOS ) {
count = min ( ISER_QP_MAX_RECV_DTOS - outstanding ,
ISER_MIN_POSTED_RX ) ;
err = iser_post_recvm ( ib_conn , count ) ;
if ( err )
iser_err ( " posting %d rx bufs err %d \n " , count , err ) ;
}
2006-05-11 10:02:19 +03:00
}
2010-02-08 13:19:56 +00:00
void iser_snd_completion ( struct iser_tx_desc * tx_desc ,
struct iser_conn * ib_conn )
2006-05-11 10:02:19 +03:00
{
2008-05-21 15:54:11 -05:00
struct iscsi_task * task ;
2010-02-08 13:19:56 +00:00
struct iser_device * device = ib_conn - > device ;
2006-05-11 10:02:19 +03:00
2010-02-08 13:19:56 +00:00
if ( tx_desc - > type = = ISCSI_TX_DATAOUT ) {
ib_dma_unmap_single ( device - > ib_device , tx_desc - > dma_addr ,
ISER_HEADERS_LEN , DMA_TO_DEVICE ) ;
2006-05-11 10:02:19 +03:00
kmem_cache_free ( ig . desc_cache , tx_desc ) ;
2010-02-08 13:19:56 +00:00
}
2006-05-11 10:02:19 +03:00
2006-09-27 15:27:10 +03:00
atomic_dec ( & ib_conn - > post_send_buf_count ) ;
2006-05-11 10:02:19 +03:00
if ( tx_desc - > type = = ISCSI_TX_CONTROL ) {
/* this arithmetic is legal by libiscsi dd_data allocation */
2008-05-21 15:54:11 -05:00
task = ( void * ) ( ( long ) ( void * ) tx_desc -
sizeof ( struct iscsi_task ) ) ;
if ( task - > hdr - > itt = = RESERVED_ITT )
iscsi_put_task ( task ) ;
2006-05-11 10:02:19 +03:00
}
}
2008-05-21 15:54:11 -05:00
void iser_task_rdma_init ( struct iscsi_iser_task * iser_task )
2006-05-11 10:02:19 +03:00
{
2008-05-21 15:54:11 -05:00
iser_task - > status = ISER_TASK_STATUS_INIT ;
2006-05-11 10:02:19 +03:00
2008-05-21 15:54:11 -05:00
iser_task - > dir [ ISER_DIR_IN ] = 0 ;
iser_task - > dir [ ISER_DIR_OUT ] = 0 ;
2006-05-11 10:02:19 +03:00
2008-05-21 15:54:11 -05:00
iser_task - > data [ ISER_DIR_IN ] . data_len = 0 ;
iser_task - > data [ ISER_DIR_OUT ] . data_len = 0 ;
2006-05-11 10:02:19 +03:00
2008-05-21 15:54:11 -05:00
memset ( & iser_task - > rdma_regd [ ISER_DIR_IN ] , 0 ,
2006-05-11 10:02:19 +03:00
sizeof ( struct iser_regd_buf ) ) ;
2008-05-21 15:54:11 -05:00
memset ( & iser_task - > rdma_regd [ ISER_DIR_OUT ] , 0 ,
2006-05-11 10:02:19 +03:00
sizeof ( struct iser_regd_buf ) ) ;
}
2008-05-21 15:54:11 -05:00
void iser_task_rdma_finalize ( struct iscsi_iser_task * iser_task )
2006-05-11 10:02:19 +03:00
{
2006-09-27 16:43:06 +03:00
int is_rdma_aligned = 1 ;
2007-03-25 12:07:10 +02:00
struct iser_regd_buf * regd ;
2006-05-11 10:02:19 +03:00
/* if we were reading, copy back to unaligned sglist,
* anyway dma_unmap and free the copy
*/
2008-05-21 15:54:11 -05:00
if ( iser_task - > data_copy [ ISER_DIR_IN ] . copy_buf ! = NULL ) {
2006-09-27 16:43:06 +03:00
is_rdma_aligned = 0 ;
2008-05-21 15:54:11 -05:00
iser_finalize_rdma_unaligned_sg ( iser_task , ISER_DIR_IN ) ;
2006-09-27 16:43:06 +03:00
}
2008-05-21 15:54:11 -05:00
if ( iser_task - > data_copy [ ISER_DIR_OUT ] . copy_buf ! = NULL ) {
2006-09-27 16:43:06 +03:00
is_rdma_aligned = 0 ;
2008-05-21 15:54:11 -05:00
iser_finalize_rdma_unaligned_sg ( iser_task , ISER_DIR_OUT ) ;
2006-09-27 16:43:06 +03:00
}
2006-05-11 10:02:19 +03:00
2008-05-21 15:54:11 -05:00
if ( iser_task - > dir [ ISER_DIR_IN ] ) {
regd = & iser_task - > rdma_regd [ ISER_DIR_IN ] ;
2010-02-08 13:19:56 +00:00
if ( regd - > reg . is_fmr )
iser_unreg_mem ( & regd - > reg ) ;
2006-05-11 10:02:19 +03:00
}
2008-05-21 15:54:11 -05:00
if ( iser_task - > dir [ ISER_DIR_OUT ] ) {
regd = & iser_task - > rdma_regd [ ISER_DIR_OUT ] ;
2010-02-08 13:19:56 +00:00
if ( regd - > reg . is_fmr )
iser_unreg_mem ( & regd - > reg ) ;
2006-05-11 10:02:19 +03:00
}
2006-09-27 16:43:06 +03:00
/* if the data was unaligned, it was already unmapped and then copied */
if ( is_rdma_aligned )
2008-05-21 15:54:11 -05:00
iser_dma_unmap_task_data ( iser_task ) ;
2006-05-11 10:02:19 +03:00
}