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