1178786Skmacy/**************************************************************************
2178786Skmacy
3178786SkmacyCopyright (c) 2007, Chelsio Inc.
4178786SkmacyAll rights reserved.
5178786Skmacy
6178786SkmacyRedistribution and use in source and binary forms, with or without
7178786Skmacymodification, are permitted provided that the following conditions are met:
8178786Skmacy
9178786Skmacy 1. Redistributions of source code must retain the above copyright notice,
10178786Skmacy    this list of conditions and the following disclaimer.
11178786Skmacy
12178786Skmacy 2. Neither the name of the Chelsio Corporation nor the names of its
13178786Skmacy    contributors may be used to endorse or promote products derived from
14178786Skmacy    this software without specific prior written permission.
15178786Skmacy
16178786SkmacyTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17178786SkmacyAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18178786SkmacyIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19178786SkmacyARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20178786SkmacyLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21178786SkmacyCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22178786SkmacySUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23178786SkmacyINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24178786SkmacyCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25178786SkmacyARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26178786SkmacyPOSSIBILITY OF SUCH DAMAGE.
27178786Skmacy
28178786Skmacy***************************************************************************/
29178786Skmacy#include <sys/cdefs.h>
30178786Skmacy__FBSDID("$FreeBSD: stable/11/sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb_cm.c 315456 2017-03-17 14:54:10Z vangyzen $");
31178786Skmacy
32237263Snp#include "opt_inet.h"
33237263Snp
34237263Snp#ifdef TCP_OFFLOAD
35178786Skmacy#include <sys/param.h>
36178786Skmacy#include <sys/systm.h>
37178786Skmacy#include <sys/kernel.h>
38178786Skmacy#include <sys/bus.h>
39178786Skmacy#include <sys/pciio.h>
40178786Skmacy#include <sys/conf.h>
41178786Skmacy#include <machine/bus.h>
42178786Skmacy#include <machine/resource.h>
43178786Skmacy#include <sys/bus_dma.h>
44178786Skmacy#include <sys/rman.h>
45178786Skmacy#include <sys/ioccom.h>
46178786Skmacy#include <sys/mbuf.h>
47178786Skmacy#include <sys/rwlock.h>
48178786Skmacy#include <sys/linker.h>
49178786Skmacy#include <sys/firmware.h>
50178786Skmacy#include <sys/socket.h>
51178786Skmacy#include <sys/socketvar.h>
52178786Skmacy#include <sys/sockio.h>
53178786Skmacy#include <sys/smp.h>
54178786Skmacy#include <sys/sysctl.h>
55178786Skmacy#include <sys/syslog.h>
56178786Skmacy#include <sys/queue.h>
57178786Skmacy#include <sys/taskqueue.h>
58178786Skmacy#include <sys/proc.h>
59178786Skmacy#include <sys/uio.h>
60178786Skmacy
61178786Skmacy#include <net/route.h>
62178786Skmacy#include <netinet/in_systm.h>
63178786Skmacy#include <netinet/in.h>
64293309Smelifaro#include <netinet/in_fib.h>
65178786Skmacy#include <netinet/in_pcb.h>
66178786Skmacy#include <netinet/ip.h>
67178786Skmacy#include <netinet/ip_var.h>
68178786Skmacy#include <netinet/tcp_var.h>
69178786Skmacy#include <netinet/tcp.h>
70178786Skmacy#include <netinet/tcpip.h>
71178786Skmacy
72237263Snp#include <rdma/ib_verbs.h>
73237263Snp#include <linux/idr.h>
74237263Snp#include <ulp/iw_cxgb/iw_cxgb_ib_intfc.h>
75178786Skmacy
76178786Skmacy#include <cxgb_include.h>
77178786Skmacy#include <ulp/tom/cxgb_tom.h>
78178786Skmacy#include <ulp/tom/cxgb_toepcb.h>
79237263Snp#include <ulp/iw_cxgb/iw_cxgb_ib_intfc.h>
80237263Snp#include <rdma/ib_verbs.h>
81237263Snp#include <linux/idr.h>
82237263Snp
83178786Skmacy#include <ulp/iw_cxgb/iw_cxgb_wr.h>
84178786Skmacy#include <ulp/iw_cxgb/iw_cxgb_hal.h>
85178786Skmacy#include <ulp/iw_cxgb/iw_cxgb_provider.h>
86178786Skmacy#include <ulp/iw_cxgb/iw_cxgb_cm.h>
87178786Skmacy#include <ulp/iw_cxgb/iw_cxgb.h>
88178786Skmacy
89178786Skmacy#ifdef KTR
90178786Skmacystatic char *states[] = {
91178786Skmacy	"idle",
92178786Skmacy	"listen",
93178786Skmacy	"connecting",
94178786Skmacy	"mpa_wait_req",
95178786Skmacy	"mpa_req_sent",
96178786Skmacy	"mpa_req_rcvd",
97178786Skmacy	"mpa_rep_sent",
98178786Skmacy	"fpdu_mode",
99178786Skmacy	"aborting",
100178786Skmacy	"closing",
101178786Skmacy	"moribund",
102178786Skmacy	"dead",
103178786Skmacy	NULL,
104178786Skmacy};
105178786Skmacy#endif
106178786Skmacy
107237263SnpSYSCTL_NODE(_hw, OID_AUTO, iw_cxgb, CTLFLAG_RD, 0, "iw_cxgb driver parameters");
108178786Skmacy
109237263Snpstatic int ep_timeout_secs = 60;
110267992ShselaskySYSCTL_INT(_hw_iw_cxgb, OID_AUTO, ep_timeout_secs, CTLFLAG_RWTUN, &ep_timeout_secs, 0,
111237263Snp    "CM Endpoint operation timeout in seconds (default=60)");
112178786Skmacy
113178786Skmacystatic int mpa_rev = 1;
114267992ShselaskySYSCTL_INT(_hw_iw_cxgb, OID_AUTO, mpa_rev, CTLFLAG_RWTUN, &mpa_rev, 0,
115178786Skmacy    "MPA Revision, 0 supports amso1100, 1 is spec compliant. (default=1)");
116178786Skmacy
117178786Skmacystatic int markers_enabled = 0;
118267992ShselaskySYSCTL_INT(_hw_iw_cxgb, OID_AUTO, markers_enabled, CTLFLAG_RWTUN, &markers_enabled, 0,
119178786Skmacy    "Enable MPA MARKERS (default(0)=disabled)");
120178786Skmacy
121178786Skmacystatic int crc_enabled = 1;
122267992ShselaskySYSCTL_INT(_hw_iw_cxgb, OID_AUTO, crc_enabled, CTLFLAG_RWTUN, &crc_enabled, 0,
123178786Skmacy    "Enable MPA CRC (default(1)=enabled)");
124178786Skmacy
125178786Skmacystatic int rcv_win = 256 * 1024;
126267992ShselaskySYSCTL_INT(_hw_iw_cxgb, OID_AUTO, rcv_win, CTLFLAG_RWTUN, &rcv_win, 0,
127178786Skmacy    "TCP receive window in bytes (default=256KB)");
128178786Skmacy
129178786Skmacystatic int snd_win = 32 * 1024;
130267992ShselaskySYSCTL_INT(_hw_iw_cxgb, OID_AUTO, snd_win, CTLFLAG_RWTUN, &snd_win, 0,
131178786Skmacy    "TCP send window in bytes (default=32KB)");
132178786Skmacy
133178786Skmacystatic unsigned int nocong = 0;
134267992ShselaskySYSCTL_UINT(_hw_iw_cxgb, OID_AUTO, nocong, CTLFLAG_RWTUN, &nocong, 0,
135178786Skmacy    "Turn off congestion control (default=0)");
136178786Skmacy
137178786Skmacystatic unsigned int cong_flavor = 1;
138267992ShselaskySYSCTL_UINT(_hw_iw_cxgb, OID_AUTO, cong_flavor, CTLFLAG_RWTUN, &cong_flavor, 0,
139178786Skmacy    "TCP Congestion control flavor (default=1)");
140178786Skmacy
141178786Skmacystatic void ep_timeout(void *arg);
142178786Skmacystatic void connect_reply_upcall(struct iwch_ep *ep, int status);
143193272Sjhbstatic int iwch_so_upcall(struct socket *so, void *arg, int waitflag);
144178786Skmacy
145178786Skmacy/*
146178786Skmacy * Cruft to offload socket upcalls onto thread.
147178786Skmacy */
148178786Skmacystatic struct mtx req_lock;
149178786Skmacystatic TAILQ_HEAD(iwch_ep_list, iwch_ep_common) req_list;
150178786Skmacystatic struct task iw_cxgb_task;
151178786Skmacystatic struct taskqueue *iw_cxgb_taskq;
152178786Skmacystatic void process_req(void *ctx, int pending);
153178786Skmacy
154178786Skmacystatic void
155178786Skmacystart_ep_timer(struct iwch_ep *ep)
156178786Skmacy{
157178786Skmacy	CTR2(KTR_IW_CXGB, "%s ep %p", __FUNCTION__, ep);
158178786Skmacy	if (callout_pending(&ep->timer)) {
159178786Skmacy		CTR2(KTR_IW_CXGB, "%s stopped / restarted timer ep %p", __FUNCTION__, ep);
160178786Skmacy		callout_deactivate(&ep->timer);
161178786Skmacy		callout_drain(&ep->timer);
162178786Skmacy	} else {
163178786Skmacy		/*
164178786Skmacy		 * XXX this looks racy
165178786Skmacy		 */
166178786Skmacy		get_ep(&ep->com);
167283291Sjkim		callout_init(&ep->timer, 1);
168178786Skmacy	}
169178786Skmacy	callout_reset(&ep->timer, ep_timeout_secs * hz, ep_timeout, ep);
170178786Skmacy}
171178786Skmacy
172178786Skmacystatic void
173178786Skmacystop_ep_timer(struct iwch_ep *ep)
174178786Skmacy{
175178786Skmacy	CTR2(KTR_IW_CXGB, "%s ep %p", __FUNCTION__, ep);
176237263Snp	if (!callout_pending(&ep->timer)) {
177237263Snp		CTR3(KTR_IW_CXGB, "%s timer stopped when its not running!  ep %p state %u\n",
178237263Snp                       __func__, ep, ep->com.state);
179237263Snp		return;
180237263Snp	}
181178786Skmacy	callout_drain(&ep->timer);
182178786Skmacy	put_ep(&ep->com);
183178786Skmacy}
184178786Skmacy
185237263Snpstatic int
186237263Snpset_tcpinfo(struct iwch_ep *ep)
187178786Skmacy{
188237263Snp	struct socket *so = ep->com.so;
189237263Snp	struct inpcb *inp = sotoinpcb(so);
190237263Snp	struct tcpcb *tp;
191237263Snp	struct toepcb *toep;
192237263Snp	int rc = 0;
193178786Skmacy
194237263Snp	INP_WLOCK(inp);
195237263Snp	tp = intotcpcb(inp);
196237263Snp
197237263Snp	if ((tp->t_flags & TF_TOE) == 0) {
198237263Snp		rc = EINVAL;
199237263Snp		printf("%s: connection NOT OFFLOADED!\n", __func__);
200237263Snp		goto done;
201178786Skmacy	}
202237263Snp	toep = tp->t_toe;
203178786Skmacy
204237263Snp	ep->hwtid = toep->tp_tid;
205237263Snp	ep->snd_seq = tp->snd_nxt;
206237263Snp	ep->rcv_seq = tp->rcv_nxt;
207237263Snp	ep->emss = tp->t_maxseg;
208178786Skmacy	if (ep->emss < 128)
209178786Skmacy		ep->emss = 128;
210237263Snpdone:
211237263Snp	INP_WUNLOCK(inp);
212237263Snp	return (rc);
213237263Snp
214178786Skmacy}
215178786Skmacy
216178786Skmacystatic enum iwch_ep_state
217178786Skmacystate_read(struct iwch_ep_common *epc)
218178786Skmacy{
219178786Skmacy	enum iwch_ep_state state;
220178786Skmacy
221178786Skmacy	mtx_lock(&epc->lock);
222178786Skmacy	state = epc->state;
223178786Skmacy	mtx_unlock(&epc->lock);
224178786Skmacy	return state;
225178786Skmacy}
226178786Skmacy
227178786Skmacystatic void
228178786Skmacy__state_set(struct iwch_ep_common *epc, enum iwch_ep_state new)
229178786Skmacy{
230178786Skmacy	epc->state = new;
231178786Skmacy}
232178786Skmacy
233178786Skmacystatic void
234178786Skmacystate_set(struct iwch_ep_common *epc, enum iwch_ep_state new)
235178786Skmacy{
236178786Skmacy
237178786Skmacy	mtx_lock(&epc->lock);
238178786Skmacy	CTR3(KTR_IW_CXGB, "%s - %s -> %s", __FUNCTION__, states[epc->state], states[new]);
239178786Skmacy	__state_set(epc, new);
240178786Skmacy	mtx_unlock(&epc->lock);
241178786Skmacy	return;
242178786Skmacy}
243178786Skmacy
244178786Skmacystatic void *
245178786Skmacyalloc_ep(int size, int flags)
246178786Skmacy{
247178786Skmacy	struct iwch_ep_common *epc;
248178786Skmacy
249178786Skmacy	epc = malloc(size, M_DEVBUF, flags);
250178786Skmacy	if (epc) {
251178786Skmacy		memset(epc, 0, size);
252178786Skmacy		refcount_init(&epc->refcount, 1);
253178786Skmacy		mtx_init(&epc->lock, "iwch_epc lock", NULL, MTX_DEF|MTX_DUPOK);
254178786Skmacy		cv_init(&epc->waitq, "iwch_epc cv");
255178786Skmacy	}
256178786Skmacy	CTR2(KTR_IW_CXGB, "%s alloc ep %p", __FUNCTION__, epc);
257178786Skmacy	return epc;
258178786Skmacy}
259178786Skmacy
260178786Skmacyvoid __free_ep(struct iwch_ep_common *epc)
261178786Skmacy{
262178786Skmacy	CTR3(KTR_IW_CXGB, "%s ep %p state %s", __FUNCTION__, epc, states[state_read(epc)]);
263178786Skmacy	KASSERT(!epc->entry.tqe_prev, ("%s epc %p still on req list!\n", __FUNCTION__, epc));
264178786Skmacy	free(epc, M_DEVBUF);
265178786Skmacy}
266178786Skmacy
267293309Smelifarostatic int
268178786Skmacyfind_route(__be32 local_ip, __be32 peer_ip, __be16 local_port,
269293309Smelifaro    __be16 peer_port, u8 tos, struct nhop4_extended *pnh4)
270178786Skmacy{
271293309Smelifaro	struct in_addr addr;
272293309Smelifaro
273293309Smelifaro	addr.s_addr = peer_ip;
274293309Smelifaro	return (fib4_lookup_nh_ext(RT_DEFAULT_FIB, addr, NHR_REF, 0, pnh4));
275178786Skmacy}
276178786Skmacy
277178786Skmacystatic void
278237263Snpclose_socket(struct iwch_ep_common *epc, int close)
279178786Skmacy{
280178786Skmacy	CTR4(KTR_IW_CXGB, "%s ep %p so %p state %s", __FUNCTION__, epc, epc->so, states[epc->state]);
281178786Skmacy	SOCK_LOCK(epc->so);
282193272Sjhb	soupcall_clear(epc->so, SO_RCV);
283178786Skmacy	SOCK_UNLOCK(epc->so);
284237263Snp	if (close)
285237263Snp		soclose(epc->so);
286237263Snp	else
287237263Snp		soshutdown(epc->so, SHUT_WR|SHUT_RD);
288178786Skmacy	epc->so = NULL;
289178786Skmacy}
290178786Skmacy
291178786Skmacystatic void
292178786Skmacyshutdown_socket(struct iwch_ep_common *epc)
293178786Skmacy{
294178786Skmacy	CTR4(KTR_IW_CXGB, "%s ep %p so %p state %s", __FUNCTION__, epc, epc->so, states[epc->state]);
295178786Skmacy	soshutdown(epc->so, SHUT_WR);
296178786Skmacy}
297178786Skmacy
298178786Skmacystatic void
299178786Skmacyabort_socket(struct iwch_ep *ep)
300178786Skmacy{
301178786Skmacy	struct sockopt sopt;
302178786Skmacy	int err;
303178786Skmacy	struct linger l;
304178786Skmacy
305178786Skmacy	CTR4(KTR_IW_CXGB, "%s ep %p so %p state %s", __FUNCTION__, ep, ep->com.so, states[ep->com.state]);
306178786Skmacy	l.l_onoff = 1;
307178786Skmacy	l.l_linger = 0;
308178786Skmacy
309178786Skmacy	/* linger_time of 0 forces RST to be sent */
310178786Skmacy	sopt.sopt_dir = SOPT_SET;
311178786Skmacy	sopt.sopt_level = SOL_SOCKET;
312178786Skmacy	sopt.sopt_name = SO_LINGER;
313178786Skmacy	sopt.sopt_val = (caddr_t)&l;
314178786Skmacy	sopt.sopt_valsize = sizeof l;
315178786Skmacy	sopt.sopt_td = NULL;
316178786Skmacy	err = sosetopt(ep->com.so, &sopt);
317178786Skmacy	if (err)
318178786Skmacy		printf("%s can't set linger to 0, no RST! err %d\n", __FUNCTION__, err);
319178786Skmacy}
320178786Skmacy
321178786Skmacystatic void
322178786Skmacysend_mpa_req(struct iwch_ep *ep)
323178786Skmacy{
324178786Skmacy	int mpalen;
325178786Skmacy	struct mpa_message *mpa;
326178786Skmacy	struct mbuf *m;
327178786Skmacy	int err;
328178786Skmacy
329178786Skmacy	CTR3(KTR_IW_CXGB, "%s ep %p pd_len %d", __FUNCTION__, ep, ep->plen);
330178786Skmacy
331178786Skmacy	mpalen = sizeof(*mpa) + ep->plen;
332178786Skmacy	m = m_gethdr(mpalen, M_NOWAIT);
333178786Skmacy	if (m == NULL) {
334178786Skmacy		connect_reply_upcall(ep, -ENOMEM);
335178786Skmacy		return;
336178786Skmacy	}
337178786Skmacy	mpa = mtod(m, struct mpa_message *);
338178786Skmacy	m->m_len = mpalen;
339178786Skmacy	m->m_pkthdr.len = mpalen;
340178786Skmacy	memset(mpa, 0, sizeof(*mpa));
341178786Skmacy	memcpy(mpa->key, MPA_KEY_REQ, sizeof(mpa->key));
342178786Skmacy	mpa->flags = (crc_enabled ? MPA_CRC : 0) |
343178786Skmacy		     (markers_enabled ? MPA_MARKERS : 0);
344178786Skmacy	mpa->private_data_size = htons(ep->plen);
345178786Skmacy	mpa->revision = mpa_rev;
346178786Skmacy	if (ep->plen)
347178786Skmacy		memcpy(mpa->private_data, ep->mpa_pkt + sizeof(*mpa), ep->plen);
348178786Skmacy
349178786Skmacy	err = sosend(ep->com.so, NULL, NULL, m, NULL, MSG_DONTWAIT, ep->com.thread);
350178786Skmacy	if (err) {
351178786Skmacy		m_freem(m);
352178786Skmacy		connect_reply_upcall(ep, -ENOMEM);
353178786Skmacy		return;
354178786Skmacy	}
355178786Skmacy
356178786Skmacy	start_ep_timer(ep);
357178786Skmacy	state_set(&ep->com, MPA_REQ_SENT);
358178786Skmacy	return;
359178786Skmacy}
360178786Skmacy
361178786Skmacystatic int
362178786Skmacysend_mpa_reject(struct iwch_ep *ep, const void *pdata, u8 plen)
363178786Skmacy{
364178786Skmacy	int mpalen;
365178786Skmacy	struct mpa_message *mpa;
366178786Skmacy	struct mbuf *m;
367178786Skmacy	int err;
368178786Skmacy
369178786Skmacy	CTR3(KTR_IW_CXGB, "%s ep %p plen %d", __FUNCTION__, ep, plen);
370178786Skmacy
371178786Skmacy	mpalen = sizeof(*mpa) + plen;
372178786Skmacy
373178786Skmacy	m = m_gethdr(mpalen, M_NOWAIT);
374178786Skmacy	if (m == NULL) {
375178786Skmacy		printf("%s - cannot alloc mbuf!\n", __FUNCTION__);
376178786Skmacy		return (-ENOMEM);
377178786Skmacy	}
378178786Skmacy	mpa = mtod(m, struct mpa_message *);
379178786Skmacy	m->m_len = mpalen;
380178786Skmacy	m->m_pkthdr.len = mpalen;
381178786Skmacy	memset(mpa, 0, sizeof(*mpa));
382178786Skmacy	memcpy(mpa->key, MPA_KEY_REP, sizeof(mpa->key));
383178786Skmacy	mpa->flags = MPA_REJECT;
384178786Skmacy	mpa->revision = mpa_rev;
385178786Skmacy	mpa->private_data_size = htons(plen);
386178786Skmacy	if (plen)
387178786Skmacy		memcpy(mpa->private_data, pdata, plen);
388178786Skmacy	err = sosend(ep->com.so, NULL, NULL, m, NULL, MSG_DONTWAIT, ep->com.thread);
389178786Skmacy	PANIC_IF(err);
390178786Skmacy	return 0;
391178786Skmacy}
392178786Skmacy
393178786Skmacystatic int
394178786Skmacysend_mpa_reply(struct iwch_ep *ep, const void *pdata, u8 plen)
395178786Skmacy{
396178786Skmacy	int mpalen;
397178786Skmacy	struct mpa_message *mpa;
398178786Skmacy	struct mbuf *m;
399178786Skmacy
400178786Skmacy	CTR4(KTR_IW_CXGB, "%s ep %p so %p plen %d", __FUNCTION__, ep, ep->com.so, plen);
401178786Skmacy
402178786Skmacy	mpalen = sizeof(*mpa) + plen;
403178786Skmacy
404178786Skmacy	m = m_gethdr(mpalen, M_NOWAIT);
405178786Skmacy	if (m == NULL) {
406178786Skmacy		printf("%s - cannot alloc mbuf!\n", __FUNCTION__);
407178786Skmacy		return (-ENOMEM);
408178786Skmacy	}
409178786Skmacy	mpa = mtod(m, struct mpa_message *);
410178786Skmacy	m->m_len = mpalen;
411178786Skmacy	m->m_pkthdr.len = mpalen;
412178786Skmacy	memset(mpa, 0, sizeof(*mpa));
413178786Skmacy	memcpy(mpa->key, MPA_KEY_REP, sizeof(mpa->key));
414178786Skmacy	mpa->flags = (ep->mpa_attr.crc_enabled ? MPA_CRC : 0) |
415178786Skmacy		     (markers_enabled ? MPA_MARKERS : 0);
416178786Skmacy	mpa->revision = mpa_rev;
417178786Skmacy	mpa->private_data_size = htons(plen);
418178786Skmacy	if (plen)
419178786Skmacy		memcpy(mpa->private_data, pdata, plen);
420178786Skmacy
421178786Skmacy	state_set(&ep->com, MPA_REP_SENT);
422178786Skmacy	return sosend(ep->com.so, NULL, NULL, m, NULL, MSG_DONTWAIT,
423178786Skmacy		ep->com.thread);
424178786Skmacy}
425178786Skmacy
426178786Skmacystatic void
427178786Skmacyclose_complete_upcall(struct iwch_ep *ep)
428178786Skmacy{
429178786Skmacy	struct iw_cm_event event;
430178786Skmacy
431178786Skmacy	CTR4(KTR_IW_CXGB, "%s ep %p so %p state %s", __FUNCTION__, ep, ep->com.so, states[ep->com.state]);
432178786Skmacy	memset(&event, 0, sizeof(event));
433178786Skmacy	event.event = IW_CM_EVENT_CLOSE;
434178786Skmacy	if (ep->com.cm_id) {
435178786Skmacy		CTR3(KTR_IW_CXGB, "close complete delivered ep %p cm_id %p tid %d",
436178786Skmacy		     ep, ep->com.cm_id, ep->hwtid);
437178786Skmacy		ep->com.cm_id->event_handler(ep->com.cm_id, &event);
438178786Skmacy		ep->com.cm_id->rem_ref(ep->com.cm_id);
439178786Skmacy		ep->com.cm_id = NULL;
440178786Skmacy		ep->com.qp = NULL;
441178786Skmacy	}
442178786Skmacy}
443178786Skmacy
444178786Skmacystatic void
445178786Skmacyabort_connection(struct iwch_ep *ep)
446178786Skmacy{
447178786Skmacy	CTR4(KTR_IW_CXGB, "%s ep %p so %p state %s", __FUNCTION__, ep, ep->com.so, states[ep->com.state]);
448178786Skmacy	state_set(&ep->com, ABORTING);
449178786Skmacy	abort_socket(ep);
450237263Snp	close_socket(&ep->com, 0);
451178786Skmacy	close_complete_upcall(ep);
452178786Skmacy	state_set(&ep->com, DEAD);
453178786Skmacy	put_ep(&ep->com);
454178786Skmacy}
455178786Skmacy
456178786Skmacystatic void
457178786Skmacypeer_close_upcall(struct iwch_ep *ep)
458178786Skmacy{
459178786Skmacy	struct iw_cm_event event;
460178786Skmacy
461178786Skmacy	CTR4(KTR_IW_CXGB, "%s ep %p so %p state %s", __FUNCTION__, ep, ep->com.so, states[ep->com.state]);
462178786Skmacy	memset(&event, 0, sizeof(event));
463178786Skmacy	event.event = IW_CM_EVENT_DISCONNECT;
464178786Skmacy	if (ep->com.cm_id) {
465178786Skmacy		CTR3(KTR_IW_CXGB, "peer close delivered ep %p cm_id %p tid %d",
466178786Skmacy		     ep, ep->com.cm_id, ep->hwtid);
467178786Skmacy		ep->com.cm_id->event_handler(ep->com.cm_id, &event);
468178786Skmacy	}
469178786Skmacy}
470178786Skmacy
471178786Skmacystatic void
472178786Skmacypeer_abort_upcall(struct iwch_ep *ep)
473178786Skmacy{
474178786Skmacy	struct iw_cm_event event;
475178786Skmacy
476178786Skmacy	CTR4(KTR_IW_CXGB, "%s ep %p so %p state %s", __FUNCTION__, ep, ep->com.so, states[ep->com.state]);
477178786Skmacy	memset(&event, 0, sizeof(event));
478178786Skmacy	event.event = IW_CM_EVENT_CLOSE;
479178786Skmacy	event.status = ECONNRESET;
480178786Skmacy	if (ep->com.cm_id) {
481178786Skmacy		CTR3(KTR_IW_CXGB, "abort delivered ep %p cm_id %p tid %d", ep,
482178786Skmacy		     ep->com.cm_id, ep->hwtid);
483178786Skmacy		ep->com.cm_id->event_handler(ep->com.cm_id, &event);
484178786Skmacy		ep->com.cm_id->rem_ref(ep->com.cm_id);
485178786Skmacy		ep->com.cm_id = NULL;
486178786Skmacy		ep->com.qp = NULL;
487178786Skmacy	}
488178786Skmacy}
489178786Skmacy
490178786Skmacystatic void
491178786Skmacyconnect_reply_upcall(struct iwch_ep *ep, int status)
492178786Skmacy{
493178786Skmacy	struct iw_cm_event event;
494178786Skmacy
495178786Skmacy	CTR5(KTR_IW_CXGB, "%s ep %p so %p state %s status %d", __FUNCTION__, ep, ep->com.so, states[ep->com.state], status);
496178786Skmacy	memset(&event, 0, sizeof(event));
497178786Skmacy	event.event = IW_CM_EVENT_CONNECT_REPLY;
498178786Skmacy	event.status = status;
499178786Skmacy	event.local_addr = ep->com.local_addr;
500178786Skmacy	event.remote_addr = ep->com.remote_addr;
501178786Skmacy
502178786Skmacy	if ((status == 0) || (status == ECONNREFUSED)) {
503178786Skmacy		event.private_data_len = ep->plen;
504178786Skmacy		event.private_data = ep->mpa_pkt + sizeof(struct mpa_message);
505178786Skmacy	}
506178786Skmacy	if (ep->com.cm_id) {
507178786Skmacy		CTR4(KTR_IW_CXGB, "%s ep %p tid %d status %d", __FUNCTION__, ep,
508178786Skmacy		     ep->hwtid, status);
509178786Skmacy		ep->com.cm_id->event_handler(ep->com.cm_id, &event);
510178786Skmacy	}
511178786Skmacy	if (status < 0) {
512178786Skmacy		ep->com.cm_id->rem_ref(ep->com.cm_id);
513178786Skmacy		ep->com.cm_id = NULL;
514178786Skmacy		ep->com.qp = NULL;
515178786Skmacy	}
516178786Skmacy}
517178786Skmacy
518178786Skmacystatic void
519178786Skmacyconnect_request_upcall(struct iwch_ep *ep)
520178786Skmacy{
521178786Skmacy	struct iw_cm_event event;
522178786Skmacy
523178786Skmacy	CTR4(KTR_IW_CXGB, "%s ep %p so %p state %s", __FUNCTION__, ep, ep->com.so, states[ep->com.state]);
524178786Skmacy	memset(&event, 0, sizeof(event));
525178786Skmacy	event.event = IW_CM_EVENT_CONNECT_REQUEST;
526178786Skmacy	event.local_addr = ep->com.local_addr;
527178786Skmacy	event.remote_addr = ep->com.remote_addr;
528178786Skmacy	event.private_data_len = ep->plen;
529178786Skmacy	event.private_data = ep->mpa_pkt + sizeof(struct mpa_message);
530178786Skmacy	event.provider_data = ep;
531178786Skmacy	event.so = ep->com.so;
532237263Snp	if (state_read(&ep->parent_ep->com) != DEAD) {
533237263Snp		get_ep(&ep->com);
534178786Skmacy		ep->parent_ep->com.cm_id->event_handler(
535178786Skmacy						ep->parent_ep->com.cm_id,
536178786Skmacy						&event);
537237263Snp	}
538178786Skmacy	put_ep(&ep->parent_ep->com);
539178786Skmacy}
540178786Skmacy
541178786Skmacystatic void
542178786Skmacyestablished_upcall(struct iwch_ep *ep)
543178786Skmacy{
544178786Skmacy	struct iw_cm_event event;
545178786Skmacy
546178786Skmacy	CTR4(KTR_IW_CXGB, "%s ep %p so %p state %s", __FUNCTION__, ep, ep->com.so, states[ep->com.state]);
547178786Skmacy	memset(&event, 0, sizeof(event));
548178786Skmacy	event.event = IW_CM_EVENT_ESTABLISHED;
549178786Skmacy	if (ep->com.cm_id) {
550178786Skmacy		CTR3(KTR_IW_CXGB, "%s ep %p tid %d", __FUNCTION__, ep, ep->hwtid);
551178786Skmacy		ep->com.cm_id->event_handler(ep->com.cm_id, &event);
552178786Skmacy	}
553178786Skmacy}
554178786Skmacy
555178786Skmacystatic void
556178786Skmacyprocess_mpa_reply(struct iwch_ep *ep)
557178786Skmacy{
558178786Skmacy	struct mpa_message *mpa;
559178786Skmacy	u16 plen;
560178786Skmacy	struct iwch_qp_attributes attrs;
561178786Skmacy	enum iwch_qp_attr_mask mask;
562178786Skmacy	int err;
563178786Skmacy	struct mbuf *top, *m;
564178786Skmacy	int flags = MSG_DONTWAIT;
565178786Skmacy	struct uio uio;
566178786Skmacy	int len;
567178786Skmacy
568178786Skmacy	CTR4(KTR_IW_CXGB, "%s ep %p so %p state %s", __FUNCTION__, ep, ep->com.so, states[ep->com.state]);
569178786Skmacy
570178786Skmacy	/*
571178786Skmacy	 * Stop mpa timer.  If it expired, then the state has
572178786Skmacy	 * changed and we bail since ep_timeout already aborted
573178786Skmacy	 * the connection.
574178786Skmacy	 */
575178786Skmacy	stop_ep_timer(ep);
576178786Skmacy	if (state_read(&ep->com) != MPA_REQ_SENT)
577178786Skmacy		return;
578178786Skmacy
579178786Skmacy	uio.uio_resid = len = 1000000;
580178786Skmacy	uio.uio_td = ep->com.thread;
581178786Skmacy	err = soreceive(ep->com.so, NULL, &uio, &top, NULL, &flags);
582178786Skmacy	if (err) {
583178786Skmacy		if (err == EWOULDBLOCK) {
584178786Skmacy			start_ep_timer(ep);
585178786Skmacy			return;
586178786Skmacy		}
587178786Skmacy		err = -err;
588178786Skmacy		goto err;
589178786Skmacy	}
590178786Skmacy
591178786Skmacy	if (ep->com.so->so_rcv.sb_mb) {
592178786Skmacy		printf("%s data after soreceive called! so %p sb_mb %p top %p\n",
593178786Skmacy			__FUNCTION__, ep->com.so, ep->com.so->so_rcv.sb_mb, top);
594178786Skmacy	}
595178786Skmacy
596178786Skmacy	m = top;
597178786Skmacy	do {
598178786Skmacy		/*
599178786Skmacy		 * If we get more than the supported amount of private data
600178786Skmacy		 * then we must fail this connection.
601178786Skmacy		 */
602178786Skmacy		if (ep->mpa_pkt_len + m->m_len > sizeof(ep->mpa_pkt)) {
603178786Skmacy			err = (-EINVAL);
604178786Skmacy			goto err;
605178786Skmacy		}
606178786Skmacy
607178786Skmacy		/*
608178786Skmacy		 * copy the new data into our accumulation buffer.
609178786Skmacy		 */
610178786Skmacy		m_copydata(m, 0, m->m_len, &(ep->mpa_pkt[ep->mpa_pkt_len]));
611178786Skmacy		ep->mpa_pkt_len += m->m_len;
612178786Skmacy		if (!m->m_next)
613178786Skmacy			m = m->m_nextpkt;
614178786Skmacy		else
615178786Skmacy			m = m->m_next;
616178786Skmacy	} while (m);
617178786Skmacy
618178786Skmacy	m_freem(top);
619178786Skmacy
620178786Skmacy	/*
621178786Skmacy	 * if we don't even have the mpa message, then bail.
622178786Skmacy	 */
623178786Skmacy	if (ep->mpa_pkt_len < sizeof(*mpa))
624178786Skmacy		return;
625178786Skmacy	mpa = (struct mpa_message *)ep->mpa_pkt;
626178786Skmacy
627178786Skmacy	/* Validate MPA header. */
628178786Skmacy	if (mpa->revision != mpa_rev) {
629178786Skmacy		CTR2(KTR_IW_CXGB, "%s bad mpa rev %d", __FUNCTION__, mpa->revision);
630178786Skmacy		err = EPROTO;
631178786Skmacy		goto err;
632178786Skmacy	}
633178786Skmacy	if (memcmp(mpa->key, MPA_KEY_REP, sizeof(mpa->key))) {
634178786Skmacy		CTR2(KTR_IW_CXGB, "%s bad mpa key |%16s|", __FUNCTION__, mpa->key);
635178786Skmacy		err = EPROTO;
636178786Skmacy		goto err;
637178786Skmacy	}
638178786Skmacy
639178786Skmacy	plen = ntohs(mpa->private_data_size);
640178786Skmacy
641178786Skmacy	/*
642178786Skmacy	 * Fail if there's too much private data.
643178786Skmacy	 */
644178786Skmacy	if (plen > MPA_MAX_PRIVATE_DATA) {
645178786Skmacy		CTR2(KTR_IW_CXGB, "%s plen too big %d", __FUNCTION__, plen);
646178786Skmacy		err = EPROTO;
647178786Skmacy		goto err;
648178786Skmacy	}
649178786Skmacy
650178786Skmacy	/*
651178786Skmacy	 * If plen does not account for pkt size
652178786Skmacy	 */
653178786Skmacy	if (ep->mpa_pkt_len > (sizeof(*mpa) + plen)) {
654178786Skmacy		CTR2(KTR_IW_CXGB, "%s pkt too big %d", __FUNCTION__, ep->mpa_pkt_len);
655178786Skmacy		err = EPROTO;
656178786Skmacy		goto err;
657178786Skmacy	}
658178786Skmacy
659178786Skmacy	ep->plen = (u8) plen;
660178786Skmacy
661178786Skmacy	/*
662178786Skmacy	 * If we don't have all the pdata yet, then bail.
663178786Skmacy	 * We'll continue process when more data arrives.
664178786Skmacy	 */
665178786Skmacy	if (ep->mpa_pkt_len < (sizeof(*mpa) + plen))
666178786Skmacy		return;
667178786Skmacy
668178786Skmacy	if (mpa->flags & MPA_REJECT) {
669178786Skmacy		err = ECONNREFUSED;
670178786Skmacy		goto err;
671178786Skmacy	}
672178786Skmacy
673178786Skmacy	/*
674178786Skmacy	 * If we get here we have accumulated the entire mpa
675178786Skmacy	 * start reply message including private data. And
676178786Skmacy	 * the MPA header is valid.
677178786Skmacy	 */
678178786Skmacy	CTR1(KTR_IW_CXGB, "%s mpa rpl looks good!", __FUNCTION__);
679178786Skmacy	state_set(&ep->com, FPDU_MODE);
680237263Snp	ep->mpa_attr.initiator = 1;
681178786Skmacy	ep->mpa_attr.crc_enabled = (mpa->flags & MPA_CRC) | crc_enabled ? 1 : 0;
682178786Skmacy	ep->mpa_attr.recv_marker_enabled = markers_enabled;
683178786Skmacy	ep->mpa_attr.xmit_marker_enabled = mpa->flags & MPA_MARKERS ? 1 : 0;
684178786Skmacy	ep->mpa_attr.version = mpa_rev;
685178786Skmacy	if (set_tcpinfo(ep)) {
686178786Skmacy		printf("%s set_tcpinfo error\n", __FUNCTION__);
687178786Skmacy		goto err;
688178786Skmacy	}
689178786Skmacy	CTR5(KTR_IW_CXGB, "%s - crc_enabled=%d, recv_marker_enabled=%d, "
690178786Skmacy	     "xmit_marker_enabled=%d, version=%d", __FUNCTION__,
691178786Skmacy	     ep->mpa_attr.crc_enabled, ep->mpa_attr.recv_marker_enabled,
692178786Skmacy	     ep->mpa_attr.xmit_marker_enabled, ep->mpa_attr.version);
693178786Skmacy
694178786Skmacy	attrs.mpa_attr = ep->mpa_attr;
695178786Skmacy	attrs.max_ird = ep->ird;
696178786Skmacy	attrs.max_ord = ep->ord;
697178786Skmacy	attrs.llp_stream_handle = ep;
698178786Skmacy	attrs.next_state = IWCH_QP_STATE_RTS;
699178786Skmacy
700178786Skmacy	mask = IWCH_QP_ATTR_NEXT_STATE |
701178786Skmacy	    IWCH_QP_ATTR_LLP_STREAM_HANDLE | IWCH_QP_ATTR_MPA_ATTR |
702178786Skmacy	    IWCH_QP_ATTR_MAX_IRD | IWCH_QP_ATTR_MAX_ORD;
703178786Skmacy
704178786Skmacy	/* bind QP and TID with INIT_WR */
705178786Skmacy	err = iwch_modify_qp(ep->com.qp->rhp,
706178786Skmacy			     ep->com.qp, mask, &attrs, 1);
707178786Skmacy	if (!err)
708178786Skmacy		goto out;
709178786Skmacyerr:
710178786Skmacy	abort_connection(ep);
711178786Skmacyout:
712178786Skmacy	connect_reply_upcall(ep, err);
713178786Skmacy	return;
714178786Skmacy}
715178786Skmacy
716178786Skmacystatic void
717178786Skmacyprocess_mpa_request(struct iwch_ep *ep)
718178786Skmacy{
719178786Skmacy	struct mpa_message *mpa;
720178786Skmacy	u16 plen;
721178786Skmacy	int flags = MSG_DONTWAIT;
722178786Skmacy	struct mbuf *top, *m;
723178786Skmacy	int err;
724178786Skmacy	struct uio uio;
725178786Skmacy	int len;
726178786Skmacy
727178786Skmacy	CTR4(KTR_IW_CXGB, "%s ep %p so %p state %s", __FUNCTION__, ep, ep->com.so, states[ep->com.state]);
728178786Skmacy
729178786Skmacy	/*
730178786Skmacy	 * Stop mpa timer.  If it expired, then the state has
731178786Skmacy	 * changed and we bail since ep_timeout already aborted
732178786Skmacy	 * the connection.
733178786Skmacy	 */
734178786Skmacy	stop_ep_timer(ep);
735178786Skmacy	if (state_read(&ep->com) != MPA_REQ_WAIT)
736178786Skmacy		return;
737178786Skmacy
738178786Skmacy	uio.uio_resid = len = 1000000;
739178786Skmacy	uio.uio_td = ep->com.thread;
740178786Skmacy	err = soreceive(ep->com.so, NULL, &uio, &top, NULL, &flags);
741178786Skmacy	if (err) {
742178786Skmacy		if (err == EWOULDBLOCK) {
743178786Skmacy			start_ep_timer(ep);
744178786Skmacy			return;
745178786Skmacy		}
746178786Skmacy		err = -err;
747178786Skmacy		goto err;
748178786Skmacy	}
749178786Skmacy
750178786Skmacy	m = top;
751178786Skmacy	do {
752178786Skmacy
753178786Skmacy		/*
754178786Skmacy		 * If we get more than the supported amount of private data
755178786Skmacy		 * then we must fail this connection.
756178786Skmacy		 */
757178786Skmacy		if (ep->mpa_pkt_len + m->m_len > sizeof(ep->mpa_pkt)) {
758178786Skmacy			CTR2(KTR_IW_CXGB, "%s mpa message too big %d", __FUNCTION__,
759178786Skmacy				ep->mpa_pkt_len + m->m_len);
760178786Skmacy			goto err;
761178786Skmacy		}
762178786Skmacy
763178786Skmacy
764178786Skmacy		/*
765178786Skmacy		 * Copy the new data into our accumulation buffer.
766178786Skmacy		 */
767178786Skmacy		m_copydata(m, 0, m->m_len, &(ep->mpa_pkt[ep->mpa_pkt_len]));
768178786Skmacy		ep->mpa_pkt_len += m->m_len;
769178786Skmacy
770178786Skmacy		if (!m->m_next)
771178786Skmacy			m = m->m_nextpkt;
772178786Skmacy		else
773178786Skmacy			m = m->m_next;
774178786Skmacy	} while (m);
775178786Skmacy
776178786Skmacy	m_freem(top);
777178786Skmacy
778178786Skmacy	/*
779178786Skmacy	 * If we don't even have the mpa message, then bail.
780178786Skmacy	 * We'll continue process when more data arrives.
781178786Skmacy	 */
782178786Skmacy	if (ep->mpa_pkt_len < sizeof(*mpa)) {
783178786Skmacy		start_ep_timer(ep);
784178786Skmacy		CTR2(KTR_IW_CXGB, "%s not enough header %d...waiting...", __FUNCTION__,
785178786Skmacy			ep->mpa_pkt_len);
786178786Skmacy		return;
787178786Skmacy	}
788178786Skmacy	mpa = (struct mpa_message *) ep->mpa_pkt;
789178786Skmacy
790178786Skmacy	/*
791178786Skmacy	 * Validate MPA Header.
792178786Skmacy	 */
793178786Skmacy	if (mpa->revision != mpa_rev) {
794178786Skmacy		CTR2(KTR_IW_CXGB, "%s bad mpa rev %d", __FUNCTION__, mpa->revision);
795178786Skmacy		goto err;
796178786Skmacy	}
797178786Skmacy
798178786Skmacy	if (memcmp(mpa->key, MPA_KEY_REQ, sizeof(mpa->key))) {
799178786Skmacy		CTR2(KTR_IW_CXGB, "%s bad mpa key |%16s|", __FUNCTION__, mpa->key);
800178786Skmacy		goto err;
801178786Skmacy	}
802178786Skmacy
803178786Skmacy	plen = ntohs(mpa->private_data_size);
804178786Skmacy
805178786Skmacy	/*
806178786Skmacy	 * Fail if there's too much private data.
807178786Skmacy	 */
808178786Skmacy	if (plen > MPA_MAX_PRIVATE_DATA) {
809178786Skmacy		CTR2(KTR_IW_CXGB, "%s plen too big %d", __FUNCTION__, plen);
810178786Skmacy		goto err;
811178786Skmacy	}
812178786Skmacy
813178786Skmacy	/*
814178786Skmacy	 * If plen does not account for pkt size
815178786Skmacy	 */
816178786Skmacy	if (ep->mpa_pkt_len > (sizeof(*mpa) + plen)) {
817178786Skmacy		CTR2(KTR_IW_CXGB, "%s more data after private data %d", __FUNCTION__,
818178786Skmacy			ep->mpa_pkt_len);
819178786Skmacy		goto err;
820178786Skmacy	}
821178786Skmacy	ep->plen = (u8) plen;
822178786Skmacy
823178786Skmacy	/*
824178786Skmacy	 * If we don't have all the pdata yet, then bail.
825178786Skmacy	 */
826178786Skmacy	if (ep->mpa_pkt_len < (sizeof(*mpa) + plen)) {
827178786Skmacy		start_ep_timer(ep);
828178786Skmacy		CTR2(KTR_IW_CXGB, "%s more mpa msg to come %d", __FUNCTION__,
829178786Skmacy			ep->mpa_pkt_len);
830178786Skmacy		return;
831178786Skmacy	}
832178786Skmacy
833178786Skmacy	/*
834178786Skmacy	 * If we get here we have accumulated the entire mpa
835178786Skmacy	 * start reply message including private data.
836178786Skmacy	 */
837237263Snp	ep->mpa_attr.initiator = 0;
838178786Skmacy	ep->mpa_attr.crc_enabled = (mpa->flags & MPA_CRC) | crc_enabled ? 1 : 0;
839178786Skmacy	ep->mpa_attr.recv_marker_enabled = markers_enabled;
840178786Skmacy	ep->mpa_attr.xmit_marker_enabled = mpa->flags & MPA_MARKERS ? 1 : 0;
841178786Skmacy	ep->mpa_attr.version = mpa_rev;
842178786Skmacy	if (set_tcpinfo(ep)) {
843178786Skmacy		printf("%s set_tcpinfo error\n", __FUNCTION__);
844178786Skmacy		goto err;
845178786Skmacy	}
846178786Skmacy	CTR5(KTR_IW_CXGB, "%s - crc_enabled=%d, recv_marker_enabled=%d, "
847178786Skmacy	     "xmit_marker_enabled=%d, version=%d", __FUNCTION__,
848178786Skmacy	     ep->mpa_attr.crc_enabled, ep->mpa_attr.recv_marker_enabled,
849178786Skmacy	     ep->mpa_attr.xmit_marker_enabled, ep->mpa_attr.version);
850178786Skmacy
851178786Skmacy	state_set(&ep->com, MPA_REQ_RCVD);
852178786Skmacy
853178786Skmacy	/* drive upcall */
854178786Skmacy	connect_request_upcall(ep);
855178786Skmacy	return;
856178786Skmacyerr:
857178786Skmacy	abort_connection(ep);
858178786Skmacy	return;
859178786Skmacy}
860178786Skmacy
861178786Skmacystatic void
862178786Skmacyprocess_peer_close(struct iwch_ep *ep)
863178786Skmacy{
864178786Skmacy	struct iwch_qp_attributes attrs;
865178786Skmacy	int disconnect = 1;
866178786Skmacy	int release = 0;
867178786Skmacy
868178786Skmacy	CTR4(KTR_IW_CXGB, "%s ep %p so %p state %s", __FUNCTION__, ep, ep->com.so, states[ep->com.state]);
869178786Skmacy
870178786Skmacy	mtx_lock(&ep->com.lock);
871178786Skmacy	switch (ep->com.state) {
872178786Skmacy	case MPA_REQ_WAIT:
873178786Skmacy		__state_set(&ep->com, CLOSING);
874178786Skmacy		break;
875178786Skmacy	case MPA_REQ_SENT:
876178786Skmacy		__state_set(&ep->com, CLOSING);
877178786Skmacy		connect_reply_upcall(ep, -ECONNRESET);
878178786Skmacy		break;
879178786Skmacy	case MPA_REQ_RCVD:
880178786Skmacy
881178786Skmacy		/*
882178786Skmacy		 * We're gonna mark this puppy DEAD, but keep
883178786Skmacy		 * the reference on it until the ULP accepts or
884178786Skmacy		 * rejects the CR.
885178786Skmacy		 */
886178786Skmacy		__state_set(&ep->com, CLOSING);
887178786Skmacy		break;
888178786Skmacy	case MPA_REP_SENT:
889178786Skmacy		__state_set(&ep->com, CLOSING);
890178786Skmacy		break;
891178786Skmacy	case FPDU_MODE:
892178786Skmacy		start_ep_timer(ep);
893178786Skmacy		__state_set(&ep->com, CLOSING);
894178786Skmacy		attrs.next_state = IWCH_QP_STATE_CLOSING;
895178786Skmacy		iwch_modify_qp(ep->com.qp->rhp, ep->com.qp,
896178786Skmacy			       IWCH_QP_ATTR_NEXT_STATE, &attrs, 1);
897178786Skmacy		peer_close_upcall(ep);
898178786Skmacy		break;
899178786Skmacy	case ABORTING:
900178786Skmacy		disconnect = 0;
901178786Skmacy		break;
902178786Skmacy	case CLOSING:
903178786Skmacy		__state_set(&ep->com, MORIBUND);
904178786Skmacy		disconnect = 0;
905178786Skmacy		break;
906178786Skmacy	case MORIBUND:
907178786Skmacy		stop_ep_timer(ep);
908178786Skmacy		if (ep->com.cm_id && ep->com.qp) {
909178786Skmacy			attrs.next_state = IWCH_QP_STATE_IDLE;
910178786Skmacy			iwch_modify_qp(ep->com.qp->rhp, ep->com.qp,
911178786Skmacy				       IWCH_QP_ATTR_NEXT_STATE, &attrs, 1);
912178786Skmacy		}
913237263Snp		close_socket(&ep->com, 0);
914178786Skmacy		close_complete_upcall(ep);
915178786Skmacy		__state_set(&ep->com, DEAD);
916178786Skmacy		release = 1;
917178786Skmacy		disconnect = 0;
918178786Skmacy		break;
919178786Skmacy	case DEAD:
920178786Skmacy		disconnect = 0;
921178786Skmacy		break;
922178786Skmacy	default:
923178786Skmacy		PANIC_IF(1);
924178786Skmacy	}
925178786Skmacy	mtx_unlock(&ep->com.lock);
926178786Skmacy	if (disconnect)
927178786Skmacy		iwch_ep_disconnect(ep, 0, M_NOWAIT);
928178786Skmacy	if (release)
929178786Skmacy		put_ep(&ep->com);
930178786Skmacy	return;
931178786Skmacy}
932178786Skmacy
933178786Skmacystatic void
934178786Skmacyprocess_conn_error(struct iwch_ep *ep)
935178786Skmacy{
936178786Skmacy	struct iwch_qp_attributes attrs;
937178786Skmacy	int ret;
938178786Skmacy
939237263Snp	mtx_lock(&ep->com.lock);
940237263Snp	CTR3(KTR_IW_CXGB, "%s ep %p state %u", __func__, ep, ep->com.state);
941237263Snp	switch (ep->com.state) {
942178786Skmacy	case MPA_REQ_WAIT:
943178786Skmacy		stop_ep_timer(ep);
944178786Skmacy		break;
945178786Skmacy	case MPA_REQ_SENT:
946178786Skmacy		stop_ep_timer(ep);
947178786Skmacy		connect_reply_upcall(ep, -ECONNRESET);
948178786Skmacy		break;
949178786Skmacy	case MPA_REP_SENT:
950178786Skmacy		ep->com.rpl_err = ECONNRESET;
951178786Skmacy		CTR1(KTR_IW_CXGB, "waking up ep %p", ep);
952178786Skmacy		break;
953178786Skmacy	case MPA_REQ_RCVD:
954178786Skmacy
955178786Skmacy		/*
956178786Skmacy		 * We're gonna mark this puppy DEAD, but keep
957178786Skmacy		 * the reference on it until the ULP accepts or
958178786Skmacy		 * rejects the CR.
959178786Skmacy		 */
960178786Skmacy		break;
961178786Skmacy	case MORIBUND:
962178786Skmacy	case CLOSING:
963178786Skmacy		stop_ep_timer(ep);
964178786Skmacy		/*FALLTHROUGH*/
965178786Skmacy	case FPDU_MODE:
966178786Skmacy		if (ep->com.cm_id && ep->com.qp) {
967178786Skmacy			attrs.next_state = IWCH_QP_STATE_ERROR;
968178786Skmacy			ret = iwch_modify_qp(ep->com.qp->rhp,
969178786Skmacy				     ep->com.qp, IWCH_QP_ATTR_NEXT_STATE,
970178786Skmacy				     &attrs, 1);
971178786Skmacy			if (ret)
972178786Skmacy				log(LOG_ERR,
973178786Skmacy				       "%s - qp <- error failed!\n",
974178786Skmacy				       __FUNCTION__);
975178786Skmacy		}
976178786Skmacy		peer_abort_upcall(ep);
977178786Skmacy		break;
978178786Skmacy	case ABORTING:
979178786Skmacy		break;
980178786Skmacy	case DEAD:
981237263Snp		mtx_unlock(&ep->com.lock);
982178786Skmacy		CTR2(KTR_IW_CXGB, "%s so_error %d IN DEAD STATE!!!!", __FUNCTION__,
983178786Skmacy			ep->com.so->so_error);
984178786Skmacy		return;
985178786Skmacy	default:
986178786Skmacy		PANIC_IF(1);
987178786Skmacy		break;
988178786Skmacy	}
989178786Skmacy
990237263Snp	if (ep->com.state != ABORTING) {
991237263Snp		close_socket(&ep->com, 0);
992237263Snp		__state_set(&ep->com, DEAD);
993178786Skmacy		put_ep(&ep->com);
994178786Skmacy	}
995237263Snp	mtx_unlock(&ep->com.lock);
996178786Skmacy	return;
997178786Skmacy}
998178786Skmacy
999178786Skmacystatic void
1000178786Skmacyprocess_close_complete(struct iwch_ep *ep)
1001178786Skmacy{
1002178786Skmacy	struct iwch_qp_attributes attrs;
1003178786Skmacy	int release = 0;
1004178786Skmacy
1005178786Skmacy	CTR4(KTR_IW_CXGB, "%s ep %p so %p state %s", __FUNCTION__, ep, ep->com.so, states[ep->com.state]);
1006178786Skmacy	PANIC_IF(!ep);
1007178786Skmacy
1008178786Skmacy	/* The cm_id may be null if we failed to connect */
1009178786Skmacy	mtx_lock(&ep->com.lock);
1010178786Skmacy	switch (ep->com.state) {
1011178786Skmacy	case CLOSING:
1012178786Skmacy		__state_set(&ep->com, MORIBUND);
1013178786Skmacy		break;
1014178786Skmacy	case MORIBUND:
1015178786Skmacy		stop_ep_timer(ep);
1016178786Skmacy		if ((ep->com.cm_id) && (ep->com.qp)) {
1017178786Skmacy			attrs.next_state = IWCH_QP_STATE_IDLE;
1018178786Skmacy			iwch_modify_qp(ep->com.qp->rhp,
1019178786Skmacy					     ep->com.qp,
1020178786Skmacy					     IWCH_QP_ATTR_NEXT_STATE,
1021178786Skmacy					     &attrs, 1);
1022178786Skmacy		}
1023237263Snp		if (ep->parent_ep)
1024237263Snp			close_socket(&ep->com, 1);
1025237263Snp		else
1026237263Snp			close_socket(&ep->com, 0);
1027178786Skmacy		close_complete_upcall(ep);
1028178786Skmacy		__state_set(&ep->com, DEAD);
1029178786Skmacy		release = 1;
1030178786Skmacy		break;
1031178786Skmacy	case ABORTING:
1032178786Skmacy		break;
1033178786Skmacy	case DEAD:
1034178786Skmacy	default:
1035178786Skmacy		PANIC_IF(1);
1036178786Skmacy		break;
1037178786Skmacy	}
1038178786Skmacy	mtx_unlock(&ep->com.lock);
1039178786Skmacy	if (release)
1040178786Skmacy		put_ep(&ep->com);
1041178786Skmacy	return;
1042178786Skmacy}
1043178786Skmacy
1044178786Skmacy/*
1045178786Skmacy * T3A does 3 things when a TERM is received:
1046178786Skmacy * 1) send up a CPL_RDMA_TERMINATE message with the TERM packet
1047178786Skmacy * 2) generate an async event on the QP with the TERMINATE opcode
1048178786Skmacy * 3) post a TERMINATE opcde cqe into the associated CQ.
1049178786Skmacy *
1050178786Skmacy * For (1), we save the message in the qp for later consumer consumption.
1051178786Skmacy * For (2), we move the QP into TERMINATE, post a QP event and disconnect.
1052178786Skmacy * For (3), we toss the CQE in cxio_poll_cq().
1053178786Skmacy *
1054178786Skmacy * terminate() handles case (1)...
1055178786Skmacy */
1056178786Skmacystatic int
1057237263Snpterminate(struct sge_qset *qs, struct rsp_desc *r, struct mbuf *m)
1058178786Skmacy{
1059237263Snp	struct adapter *sc = qs->adap;
1060237263Snp	struct tom_data *td = sc->tom_softc;
1061237263Snp	uint32_t hash = *((uint32_t *)r + 1);
1062237263Snp	unsigned int tid = ntohl(hash) >> 8 & 0xfffff;
1063237263Snp	struct toepcb *toep = lookup_tid(&td->tid_maps, tid);
1064237263Snp	struct socket *so = toep->tp_inp->inp_socket;
1065193272Sjhb	struct iwch_ep *ep = so->so_rcv.sb_upcallarg;
1066178786Skmacy
1067237263Snp	if (state_read(&ep->com) != FPDU_MODE)
1068237263Snp		goto done;
1069237263Snp
1070178786Skmacy	m_adj(m, sizeof(struct cpl_rdma_terminate));
1071237263Snp
1072237263Snp	CTR4(KTR_IW_CXGB, "%s: tid %u, ep %p, saved %d bytes",
1073237263Snp	    __func__, tid, ep, m->m_len);
1074237263Snp
1075178786Skmacy	m_copydata(m, 0, m->m_len, ep->com.qp->attr.terminate_buffer);
1076178786Skmacy	ep->com.qp->attr.terminate_msg_len = m->m_len;
1077178786Skmacy	ep->com.qp->attr.is_terminate_local = 0;
1078237263Snp
1079237263Snpdone:
1080237263Snp	m_freem(m);
1081237263Snp	return (0);
1082178786Skmacy}
1083178786Skmacy
1084178786Skmacystatic int
1085237263Snpec_status(struct sge_qset *qs, struct rsp_desc *r, struct mbuf *m)
1086178786Skmacy{
1087237263Snp	struct adapter *sc = qs->adap;
1088237263Snp	struct tom_data *td = sc->tom_softc;
1089237263Snp	struct cpl_rdma_ec_status *rep = mtod(m, void *);
1090237263Snp	unsigned int tid = GET_TID(rep);
1091237263Snp	struct toepcb *toep = lookup_tid(&td->tid_maps, tid);
1092237263Snp	struct socket *so = toep->tp_inp->inp_socket;
1093237263Snp	struct iwch_ep *ep = so->so_rcv.sb_upcallarg;
1094178786Skmacy
1095237263Snp	if (rep->status) {
1096237263Snp		struct iwch_qp_attributes attrs;
1097237263Snp
1098237263Snp		CTR1(KTR_IW_CXGB, "%s BAD CLOSE - Aborting", __FUNCTION__);
1099178786Skmacy		stop_ep_timer(ep);
1100178786Skmacy		attrs.next_state = IWCH_QP_STATE_ERROR;
1101178786Skmacy		iwch_modify_qp(ep->com.qp->rhp,
1102237263Snp			     ep->com.qp,
1103237263Snp			     IWCH_QP_ATTR_NEXT_STATE,
1104237263Snp			     &attrs, 1);
1105237263Snp		abort_connection(ep);
1106178786Skmacy	}
1107237263Snp
1108237263Snp	m_freem(m);
1109237263Snp	return (0);
1110178786Skmacy}
1111178786Skmacy
1112178786Skmacystatic void
1113178786Skmacyep_timeout(void *arg)
1114178786Skmacy{
1115178786Skmacy	struct iwch_ep *ep = (struct iwch_ep *)arg;
1116178786Skmacy	struct iwch_qp_attributes attrs;
1117178786Skmacy	int err = 0;
1118237263Snp	int abort = 1;
1119178786Skmacy
1120178786Skmacy	mtx_lock(&ep->com.lock);
1121178786Skmacy	CTR4(KTR_IW_CXGB, "%s ep %p so %p state %s", __FUNCTION__, ep, ep->com.so, states[ep->com.state]);
1122178786Skmacy	switch (ep->com.state) {
1123178786Skmacy	case MPA_REQ_SENT:
1124237263Snp		__state_set(&ep->com, ABORTING);
1125178786Skmacy		connect_reply_upcall(ep, -ETIMEDOUT);
1126178786Skmacy		break;
1127178786Skmacy	case MPA_REQ_WAIT:
1128237263Snp		__state_set(&ep->com, ABORTING);
1129178786Skmacy		break;
1130178786Skmacy	case CLOSING:
1131178786Skmacy	case MORIBUND:
1132178786Skmacy		if (ep->com.cm_id && ep->com.qp)
1133178786Skmacy			err = 1;
1134237263Snp		__state_set(&ep->com, ABORTING);
1135178786Skmacy		break;
1136178786Skmacy	default:
1137237263Snp		CTR3(KTR_IW_CXGB, "%s unexpected state ep %p state %u\n",
1138237263Snp			__func__, ep, ep->com.state);
1139237263Snp		abort = 0;
1140178786Skmacy	}
1141178786Skmacy	mtx_unlock(&ep->com.lock);
1142178786Skmacy	if (err){
1143178786Skmacy		attrs.next_state = IWCH_QP_STATE_ERROR;
1144178786Skmacy		iwch_modify_qp(ep->com.qp->rhp,
1145178786Skmacy			     ep->com.qp, IWCH_QP_ATTR_NEXT_STATE,
1146178786Skmacy			     &attrs, 1);
1147178786Skmacy	}
1148237263Snp	if (abort)
1149237263Snp		abort_connection(ep);
1150178786Skmacy	put_ep(&ep->com);
1151178786Skmacy}
1152178786Skmacy
1153178786Skmacyint
1154178786Skmacyiwch_reject_cr(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
1155178786Skmacy{
1156178786Skmacy	int err;
1157178786Skmacy	struct iwch_ep *ep = to_ep(cm_id);
1158178786Skmacy	CTR4(KTR_IW_CXGB, "%s ep %p so %p state %s", __FUNCTION__, ep, ep->com.so, states[ep->com.state]);
1159178786Skmacy
1160178786Skmacy	if (state_read(&ep->com) == DEAD) {
1161178786Skmacy		put_ep(&ep->com);
1162178786Skmacy		return (-ECONNRESET);
1163178786Skmacy	}
1164178786Skmacy	PANIC_IF(state_read(&ep->com) != MPA_REQ_RCVD);
1165178786Skmacy	if (mpa_rev == 0) {
1166178786Skmacy		abort_connection(ep);
1167178786Skmacy	} else {
1168178786Skmacy		err = send_mpa_reject(ep, pdata, pdata_len);
1169178786Skmacy		err = soshutdown(ep->com.so, 3);
1170178786Skmacy	}
1171237263Snp	put_ep(&ep->com);
1172178786Skmacy	return 0;
1173178786Skmacy}
1174178786Skmacy
1175178786Skmacyint
1176178786Skmacyiwch_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
1177178786Skmacy{
1178178786Skmacy	int err;
1179178786Skmacy	struct iwch_qp_attributes attrs;
1180178786Skmacy	enum iwch_qp_attr_mask mask;
1181178786Skmacy	struct iwch_ep *ep = to_ep(cm_id);
1182178786Skmacy	struct iwch_dev *h = to_iwch_dev(cm_id->device);
1183178786Skmacy	struct iwch_qp *qp = get_qhp(h, conn_param->qpn);
1184178786Skmacy
1185178786Skmacy	CTR4(KTR_IW_CXGB, "%s ep %p so %p state %s", __FUNCTION__, ep, ep->com.so, states[ep->com.state]);
1186237263Snp	if (state_read(&ep->com) == DEAD) {
1187237263Snp		err = -ECONNRESET;
1188237263Snp		goto err;
1189237263Snp	}
1190178786Skmacy
1191178786Skmacy	PANIC_IF(state_read(&ep->com) != MPA_REQ_RCVD);
1192178786Skmacy	PANIC_IF(!qp);
1193178786Skmacy
1194178786Skmacy	if ((conn_param->ord > qp->rhp->attr.max_rdma_read_qp_depth) ||
1195178786Skmacy	    (conn_param->ird > qp->rhp->attr.max_rdma_reads_per_qp)) {
1196178786Skmacy		abort_connection(ep);
1197237263Snp		err = -EINVAL;
1198237263Snp		goto err;
1199178786Skmacy	}
1200178786Skmacy
1201178786Skmacy	cm_id->add_ref(cm_id);
1202178786Skmacy	ep->com.cm_id = cm_id;
1203178786Skmacy	ep->com.qp = qp;
1204178786Skmacy
1205178786Skmacy	ep->com.rpl_err = 0;
1206178786Skmacy	ep->com.rpl_done = 0;
1207178786Skmacy	ep->ird = conn_param->ird;
1208178786Skmacy	ep->ord = conn_param->ord;
1209178786Skmacy	CTR3(KTR_IW_CXGB, "%s ird %d ord %d", __FUNCTION__, ep->ird, ep->ord);
1210178786Skmacy
1211178786Skmacy	/* bind QP to EP and move to RTS */
1212178786Skmacy	attrs.mpa_attr = ep->mpa_attr;
1213237263Snp	attrs.max_ird = ep->ird;
1214178786Skmacy	attrs.max_ord = ep->ord;
1215178786Skmacy	attrs.llp_stream_handle = ep;
1216178786Skmacy	attrs.next_state = IWCH_QP_STATE_RTS;
1217178786Skmacy
1218178786Skmacy	/* bind QP and TID with INIT_WR */
1219178786Skmacy	mask = IWCH_QP_ATTR_NEXT_STATE |
1220178786Skmacy			     IWCH_QP_ATTR_LLP_STREAM_HANDLE |
1221178786Skmacy			     IWCH_QP_ATTR_MPA_ATTR |
1222178786Skmacy			     IWCH_QP_ATTR_MAX_IRD |
1223178786Skmacy			     IWCH_QP_ATTR_MAX_ORD;
1224178786Skmacy
1225178786Skmacy	err = iwch_modify_qp(ep->com.qp->rhp,
1226178786Skmacy			     ep->com.qp, mask, &attrs, 1);
1227178786Skmacy
1228178786Skmacy	if (err)
1229237263Snp		goto err1;
1230178786Skmacy
1231178786Skmacy	err = send_mpa_reply(ep, conn_param->private_data,
1232178786Skmacy 			     conn_param->private_data_len);
1233178786Skmacy	if (err)
1234237263Snp		goto err1;
1235178786Skmacy	state_set(&ep->com, FPDU_MODE);
1236178786Skmacy	established_upcall(ep);
1237178786Skmacy	put_ep(&ep->com);
1238178786Skmacy	return 0;
1239237263Snperr1:
1240178786Skmacy	ep->com.cm_id = NULL;
1241178786Skmacy	ep->com.qp = NULL;
1242178786Skmacy	cm_id->rem_ref(cm_id);
1243237263Snperr:
1244178786Skmacy	put_ep(&ep->com);
1245178786Skmacy	return err;
1246178786Skmacy}
1247178786Skmacy
1248178786Skmacystatic int init_sock(struct iwch_ep_common *epc)
1249178786Skmacy{
1250178786Skmacy	int err;
1251178786Skmacy	struct sockopt sopt;
1252178786Skmacy	int on=1;
1253178786Skmacy
1254193272Sjhb	SOCK_LOCK(epc->so);
1255193272Sjhb	soupcall_set(epc->so, SO_RCV, iwch_so_upcall, epc);
1256178786Skmacy	epc->so->so_state |= SS_NBIO;
1257193272Sjhb	SOCK_UNLOCK(epc->so);
1258178786Skmacy	sopt.sopt_dir = SOPT_SET;
1259178786Skmacy	sopt.sopt_level = IPPROTO_TCP;
1260178786Skmacy	sopt.sopt_name = TCP_NODELAY;
1261178786Skmacy	sopt.sopt_val = (caddr_t)&on;
1262178786Skmacy	sopt.sopt_valsize = sizeof on;
1263178786Skmacy	sopt.sopt_td = NULL;
1264178786Skmacy	err = sosetopt(epc->so, &sopt);
1265178786Skmacy	if (err)
1266178786Skmacy		printf("%s can't set TCP_NODELAY err %d\n", __FUNCTION__, err);
1267178786Skmacy
1268178786Skmacy	return 0;
1269178786Skmacy}
1270178786Skmacy
1271178786Skmacystatic int
1272178786Skmacyis_loopback_dst(struct iw_cm_id *cm_id)
1273178786Skmacy{
1274178786Skmacy	uint16_t port = cm_id->remote_addr.sin_port;
1275194622Srwatson	int ifa_present;
1276178786Skmacy
1277178786Skmacy	cm_id->remote_addr.sin_port = 0;
1278194622Srwatson	ifa_present = ifa_ifwithaddr_check(
1279194622Srwatson	    (struct sockaddr *)&cm_id->remote_addr);
1280178786Skmacy	cm_id->remote_addr.sin_port = port;
1281194622Srwatson	return (ifa_present);
1282178786Skmacy}
1283178786Skmacy
1284178786Skmacyint
1285178786Skmacyiwch_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
1286178786Skmacy{
1287178786Skmacy	int err = 0;
1288178786Skmacy	struct iwch_dev *h = to_iwch_dev(cm_id->device);
1289178786Skmacy	struct iwch_ep *ep;
1290293309Smelifaro	struct nhop4_extended nh4;
1291178786Skmacy	struct toedev *tdev;
1292178786Skmacy
1293178786Skmacy	if (is_loopback_dst(cm_id)) {
1294178786Skmacy		err = -ENOSYS;
1295178786Skmacy		goto out;
1296178786Skmacy	}
1297178786Skmacy
1298178786Skmacy	ep = alloc_ep(sizeof(*ep), M_NOWAIT);
1299178786Skmacy	if (!ep) {
1300178786Skmacy		printf("%s - cannot alloc ep.\n", __FUNCTION__);
1301178786Skmacy		err = (-ENOMEM);
1302178786Skmacy		goto out;
1303178786Skmacy	}
1304283291Sjkim	callout_init(&ep->timer, 1);
1305178786Skmacy	ep->plen = conn_param->private_data_len;
1306178786Skmacy	if (ep->plen)
1307178786Skmacy		memcpy(ep->mpa_pkt + sizeof(struct mpa_message),
1308178786Skmacy		       conn_param->private_data, ep->plen);
1309178786Skmacy	ep->ird = conn_param->ird;
1310178786Skmacy	ep->ord = conn_param->ord;
1311178786Skmacy
1312178786Skmacy	cm_id->add_ref(cm_id);
1313178786Skmacy	ep->com.cm_id = cm_id;
1314178786Skmacy	ep->com.qp = get_qhp(h, conn_param->qpn);
1315178786Skmacy	ep->com.thread = curthread;
1316178786Skmacy	PANIC_IF(!ep->com.qp);
1317178786Skmacy	CTR4(KTR_IW_CXGB, "%s qpn 0x%x qp %p cm_id %p", __FUNCTION__, conn_param->qpn,
1318178786Skmacy	     ep->com.qp, cm_id);
1319178786Skmacy
1320178786Skmacy	ep->com.so = cm_id->so;
1321178786Skmacy	err = init_sock(&ep->com);
1322178786Skmacy	if (err)
1323178786Skmacy		goto fail2;
1324178786Skmacy
1325178786Skmacy	/* find a route */
1326293309Smelifaro	err = find_route(cm_id->local_addr.sin_addr.s_addr,
1327178786Skmacy			cm_id->remote_addr.sin_addr.s_addr,
1328178786Skmacy			cm_id->local_addr.sin_port,
1329293309Smelifaro			cm_id->remote_addr.sin_port, IPTOS_LOWDELAY, &nh4);
1330293309Smelifaro	if (err) {
1331178786Skmacy		printf("%s - cannot find route.\n", __FUNCTION__);
1332178786Skmacy		err = EHOSTUNREACH;
1333178786Skmacy		goto fail2;
1334178786Skmacy	}
1335178786Skmacy
1336293309Smelifaro	if (!(nh4.nh_ifp->if_flags & IFCAP_TOE)) {
1337178786Skmacy		printf("%s - interface not TOE capable.\n", __FUNCTION__);
1338293309Smelifaro		fib4_free_nh_ext(RT_DEFAULT_FIB, &nh4);
1339237263Snp		goto fail2;
1340178786Skmacy	}
1341293309Smelifaro	tdev = TOEDEV(nh4.nh_ifp);
1342178786Skmacy	if (tdev == NULL) {
1343178786Skmacy		printf("%s - No toedev for interface.\n", __FUNCTION__);
1344293309Smelifaro		fib4_free_nh_ext(RT_DEFAULT_FIB, &nh4);
1345237263Snp		goto fail2;
1346178786Skmacy	}
1347293309Smelifaro	fib4_free_nh_ext(RT_DEFAULT_FIB, &nh4);
1348178786Skmacy
1349178786Skmacy	state_set(&ep->com, CONNECTING);
1350178786Skmacy	ep->com.local_addr = cm_id->local_addr;
1351178786Skmacy	ep->com.remote_addr = cm_id->remote_addr;
1352178786Skmacy	err = soconnect(ep->com.so, (struct sockaddr *)&ep->com.remote_addr,
1353178786Skmacy		ep->com.thread);
1354178786Skmacy	if (!err)
1355178786Skmacy		goto out;
1356178786Skmacyfail2:
1357178786Skmacy	put_ep(&ep->com);
1358178786Skmacyout:
1359178786Skmacy	return err;
1360178786Skmacy}
1361178786Skmacy
1362178786Skmacyint
1363294610Snpiwch_create_listen_ep(struct iw_cm_id *cm_id, int backlog)
1364178786Skmacy{
1365178786Skmacy	int err = 0;
1366178786Skmacy	struct iwch_listen_ep *ep;
1367178786Skmacy
1368178786Skmacy	ep = alloc_ep(sizeof(*ep), M_NOWAIT);
1369178786Skmacy	if (!ep) {
1370178786Skmacy		printf("%s - cannot alloc ep.\n", __FUNCTION__);
1371178786Skmacy		err = ENOMEM;
1372178786Skmacy		goto out;
1373178786Skmacy	}
1374178786Skmacy	CTR2(KTR_IW_CXGB, "%s ep %p", __FUNCTION__, ep);
1375178786Skmacy	cm_id->add_ref(cm_id);
1376178786Skmacy	ep->com.cm_id = cm_id;
1377178786Skmacy	ep->backlog = backlog;
1378178786Skmacy	ep->com.local_addr = cm_id->local_addr;
1379178786Skmacy	ep->com.thread = curthread;
1380178786Skmacy	state_set(&ep->com, LISTEN);
1381178786Skmacy
1382178786Skmacy	ep->com.so = cm_id->so;
1383294610Snp	cm_id->provider_data = ep;
1384178786Skmacyout:
1385178786Skmacy	return err;
1386178786Skmacy}
1387178786Skmacy
1388294610Snpvoid
1389294610Snpiwch_destroy_listen_ep(struct iw_cm_id *cm_id)
1390178786Skmacy{
1391178786Skmacy	struct iwch_listen_ep *ep = to_listen_ep(cm_id);
1392178786Skmacy
1393178786Skmacy	CTR2(KTR_IW_CXGB, "%s ep %p", __FUNCTION__, ep);
1394178786Skmacy
1395178786Skmacy	state_set(&ep->com, DEAD);
1396178786Skmacy	cm_id->rem_ref(cm_id);
1397178786Skmacy	put_ep(&ep->com);
1398294610Snp	return;
1399178786Skmacy}
1400178786Skmacy
1401178786Skmacyint
1402178786Skmacyiwch_ep_disconnect(struct iwch_ep *ep, int abrupt, int flags)
1403178786Skmacy{
1404178786Skmacy	int close = 0;
1405178786Skmacy
1406178786Skmacy	mtx_lock(&ep->com.lock);
1407178786Skmacy
1408178786Skmacy	PANIC_IF(!ep);
1409178786Skmacy	PANIC_IF(!ep->com.so);
1410178786Skmacy
1411178786Skmacy	CTR5(KTR_IW_CXGB, "%s ep %p so %p state %s, abrupt %d", __FUNCTION__, ep,
1412178786Skmacy	     ep->com.so, states[ep->com.state], abrupt);
1413178786Skmacy
1414178786Skmacy	switch (ep->com.state) {
1415178786Skmacy	case MPA_REQ_WAIT:
1416178786Skmacy	case MPA_REQ_SENT:
1417178786Skmacy	case MPA_REQ_RCVD:
1418178786Skmacy	case MPA_REP_SENT:
1419178786Skmacy	case FPDU_MODE:
1420178786Skmacy		close = 1;
1421237263Snp		if (abrupt)
1422237263Snp			ep->com.state = ABORTING;
1423237263Snp		else {
1424237263Snp			ep->com.state = CLOSING;
1425237263Snp			start_ep_timer(ep);
1426237263Snp		}
1427178786Skmacy		break;
1428178786Skmacy	case CLOSING:
1429178786Skmacy		close = 1;
1430237263Snp		if (abrupt) {
1431237263Snp			stop_ep_timer(ep);
1432237263Snp			ep->com.state = ABORTING;
1433237263Snp		} else
1434237263Snp			ep->com.state = MORIBUND;
1435178786Skmacy		break;
1436178786Skmacy	case MORIBUND:
1437178786Skmacy	case ABORTING:
1438237263Snp	case DEAD:
1439237263Snp		CTR3(KTR_IW_CXGB, "%s ignoring disconnect ep %p state %u\n",
1440237263Snp			__func__, ep, ep->com.state);
1441178786Skmacy		break;
1442178786Skmacy	default:
1443178786Skmacy		panic("unknown state: %d\n", ep->com.state);
1444178786Skmacy		break;
1445178786Skmacy	}
1446237263Snp
1447178786Skmacy	mtx_unlock(&ep->com.lock);
1448178786Skmacy	if (close) {
1449178786Skmacy		if (abrupt)
1450178786Skmacy			abort_connection(ep);
1451237263Snp		else {
1452237263Snp			if (!ep->parent_ep)
1453237263Snp				__state_set(&ep->com, MORIBUND);
1454178786Skmacy			shutdown_socket(&ep->com);
1455237263Snp		}
1456178786Skmacy	}
1457178786Skmacy	return 0;
1458178786Skmacy}
1459178786Skmacy
1460178786Skmacystatic void
1461178786Skmacyprocess_data(struct iwch_ep *ep)
1462178786Skmacy{
1463178786Skmacy	struct sockaddr_in *local, *remote;
1464178786Skmacy
1465178786Skmacy	CTR4(KTR_IW_CXGB, "%s ep %p so %p state %s", __FUNCTION__, ep, ep->com.so, states[ep->com.state]);
1466178786Skmacy
1467178786Skmacy	switch (state_read(&ep->com)) {
1468178786Skmacy	case MPA_REQ_SENT:
1469178786Skmacy		process_mpa_reply(ep);
1470178786Skmacy		break;
1471178786Skmacy	case MPA_REQ_WAIT:
1472178786Skmacy
1473178786Skmacy		/*
1474178786Skmacy		 * XXX
1475178786Skmacy		 * Set local and remote addrs here because when we
1476178786Skmacy		 * dequeue the newly accepted socket, they aren't set
1477178786Skmacy		 * yet in the pcb!
1478178786Skmacy		 */
1479178786Skmacy		in_getsockaddr(ep->com.so, (struct sockaddr **)&local);
1480178786Skmacy		in_getpeeraddr(ep->com.so, (struct sockaddr **)&remote);
1481315456Svangyzen		CTR3(KTR_IW_CXGB, "%s local 0x%08x remote 0x%08x", __FUNCTION__,
1482315456Svangyzen			ntohl(local->sin_addr.s_addr),
1483315456Svangyzen			ntohl(remote->sin_addr.s_addr));
1484178786Skmacy		ep->com.local_addr = *local;
1485178786Skmacy		ep->com.remote_addr = *remote;
1486178786Skmacy		free(local, M_SONAME);
1487178786Skmacy		free(remote, M_SONAME);
1488178786Skmacy		process_mpa_request(ep);
1489178786Skmacy		break;
1490178786Skmacy	default:
1491274421Sglebius		if (sbavail(&ep->com.so->so_rcv))
1492178786Skmacy			printf("%s Unexpected streaming data."
1493178786Skmacy			       " ep %p state %d so %p so_state %x so_rcv.sb_cc %u so_rcv.sb_mb %p\n",
1494178786Skmacy			       __FUNCTION__, ep, state_read(&ep->com), ep->com.so, ep->com.so->so_state,
1495274421Sglebius			       sbavail(&ep->com.so->so_rcv), ep->com.so->so_rcv.sb_mb);
1496178786Skmacy		break;
1497178786Skmacy	}
1498178786Skmacy	return;
1499178786Skmacy}
1500178786Skmacy
1501178786Skmacystatic void
1502178786Skmacyprocess_connected(struct iwch_ep *ep)
1503178786Skmacy{
1504178786Skmacy	CTR4(KTR_IW_CXGB, "%s ep %p so %p state %s", __FUNCTION__, ep, ep->com.so, states[ep->com.state]);
1505178786Skmacy	if ((ep->com.so->so_state & SS_ISCONNECTED) && !ep->com.so->so_error) {
1506178786Skmacy		send_mpa_req(ep);
1507178786Skmacy	} else {
1508178786Skmacy		connect_reply_upcall(ep, -ep->com.so->so_error);
1509237263Snp		close_socket(&ep->com, 0);
1510178786Skmacy		state_set(&ep->com, DEAD);
1511178786Skmacy		put_ep(&ep->com);
1512178786Skmacy	}
1513178786Skmacy}
1514178786Skmacy
1515294610Snpvoid
1516294610Snpprocess_newconn(struct iw_cm_id *parent_cm_id, struct socket *child_so)
1517178786Skmacy{
1518178786Skmacy	struct iwch_ep *child_ep;
1519294610Snp	struct sockaddr_in *local;
1520178786Skmacy	struct sockaddr_in *remote;
1521294610Snp	struct iwch_ep *parent_ep = parent_cm_id->provider_data;
1522178786Skmacy
1523178786Skmacy	CTR3(KTR_IW_CXGB, "%s parent ep %p so %p", __FUNCTION__, parent_ep, parent_ep->com.so);
1524294610Snp	if (!child_so) {
1525294610Snp		log(LOG_ERR, "%s - invalid child socket!\n", __func__);
1526294610Snp		return;
1527294610Snp	}
1528178786Skmacy	child_ep = alloc_ep(sizeof(*child_ep), M_NOWAIT);
1529178786Skmacy	if (!child_ep) {
1530178786Skmacy		log(LOG_ERR, "%s - failed to allocate ep entry!\n",
1531178786Skmacy		       __FUNCTION__);
1532178786Skmacy		return;
1533178786Skmacy	}
1534294610Snp	SOCKBUF_LOCK(&child_so->so_rcv);
1535294610Snp	soupcall_set(child_so, SO_RCV, iwch_so_upcall, child_ep);
1536294610Snp	SOCKBUF_UNLOCK(&child_so->so_rcv);
1537294610Snp
1538294610Snp	in_getsockaddr(child_so, (struct sockaddr **)&local);
1539294610Snp	in_getpeeraddr(child_so, (struct sockaddr **)&remote);
1540294610Snp
1541315456Svangyzen	CTR3(KTR_IW_CXGB, "%s remote addr 0x%08x port %d", __FUNCTION__,
1542315456Svangyzen		ntohl(remote->sin_addr.s_addr), ntohs(remote->sin_port));
1543237263Snp	child_ep->com.tdev = parent_ep->com.tdev;
1544237263Snp	child_ep->com.local_addr.sin_family = parent_ep->com.local_addr.sin_family;
1545237263Snp	child_ep->com.local_addr.sin_port = parent_ep->com.local_addr.sin_port;
1546237263Snp	child_ep->com.local_addr.sin_addr.s_addr = parent_ep->com.local_addr.sin_addr.s_addr;
1547237263Snp	child_ep->com.local_addr.sin_len = parent_ep->com.local_addr.sin_len;
1548237263Snp	child_ep->com.remote_addr.sin_family = remote->sin_family;
1549237263Snp	child_ep->com.remote_addr.sin_port = remote->sin_port;
1550237263Snp	child_ep->com.remote_addr.sin_addr.s_addr = remote->sin_addr.s_addr;
1551237263Snp	child_ep->com.remote_addr.sin_len = remote->sin_len;
1552178786Skmacy	child_ep->com.so = child_so;
1553178786Skmacy	child_ep->com.cm_id = NULL;
1554178786Skmacy	child_ep->com.thread = parent_ep->com.thread;
1555178786Skmacy	child_ep->parent_ep = parent_ep;
1556237263Snp
1557294610Snp	free(local, M_SONAME);
1558178786Skmacy	free(remote, M_SONAME);
1559178786Skmacy	get_ep(&parent_ep->com);
1560283291Sjkim	callout_init(&child_ep->timer, 1);
1561178786Skmacy	state_set(&child_ep->com, MPA_REQ_WAIT);
1562178786Skmacy	start_ep_timer(child_ep);
1563178786Skmacy
1564178786Skmacy	/* maybe the request has already been queued up on the socket... */
1565178786Skmacy	process_mpa_request(child_ep);
1566178786Skmacy}
1567178786Skmacy
1568193272Sjhbstatic int
1569178786Skmacyiwch_so_upcall(struct socket *so, void *arg, int waitflag)
1570178786Skmacy{
1571178786Skmacy	struct iwch_ep *ep = arg;
1572178786Skmacy
1573178786Skmacy	CTR6(KTR_IW_CXGB, "%s so %p so state %x ep %p ep state(%d)=%s", __FUNCTION__, so, so->so_state, ep, ep->com.state, states[ep->com.state]);
1574178786Skmacy	mtx_lock(&req_lock);
1575178786Skmacy	if (ep && ep->com.so && !ep->com.entry.tqe_prev) {
1576178786Skmacy		get_ep(&ep->com);
1577178786Skmacy		TAILQ_INSERT_TAIL(&req_list, &ep->com, entry);
1578178786Skmacy		taskqueue_enqueue(iw_cxgb_taskq, &iw_cxgb_task);
1579178786Skmacy	}
1580178786Skmacy	mtx_unlock(&req_lock);
1581193272Sjhb	return (SU_OK);
1582178786Skmacy}
1583178786Skmacy
1584178786Skmacystatic void
1585178786Skmacyprocess_socket_event(struct iwch_ep *ep)
1586178786Skmacy{
1587178786Skmacy	int state = state_read(&ep->com);
1588178786Skmacy	struct socket *so = ep->com.so;
1589178786Skmacy
1590178786Skmacy	CTR6(KTR_IW_CXGB, "%s so %p so state %x ep %p ep state(%d)=%s", __FUNCTION__, so, so->so_state, ep, ep->com.state, states[ep->com.state]);
1591178786Skmacy	if (state == CONNECTING) {
1592178786Skmacy		process_connected(ep);
1593178786Skmacy		return;
1594178786Skmacy	}
1595178786Skmacy
1596178786Skmacy	if (state == LISTEN) {
1597294610Snp		/* socket listening events are handled at IWCM */
1598294610Snp		CTR3(KTR_IW_CXGB, "%s Invalid ep state:%u, ep:%p", __func__,
1599294610Snp			ep->com.state, ep);
1600294610Snp		BUG();
1601178786Skmacy		return;
1602178786Skmacy	}
1603178786Skmacy
1604178786Skmacy	/* connection error */
1605178786Skmacy	if (so->so_error) {
1606178786Skmacy		process_conn_error(ep);
1607178786Skmacy		return;
1608178786Skmacy	}
1609178786Skmacy
1610178786Skmacy	/* peer close */
1611178786Skmacy	if ((so->so_rcv.sb_state & SBS_CANTRCVMORE) && state < CLOSING) {
1612178786Skmacy		process_peer_close(ep);
1613178786Skmacy		return;
1614178786Skmacy	}
1615178786Skmacy
1616178786Skmacy	/* close complete */
1617178786Skmacy	if (so->so_state & (SS_ISDISCONNECTED)) {
1618178786Skmacy		process_close_complete(ep);
1619178786Skmacy		return;
1620178786Skmacy	}
1621178786Skmacy
1622178786Skmacy	/* rx data */
1623178786Skmacy	process_data(ep);
1624178786Skmacy	return;
1625178786Skmacy}
1626178786Skmacy
1627178786Skmacystatic void
1628178786Skmacyprocess_req(void *ctx, int pending)
1629178786Skmacy{
1630178786Skmacy	struct iwch_ep_common *epc;
1631178786Skmacy
1632178786Skmacy	CTR1(KTR_IW_CXGB, "%s enter", __FUNCTION__);
1633178786Skmacy	mtx_lock(&req_lock);
1634178786Skmacy	while (!TAILQ_EMPTY(&req_list)) {
1635178786Skmacy		epc = TAILQ_FIRST(&req_list);
1636178786Skmacy		TAILQ_REMOVE(&req_list, epc, entry);
1637178786Skmacy		epc->entry.tqe_prev = NULL;
1638178786Skmacy		mtx_unlock(&req_lock);
1639178786Skmacy		if (epc->so)
1640178786Skmacy			process_socket_event((struct iwch_ep *)epc);
1641178786Skmacy		put_ep(epc);
1642178786Skmacy		mtx_lock(&req_lock);
1643178786Skmacy	}
1644178786Skmacy	mtx_unlock(&req_lock);
1645178786Skmacy}
1646178786Skmacy
1647178786Skmacyint
1648178786Skmacyiwch_cm_init(void)
1649178786Skmacy{
1650178786Skmacy	TAILQ_INIT(&req_list);
1651178786Skmacy	mtx_init(&req_lock, "iw_cxgb req_list lock", NULL, MTX_DEF);
1652178786Skmacy	iw_cxgb_taskq = taskqueue_create("iw_cxgb_taskq", M_NOWAIT,
1653178786Skmacy		taskqueue_thread_enqueue, &iw_cxgb_taskq);
1654178786Skmacy        if (iw_cxgb_taskq == NULL) {
1655178786Skmacy                printf("failed to allocate iw_cxgb taskqueue\n");
1656178786Skmacy                return (ENOMEM);
1657178786Skmacy        }
1658178786Skmacy        taskqueue_start_threads(&iw_cxgb_taskq, 1, PI_NET, "iw_cxgb taskq");
1659178786Skmacy        TASK_INIT(&iw_cxgb_task, 0, process_req, NULL);
1660237263Snp	return (0);
1661178786Skmacy}
1662178786Skmacy
1663178786Skmacyvoid
1664178786Skmacyiwch_cm_term(void)
1665178786Skmacy{
1666237263Snp
1667178786Skmacy	taskqueue_drain(iw_cxgb_taskq, &iw_cxgb_task);
1668178786Skmacy	taskqueue_free(iw_cxgb_taskq);
1669178786Skmacy}
1670178786Skmacy
1671237263Snpvoid
1672237263Snpiwch_cm_init_cpl(struct adapter *sc)
1673237263Snp{
1674237263Snp
1675237263Snp	t3_register_cpl_handler(sc, CPL_RDMA_TERMINATE, terminate);
1676237263Snp	t3_register_cpl_handler(sc, CPL_RDMA_EC_STATUS, ec_status);
1677237263Snp}
1678237263Snp
1679237263Snpvoid
1680237263Snpiwch_cm_term_cpl(struct adapter *sc)
1681237263Snp{
1682237263Snp
1683237263Snp	t3_register_cpl_handler(sc, CPL_RDMA_TERMINATE, NULL);
1684237263Snp	t3_register_cpl_handler(sc, CPL_RDMA_EC_STATUS, NULL);
1685237263Snp}
1686237263Snp#endif
1687