]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/cxgbe/tom/t4_connect.c
- Updated TOE support in the kernel.
[FreeBSD/FreeBSD.git] / sys / dev / cxgbe / tom / t4_connect.c
1 /*-
2  * Copyright (c) 2012 Chelsio Communications, Inc.
3  * All rights reserved.
4  * Written by: Navdeep Parhar <np@FreeBSD.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include "opt_inet.h"
32
33 #ifdef TCP_OFFLOAD
34 #include <sys/param.h>
35 #include <sys/types.h>
36 #include <sys/kernel.h>
37 #include <sys/ktr.h>
38 #include <sys/module.h>
39 #include <sys/protosw.h>
40 #include <sys/domain.h>
41 #include <sys/socket.h>
42 #include <sys/socketvar.h>
43 #include <net/ethernet.h>
44 #include <net/if.h>
45 #include <net/if_types.h>
46 #include <net/if_vlan_var.h>
47 #include <net/route.h>
48 #include <netinet/in.h>
49 #include <netinet/in_pcb.h>
50 #include <netinet/ip.h>
51 #include <netinet/tcp_var.h>
52 #define TCPSTATES
53 #include <netinet/tcp_fsm.h>
54 #include <netinet/toecore.h>
55
56 #include "common/common.h"
57 #include "common/t4_msg.h"
58 #include "common/t4_regs.h"
59 #include "tom/t4_tom_l2t.h"
60 #include "tom/t4_tom.h"
61
62 /* atid services */
63 static int alloc_atid(struct adapter *, void *);
64 static void *lookup_atid(struct adapter *, int);
65 static void free_atid(struct adapter *, int);
66
67 static int
68 alloc_atid(struct adapter *sc, void *ctx)
69 {
70         struct tid_info *t = &sc->tids;
71         int atid = -1;
72
73         mtx_lock(&t->atid_lock);
74         if (t->afree) {
75                 union aopen_entry *p = t->afree;
76
77                 atid = p - t->atid_tab;
78                 t->afree = p->next;
79                 p->data = ctx;
80                 t->atids_in_use++;
81         }
82         mtx_unlock(&t->atid_lock);
83         return (atid);
84 }
85
86 static void *
87 lookup_atid(struct adapter *sc, int atid)
88 {
89         struct tid_info *t = &sc->tids;
90
91         return (t->atid_tab[atid].data);
92 }
93
94 static void
95 free_atid(struct adapter *sc, int atid)
96 {
97         struct tid_info *t = &sc->tids;
98         union aopen_entry *p = &t->atid_tab[atid];
99
100         mtx_lock(&t->atid_lock);
101         p->next = t->afree;
102         t->afree = p;
103         t->atids_in_use--;
104         mtx_unlock(&t->atid_lock);
105 }
106
107 /*
108  * Active open failed.
109  */
110 static int
111 do_act_establish(struct sge_iq *iq, const struct rss_header *rss,
112     struct mbuf *m)
113 {
114         struct adapter *sc = iq->adapter;
115         const struct cpl_act_establish *cpl = (const void *)(rss + 1);
116         unsigned int tid = GET_TID(cpl);
117         unsigned int atid = G_TID_TID(ntohl(cpl->tos_atid));
118         struct toepcb *toep = lookup_atid(sc, atid);
119         struct inpcb *inp = toep->inp;
120
121         KASSERT(m == NULL, ("%s: wasn't expecting payload", __func__));
122         KASSERT(toep->tid == atid, ("%s: toep tid/atid mismatch", __func__));
123
124         CTR3(KTR_CXGBE, "%s: atid %u, tid %u", __func__, atid, tid);
125         free_atid(sc, atid);
126
127         INP_WLOCK(inp);
128         toep->tid = tid;
129         insert_tid(sc, tid, toep);
130         if (inp->inp_flags & INP_DROPPED) {
131
132                 /* socket closed by the kernel before hw told us it connected */
133
134                 send_flowc_wr(toep, NULL);
135                 send_reset(sc, toep, be32toh(cpl->snd_isn));
136                 goto done;
137         }
138
139         make_established(toep, cpl->snd_isn, cpl->rcv_isn, cpl->tcp_opt);
140 done:
141         INP_WUNLOCK(inp);
142         return (0);
143 }
144
145 static inline int
146 act_open_has_tid(unsigned int status)
147 {
148
149         return (status != CPL_ERR_TCAM_FULL &&
150             status != CPL_ERR_TCAM_PARITY &&
151             status != CPL_ERR_CONN_EXIST &&
152             status != CPL_ERR_ARP_MISS);
153 }
154
155 /*
156  * Convert an ACT_OPEN_RPL status to an errno.
157  */
158 static inline int
159 act_open_rpl_status_to_errno(int status)
160 {
161
162         switch (status) {
163         case CPL_ERR_CONN_RESET:
164                 return (ECONNREFUSED);
165         case CPL_ERR_ARP_MISS:
166                 return (EHOSTUNREACH);
167         case CPL_ERR_CONN_TIMEDOUT:
168                 return (ETIMEDOUT);
169         case CPL_ERR_TCAM_FULL:
170                 return (ENOMEM);
171         case CPL_ERR_CONN_EXIST:
172                 log(LOG_ERR, "ACTIVE_OPEN_RPL: 4-tuple in use\n");
173                 return (EADDRINUSE);
174         default:
175                 return (EIO);
176         }
177 }
178
179 static int
180 do_act_open_rpl(struct sge_iq *iq, const struct rss_header *rss,
181     struct mbuf *m)
182 {
183         struct adapter *sc = iq->adapter;
184         const struct cpl_act_open_rpl *cpl = (const void *)(rss + 1);
185         unsigned int atid = G_TID_TID(G_AOPEN_ATID(be32toh(cpl->atid_status)));
186         unsigned int status = G_AOPEN_STATUS(be32toh(cpl->atid_status));
187         struct toepcb *toep = lookup_atid(sc, atid);
188         struct inpcb *inp = toep->inp;
189         struct tcpcb *tp = intotcpcb(inp);
190         struct toedev *tod = &toep->td->tod;
191
192         KASSERT(m == NULL, ("%s: wasn't expecting payload", __func__));
193         KASSERT(toep->tid == atid, ("%s: toep tid/atid mismatch", __func__));
194
195         CTR3(KTR_CXGBE, "%s: atid %u, status %u ", __func__, atid, status);
196
197         /* Ignore negative advice */
198         if (status == CPL_ERR_RTX_NEG_ADVICE)
199                 return (0);
200
201         free_atid(sc, atid);
202         toep->tid = -1;
203
204         if (status && act_open_has_tid(status))
205                 release_tid(sc, GET_TID(cpl), toep->ctrlq);
206
207         if (status == CPL_ERR_TCAM_FULL) {
208                 INP_WLOCK(inp);
209                 toe_connect_failed(tod, tp, EAGAIN);
210                 final_cpl_received(toep);       /* unlocks inp */
211         } else {
212                 INP_INFO_WLOCK(&V_tcbinfo);
213                 INP_WLOCK(inp);
214                 toe_connect_failed(tod, tp, act_open_rpl_status_to_errno(status));
215                 final_cpl_received(toep);       /* unlocks inp */
216                 INP_INFO_WUNLOCK(&V_tcbinfo);
217         }
218
219         return (0);
220 }
221
222 /*
223  * Options2 for active open.
224  */
225 static uint32_t
226 calc_opt2a(struct socket *so)
227 {
228         struct tcpcb *tp = so_sototcpcb(so);
229         struct toepcb *toep = tp->t_toe;
230         struct port_info *pi = toep->port;
231         struct adapter *sc = pi->adapter;
232         uint32_t opt2 = 0;
233
234         if (tp->t_flags & TF_SACK_PERMIT)
235                 opt2 |= F_SACK_EN;
236
237         if (tp->t_flags & TF_REQ_TSTMP)
238                 opt2 |= F_TSTAMPS_EN;
239
240         if (tp->t_flags & TF_REQ_SCALE)
241                 opt2 |= F_WND_SCALE_EN;
242
243         if (V_tcp_do_ecn)
244                 opt2 |= F_CCTRL_ECN;
245
246         opt2 |= V_TX_QUEUE(sc->params.tp.tx_modq[pi->tx_chan]);
247         opt2 |= F_RX_COALESCE_VALID | V_RX_COALESCE(M_RX_COALESCE);
248         opt2 |= F_RSS_QUEUE_VALID | V_RSS_QUEUE(toep->ofld_rxq->iq.abs_id);
249
250         return (htobe32(opt2));
251 }
252
253
254 void
255 t4_init_connect_cpl_handlers(struct adapter *sc)
256 {
257
258         t4_register_cpl_handler(sc, CPL_ACT_ESTABLISH, do_act_establish);
259         t4_register_cpl_handler(sc, CPL_ACT_OPEN_RPL, do_act_open_rpl);
260 }
261
262 /*
263  * active open (soconnect).
264  *
265  * State of affairs on entry:
266  * soisconnecting (so_state |= SS_ISCONNECTING)
267  * tcbinfo not locked (This has changed - used to be WLOCKed)
268  * inp WLOCKed
269  * tp->t_state = TCPS_SYN_SENT
270  * rtalloc1, RT_UNLOCK on rt.
271  */
272 int
273 t4_connect(struct toedev *tod, struct socket *so, struct rtentry *rt,
274     struct sockaddr *nam)
275 {
276         struct adapter *sc = tod->tod_softc;
277         struct toepcb *toep = NULL;
278         struct wrqe *wr = NULL;
279         struct cpl_act_open_req *cpl;
280         struct l2t_entry *e = NULL;
281         struct ifnet *rt_ifp = rt->rt_ifp;
282         struct port_info *pi;
283         int atid = -1, mtu_idx, rscale, qid_atid, rc = ENOMEM;
284         struct inpcb *inp = sotoinpcb(so);
285         struct tcpcb *tp = intotcpcb(inp);
286
287         INP_WLOCK_ASSERT(inp);
288
289         if (nam->sa_family != AF_INET)
290                 CXGBE_UNIMPLEMENTED("IPv6 connect");
291
292         if (rt_ifp->if_type == IFT_ETHER)
293                 pi = rt_ifp->if_softc;
294         else if (rt_ifp->if_type == IFT_L2VLAN) {
295                 struct ifnet *ifp = VLAN_COOKIE(rt_ifp);
296
297                 pi = ifp->if_softc;
298         } else if (rt_ifp->if_type == IFT_IEEE8023ADLAG)
299                 return (ENOSYS);        /* XXX: implement lagg support */
300         else
301                 return (ENOTSUP);
302
303         toep = alloc_toepcb(pi, -1, -1, M_NOWAIT);
304         if (toep == NULL)
305                 goto failed;
306
307         atid = alloc_atid(sc, toep);
308         if (atid < 0)
309                 goto failed;
310
311         e = t4_l2t_get(pi, rt_ifp,
312             rt->rt_flags & RTF_GATEWAY ? rt->rt_gateway : nam);
313         if (e == NULL)
314                 goto failed;
315
316         wr = alloc_wrqe(sizeof(*cpl), toep->ctrlq);
317         if (wr == NULL)
318                 goto failed;
319         cpl = wrtod(wr);
320
321         toep->tid = atid;
322         toep->l2te = e;
323         toep->ulp_mode = ULP_MODE_NONE;
324         SOCKBUF_LOCK(&so->so_rcv);
325         /* opt0 rcv_bufsiz initially, assumes its normal meaning later */
326         toep->rx_credits = min(select_rcv_wnd(so) >> 10, M_RCV_BUFSIZ);
327         SOCKBUF_UNLOCK(&so->so_rcv);
328
329         offload_socket(so, toep);
330
331         /*
332          * The kernel sets request_r_scale based on sb_max whereas we need to
333          * take hardware's MAX_RCV_WND into account too.  This is normally a
334          * no-op as MAX_RCV_WND is much larger than the default sb_max.
335          */
336         if (tp->t_flags & TF_REQ_SCALE)
337                 rscale = tp->request_r_scale = select_rcv_wscale();
338         else
339                 rscale = 0;
340         mtu_idx = find_best_mtu_idx(sc, &inp->inp_inc, 0);
341         qid_atid = (toep->ofld_rxq->iq.abs_id << 14) | atid;
342
343         INIT_TP_WR(cpl, 0);
344         OPCODE_TID(cpl) = htobe32(MK_OPCODE_TID(CPL_ACT_OPEN_REQ, qid_atid));
345         inp_4tuple_get(inp, &cpl->local_ip, &cpl->local_port, &cpl->peer_ip,
346             &cpl->peer_port);
347         cpl->opt0 = calc_opt0(so, pi, e, mtu_idx, rscale, toep->rx_credits,
348             toep->ulp_mode);
349         cpl->params = select_ntuple(pi, e, sc->filter_mode);
350         cpl->opt2 = calc_opt2a(so);
351
352         CTR5(KTR_CXGBE, "%s: atid %u (%s), toep %p, inp %p", __func__,
353             toep->tid, tcpstates[tp->t_state], toep, inp);
354
355         rc = t4_l2t_send(sc, wr, e);
356         if (rc == 0) {
357                 toepcb_set_flag(toep, TPF_CPL_PENDING);
358                 return (0);
359         }
360
361         undo_offload_socket(so);
362 failed:
363         CTR5(KTR_CXGBE, "%s: FAILED, atid %d, toep %p, l2te %p, wr %p",
364             __func__, atid, toep, e, wr);
365
366         if (e)
367                 t4_l2t_release(e);
368         if (wr)
369                 free_wrqe(wr);
370         if (atid >= 0)
371                 free_atid(sc, atid);
372         if (toep)
373                 free_toepcb(toep);
374
375         return (rc);
376 }
377 #endif