diff options
Diffstat (limited to 'drivers/infiniband/hw/cxgb4/cm.c')
| -rw-r--r-- | drivers/infiniband/hw/cxgb4/cm.c | 645 | 
1 files changed, 452 insertions, 193 deletions
diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index 12fef76c791..768a0fb67dd 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -1,5 +1,5 @@  /* - * Copyright (c) 2009-2010 Chelsio, Inc. All rights reserved. + * Copyright (c) 2009-2014 Chelsio, Inc. All rights reserved.   *   * This software is available to you under a choice of one of two   * licenses.  You may choose to be licensed under the terms of the GNU @@ -47,6 +47,8 @@  #include <net/ip6_route.h>  #include <net/addrconf.h> +#include <rdma/ib_addr.h> +  #include "iw_cxgb4.h"  static char *states[] = { @@ -98,9 +100,9 @@ int c4iw_debug;  module_param(c4iw_debug, int, 0644);  MODULE_PARM_DESC(c4iw_debug, "Enable debug logging (default=0)"); -static int peer2peer; +static int peer2peer = 1;  module_param(peer2peer, int, 0644); -MODULE_PARM_DESC(peer2peer, "Support peer2peer ULPs (default=0)"); +MODULE_PARM_DESC(peer2peer, "Support peer2peer ULPs (default=1)");  static int p2p_type = FW_RI_INIT_P2PTYPE_READ_REQ;  module_param(p2p_type, int, 0644); @@ -173,12 +175,15 @@ static void start_ep_timer(struct c4iw_ep *ep)  	add_timer(&ep->timer);  } -static void stop_ep_timer(struct c4iw_ep *ep) +static int stop_ep_timer(struct c4iw_ep *ep)  {  	PDBG("%s ep %p stopping\n", __func__, ep);  	del_timer_sync(&ep->timer); -	if (!test_and_set_bit(TIMEOUT, &ep->com.flags)) +	if (!test_and_set_bit(TIMEOUT, &ep->com.flags)) {  		c4iw_put_ep(&ep->com); +		return 0; +	} +	return 1;  }  static int c4iw_l2t_send(struct c4iw_rdev *rdev, struct sk_buff *skb, @@ -229,12 +234,16 @@ static void release_tid(struct c4iw_rdev *rdev, u32 hwtid, struct sk_buff *skb)  static void set_emss(struct c4iw_ep *ep, u16 opt)  { -	ep->emss = ep->com.dev->rdev.lldi.mtus[GET_TCPOPT_MSS(opt)] - 40; +	ep->emss = ep->com.dev->rdev.lldi.mtus[GET_TCPOPT_MSS(opt)] - +		   sizeof(struct iphdr) - sizeof(struct tcphdr);  	ep->mss = ep->emss;  	if (GET_TCPOPT_TSTAMP(opt))  		ep->emss -= 12;  	if (ep->emss < 128)  		ep->emss = 128; +	if (ep->emss & 7) +		PDBG("Warning: misaligned mtu idx %u mss %u emss=%u\n", +		     GET_TCPOPT_MSS(opt), ep->mss, ep->emss);  	PDBG("%s mss_idx %u mss %u emss=%u\n", __func__, GET_TCPOPT_MSS(opt),  	     ep->mss, ep->emss);  } @@ -291,6 +300,12 @@ void _c4iw_free_ep(struct kref *kref)  		dst_release(ep->dst);  		cxgb4_l2t_release(ep->l2t);  	} +	if (test_bit(RELEASE_MAPINFO, &ep->com.flags)) { +		print_addr(&ep->com, __func__, "remove_mapinfo/mapping"); +		iwpm_remove_mapinfo(&ep->com.local_addr, +				    &ep->com.mapped_local_addr); +		iwpm_remove_mapping(&ep->com.local_addr, RDMA_NL_C4IW); +	}  	kfree(ep);  } @@ -338,10 +353,7 @@ static struct sk_buff *get_skb(struct sk_buff *skb, int len, gfp_t gfp)  static struct net_device *get_real_dev(struct net_device *egress_dev)  { -	struct net_device *phys_dev = egress_dev; -	if (egress_dev->priv_flags & IFF_802_1Q_VLAN) -		phys_dev = vlan_dev_real_dev(egress_dev); -	return phys_dev; +	return rdma_vlan_dev_real_dev(egress_dev) ? : egress_dev;  }  static int our_interface(struct c4iw_dev *dev, struct net_device *egress_dev) @@ -400,7 +412,8 @@ static struct dst_entry *find_route(struct c4iw_dev *dev, __be32 local_ip,  	n = dst_neigh_lookup(&rt->dst, &peer_ip);  	if (!n)  		return NULL; -	if (!our_interface(dev, n->dev)) { +	if (!our_interface(dev, n->dev) && +	    !(n->dev->flags & IFF_LOOPBACK)) {  		dst_release(&rt->dst);  		return NULL;  	} @@ -419,8 +432,17 @@ static void arp_failure_discard(void *handle, struct sk_buff *skb)   */  static void act_open_req_arp_failure(void *handle, struct sk_buff *skb)  { +	struct c4iw_ep *ep = handle; +  	printk(KERN_ERR MOD "ARP failure duing connect\n");  	kfree_skb(skb); +	connect_reply_upcall(ep, -EHOSTUNREACH); +	state_set(&ep->com, DEAD); +	remove_handle(ep->com.dev, &ep->com.dev->atid_idr, ep->atid); +	cxgb4_free_atid(ep->com.dev->rdev.lldi.tids, ep->atid); +	dst_release(ep->dst); +	cxgb4_l2t_release(ep->l2t); +	c4iw_put_ep(&ep->com);  }  /* @@ -464,7 +486,7 @@ static void send_flowc(struct c4iw_ep *ep, struct sk_buff *skb)  	flowc->mnemval[5].mnemonic = FW_FLOWC_MNEM_RCVNXT;  	flowc->mnemval[5].val = cpu_to_be32(ep->rcv_seq);  	flowc->mnemval[6].mnemonic = FW_FLOWC_MNEM_SNDBUF; -	flowc->mnemval[6].val = cpu_to_be32(snd_win); +	flowc->mnemval[6].val = cpu_to_be32(ep->snd_win);  	flowc->mnemval[7].mnemonic = FW_FLOWC_MNEM_MSS;  	flowc->mnemval[7].val = cpu_to_be32(ep->emss);  	/* Pad WR to 16 byte boundary */ @@ -524,48 +546,47 @@ static int send_abort(struct c4iw_ep *ep, struct sk_buff *skb, gfp_t gfp)  	return c4iw_l2t_send(&ep->com.dev->rdev, skb, ep->l2t);  } -#define VLAN_NONE 0xfff -#define FILTER_SEL_VLAN_NONE 0xffff -#define FILTER_SEL_WIDTH_P_FC (3+1) /* port uses 3 bits, FCoE one bit */ -#define FILTER_SEL_WIDTH_VIN_P_FC \ -	(6 + 7 + FILTER_SEL_WIDTH_P_FC) /* 6 bits are unused, VF uses 7 bits*/ -#define FILTER_SEL_WIDTH_TAG_P_FC \ -	(3 + FILTER_SEL_WIDTH_VIN_P_FC) /* PF uses 3 bits */ -#define FILTER_SEL_WIDTH_VLD_TAG_P_FC (1 + FILTER_SEL_WIDTH_TAG_P_FC) +/* + * c4iw_form_pm_msg - Form a port mapper message with mapping info + */ +static void c4iw_form_pm_msg(struct c4iw_ep *ep, +				struct iwpm_sa_data *pm_msg) +{ +	memcpy(&pm_msg->loc_addr, &ep->com.local_addr, +		sizeof(ep->com.local_addr)); +	memcpy(&pm_msg->rem_addr, &ep->com.remote_addr, +		sizeof(ep->com.remote_addr)); +} -static unsigned int select_ntuple(struct c4iw_dev *dev, struct dst_entry *dst, -				  struct l2t_entry *l2t) +/* + * c4iw_form_reg_msg - Form a port mapper message with dev info + */ +static void c4iw_form_reg_msg(struct c4iw_dev *dev, +				struct iwpm_dev_data *pm_msg)  { -	unsigned int ntuple = 0; -	u32 viid; +	memcpy(pm_msg->dev_name, dev->ibdev.name, IWPM_DEVNAME_SIZE); +	memcpy(pm_msg->if_name, dev->rdev.lldi.ports[0]->name, +				IWPM_IFNAME_SIZE); +} -	switch (dev->rdev.lldi.filt_mode) { +static void c4iw_record_pm_msg(struct c4iw_ep *ep, +			struct iwpm_sa_data *pm_msg) +{ +	memcpy(&ep->com.mapped_local_addr, &pm_msg->mapped_loc_addr, +		sizeof(ep->com.mapped_local_addr)); +	memcpy(&ep->com.mapped_remote_addr, &pm_msg->mapped_rem_addr, +		sizeof(ep->com.mapped_remote_addr)); +} -	/* default filter mode */ -	case HW_TPL_FR_MT_PR_IV_P_FC: -		if (l2t->vlan == VLAN_NONE) -			ntuple |= FILTER_SEL_VLAN_NONE << FILTER_SEL_WIDTH_P_FC; -		else { -			ntuple |= l2t->vlan << FILTER_SEL_WIDTH_P_FC; -			ntuple |= 1 << FILTER_SEL_WIDTH_TAG_P_FC; -		} -		ntuple |= l2t->lport << S_PORT | IPPROTO_TCP << -			  FILTER_SEL_WIDTH_VLD_TAG_P_FC; -		break; -	case HW_TPL_FR_MT_PR_OV_P_FC: { -		viid = cxgb4_port_viid(l2t->neigh->dev); - -		ntuple |= FW_VIID_VIN_GET(viid) << FILTER_SEL_WIDTH_P_FC; -		ntuple |= FW_VIID_PFN_GET(viid) << FILTER_SEL_WIDTH_VIN_P_FC; -		ntuple |= FW_VIID_VIVLD_GET(viid) << FILTER_SEL_WIDTH_TAG_P_FC; -		ntuple |= l2t->lport << S_PORT | IPPROTO_TCP << -			  FILTER_SEL_WIDTH_VLD_TAG_P_FC; -		break; -	} -	default: -		break; -	} -	return ntuple; +static void best_mtu(const unsigned short *mtus, unsigned short mtu, +		     unsigned int *idx, int use_ts) +{ +	unsigned short hdr_size = sizeof(struct iphdr) + +				  sizeof(struct tcphdr) + +				  (use_ts ? 12 : 0); +	unsigned short data_size = mtu - hdr_size; + +	cxgb4_best_aligned_mtu(mtus, hdr_size, data_size, 8, idx);  }  static int send_connect(struct c4iw_ep *ep) @@ -586,10 +607,15 @@ static int send_connect(struct c4iw_ep *ep)  	int sizev6 = is_t4(ep->com.dev->rdev.lldi.adapter_type) ?  				sizeof(struct cpl_act_open_req6) :  				sizeof(struct cpl_t5_act_open_req6); -	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; +	struct sockaddr_in *la = (struct sockaddr_in *) +				 &ep->com.mapped_local_addr; +	struct sockaddr_in *ra = (struct sockaddr_in *) +				 &ep->com.mapped_remote_addr; +	struct sockaddr_in6 *la6 = (struct sockaddr_in6 *) +				   &ep->com.mapped_local_addr; +	struct sockaddr_in6 *ra6 = (struct sockaddr_in6 *) +				   &ep->com.mapped_remote_addr; +	int win;  	wrlen = (ep->com.remote_addr.ss_family == AF_INET) ?  			roundup(sizev4, 16) : @@ -605,8 +631,18 @@ static int send_connect(struct c4iw_ep *ep)  	}  	set_wr_txq(skb, CPL_PRIORITY_SETUP, ep->ctrlq_idx); -	cxgb4_best_mtu(ep->com.dev->rdev.lldi.mtus, ep->mtu, &mtu_idx); +	best_mtu(ep->com.dev->rdev.lldi.mtus, ep->mtu, &mtu_idx, +		 enable_tcp_timestamps);  	wscale = 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_MASK) +		win = RCV_BUFSIZ_MASK; +  	opt0 = (nocong ? NO_CONG(1) : 0) |  	       KEEP_ALIVE(1) |  	       DELACK(1) | @@ -617,7 +653,7 @@ static int send_connect(struct c4iw_ep *ep)  	       SMAC_SEL(ep->smac_idx) |  	       DSCP(ep->tos) |  	       ULP_MODE(ULP_MODE_TCPDDP) | -	       RCV_BUFSIZ(rcv_win>>10); +	       RCV_BUFSIZ(win);  	opt2 = RX_CHANNEL(0) |  	       CCTRL_ECN(enable_ecn) |  	       RSS_QUEUE_VALID | RSS_QUEUE(ep->rss_qid); @@ -627,7 +663,11 @@ static int send_connect(struct c4iw_ep *ep)  		opt2 |= SACK_EN(1);  	if (wscale && enable_tcp_window_scaling)  		opt2 |= WND_SCALE_EN(1); -	t4_set_arp_err_handler(skb, NULL, act_open_req_arp_failure); +	if (is_t5(ep->com.dev->rdev.lldi.adapter_type)) { +		opt2 |= T5_OPT_2_VALID; +		opt2 |= V_CONG_CNTRL(CONG_ALG_TAHOE); +	} +	t4_set_arp_err_handler(skb, ep, act_open_req_arp_failure);  	if (is_t4(ep->com.dev->rdev.lldi.adapter_type)) {  		if (ep->com.remote_addr.ss_family == AF_INET) { @@ -641,8 +681,9 @@ static int send_connect(struct c4iw_ep *ep)  			req->local_ip = la->sin_addr.s_addr;  			req->peer_ip = ra->sin_addr.s_addr;  			req->opt0 = cpu_to_be64(opt0); -			req->params = cpu_to_be32(select_ntuple(ep->com.dev, -						ep->dst, ep->l2t)); +			req->params = cpu_to_be32(cxgb4_select_ntuple( +						ep->com.dev->rdev.lldi.ports[0], +						ep->l2t));  			req->opt2 = cpu_to_be32(opt2);  		} else {  			req6 = (struct cpl_act_open_req6 *)skb_put(skb, wrlen); @@ -662,12 +703,19 @@ static int send_connect(struct c4iw_ep *ep)  			req6->peer_ip_lo = *((__be64 *)  						(ra6->sin6_addr.s6_addr + 8));  			req6->opt0 = cpu_to_be64(opt0); -			req6->params = cpu_to_be32( -					select_ntuple(ep->com.dev, ep->dst, -						      ep->l2t)); +			req6->params = cpu_to_be32(cxgb4_select_ntuple( +						ep->com.dev->rdev.lldi.ports[0], +						ep->l2t));  			req6->opt2 = cpu_to_be32(opt2);  		}  	} else { +		u32 isn = (prandom_u32() & ~7UL) - 1; + +		opt2 |= T5_OPT_2_VALID; +		opt2 |= CONG_CNTRL_VALID; /* OPT_2_ISS for T5 */ +		if (peer2peer) +			isn += 4; +  		if (ep->com.remote_addr.ss_family == AF_INET) {  			t5_req = (struct cpl_t5_act_open_req *)  				 skb_put(skb, wrlen); @@ -681,8 +729,12 @@ static int send_connect(struct c4iw_ep *ep)  			t5_req->peer_ip = ra->sin_addr.s_addr;  			t5_req->opt0 = cpu_to_be64(opt0);  			t5_req->params = cpu_to_be64(V_FILTER_TUPLE( -						select_ntuple(ep->com.dev, -						ep->dst, ep->l2t))); +						     cxgb4_select_ntuple( +					     ep->com.dev->rdev.lldi.ports[0], +					     ep->l2t))); +			t5_req->rsvd = cpu_to_be32(isn); +			PDBG("%s snd_isn %u\n", __func__, +			     be32_to_cpu(t5_req->rsvd));  			t5_req->opt2 = cpu_to_be32(opt2);  		} else {  			t5_req6 = (struct cpl_t5_act_open_req6 *) @@ -703,7 +755,12 @@ static int send_connect(struct c4iw_ep *ep)  						(ra6->sin6_addr.s6_addr + 8));  			t5_req6->opt0 = cpu_to_be64(opt0);  			t5_req6->params = (__force __be64)cpu_to_be32( -				select_ntuple(ep->com.dev, ep->dst, ep->l2t)); +							cxgb4_select_ntuple( +						ep->com.dev->rdev.lldi.ports[0], +						ep->l2t)); +			t5_req6->rsvd = cpu_to_be32(isn); +			PDBG("%s snd_isn %u\n", __func__, +			     be32_to_cpu(t5_req6->rsvd));  			t5_req6->opt2 = cpu_to_be32(opt2);  		}  	} @@ -799,8 +856,9 @@ static void send_mpa_req(struct c4iw_ep *ep, struct sk_buff *skb,  	ep->mpa_skb = skb;  	c4iw_l2t_send(&ep->com.dev->rdev, skb, ep->l2t);  	start_ep_timer(ep); -	state_set(&ep->com, MPA_REQ_SENT); +	__state_set(&ep->com, MPA_REQ_SENT);  	ep->mpa_attr.initiator = 1; +	ep->snd_seq += mpalen;  	return;  } @@ -880,6 +938,7 @@ static int send_mpa_reject(struct c4iw_ep *ep, const void *pdata, u8 plen)  	t4_set_arp_err_handler(skb, NULL, arp_failure_discard);  	BUG_ON(ep->mpa_skb);  	ep->mpa_skb = skb; +	ep->snd_seq += mpalen;  	return c4iw_l2t_send(&ep->com.dev->rdev, skb, ep->l2t);  } @@ -963,7 +1022,8 @@ static int send_mpa_reply(struct c4iw_ep *ep, const void *pdata, u8 plen)  	skb_get(skb);  	t4_set_arp_err_handler(skb, NULL, arp_failure_discard);  	ep->mpa_skb = skb; -	state_set(&ep->com, MPA_REP_SENT); +	__state_set(&ep->com, MPA_REP_SENT); +	ep->snd_seq += mpalen;  	return c4iw_l2t_send(&ep->com.dev->rdev, skb, ep->l2t);  } @@ -980,6 +1040,7 @@ static int act_establish(struct c4iw_dev *dev, struct sk_buff *skb)  	PDBG("%s ep %p tid %u snd_isn %u rcv_isn %u\n", __func__, ep, tid,  	     be32_to_cpu(req->snd_isn), be32_to_cpu(req->rcv_isn)); +	mutex_lock(&ep->com.mutex);  	dst_confirm(ep->dst);  	/* setup the hwtid for this connection */ @@ -1003,17 +1064,18 @@ static int act_establish(struct c4iw_dev *dev, struct sk_buff *skb)  		send_mpa_req(ep, skb, 1);  	else  		send_mpa_req(ep, skb, mpa_rev); - +	mutex_unlock(&ep->com.mutex);  	return 0;  } -static void close_complete_upcall(struct c4iw_ep *ep) +static void close_complete_upcall(struct c4iw_ep *ep, int status)  {  	struct iw_cm_event event;  	PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);  	memset(&event, 0, sizeof(event));  	event.event = IW_CM_EVENT_CLOSE; +	event.status = status;  	if (ep->com.cm_id) {  		PDBG("close complete delivered ep %p cm_id %p tid %u\n",  		     ep, ep->com.cm_id, ep->hwtid); @@ -1027,8 +1089,7 @@ static void close_complete_upcall(struct c4iw_ep *ep)  static int abort_connection(struct c4iw_ep *ep, struct sk_buff *skb, gfp_t gfp)  {  	PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid); -	close_complete_upcall(ep); -	state_set(&ep->com, ABORTING); +	__state_set(&ep->com, ABORTING);  	set_bit(ABORT_CONN, &ep->com.history);  	return send_abort(ep, skb, gfp);  } @@ -1106,9 +1167,10 @@ static void connect_reply_upcall(struct c4iw_ep *ep, int status)  	}  } -static void connect_request_upcall(struct c4iw_ep *ep) +static int connect_request_upcall(struct c4iw_ep *ep)  {  	struct iw_cm_event event; +	int ret;  	PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);  	memset(&event, 0, sizeof(event)); @@ -1133,15 +1195,14 @@ static void connect_request_upcall(struct c4iw_ep *ep)  		event.private_data_len = ep->plen;  		event.private_data = ep->mpa_pkt + sizeof(struct mpa_message);  	} -	if (state_read(&ep->parent_ep->com) != DEAD) { -		c4iw_get_ep(&ep->com); -		ep->parent_ep->com.cm_id->event_handler( -						ep->parent_ep->com.cm_id, -						&event); -	} +	c4iw_get_ep(&ep->com); +	ret = ep->parent_ep->com.cm_id->event_handler(ep->parent_ep->com.cm_id, +						      &event); +	if (ret) +		c4iw_put_ep(&ep->com);  	set_bit(CONNREQ_UPCALL, &ep->com.history);  	c4iw_put_ep(&ep->parent_ep->com); -	ep->parent_ep = NULL; +	return ret;  }  static void established_upcall(struct c4iw_ep *ep) @@ -1173,6 +1234,14 @@ static int update_rx_credits(struct c4iw_ep *ep, u32 credits)  		return 0;  	} +	/* +	 * If we couldn't specify the entire rcv window at connection setup +	 * due to the limit in the number of bits in the RCV_BUFSIZ field, +	 * then add the overage in to the credits returned. +	 */ +	if (ep->rcv_win > RCV_BUFSIZ_MASK * 1024) +		credits += ep->rcv_win - RCV_BUFSIZ_MASK * 1024; +  	req = (struct cpl_rx_data_ack *) skb_put(skb, wrlen);  	memset(req, 0, wrlen);  	INIT_TP_WR(req, ep->hwtid); @@ -1186,7 +1255,7 @@ static int update_rx_credits(struct c4iw_ep *ep, u32 credits)  	return credits;  } -static void process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb) +static int process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb)  {  	struct mpa_message *mpa;  	struct mpa_v2_conn_params *mpa_v2_params; @@ -1196,17 +1265,17 @@ static void process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb)  	struct c4iw_qp_attributes attrs;  	enum c4iw_qp_attr_mask mask;  	int err; +	int disconnect = 0;  	PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);  	/* -	 * Stop mpa timer.  If it expired, then the state has -	 * changed and we bail since ep_timeout already aborted -	 * the connection. +	 * Stop mpa timer.  If it expired, then +	 * we ignore the MPA reply.  process_timeout() +	 * will abort the connection.  	 */ -	stop_ep_timer(ep); -	if (state_read(&ep->com) != MPA_REQ_SENT) -		return; +	if (stop_ep_timer(ep)) +		return 0;  	/*  	 * If we get more than the supported amount of private data @@ -1228,7 +1297,7 @@ static void process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb)  	 * if we don't even have the mpa message, then bail.  	 */  	if (ep->mpa_pkt_len < sizeof(*mpa)) -		return; +		return 0;  	mpa = (struct mpa_message *) ep->mpa_pkt;  	/* Validate MPA header. */ @@ -1268,7 +1337,7 @@ static void process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb)  	 * We'll continue process when more data arrives.  	 */  	if (ep->mpa_pkt_len < (sizeof(*mpa) + plen)) -		return; +		return 0;  	if (mpa->flags & MPA_REJECT) {  		err = -ECONNREFUSED; @@ -1280,7 +1349,7 @@ static void process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb)  	 * start reply message including private data. And  	 * the MPA header is valid.  	 */ -	state_set(&ep->com, FPDU_MODE); +	__state_set(&ep->com, FPDU_MODE);  	ep->mpa_attr.crc_enabled = (mpa->flags & MPA_CRC) | crc_enabled ? 1 : 0;  	ep->mpa_attr.recv_marker_enabled = markers_enabled;  	ep->mpa_attr.xmit_marker_enabled = mpa->flags & MPA_MARKERS ? 1 : 0; @@ -1370,9 +1439,11 @@ static void process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb)  		attrs.layer_etype = LAYER_MPA | DDP_LLP;  		attrs.ecode = MPA_NOMATCH_RTR;  		attrs.next_state = C4IW_QP_STATE_TERMINATE; +		attrs.send_term = 1;  		err = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp, -				C4IW_QP_ATTR_NEXT_STATE, &attrs, 0); +				C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);  		err = -ENOMEM; +		disconnect = 1;  		goto out;  	} @@ -1388,18 +1459,20 @@ static void process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb)  		attrs.layer_etype = LAYER_MPA | DDP_LLP;  		attrs.ecode = MPA_INSUFF_IRD;  		attrs.next_state = C4IW_QP_STATE_TERMINATE; +		attrs.send_term = 1;  		err = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp, -				C4IW_QP_ATTR_NEXT_STATE, &attrs, 0); +				C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);  		err = -ENOMEM; +		disconnect = 1;  		goto out;  	}  	goto out;  err: -	state_set(&ep->com, ABORTING); +	__state_set(&ep->com, ABORTING);  	send_abort(ep, skb, GFP_KERNEL);  out:  	connect_reply_upcall(ep, err); -	return; +	return disconnect;  }  static void process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb) @@ -1410,15 +1483,12 @@ static void process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb)  	PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid); -	if (state_read(&ep->com) != MPA_REQ_WAIT) -		return; -  	/*  	 * If we get more than the supported amount of private data  	 * then we must fail this connection.  	 */  	if (ep->mpa_pkt_len + skb->len > sizeof(ep->mpa_pkt)) { -		stop_ep_timer(ep); +		(void)stop_ep_timer(ep);  		abort_connection(ep, skb, GFP_KERNEL);  		return;  	} @@ -1440,7 +1510,6 @@ static void process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb)  		return;  	PDBG("%s enter (%s line %u)\n", __func__, __FILE__, __LINE__); -	stop_ep_timer(ep);  	mpa = (struct mpa_message *) ep->mpa_pkt;  	/* @@ -1449,13 +1518,13 @@ static void process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb)  	if (mpa->revision > mpa_rev) {  		printk(KERN_ERR MOD "%s MPA version mismatch. Local = %d,"  		       " Received = %d\n", __func__, mpa_rev, mpa->revision); -		stop_ep_timer(ep); +		(void)stop_ep_timer(ep);  		abort_connection(ep, skb, GFP_KERNEL);  		return;  	}  	if (memcmp(mpa->key, MPA_KEY_REQ, sizeof(mpa->key))) { -		stop_ep_timer(ep); +		(void)stop_ep_timer(ep);  		abort_connection(ep, skb, GFP_KERNEL);  		return;  	} @@ -1466,7 +1535,7 @@ static void process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb)  	 * Fail if there's too much private data.  	 */  	if (plen > MPA_MAX_PRIVATE_DATA) { -		stop_ep_timer(ep); +		(void)stop_ep_timer(ep);  		abort_connection(ep, skb, GFP_KERNEL);  		return;  	} @@ -1475,7 +1544,7 @@ static void process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb)  	 * If plen does not account for pkt size  	 */  	if (ep->mpa_pkt_len > (sizeof(*mpa) + plen)) { -		stop_ep_timer(ep); +		(void)stop_ep_timer(ep);  		abort_connection(ep, skb, GFP_KERNEL);  		return;  	} @@ -1532,10 +1601,24 @@ static void process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb)  	     ep->mpa_attr.xmit_marker_enabled, ep->mpa_attr.version,  	     ep->mpa_attr.p2p_type); -	state_set(&ep->com, MPA_REQ_RCVD); - -	/* drive upcall */ -	connect_request_upcall(ep); +	/* +	 * If the endpoint timer already expired, then we ignore +	 * the start request.  process_timeout() will abort +	 * the connection. +	 */ +	if (!stop_ep_timer(ep)) { +		__state_set(&ep->com, MPA_REQ_RCVD); + +		/* drive upcall */ +		mutex_lock(&ep->parent_ep->com.mutex); +		if (ep->parent_ep->com.state != DEAD) { +			if (connect_request_upcall(ep)) +				abort_connection(ep, skb, GFP_KERNEL); +		} else { +			abort_connection(ep, skb, GFP_KERNEL); +		} +		mutex_unlock(&ep->parent_ep->com.mutex); +	}  	return;  } @@ -1547,19 +1630,23 @@ static int rx_data(struct c4iw_dev *dev, struct sk_buff *skb)  	unsigned int tid = GET_TID(hdr);  	struct tid_info *t = dev->rdev.lldi.tids;  	__u8 status = hdr->status; +	int disconnect = 0;  	ep = lookup_tid(t, tid); +	if (!ep) +		return 0;  	PDBG("%s ep %p tid %u dlen %u\n", __func__, ep, ep->hwtid, dlen);  	skb_pull(skb, sizeof(*hdr));  	skb_trim(skb, dlen); +	mutex_lock(&ep->com.mutex);  	/* update RX credits */  	update_rx_credits(ep, dlen); -	switch (state_read(&ep->com)) { +	switch (ep->com.state) {  	case MPA_REQ_SENT:  		ep->rcv_seq += dlen; -		process_mpa_reply(ep, skb); +		disconnect = process_mpa_reply(ep, skb);  		break;  	case MPA_REQ_WAIT:  		ep->rcv_seq += dlen; @@ -1572,15 +1659,19 @@ static int rx_data(struct c4iw_dev *dev, struct sk_buff *skb)  			pr_err("%s Unexpected streaming data." \  			       " qpid %u ep %p state %d tid %u status %d\n",  			       __func__, ep->com.qp->wq.sq.qid, ep, -			       state_read(&ep->com), ep->hwtid, status); +			       ep->com.state, ep->hwtid, status);  		attrs.next_state = C4IW_QP_STATE_TERMINATE;  		c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp, -			       C4IW_QP_ATTR_NEXT_STATE, &attrs, 0); +			       C4IW_QP_ATTR_NEXT_STATE, &attrs, 1); +		disconnect = 1;  		break;  	}  	default:  		break;  	} +	mutex_unlock(&ep->com.mutex); +	if (disconnect) +		c4iw_ep_disconnect(ep, 0, GFP_KERNEL);  	return 0;  } @@ -1624,18 +1715,20 @@ static void send_fw_act_open_req(struct c4iw_ep *ep, unsigned int atid)  	unsigned int mtu_idx;  	int wscale;  	struct sockaddr_in *sin; +	int win;  	skb = get_skb(NULL, sizeof(*req), GFP_KERNEL);  	req = (struct fw_ofld_connection_wr *)__skb_put(skb, sizeof(*req));  	memset(req, 0, sizeof(*req));  	req->op_compl = htonl(V_WR_OP(FW_OFLD_CONNECTION_WR));  	req->len16_pkd = htonl(FW_WR_LEN16(DIV_ROUND_UP(sizeof(*req), 16))); -	req->le.filter = cpu_to_be32(select_ntuple(ep->com.dev, ep->dst, +	req->le.filter = cpu_to_be32(cxgb4_select_ntuple( +				     ep->com.dev->rdev.lldi.ports[0],  				     ep->l2t)); -	sin = (struct sockaddr_in *)&ep->com.local_addr; +	sin = (struct sockaddr_in *)&ep->com.mapped_local_addr;  	req->le.lport = sin->sin_port;  	req->le.u.ipv4.lip = sin->sin_addr.s_addr; -	sin = (struct sockaddr_in *)&ep->com.remote_addr; +	sin = (struct sockaddr_in *)&ep->com.mapped_remote_addr;  	req->le.pport = sin->sin_port;  	req->le.u.ipv4.pip = sin->sin_addr.s_addr;  	req->tcb.t_state_to_astid = @@ -1645,8 +1738,18 @@ static void send_fw_act_open_req(struct c4iw_ep *ep, unsigned int atid)  			htons(F_FW_OFLD_CONNECTION_WR_CPLRXDATAACK);  	req->tcb.tx_max = (__force __be32) jiffies;  	req->tcb.rcv_adv = htons(1); -	cxgb4_best_mtu(ep->com.dev->rdev.lldi.mtus, ep->mtu, &mtu_idx); +	best_mtu(ep->com.dev->rdev.lldi.mtus, ep->mtu, &mtu_idx, +		 enable_tcp_timestamps);  	wscale = 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_MASK) +		win = RCV_BUFSIZ_MASK; +  	req->tcb.opt0 = (__force __be64) (TCAM_BYPASS(1) |  		(nocong ? NO_CONG(1) : 0) |  		KEEP_ALIVE(1) | @@ -1658,7 +1761,7 @@ static void send_fw_act_open_req(struct c4iw_ep *ep, unsigned int atid)  		SMAC_SEL(ep->smac_idx) |  		DSCP(ep->tos) |  		ULP_MODE(ULP_MODE_TCPDDP) | -		RCV_BUFSIZ(rcv_win >> 10)); +		RCV_BUFSIZ(win));  	req->tcb.opt2 = (__force __be32) (PACE(1) |  		TX_QUEUE(ep->com.dev->rdev.lldi.tx_modq[ep->tx_chan]) |  		RX_CHANNEL(0) | @@ -1686,6 +1789,22 @@ static inline int act_open_has_tid(int status)  	       status != CPL_ERR_ARP_MISS;  } +/* Returns whether a CPL status conveys negative advice. + */ +static int is_neg_adv(unsigned int status) +{ +	return status == CPL_ERR_RTX_NEG_ADVICE || +	       status == CPL_ERR_PERSIST_NEG_ADVICE || +	       status == CPL_ERR_KEEPALV_NEG_ADVICE; +} + +static void set_tcp_window(struct c4iw_ep *ep, struct port_info *pi) +{ +	ep->snd_win = snd_win; +	ep->rcv_win = rcv_win; +	PDBG("%s snd_win %d rcv_win %d\n", __func__, ep->snd_win, ep->rcv_win); +} +  #define ACT_OPEN_RETRY_COUNT 2  static int import_ep(struct c4iw_ep *ep, int iptype, __u8 *peer_ip, @@ -1734,6 +1853,7 @@ static int import_ep(struct c4iw_ep *ep, int iptype, __u8 *peer_ip,  		ep->ctrlq_idx = cxgb4_port_idx(pdev);  		ep->rss_qid = cdev->rdev.lldi.rxq_ids[  			cxgb4_port_idx(pdev) * step]; +		set_tcp_window(ep, (struct port_info *)netdev_priv(pdev));  		dev_put(pdev);  	} else {  		pdev = get_real_dev(n->dev); @@ -1742,16 +1862,17 @@ static int import_ep(struct c4iw_ep *ep, int iptype, __u8 *peer_ip,  		if (!ep->l2t)  			goto out;  		ep->mtu = dst_mtu(dst); -		ep->tx_chan = cxgb4_port_chan(n->dev); -		ep->smac_idx = (cxgb4_port_viid(n->dev) & 0x7F) << 1; +		ep->tx_chan = cxgb4_port_chan(pdev); +		ep->smac_idx = (cxgb4_port_viid(pdev) & 0x7F) << 1;  		step = cdev->rdev.lldi.ntxq /  			cdev->rdev.lldi.nchan; -		ep->txq_idx = cxgb4_port_idx(n->dev) * step; -		ep->ctrlq_idx = cxgb4_port_idx(n->dev); +		ep->txq_idx = cxgb4_port_idx(pdev) * step; +		ep->ctrlq_idx = cxgb4_port_idx(pdev);  		step = cdev->rdev.lldi.nrxq /  			cdev->rdev.lldi.nchan;  		ep->rss_qid = cdev->rdev.lldi.rxq_ids[ -			cxgb4_port_idx(n->dev) * step]; +			cxgb4_port_idx(pdev) * step]; +		set_tcp_window(ep, (struct port_info *)netdev_priv(pdev));  		if (clear_mpa_v1) {  			ep->retry_with_mpa_v1 = 0; @@ -1866,15 +1987,15 @@ static int act_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb)  	struct sockaddr_in6 *ra6;  	ep = lookup_atid(t, atid); -	la = (struct sockaddr_in *)&ep->com.local_addr; -	ra = (struct sockaddr_in *)&ep->com.remote_addr; -	la6 = (struct sockaddr_in6 *)&ep->com.local_addr; -	ra6 = (struct sockaddr_in6 *)&ep->com.remote_addr; +	la = (struct sockaddr_in *)&ep->com.mapped_local_addr; +	ra = (struct sockaddr_in *)&ep->com.mapped_remote_addr; +	la6 = (struct sockaddr_in6 *)&ep->com.mapped_local_addr; +	ra6 = (struct sockaddr_in6 *)&ep->com.mapped_remote_addr;  	PDBG("%s ep %p atid %u status %u errno %d\n", __func__, ep, atid,  	     status, status2errno(status)); -	if (status == CPL_ERR_RTX_NEG_ADVICE) { +	if (is_neg_adv(status)) {  		printk(KERN_WARNING MOD "Connection problems for atid %u\n",  			atid);  		return 0; @@ -1982,13 +2103,36 @@ static void accept_cr(struct c4iw_ep *ep, struct sk_buff *skb,  	u64 opt0;  	u32 opt2;  	int wscale; +	struct cpl_t5_pass_accept_rpl *rpl5 = NULL; +	int win;  	PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);  	BUG_ON(skb_cloned(skb)); -	skb_trim(skb, sizeof(*rpl)); +  	skb_get(skb); -	cxgb4_best_mtu(ep->com.dev->rdev.lldi.mtus, ep->mtu, &mtu_idx); +	rpl = cplhdr(skb); +	if (is_t5(ep->com.dev->rdev.lldi.adapter_type)) { +		skb_trim(skb, roundup(sizeof(*rpl5), 16)); +		rpl5 = (void *)rpl; +		INIT_TP_WR(rpl5, ep->hwtid); +	} else { +		skb_trim(skb, sizeof(*rpl)); +		INIT_TP_WR(rpl, ep->hwtid); +	} +	OPCODE_TID(rpl) = cpu_to_be32(MK_OPCODE_TID(CPL_PASS_ACCEPT_RPL, +						    ep->hwtid)); + +	best_mtu(ep->com.dev->rdev.lldi.mtus, ep->mtu, &mtu_idx, +		 enable_tcp_timestamps && req->tcpopt.tstamp);  	wscale = 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_MASK) +		win = RCV_BUFSIZ_MASK;  	opt0 = (nocong ? NO_CONG(1) : 0) |  	       KEEP_ALIVE(1) |  	       DELACK(1) | @@ -1999,7 +2143,7 @@ static void accept_cr(struct c4iw_ep *ep, struct sk_buff *skb,  	       SMAC_SEL(ep->smac_idx) |  	       DSCP(ep->tos >> 2) |  	       ULP_MODE(ULP_MODE_TCPDDP) | -	       RCV_BUFSIZ(rcv_win>>10); +	       RCV_BUFSIZ(win);  	opt2 = RX_CHANNEL(0) |  	       RSS_QUEUE_VALID | RSS_QUEUE(ep->rss_qid); @@ -2018,11 +2162,19 @@ static void accept_cr(struct c4iw_ep *ep, struct sk_buff *skb,  		if (tcph->ece && tcph->cwr)  			opt2 |= CCTRL_ECN(1);  	} +	if (is_t5(ep->com.dev->rdev.lldi.adapter_type)) { +		u32 isn = (prandom_u32() & ~7UL) - 1; +		opt2 |= T5_OPT_2_VALID; +		opt2 |= V_CONG_CNTRL(CONG_ALG_TAHOE); +		opt2 |= CONG_CNTRL_VALID; /* OPT_2_ISS for T5 */ +		rpl5 = (void *)rpl; +		memset(&rpl5->iss, 0, roundup(sizeof(*rpl5)-sizeof(*rpl), 16)); +		if (peer2peer) +			isn += 4; +		rpl5->iss = cpu_to_be32(isn); +		PDBG("%s iss %u\n", __func__, be32_to_cpu(rpl5->iss)); +	} -	rpl = cplhdr(skb); -	INIT_TP_WR(rpl, ep->hwtid); -	OPCODE_TID(rpl) = cpu_to_be32(MK_OPCODE_TID(CPL_PASS_ACCEPT_RPL, -				      ep->hwtid));  	rpl->opt0 = cpu_to_be64(opt0);  	rpl->opt2 = cpu_to_be32(opt2);  	set_wr_txq(skb, CPL_PRIORITY_SETUP, ep->ctrlq_idx); @@ -2037,7 +2189,6 @@ static void reject_cr(struct c4iw_dev *dev, u32 hwtid, struct sk_buff *skb)  	PDBG("%s c4iw_dev %p tid %u\n", __func__, dev, hwtid);  	BUG_ON(skb_cloned(skb));  	skb_trim(skb, sizeof(struct cpl_tid_release)); -	skb_get(skb);  	release_tid(&dev->rdev, hwtid, skb);  	return;  } @@ -2087,6 +2238,7 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb)  	int err;  	u16 peer_mss = ntohs(req->tcpopt.mss);  	int iptype; +	unsigned short hdrs;  	parent_ep = lookup_stid(t, stid);  	if (!parent_ep) { @@ -2144,8 +2296,10 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb)  		goto reject;  	} -	if (peer_mss && child_ep->mtu > (peer_mss + 40)) -		child_ep->mtu = peer_mss + 40; +	hdrs = sizeof(struct iphdr) + sizeof(struct tcphdr) + +	       ((enable_tcp_timestamps && req->tcpopt.tstamp) ? 12 : 0); +	if (peer_mss && child_ep->mtu > (peer_mss + hdrs)) +		child_ep->mtu = peer_mss + hdrs;  	state_set(&child_ep->com, CONNECTING);  	child_ep->com.dev = dev; @@ -2279,13 +2433,13 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)  		disconnect = 0;  		break;  	case MORIBUND: -		stop_ep_timer(ep); +		(void)stop_ep_timer(ep);  		if (ep->com.cm_id && ep->com.qp) {  			attrs.next_state = C4IW_QP_STATE_IDLE;  			c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,  				       C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);  		} -		close_complete_upcall(ep); +		close_complete_upcall(ep, 0);  		__state_set(&ep->com, DEAD);  		release = 1;  		disconnect = 0; @@ -2304,15 +2458,6 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)  	return 0;  } -/* - * Returns whether an ABORT_REQ_RSS message is a negative advice. - */ -static int is_neg_adv_abort(unsigned int status) -{ -	return status == CPL_ERR_RTX_NEG_ADVICE || -	       status == CPL_ERR_PERSIST_NEG_ADVICE; -} -  static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)  {  	struct cpl_abort_req_rss *req = cplhdr(skb); @@ -2326,7 +2471,7 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)  	unsigned int tid = GET_TID(req);  	ep = lookup_tid(t, tid); -	if (is_neg_adv_abort(req->status)) { +	if (is_neg_adv(req->status)) {  		PDBG("%s neg_adv_abort ep %p tid %u\n", __func__, ep,  		     ep->hwtid);  		return 0; @@ -2348,10 +2493,10 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)  	case CONNECTING:  		break;  	case MPA_REQ_WAIT: -		stop_ep_timer(ep); +		(void)stop_ep_timer(ep);  		break;  	case MPA_REQ_SENT: -		stop_ep_timer(ep); +		(void)stop_ep_timer(ep);  		if (mpa_rev == 1 || (mpa_rev == 2 && ep->tried_with_mpa_v1))  			connect_reply_upcall(ep, -ECONNRESET);  		else { @@ -2456,7 +2601,7 @@ static int close_con_rpl(struct c4iw_dev *dev, struct sk_buff *skb)  		__state_set(&ep->com, MORIBUND);  		break;  	case MORIBUND: -		stop_ep_timer(ep); +		(void)stop_ep_timer(ep);  		if ((ep->com.cm_id) && (ep->com.qp)) {  			attrs.next_state = C4IW_QP_STATE_IDLE;  			c4iw_modify_qp(ep->com.qp->rhp, @@ -2464,7 +2609,7 @@ static int close_con_rpl(struct c4iw_dev *dev, struct sk_buff *skb)  					     C4IW_QP_ATTR_NEXT_STATE,  					     &attrs, 1);  		} -		close_complete_upcall(ep); +		close_complete_upcall(ep, 0);  		__state_set(&ep->com, DEAD);  		release = 1;  		break; @@ -2539,22 +2684,28 @@ static int fw4_ack(struct c4iw_dev *dev, struct sk_buff *skb)  int c4iw_reject_cr(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)  { -	int err; +	int err = 0; +	int disconnect = 0;  	struct c4iw_ep *ep = to_ep(cm_id);  	PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid); -	if (state_read(&ep->com) == DEAD) { +	mutex_lock(&ep->com.mutex); +	if (ep->com.state == DEAD) { +		mutex_unlock(&ep->com.mutex);  		c4iw_put_ep(&ep->com);  		return -ECONNRESET;  	}  	set_bit(ULP_REJECT, &ep->com.history); -	BUG_ON(state_read(&ep->com) != MPA_REQ_RCVD); +	BUG_ON(ep->com.state != MPA_REQ_RCVD);  	if (mpa_rev == 0)  		abort_connection(ep, NULL, GFP_KERNEL);  	else {  		err = send_mpa_reject(ep, pdata, pdata_len); -		err = c4iw_ep_disconnect(ep, 0, GFP_KERNEL); +		disconnect = 1;  	} +	mutex_unlock(&ep->com.mutex); +	if (disconnect) +		err = c4iw_ep_disconnect(ep, 0, GFP_KERNEL);  	c4iw_put_ep(&ep->com);  	return 0;  } @@ -2569,12 +2720,14 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)  	struct c4iw_qp *qp = get_qhp(h, conn_param->qpn);  	PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid); -	if (state_read(&ep->com) == DEAD) { + +	mutex_lock(&ep->com.mutex); +	if (ep->com.state == DEAD) {  		err = -ECONNRESET;  		goto err;  	} -	BUG_ON(state_read(&ep->com) != MPA_REQ_RCVD); +	BUG_ON(ep->com.state != MPA_REQ_RCVD);  	BUG_ON(!qp);  	set_bit(ULP_ACCEPT, &ep->com.history); @@ -2643,14 +2796,16 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)  	if (err)  		goto err1; -	state_set(&ep->com, FPDU_MODE); +	__state_set(&ep->com, FPDU_MODE);  	established_upcall(ep); +	mutex_unlock(&ep->com.mutex);  	c4iw_put_ep(&ep->com);  	return 0;  err1:  	ep->com.cm_id = NULL;  	cm_id->rem_ref(cm_id);  err: +	mutex_unlock(&ep->com.mutex);  	c4iw_put_ep(&ep->com);  	return err;  } @@ -2721,13 +2876,15 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)  	struct c4iw_dev *dev = to_c4iw_dev(cm_id->device);  	struct c4iw_ep *ep;  	int err = 0; -	struct sockaddr_in *laddr = (struct sockaddr_in *)&cm_id->local_addr; -	struct sockaddr_in *raddr = (struct sockaddr_in *)&cm_id->remote_addr; -	struct sockaddr_in6 *laddr6 = (struct sockaddr_in6 *)&cm_id->local_addr; -	struct sockaddr_in6 *raddr6 = (struct sockaddr_in6 *) -				      &cm_id->remote_addr; +	struct sockaddr_in *laddr; +	struct sockaddr_in *raddr; +	struct sockaddr_in6 *laddr6; +	struct sockaddr_in6 *raddr6; +	struct iwpm_dev_data pm_reg_msg; +	struct iwpm_sa_data pm_msg;  	__u8 *ra;  	int iptype; +	int iwpm_err = 0;  	if ((conn_param->ord > c4iw_max_read_depth) ||  	    (conn_param->ird > c4iw_max_read_depth)) { @@ -2758,7 +2915,7 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)  	if (!ep->com.qp) {  		PDBG("%s qpn 0x%x not found!\n", __func__, conn_param->qpn);  		err = -EINVAL; -		goto fail2; +		goto fail1;  	}  	ref_qp(ep);  	PDBG("%s qpn 0x%x qp %p cm_id %p\n", __func__, conn_param->qpn, @@ -2771,10 +2928,50 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)  	if (ep->atid == -1) {  		printk(KERN_ERR MOD "%s - cannot alloc atid.\n", __func__);  		err = -ENOMEM; -		goto fail2; +		goto fail1;  	}  	insert_handle(dev, &dev->atid_idr, ep, ep->atid); +	memcpy(&ep->com.local_addr, &cm_id->local_addr, +	       sizeof(ep->com.local_addr)); +	memcpy(&ep->com.remote_addr, &cm_id->remote_addr, +	       sizeof(ep->com.remote_addr)); + +	/* No port mapper available, go with the specified peer information */ +	memcpy(&ep->com.mapped_local_addr, &cm_id->local_addr, +	       sizeof(ep->com.mapped_local_addr)); +	memcpy(&ep->com.mapped_remote_addr, &cm_id->remote_addr, +	       sizeof(ep->com.mapped_remote_addr)); + +	c4iw_form_reg_msg(dev, &pm_reg_msg); +	iwpm_err = iwpm_register_pid(&pm_reg_msg, RDMA_NL_C4IW); +	if (iwpm_err) { +		PDBG("%s: Port Mapper reg pid fail (err = %d).\n", +			__func__, iwpm_err); +	} +	if (iwpm_valid_pid() && !iwpm_err) { +		c4iw_form_pm_msg(ep, &pm_msg); +		iwpm_err = iwpm_add_and_query_mapping(&pm_msg, RDMA_NL_C4IW); +		if (iwpm_err) +			PDBG("%s: Port Mapper query fail (err = %d).\n", +				__func__, iwpm_err); +		else +			c4iw_record_pm_msg(ep, &pm_msg); +	} +	if (iwpm_create_mapinfo(&ep->com.local_addr, +				&ep->com.mapped_local_addr, RDMA_NL_C4IW)) { +		iwpm_remove_mapping(&ep->com.local_addr, RDMA_NL_C4IW); +		err = -ENOMEM; +		goto fail1; +	} +	print_addr(&ep->com, __func__, "add_query/create_mapinfo"); +	set_bit(RELEASE_MAPINFO, &ep->com.flags); + +	laddr = (struct sockaddr_in *)&ep->com.mapped_local_addr; +	raddr = (struct sockaddr_in *)&ep->com.mapped_remote_addr; +	laddr6 = (struct sockaddr_in6 *)&ep->com.mapped_local_addr; +	raddr6 = (struct sockaddr_in6 *) &ep->com.mapped_remote_addr; +  	if (cm_id->remote_addr.ss_family == AF_INET) {  		iptype = 4;  		ra = (__u8 *)&raddr->sin_addr; @@ -2785,7 +2982,7 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)  		if ((__force int)raddr->sin_addr.s_addr == INADDR_ANY) {  			err = pick_local_ipaddrs(dev, cm_id);  			if (err) -				goto fail2; +				goto fail1;  		}  		/* find a route */ @@ -2805,7 +3002,7 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)  		if (ipv6_addr_type(&raddr6->sin6_addr) == IPV6_ADDR_ANY) {  			err = pick_local_ip6addrs(dev, cm_id);  			if (err) -				goto fail2; +				goto fail1;  		}  		/* find a route */ @@ -2821,13 +3018,13 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)  	if (!ep->dst) {  		printk(KERN_ERR MOD "%s - cannot find route.\n", __func__);  		err = -EHOSTUNREACH; -		goto fail3; +		goto fail2;  	}  	err = import_ep(ep, iptype, ra, ep->dst, ep->com.dev, true);  	if (err) {  		printk(KERN_ERR MOD "%s - cannot alloc l2e.\n", __func__); -		goto fail4; +		goto fail3;  	}  	PDBG("%s txq_idx %u tx_chan %u smac_idx %u rss_qid %u l2t_idx %u\n", @@ -2836,10 +3033,6 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)  	state_set(&ep->com, CONNECTING);  	ep->tos = 0; -	memcpy(&ep->com.local_addr, &cm_id->local_addr, -	       sizeof(ep->com.local_addr)); -	memcpy(&ep->com.remote_addr, &cm_id->remote_addr, -	       sizeof(ep->com.remote_addr));  	/* send connect request to rnic */  	err = send_connect(ep); @@ -2847,12 +3040,12 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)  		goto out;  	cxgb4_l2t_release(ep->l2t); -fail4: -	dst_release(ep->dst);  fail3: +	dst_release(ep->dst); +fail2:  	remove_handle(ep->com.dev, &ep->com.dev->atid_idr, ep->atid);  	cxgb4_free_atid(ep->com.dev->rdev.lldi.tids, ep->atid); -fail2: +fail1:  	cm_id->rem_ref(cm_id);  	c4iw_put_ep(&ep->com);  out: @@ -2862,7 +3055,8 @@ out:  static int create_server6(struct c4iw_dev *dev, struct c4iw_listen_ep *ep)  {  	int err; -	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ep->com.local_addr; +	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) +				    &ep->com.mapped_local_addr;  	c4iw_init_wr_wait(&ep->com.wr_wait);  	err = cxgb4_create_server6(ep->com.dev->rdev.lldi.ports[0], @@ -2883,7 +3077,8 @@ static int create_server6(struct c4iw_dev *dev, struct c4iw_listen_ep *ep)  static int create_server4(struct c4iw_dev *dev, struct c4iw_listen_ep *ep)  {  	int err; -	struct sockaddr_in *sin = (struct sockaddr_in *)&ep->com.local_addr; +	struct sockaddr_in *sin = (struct sockaddr_in *) +				  &ep->com.mapped_local_addr;  	if (dev->rdev.lldi.enable_fw_ofld_conn) {  		do { @@ -2918,6 +3113,9 @@ int c4iw_create_listen(struct iw_cm_id *cm_id, int backlog)  	int err = 0;  	struct c4iw_dev *dev = to_c4iw_dev(cm_id->device);  	struct c4iw_listen_ep *ep; +	struct iwpm_dev_data pm_reg_msg; +	struct iwpm_sa_data pm_msg; +	int iwpm_err = 0;  	might_sleep(); @@ -2938,7 +3136,8 @@ int c4iw_create_listen(struct iw_cm_id *cm_id, int backlog)  	/*  	 * Allocate a server TID.  	 */ -	if (dev->rdev.lldi.enable_fw_ofld_conn) +	if (dev->rdev.lldi.enable_fw_ofld_conn && +	    ep->com.local_addr.ss_family == AF_INET)  		ep->stid = cxgb4_alloc_sftid(dev->rdev.lldi.tids,  					     cm_id->local_addr.ss_family, ep);  	else @@ -2951,6 +3150,37 @@ int c4iw_create_listen(struct iw_cm_id *cm_id, int backlog)  		goto fail2;  	}  	insert_handle(dev, &dev->stid_idr, ep, ep->stid); + +	/* No port mapper available, go with the specified info */ +	memcpy(&ep->com.mapped_local_addr, &cm_id->local_addr, +	       sizeof(ep->com.mapped_local_addr)); + +	c4iw_form_reg_msg(dev, &pm_reg_msg); +	iwpm_err = iwpm_register_pid(&pm_reg_msg, RDMA_NL_C4IW); +	if (iwpm_err) { +		PDBG("%s: Port Mapper reg pid fail (err = %d).\n", +			__func__, iwpm_err); +	} +	if (iwpm_valid_pid() && !iwpm_err) { +		memcpy(&pm_msg.loc_addr, &ep->com.local_addr, +				sizeof(ep->com.local_addr)); +		iwpm_err = iwpm_add_mapping(&pm_msg, RDMA_NL_C4IW); +		if (iwpm_err) +			PDBG("%s: Port Mapper query fail (err = %d).\n", +				__func__, iwpm_err); +		else +			memcpy(&ep->com.mapped_local_addr, +				&pm_msg.mapped_loc_addr, +				sizeof(ep->com.mapped_local_addr)); +	} +	if (iwpm_create_mapinfo(&ep->com.local_addr, +				&ep->com.mapped_local_addr, RDMA_NL_C4IW)) { +		err = -ENOMEM; +		goto fail3; +	} +	print_addr(&ep->com, __func__, "add_mapping/create_mapinfo"); + +	set_bit(RELEASE_MAPINFO, &ep->com.flags);  	state_set(&ep->com, LISTEN);  	if (ep->com.local_addr.ss_family == AF_INET)  		err = create_server4(dev, ep); @@ -2960,6 +3190,8 @@ int c4iw_create_listen(struct iw_cm_id *cm_id, int backlog)  		cm_id->provider_data = ep;  		goto out;  	} + +fail3:  	cxgb4_free_stid(ep->com.dev->rdev.lldi.tids, ep->stid,  			ep->com.local_addr.ss_family);  fail2: @@ -3018,7 +3250,7 @@ int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp)  	rdev = &ep->com.dev->rdev;  	if (c4iw_fatal_error(rdev)) {  		fatal = 1; -		close_complete_upcall(ep); +		close_complete_upcall(ep, -EIO);  		ep->com.state = DEAD;  	}  	switch (ep->com.state) { @@ -3040,7 +3272,7 @@ int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp)  		if (!test_and_set_bit(CLOSE_SENT, &ep->com.flags)) {  			close = 1;  			if (abrupt) { -				stop_ep_timer(ep); +				(void)stop_ep_timer(ep);  				ep->com.state = ABORTING;  			} else  				ep->com.state = MORIBUND; @@ -3060,7 +3292,7 @@ int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp)  	if (close) {  		if (abrupt) {  			set_bit(EP_DISC_ABORT, &ep->com.history); -			close_complete_upcall(ep); +			close_complete_upcall(ep, -ECONNRESET);  			ret = send_abort(ep, NULL, gfp);  		} else {  			set_bit(EP_DISC_CLOSE, &ep->com.history); @@ -3241,6 +3473,7 @@ static void send_fw_pass_open_req(struct c4iw_dev *dev, struct sk_buff *skb,  	struct sk_buff *req_skb;  	struct fw_ofld_connection_wr *req;  	struct cpl_pass_accept_req *cpl = cplhdr(skb); +	int ret;  	req_skb = alloc_skb(sizeof(struct fw_ofld_connection_wr), GFP_KERNEL);  	req = (struct fw_ofld_connection_wr *)__skb_put(req_skb, sizeof(*req)); @@ -3277,7 +3510,13 @@ static void send_fw_pass_open_req(struct c4iw_dev *dev, struct sk_buff *skb,  	req->cookie = (unsigned long)skb;  	set_wr_txq(req_skb, CPL_PRIORITY_CONTROL, port_id); -	cxgb4_ofld_send(dev->rdev.lldi.ports[0], req_skb); +	ret = cxgb4_ofld_send(dev->rdev.lldi.ports[0], req_skb); +	if (ret < 0) { +		pr_err("%s - cxgb4_ofld_send error %d - dropping\n", __func__, +		       ret); +		kfree_skb(skb); +		kfree_skb(req_skb); +	}  }  /* @@ -3323,9 +3562,7 @@ static int rx_pkt(struct c4iw_dev *dev, struct sk_buff *skb)  	/*  	 * Calculate the server tid from filter hit index from cpl_rx_pkt.  	 */ -	stid = (__force int) cpu_to_be32((__force u32) rss->hash_val) -					  - dev->rdev.lldi.tids->sftid_base -					  + dev->rdev.lldi.tids->nstids; +	stid = (__force int) cpu_to_be32((__force u32) rss->hash_val);  	lep = (struct c4iw_ep *)lookup_stid(dev->rdev.lldi.tids, stid);  	if (!lep) { @@ -3386,6 +3623,7 @@ static int rx_pkt(struct c4iw_dev *dev, struct sk_buff *skb)  		pi = (struct port_info *)netdev_priv(pdev);  		tx_chan = cxgb4_port_chan(pdev);  	} +	neigh_release(neigh);  	if (!e) {  		pr_err("%s - failed to allocate l2t entry!\n",  		       __func__); @@ -3397,7 +3635,9 @@ static int rx_pkt(struct c4iw_dev *dev, struct sk_buff *skb)  	window = (__force u16) htons((__force u16)tcph->window);  	/* Calcuate filter portion for LE region. */ -	filter = (__force unsigned int) cpu_to_be32(select_ntuple(dev, dst, e)); +	filter = (__force unsigned int) cpu_to_be32(cxgb4_select_ntuple( +						    dev->rdev.lldi.ports[0], +						    e));  	/*  	 * Synthesize the cpl_pass_accept_req. We have everything except the @@ -3464,15 +3704,26 @@ static void process_timeout(struct c4iw_ep *ep)  				     &attrs, 1);  		}  		__state_set(&ep->com, ABORTING); +		close_complete_upcall(ep, -ETIMEDOUT); +		break; +	case ABORTING: +	case DEAD: + +		/* +		 * These states are expected if the ep timed out at the same +		 * time as another thread was calling stop_ep_timer(). +		 * So we silently do nothing for these states. +		 */ +		abort = 0;  		break;  	default:  		WARN(1, "%s unexpected state ep %p tid %u state %u\n",  			__func__, ep, ep->hwtid, ep->com.state);  		abort = 0;  	} -	mutex_unlock(&ep->com.mutex);  	if (abort)  		abort_connection(ep, NULL, GFP_KERNEL); +	mutex_unlock(&ep->com.mutex);  	c4iw_put_ep(&ep->com);  } @@ -3486,6 +3737,8 @@ static void process_timedout_eps(void)  		tmp = timeout_list.next;  		list_del(tmp); +		tmp->next = NULL; +		tmp->prev = NULL;  		spin_unlock_irq(&timeout_lock);  		ep = list_entry(tmp, struct c4iw_ep, entry);  		process_timeout(ep); @@ -3502,6 +3755,7 @@ static void process_work(struct work_struct *work)  	unsigned int opcode;  	int ret; +	process_timedout_eps();  	while ((skb = skb_dequeue(&rxq))) {  		rpl = cplhdr(skb);  		dev = *((struct c4iw_dev **) (skb->cb + sizeof(void *))); @@ -3511,8 +3765,8 @@ static void process_work(struct work_struct *work)  		ret = work_handlers[opcode](dev, skb);  		if (!ret)  			kfree_skb(skb); +		process_timedout_eps();  	} -	process_timedout_eps();  }  static DECLARE_WORK(skb_work, process_work); @@ -3524,8 +3778,13 @@ static void ep_timeout(unsigned long arg)  	spin_lock(&timeout_lock);  	if (!test_and_set_bit(TIMEOUT, &ep->com.flags)) { -		list_add_tail(&ep->entry, &timeout_list); -		kickit = 1; +		/* +		 * Only insert if it is not already on the list. +		 */ +		if (!ep->entry.next) { +			list_add_tail(&ep->entry, &timeout_list); +			kickit = 1; +		}  	}  	spin_unlock(&timeout_lock);  	if (kickit) @@ -3607,7 +3866,7 @@ static int peer_abort_intr(struct c4iw_dev *dev, struct sk_buff *skb)  		kfree_skb(skb);  		return 0;  	} -	if (is_neg_adv_abort(req->status)) { +	if (is_neg_adv(req->status)) {  		PDBG("%s neg_adv_abort ep %p tid %u\n", __func__, ep,  		     ep->hwtid);  		kfree_skb(skb); @@ -3666,7 +3925,7 @@ int __init c4iw_cm_init(void)  	return 0;  } -void __exit c4iw_cm_term(void) +void c4iw_cm_term(void)  {  	WARN_ON(!list_empty(&timeout_list));  	flush_workqueue(workq);  | 
