xref: /freebsd/sys/dev/cxgbe/cxgbei/icl_cxgbei.c (revision eb9da1ada8b6b2c74378a5c17029ec5a7fb199e6)
1 /*-
2  * Copyright (c) 2012 The FreeBSD Foundation
3  * Copyright (c) 2015 Chelsio Communications, Inc.
4  * All rights reserved.
5  *
6  * This software was developed by Edward Tomasz Napierala under sponsorship
7  * from the FreeBSD Foundation.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  */
31 
32 /*
33  * cxgbei implementation of iSCSI Common Layer kobj(9) interface.
34  */
35 
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
38 
39 #include "opt_inet.h"
40 #include "opt_inet6.h"
41 
42 #ifdef TCP_OFFLOAD
43 #include <sys/param.h>
44 #include <sys/capsicum.h>
45 #include <sys/condvar.h>
46 #include <sys/conf.h>
47 #include <sys/file.h>
48 #include <sys/kernel.h>
49 #include <sys/kthread.h>
50 #include <sys/lock.h>
51 #include <sys/mbuf.h>
52 #include <sys/mutex.h>
53 #include <sys/module.h>
54 #include <sys/protosw.h>
55 #include <sys/socket.h>
56 #include <sys/socketvar.h>
57 #include <sys/sysctl.h>
58 #include <sys/systm.h>
59 #include <sys/sx.h>
60 #include <sys/uio.h>
61 #include <machine/bus.h>
62 #include <vm/uma.h>
63 #include <netinet/in.h>
64 #include <netinet/in_pcb.h>
65 #include <netinet/tcp.h>
66 #include <netinet/tcp_var.h>
67 #include <netinet/toecore.h>
68 
69 #include <dev/iscsi/icl.h>
70 #include <dev/iscsi/iscsi_proto.h>
71 #include <icl_conn_if.h>
72 
73 #include "common/common.h"
74 #include "common/t4_tcb.h"
75 #include "tom/t4_tom.h"
76 #include "cxgbei.h"
77 
78 SYSCTL_NODE(_kern_icl, OID_AUTO, cxgbei, CTLFLAG_RD, 0, "Chelsio iSCSI offload");
79 static int coalesce = 1;
80 SYSCTL_INT(_kern_icl_cxgbei, OID_AUTO, coalesce, CTLFLAG_RWTUN,
81 	&coalesce, 0, "Try to coalesce PDUs before sending");
82 static int partial_receive_len = 128 * 1024;
83 SYSCTL_INT(_kern_icl_cxgbei, OID_AUTO, partial_receive_len, CTLFLAG_RWTUN,
84     &partial_receive_len, 0, "Minimum read size for partially received "
85     "data segment");
86 static int sendspace = 1048576;
87 SYSCTL_INT(_kern_icl_cxgbei, OID_AUTO, sendspace, CTLFLAG_RWTUN,
88     &sendspace, 0, "Default send socket buffer size");
89 static int recvspace = 1048576;
90 SYSCTL_INT(_kern_icl_cxgbei, OID_AUTO, recvspace, CTLFLAG_RWTUN,
91     &recvspace, 0, "Default receive socket buffer size");
92 
93 static uma_zone_t icl_transfer_zone;
94 
95 static volatile u_int icl_cxgbei_ncons;
96 
97 #define ICL_CONN_LOCK(X)		mtx_lock(X->ic_lock)
98 #define ICL_CONN_UNLOCK(X)		mtx_unlock(X->ic_lock)
99 #define ICL_CONN_LOCK_ASSERT(X)		mtx_assert(X->ic_lock, MA_OWNED)
100 #define ICL_CONN_LOCK_ASSERT_NOT(X)	mtx_assert(X->ic_lock, MA_NOTOWNED)
101 
102 struct icl_pdu *icl_cxgbei_new_pdu(int);
103 void icl_cxgbei_new_pdu_set_conn(struct icl_pdu *, struct icl_conn *);
104 
105 static icl_conn_new_pdu_t	icl_cxgbei_conn_new_pdu;
106 icl_conn_pdu_free_t	icl_cxgbei_conn_pdu_free;
107 static icl_conn_pdu_data_segment_length_t
108 				    icl_cxgbei_conn_pdu_data_segment_length;
109 static icl_conn_pdu_append_data_t	icl_cxgbei_conn_pdu_append_data;
110 static icl_conn_pdu_get_data_t	icl_cxgbei_conn_pdu_get_data;
111 static icl_conn_pdu_queue_t	icl_cxgbei_conn_pdu_queue;
112 static icl_conn_handoff_t	icl_cxgbei_conn_handoff;
113 static icl_conn_free_t		icl_cxgbei_conn_free;
114 static icl_conn_close_t		icl_cxgbei_conn_close;
115 static icl_conn_task_setup_t	icl_cxgbei_conn_task_setup;
116 static icl_conn_task_done_t	icl_cxgbei_conn_task_done;
117 static icl_conn_transfer_setup_t	icl_cxgbei_conn_transfer_setup;
118 static icl_conn_transfer_done_t	icl_cxgbei_conn_transfer_done;
119 
120 static kobj_method_t icl_cxgbei_methods[] = {
121 	KOBJMETHOD(icl_conn_new_pdu, icl_cxgbei_conn_new_pdu),
122 	KOBJMETHOD(icl_conn_pdu_free, icl_cxgbei_conn_pdu_free),
123 	KOBJMETHOD(icl_conn_pdu_data_segment_length,
124 	    icl_cxgbei_conn_pdu_data_segment_length),
125 	KOBJMETHOD(icl_conn_pdu_append_data, icl_cxgbei_conn_pdu_append_data),
126 	KOBJMETHOD(icl_conn_pdu_get_data, icl_cxgbei_conn_pdu_get_data),
127 	KOBJMETHOD(icl_conn_pdu_queue, icl_cxgbei_conn_pdu_queue),
128 	KOBJMETHOD(icl_conn_handoff, icl_cxgbei_conn_handoff),
129 	KOBJMETHOD(icl_conn_free, icl_cxgbei_conn_free),
130 	KOBJMETHOD(icl_conn_close, icl_cxgbei_conn_close),
131 	KOBJMETHOD(icl_conn_task_setup, icl_cxgbei_conn_task_setup),
132 	KOBJMETHOD(icl_conn_task_done, icl_cxgbei_conn_task_done),
133 	KOBJMETHOD(icl_conn_transfer_setup, icl_cxgbei_conn_transfer_setup),
134 	KOBJMETHOD(icl_conn_transfer_done, icl_cxgbei_conn_transfer_done),
135 	{ 0, 0 }
136 };
137 
138 DEFINE_CLASS(icl_cxgbei, icl_cxgbei_methods, sizeof(struct icl_cxgbei_conn));
139 
140 #if 0
141 /*
142  * Subtract another 256 for AHS from MAX_DSL if AHS could be used.
143  */
144 #define CXGBEI_MAX_PDU 16224
145 #define CXGBEI_MAX_DSL (CXGBEI_MAX_PDU - sizeof(struct iscsi_bhs) - 8)
146 #endif
147 #define CXGBEI_MAX_DSL 8192
148 #define CXGBEI_MAX_PDU (CXGBEI_MAX_DSL + sizeof(struct iscsi_bhs) + 8)
149 
150 void
151 icl_cxgbei_conn_pdu_free(struct icl_conn *ic, struct icl_pdu *ip)
152 {
153 #ifdef INVARIANTS
154 	struct icl_cxgbei_pdu *icp = ip_to_icp(ip);
155 #endif
156 
157 	MPASS(icp->icp_signature == CXGBEI_PDU_SIGNATURE);
158 	MPASS(ic == ip->ip_conn);
159 	MPASS(ip->ip_bhs_mbuf != NULL);
160 
161 	m_freem(ip->ip_ahs_mbuf);
162 	m_freem(ip->ip_data_mbuf);
163 	m_freem(ip->ip_bhs_mbuf);	/* storage for icl_cxgbei_pdu itself */
164 
165 #ifdef DIAGNOSTIC
166 	if (__predict_true(ic != NULL))
167 		refcount_release(&ic->ic_outstanding_pdus);
168 #endif
169 }
170 
171 struct icl_pdu *
172 icl_cxgbei_new_pdu(int flags)
173 {
174 	struct icl_cxgbei_pdu *icp;
175 	struct icl_pdu *ip;
176 	struct mbuf *m;
177 	uintptr_t a;
178 
179 	m = m_gethdr(flags, MT_DATA);
180 	if (__predict_false(m == NULL))
181 		return (NULL);
182 
183 	a = roundup2(mtod(m, uintptr_t), _Alignof(struct icl_cxgbei_pdu));
184 	icp = (struct icl_cxgbei_pdu *)a;
185 	bzero(icp, sizeof(*icp));
186 
187 	icp->icp_signature = CXGBEI_PDU_SIGNATURE;
188 	ip = &icp->ip;
189 	ip->ip_bhs_mbuf = m;
190 
191 	a = roundup2((uintptr_t)(icp + 1), _Alignof(struct iscsi_bhs *));
192 	ip->ip_bhs = (struct iscsi_bhs *)a;
193 #ifdef INVARIANTS
194 	/* Everything must fit entirely in the mbuf. */
195 	a = (uintptr_t)(ip->ip_bhs + 1);
196 	MPASS(a <= (uintptr_t)m + MSIZE);
197 #endif
198 	bzero(ip->ip_bhs, sizeof(*ip->ip_bhs));
199 
200 	m->m_data = (void *)ip->ip_bhs;
201 	m->m_len = sizeof(struct iscsi_bhs);
202 	m->m_pkthdr.len = m->m_len;
203 
204 	return (ip);
205 }
206 
207 void
208 icl_cxgbei_new_pdu_set_conn(struct icl_pdu *ip, struct icl_conn *ic)
209 {
210 
211 	ip->ip_conn = ic;
212 #ifdef DIAGNOSTIC
213 	refcount_acquire(&ic->ic_outstanding_pdus);
214 #endif
215 }
216 
217 /*
218  * Allocate icl_pdu with empty BHS to fill up by the caller.
219  */
220 static struct icl_pdu *
221 icl_cxgbei_conn_new_pdu(struct icl_conn *ic, int flags)
222 {
223 	struct icl_pdu *ip;
224 
225 	ip = icl_cxgbei_new_pdu(flags);
226 	if (__predict_false(ip == NULL))
227 		return (NULL);
228 	icl_cxgbei_new_pdu_set_conn(ip, ic);
229 
230 	return (ip);
231 }
232 
233 static size_t
234 icl_pdu_data_segment_length(const struct icl_pdu *request)
235 {
236 	uint32_t len = 0;
237 
238 	len += request->ip_bhs->bhs_data_segment_len[0];
239 	len <<= 8;
240 	len += request->ip_bhs->bhs_data_segment_len[1];
241 	len <<= 8;
242 	len += request->ip_bhs->bhs_data_segment_len[2];
243 
244 	return (len);
245 }
246 
247 size_t
248 icl_cxgbei_conn_pdu_data_segment_length(struct icl_conn *ic,
249     const struct icl_pdu *request)
250 {
251 
252 	return (icl_pdu_data_segment_length(request));
253 }
254 
255 static uint32_t
256 icl_conn_build_tasktag(struct icl_conn *ic, uint32_t tag)
257 {
258 	return tag;
259 }
260 
261 static struct mbuf *
262 finalize_pdu(struct icl_cxgbei_conn *icc, struct icl_cxgbei_pdu *icp)
263 {
264 	struct icl_pdu *ip = &icp->ip;
265 	uint8_t ulp_submode, padding;
266 	struct mbuf *m, *last;
267 	struct iscsi_bhs *bhs;
268 
269 	/*
270 	 * Fix up the data segment mbuf first.
271 	 */
272 	m = ip->ip_data_mbuf;
273 	ulp_submode = icc->ulp_submode;
274 	if (m) {
275 		last = m_last(m);
276 
277 		/*
278 		 * Round up the data segment to a 4B boundary.  Pad with 0 if
279 		 * necessary.  There will definitely be room in the mbuf.
280 		 */
281 		padding = roundup2(ip->ip_data_len, 4) - ip->ip_data_len;
282 		if (padding) {
283 			bzero(mtod(last, uint8_t *) + last->m_len, padding);
284 			last->m_len += padding;
285 		}
286 	} else {
287 		MPASS(ip->ip_data_len == 0);
288 		ulp_submode &= ~ULP_CRC_DATA;
289 		padding = 0;
290 	}
291 
292 	/*
293 	 * Now the header mbuf that has the BHS.
294 	 */
295 	m = ip->ip_bhs_mbuf;
296 	MPASS(m->m_pkthdr.len == sizeof(struct iscsi_bhs));
297 	MPASS(m->m_len == sizeof(struct iscsi_bhs));
298 
299 	bhs = ip->ip_bhs;
300 	bhs->bhs_data_segment_len[2] = ip->ip_data_len;
301 	bhs->bhs_data_segment_len[1] = ip->ip_data_len >> 8;
302 	bhs->bhs_data_segment_len[0] = ip->ip_data_len >> 16;
303 
304 	/* "Convert" PDU to mbuf chain.  Do not use icp/ip after this. */
305 	m->m_pkthdr.len = sizeof(struct iscsi_bhs) + ip->ip_data_len + padding;
306 	m->m_next = ip->ip_data_mbuf;
307 	set_mbuf_ulp_submode(m, ulp_submode);
308 #ifdef INVARIANTS
309 	bzero(icp, sizeof(*icp));
310 #endif
311 #ifdef DIAGNOSTIC
312 	refcount_release(&icc->ic.ic_outstanding_pdus);
313 #endif
314 
315 	return (m);
316 }
317 
318 int
319 icl_cxgbei_conn_pdu_append_data(struct icl_conn *ic, struct icl_pdu *ip,
320     const void *addr, size_t len, int flags)
321 {
322 	struct mbuf *m;
323 #ifdef INVARIANTS
324 	struct icl_cxgbei_pdu *icp = ip_to_icp(ip);
325 #endif
326 
327 	MPASS(icp->icp_signature == CXGBEI_PDU_SIGNATURE);
328 	MPASS(ic == ip->ip_conn);
329 	KASSERT(len > 0, ("%s: len is %jd", __func__, (intmax_t)len));
330 
331 	m = ip->ip_data_mbuf;
332 	if (m == NULL) {
333 		m = m_getjcl(M_NOWAIT, MT_DATA, 0, MJUM16BYTES);
334 		if (__predict_false(m == NULL))
335 			return (ENOMEM);
336 
337 		ip->ip_data_mbuf = m;
338 	}
339 
340 	if (__predict_true(m_append(m, len, addr) != 0)) {
341 		ip->ip_data_len += len;
342 		MPASS(ip->ip_data_len <= CXGBEI_MAX_DSL);
343 		return (0);
344 	} else {
345 	    	if (flags & M_WAITOK) {
346 			CXGBE_UNIMPLEMENTED("fail safe append");
347 		}
348 		ip->ip_data_len = m_length(m, NULL);
349 		return (1);
350 	}
351 }
352 
353 void
354 icl_cxgbei_conn_pdu_get_data(struct icl_conn *ic, struct icl_pdu *ip,
355     size_t off, void *addr, size_t len)
356 {
357 	struct icl_cxgbei_pdu *icp = ip_to_icp(ip);
358 
359 	if (icp->pdu_flags & SBUF_ULP_FLAG_DATA_DDPED)
360 		return; /* data is DDP'ed, no need to copy */
361 	m_copydata(ip->ip_data_mbuf, off, len, addr);
362 }
363 
364 void
365 icl_cxgbei_conn_pdu_queue(struct icl_conn *ic, struct icl_pdu *ip)
366 {
367 	struct icl_cxgbei_conn *icc = ic_to_icc(ic);
368 	struct icl_cxgbei_pdu *icp = ip_to_icp(ip);
369 	struct socket *so = ic->ic_socket;
370 	struct toepcb *toep = icc->toep;
371 	struct inpcb *inp;
372 	struct mbuf *m;
373 
374 	MPASS(ic == ip->ip_conn);
375 	MPASS(ip->ip_bhs_mbuf != NULL);
376 	/* The kernel doesn't generate PDUs with AHS. */
377 	MPASS(ip->ip_ahs_mbuf == NULL && ip->ip_ahs_len == 0);
378 
379 	ICL_CONN_LOCK_ASSERT(ic);
380 	/* NOTE: sowriteable without so_snd lock is a mostly harmless race. */
381 	if (ic->ic_disconnecting || so == NULL || !sowriteable(so)) {
382 		icl_cxgbei_conn_pdu_free(ic, ip);
383 		return;
384 	}
385 
386 	m = finalize_pdu(icc, icp);
387 	M_ASSERTPKTHDR(m);
388 	MPASS((m->m_pkthdr.len & 3) == 0);
389 	MPASS(m->m_pkthdr.len + 8 <= CXGBEI_MAX_PDU);
390 
391 	/*
392 	 * Do not get inp from toep->inp as the toepcb might have detached
393 	 * already.
394 	 */
395 	inp = sotoinpcb(so);
396 	INP_WLOCK(inp);
397 	if (__predict_false(inp->inp_flags & (INP_DROPPED | INP_TIMEWAIT)) ||
398 	    __predict_false((toep->flags & TPF_ATTACHED) == 0))
399 		m_freem(m);
400 	else {
401 		mbufq_enqueue(&toep->ulp_pduq, m);
402 		t4_push_pdus(icc->sc, toep, 0);
403 	}
404 	INP_WUNLOCK(inp);
405 }
406 
407 static struct icl_conn *
408 icl_cxgbei_new_conn(const char *name, struct mtx *lock)
409 {
410 	struct icl_cxgbei_conn *icc;
411 	struct icl_conn *ic;
412 
413 	refcount_acquire(&icl_cxgbei_ncons);
414 
415 	icc = (struct icl_cxgbei_conn *)kobj_create(&icl_cxgbei_class, M_CXGBE,
416 	    M_WAITOK | M_ZERO);
417 	icc->icc_signature = CXGBEI_CONN_SIGNATURE;
418 	STAILQ_INIT(&icc->rcvd_pdus);
419 
420 	ic = &icc->ic;
421 	ic->ic_lock = lock;
422 
423 	/* XXXNP: review.  Most of these icl_conn fields aren't really used */
424 	STAILQ_INIT(&ic->ic_to_send);
425 	cv_init(&ic->ic_send_cv, "icl_cxgbei_tx");
426 	cv_init(&ic->ic_receive_cv, "icl_cxgbei_rx");
427 #ifdef DIAGNOSTIC
428 	refcount_init(&ic->ic_outstanding_pdus, 0);
429 #endif
430 	ic->ic_max_data_segment_length = CXGBEI_MAX_DSL;
431 	ic->ic_name = name;
432 	ic->ic_offload = "cxgbei";
433 	ic->ic_unmapped = false;
434 
435 	CTR2(KTR_CXGBE, "%s: icc %p", __func__, icc);
436 
437 	return (ic);
438 }
439 
440 void
441 icl_cxgbei_conn_free(struct icl_conn *ic)
442 {
443 	struct icl_cxgbei_conn *icc = ic_to_icc(ic);
444 
445 	MPASS(icc->icc_signature == CXGBEI_CONN_SIGNATURE);
446 
447 	CTR2(KTR_CXGBE, "%s: icc %p", __func__, icc);
448 
449 	cv_destroy(&ic->ic_send_cv);
450 	cv_destroy(&ic->ic_receive_cv);
451 
452 	kobj_delete((struct kobj *)icc, M_CXGBE);
453 	refcount_release(&icl_cxgbei_ncons);
454 }
455 
456 static int
457 icl_cxgbei_setsockopt(struct icl_conn *ic, struct socket *so)
458 {
459 	size_t minspace;
460 	struct sockopt opt;
461 	int error, one = 1;
462 
463 	/*
464 	 * For sendspace, this is required because the current code cannot
465 	 * send a PDU in pieces; thus, the minimum buffer size is equal
466 	 * to the maximum PDU size.  "+4" is to account for possible padding.
467 	 *
468 	 * What we should actually do here is to use autoscaling, but set
469 	 * some minimal buffer size to "minspace".  I don't know a way to do
470 	 * that, though.
471 	 */
472 	minspace = sizeof(struct iscsi_bhs) + ic->ic_max_data_segment_length +
473 	    ISCSI_HEADER_DIGEST_SIZE + ISCSI_DATA_DIGEST_SIZE + 4;
474 	if (sendspace < minspace)
475 		sendspace = minspace;
476 	if (recvspace < minspace)
477 		recvspace = minspace;
478 
479 	error = soreserve(so, sendspace, recvspace);
480 	if (error != 0) {
481 		icl_cxgbei_conn_close(ic);
482 		return (error);
483 	}
484 	SOCKBUF_LOCK(&so->so_snd);
485 	so->so_snd.sb_flags |= SB_AUTOSIZE;
486 	SOCKBUF_UNLOCK(&so->so_snd);
487 	SOCKBUF_LOCK(&so->so_rcv);
488 	so->so_rcv.sb_flags |= SB_AUTOSIZE;
489 	SOCKBUF_UNLOCK(&so->so_rcv);
490 
491 	/*
492 	 * Disable Nagle.
493 	 */
494 	bzero(&opt, sizeof(opt));
495 	opt.sopt_dir = SOPT_SET;
496 	opt.sopt_level = IPPROTO_TCP;
497 	opt.sopt_name = TCP_NODELAY;
498 	opt.sopt_val = &one;
499 	opt.sopt_valsize = sizeof(one);
500 	error = sosetopt(so, &opt);
501 	if (error != 0) {
502 		icl_cxgbei_conn_close(ic);
503 		return (error);
504 	}
505 
506 	return (0);
507 }
508 
509 /*
510  * Request/response structure used to find out the adapter offloading a socket.
511  */
512 struct find_ofld_adapter_rr {
513 	struct socket *so;
514 	struct adapter *sc;	/* result */
515 };
516 
517 static void
518 find_offload_adapter(struct adapter *sc, void *arg)
519 {
520 	struct find_ofld_adapter_rr *fa = arg;
521 	struct socket *so = fa->so;
522 	struct tom_data *td = sc->tom_softc;
523 	struct tcpcb *tp;
524 	struct inpcb *inp;
525 
526 	/* Non-TCP were filtered out earlier. */
527 	MPASS(so->so_proto->pr_protocol == IPPROTO_TCP);
528 
529 	if (fa->sc != NULL)
530 		return;	/* Found already. */
531 
532 	if (td == NULL)
533 		return;	/* TOE not enabled on this adapter. */
534 
535 	inp = sotoinpcb(so);
536 	INP_WLOCK(inp);
537 	if ((inp->inp_flags & (INP_DROPPED | INP_TIMEWAIT)) == 0) {
538 		tp = intotcpcb(inp);
539 		if (tp->t_flags & TF_TOE && tp->tod == &td->tod)
540 			fa->sc = sc;	/* Found. */
541 	}
542 	INP_WUNLOCK(inp);
543 }
544 
545 /* XXXNP: move this to t4_tom. */
546 static void
547 send_iscsi_flowc_wr(struct adapter *sc, struct toepcb *toep, int maxlen)
548 {
549 	struct wrqe *wr;
550 	struct fw_flowc_wr *flowc;
551 	const u_int nparams = 1;
552 	u_int flowclen;
553 	struct ofld_tx_sdesc *txsd = &toep->txsd[toep->txsd_pidx];
554 
555 	flowclen = sizeof(*flowc) + nparams * sizeof(struct fw_flowc_mnemval);
556 
557 	wr = alloc_wrqe(roundup2(flowclen, 16), toep->ofld_txq);
558 	if (wr == NULL) {
559 		/* XXX */
560 		panic("%s: allocation failure.", __func__);
561 	}
562 	flowc = wrtod(wr);
563 	memset(flowc, 0, wr->wr_len);
564 
565 	flowc->op_to_nparams = htobe32(V_FW_WR_OP(FW_FLOWC_WR) |
566 	    V_FW_FLOWC_WR_NPARAMS(nparams));
567 	flowc->flowid_len16 = htonl(V_FW_WR_LEN16(howmany(flowclen, 16)) |
568 	    V_FW_WR_FLOWID(toep->tid));
569 
570 	flowc->mnemval[0].mnemonic = FW_FLOWC_MNEM_TXDATAPLEN_MAX;
571 	flowc->mnemval[0].val = htobe32(maxlen);
572 
573 	txsd->tx_credits = howmany(flowclen, 16);
574 	txsd->plen = 0;
575 	KASSERT(toep->tx_credits >= txsd->tx_credits && toep->txsd_avail > 0,
576 	    ("%s: not enough credits (%d)", __func__, toep->tx_credits));
577 	toep->tx_credits -= txsd->tx_credits;
578 	if (__predict_false(++toep->txsd_pidx == toep->txsd_total))
579 		toep->txsd_pidx = 0;
580 	toep->txsd_avail--;
581 
582         t4_wrq_tx(sc, wr);
583 }
584 
585 static void
586 set_ulp_mode_iscsi(struct adapter *sc, struct toepcb *toep, int hcrc, int dcrc)
587 {
588 	uint64_t val = ULP_MODE_ISCSI;
589 
590 	if (hcrc)
591 		val |= ULP_CRC_HEADER << 4;
592 	if (dcrc)
593 		val |= ULP_CRC_DATA << 4;
594 
595 	CTR4(KTR_CXGBE, "%s: tid %u, ULP_MODE_ISCSI, CRC hdr=%d data=%d",
596 	    __func__, toep->tid, hcrc, dcrc);
597 
598 	t4_set_tcb_field(sc, toep->ctrlq, toep->tid, W_TCB_ULP_TYPE,
599 	    V_TCB_ULP_TYPE(M_TCB_ULP_TYPE) | V_TCB_ULP_RAW(M_TCB_ULP_RAW), val,
600 	    0, 0, toep->ofld_rxq->iq.abs_id);
601 }
602 
603 /*
604  * XXXNP: Who is responsible for cleaning up the socket if this returns with an
605  * error?  Review all error paths.
606  *
607  * XXXNP: What happens to the socket's fd reference if the operation is
608  * successful, and how does that affect the socket's life cycle?
609  */
610 int
611 icl_cxgbei_conn_handoff(struct icl_conn *ic, int fd)
612 {
613 	struct icl_cxgbei_conn *icc = ic_to_icc(ic);
614 	struct find_ofld_adapter_rr fa;
615 	struct file *fp;
616 	struct socket *so;
617 	struct inpcb *inp;
618 	struct tcpcb *tp;
619 	struct toepcb *toep;
620 	cap_rights_t rights;
621 	int error;
622 
623 	MPASS(icc->icc_signature == CXGBEI_CONN_SIGNATURE);
624 	ICL_CONN_LOCK_ASSERT_NOT(ic);
625 
626 	/*
627 	 * Steal the socket from userland.
628 	 */
629 	error = fget(curthread, fd,
630 	    cap_rights_init(&rights, CAP_SOCK_CLIENT), &fp);
631 	if (error != 0)
632 		return (error);
633 	if (fp->f_type != DTYPE_SOCKET) {
634 		fdrop(fp, curthread);
635 		return (EINVAL);
636 	}
637 	so = fp->f_data;
638 	if (so->so_type != SOCK_STREAM ||
639 	    so->so_proto->pr_protocol != IPPROTO_TCP) {
640 		fdrop(fp, curthread);
641 		return (EINVAL);
642 	}
643 
644 	ICL_CONN_LOCK(ic);
645 	if (ic->ic_socket != NULL) {
646 		ICL_CONN_UNLOCK(ic);
647 		fdrop(fp, curthread);
648 		return (EBUSY);
649 	}
650 	ic->ic_disconnecting = false;
651 	ic->ic_socket = so;
652 	fp->f_ops = &badfileops;
653 	fp->f_data = NULL;
654 	fdrop(fp, curthread);
655 	ICL_CONN_UNLOCK(ic);
656 
657 	/* Find the adapter offloading this socket. */
658 	fa.sc = NULL;
659 	fa.so = so;
660 	t4_iterate(find_offload_adapter, &fa);
661 	if (fa.sc == NULL)
662 		return (EINVAL);
663 	icc->sc = fa.sc;
664 
665 	error = icl_cxgbei_setsockopt(ic, so);
666 	if (error)
667 		return (error);
668 
669 	inp = sotoinpcb(so);
670 	INP_WLOCK(inp);
671 	tp = intotcpcb(inp);
672 	if (inp->inp_flags & (INP_DROPPED | INP_TIMEWAIT))
673 		error = EBUSY;
674 	else {
675 		/*
676 		 * socket could not have been "unoffloaded" if here.
677 		 */
678 		MPASS(tp->t_flags & TF_TOE);
679 		MPASS(tp->tod != NULL);
680 		MPASS(tp->t_toe != NULL);
681 		toep = tp->t_toe;
682 		MPASS(toep->vi->pi->adapter == icc->sc);
683 		icc->toep = toep;
684 		icc->cwt = cxgbei_select_worker_thread(icc);
685 		icc->ulp_submode = 0;
686 		if (ic->ic_header_crc32c)
687 			icc->ulp_submode |= ULP_CRC_HEADER;
688 		if (ic->ic_data_crc32c)
689 			icc->ulp_submode |= ULP_CRC_DATA;
690 		so->so_options |= SO_NO_DDP;
691 		toep->ulp_mode = ULP_MODE_ISCSI;
692 		toep->ulpcb = icc;
693 
694 		send_iscsi_flowc_wr(icc->sc, toep, CXGBEI_MAX_PDU);
695 		set_ulp_mode_iscsi(icc->sc, toep, ic->ic_header_crc32c,
696 		    ic->ic_data_crc32c);
697 		error = 0;
698 	}
699 	INP_WUNLOCK(inp);
700 
701 	return (error);
702 }
703 
704 void
705 icl_cxgbei_conn_close(struct icl_conn *ic)
706 {
707 	struct icl_cxgbei_conn *icc = ic_to_icc(ic);
708 	struct icl_pdu *ip;
709 	struct socket *so;
710 	struct sockbuf *sb;
711 	struct inpcb *inp;
712 	struct toepcb *toep = icc->toep;
713 
714 	MPASS(icc->icc_signature == CXGBEI_CONN_SIGNATURE);
715 	ICL_CONN_LOCK_ASSERT_NOT(ic);
716 
717 	ICL_CONN_LOCK(ic);
718 	so = ic->ic_socket;
719 	if (ic->ic_disconnecting || so == NULL) {
720 		CTR4(KTR_CXGBE, "%s: icc %p (disconnecting = %d), so %p",
721 		    __func__, icc, ic->ic_disconnecting, so);
722 		ICL_CONN_UNLOCK(ic);
723 		return;
724 	}
725 	ic->ic_disconnecting = true;
726 
727 	/* These are unused in this driver right now. */
728 	MPASS(STAILQ_EMPTY(&ic->ic_to_send));
729 	MPASS(ic->ic_receive_pdu == NULL);
730 
731 #ifdef DIAGNOSTIC
732 	KASSERT(ic->ic_outstanding_pdus == 0,
733 	    ("destroying session with %d outstanding PDUs",
734 	     ic->ic_outstanding_pdus));
735 #endif
736 	ICL_CONN_UNLOCK(ic);
737 
738 	CTR3(KTR_CXGBE, "%s: tid %d, icc %p", __func__, toep ? toep->tid : -1,
739 	    icc);
740 	inp = sotoinpcb(so);
741 	sb = &so->so_rcv;
742 	INP_WLOCK(inp);
743 	if (toep != NULL) {	/* NULL if connection was never offloaded. */
744 		toep->ulpcb = NULL;
745 		mbufq_drain(&toep->ulp_pduq);
746 		SOCKBUF_LOCK(sb);
747 		if (icc->rx_flags & RXF_ACTIVE) {
748 			volatile u_int *p = &icc->rx_flags;
749 
750 			SOCKBUF_UNLOCK(sb);
751 			INP_WUNLOCK(inp);
752 
753 			while (*p & RXF_ACTIVE)
754 				pause("conclo", 1);
755 
756 			INP_WLOCK(inp);
757 			SOCKBUF_LOCK(sb);
758 		}
759 
760 		while (!STAILQ_EMPTY(&icc->rcvd_pdus)) {
761 			ip = STAILQ_FIRST(&icc->rcvd_pdus);
762 			STAILQ_REMOVE_HEAD(&icc->rcvd_pdus, ip_next);
763 			icl_cxgbei_conn_pdu_free(ic, ip);
764 		}
765 		SOCKBUF_UNLOCK(sb);
766 	}
767 	INP_WUNLOCK(inp);
768 
769 	ICL_CONN_LOCK(ic);
770 	ic->ic_socket = NULL;
771 	ICL_CONN_UNLOCK(ic);
772 
773 	/*
774 	 * XXXNP: we should send RST instead of FIN when PDUs held in various
775 	 * queues were purged instead of delivered reliably but soabort isn't
776 	 * really general purpose and wouldn't do the right thing here.
777 	 */
778 	soclose(so);
779 }
780 
781 int
782 icl_cxgbei_conn_task_setup(struct icl_conn *ic, struct icl_pdu *ip,
783     struct ccb_scsiio *csio, uint32_t *task_tagp, void **prvp)
784 {
785 	void *prv;
786 
787 	*task_tagp = icl_conn_build_tasktag(ic, *task_tagp);
788 
789 	prv = uma_zalloc(icl_transfer_zone, M_NOWAIT | M_ZERO);
790 	if (prv == NULL)
791 		return (ENOMEM);
792 
793 	*prvp = prv;
794 
795 	cxgbei_conn_task_reserve_itt(ic, prvp, csio, task_tagp);
796 
797 	return (0);
798 }
799 
800 void
801 icl_cxgbei_conn_task_done(struct icl_conn *ic, void *prv)
802 {
803 
804 	cxgbei_cleanup_task(ic, prv);
805 	uma_zfree(icl_transfer_zone, prv);
806 }
807 
808 int
809 icl_cxgbei_conn_transfer_setup(struct icl_conn *ic, union ctl_io *io,
810     uint32_t *transfer_tag, void **prvp)
811 {
812 	void *prv;
813 
814 	*transfer_tag = icl_conn_build_tasktag(ic, *transfer_tag);
815 
816 	prv = uma_zalloc(icl_transfer_zone, M_NOWAIT | M_ZERO);
817 	if (prv == NULL)
818 		return (ENOMEM);
819 
820 	*prvp = prv;
821 
822 	cxgbei_conn_transfer_reserve_ttt(ic, prvp, io, transfer_tag);
823 
824 	return (0);
825 }
826 
827 void
828 icl_cxgbei_conn_transfer_done(struct icl_conn *ic, void *prv)
829 {
830 	cxgbei_cleanup_task(ic, prv);
831 	uma_zfree(icl_transfer_zone, prv);
832 }
833 
834 static int
835 icl_cxgbei_limits(size_t *limitp)
836 {
837 
838 	*limitp = CXGBEI_MAX_DSL;
839 
840 	return (0);
841 }
842 
843 static int
844 icl_cxgbei_load(void)
845 {
846 	int error;
847 
848 	icl_transfer_zone = uma_zcreate("icl_transfer",
849 	    16 * 1024, NULL, NULL, NULL, NULL,
850 	    UMA_ALIGN_PTR, 0);
851 
852 	refcount_init(&icl_cxgbei_ncons, 0);
853 
854 	error = icl_register("cxgbei", false, -100, icl_cxgbei_limits,
855 	    icl_cxgbei_new_conn);
856 	KASSERT(error == 0, ("failed to register"));
857 
858 	return (error);
859 }
860 
861 static int
862 icl_cxgbei_unload(void)
863 {
864 
865 	if (icl_cxgbei_ncons != 0)
866 		return (EBUSY);
867 
868 	icl_unregister("cxgbei", false);
869 
870 	uma_zdestroy(icl_transfer_zone);
871 
872 	return (0);
873 }
874 
875 static int
876 icl_cxgbei_modevent(module_t mod, int what, void *arg)
877 {
878 
879 	switch (what) {
880 	case MOD_LOAD:
881 		return (icl_cxgbei_load());
882 	case MOD_UNLOAD:
883 		return (icl_cxgbei_unload());
884 	default:
885 		return (EINVAL);
886 	}
887 }
888 
889 moduledata_t icl_cxgbei_data = {
890 	"icl_cxgbei",
891 	icl_cxgbei_modevent,
892 	0
893 };
894 
895 DECLARE_MODULE(icl_cxgbei, icl_cxgbei_data, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
896 MODULE_DEPEND(icl_cxgbei, icl, 1, 1, 1);
897 MODULE_VERSION(icl_cxgbei, 1);
898 #endif
899