xref: /onnv-gate/usr/src/uts/common/io/ib/clients/rdsv3/ib_recv.c (revision 13118:e192495818d4)
112198SEiji.Ota@Sun.COM /*
212198SEiji.Ota@Sun.COM  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
312198SEiji.Ota@Sun.COM  */
412198SEiji.Ota@Sun.COM 
512198SEiji.Ota@Sun.COM /*
612763SGiri.Adari@Sun.COM  * This file contains code imported from the OFED rds source file ib_recv.c
712763SGiri.Adari@Sun.COM  * Oracle elects to have and use the contents of ib_recv.c under and governed
812763SGiri.Adari@Sun.COM  * by the OpenIB.org BSD license (see below for full license text). However,
912763SGiri.Adari@Sun.COM  * the following notice accompanied the original version of this file:
1012763SGiri.Adari@Sun.COM  */
1112763SGiri.Adari@Sun.COM 
1212763SGiri.Adari@Sun.COM /*
1312198SEiji.Ota@Sun.COM  * Copyright (c) 2006 Oracle.  All rights reserved.
1412198SEiji.Ota@Sun.COM  *
1512198SEiji.Ota@Sun.COM  * This software is available to you under a choice of one of two
1612198SEiji.Ota@Sun.COM  * licenses.  You may choose to be licensed under the terms of the GNU
1712198SEiji.Ota@Sun.COM  * General Public License (GPL) Version 2, available from the file
1812198SEiji.Ota@Sun.COM  * COPYING in the main directory of this source tree, or the
1912198SEiji.Ota@Sun.COM  * OpenIB.org BSD license below:
2012198SEiji.Ota@Sun.COM  *
2112198SEiji.Ota@Sun.COM  *     Redistribution and use in source and binary forms, with or
2212198SEiji.Ota@Sun.COM  *     without modification, are permitted provided that the following
2312198SEiji.Ota@Sun.COM  *     conditions are met:
2412198SEiji.Ota@Sun.COM  *
2512198SEiji.Ota@Sun.COM  *      - Redistributions of source code must retain the above
2612198SEiji.Ota@Sun.COM  *        copyright notice, this list of conditions and the following
2712198SEiji.Ota@Sun.COM  *        disclaimer.
2812198SEiji.Ota@Sun.COM  *
2912198SEiji.Ota@Sun.COM  *      - Redistributions in binary form must reproduce the above
3012198SEiji.Ota@Sun.COM  *        copyright notice, this list of conditions and the following
3112198SEiji.Ota@Sun.COM  *        disclaimer in the documentation and/or other materials
3212198SEiji.Ota@Sun.COM  *        provided with the distribution.
3312198SEiji.Ota@Sun.COM  *
3412198SEiji.Ota@Sun.COM  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
3512198SEiji.Ota@Sun.COM  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
3612198SEiji.Ota@Sun.COM  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
3712198SEiji.Ota@Sun.COM  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
3812198SEiji.Ota@Sun.COM  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
3912198SEiji.Ota@Sun.COM  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
4012198SEiji.Ota@Sun.COM  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
4112198SEiji.Ota@Sun.COM  * SOFTWARE.
4212198SEiji.Ota@Sun.COM  *
4312198SEiji.Ota@Sun.COM  */
4412198SEiji.Ota@Sun.COM #include <sys/types.h>
4512198SEiji.Ota@Sun.COM #include <sys/kmem.h>
4612198SEiji.Ota@Sun.COM #include <sys/cpuvar.h>
4712198SEiji.Ota@Sun.COM #include <sys/rds.h>
4812198SEiji.Ota@Sun.COM 
4912198SEiji.Ota@Sun.COM #include <sys/ib/clients/rdsv3/rdsv3.h>
5012198SEiji.Ota@Sun.COM #include <sys/ib/clients/rdsv3/ib.h>
5112198SEiji.Ota@Sun.COM #include <sys/ib/clients/rdsv3/rdsv3_debug.h>
5212198SEiji.Ota@Sun.COM 
5312198SEiji.Ota@Sun.COM static struct kmem_cache *rdsv3_ib_incoming_slab;
5412198SEiji.Ota@Sun.COM static atomic_t	rdsv3_ib_allocation = ATOMIC_INIT(0);
5512198SEiji.Ota@Sun.COM 
5612198SEiji.Ota@Sun.COM void
rdsv3_ib_recv_init_ring(struct rdsv3_ib_connection * ic)5712198SEiji.Ota@Sun.COM rdsv3_ib_recv_init_ring(struct rdsv3_ib_connection *ic)
5812198SEiji.Ota@Sun.COM {
5912198SEiji.Ota@Sun.COM 	struct rdsv3_ib_recv_work *recv;
6012198SEiji.Ota@Sun.COM 	struct rdsv3_header *hdrp;
6112198SEiji.Ota@Sun.COM 	uint32_t i;
6212198SEiji.Ota@Sun.COM 
6312198SEiji.Ota@Sun.COM 	RDSV3_DPRINTF4("rdsv3_ib_recv_init_ring", "ic: %p", ic);
6412198SEiji.Ota@Sun.COM 
6512198SEiji.Ota@Sun.COM 	hdrp = ic->i_recv_hdrs;
6612198SEiji.Ota@Sun.COM 	for (i = 0, recv = ic->i_recvs; i < ic->i_recv_ring.w_nr; i++, recv++) {
6712198SEiji.Ota@Sun.COM 		recv->r_ibinc = NULL;
6812198SEiji.Ota@Sun.COM 		recv->r_frag = NULL;
6912198SEiji.Ota@Sun.COM 
7012198SEiji.Ota@Sun.COM 		/* initialize the hdr sgl permanently */
7112198SEiji.Ota@Sun.COM 		recv->r_sge[0].ds_va = (ib_vaddr_t)(uintptr_t)hdrp++;
7212198SEiji.Ota@Sun.COM 		recv->r_sge[0].ds_len = sizeof (struct rdsv3_header);
7312198SEiji.Ota@Sun.COM 		recv->r_sge[0].ds_key = ic->i_mr->lkey;
7412198SEiji.Ota@Sun.COM 	}
7512198SEiji.Ota@Sun.COM }
7612198SEiji.Ota@Sun.COM 
7712198SEiji.Ota@Sun.COM static void
rdsv3_ib_recv_clear_one(struct rdsv3_ib_connection * ic,struct rdsv3_ib_recv_work * recv)7812198SEiji.Ota@Sun.COM rdsv3_ib_recv_clear_one(struct rdsv3_ib_connection *ic,
7912198SEiji.Ota@Sun.COM     struct rdsv3_ib_recv_work *recv)
8012198SEiji.Ota@Sun.COM {
8112198SEiji.Ota@Sun.COM 	RDSV3_DPRINTF4("rdsv3_ib_recv_clear_one", "ic: %p, recv: %p",
8212198SEiji.Ota@Sun.COM 	    ic, recv);
8312198SEiji.Ota@Sun.COM 
8412198SEiji.Ota@Sun.COM 	if (recv->r_ibinc) {
8512198SEiji.Ota@Sun.COM 		rdsv3_inc_put(&recv->r_ibinc->ii_inc);
8612198SEiji.Ota@Sun.COM 		recv->r_ibinc = NULL;
8712198SEiji.Ota@Sun.COM 	}
8812676SEiji.Ota@Sun.COM 
8912198SEiji.Ota@Sun.COM 	if (recv->r_frag) {
9012444SGiri.Adari@Sun.COM 		kmem_cache_free(ic->rds_ibdev->ib_frag_slab, recv->r_frag);
9112198SEiji.Ota@Sun.COM 		recv->r_frag = NULL;
9212198SEiji.Ota@Sun.COM 	}
9312198SEiji.Ota@Sun.COM 
9412198SEiji.Ota@Sun.COM 	RDSV3_DPRINTF4("rdsv3_ib_recv_clear_one", "Return: ic: %p, recv: %p",
9512198SEiji.Ota@Sun.COM 	    ic, recv);
9612198SEiji.Ota@Sun.COM }
9712198SEiji.Ota@Sun.COM 
9812198SEiji.Ota@Sun.COM void
rdsv3_ib_recv_clear_ring(struct rdsv3_ib_connection * ic)9912198SEiji.Ota@Sun.COM rdsv3_ib_recv_clear_ring(struct rdsv3_ib_connection *ic)
10012198SEiji.Ota@Sun.COM {
10112198SEiji.Ota@Sun.COM 	uint32_t i;
10212198SEiji.Ota@Sun.COM 
10312198SEiji.Ota@Sun.COM 	RDSV3_DPRINTF4("rdsv3_ib_recv_clear_ring", "ic: %p", ic);
10412198SEiji.Ota@Sun.COM 
10512198SEiji.Ota@Sun.COM 	for (i = 0; i < ic->i_recv_ring.w_nr; i++)
10612198SEiji.Ota@Sun.COM 		rdsv3_ib_recv_clear_one(ic, &ic->i_recvs[i]);
10712198SEiji.Ota@Sun.COM }
10812198SEiji.Ota@Sun.COM 
10912414SEiji.Ota@Sun.COM extern int atomic_add_unless(atomic_t *, uint_t, ulong_t);
11012414SEiji.Ota@Sun.COM 
11112198SEiji.Ota@Sun.COM static int
rdsv3_ib_recv_refill_one(struct rdsv3_connection * conn,struct rdsv3_ib_recv_work * recv)11212198SEiji.Ota@Sun.COM rdsv3_ib_recv_refill_one(struct rdsv3_connection *conn,
11312676SEiji.Ota@Sun.COM     struct rdsv3_ib_recv_work *recv)
11412198SEiji.Ota@Sun.COM {
11512198SEiji.Ota@Sun.COM 	struct rdsv3_ib_connection *ic = conn->c_transport_data;
11612198SEiji.Ota@Sun.COM 	ibt_mi_hdl_t mi_hdl;
11712198SEiji.Ota@Sun.COM 	ibt_iov_attr_t iov_attr;
11812198SEiji.Ota@Sun.COM 	ibt_iov_t iov_arr[1];
11912198SEiji.Ota@Sun.COM 
12012198SEiji.Ota@Sun.COM 	RDSV3_DPRINTF5("rdsv3_ib_recv_refill_one", "conn: %p, recv: %p",
12112198SEiji.Ota@Sun.COM 	    conn, recv);
12212198SEiji.Ota@Sun.COM 
12312676SEiji.Ota@Sun.COM 	if (!recv->r_ibinc) {
12412414SEiji.Ota@Sun.COM 		if (!atomic_add_unless(&rdsv3_ib_allocation, 1,
125*13118SEiji.Ota@Sun.COM 		    ic->i_max_recv_alloc)) {
12612198SEiji.Ota@Sun.COM 			rdsv3_ib_stats_inc(s_ib_rx_alloc_limit);
12712198SEiji.Ota@Sun.COM 			goto out;
12812198SEiji.Ota@Sun.COM 		}
12912198SEiji.Ota@Sun.COM 		recv->r_ibinc = kmem_cache_alloc(rdsv3_ib_incoming_slab,
13012676SEiji.Ota@Sun.COM 		    KM_NOSLEEP);
13112198SEiji.Ota@Sun.COM 		if (recv->r_ibinc == NULL) {
13212198SEiji.Ota@Sun.COM 			atomic_add_32(&rdsv3_ib_allocation, -1);
13312198SEiji.Ota@Sun.COM 			goto out;
13412198SEiji.Ota@Sun.COM 		}
13512198SEiji.Ota@Sun.COM 		rdsv3_inc_init(&recv->r_ibinc->ii_inc, conn, conn->c_faddr);
13612676SEiji.Ota@Sun.COM 		recv->r_ibinc->ii_ibdev = ic->rds_ibdev;
13712676SEiji.Ota@Sun.COM 		recv->r_ibinc->ii_pool = ic->rds_ibdev->inc_pool;
13812198SEiji.Ota@Sun.COM 	}
13912198SEiji.Ota@Sun.COM 
14012676SEiji.Ota@Sun.COM 	if (!recv->r_frag) {
14112444SGiri.Adari@Sun.COM 		recv->r_frag = kmem_cache_alloc(ic->rds_ibdev->ib_frag_slab,
14212676SEiji.Ota@Sun.COM 		    KM_NOSLEEP);
14312676SEiji.Ota@Sun.COM 		if (!recv->r_frag)
14412198SEiji.Ota@Sun.COM 			goto out;
14512198SEiji.Ota@Sun.COM 	}
14612198SEiji.Ota@Sun.COM 
14712444SGiri.Adari@Sun.COM 	/* Data sge, structure copy */
14812444SGiri.Adari@Sun.COM 	recv->r_sge[1] = recv->r_frag->f_sge;
14912198SEiji.Ota@Sun.COM 
15012198SEiji.Ota@Sun.COM 	RDSV3_DPRINTF5("rdsv3_ib_recv_refill_one", "Return: conn: %p, recv: %p",
15112198SEiji.Ota@Sun.COM 	    conn, recv);
15212444SGiri.Adari@Sun.COM 
15312444SGiri.Adari@Sun.COM 	return (0);
15412198SEiji.Ota@Sun.COM out:
15512676SEiji.Ota@Sun.COM 	if (recv->r_ibinc) {
15612676SEiji.Ota@Sun.COM 		kmem_cache_free(rdsv3_ib_incoming_slab, recv->r_ibinc);
15712676SEiji.Ota@Sun.COM 		atomic_add_32(&rdsv3_ib_allocation, -1);
15812676SEiji.Ota@Sun.COM 		recv->r_ibinc = NULL;
15912676SEiji.Ota@Sun.COM 	}
16012444SGiri.Adari@Sun.COM 	return (-ENOMEM);
16112198SEiji.Ota@Sun.COM }
16212198SEiji.Ota@Sun.COM 
16312198SEiji.Ota@Sun.COM /*
16412198SEiji.Ota@Sun.COM  * This tries to allocate and post unused work requests after making sure that
16512198SEiji.Ota@Sun.COM  * they have all the allocations they need to queue received fragments into
16612198SEiji.Ota@Sun.COM  * sockets.  The i_recv_mutex is held here so that ring_alloc and _unalloc
16712198SEiji.Ota@Sun.COM  * pairs don't go unmatched.
16812198SEiji.Ota@Sun.COM  *
16912198SEiji.Ota@Sun.COM  * -1 is returned if posting fails due to temporary resource exhaustion.
17012198SEiji.Ota@Sun.COM  */
17112198SEiji.Ota@Sun.COM int
rdsv3_ib_recv_refill(struct rdsv3_connection * conn,int prefill)17212676SEiji.Ota@Sun.COM rdsv3_ib_recv_refill(struct rdsv3_connection *conn, int prefill)
17312198SEiji.Ota@Sun.COM {
17412198SEiji.Ota@Sun.COM 	struct rdsv3_ib_connection *ic = conn->c_transport_data;
17512198SEiji.Ota@Sun.COM 	struct rdsv3_ib_recv_work *recv;
17612198SEiji.Ota@Sun.COM 	unsigned int posted = 0;
17712444SGiri.Adari@Sun.COM 	int ret = 0, avail;
17812444SGiri.Adari@Sun.COM 	uint32_t pos, i;
17912198SEiji.Ota@Sun.COM 
18012198SEiji.Ota@Sun.COM 	RDSV3_DPRINTF4("rdsv3_ib_recv_refill", "conn: %p, prefill: %d",
18112198SEiji.Ota@Sun.COM 	    conn, prefill);
18212198SEiji.Ota@Sun.COM 
18312444SGiri.Adari@Sun.COM 	if (prefill || rdsv3_conn_up(conn)) {
18412444SGiri.Adari@Sun.COM 		uint_t w_nr = ic->i_recv_ring.w_nr;
18512444SGiri.Adari@Sun.COM 
18612444SGiri.Adari@Sun.COM 		avail = rdsv3_ib_ring_alloc(&ic->i_recv_ring, w_nr, &pos);
18712444SGiri.Adari@Sun.COM 		if ((avail <= 0) || (pos >= w_nr)) {
18812320SGiri.Adari@Sun.COM 			RDSV3_DPRINTF2("rdsv3_ib_recv_refill",
18912444SGiri.Adari@Sun.COM 			    "Argh - ring alloc returned pos=%u, avail: %d",
19012444SGiri.Adari@Sun.COM 			    pos, avail);
19112444SGiri.Adari@Sun.COM 			return (-EINVAL);
19212198SEiji.Ota@Sun.COM 		}
19312198SEiji.Ota@Sun.COM 
19412444SGiri.Adari@Sun.COM 		/* populate the WRs */
19512444SGiri.Adari@Sun.COM 		for (i = 0; i < avail; i++) {
19612444SGiri.Adari@Sun.COM 			recv = &ic->i_recvs[pos];
19712676SEiji.Ota@Sun.COM 			ret = rdsv3_ib_recv_refill_one(conn, recv);
19812444SGiri.Adari@Sun.COM 			if (ret) {
19912444SGiri.Adari@Sun.COM 				rdsv3_ib_ring_unalloc(&ic->i_recv_ring,
20012444SGiri.Adari@Sun.COM 				    avail - i);
20112444SGiri.Adari@Sun.COM 				break;
20212444SGiri.Adari@Sun.COM 			}
20312676SEiji.Ota@Sun.COM 			ic->i_recv_wrs[i].wr_id = (ibt_wrid_t)pos;
20412444SGiri.Adari@Sun.COM 			ic->i_recv_wrs[i].wr_nds = RDSV3_IB_RECV_SGE;
20512444SGiri.Adari@Sun.COM 			ic->i_recv_wrs[i].wr_sgl = &recv->r_sge[0];
20612444SGiri.Adari@Sun.COM 
20712444SGiri.Adari@Sun.COM 			pos = (pos + 1) % w_nr;
20812198SEiji.Ota@Sun.COM 		}
20912198SEiji.Ota@Sun.COM 
21012444SGiri.Adari@Sun.COM 		if (i) {
21112444SGiri.Adari@Sun.COM 			/* post the WRs at one shot */
21212444SGiri.Adari@Sun.COM 			ret = ibt_post_recv(ib_get_ibt_channel_hdl(ic->i_cm_id),
21312444SGiri.Adari@Sun.COM 			    &ic->i_recv_wrs[0], i, &posted);
21412444SGiri.Adari@Sun.COM 			RDSV3_DPRINTF3("rdsv3_ib_recv_refill",
21512444SGiri.Adari@Sun.COM 			    "attempted: %d posted: %d WRs ret %d",
21612444SGiri.Adari@Sun.COM 			    i, posted, ret);
21712444SGiri.Adari@Sun.COM 			if (ret) {
21812444SGiri.Adari@Sun.COM 				RDSV3_DPRINTF2("rdsv3_ib_recv_refill",
21912444SGiri.Adari@Sun.COM 				    "disconnecting and reconnecting\n",
22012444SGiri.Adari@Sun.COM 				    NIPQUAD(conn->c_faddr), ret);
22112444SGiri.Adari@Sun.COM 				rdsv3_ib_ring_unalloc(&ic->i_recv_ring,
22212444SGiri.Adari@Sun.COM 				    i - posted);
22312444SGiri.Adari@Sun.COM 				rdsv3_conn_drop(conn);
22412444SGiri.Adari@Sun.COM 			}
22512444SGiri.Adari@Sun.COM 		}
22612198SEiji.Ota@Sun.COM 	}
22712198SEiji.Ota@Sun.COM 
22812198SEiji.Ota@Sun.COM 	/* We're doing flow control - update the window. */
22912198SEiji.Ota@Sun.COM 	if (ic->i_flowctl && posted)
23012198SEiji.Ota@Sun.COM 		rdsv3_ib_advertise_credits(conn, posted);
23112198SEiji.Ota@Sun.COM 
23212198SEiji.Ota@Sun.COM 	RDSV3_DPRINTF4("rdsv3_ib_recv_refill", "Return: conn: %p, posted: %d",
23312198SEiji.Ota@Sun.COM 	    conn, posted);
23412198SEiji.Ota@Sun.COM 	return (ret);
23512198SEiji.Ota@Sun.COM }
23612198SEiji.Ota@Sun.COM 
23712676SEiji.Ota@Sun.COM /*
23812676SEiji.Ota@Sun.COM  * delayed freed incoming's
23912676SEiji.Ota@Sun.COM  */
24012676SEiji.Ota@Sun.COM struct rdsv3_inc_pool {
24112676SEiji.Ota@Sun.COM 	list_t			f_list;	/* list of freed incoming */
24212676SEiji.Ota@Sun.COM 	kmutex_t		f_lock; /* lock of fmr pool */
24312676SEiji.Ota@Sun.COM 	int32_t			f_listcnt;
24412676SEiji.Ota@Sun.COM };
24512676SEiji.Ota@Sun.COM 
24612198SEiji.Ota@Sun.COM void
rdsv3_ib_destroy_inc_pool(struct rdsv3_ib_device * rds_ibdev)24712676SEiji.Ota@Sun.COM rdsv3_ib_destroy_inc_pool(struct rdsv3_ib_device *rds_ibdev)
24812676SEiji.Ota@Sun.COM {
24912676SEiji.Ota@Sun.COM 	struct rdsv3_inc_pool *pool = rds_ibdev->inc_pool;
25012676SEiji.Ota@Sun.COM 
25112676SEiji.Ota@Sun.COM 	if (pool) {
25212676SEiji.Ota@Sun.COM 		list_destroy(&pool->f_list);
25312676SEiji.Ota@Sun.COM 		kmem_free((void *) pool, sizeof (*pool));
25412676SEiji.Ota@Sun.COM 	}
25512676SEiji.Ota@Sun.COM }
25612676SEiji.Ota@Sun.COM 
25712676SEiji.Ota@Sun.COM int
rdsv3_ib_create_inc_pool(struct rdsv3_ib_device * rds_ibdev)25812676SEiji.Ota@Sun.COM rdsv3_ib_create_inc_pool(struct rdsv3_ib_device *rds_ibdev)
25912198SEiji.Ota@Sun.COM {
26012676SEiji.Ota@Sun.COM 	struct rdsv3_inc_pool *pool;
26112676SEiji.Ota@Sun.COM 
26212676SEiji.Ota@Sun.COM 	pool = (struct rdsv3_inc_pool *)kmem_zalloc(sizeof (*pool), KM_NOSLEEP);
26312676SEiji.Ota@Sun.COM 	if (pool == NULL) {
26412676SEiji.Ota@Sun.COM 		return (-ENOMEM);
26512676SEiji.Ota@Sun.COM 	}
26612676SEiji.Ota@Sun.COM 	list_create(&pool->f_list, sizeof (struct rdsv3_ib_incoming),
26712676SEiji.Ota@Sun.COM 	    offsetof(struct rdsv3_ib_incoming, ii_obj));
26812676SEiji.Ota@Sun.COM 	mutex_init(&pool->f_lock, NULL, MUTEX_DRIVER, NULL);
26912676SEiji.Ota@Sun.COM 	rds_ibdev->inc_pool = pool;
27012676SEiji.Ota@Sun.COM 	return (0);
27112676SEiji.Ota@Sun.COM }
27212676SEiji.Ota@Sun.COM 
27312676SEiji.Ota@Sun.COM static void
rdsv3_ib_inc_drop(struct rdsv3_ib_incoming * ibinc)27412676SEiji.Ota@Sun.COM rdsv3_ib_inc_drop(struct rdsv3_ib_incoming *ibinc)
27512676SEiji.Ota@Sun.COM {
27612198SEiji.Ota@Sun.COM 	struct rdsv3_page_frag *frag;
27712198SEiji.Ota@Sun.COM 	struct rdsv3_page_frag *pos;
27812198SEiji.Ota@Sun.COM 
27912198SEiji.Ota@Sun.COM 	RDSV3_FOR_EACH_LIST_NODE_SAFE(frag, pos, &ibinc->ii_frags, f_item) {
28012198SEiji.Ota@Sun.COM 		list_remove_node(&frag->f_item);
28112676SEiji.Ota@Sun.COM 		kmem_cache_free(ibinc->ii_ibdev->ib_frag_slab, frag);
28212198SEiji.Ota@Sun.COM 	}
28312198SEiji.Ota@Sun.COM 
28412676SEiji.Ota@Sun.COM 	ASSERT(list_is_empty(&ibinc->ii_frags));
28512676SEiji.Ota@Sun.COM 	kmem_cache_free(rdsv3_ib_incoming_slab, ibinc);
28612676SEiji.Ota@Sun.COM 	atomic_dec_uint(&rdsv3_ib_allocation);
28712676SEiji.Ota@Sun.COM }
28812676SEiji.Ota@Sun.COM 
28912676SEiji.Ota@Sun.COM void
rdsv3_ib_drain_inclist(void * data)29012676SEiji.Ota@Sun.COM rdsv3_ib_drain_inclist(void *data)
29112676SEiji.Ota@Sun.COM {
29212676SEiji.Ota@Sun.COM 	struct rdsv3_inc_pool *pool = (struct rdsv3_inc_pool *)data;
29312676SEiji.Ota@Sun.COM 	struct rdsv3_ib_incoming *ibinc;
29412676SEiji.Ota@Sun.COM 	list_t *listp = &pool->f_list;
29512676SEiji.Ota@Sun.COM 	kmutex_t *lockp = &pool->f_lock;
29612676SEiji.Ota@Sun.COM 	int i = 0;
29712676SEiji.Ota@Sun.COM 
29812676SEiji.Ota@Sun.COM 	for (;;) {
29912676SEiji.Ota@Sun.COM 		mutex_enter(lockp);
30012676SEiji.Ota@Sun.COM 		ibinc = (struct rdsv3_ib_incoming *)list_remove_head(listp);
30112676SEiji.Ota@Sun.COM 		if (ibinc)
30212676SEiji.Ota@Sun.COM 			pool->f_listcnt--;
30312676SEiji.Ota@Sun.COM 		mutex_exit(lockp);
30412676SEiji.Ota@Sun.COM 		if (!ibinc)
30512676SEiji.Ota@Sun.COM 			break;
30612676SEiji.Ota@Sun.COM 		i++;
30712676SEiji.Ota@Sun.COM 		rdsv3_ib_inc_drop(ibinc);
30812676SEiji.Ota@Sun.COM 	}
30912198SEiji.Ota@Sun.COM }
31012198SEiji.Ota@Sun.COM 
31112198SEiji.Ota@Sun.COM void
rdsv3_ib_inc_free(struct rdsv3_incoming * inc)31212198SEiji.Ota@Sun.COM rdsv3_ib_inc_free(struct rdsv3_incoming *inc)
31312198SEiji.Ota@Sun.COM {
31412198SEiji.Ota@Sun.COM 	struct rdsv3_ib_incoming *ibinc;
31512676SEiji.Ota@Sun.COM 	rdsv3_af_thr_t *af_thr;
31612198SEiji.Ota@Sun.COM 
31712198SEiji.Ota@Sun.COM 	RDSV3_DPRINTF4("rdsv3_ib_inc_free", "inc: %p", inc);
31812198SEiji.Ota@Sun.COM 
31912198SEiji.Ota@Sun.COM 	ibinc = container_of(inc, struct rdsv3_ib_incoming, ii_inc);
32012676SEiji.Ota@Sun.COM 	/* save af_thr in a local as ib_inc might be freed at mutex_exit */
32112676SEiji.Ota@Sun.COM 	af_thr = ibinc->ii_ibdev->inc_soft_cq;
32212198SEiji.Ota@Sun.COM 
32312676SEiji.Ota@Sun.COM 	mutex_enter(&ibinc->ii_pool->f_lock);
32412676SEiji.Ota@Sun.COM 	list_insert_tail(&ibinc->ii_pool->f_list, ibinc);
32512676SEiji.Ota@Sun.COM 	ibinc->ii_pool->f_listcnt++;
32612676SEiji.Ota@Sun.COM 	mutex_exit(&ibinc->ii_pool->f_lock);
32712198SEiji.Ota@Sun.COM 
32812676SEiji.Ota@Sun.COM 	rdsv3_af_thr_fire(af_thr);
32912198SEiji.Ota@Sun.COM }
33012198SEiji.Ota@Sun.COM 
33112198SEiji.Ota@Sun.COM int
rdsv3_ib_inc_copy_to_user(struct rdsv3_incoming * inc,uio_t * uiop,size_t size)33212198SEiji.Ota@Sun.COM rdsv3_ib_inc_copy_to_user(struct rdsv3_incoming *inc, uio_t *uiop,
33312198SEiji.Ota@Sun.COM     size_t size)
33412198SEiji.Ota@Sun.COM {
33512198SEiji.Ota@Sun.COM 	struct rdsv3_ib_incoming *ibinc;
33612198SEiji.Ota@Sun.COM 	struct rdsv3_page_frag *frag;
33712198SEiji.Ota@Sun.COM 	unsigned long to_copy;
33812198SEiji.Ota@Sun.COM 	unsigned long frag_off = 0;
33912198SEiji.Ota@Sun.COM 	int copied = 0;
34012198SEiji.Ota@Sun.COM 	int ret;
34112198SEiji.Ota@Sun.COM 	uint32_t len;
34212198SEiji.Ota@Sun.COM 
34312198SEiji.Ota@Sun.COM 	ibinc = container_of(inc, struct rdsv3_ib_incoming, ii_inc);
34412198SEiji.Ota@Sun.COM 	frag = list_head(&ibinc->ii_frags);
34512198SEiji.Ota@Sun.COM 	len = ntohl(inc->i_hdr.h_len);
34612198SEiji.Ota@Sun.COM 
34712198SEiji.Ota@Sun.COM 	RDSV3_DPRINTF4("rdsv3_ib_inc_copy_to_user", "inc: %p, size: %d len: %d",
34812198SEiji.Ota@Sun.COM 	    inc, size, len);
34912198SEiji.Ota@Sun.COM 
35012198SEiji.Ota@Sun.COM 	while (copied < size && copied < len) {
35112198SEiji.Ota@Sun.COM 		if (frag_off == RDSV3_FRAG_SIZE) {
35212198SEiji.Ota@Sun.COM 			frag = list_next(&ibinc->ii_frags, frag);
35312198SEiji.Ota@Sun.COM 			frag_off = 0;
35412198SEiji.Ota@Sun.COM 		}
35512198SEiji.Ota@Sun.COM 
35612198SEiji.Ota@Sun.COM 		to_copy = min(len - copied, RDSV3_FRAG_SIZE - frag_off);
35712198SEiji.Ota@Sun.COM 		to_copy = min(size - copied, to_copy);
35812198SEiji.Ota@Sun.COM 
35912198SEiji.Ota@Sun.COM 		RDSV3_DPRINTF5("rdsv3_ib_inc_copy_to_user",
36012198SEiji.Ota@Sun.COM 		    "%lu bytes to user %p from frag [%p, %u] + %lu",
36112198SEiji.Ota@Sun.COM 		    to_copy, uiop,
36212198SEiji.Ota@Sun.COM 		    frag->f_page, frag->f_offset, frag_off);
36312198SEiji.Ota@Sun.COM 
36412198SEiji.Ota@Sun.COM 		ret = uiomove((caddr_t)(frag->f_page +
36512198SEiji.Ota@Sun.COM 		    frag->f_offset + frag_off),
36612198SEiji.Ota@Sun.COM 		    to_copy, UIO_READ, uiop);
36712198SEiji.Ota@Sun.COM 		if (ret) {
36812198SEiji.Ota@Sun.COM 			RDSV3_DPRINTF2("rdsv3_ib_inc_copy_to_user",
36912198SEiji.Ota@Sun.COM 			    "uiomove (%d) returned: %d", to_copy, ret);
37012198SEiji.Ota@Sun.COM 			break;
37112198SEiji.Ota@Sun.COM 		}
37212198SEiji.Ota@Sun.COM 
37312198SEiji.Ota@Sun.COM 		frag_off += to_copy;
37412198SEiji.Ota@Sun.COM 		copied += to_copy;
37512198SEiji.Ota@Sun.COM 	}
37612198SEiji.Ota@Sun.COM 
37712198SEiji.Ota@Sun.COM 	RDSV3_DPRINTF4("rdsv3_ib_inc_copy_to_user",
37812198SEiji.Ota@Sun.COM 	    "Return: inc: %p, copied: %d", inc, copied);
37912198SEiji.Ota@Sun.COM 
38012198SEiji.Ota@Sun.COM 	return (copied);
38112198SEiji.Ota@Sun.COM }
38212198SEiji.Ota@Sun.COM 
38312198SEiji.Ota@Sun.COM /* ic starts out kmem_zalloc()ed */
38412198SEiji.Ota@Sun.COM void
rdsv3_ib_recv_init_ack(struct rdsv3_ib_connection * ic)38512198SEiji.Ota@Sun.COM rdsv3_ib_recv_init_ack(struct rdsv3_ib_connection *ic)
38612198SEiji.Ota@Sun.COM {
38712198SEiji.Ota@Sun.COM 	ibt_send_wr_t *wr = &ic->i_ack_wr;
38812198SEiji.Ota@Sun.COM 	ibt_wr_ds_t *sge = &ic->i_ack_sge;
38912198SEiji.Ota@Sun.COM 
39012198SEiji.Ota@Sun.COM 	RDSV3_DPRINTF4("rdsv3_ib_recv_init_ack", "ic: %p", ic);
39112198SEiji.Ota@Sun.COM 
39212198SEiji.Ota@Sun.COM 	sge->ds_va = ic->i_ack_dma;
39312198SEiji.Ota@Sun.COM 	sge->ds_len = sizeof (struct rdsv3_header);
39412198SEiji.Ota@Sun.COM 	sge->ds_key = ic->i_mr->lkey;
39512198SEiji.Ota@Sun.COM 
39612198SEiji.Ota@Sun.COM 	wr->wr_sgl = sge;
39712198SEiji.Ota@Sun.COM 	wr->wr_nds = 1;
39812198SEiji.Ota@Sun.COM 	wr->wr_opcode = IBT_WRC_SEND;
39912198SEiji.Ota@Sun.COM 	wr->wr_id = RDSV3_IB_ACK_WR_ID;
40012198SEiji.Ota@Sun.COM 	wr->wr_flags = IBT_WR_SEND_SIGNAL | IBT_WR_SEND_SOLICIT;
40112198SEiji.Ota@Sun.COM }
40212198SEiji.Ota@Sun.COM 
40312198SEiji.Ota@Sun.COM /*
40412198SEiji.Ota@Sun.COM  * You'd think that with reliable IB connections you wouldn't need to ack
40512198SEiji.Ota@Sun.COM  * messages that have been received.  The problem is that IB hardware generates
40612198SEiji.Ota@Sun.COM  * an ack message before it has DMAed the message into memory.  This creates a
40712198SEiji.Ota@Sun.COM  * potential message loss if the HCA is disabled for any reason between when it
40812198SEiji.Ota@Sun.COM  * sends the ack and before the message is DMAed and processed.  This is only a
40912198SEiji.Ota@Sun.COM  * potential issue if another HCA is available for fail-over.
41012198SEiji.Ota@Sun.COM  *
41112198SEiji.Ota@Sun.COM  * When the remote host receives our ack they'll free the sent message from
41212198SEiji.Ota@Sun.COM  * their send queue.  To decrease the latency of this we always send an ack
41312198SEiji.Ota@Sun.COM  * immediately after we've received messages.
41412198SEiji.Ota@Sun.COM  *
41512198SEiji.Ota@Sun.COM  * For simplicity, we only have one ack in flight at a time.  This puts
41612198SEiji.Ota@Sun.COM  * pressure on senders to have deep enough send queues to absorb the latency of
41712198SEiji.Ota@Sun.COM  * a single ack frame being in flight.  This might not be good enough.
41812198SEiji.Ota@Sun.COM  *
41912198SEiji.Ota@Sun.COM  * This is implemented by have a long-lived send_wr and sge which point to a
42012198SEiji.Ota@Sun.COM  * statically allocated ack frame.  This ack wr does not fall under the ring
42112198SEiji.Ota@Sun.COM  * accounting that the tx and rx wrs do.  The QP attribute specifically makes
42212198SEiji.Ota@Sun.COM  * room for it beyond the ring size.  Send completion notices its special
42312198SEiji.Ota@Sun.COM  * wr_id and avoids working with the ring in that case.
42412198SEiji.Ota@Sun.COM  */
42512676SEiji.Ota@Sun.COM void
rdsv3_ib_set_ack(struct rdsv3_ib_connection * ic,uint64_t seq,int ack_required)42612198SEiji.Ota@Sun.COM rdsv3_ib_set_ack(struct rdsv3_ib_connection *ic, uint64_t seq,
42712198SEiji.Ota@Sun.COM     int ack_required)
42812198SEiji.Ota@Sun.COM {
42912198SEiji.Ota@Sun.COM 	RDSV3_DPRINTF4("rdsv3_ib_set_ack", "ic: %p, seq: %lld ack: %d",
43012198SEiji.Ota@Sun.COM 	    ic, seq, ack_required);
43112198SEiji.Ota@Sun.COM 
43212198SEiji.Ota@Sun.COM 	mutex_enter(&ic->i_ack_lock);
43312198SEiji.Ota@Sun.COM 	ic->i_ack_next = seq;
43412198SEiji.Ota@Sun.COM 	if (ack_required)
43512198SEiji.Ota@Sun.COM 		set_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
43612198SEiji.Ota@Sun.COM 	mutex_exit(&ic->i_ack_lock);
43712198SEiji.Ota@Sun.COM }
43812198SEiji.Ota@Sun.COM 
43912198SEiji.Ota@Sun.COM static uint64_t
rdsv3_ib_get_ack(struct rdsv3_ib_connection * ic)44012198SEiji.Ota@Sun.COM rdsv3_ib_get_ack(struct rdsv3_ib_connection *ic)
44112198SEiji.Ota@Sun.COM {
44212198SEiji.Ota@Sun.COM 	uint64_t seq;
44312198SEiji.Ota@Sun.COM 
44412198SEiji.Ota@Sun.COM 	RDSV3_DPRINTF4("rdsv3_ib_get_ack", "ic: %p", ic);
44512198SEiji.Ota@Sun.COM 
44612198SEiji.Ota@Sun.COM 	clear_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
44712198SEiji.Ota@Sun.COM 
44812198SEiji.Ota@Sun.COM 	mutex_enter(&ic->i_ack_lock);
44912198SEiji.Ota@Sun.COM 	seq = ic->i_ack_next;
45012198SEiji.Ota@Sun.COM 	mutex_exit(&ic->i_ack_lock);
45112198SEiji.Ota@Sun.COM 
45212198SEiji.Ota@Sun.COM 	return (seq);
45312198SEiji.Ota@Sun.COM }
45412198SEiji.Ota@Sun.COM 
45512198SEiji.Ota@Sun.COM static void
rdsv3_ib_send_ack(struct rdsv3_ib_connection * ic,unsigned int adv_credits)45612198SEiji.Ota@Sun.COM rdsv3_ib_send_ack(struct rdsv3_ib_connection *ic, unsigned int adv_credits)
45712198SEiji.Ota@Sun.COM {
45812198SEiji.Ota@Sun.COM 	struct rdsv3_header *hdr = ic->i_ack;
45912198SEiji.Ota@Sun.COM 	uint64_t seq;
46012198SEiji.Ota@Sun.COM 	int ret;
46112198SEiji.Ota@Sun.COM 
46212198SEiji.Ota@Sun.COM 	RDSV3_DPRINTF4("rdsv3_ib_send_ack", "ic: %p adv_credits: %d",
46312198SEiji.Ota@Sun.COM 	    ic, adv_credits);
46412198SEiji.Ota@Sun.COM 
46512198SEiji.Ota@Sun.COM 	seq = rdsv3_ib_get_ack(ic);
46612198SEiji.Ota@Sun.COM 
46712198SEiji.Ota@Sun.COM 	RDSV3_DPRINTF4("rdsv3_ib_send_ack", "send_ack: ic %p ack %llu",
46812198SEiji.Ota@Sun.COM 	    ic, (unsigned long long) seq);
46912198SEiji.Ota@Sun.COM 	rdsv3_message_populate_header(hdr, 0, 0, 0);
47012198SEiji.Ota@Sun.COM 	hdr->h_ack = htonll(seq);
47112198SEiji.Ota@Sun.COM 	hdr->h_credit = adv_credits;
47212198SEiji.Ota@Sun.COM 	rdsv3_message_make_checksum(hdr);
47312198SEiji.Ota@Sun.COM 	ic->i_ack_queued = jiffies;
47412198SEiji.Ota@Sun.COM 
47512198SEiji.Ota@Sun.COM 	ret = ibt_post_send(RDSV3_QP2CHANHDL(ic->i_cm_id->qp), &ic->i_ack_wr, 1,
47612198SEiji.Ota@Sun.COM 	    NULL);
47712198SEiji.Ota@Sun.COM 	if (ret) {
47812198SEiji.Ota@Sun.COM 		/*
47912198SEiji.Ota@Sun.COM 		 * Failed to send. Release the WR, and
48012198SEiji.Ota@Sun.COM 		 * force another ACK.
48112198SEiji.Ota@Sun.COM 		 */
48212198SEiji.Ota@Sun.COM 		clear_bit(IB_ACK_IN_FLIGHT, &ic->i_ack_flags);
48312198SEiji.Ota@Sun.COM 		set_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
48412198SEiji.Ota@Sun.COM 		rdsv3_ib_stats_inc(s_ib_ack_send_failure);
48512414SEiji.Ota@Sun.COM 		RDSV3_DPRINTF2("rdsv3_ib_send_ack", "sending ack failed\n");
48612414SEiji.Ota@Sun.COM 		rdsv3_conn_drop(ic->conn);
48712198SEiji.Ota@Sun.COM 	} else {
48812198SEiji.Ota@Sun.COM 		rdsv3_ib_stats_inc(s_ib_ack_sent);
48912198SEiji.Ota@Sun.COM 	}
49012198SEiji.Ota@Sun.COM 	RDSV3_DPRINTF4("rdsv3_ib_send_ack", "Return: ic: %p adv_credits: %d",
49112198SEiji.Ota@Sun.COM 	    ic, adv_credits);
49212198SEiji.Ota@Sun.COM }
49312198SEiji.Ota@Sun.COM 
49412198SEiji.Ota@Sun.COM /*
49512198SEiji.Ota@Sun.COM  * There are 3 ways of getting acknowledgements to the peer:
49612198SEiji.Ota@Sun.COM  *  1.	We call rdsv3_ib_attempt_ack from the recv completion handler
49712198SEiji.Ota@Sun.COM  *	to send an ACK-only frame.
49812198SEiji.Ota@Sun.COM  *	However, there can be only one such frame in the send queue
49912198SEiji.Ota@Sun.COM  *	at any time, so we may have to postpone it.
50012198SEiji.Ota@Sun.COM  *  2.	When another (data) packet is transmitted while there's
50112198SEiji.Ota@Sun.COM  *	an ACK in the queue, we piggyback the ACK sequence number
50212198SEiji.Ota@Sun.COM  *	on the data packet.
50312198SEiji.Ota@Sun.COM  *  3.	If the ACK WR is done sending, we get called from the
50412198SEiji.Ota@Sun.COM  *	send queue completion handler, and check whether there's
50512198SEiji.Ota@Sun.COM  *	another ACK pending (postponed because the WR was on the
50612198SEiji.Ota@Sun.COM  *	queue). If so, we transmit it.
50712198SEiji.Ota@Sun.COM  *
50812198SEiji.Ota@Sun.COM  * We maintain 2 variables:
50912198SEiji.Ota@Sun.COM  *  -	i_ack_flags, which keeps track of whether the ACK WR
51012198SEiji.Ota@Sun.COM  *	is currently in the send queue or not (IB_ACK_IN_FLIGHT)
51112198SEiji.Ota@Sun.COM  *  -	i_ack_next, which is the last sequence number we received
51212198SEiji.Ota@Sun.COM  *
51312198SEiji.Ota@Sun.COM  * Potentially, send queue and receive queue handlers can run concurrently.
51412198SEiji.Ota@Sun.COM  * It would be nice to not have to use a spinlock to synchronize things,
51512198SEiji.Ota@Sun.COM  * but the one problem that rules this out is that 64bit updates are
51612198SEiji.Ota@Sun.COM  * not atomic on all platforms. Things would be a lot simpler if
51712198SEiji.Ota@Sun.COM  * we had atomic64 or maybe cmpxchg64 everywhere.
51812198SEiji.Ota@Sun.COM  *
51912198SEiji.Ota@Sun.COM  * Reconnecting complicates this picture just slightly. When we
52012198SEiji.Ota@Sun.COM  * reconnect, we may be seeing duplicate packets. The peer
52112198SEiji.Ota@Sun.COM  * is retransmitting them, because it hasn't seen an ACK for
52212198SEiji.Ota@Sun.COM  * them. It is important that we ACK these.
52312198SEiji.Ota@Sun.COM  *
52412198SEiji.Ota@Sun.COM  * ACK mitigation adds a header flag "ACK_REQUIRED"; any packet with
52512198SEiji.Ota@Sun.COM  * this flag set *MUST* be acknowledged immediately.
52612198SEiji.Ota@Sun.COM  */
52712198SEiji.Ota@Sun.COM 
52812198SEiji.Ota@Sun.COM /*
52912198SEiji.Ota@Sun.COM  * When we get here, we're called from the recv queue handler.
53012198SEiji.Ota@Sun.COM  * Check whether we ought to transmit an ACK.
53112198SEiji.Ota@Sun.COM  */
53212198SEiji.Ota@Sun.COM void
rdsv3_ib_attempt_ack(struct rdsv3_ib_connection * ic)53312198SEiji.Ota@Sun.COM rdsv3_ib_attempt_ack(struct rdsv3_ib_connection *ic)
53412198SEiji.Ota@Sun.COM {
53512198SEiji.Ota@Sun.COM 	unsigned int adv_credits;
53612198SEiji.Ota@Sun.COM 
53712198SEiji.Ota@Sun.COM 	RDSV3_DPRINTF4("rdsv3_ib_attempt_ack", "ic: %p", ic);
53812198SEiji.Ota@Sun.COM 
53912198SEiji.Ota@Sun.COM 	if (!test_bit(IB_ACK_REQUESTED, &ic->i_ack_flags))
54012198SEiji.Ota@Sun.COM 		return;
54112198SEiji.Ota@Sun.COM 
54212198SEiji.Ota@Sun.COM 	if (test_and_set_bit(IB_ACK_IN_FLIGHT, &ic->i_ack_flags)) {
54312198SEiji.Ota@Sun.COM 		rdsv3_ib_stats_inc(s_ib_ack_send_delayed);
54412198SEiji.Ota@Sun.COM 		return;
54512198SEiji.Ota@Sun.COM 	}
54612198SEiji.Ota@Sun.COM 
54712198SEiji.Ota@Sun.COM 	/* Can we get a send credit? */
54812414SEiji.Ota@Sun.COM 	if (!rdsv3_ib_send_grab_credits(ic, 1, &adv_credits, 0)) {
54912198SEiji.Ota@Sun.COM 		rdsv3_ib_stats_inc(s_ib_tx_throttle);
55012198SEiji.Ota@Sun.COM 		clear_bit(IB_ACK_IN_FLIGHT, &ic->i_ack_flags);
55112198SEiji.Ota@Sun.COM 		return;
55212198SEiji.Ota@Sun.COM 	}
55312198SEiji.Ota@Sun.COM 
55412198SEiji.Ota@Sun.COM 	clear_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
55512198SEiji.Ota@Sun.COM 	rdsv3_ib_send_ack(ic, adv_credits);
55612198SEiji.Ota@Sun.COM 
55712198SEiji.Ota@Sun.COM 	RDSV3_DPRINTF4("rdsv3_ib_attempt_ack", "Return: ic: %p", ic);
55812198SEiji.Ota@Sun.COM }
55912198SEiji.Ota@Sun.COM 
56012198SEiji.Ota@Sun.COM /*
56112198SEiji.Ota@Sun.COM  * We get here from the send completion handler, when the
56212198SEiji.Ota@Sun.COM  * adapter tells us the ACK frame was sent.
56312198SEiji.Ota@Sun.COM  */
56412198SEiji.Ota@Sun.COM void
rdsv3_ib_ack_send_complete(struct rdsv3_ib_connection * ic)56512198SEiji.Ota@Sun.COM rdsv3_ib_ack_send_complete(struct rdsv3_ib_connection *ic)
56612198SEiji.Ota@Sun.COM {
56712198SEiji.Ota@Sun.COM 	RDSV3_DPRINTF4("rdsv3_ib_ack_send_complete", "ic: %p", ic);
56812198SEiji.Ota@Sun.COM 	clear_bit(IB_ACK_IN_FLIGHT, &ic->i_ack_flags);
56912198SEiji.Ota@Sun.COM 	rdsv3_ib_attempt_ack(ic);
57012198SEiji.Ota@Sun.COM }
57112198SEiji.Ota@Sun.COM 
57212198SEiji.Ota@Sun.COM /*
57312198SEiji.Ota@Sun.COM  * This is called by the regular xmit code when it wants to piggyback
57412198SEiji.Ota@Sun.COM  * an ACK on an outgoing frame.
57512198SEiji.Ota@Sun.COM  */
57612198SEiji.Ota@Sun.COM uint64_t
rdsv3_ib_piggyb_ack(struct rdsv3_ib_connection * ic)57712198SEiji.Ota@Sun.COM rdsv3_ib_piggyb_ack(struct rdsv3_ib_connection *ic)
57812198SEiji.Ota@Sun.COM {
57912198SEiji.Ota@Sun.COM 	RDSV3_DPRINTF4("rdsv3_ib_piggyb_ack", "ic: %p", ic);
58012198SEiji.Ota@Sun.COM 	if (test_and_clear_bit(IB_ACK_REQUESTED, &ic->i_ack_flags)) {
58112198SEiji.Ota@Sun.COM 		rdsv3_ib_stats_inc(s_ib_ack_send_piggybacked);
58212198SEiji.Ota@Sun.COM 	}
58312198SEiji.Ota@Sun.COM 	return (rdsv3_ib_get_ack(ic));
58412198SEiji.Ota@Sun.COM }
58512198SEiji.Ota@Sun.COM 
58612198SEiji.Ota@Sun.COM /*
58712198SEiji.Ota@Sun.COM  * It's kind of lame that we're copying from the posted receive pages into
58812198SEiji.Ota@Sun.COM  * long-lived bitmaps.  We could have posted the bitmaps and rdma written into
58912198SEiji.Ota@Sun.COM  * them.  But receiving new congestion bitmaps should be a *rare* event, so
59012198SEiji.Ota@Sun.COM  * hopefully we won't need to invest that complexity in making it more
59112198SEiji.Ota@Sun.COM  * efficient.  By copying we can share a simpler core with TCP which has to
59212198SEiji.Ota@Sun.COM  * copy.
59312198SEiji.Ota@Sun.COM  */
59412198SEiji.Ota@Sun.COM static void
rdsv3_ib_cong_recv(struct rdsv3_connection * conn,struct rdsv3_ib_incoming * ibinc)59512198SEiji.Ota@Sun.COM rdsv3_ib_cong_recv(struct rdsv3_connection *conn,
59612198SEiji.Ota@Sun.COM     struct rdsv3_ib_incoming *ibinc)
59712198SEiji.Ota@Sun.COM {
59812198SEiji.Ota@Sun.COM 	struct rdsv3_cong_map *map;
59912198SEiji.Ota@Sun.COM 	unsigned int map_off;
60012198SEiji.Ota@Sun.COM 	unsigned int map_page;
60112198SEiji.Ota@Sun.COM 	struct rdsv3_page_frag *frag;
60212198SEiji.Ota@Sun.COM 	unsigned long frag_off;
60312198SEiji.Ota@Sun.COM 	unsigned long to_copy;
60412198SEiji.Ota@Sun.COM 	unsigned long copied;
60512198SEiji.Ota@Sun.COM 	uint64_t uncongested = 0;
60612198SEiji.Ota@Sun.COM 	caddr_t addr;
60712198SEiji.Ota@Sun.COM 
60812198SEiji.Ota@Sun.COM 	RDSV3_DPRINTF4("rdsv3_ib_cong_recv", "conn: %p, ibinc: %p",
60912198SEiji.Ota@Sun.COM 	    conn, ibinc);
61012198SEiji.Ota@Sun.COM 
61112198SEiji.Ota@Sun.COM 	/* catch completely corrupt packets */
61212198SEiji.Ota@Sun.COM 	if (ntohl(ibinc->ii_inc.i_hdr.h_len) != RDSV3_CONG_MAP_BYTES)
61312198SEiji.Ota@Sun.COM 		return;
61412198SEiji.Ota@Sun.COM 
61512198SEiji.Ota@Sun.COM 	map = conn->c_fcong;
61612198SEiji.Ota@Sun.COM 	map_page = 0;
61712198SEiji.Ota@Sun.COM 	map_off = 0;
61812198SEiji.Ota@Sun.COM 
61912198SEiji.Ota@Sun.COM 	frag = list_head(&ibinc->ii_frags);
62012198SEiji.Ota@Sun.COM 	frag_off = 0;
62112198SEiji.Ota@Sun.COM 
62212198SEiji.Ota@Sun.COM 	copied = 0;
62312198SEiji.Ota@Sun.COM 
62412198SEiji.Ota@Sun.COM 	while (copied < RDSV3_CONG_MAP_BYTES) {
62512198SEiji.Ota@Sun.COM 		uint64_t *src, *dst;
62612198SEiji.Ota@Sun.COM 		unsigned int k;
62712198SEiji.Ota@Sun.COM 
62812198SEiji.Ota@Sun.COM 		to_copy = min(RDSV3_FRAG_SIZE - frag_off, PAGE_SIZE - map_off);
62912198SEiji.Ota@Sun.COM 		ASSERT(!(to_copy & 7)); /* Must be 64bit aligned. */
63012198SEiji.Ota@Sun.COM 
63112198SEiji.Ota@Sun.COM 		addr = frag->f_page + frag->f_offset;
63212198SEiji.Ota@Sun.COM 
63312198SEiji.Ota@Sun.COM 		src = (uint64_t *)(addr + frag_off);
63412198SEiji.Ota@Sun.COM 		dst = (uint64_t *)(map->m_page_addrs[map_page] + map_off);
63512198SEiji.Ota@Sun.COM 		RDSV3_DPRINTF4("rdsv3_ib_cong_recv",
63612198SEiji.Ota@Sun.COM 		    "src: %p dst: %p copied: %d", src, dst, copied);
63712198SEiji.Ota@Sun.COM 		for (k = 0; k < to_copy; k += 8) {
63812198SEiji.Ota@Sun.COM 			/*
63912198SEiji.Ota@Sun.COM 			 * Record ports that became uncongested, ie
64012198SEiji.Ota@Sun.COM 			 * bits that changed from 0 to 1.
64112198SEiji.Ota@Sun.COM 			 */
64212198SEiji.Ota@Sun.COM 			uncongested |= ~(*src) & *dst;
64312198SEiji.Ota@Sun.COM 			*dst++ = *src++;
64412198SEiji.Ota@Sun.COM 		}
64512198SEiji.Ota@Sun.COM 
64612198SEiji.Ota@Sun.COM 		copied += to_copy;
64712198SEiji.Ota@Sun.COM 		RDSV3_DPRINTF4("rdsv3_ib_cong_recv",
64812198SEiji.Ota@Sun.COM 		    "src: %p dst: %p copied: %d", src, dst, copied);
64912198SEiji.Ota@Sun.COM 
65012198SEiji.Ota@Sun.COM 		map_off += to_copy;
65112198SEiji.Ota@Sun.COM 		if (map_off == PAGE_SIZE) {
65212198SEiji.Ota@Sun.COM 			map_off = 0;
65312198SEiji.Ota@Sun.COM 			map_page++;
65412198SEiji.Ota@Sun.COM 		}
65512198SEiji.Ota@Sun.COM 
65612198SEiji.Ota@Sun.COM 		frag_off += to_copy;
65712198SEiji.Ota@Sun.COM 		if (frag_off == RDSV3_FRAG_SIZE) {
65812198SEiji.Ota@Sun.COM 			frag = list_next(&ibinc->ii_frags, frag);
65912198SEiji.Ota@Sun.COM 			frag_off = 0;
66012198SEiji.Ota@Sun.COM 		}
66112198SEiji.Ota@Sun.COM 	}
66212198SEiji.Ota@Sun.COM 
66312198SEiji.Ota@Sun.COM #if 0
66412198SEiji.Ota@Sun.COM XXX
66512198SEiji.Ota@Sun.COM 	/* the congestion map is in little endian order */
66612198SEiji.Ota@Sun.COM 	uncongested = le64_to_cpu(uncongested);
66712198SEiji.Ota@Sun.COM #endif
66812198SEiji.Ota@Sun.COM 
66912198SEiji.Ota@Sun.COM 	rdsv3_cong_map_updated(map, uncongested);
67012198SEiji.Ota@Sun.COM 
67112198SEiji.Ota@Sun.COM 	RDSV3_DPRINTF4("rdsv3_ib_cong_recv", "Return: conn: %p, ibinc: %p",
67212198SEiji.Ota@Sun.COM 	    conn, ibinc);
67312198SEiji.Ota@Sun.COM }
67412198SEiji.Ota@Sun.COM 
67512198SEiji.Ota@Sun.COM static void
rdsv3_ib_process_recv(struct rdsv3_connection * conn,struct rdsv3_ib_recv_work * recv,uint32_t data_len,struct rdsv3_ib_ack_state * state)67612198SEiji.Ota@Sun.COM rdsv3_ib_process_recv(struct rdsv3_connection *conn,
67712198SEiji.Ota@Sun.COM     struct rdsv3_ib_recv_work *recv, uint32_t data_len,
67812198SEiji.Ota@Sun.COM     struct rdsv3_ib_ack_state *state)
67912198SEiji.Ota@Sun.COM {
68012198SEiji.Ota@Sun.COM 	struct rdsv3_ib_connection *ic = conn->c_transport_data;
68112198SEiji.Ota@Sun.COM 	struct rdsv3_ib_incoming *ibinc = ic->i_ibinc;
68212198SEiji.Ota@Sun.COM 	struct rdsv3_header *ihdr, *hdr;
68312198SEiji.Ota@Sun.COM 
68412198SEiji.Ota@Sun.COM 	/* XXX shut down the connection if port 0,0 are seen? */
68512198SEiji.Ota@Sun.COM 
68612198SEiji.Ota@Sun.COM 	RDSV3_DPRINTF5("rdsv3_ib_process_recv",
68712198SEiji.Ota@Sun.COM 	    "ic %p ibinc %p recv %p byte len %u", ic, ibinc, recv, data_len);
68812198SEiji.Ota@Sun.COM 
68912198SEiji.Ota@Sun.COM 	if (data_len < sizeof (struct rdsv3_header)) {
69012198SEiji.Ota@Sun.COM 		RDSV3_DPRINTF2("rdsv3_ib_process_recv",
69112198SEiji.Ota@Sun.COM 		    "incoming message from %u.%u.%u.%u didn't include a "
69212198SEiji.Ota@Sun.COM 		    "header, disconnecting and reconnecting",
69312198SEiji.Ota@Sun.COM 		    NIPQUAD(conn->c_faddr));
69412198SEiji.Ota@Sun.COM 		rdsv3_conn_drop(conn);
69512198SEiji.Ota@Sun.COM 		return;
69612198SEiji.Ota@Sun.COM 	}
69712198SEiji.Ota@Sun.COM 	data_len -= sizeof (struct rdsv3_header);
69812198SEiji.Ota@Sun.COM 
69912676SEiji.Ota@Sun.COM 	ihdr = &ic->i_recv_hdrs[recv - ic->i_recvs];
70012198SEiji.Ota@Sun.COM 
70112198SEiji.Ota@Sun.COM 	/* Validate the checksum. */
70212198SEiji.Ota@Sun.COM 	if (!rdsv3_message_verify_checksum(ihdr)) {
70312198SEiji.Ota@Sun.COM 		RDSV3_DPRINTF2("rdsv3_ib_process_recv", "incoming message "
70412198SEiji.Ota@Sun.COM 		    "from %u.%u.%u.%u has corrupted header - "
70512198SEiji.Ota@Sun.COM 		    "forcing a reconnect",
70612198SEiji.Ota@Sun.COM 		    NIPQUAD(conn->c_faddr));
70712198SEiji.Ota@Sun.COM 		rdsv3_conn_drop(conn);
70812198SEiji.Ota@Sun.COM 		rdsv3_stats_inc(s_recv_drop_bad_checksum);
70912198SEiji.Ota@Sun.COM 		return;
71012198SEiji.Ota@Sun.COM 	}
71112198SEiji.Ota@Sun.COM 
71212198SEiji.Ota@Sun.COM 	/* Process the ACK sequence which comes with every packet */
71312198SEiji.Ota@Sun.COM 	state->ack_recv = ntohll(ihdr->h_ack);
71412198SEiji.Ota@Sun.COM 	state->ack_recv_valid = 1;
71512198SEiji.Ota@Sun.COM 
71612198SEiji.Ota@Sun.COM 	/* Process the credits update if there was one */
71712198SEiji.Ota@Sun.COM 	if (ihdr->h_credit)
71812198SEiji.Ota@Sun.COM 		rdsv3_ib_send_add_credits(conn, ihdr->h_credit);
71912198SEiji.Ota@Sun.COM 
72012198SEiji.Ota@Sun.COM 	if (ihdr->h_sport == 0 && ihdr->h_dport == 0 && data_len == 0) {
72112198SEiji.Ota@Sun.COM 		/*
72212198SEiji.Ota@Sun.COM 		 * This is an ACK-only packet. The fact that it gets
72312198SEiji.Ota@Sun.COM 		 * special treatment here is that historically, ACKs
72412198SEiji.Ota@Sun.COM 		 * were rather special beasts.
72512198SEiji.Ota@Sun.COM 		 */
72612198SEiji.Ota@Sun.COM 		rdsv3_ib_stats_inc(s_ib_ack_received);
72712198SEiji.Ota@Sun.COM 		return;
72812198SEiji.Ota@Sun.COM 	}
72912198SEiji.Ota@Sun.COM 
73012198SEiji.Ota@Sun.COM 	/*
73112198SEiji.Ota@Sun.COM 	 * If we don't already have an inc on the connection then this
73212198SEiji.Ota@Sun.COM 	 * fragment has a header and starts a message.. copy its header
73312198SEiji.Ota@Sun.COM 	 * into the inc and save the inc so we can hang upcoming fragments
73412198SEiji.Ota@Sun.COM 	 * off its list.
73512198SEiji.Ota@Sun.COM 	 */
73612676SEiji.Ota@Sun.COM 	if (!ibinc) {
73712198SEiji.Ota@Sun.COM 		ibinc = recv->r_ibinc;
73812198SEiji.Ota@Sun.COM 		recv->r_ibinc = NULL;
73912198SEiji.Ota@Sun.COM 		ic->i_ibinc = ibinc;
74012198SEiji.Ota@Sun.COM 
74112198SEiji.Ota@Sun.COM 		hdr = &ibinc->ii_inc.i_hdr;
74212198SEiji.Ota@Sun.COM 		(void) memcpy(hdr, ihdr, sizeof (*hdr));
74312198SEiji.Ota@Sun.COM 		ic->i_recv_data_rem = ntohl(hdr->h_len);
74412198SEiji.Ota@Sun.COM 
74512198SEiji.Ota@Sun.COM 		RDSV3_DPRINTF5("rdsv3_ib_process_recv",
74612198SEiji.Ota@Sun.COM 		    "ic %p ibinc %p rem %u flag 0x%x", ic, ibinc,
74712198SEiji.Ota@Sun.COM 		    ic->i_recv_data_rem, hdr->h_flags);
74812198SEiji.Ota@Sun.COM 	} else {
74912198SEiji.Ota@Sun.COM 		hdr = &ibinc->ii_inc.i_hdr;
75012198SEiji.Ota@Sun.COM 		/*
75112198SEiji.Ota@Sun.COM 		 * We can't just use memcmp here; fragments of a
75212198SEiji.Ota@Sun.COM 		 * single message may carry different ACKs
75312198SEiji.Ota@Sun.COM 		 */
75412198SEiji.Ota@Sun.COM 		if (hdr->h_sequence != ihdr->h_sequence ||
75512198SEiji.Ota@Sun.COM 		    hdr->h_len != ihdr->h_len ||
75612198SEiji.Ota@Sun.COM 		    hdr->h_sport != ihdr->h_sport ||
75712198SEiji.Ota@Sun.COM 		    hdr->h_dport != ihdr->h_dport) {
75812198SEiji.Ota@Sun.COM 			RDSV3_DPRINTF2("rdsv3_ib_process_recv",
75912198SEiji.Ota@Sun.COM 			    "fragment header mismatch; forcing reconnect");
76012198SEiji.Ota@Sun.COM 			rdsv3_conn_drop(conn);
76112198SEiji.Ota@Sun.COM 			return;
76212198SEiji.Ota@Sun.COM 		}
76312198SEiji.Ota@Sun.COM 	}
76412198SEiji.Ota@Sun.COM 
76512198SEiji.Ota@Sun.COM 	list_insert_tail(&ibinc->ii_frags, recv->r_frag);
76612198SEiji.Ota@Sun.COM 	recv->r_frag = NULL;
76712198SEiji.Ota@Sun.COM 
76812198SEiji.Ota@Sun.COM 	if (ic->i_recv_data_rem > RDSV3_FRAG_SIZE)
76912198SEiji.Ota@Sun.COM 		ic->i_recv_data_rem -= RDSV3_FRAG_SIZE;
77012198SEiji.Ota@Sun.COM 	else {
77112198SEiji.Ota@Sun.COM 		ic->i_recv_data_rem = 0;
77212198SEiji.Ota@Sun.COM 		ic->i_ibinc = NULL;
77312198SEiji.Ota@Sun.COM 
77412198SEiji.Ota@Sun.COM 		if (ibinc->ii_inc.i_hdr.h_flags == RDSV3_FLAG_CONG_BITMAP)
77512198SEiji.Ota@Sun.COM 			rdsv3_ib_cong_recv(conn, ibinc);
77612198SEiji.Ota@Sun.COM 		else {
77712198SEiji.Ota@Sun.COM 			rdsv3_recv_incoming(conn, conn->c_faddr, conn->c_laddr,
77812198SEiji.Ota@Sun.COM 			    &ibinc->ii_inc, KM_NOSLEEP);
77912198SEiji.Ota@Sun.COM 			state->ack_next = ntohll(hdr->h_sequence);
78012198SEiji.Ota@Sun.COM 			state->ack_next_valid = 1;
78112198SEiji.Ota@Sun.COM 		}
78212198SEiji.Ota@Sun.COM 
78312198SEiji.Ota@Sun.COM 		/*
78412198SEiji.Ota@Sun.COM 		 * Evaluate the ACK_REQUIRED flag *after* we received
78512198SEiji.Ota@Sun.COM 		 * the complete frame, and after bumping the next_rx
78612198SEiji.Ota@Sun.COM 		 * sequence.
78712198SEiji.Ota@Sun.COM 		 */
78812198SEiji.Ota@Sun.COM 		if (hdr->h_flags & RDSV3_FLAG_ACK_REQUIRED) {
78912198SEiji.Ota@Sun.COM 			rdsv3_stats_inc(s_recv_ack_required);
79012198SEiji.Ota@Sun.COM 			state->ack_required = 1;
79112198SEiji.Ota@Sun.COM 		}
79212198SEiji.Ota@Sun.COM 
79312198SEiji.Ota@Sun.COM 		rdsv3_inc_put(&ibinc->ii_inc);
79412198SEiji.Ota@Sun.COM 	}
79512198SEiji.Ota@Sun.COM 
79612198SEiji.Ota@Sun.COM 	RDSV3_DPRINTF4("rdsv3_ib_process_recv",
79712198SEiji.Ota@Sun.COM 	    "Return: conn: %p recv: %p len: %d state: %p",
79812198SEiji.Ota@Sun.COM 	    conn, recv, data_len, state);
79912198SEiji.Ota@Sun.COM }
80012198SEiji.Ota@Sun.COM 
80112198SEiji.Ota@Sun.COM void
rdsv3_ib_recv_cqe_handler(struct rdsv3_ib_connection * ic,ibt_wc_t * wc,struct rdsv3_ib_ack_state * state)80212676SEiji.Ota@Sun.COM rdsv3_ib_recv_cqe_handler(struct rdsv3_ib_connection *ic, ibt_wc_t *wc,
80312676SEiji.Ota@Sun.COM     struct rdsv3_ib_ack_state *state)
80412198SEiji.Ota@Sun.COM {
80512198SEiji.Ota@Sun.COM 	struct rdsv3_connection *conn = ic->conn;
80612198SEiji.Ota@Sun.COM 	struct rdsv3_ib_recv_work *recv;
80712676SEiji.Ota@Sun.COM 	struct rdsv3_ib_work_ring *recv_ringp = &ic->i_recv_ring;
80812198SEiji.Ota@Sun.COM 
80912676SEiji.Ota@Sun.COM 	RDSV3_DPRINTF4("rdsv3_ib_recv_cqe_handler",
81012676SEiji.Ota@Sun.COM 	    "rwc wc_id 0x%llx status %u byte_len %u imm_data %u\n",
81112676SEiji.Ota@Sun.COM 	    (unsigned long long)wc->wc_id, wc->wc_status,
81212676SEiji.Ota@Sun.COM 	    wc->wc_bytes_xfer, ntohl(wc->wc_immed_data));
81312198SEiji.Ota@Sun.COM 
81412676SEiji.Ota@Sun.COM 	rdsv3_ib_stats_inc(s_ib_rx_cq_event);
81512676SEiji.Ota@Sun.COM 
81612676SEiji.Ota@Sun.COM 	recv = &ic->i_recvs[rdsv3_ib_ring_oldest(recv_ringp)];
81712198SEiji.Ota@Sun.COM 
81812676SEiji.Ota@Sun.COM 	/*
81912676SEiji.Ota@Sun.COM 	 * Also process recvs in connecting state because it is possible
82012676SEiji.Ota@Sun.COM 	 * to get a recv completion _before_ the rdmacm ESTABLISHED
82112676SEiji.Ota@Sun.COM 	 * event is processed.
82212676SEiji.Ota@Sun.COM 	 */
82312676SEiji.Ota@Sun.COM 	if (rdsv3_conn_up(conn) || rdsv3_conn_connecting(conn)) {
82412676SEiji.Ota@Sun.COM 		/* We expect errors as the qp is drained during shutdown */
82512676SEiji.Ota@Sun.COM 		if (wc->wc_status == IBT_WC_SUCCESS) {
82612676SEiji.Ota@Sun.COM 			rdsv3_ib_process_recv(conn, recv,
82712676SEiji.Ota@Sun.COM 			    wc->wc_bytes_xfer, state);
82812676SEiji.Ota@Sun.COM 		} else {
82912676SEiji.Ota@Sun.COM 			RDSV3_DPRINTF2("rdsv3_ib_recv_cqe_handler",
83012676SEiji.Ota@Sun.COM 			    "recv completion on "
83112676SEiji.Ota@Sun.COM 			    "%u.%u.%u.%u had status %u, "
83212676SEiji.Ota@Sun.COM 			    "disconnecting and reconnecting\n",
83312676SEiji.Ota@Sun.COM 			    NIPQUAD(conn->c_faddr),
83412676SEiji.Ota@Sun.COM 			    wc->wc_status);
83512676SEiji.Ota@Sun.COM 			rdsv3_conn_drop(conn);
83612198SEiji.Ota@Sun.COM 		}
83712198SEiji.Ota@Sun.COM 	}
83812198SEiji.Ota@Sun.COM 
83912676SEiji.Ota@Sun.COM 	rdsv3_ib_ring_free(recv_ringp, 1);
84012198SEiji.Ota@Sun.COM 
84112198SEiji.Ota@Sun.COM 	/*
84212198SEiji.Ota@Sun.COM 	 * If we ever end up with a really empty receive ring, we're
84312198SEiji.Ota@Sun.COM 	 * in deep trouble, as the sender will definitely see RNR
84412198SEiji.Ota@Sun.COM 	 * timeouts.
84512198SEiji.Ota@Sun.COM 	 */
84612676SEiji.Ota@Sun.COM 	if (rdsv3_ib_ring_empty(recv_ringp))
84712198SEiji.Ota@Sun.COM 		rdsv3_ib_stats_inc(s_ib_rx_ring_empty);
84812198SEiji.Ota@Sun.COM 
84912676SEiji.Ota@Sun.COM 	if (rdsv3_ib_ring_low(recv_ringp)) {
85012676SEiji.Ota@Sun.COM 		rdsv3_af_thr_fire(ic->i_refill_rq);
85112676SEiji.Ota@Sun.COM 	}
85212198SEiji.Ota@Sun.COM }
85312198SEiji.Ota@Sun.COM 
85412198SEiji.Ota@Sun.COM int
rdsv3_ib_recv(struct rdsv3_connection * conn)85512198SEiji.Ota@Sun.COM rdsv3_ib_recv(struct rdsv3_connection *conn)
85612198SEiji.Ota@Sun.COM {
85712198SEiji.Ota@Sun.COM 	struct rdsv3_ib_connection *ic = conn->c_transport_data;
85812198SEiji.Ota@Sun.COM 	int ret = 0;
85912198SEiji.Ota@Sun.COM 
86012198SEiji.Ota@Sun.COM 	RDSV3_DPRINTF4("rdsv3_ib_recv", "conn %p\n", conn);
86112198SEiji.Ota@Sun.COM 
86212198SEiji.Ota@Sun.COM 	if (rdsv3_conn_up(conn))
86312198SEiji.Ota@Sun.COM 		rdsv3_ib_attempt_ack(ic);
86412198SEiji.Ota@Sun.COM 
86512198SEiji.Ota@Sun.COM 	RDSV3_DPRINTF4("rdsv3_ib_recv", "Return: conn: %p", conn);
86612198SEiji.Ota@Sun.COM 
86712198SEiji.Ota@Sun.COM 	return (ret);
86812198SEiji.Ota@Sun.COM }
86912198SEiji.Ota@Sun.COM 
87012444SGiri.Adari@Sun.COM extern int rdsv3_ib_inc_constructor(void *buf, void *arg, int kmflags);
87112444SGiri.Adari@Sun.COM extern void rdsv3_ib_inc_destructor(void *buf, void *arg);
87212444SGiri.Adari@Sun.COM 
87312198SEiji.Ota@Sun.COM int
rdsv3_ib_recv_init(void)87412198SEiji.Ota@Sun.COM rdsv3_ib_recv_init(void)
87512198SEiji.Ota@Sun.COM {
87612198SEiji.Ota@Sun.COM 	RDSV3_DPRINTF4("rdsv3_ib_recv_init", "Enter");
87712198SEiji.Ota@Sun.COM 
87812198SEiji.Ota@Sun.COM 	rdsv3_ib_incoming_slab = kmem_cache_create("rdsv3_ib_incoming",
87912444SGiri.Adari@Sun.COM 	    sizeof (struct rdsv3_ib_incoming), 0, rdsv3_ib_inc_constructor,
88012444SGiri.Adari@Sun.COM 	    rdsv3_ib_inc_destructor, NULL, NULL, NULL, 0);
88112676SEiji.Ota@Sun.COM 	if (!rdsv3_ib_incoming_slab) {
88212444SGiri.Adari@Sun.COM 		RDSV3_DPRINTF2("rdsv3_ib_recv_init", "kmem_cache_create "
88312444SGiri.Adari@Sun.COM 		    "failed");
88412444SGiri.Adari@Sun.COM 		return (-ENOMEM);
88512444SGiri.Adari@Sun.COM 	}
88612198SEiji.Ota@Sun.COM 
88712198SEiji.Ota@Sun.COM 	RDSV3_DPRINTF4("rdsv3_ib_recv_init", "Return");
88812444SGiri.Adari@Sun.COM 	return (0);
88912198SEiji.Ota@Sun.COM }
89012198SEiji.Ota@Sun.COM 
89112198SEiji.Ota@Sun.COM void
rdsv3_ib_recv_exit(void)89212198SEiji.Ota@Sun.COM rdsv3_ib_recv_exit(void)
89312198SEiji.Ota@Sun.COM {
89412198SEiji.Ota@Sun.COM 	RDSV3_DPRINTF4("rdsv3_ib_recv_exit", "Enter");
89512198SEiji.Ota@Sun.COM 	kmem_cache_destroy(rdsv3_ib_incoming_slab);
89612198SEiji.Ota@Sun.COM 	RDSV3_DPRINTF4("rdsv3_ib_recv_exit", "Return");
89712198SEiji.Ota@Sun.COM }
898