2015-03-30 14:34:21 -04:00
/*
* Copyright ( c ) 2015 Oracle . All rights reserved .
* Copyright ( c ) 2003 - 2007 Network Appliance , Inc . All rights reserved .
*/
/* Lightweight memory registration using Fast Registration Work
* Requests ( FRWR ) . Also referred to sometimes as FRMR mode .
*
* FRWR features ordered asynchronous registration and deregistration
* of arbitrarily sized memory regions . This is the fastest and safest
* but most complex memory registration mode .
*/
2015-05-26 11:52:35 -04:00
/* Normal operation
*
* A Memory Region is prepared for RDMA READ or WRITE using a FAST_REG
* Work Request ( frmr_op_map ) . When the RDMA operation is finished , this
* Memory Region is invalidated using a LOCAL_INV Work Request
* ( frmr_op_unmap ) .
*
* Typically these Work Requests are not signaled , and neither are RDMA
* SEND Work Requests ( with the exception of signaling occasionally to
* prevent provider work queue overflows ) . This greatly reduces HCA
* interrupt workload .
*
* As an optimization , frwr_op_unmap marks MRs INVALID before the
* LOCAL_INV WR is posted . If posting succeeds , the MR is placed on
* rb_mws immediately so that no work ( like managing a linked list
* under a spinlock ) is needed in the completion upcall .
*
* But this means that frwr_op_map ( ) can occasionally encounter an MR
* that is INVALID but the LOCAL_INV WR has not completed . Work Queue
* ordering prevents a subsequent FAST_REG WR from executing against
* that MR while it is still being invalidated .
*/
/* Transport recovery
*
* - > op_map and the transport connect worker cannot run at the same
* time , but - > op_unmap can fire while the transport connect worker
* is running . Thus MR recovery is handled in - > op_map , to guarantee
* that recovered MRs are owned by a sending RPC , and not one where
* - > op_unmap could fire at the same time transport reconnect is
* being done .
*
* When the underlying transport disconnects , MRs are left in one of
* three states :
*
* INVALID : The MR was not in use before the QP entered ERROR state .
* ( Or , the LOCAL_INV WR has not completed or flushed yet ) .
*
* STALE : The MR was being registered or unregistered when the QP
* entered ERROR state , and the pending WR was flushed .
*
* VALID : The MR was registered before the QP entered ERROR state .
*
* When frwr_op_map encounters STALE and VALID MRs , they are recovered
* with ib_dereg_mr and then are re - initialized . Beause MR recovery
* allocates fresh resources , it is deferred to a workqueue , and the
* recovered MRs are placed back on the rb_mws list when recovery is
* complete . frwr_op_map allocates another MR for the current RPC while
* the broken MR is reset .
*
* To ensure that frwr_op_map doesn ' t encounter an MR that is marked
* INVALID but that is about to be flushed due to a previous transport
* disconnect , the transport connect worker attempts to drain all
* pending send queue WRs before the transport is reconnected .
*/
2015-03-30 14:34:21 -04:00
# include "xprt_rdma.h"
# if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
# define RPCDBG_FACILITY RPCDBG_TRANS
# endif
2016-06-29 13:53:27 -04:00
bool
frwr_is_supported ( struct rpcrdma_ia * ia )
{
struct ib_device_attr * attrs = & ia - > ri_device - > attrs ;
if ( ! ( attrs - > device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS ) )
goto out_not_supported ;
if ( attrs - > max_fast_reg_page_list_len = = 0 )
goto out_not_supported ;
return true ;
out_not_supported :
pr_info ( " rpcrdma: 'frwr' mode is not supported by device %s \n " ,
ia - > ri_device - > name ) ;
return false ;
}
2016-06-29 13:52:29 -04:00
static int
2016-06-29 13:54:00 -04:00
frwr_op_init_mr ( struct rpcrdma_ia * ia , struct rpcrdma_mw * r )
2016-06-29 13:52:29 -04:00
{
2016-06-29 13:54:00 -04:00
unsigned int depth = ia - > ri_max_frmr_depth ;
2016-06-29 13:52:29 -04:00
struct rpcrdma_frmr * f = & r - > frmr ;
int rc ;
2016-06-29 13:54:00 -04:00
f - > fr_mr = ib_alloc_mr ( ia - > ri_pd , IB_MR_TYPE_MEM_REG , depth ) ;
2016-06-29 13:52:29 -04:00
if ( IS_ERR ( f - > fr_mr ) )
goto out_mr_err ;
r - > mw_sg = kcalloc ( depth , sizeof ( * r - > mw_sg ) , GFP_KERNEL ) ;
if ( ! r - > mw_sg )
goto out_list_err ;
sg_init_table ( r - > mw_sg , depth ) ;
init_completion ( & f - > fr_linv_done ) ;
return 0 ;
out_mr_err :
rc = PTR_ERR ( f - > fr_mr ) ;
dprintk ( " RPC: %s: ib_alloc_mr status %i \n " ,
__func__ , rc ) ;
return rc ;
out_list_err :
rc = - ENOMEM ;
dprintk ( " RPC: %s: sg allocation failure \n " ,
__func__ ) ;
ib_dereg_mr ( f - > fr_mr ) ;
return rc ;
}
static void
2016-06-29 13:54:00 -04:00
frwr_op_release_mr ( struct rpcrdma_mw * r )
2016-06-29 13:52:29 -04:00
{
int rc ;
2016-06-29 13:54:16 -04:00
/* Ensure MW is not on any rl_registered list */
if ( ! list_empty ( & r - > mw_list ) )
list_del ( & r - > mw_list ) ;
2016-06-29 13:52:29 -04:00
rc = ib_dereg_mr ( r - > frmr . fr_mr ) ;
if ( rc )
pr_err ( " rpcrdma: final ib_dereg_mr for %p returned %i \n " ,
r , rc ) ;
kfree ( r - > mw_sg ) ;
2016-06-29 13:54:00 -04:00
kfree ( r ) ;
2016-06-29 13:52:29 -04:00
}
2016-05-02 14:42:12 -04:00
static int
__frwr_reset_mr ( struct rpcrdma_ia * ia , struct rpcrdma_mw * r )
{
struct rpcrdma_frmr * f = & r - > frmr ;
int rc ;
rc = ib_dereg_mr ( f - > fr_mr ) ;
if ( rc ) {
pr_warn ( " rpcrdma: ib_dereg_mr status %d, frwr %p orphaned \n " ,
rc , r ) ;
return rc ;
}
f - > fr_mr = ib_alloc_mr ( ia - > ri_pd , IB_MR_TYPE_MEM_REG ,
ia - > ri_max_frmr_depth ) ;
if ( IS_ERR ( f - > fr_mr ) ) {
pr_warn ( " rpcrdma: ib_alloc_mr status %ld, frwr %p orphaned \n " ,
PTR_ERR ( f - > fr_mr ) , r ) ;
return PTR_ERR ( f - > fr_mr ) ;
}
dprintk ( " RPC: %s: recovered FRMR %p \n " , __func__ , r ) ;
f - > fr_state = FRMR_IS_INVALID ;
return 0 ;
}
2016-06-29 13:52:54 -04:00
/* Reset of a single FRMR. Generate a fresh rkey by replacing the MR.
*
* There ' s no recovery if this fails . The FRMR is abandoned , but
* remains in rb_all . It will be cleaned up when the transport is
* destroyed .
*/
2016-05-02 14:42:21 -04:00
static void
2016-06-29 13:52:54 -04:00
frwr_op_recover_mr ( struct rpcrdma_mw * mw )
2016-05-02 14:42:21 -04:00
{
2016-06-29 13:52:21 -04:00
struct rpcrdma_xprt * r_xprt = mw - > mw_xprt ;
2016-05-02 14:42:21 -04:00
struct rpcrdma_ia * ia = & r_xprt - > rx_ia ;
int rc ;
rc = __frwr_reset_mr ( ia , mw ) ;
2016-06-29 13:52:21 -04:00
ib_dma_unmap_sg ( ia - > ri_device , mw - > mw_sg , mw - > mw_nents , mw - > mw_dir ) ;
2016-06-29 13:54:08 -04:00
if ( rc )
goto out_release ;
2015-05-26 11:52:25 -04:00
2016-06-29 13:52:54 -04:00
rpcrdma_put_mw ( r_xprt , mw ) ;
r_xprt - > rx_stats . mrs_recovered + + ;
2016-06-29 13:54:08 -04:00
return ;
out_release :
pr_err ( " rpcrdma: FRMR reset failed %d, %p release \n " , rc , mw ) ;
r_xprt - > rx_stats . mrs_orphaned + + ;
spin_lock ( & r_xprt - > rx_buf . rb_mwlock ) ;
list_del ( & mw - > mw_all ) ;
spin_unlock ( & r_xprt - > rx_buf . rb_mwlock ) ;
frwr_op_release_mr ( mw ) ;
2015-05-26 11:52:25 -04:00
}
2015-03-30 14:35:26 -04:00
static int
frwr_op_open ( struct rpcrdma_ia * ia , struct rpcrdma_ep * ep ,
struct rpcrdma_create_data_internal * cdata )
{
int depth , delta ;
ia - > ri_max_frmr_depth =
min_t ( unsigned int , RPCRDMA_MAX_DATA_SEGS ,
2015-12-18 10:59:48 +02:00
ia - > ri_device - > attrs . max_fast_reg_page_list_len ) ;
2015-03-30 14:35:26 -04:00
dprintk ( " RPC: %s: device's max FR page list len = %u \n " ,
__func__ , ia - > ri_max_frmr_depth ) ;
/* Add room for frmr register and invalidate WRs.
* 1. FRMR reg WR for head
* 2. FRMR invalidate WR for head
* 3. N FRMR reg WRs for pagelist
* 4. N FRMR invalidate WRs for pagelist
* 5. FRMR reg WR for tail
* 6. FRMR invalidate WR for tail
* 7. The RDMA_SEND WR
*/
depth = 7 ;
/* Calculate N if the device max FRMR depth is smaller than
* RPCRDMA_MAX_DATA_SEGS .
*/
if ( ia - > ri_max_frmr_depth < RPCRDMA_MAX_DATA_SEGS ) {
delta = RPCRDMA_MAX_DATA_SEGS - ia - > ri_max_frmr_depth ;
do {
depth + = 2 ; /* FRMR reg + invalidate */
delta - = ia - > ri_max_frmr_depth ;
} while ( delta > 0 ) ;
}
ep - > rep_attr . cap . max_send_wr * = depth ;
2015-12-18 10:59:48 +02:00
if ( ep - > rep_attr . cap . max_send_wr > ia - > ri_device - > attrs . max_qp_wr ) {
cdata - > max_requests = ia - > ri_device - > attrs . max_qp_wr / depth ;
2015-03-30 14:35:26 -04:00
if ( ! cdata - > max_requests )
return - EINVAL ;
ep - > rep_attr . cap . max_send_wr = cdata - > max_requests *
depth ;
}
2016-09-15 10:57:07 -04:00
ia - > ri_max_segs = max_t ( unsigned int , 1 , RPCRDMA_MAX_DATA_SEGS /
ia - > ri_max_frmr_depth ) ;
2015-03-30 14:35:26 -04:00
return 0 ;
}
2015-03-30 14:34:30 -04:00
/* FRWR mode conveys a list of pages per chunk segment. The
* maximum length of that list is the FRWR page list depth .
*/
static size_t
frwr_op_maxpages ( struct rpcrdma_xprt * r_xprt )
{
struct rpcrdma_ia * ia = & r_xprt - > rx_ia ;
return min_t ( unsigned int , RPCRDMA_MAX_DATA_SEGS ,
2016-05-02 14:40:56 -04:00
RPCRDMA_MAX_HDR_SEGS * ia - > ri_max_frmr_depth ) ;
2015-03-30 14:34:30 -04:00
}
2016-03-04 11:28:53 -05:00
static void
__frwr_sendcompletion_flush ( struct ib_wc * wc , struct rpcrdma_frmr * frmr ,
const char * wr )
{
frmr - > fr_state = FRMR_IS_STALE ;
if ( wc - > status ! = IB_WC_WR_FLUSH_ERR )
pr_err ( " rpcrdma: %s: %s (%u/0x%x) \n " ,
wr , ib_wc_status_msg ( wc - > status ) ,
wc - > status , wc - > vendor_err ) ;
}
/**
* frwr_wc_fastreg - Invoked by RDMA provider for each polled FastReg WC
* @ cq : completion queue ( ignored )
* @ wc : completed WR
2015-12-16 17:22:47 -05:00
*
*/
2015-03-30 14:35:35 -04:00
static void
2016-03-04 11:28:53 -05:00
frwr_wc_fastreg ( struct ib_cq * cq , struct ib_wc * wc )
2015-03-30 14:35:35 -04:00
{
2016-03-04 11:28:53 -05:00
struct rpcrdma_frmr * frmr ;
struct ib_cqe * cqe ;
2015-12-16 17:22:47 -05:00
2016-03-04 11:28:53 -05:00
/* WARNING: Only wr_cqe and status are reliable at this point */
if ( wc - > status ! = IB_WC_SUCCESS ) {
cqe = wc - > wr_cqe ;
frmr = container_of ( cqe , struct rpcrdma_frmr , fr_cqe ) ;
__frwr_sendcompletion_flush ( wc , frmr , " fastreg " ) ;
}
2015-03-30 14:35:35 -04:00
}
2016-03-04 11:28:53 -05:00
/**
* frwr_wc_localinv - Invoked by RDMA provider for each polled LocalInv WC
* @ cq : completion queue ( ignored )
* @ wc : completed WR
*
*/
2015-12-16 17:22:47 -05:00
static void
2016-03-04 11:28:53 -05:00
frwr_wc_localinv ( struct ib_cq * cq , struct ib_wc * wc )
2015-12-16 17:22:47 -05:00
{
2016-03-04 11:28:53 -05:00
struct rpcrdma_frmr * frmr ;
struct ib_cqe * cqe ;
2015-12-16 17:22:47 -05:00
2016-03-04 11:28:53 -05:00
/* WARNING: Only wr_cqe and status are reliable at this point */
if ( wc - > status ! = IB_WC_SUCCESS ) {
cqe = wc - > wr_cqe ;
frmr = container_of ( cqe , struct rpcrdma_frmr , fr_cqe ) ;
__frwr_sendcompletion_flush ( wc , frmr , " localinv " ) ;
}
}
2015-12-16 17:22:47 -05:00
2016-03-04 11:28:53 -05:00
/**
* frwr_wc_localinv - Invoked by RDMA provider for each polled LocalInv WC
* @ cq : completion queue ( ignored )
* @ wc : completed WR
*
* Awaken anyone waiting for an MR to finish being fenced .
*/
static void
frwr_wc_localinv_wake ( struct ib_cq * cq , struct ib_wc * wc )
{
struct rpcrdma_frmr * frmr ;
struct ib_cqe * cqe ;
/* WARNING: Only wr_cqe and status are reliable at this point */
cqe = wc - > wr_cqe ;
frmr = container_of ( cqe , struct rpcrdma_frmr , fr_cqe ) ;
if ( wc - > status ! = IB_WC_SUCCESS )
__frwr_sendcompletion_flush ( wc , frmr , " localinv " ) ;
complete_all ( & frmr - > fr_linv_done ) ;
2015-12-16 17:22:47 -05:00
}
2016-06-29 13:52:21 -04:00
/* Post a REG_MR Work Request to register a memory region
2015-03-30 14:34:39 -04:00
* for remote access via RDMA READ or RDMA WRITE .
*/
static int
frwr_op_map ( struct rpcrdma_xprt * r_xprt , struct rpcrdma_mr_seg * seg ,
2016-06-29 13:54:16 -04:00
int nsegs , bool writing , struct rpcrdma_mw * * out )
2015-03-30 14:34:39 -04:00
{
struct rpcrdma_ia * ia = & r_xprt - > rx_ia ;
2015-05-26 11:52:35 -04:00
struct rpcrdma_mw * mw ;
struct rpcrdma_frmr * frmr ;
struct ib_mr * mr ;
2015-12-16 17:22:31 -05:00
struct ib_reg_wr * reg_wr ;
2015-10-08 09:16:33 +01:00
struct ib_send_wr * bad_wr ;
2015-10-13 19:11:35 +03:00
int rc , i , n , dma_nents ;
2015-03-30 14:34:39 -04:00
u8 key ;
2016-06-29 13:54:16 -04:00
mw = NULL ;
2015-05-26 11:52:35 -04:00
do {
if ( mw )
2016-06-29 13:52:54 -04:00
rpcrdma_defer_mr_recovery ( mw ) ;
2015-05-26 11:52:35 -04:00
mw = rpcrdma_get_mw ( r_xprt ) ;
if ( ! mw )
2016-06-29 13:53:43 -04:00
return - ENOBUFS ;
2016-03-04 11:28:45 -05:00
} while ( mw - > frmr . fr_state ! = FRMR_IS_INVALID ) ;
frmr = & mw - > frmr ;
2015-05-26 11:52:35 -04:00
frmr - > fr_state = FRMR_IS_VALID ;
2015-10-13 19:11:35 +03:00
mr = frmr - > fr_mr ;
2015-12-16 17:22:31 -05:00
reg_wr = & frmr - > fr_regwr ;
2015-05-26 11:52:35 -04:00
2015-03-30 14:34:39 -04:00
if ( nsegs > ia - > ri_max_frmr_depth )
nsegs = ia - > ri_max_frmr_depth ;
2015-10-13 19:11:35 +03:00
for ( i = 0 ; i < nsegs ; ) {
if ( seg - > mr_page )
2016-06-29 13:52:21 -04:00
sg_set_page ( & mw - > mw_sg [ i ] ,
2015-10-13 19:11:35 +03:00
seg - > mr_page ,
seg - > mr_len ,
offset_in_page ( seg - > mr_offset ) ) ;
else
2016-06-29 13:52:21 -04:00
sg_set_buf ( & mw - > mw_sg [ i ] , seg - > mr_offset ,
2015-10-13 19:11:35 +03:00
seg - > mr_len ) ;
2015-03-30 14:34:39 -04:00
+ + seg ;
+ + i ;
2015-10-13 19:11:35 +03:00
2015-03-30 14:34:39 -04:00
/* Check for holes */
if ( ( i < nsegs & & offset_in_page ( seg - > mr_offset ) ) | |
offset_in_page ( ( seg - 1 ) - > mr_offset + ( seg - 1 ) - > mr_len ) )
break ;
}
2016-06-29 13:52:21 -04:00
mw - > mw_nents = i ;
mw - > mw_dir = rpcrdma_data_dir ( writing ) ;
2016-06-29 13:53:52 -04:00
if ( i = = 0 )
goto out_dmamap_err ;
2015-10-13 19:11:35 +03:00
2016-06-29 13:52:21 -04:00
dma_nents = ib_dma_map_sg ( ia - > ri_device ,
mw - > mw_sg , mw - > mw_nents , mw - > mw_dir ) ;
if ( ! dma_nents )
goto out_dmamap_err ;
n = ib_map_mr_sg ( mr , mw - > mw_sg , mw - > mw_nents , NULL , PAGE_SIZE ) ;
if ( unlikely ( n ! = mw - > mw_nents ) )
goto out_mapmr_err ;
2015-10-13 19:11:35 +03:00
dprintk ( " RPC: %s: Using frmr %p to map %u segments (%u bytes) \n " ,
2016-06-29 13:52:21 -04:00
__func__ , mw , mw - > mw_nents , mr - > length ) ;
2015-10-13 19:11:35 +03:00
2015-03-30 14:34:39 -04:00
key = ( u8 ) ( mr - > rkey & 0x000000FF ) ;
ib_update_fast_reg_key ( mr , + + key ) ;
2015-10-13 19:11:35 +03:00
2015-12-16 17:22:31 -05:00
reg_wr - > wr . next = NULL ;
reg_wr - > wr . opcode = IB_WR_REG_MR ;
2016-03-04 11:28:53 -05:00
frmr - > fr_cqe . done = frwr_wc_fastreg ;
reg_wr - > wr . wr_cqe = & frmr - > fr_cqe ;
2015-12-16 17:22:31 -05:00
reg_wr - > wr . num_sge = 0 ;
reg_wr - > wr . send_flags = 0 ;
reg_wr - > mr = mr ;
reg_wr - > key = mr - > rkey ;
reg_wr - > access = writing ?
IB_ACCESS_REMOTE_WRITE | IB_ACCESS_LOCAL_WRITE :
IB_ACCESS_REMOTE_READ ;
2015-03-30 14:34:39 -04:00
DECR_CQCOUNT ( & r_xprt - > rx_ep ) ;
2015-12-16 17:22:31 -05:00
rc = ib_post_send ( ia - > ri_id - > qp , & reg_wr - > wr , & bad_wr ) ;
2015-03-30 14:34:39 -04:00
if ( rc )
goto out_senderr ;
2016-06-29 13:54:16 -04:00
mw - > mw_handle = mr - > rkey ;
mw - > mw_length = mr - > length ;
mw - > mw_offset = mr - > iova ;
2015-10-13 19:11:35 +03:00
2016-06-29 13:54:16 -04:00
* out = mw ;
2016-06-29 13:52:21 -04:00
return mw - > mw_nents ;
out_dmamap_err :
pr_err ( " rpcrdma: failed to dma map sg %p sg_nents %u \n " ,
mw - > mw_sg , mw - > mw_nents ) ;
2016-06-29 13:53:02 -04:00
rpcrdma_defer_mr_recovery ( mw ) ;
2016-06-29 13:53:43 -04:00
return - EIO ;
2016-06-29 13:52:21 -04:00
out_mapmr_err :
pr_err ( " rpcrdma: failed to map mr %p (%u/%u) \n " ,
frmr - > fr_mr , n , mw - > mw_nents ) ;
2016-06-29 13:52:54 -04:00
rpcrdma_defer_mr_recovery ( mw ) ;
2016-06-29 13:53:43 -04:00
return - EIO ;
2015-03-30 14:34:39 -04:00
out_senderr :
2016-06-29 13:53:43 -04:00
pr_err ( " rpcrdma: FRMR registration ib_post_send returned %i \n " , rc ) ;
2016-06-29 13:52:54 -04:00
rpcrdma_defer_mr_recovery ( mw ) ;
2016-06-29 13:53:43 -04:00
return - ENOTCONN ;
2015-03-30 14:34:39 -04:00
}
2015-12-16 17:22:47 -05:00
static struct ib_send_wr *
2016-06-29 13:54:16 -04:00
__frwr_prepare_linv_wr ( struct rpcrdma_mw * mw )
2015-12-16 17:22:47 -05:00
{
2016-03-04 11:28:45 -05:00
struct rpcrdma_frmr * f = & mw - > frmr ;
2015-12-16 17:22:47 -05:00
struct ib_send_wr * invalidate_wr ;
f - > fr_state = FRMR_IS_INVALID ;
invalidate_wr = & f - > fr_invwr ;
memset ( invalidate_wr , 0 , sizeof ( * invalidate_wr ) ) ;
2016-03-04 11:28:53 -05:00
f - > fr_cqe . done = frwr_wc_localinv ;
invalidate_wr - > wr_cqe = & f - > fr_cqe ;
2015-12-16 17:22:47 -05:00
invalidate_wr - > opcode = IB_WR_LOCAL_INV ;
invalidate_wr - > ex . invalidate_rkey = f - > fr_mr - > rkey ;
return invalidate_wr ;
}
/* Invalidate all memory regions that were registered for "req".
*
* Sleeps until it is safe for the host CPU to access the
* previously mapped memory regions .
2016-06-29 13:54:16 -04:00
*
* Caller ensures that req - > rl_registered is not empty .
2015-12-16 17:22:47 -05:00
*/
static void
frwr_op_unmap_sync ( struct rpcrdma_xprt * r_xprt , struct rpcrdma_req * req )
{
struct ib_send_wr * invalidate_wrs , * pos , * prev , * bad_wr ;
struct rpcrdma_ia * ia = & r_xprt - > rx_ia ;
2016-06-29 13:54:16 -04:00
struct rpcrdma_mw * mw , * tmp ;
2015-12-16 17:22:47 -05:00
struct rpcrdma_frmr * f ;
int rc ;
dprintk ( " RPC: %s: req %p \n " , __func__ , req ) ;
/* ORDER: Invalidate all of the req's MRs first
*
* Chain the LOCAL_INV Work Requests and post them with
* a single ib_post_send ( ) call .
*/
2016-06-29 13:54:16 -04:00
f = NULL ;
2015-12-16 17:22:47 -05:00
invalidate_wrs = pos = prev = NULL ;
2016-06-29 13:54:16 -04:00
list_for_each_entry ( mw , & req - > rl_registered , mw_list ) {
pos = __frwr_prepare_linv_wr ( mw ) ;
2015-12-16 17:22:47 -05:00
if ( ! invalidate_wrs )
invalidate_wrs = pos ;
else
prev - > next = pos ;
prev = pos ;
2016-06-29 13:54:16 -04:00
f = & mw - > frmr ;
2015-12-16 17:22:47 -05:00
}
/* Strong send queue ordering guarantees that when the
* last WR in the chain completes , all WRs in the chain
* are complete .
*/
f - > fr_invwr . send_flags = IB_SEND_SIGNALED ;
2016-03-04 11:28:53 -05:00
f - > fr_cqe . done = frwr_wc_localinv_wake ;
reinit_completion ( & f - > fr_linv_done ) ;
2015-12-16 17:22:47 -05:00
INIT_CQCOUNT ( & r_xprt - > rx_ep ) ;
/* Transport disconnect drains the receive CQ before it
* replaces the QP . The RPC reply handler won ' t call us
* unless ri_id - > qp is a valid pointer .
*/
rc = ib_post_send ( ia - > ri_id - > qp , invalidate_wrs , & bad_wr ) ;
2016-05-02 14:42:12 -04:00
if ( rc )
goto reset_mrs ;
2015-12-16 17:22:47 -05:00
wait_for_completion ( & f - > fr_linv_done ) ;
/* ORDER: Now DMA unmap all of the req's MRs, and return
* them to the free MW list .
*/
2016-03-04 11:28:01 -05:00
unmap :
2016-06-29 13:54:16 -04:00
list_for_each_entry_safe ( mw , tmp , & req - > rl_registered , mw_list ) {
list_del_init ( & mw - > mw_list ) ;
2016-06-29 13:52:21 -04:00
ib_dma_unmap_sg ( ia - > ri_device ,
mw - > mw_sg , mw - > mw_nents , mw - > mw_dir ) ;
2016-05-02 14:42:12 -04:00
rpcrdma_put_mw ( r_xprt , mw ) ;
2015-12-16 17:22:47 -05:00
}
2016-05-02 14:42:12 -04:00
return ;
2015-12-16 17:22:47 -05:00
2016-05-02 14:42:12 -04:00
reset_mrs :
2016-06-29 13:53:43 -04:00
pr_err ( " rpcrdma: FRMR invalidate ib_post_send returned %i \n " , rc ) ;
rdma_disconnect ( ia - > ri_id ) ;
2015-03-30 14:34:48 -04:00
2016-05-02 14:42:12 -04:00
/* Find and reset the MRs in the LOCAL_INV WRs that did not
* get posted . This is synchronous , and slow .
*/
2016-06-29 13:54:16 -04:00
list_for_each_entry ( mw , & req - > rl_registered , mw_list ) {
2016-05-02 14:42:12 -04:00
f = & mw - > frmr ;
if ( mw - > frmr . fr_mr - > rkey = = bad_wr - > ex . invalidate_rkey ) {
__frwr_reset_mr ( ia , mw ) ;
bad_wr = bad_wr - > next ;
}
}
goto unmap ;
2015-12-16 17:22:47 -05:00
}
2015-03-30 14:34:48 -04:00
2016-05-02 14:42:46 -04:00
/* Use a slow, safe mechanism to invalidate all memory regions
* that were registered for " req " .
*/
static void
frwr_op_unmap_safe ( struct rpcrdma_xprt * r_xprt , struct rpcrdma_req * req ,
bool sync )
{
struct rpcrdma_mw * mw ;
2015-05-26 11:52:35 -04:00
2016-06-29 13:54:16 -04:00
while ( ! list_empty ( & req - > rl_registered ) ) {
mw = list_first_entry ( & req - > rl_registered ,
struct rpcrdma_mw , mw_list ) ;
list_del_init ( & mw - > mw_list ) ;
2015-03-30 14:34:48 -04:00
2016-05-02 14:42:46 -04:00
if ( sync )
2016-06-29 13:52:54 -04:00
frwr_op_recover_mr ( mw ) ;
2016-05-02 14:42:46 -04:00
else
2016-06-29 13:52:54 -04:00
rpcrdma_defer_mr_recovery ( mw ) ;
2016-05-02 14:42:46 -04:00
}
2015-03-30 14:34:48 -04:00
}
2015-03-30 14:34:21 -04:00
const struct rpcrdma_memreg_ops rpcrdma_frwr_memreg_ops = {
2015-03-30 14:34:39 -04:00
. ro_map = frwr_op_map ,
2015-12-16 17:22:47 -05:00
. ro_unmap_sync = frwr_op_unmap_sync ,
2016-05-02 14:42:46 -04:00
. ro_unmap_safe = frwr_op_unmap_safe ,
2016-06-29 13:52:54 -04:00
. ro_recover_mr = frwr_op_recover_mr ,
2015-03-30 14:35:26 -04:00
. ro_open = frwr_op_open ,
2015-03-30 14:34:30 -04:00
. ro_maxpages = frwr_op_maxpages ,
2016-06-29 13:54:00 -04:00
. ro_init_mr = frwr_op_init_mr ,
. ro_release_mr = frwr_op_release_mr ,
2015-03-30 14:34:21 -04:00
. ro_displayname = " frwr " ,
} ;