static int send_connect()

in hw/cxgb4/cm.c [713:938]


static int send_connect(struct c4iw_ep *ep)
{
	struct cpl_act_open_req *req = NULL;
	struct cpl_t5_act_open_req *t5req = NULL;
	struct cpl_t6_act_open_req *t6req = NULL;
	struct cpl_act_open_req6 *req6 = NULL;
	struct cpl_t5_act_open_req6 *t5req6 = NULL;
	struct cpl_t6_act_open_req6 *t6req6 = NULL;
	struct sk_buff *skb;
	u64 opt0;
	u32 opt2;
	unsigned int mtu_idx;
	u32 wscale;
	int win, sizev4, sizev6, wrlen;
	struct sockaddr_in *la = (struct sockaddr_in *)
				 &ep->com.local_addr;
	struct sockaddr_in *ra = (struct sockaddr_in *)
				 &ep->com.remote_addr;
	struct sockaddr_in6 *la6 = (struct sockaddr_in6 *)
				   &ep->com.local_addr;
	struct sockaddr_in6 *ra6 = (struct sockaddr_in6 *)
				   &ep->com.remote_addr;
	int ret;
	enum chip_type adapter_type = ep->com.dev->rdev.lldi.adapter_type;
	u32 isn = (prandom_u32() & ~7UL) - 1;
	struct net_device *netdev;
	u64 params;

	netdev = ep->com.dev->rdev.lldi.ports[0];

	switch (CHELSIO_CHIP_VERSION(adapter_type)) {
	case CHELSIO_T4:
		sizev4 = sizeof(struct cpl_act_open_req);
		sizev6 = sizeof(struct cpl_act_open_req6);
		break;
	case CHELSIO_T5:
		sizev4 = sizeof(struct cpl_t5_act_open_req);
		sizev6 = sizeof(struct cpl_t5_act_open_req6);
		break;
	case CHELSIO_T6:
		sizev4 = sizeof(struct cpl_t6_act_open_req);
		sizev6 = sizeof(struct cpl_t6_act_open_req6);
		break;
	default:
		pr_err("T%d Chip is not supported\n",
		       CHELSIO_CHIP_VERSION(adapter_type));
		return -EINVAL;
	}

	wrlen = (ep->com.remote_addr.ss_family == AF_INET) ?
			roundup(sizev4, 16) :
			roundup(sizev6, 16);

	pr_debug("ep %p atid %u\n", ep, ep->atid);

	skb = get_skb(NULL, wrlen, GFP_KERNEL);
	if (!skb) {
		pr_err("%s - failed to alloc skb\n", __func__);
		return -ENOMEM;
	}
	set_wr_txq(skb, CPL_PRIORITY_SETUP, ep->ctrlq_idx);

	cxgb_best_mtu(ep->com.dev->rdev.lldi.mtus, ep->mtu, &mtu_idx,
		      enable_tcp_timestamps,
		      (ep->com.remote_addr.ss_family == AF_INET) ? 0 : 1);
	wscale = cxgb_compute_wscale(rcv_win);

	/*
	 * Specify the largest window that will fit in opt0. The
	 * remainder will be specified in the rx_data_ack.
	 */
	win = ep->rcv_win >> 10;
	if (win > RCV_BUFSIZ_M)
		win = RCV_BUFSIZ_M;

	opt0 = (nocong ? NO_CONG_F : 0) |
	       KEEP_ALIVE_F |
	       DELACK_F |
	       WND_SCALE_V(wscale) |
	       MSS_IDX_V(mtu_idx) |
	       L2T_IDX_V(ep->l2t->idx) |
	       TX_CHAN_V(ep->tx_chan) |
	       SMAC_SEL_V(ep->smac_idx) |
	       DSCP_V(ep->tos >> 2) |
	       ULP_MODE_V(ULP_MODE_TCPDDP) |
	       RCV_BUFSIZ_V(win);
	opt2 = RX_CHANNEL_V(0) |
	       CCTRL_ECN_V(enable_ecn) |
	       RSS_QUEUE_VALID_F | RSS_QUEUE_V(ep->rss_qid);
	if (enable_tcp_timestamps)
		opt2 |= TSTAMPS_EN_F;
	if (enable_tcp_sack)
		opt2 |= SACK_EN_F;
	if (wscale && enable_tcp_window_scaling)
		opt2 |= WND_SCALE_EN_F;
	if (CHELSIO_CHIP_VERSION(adapter_type) > CHELSIO_T4) {
		if (peer2peer)
			isn += 4;

		opt2 |= T5_OPT_2_VALID_F;
		opt2 |= CONG_CNTRL_V(CONG_ALG_TAHOE);
		opt2 |= T5_ISS_F;
	}

	params = cxgb4_select_ntuple(netdev, ep->l2t);

	if (ep->com.remote_addr.ss_family == AF_INET6)
		cxgb4_clip_get(ep->com.dev->rdev.lldi.ports[0],
			       (const u32 *)&la6->sin6_addr.s6_addr, 1);

	t4_set_arp_err_handler(skb, ep, act_open_req_arp_failure);

	if (ep->com.remote_addr.ss_family == AF_INET) {
		switch (CHELSIO_CHIP_VERSION(adapter_type)) {
		case CHELSIO_T4:
			req = skb_put(skb, wrlen);
			INIT_TP_WR(req, 0);
			break;
		case CHELSIO_T5:
			t5req = skb_put(skb, wrlen);
			INIT_TP_WR(t5req, 0);
			req = (struct cpl_act_open_req *)t5req;
			break;
		case CHELSIO_T6:
			t6req = skb_put(skb, wrlen);
			INIT_TP_WR(t6req, 0);
			req = (struct cpl_act_open_req *)t6req;
			t5req = (struct cpl_t5_act_open_req *)t6req;
			break;
		default:
			pr_err("T%d Chip is not supported\n",
			       CHELSIO_CHIP_VERSION(adapter_type));
			ret = -EINVAL;
			goto clip_release;
		}

		OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_ACT_OPEN_REQ,
					((ep->rss_qid<<14) | ep->atid)));
		req->local_port = la->sin_port;
		req->peer_port = ra->sin_port;
		req->local_ip = la->sin_addr.s_addr;
		req->peer_ip = ra->sin_addr.s_addr;
		req->opt0 = cpu_to_be64(opt0);

		if (is_t4(ep->com.dev->rdev.lldi.adapter_type)) {
			req->params = cpu_to_be32(params);
			req->opt2 = cpu_to_be32(opt2);
		} else {
			if (is_t5(ep->com.dev->rdev.lldi.adapter_type)) {
				t5req->params =
					  cpu_to_be64(FILTER_TUPLE_V(params));
				t5req->rsvd = cpu_to_be32(isn);
				pr_debug("snd_isn %u\n", t5req->rsvd);
				t5req->opt2 = cpu_to_be32(opt2);
			} else {
				t6req->params =
					  cpu_to_be64(FILTER_TUPLE_V(params));
				t6req->rsvd = cpu_to_be32(isn);
				pr_debug("snd_isn %u\n", t6req->rsvd);
				t6req->opt2 = cpu_to_be32(opt2);
			}
		}
	} else {
		switch (CHELSIO_CHIP_VERSION(adapter_type)) {
		case CHELSIO_T4:
			req6 = skb_put(skb, wrlen);
			INIT_TP_WR(req6, 0);
			break;
		case CHELSIO_T5:
			t5req6 = skb_put(skb, wrlen);
			INIT_TP_WR(t5req6, 0);
			req6 = (struct cpl_act_open_req6 *)t5req6;
			break;
		case CHELSIO_T6:
			t6req6 = skb_put(skb, wrlen);
			INIT_TP_WR(t6req6, 0);
			req6 = (struct cpl_act_open_req6 *)t6req6;
			t5req6 = (struct cpl_t5_act_open_req6 *)t6req6;
			break;
		default:
			pr_err("T%d Chip is not supported\n",
			       CHELSIO_CHIP_VERSION(adapter_type));
			ret = -EINVAL;
			goto clip_release;
		}

		OPCODE_TID(req6) = cpu_to_be32(MK_OPCODE_TID(CPL_ACT_OPEN_REQ6,
					((ep->rss_qid<<14)|ep->atid)));
		req6->local_port = la6->sin6_port;
		req6->peer_port = ra6->sin6_port;
		req6->local_ip_hi = *((__be64 *)(la6->sin6_addr.s6_addr));
		req6->local_ip_lo = *((__be64 *)(la6->sin6_addr.s6_addr + 8));
		req6->peer_ip_hi = *((__be64 *)(ra6->sin6_addr.s6_addr));
		req6->peer_ip_lo = *((__be64 *)(ra6->sin6_addr.s6_addr + 8));
		req6->opt0 = cpu_to_be64(opt0);

		if (is_t4(ep->com.dev->rdev.lldi.adapter_type)) {
			req6->params = cpu_to_be32(cxgb4_select_ntuple(netdev,
								      ep->l2t));
			req6->opt2 = cpu_to_be32(opt2);
		} else {
			if (is_t5(ep->com.dev->rdev.lldi.adapter_type)) {
				t5req6->params =
					    cpu_to_be64(FILTER_TUPLE_V(params));
				t5req6->rsvd = cpu_to_be32(isn);
				pr_debug("snd_isn %u\n", t5req6->rsvd);
				t5req6->opt2 = cpu_to_be32(opt2);
			} else {
				t6req6->params =
					    cpu_to_be64(FILTER_TUPLE_V(params));
				t6req6->rsvd = cpu_to_be32(isn);
				pr_debug("snd_isn %u\n", t6req6->rsvd);
				t6req6->opt2 = cpu_to_be32(opt2);
			}

		}
	}

	set_bit(ACT_OPEN_REQ, &ep->com.history);
	ret = c4iw_l2t_send(&ep->com.dev->rdev, skb, ep->l2t);
clip_release:
	if (ret && ep->com.remote_addr.ss_family == AF_INET6)
		cxgb4_clip_release(ep->com.dev->rdev.lldi.ports[0],
				   (const u32 *)&la6->sin6_addr.s6_addr, 1);
	return ret;
}