Commit 6492cdf3 authored by Faisal Latif's avatar Faisal Latif Committed by Roland Dreier

RDMA/nes: CM connection setup/teardown rework

Major rework of CM connection setup/teardown.  We had a number of issues
with MPI applications not starting/terminating properly over time.
With these changes we were able to run longer on larger clusters.

* Remove memory allocation from nes_connect() and nes_cm_connect().
* Fix mini_cm_dec_refcnt_listen() when destroying listener.
* Remove unnecessary code from schedule_nes_timer() and nes_cm_timer_tick().
* Functionalize mini_cm_recv_pkt() and process_packet().
* Clean up cm_node->ref_count usage.
* Reuse skbs if available.
Signed-off-by: default avatarFaisal Latif <flatif@neteffect.com>
Signed-off-by: default avatarRoland Dreier <rolandd@cisco.com>
parent fb2e405f
...@@ -276,6 +276,7 @@ static void nes_cqp_rem_ref_callback(struct nes_device *nesdev, struct nes_cqp_r ...@@ -276,6 +276,7 @@ static void nes_cqp_rem_ref_callback(struct nes_device *nesdev, struct nes_cqp_r
} }
nes_free_resource(nesadapter, nesadapter->allocated_qps, nesqp->hwqp.qp_id); nes_free_resource(nesadapter, nesadapter->allocated_qps, nesqp->hwqp.qp_id);
nesadapter->qp_table[nesqp->hwqp.qp_id-NES_FIRST_QPN] = NULL;
kfree(nesqp->allocated_buffer); kfree(nesqp->allocated_buffer);
} }
...@@ -289,7 +290,6 @@ void nes_rem_ref(struct ib_qp *ibqp) ...@@ -289,7 +290,6 @@ void nes_rem_ref(struct ib_qp *ibqp)
struct nes_qp *nesqp; struct nes_qp *nesqp;
struct nes_vnic *nesvnic = to_nesvnic(ibqp->device); struct nes_vnic *nesvnic = to_nesvnic(ibqp->device);
struct nes_device *nesdev = nesvnic->nesdev; struct nes_device *nesdev = nesvnic->nesdev;
struct nes_adapter *nesadapter = nesdev->nesadapter;
struct nes_hw_cqp_wqe *cqp_wqe; struct nes_hw_cqp_wqe *cqp_wqe;
struct nes_cqp_request *cqp_request; struct nes_cqp_request *cqp_request;
u32 opcode; u32 opcode;
...@@ -303,8 +303,6 @@ void nes_rem_ref(struct ib_qp *ibqp) ...@@ -303,8 +303,6 @@ void nes_rem_ref(struct ib_qp *ibqp)
} }
if (atomic_dec_and_test(&nesqp->refcount)) { if (atomic_dec_and_test(&nesqp->refcount)) {
nesadapter->qp_table[nesqp->hwqp.qp_id-NES_FIRST_QPN] = NULL;
/* Destroy the QP */ /* Destroy the QP */
cqp_request = nes_get_cqp_request(nesdev); cqp_request = nes_get_cqp_request(nesdev);
if (cqp_request == NULL) { if (cqp_request == NULL) {
......
...@@ -74,36 +74,59 @@ atomic_t cm_nodes_destroyed; ...@@ -74,36 +74,59 @@ atomic_t cm_nodes_destroyed;
atomic_t cm_accel_dropped_pkts; atomic_t cm_accel_dropped_pkts;
atomic_t cm_resets_recvd; atomic_t cm_resets_recvd;
static inline int mini_cm_accelerated(struct nes_cm_core *, struct nes_cm_node *); static inline int mini_cm_accelerated(struct nes_cm_core *,
struct nes_cm_node *);
static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *, static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *,
struct nes_vnic *, struct nes_cm_info *); struct nes_vnic *, struct nes_cm_info *);
static int add_ref_cm_node(struct nes_cm_node *);
static int rem_ref_cm_node(struct nes_cm_core *, struct nes_cm_node *);
static int mini_cm_del_listen(struct nes_cm_core *, struct nes_cm_listener *); static int mini_cm_del_listen(struct nes_cm_core *, struct nes_cm_listener *);
static struct sk_buff *form_cm_frame(struct sk_buff *, struct nes_cm_node *,
void *, u32, void *, u32, u8);
static struct sk_buff *get_free_pkt(struct nes_cm_node *cm_node);
static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *, static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *,
struct nes_vnic *, struct nes_vnic *, u16, void *, struct nes_cm_info *);
struct ietf_mpa_frame *, static int mini_cm_close(struct nes_cm_core *, struct nes_cm_node *);
struct nes_cm_info *);
static int mini_cm_accept(struct nes_cm_core *, struct ietf_mpa_frame *, static int mini_cm_accept(struct nes_cm_core *, struct ietf_mpa_frame *,
struct nes_cm_node *); struct nes_cm_node *);
static int mini_cm_reject(struct nes_cm_core *, struct ietf_mpa_frame *, static int mini_cm_reject(struct nes_cm_core *, struct ietf_mpa_frame *,
struct nes_cm_node *); struct nes_cm_node *);
static int mini_cm_close(struct nes_cm_core *, struct nes_cm_node *); static void mini_cm_recv_pkt(struct nes_cm_core *, struct nes_vnic *,
static int mini_cm_recv_pkt(struct nes_cm_core *, struct nes_vnic *, struct sk_buff *);
struct sk_buff *);
static int mini_cm_dealloc_core(struct nes_cm_core *); static int mini_cm_dealloc_core(struct nes_cm_core *);
static int mini_cm_get(struct nes_cm_core *); static int mini_cm_get(struct nes_cm_core *);
static int mini_cm_set(struct nes_cm_core *, u32, u32); static int mini_cm_set(struct nes_cm_core *, u32, u32);
static struct sk_buff *form_cm_frame(struct sk_buff *, struct nes_cm_node *,
void *, u32, void *, u32, u8);
static struct sk_buff *get_free_pkt(struct nes_cm_node *cm_node);
static int add_ref_cm_node(struct nes_cm_node *);
static int rem_ref_cm_node(struct nes_cm_core *, struct nes_cm_node *);
static int nes_cm_disconn_true(struct nes_qp *); static int nes_cm_disconn_true(struct nes_qp *);
static int nes_cm_post_event(struct nes_cm_event *event); static int nes_cm_post_event(struct nes_cm_event *event);
static int nes_disconnect(struct nes_qp *nesqp, int abrupt); static int nes_disconnect(struct nes_qp *nesqp, int abrupt);
static void nes_disconnect_worker(struct work_struct *work); static void nes_disconnect_worker(struct work_struct *work);
static int send_ack(struct nes_cm_node *cm_node);
static int send_mpa_request(struct nes_cm_node *, struct sk_buff *);
static int send_syn(struct nes_cm_node *, u32, struct sk_buff *);
static int send_reset(struct nes_cm_node *, struct sk_buff *);
static int send_ack(struct nes_cm_node *cm_node, struct sk_buff *skb);
static int send_fin(struct nes_cm_node *cm_node, struct sk_buff *skb); static int send_fin(struct nes_cm_node *cm_node, struct sk_buff *skb);
static void process_packet(struct nes_cm_node *, struct sk_buff *,
struct nes_cm_core *);
static void active_open_err(struct nes_cm_node *, struct sk_buff *, int);
static void passive_open_err(struct nes_cm_node *, struct sk_buff *, int);
static void cleanup_retrans_entry(struct nes_cm_node *);
static void handle_rcv_mpa(struct nes_cm_node *, struct sk_buff *,
enum nes_cm_event_type);
static void free_retrans_entry(struct nes_cm_node *cm_node);
static int handle_tcp_options(struct nes_cm_node *cm_node, struct tcphdr *tcph,
struct sk_buff *skb, int optionsize, int passive);
/* CM event handler functions */
static void cm_event_connected(struct nes_cm_event *);
static void cm_event_connect_error(struct nes_cm_event *);
static void cm_event_reset(struct nes_cm_event *);
static void cm_event_mpa_req(struct nes_cm_event *);
static void print_core(struct nes_cm_core *core);
/* External CM API Interface */ /* External CM API Interface */
/* instance of function pointers for client API */ /* instance of function pointers for client API */
...@@ -158,11 +181,11 @@ static struct nes_cm_event *create_event(struct nes_cm_node *cm_node, ...@@ -158,11 +181,11 @@ static struct nes_cm_event *create_event(struct nes_cm_node *cm_node,
event->cm_info.loc_port = cm_node->loc_port; event->cm_info.loc_port = cm_node->loc_port;
event->cm_info.cm_id = cm_node->cm_id; event->cm_info.cm_id = cm_node->cm_id;
nes_debug(NES_DBG_CM, "Created event=%p, type=%u, dst_addr=%08x[%x]," nes_debug(NES_DBG_CM, "cm_node=%p Created event=%p, type=%u, "
" src_addr=%08x[%x]\n", "dst_addr=%08x[%x], src_addr=%08x[%x]\n",
event, type, cm_node, event, type, event->cm_info.loc_addr,
event->cm_info.loc_addr, event->cm_info.loc_port, event->cm_info.loc_port, event->cm_info.rem_addr,
event->cm_info.rem_addr, event->cm_info.rem_port); event->cm_info.rem_port);
nes_cm_post_event(event); nes_cm_post_event(event);
return event; return event;
...@@ -172,14 +195,11 @@ static struct nes_cm_event *create_event(struct nes_cm_node *cm_node, ...@@ -172,14 +195,11 @@ static struct nes_cm_event *create_event(struct nes_cm_node *cm_node,
/** /**
* send_mpa_request * send_mpa_request
*/ */
static int send_mpa_request(struct nes_cm_node *cm_node) static int send_mpa_request(struct nes_cm_node *cm_node, struct sk_buff *skb)
{ {
struct sk_buff *skb;
int ret; int ret;
skb = get_free_pkt(cm_node);
if (!skb) { if (!skb) {
nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n"); nes_debug(NES_DBG_CM, "skb set to NULL\n");
return -1; return -1;
} }
...@@ -188,9 +208,8 @@ static int send_mpa_request(struct nes_cm_node *cm_node) ...@@ -188,9 +208,8 @@ static int send_mpa_request(struct nes_cm_node *cm_node)
cm_node->mpa_frame_size, SET_ACK); cm_node->mpa_frame_size, SET_ACK);
ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0); ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0);
if (ret < 0) { if (ret < 0)
return ret; return ret;
}
return 0; return 0;
} }
...@@ -228,47 +247,13 @@ static int parse_mpa(struct nes_cm_node *cm_node, u8 *buffer, u32 len) ...@@ -228,47 +247,13 @@ static int parse_mpa(struct nes_cm_node *cm_node, u8 *buffer, u32 len)
} }
/**
* handle_exception_pkt - process an exception packet.
* We have been in a TSA state, and we have now received SW
* TCP/IP traffic should be a FIN request or IP pkt with options
*/
static int handle_exception_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb)
{
int ret = 0;
struct tcphdr *tcph = tcp_hdr(skb);
/* first check to see if this a FIN pkt */
if (tcph->fin) {
/* we need to ACK the FIN request */
send_ack(cm_node);
/* check which side we are (client/server) and set next state accordingly */
if (cm_node->tcp_cntxt.client)
cm_node->state = NES_CM_STATE_CLOSING;
else {
/* we are the server side */
cm_node->state = NES_CM_STATE_CLOSE_WAIT;
/* since this is a self contained CM we don't wait for */
/* an APP to close us, just send final FIN immediately */
ret = send_fin(cm_node, NULL);
cm_node->state = NES_CM_STATE_LAST_ACK;
}
} else {
ret = -EINVAL;
}
return ret;
}
/** /**
* form_cm_frame - get a free packet and build empty frame Use * form_cm_frame - get a free packet and build empty frame Use
* node info to build. * node info to build.
*/ */
static struct sk_buff *form_cm_frame(struct sk_buff *skb, struct nes_cm_node *cm_node, static struct sk_buff *form_cm_frame(struct sk_buff *skb,
void *options, u32 optionsize, void *data, struct nes_cm_node *cm_node, void *options, u32 optionsize,
u32 datasize, u8 flags) void *data, u32 datasize, u8 flags)
{ {
struct tcphdr *tcph; struct tcphdr *tcph;
struct iphdr *iph; struct iphdr *iph;
...@@ -332,10 +317,12 @@ static struct sk_buff *form_cm_frame(struct sk_buff *skb, struct nes_cm_node *cm ...@@ -332,10 +317,12 @@ static struct sk_buff *form_cm_frame(struct sk_buff *skb, struct nes_cm_node *cm
cm_node->tcp_cntxt.loc_seq_num++; cm_node->tcp_cntxt.loc_seq_num++;
tcph->syn = 1; tcph->syn = 1;
} else } else
cm_node->tcp_cntxt.loc_seq_num += datasize; /* data (no headers) */ cm_node->tcp_cntxt.loc_seq_num += datasize;
if (flags & SET_FIN) if (flags & SET_FIN) {
cm_node->tcp_cntxt.loc_seq_num++;
tcph->fin = 1; tcph->fin = 1;
}
if (flags & SET_RST) if (flags & SET_RST)
tcph->rst = 1; tcph->rst = 1;
...@@ -389,7 +376,7 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb, ...@@ -389,7 +376,7 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb,
int close_when_complete) int close_when_complete)
{ {
unsigned long flags; unsigned long flags;
struct nes_cm_core *cm_core; struct nes_cm_core *cm_core = cm_node->cm_core;
struct nes_timer_entry *new_send; struct nes_timer_entry *new_send;
int ret = 0; int ret = 0;
u32 was_timer_set; u32 was_timer_set;
...@@ -411,7 +398,7 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb, ...@@ -411,7 +398,7 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb,
new_send->close_when_complete = close_when_complete; new_send->close_when_complete = close_when_complete;
if (type == NES_TIMER_TYPE_CLOSE) { if (type == NES_TIMER_TYPE_CLOSE) {
new_send->timetosend += (HZ/2); /* TODO: decide on the correct value here */ new_send->timetosend += (HZ/10);
spin_lock_irqsave(&cm_node->recv_list_lock, flags); spin_lock_irqsave(&cm_node->recv_list_lock, flags);
list_add_tail(&new_send->list, &cm_node->recv_list); list_add_tail(&new_send->list, &cm_node->recv_list);
spin_unlock_irqrestore(&cm_node->recv_list_lock, flags); spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
...@@ -420,36 +407,28 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb, ...@@ -420,36 +407,28 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb,
if (type == NES_TIMER_TYPE_SEND) { if (type == NES_TIMER_TYPE_SEND) {
new_send->seq_num = ntohl(tcp_hdr(skb)->seq); new_send->seq_num = ntohl(tcp_hdr(skb)->seq);
atomic_inc(&new_send->skb->users); atomic_inc(&new_send->skb->users);
spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
cm_node->send_entry = new_send;
add_ref_cm_node(cm_node);
spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
new_send->timetosend = jiffies + NES_RETRY_TIMEOUT;
ret = nes_nic_cm_xmit(new_send->skb, cm_node->netdev); ret = nes_nic_cm_xmit(new_send->skb, cm_node->netdev);
if (ret != NETDEV_TX_OK) { if (ret != NETDEV_TX_OK) {
nes_debug(NES_DBG_CM, "Error sending packet %p (jiffies = %lu)\n", nes_debug(NES_DBG_CM, "Error sending packet %p "
new_send, jiffies); "(jiffies = %lu)\n", new_send, jiffies);
atomic_dec(&new_send->skb->users); atomic_dec(&new_send->skb->users);
new_send->timetosend = jiffies; new_send->timetosend = jiffies;
} else { } else {
cm_packets_sent++; cm_packets_sent++;
if (!send_retrans) { if (!send_retrans) {
cleanup_retrans_entry(cm_node);
if (close_when_complete) if (close_when_complete)
rem_ref_cm_node(cm_node->cm_core, cm_node); rem_ref_cm_node(cm_core, cm_node);
dev_kfree_skb_any(new_send->skb);
kfree(new_send);
return ret; return ret;
} }
new_send->timetosend = jiffies + NES_RETRY_TIMEOUT;
} }
spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
list_add_tail(&new_send->list, &cm_node->retrans_list);
spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
}
if (type == NES_TIMER_TYPE_RECV) {
new_send->seq_num = ntohl(tcp_hdr(skb)->seq);
new_send->timetosend = jiffies;
spin_lock_irqsave(&cm_node->recv_list_lock, flags);
list_add_tail(&new_send->list, &cm_node->recv_list);
spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
} }
cm_core = cm_node->cm_core;
was_timer_set = timer_pending(&cm_core->tcp_timer); was_timer_set = timer_pending(&cm_core->tcp_timer);
...@@ -476,23 +455,27 @@ static void nes_cm_timer_tick(unsigned long pass) ...@@ -476,23 +455,27 @@ static void nes_cm_timer_tick(unsigned long pass)
struct list_head *list_node, *list_node_temp; struct list_head *list_node, *list_node_temp;
struct nes_cm_core *cm_core = g_cm_core; struct nes_cm_core *cm_core = g_cm_core;
struct nes_qp *nesqp; struct nes_qp *nesqp;
struct sk_buff *skb;
u32 settimer = 0; u32 settimer = 0;
int ret = NETDEV_TX_OK; int ret = NETDEV_TX_OK;
int node_done; enum nes_cm_node_state last_state;
spin_lock_irqsave(&cm_core->ht_lock, flags); spin_lock_irqsave(&cm_core->ht_lock, flags);
list_for_each_safe(list_node, list_core_temp, &cm_core->connected_nodes) { list_for_each_safe(list_node, list_core_temp,
&cm_core->connected_nodes) {
cm_node = container_of(list_node, struct nes_cm_node, list); cm_node = container_of(list_node, struct nes_cm_node, list);
add_ref_cm_node(cm_node); add_ref_cm_node(cm_node);
spin_unlock_irqrestore(&cm_core->ht_lock, flags); spin_unlock_irqrestore(&cm_core->ht_lock, flags);
spin_lock_irqsave(&cm_node->recv_list_lock, flags); spin_lock_irqsave(&cm_node->recv_list_lock, flags);
list_for_each_safe(list_core, list_node_temp, &cm_node->recv_list) { list_for_each_safe(list_core, list_node_temp,
recv_entry = container_of(list_core, struct nes_timer_entry, list); &cm_node->recv_list) {
if ((time_after(recv_entry->timetosend, jiffies)) && recv_entry = container_of(list_core,
(recv_entry->type == NES_TIMER_TYPE_CLOSE)) { struct nes_timer_entry, list);
if (nexttimeout > recv_entry->timetosend || !settimer) { if (!recv_entry)
break;
if (time_after(recv_entry->timetosend, jiffies)) {
if (nexttimeout > recv_entry->timetosend ||
!settimer) {
nexttimeout = recv_entry->timetosend; nexttimeout = recv_entry->timetosend;
settimer = 1; settimer = 1;
} }
...@@ -501,157 +484,143 @@ static void nes_cm_timer_tick(unsigned long pass) ...@@ -501,157 +484,143 @@ static void nes_cm_timer_tick(unsigned long pass)
list_del(&recv_entry->list); list_del(&recv_entry->list);
cm_id = cm_node->cm_id; cm_id = cm_node->cm_id;
spin_unlock_irqrestore(&cm_node->recv_list_lock, flags); spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
if (recv_entry->type == NES_TIMER_TYPE_CLOSE) { nesqp = (struct nes_qp *)recv_entry->skb;
nesqp = (struct nes_qp *)recv_entry->skb; spin_lock_irqsave(&nesqp->lock, qplockflags);
spin_lock_irqsave(&nesqp->lock, qplockflags); if (nesqp->cm_id) {
if (nesqp->cm_id) { nes_debug(NES_DBG_CM, "QP%u: cm_id = %p, "
nes_debug(NES_DBG_CM, "QP%u: cm_id = %p, refcount = %d: " "refcount = %d: HIT A "
"****** HIT A NES_TIMER_TYPE_CLOSE" "NES_TIMER_TYPE_CLOSE with something "
" with something to do!!! ******\n", "to do!!!\n", nesqp->hwqp.qp_id, cm_id,
nesqp->hwqp.qp_id, cm_id, atomic_read(&nesqp->refcount));
atomic_read(&nesqp->refcount)); nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED; nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT;
nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT; nesqp->ibqp_state = IB_QPS_ERR;
nesqp->ibqp_state = IB_QPS_ERR; spin_unlock_irqrestore(&nesqp->lock,
spin_unlock_irqrestore(&nesqp->lock, qplockflags); qplockflags);
nes_cm_disconn(nesqp); nes_cm_disconn(nesqp);
} else { } else {
spin_unlock_irqrestore(&nesqp->lock, qplockflags); spin_unlock_irqrestore(&nesqp->lock,
nes_debug(NES_DBG_CM, "QP%u: cm_id = %p, refcount = %d:" qplockflags);
" ****** HIT A NES_TIMER_TYPE_CLOSE" nes_debug(NES_DBG_CM, "QP%u: cm_id = %p, "
" with nothing to do!!! ******\n", "refcount = %d: HIT A "
nesqp->hwqp.qp_id, cm_id, "NES_TIMER_TYPE_CLOSE with nothing "
atomic_read(&nesqp->refcount)); "to do!!!\n", nesqp->hwqp.qp_id, cm_id,
nes_rem_ref(&nesqp->ibqp); atomic_read(&nesqp->refcount));
}
if (cm_id)
cm_id->rem_ref(cm_id);
} }
if (cm_id)
cm_id->rem_ref(cm_id);
kfree(recv_entry); kfree(recv_entry);
spin_lock_irqsave(&cm_node->recv_list_lock, flags); spin_lock_irqsave(&cm_node->recv_list_lock, flags);
} }
spin_unlock_irqrestore(&cm_node->recv_list_lock, flags); spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
spin_lock_irqsave(&cm_node->retrans_list_lock, flags); spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
node_done = 0; do {
list_for_each_safe(list_core, list_node_temp, &cm_node->retrans_list) { send_entry = cm_node->send_entry;
if (node_done) { if (!send_entry)
break; continue;
}
send_entry = container_of(list_core, struct nes_timer_entry, list);
if (time_after(send_entry->timetosend, jiffies)) { if (time_after(send_entry->timetosend, jiffies)) {
if (cm_node->state != NES_CM_STATE_TSA) { if (cm_node->state != NES_CM_STATE_TSA) {
if ((nexttimeout > send_entry->timetosend) || !settimer) { if ((nexttimeout >
nexttimeout = send_entry->timetosend; send_entry->timetosend) ||
!settimer) {
nexttimeout =
send_entry->timetosend;
settimer = 1; settimer = 1;
continue;
} }
node_done = 1;
continue;
} else { } else {
list_del(&send_entry->list); free_retrans_entry(cm_node);
skb = send_entry->skb;
spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
dev_kfree_skb_any(skb);
kfree(send_entry);
spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
continue; continue;
} }
} }
if (send_entry->type == NES_TIMER_NODE_CLEANUP) {
list_del(&send_entry->list); if ((cm_node->state == NES_CM_STATE_TSA) ||
spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); (cm_node->state == NES_CM_STATE_CLOSED)) {
kfree(send_entry); free_retrans_entry(cm_node);
spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
continue;
}
if ((send_entry->seq_num < cm_node->tcp_cntxt.rem_ack_num) ||
(cm_node->state == NES_CM_STATE_TSA) ||
(cm_node->state == NES_CM_STATE_CLOSED)) {
skb = send_entry->skb;
list_del(&send_entry->list);
spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
kfree(send_entry);
dev_kfree_skb_any(skb);
spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
continue; continue;
} }
if (!send_entry->retranscount || !send_entry->retrycount) { if (!send_entry->retranscount ||
!send_entry->retrycount) {
cm_packets_dropped++; cm_packets_dropped++;
skb = send_entry->skb; last_state = cm_node->state;
list_del(&send_entry->list); cm_node->state = NES_CM_STATE_CLOSED;
spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); free_retrans_entry(cm_node);
dev_kfree_skb_any(skb); spin_unlock_irqrestore(
kfree(send_entry); &cm_node->retrans_list_lock, flags);
if (cm_node->state == NES_CM_STATE_SYN_RCVD) { if (last_state == NES_CM_STATE_SYN_RCVD)
/* this node never even generated an indication up to the cm */
rem_ref_cm_node(cm_core, cm_node); rem_ref_cm_node(cm_core, cm_node);
} else { else
cm_node->state = NES_CM_STATE_CLOSED; create_event(cm_node,
create_event(cm_node, NES_CM_EVENT_ABORTED); NES_CM_EVENT_ABORTED);
} spin_lock_irqsave(&cm_node->retrans_list_lock,
spin_lock_irqsave(&cm_node->retrans_list_lock, flags); flags);
continue; continue;
} }
/* this seems like the correct place, but leave send entry unprotected */
/* spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); */
atomic_inc(&send_entry->skb->users); atomic_inc(&send_entry->skb->users);
cm_packets_retrans++; cm_packets_retrans++;
nes_debug(NES_DBG_CM, "Retransmitting send_entry %p for node %p," nes_debug(NES_DBG_CM, "Retransmitting send_entry %p "
" jiffies = %lu, time to send = %lu, retranscount = %u, " "for node %p, jiffies = %lu, time to send = "
"send_entry->seq_num = 0x%08X, cm_node->tcp_cntxt.rem_ack_num = 0x%08X\n", "%lu, retranscount = %u, send_entry->seq_num = "
send_entry, cm_node, jiffies, send_entry->timetosend, send_entry->retranscount, "0x%08X, cm_node->tcp_cntxt.rem_ack_num = "
send_entry->seq_num, cm_node->tcp_cntxt.rem_ack_num); "0x%08X\n", send_entry, cm_node, jiffies,
send_entry->timetosend,
spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); send_entry->retranscount,
send_entry->seq_num,
cm_node->tcp_cntxt.rem_ack_num);
spin_unlock_irqrestore(&cm_node->retrans_list_lock,
flags);
ret = nes_nic_cm_xmit(send_entry->skb, cm_node->netdev); ret = nes_nic_cm_xmit(send_entry->skb, cm_node->netdev);
spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
if (ret != NETDEV_TX_OK) { if (ret != NETDEV_TX_OK) {
nes_debug(NES_DBG_CM, "rexmit failed for "
"node=%p\n", cm_node);
cm_packets_bounced++; cm_packets_bounced++;
atomic_dec(&send_entry->skb->users); atomic_dec(&send_entry->skb->users);
send_entry->retrycount--; send_entry->retrycount--;
nexttimeout = jiffies + NES_SHORT_TIME; nexttimeout = jiffies + NES_SHORT_TIME;
settimer = 1; settimer = 1;
node_done = 1;
spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
continue; continue;
} else { } else {
cm_packets_sent++; cm_packets_sent++;
} }
spin_lock_irqsave(&cm_node->retrans_list_lock, flags); nes_debug(NES_DBG_CM, "Packet Sent: retrans count = "
list_del(&send_entry->list); "%u, retry count = %u.\n",
nes_debug(NES_DBG_CM, "Packet Sent: retrans count = %u, retry count = %u.\n", send_entry->retranscount,
send_entry->retranscount, send_entry->retrycount); send_entry->retrycount);
if (send_entry->send_retrans) { if (send_entry->send_retrans) {
send_entry->retranscount--; send_entry->retranscount--;
send_entry->timetosend = jiffies + NES_RETRY_TIMEOUT; send_entry->timetosend = jiffies +
if (nexttimeout > send_entry->timetosend || !settimer) { NES_RETRY_TIMEOUT;
if (nexttimeout > send_entry->timetosend ||
!settimer) {
nexttimeout = send_entry->timetosend; nexttimeout = send_entry->timetosend;
settimer = 1; settimer = 1;
} }
list_add(&send_entry->list, &cm_node->retrans_list);
continue;
} else { } else {
int close_when_complete; int close_when_complete;
skb = send_entry->skb; close_when_complete =
close_when_complete = send_entry->close_when_complete; send_entry->close_when_complete;
spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); nes_debug(NES_DBG_CM, "cm_node=%p state=%d\n",
if (close_when_complete) { cm_node, cm_node->state);
BUG_ON(atomic_read(&cm_node->ref_count) == 1); free_retrans_entry(cm_node);
rem_ref_cm_node(cm_core, cm_node); if (close_when_complete)
} rem_ref_cm_node(cm_node->cm_core,
dev_kfree_skb_any(skb); cm_node);
kfree(send_entry);
spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
continue;
} }
} } while (0);
spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
rem_ref_cm_node(cm_core, cm_node);
spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
rem_ref_cm_node(cm_node->cm_core, cm_node);
spin_lock_irqsave(&cm_core->ht_lock, flags); spin_lock_irqsave(&cm_core->ht_lock, flags);
if (ret != NETDEV_TX_OK) if (ret != NETDEV_TX_OK) {
nes_debug(NES_DBG_CM, "rexmit failed for cm_node=%p\n",
cm_node);
break; break;
}
} }
spin_unlock_irqrestore(&cm_core->ht_lock, flags); spin_unlock_irqrestore(&cm_core->ht_lock, flags);
...@@ -667,14 +636,14 @@ static void nes_cm_timer_tick(unsigned long pass) ...@@ -667,14 +636,14 @@ static void nes_cm_timer_tick(unsigned long pass)
/** /**
* send_syn * send_syn
*/ */
static int send_syn(struct nes_cm_node *cm_node, u32 sendack) static int send_syn(struct nes_cm_node *cm_node, u32 sendack,
struct sk_buff *skb)
{ {
int ret; int ret;
int flags = SET_SYN; int flags = SET_SYN;
struct sk_buff *skb;
char optionsbuffer[sizeof(struct option_mss) + char optionsbuffer[sizeof(struct option_mss) +
sizeof(struct option_windowscale) + sizeof(struct option_windowscale) + sizeof(struct option_base) +
sizeof(struct option_base) + 1]; TCP_OPTIONS_PADDING];
int optionssize = 0; int optionssize = 0;
/* Sending MSS option */ /* Sending MSS option */
...@@ -695,8 +664,7 @@ static int send_syn(struct nes_cm_node *cm_node, u32 sendack) ...@@ -695,8 +664,7 @@ static int send_syn(struct nes_cm_node *cm_node, u32 sendack)
options->as_windowscale.shiftcount = cm_node->tcp_cntxt.rcv_wscale; options->as_windowscale.shiftcount = cm_node->tcp_cntxt.rcv_wscale;
optionssize += sizeof(struct option_windowscale); optionssize += sizeof(struct option_windowscale);
if (sendack && !(NES_DRV_OPT_SUPRESS_OPTION_BC & nes_drv_opt) if (sendack && !(NES_DRV_OPT_SUPRESS_OPTION_BC & nes_drv_opt)) {
) {
options = (union all_known_options *)&optionsbuffer[optionssize]; options = (union all_known_options *)&optionsbuffer[optionssize];
options->as_base.optionnum = OPTION_NUMBER_WRITE0; options->as_base.optionnum = OPTION_NUMBER_WRITE0;
options->as_base.length = sizeof(struct option_base); options->as_base.length = sizeof(struct option_base);
...@@ -714,7 +682,8 @@ static int send_syn(struct nes_cm_node *cm_node, u32 sendack) ...@@ -714,7 +682,8 @@ static int send_syn(struct nes_cm_node *cm_node, u32 sendack)
options->as_end = OPTION_NUMBER_END; options->as_end = OPTION_NUMBER_END;
optionssize += 1; optionssize += 1;
skb = get_free_pkt(cm_node); if (!skb)
skb = get_free_pkt(cm_node);
if (!skb) { if (!skb) {
nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n"); nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
return -1; return -1;
...@@ -733,18 +702,18 @@ static int send_syn(struct nes_cm_node *cm_node, u32 sendack) ...@@ -733,18 +702,18 @@ static int send_syn(struct nes_cm_node *cm_node, u32 sendack)
/** /**
* send_reset * send_reset
*/ */
static int send_reset(struct nes_cm_node *cm_node) static int send_reset(struct nes_cm_node *cm_node, struct sk_buff *skb)
{ {
int ret; int ret;
struct sk_buff *skb = get_free_pkt(cm_node);
int flags = SET_RST | SET_ACK; int flags = SET_RST | SET_ACK;
if (!skb)
skb = get_free_pkt(cm_node);
if (!skb) { if (!skb) {
nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n"); nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
return -1; return -1;
} }
add_ref_cm_node(cm_node);
form_cm_frame(skb, cm_node, NULL, 0, NULL, 0, flags); form_cm_frame(skb, cm_node, NULL, 0, NULL, 0, flags);
ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 0, 1); ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 0, 1);
...@@ -755,10 +724,12 @@ static int send_reset(struct nes_cm_node *cm_node) ...@@ -755,10 +724,12 @@ static int send_reset(struct nes_cm_node *cm_node)
/** /**
* send_ack * send_ack
*/ */
static int send_ack(struct nes_cm_node *cm_node) static int send_ack(struct nes_cm_node *cm_node, struct sk_buff *skb)
{ {
int ret; int ret;
struct sk_buff *skb = get_free_pkt(cm_node);
if (!skb)
skb = get_free_pkt(cm_node);
if (!skb) { if (!skb) {
nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n"); nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
...@@ -922,7 +893,8 @@ static int add_hte_node(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node ...@@ -922,7 +893,8 @@ static int add_hte_node(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node
if (!cm_node || !cm_core) if (!cm_node || !cm_core)
return -EINVAL; return -EINVAL;
nes_debug(NES_DBG_CM, "Adding Node to Active Connection HT\n"); nes_debug(NES_DBG_CM, "Adding Node %p to Active Connection HT\n",
cm_node);
/* first, make an index into our hash table */ /* first, make an index into our hash table */
hashkey = make_hashkey(cm_node->loc_port, cm_node->loc_addr, hashkey = make_hashkey(cm_node->loc_port, cm_node->loc_addr,
...@@ -946,10 +918,35 @@ static int add_hte_node(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node ...@@ -946,10 +918,35 @@ static int add_hte_node(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node
* mini_cm_dec_refcnt_listen * mini_cm_dec_refcnt_listen
*/ */
static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core, static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,
struct nes_cm_listener *listener, int free_hanging_nodes) struct nes_cm_listener *listener, int free_hanging_nodes)
{ {
int ret = 1; int ret = 1;
unsigned long flags; unsigned long flags;
struct list_head *list_pos = NULL;
struct list_head *list_temp = NULL;
struct nes_cm_node *cm_node = NULL;
nes_debug(NES_DBG_CM, "attempting listener= %p free_nodes= %d, "
"refcnt=%d\n", listener, free_hanging_nodes,
atomic_read(&listener->ref_count));
/* free non-accelerated child nodes for this listener */
if (free_hanging_nodes) {
spin_lock_irqsave(&cm_core->ht_lock, flags);
list_for_each_safe(list_pos, list_temp,
&g_cm_core->connected_nodes) {
cm_node = container_of(list_pos, struct nes_cm_node,
list);
if ((cm_node->listener == listener) &&
(!cm_node->accelerated)) {
cleanup_retrans_entry(cm_node);
spin_unlock_irqrestore(&cm_core->ht_lock,
flags);
send_reset(cm_node, NULL);
spin_lock_irqsave(&cm_core->ht_lock, flags);
}
}
spin_unlock_irqrestore(&cm_core->ht_lock, flags);
}
spin_lock_irqsave(&cm_core->listen_list_lock, flags); spin_lock_irqsave(&cm_core->listen_list_lock, flags);
if (!atomic_dec_return(&listener->ref_count)) { if (!atomic_dec_return(&listener->ref_count)) {
list_del(&listener->list); list_del(&listener->list);
...@@ -1067,18 +1064,18 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core, ...@@ -1067,18 +1064,18 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core,
cm_node->loc_port = cm_info->loc_port; cm_node->loc_port = cm_info->loc_port;
cm_node->rem_port = cm_info->rem_port; cm_node->rem_port = cm_info->rem_port;
cm_node->send_write0 = send_first; cm_node->send_write0 = send_first;
nes_debug(NES_DBG_CM, "Make node addresses : loc = " NIPQUAD_FMT ":%x, rem = " NIPQUAD_FMT ":%x\n", nes_debug(NES_DBG_CM, "Make node addresses : loc = " NIPQUAD_FMT
HIPQUAD(cm_node->loc_addr), cm_node->loc_port, ":%x, rem = " NIPQUAD_FMT ":%x\n",
HIPQUAD(cm_node->rem_addr), cm_node->rem_port); HIPQUAD(cm_node->loc_addr), cm_node->loc_port,
HIPQUAD(cm_node->rem_addr), cm_node->rem_port);
cm_node->listener = listener; cm_node->listener = listener;
cm_node->netdev = nesvnic->netdev; cm_node->netdev = nesvnic->netdev;
cm_node->cm_id = cm_info->cm_id; cm_node->cm_id = cm_info->cm_id;
memcpy(cm_node->loc_mac, nesvnic->netdev->dev_addr, ETH_ALEN); memcpy(cm_node->loc_mac, nesvnic->netdev->dev_addr, ETH_ALEN);
nes_debug(NES_DBG_CM, "listener=%p, cm_id=%p\n", nes_debug(NES_DBG_CM, "listener=%p, cm_id=%p\n", cm_node->listener,
cm_node->listener, cm_node->cm_id); cm_node->cm_id);
INIT_LIST_HEAD(&cm_node->retrans_list);
spin_lock_init(&cm_node->retrans_list_lock); spin_lock_init(&cm_node->retrans_list_lock);
INIT_LIST_HEAD(&cm_node->recv_list); INIT_LIST_HEAD(&cm_node->recv_list);
spin_lock_init(&cm_node->recv_list_lock); spin_lock_init(&cm_node->recv_list_lock);
...@@ -1142,10 +1139,9 @@ static int add_ref_cm_node(struct nes_cm_node *cm_node) ...@@ -1142,10 +1139,9 @@ static int add_ref_cm_node(struct nes_cm_node *cm_node)
* rem_ref_cm_node - destroy an instance of a cm node * rem_ref_cm_node - destroy an instance of a cm node
*/ */
static int rem_ref_cm_node(struct nes_cm_core *cm_core, static int rem_ref_cm_node(struct nes_cm_core *cm_core,
struct nes_cm_node *cm_node) struct nes_cm_node *cm_node)
{ {
unsigned long flags, qplockflags; unsigned long flags, qplockflags;
struct nes_timer_entry *send_entry;
struct nes_timer_entry *recv_entry; struct nes_timer_entry *recv_entry;
struct iw_cm_id *cm_id; struct iw_cm_id *cm_id;
struct list_head *list_core, *list_node_temp; struct list_head *list_core, *list_node_temp;
...@@ -1169,48 +1165,33 @@ static int rem_ref_cm_node(struct nes_cm_core *cm_core, ...@@ -1169,48 +1165,33 @@ static int rem_ref_cm_node(struct nes_cm_core *cm_core,
atomic_dec(&cm_node->listener->pend_accepts_cnt); atomic_dec(&cm_node->listener->pend_accepts_cnt);
BUG_ON(atomic_read(&cm_node->listener->pend_accepts_cnt) < 0); BUG_ON(atomic_read(&cm_node->listener->pend_accepts_cnt) < 0);
} }
BUG_ON(cm_node->send_entry);
spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
list_for_each_safe(list_core, list_node_temp, &cm_node->retrans_list) {
send_entry = container_of(list_core, struct nes_timer_entry, list);
list_del(&send_entry->list);
spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
dev_kfree_skb_any(send_entry->skb);
kfree(send_entry);
spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
continue;
}
spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
spin_lock_irqsave(&cm_node->recv_list_lock, flags); spin_lock_irqsave(&cm_node->recv_list_lock, flags);
list_for_each_safe(list_core, list_node_temp, &cm_node->recv_list) { list_for_each_safe(list_core, list_node_temp, &cm_node->recv_list) {
recv_entry = container_of(list_core, struct nes_timer_entry, list); recv_entry = container_of(list_core, struct nes_timer_entry,
list);
list_del(&recv_entry->list); list_del(&recv_entry->list);
cm_id = cm_node->cm_id; cm_id = cm_node->cm_id;
spin_unlock_irqrestore(&cm_node->recv_list_lock, flags); spin_unlock_irqrestore(&cm_node->recv_list_lock, flags);
if (recv_entry->type == NES_TIMER_TYPE_CLOSE) { nesqp = (struct nes_qp *)recv_entry->skb;
nesqp = (struct nes_qp *)recv_entry->skb; spin_lock_irqsave(&nesqp->lock, qplockflags);
spin_lock_irqsave(&nesqp->lock, qplockflags); if (nesqp->cm_id) {
if (nesqp->cm_id) { nes_debug(NES_DBG_CM, "QP%u: cm_id = %p: HIT A "
nes_debug(NES_DBG_CM, "QP%u: cm_id = %p: ****** HIT A NES_TIMER_TYPE_CLOSE" "NES_TIMER_TYPE_CLOSE with something to do!\n",
" with something to do!!! ******\n", nesqp->hwqp.qp_id, cm_id);
nesqp->hwqp.qp_id, cm_id); nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED; nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT;
nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT; nesqp->ibqp_state = IB_QPS_ERR;
nesqp->ibqp_state = IB_QPS_ERR; spin_unlock_irqrestore(&nesqp->lock, qplockflags);
spin_unlock_irqrestore(&nesqp->lock, qplockflags); nes_cm_disconn(nesqp);
nes_cm_disconn(nesqp); } else {
} else { spin_unlock_irqrestore(&nesqp->lock, qplockflags);
spin_unlock_irqrestore(&nesqp->lock, qplockflags); nes_debug(NES_DBG_CM, "QP%u: cm_id = %p: HIT A "
nes_debug(NES_DBG_CM, "QP%u: cm_id = %p: ****** HIT A NES_TIMER_TYPE_CLOSE" "NES_TIMER_TYPE_CLOSE with nothing to do!\n",
" with nothing to do!!! ******\n", nesqp->hwqp.qp_id, cm_id);
nesqp->hwqp.qp_id, cm_id);
nes_rem_ref(&nesqp->ibqp);
}
cm_id->rem_ref(cm_id);
} else if (recv_entry->type == NES_TIMER_TYPE_RECV) {
dev_kfree_skb_any(recv_entry->skb);
} }
cm_id->rem_ref(cm_id);
kfree(recv_entry); kfree(recv_entry);
spin_lock_irqsave(&cm_node->recv_list_lock, flags); spin_lock_irqsave(&cm_node->recv_list_lock, flags);
} }
...@@ -1221,23 +1202,31 @@ static int rem_ref_cm_node(struct nes_cm_core *cm_core, ...@@ -1221,23 +1202,31 @@ static int rem_ref_cm_node(struct nes_cm_core *cm_core,
} else { } else {
if (cm_node->apbvt_set && cm_node->nesvnic) { if (cm_node->apbvt_set && cm_node->nesvnic) {
nes_manage_apbvt(cm_node->nesvnic, cm_node->loc_port, nes_manage_apbvt(cm_node->nesvnic, cm_node->loc_port,
PCI_FUNC(cm_node->nesvnic->nesdev->pcidev->devfn), PCI_FUNC(
NES_MANAGE_APBVT_DEL); cm_node->nesvnic->nesdev->pcidev->devfn),
NES_MANAGE_APBVT_DEL);
} }
} }
kfree(cm_node);
atomic_dec(&cm_core->node_cnt); atomic_dec(&cm_core->node_cnt);
atomic_inc(&cm_nodes_destroyed); atomic_inc(&cm_nodes_destroyed);
nesqp = cm_node->nesqp;
if (nesqp) {
nesqp->cm_node = NULL;
nes_rem_ref(&nesqp->ibqp);
cm_node->nesqp = NULL;
}
cm_node->freed = 1;
kfree(cm_node);
return 0; return 0;
} }
/** /**
* process_options * process_options
*/ */
static int process_options(struct nes_cm_node *cm_node, u8 *optionsloc, u32 optionsize, u32 syn_packet) static int process_options(struct nes_cm_node *cm_node, u8 *optionsloc,
u32 optionsize, u32 syn_packet)
{ {
u32 tmp; u32 tmp;
u32 offset = 0; u32 offset = 0;
...@@ -1247,35 +1236,37 @@ static int process_options(struct nes_cm_node *cm_node, u8 *optionsloc, u32 opti ...@@ -1247,35 +1236,37 @@ static int process_options(struct nes_cm_node *cm_node, u8 *optionsloc, u32 opti
while (offset < optionsize) { while (offset < optionsize) {
all_options = (union all_known_options *)(optionsloc + offset); all_options = (union all_known_options *)(optionsloc + offset);
switch (all_options->as_base.optionnum) { switch (all_options->as_base.optionnum) {
case OPTION_NUMBER_END: case OPTION_NUMBER_END:
offset = optionsize; offset = optionsize;
break; break;
case OPTION_NUMBER_NONE: case OPTION_NUMBER_NONE:
offset += 1; offset += 1;
continue; continue;
case OPTION_NUMBER_MSS: case OPTION_NUMBER_MSS:
nes_debug(NES_DBG_CM, "%s: MSS Length: %d Offset: %d Size: %d\n", nes_debug(NES_DBG_CM, "%s: MSS Length: %d Offset: %d "
__func__, "Size: %d\n", __func__,
all_options->as_mss.length, offset, optionsize); all_options->as_mss.length, offset, optionsize);
got_mss_option = 1; got_mss_option = 1;
if (all_options->as_mss.length != 4) { if (all_options->as_mss.length != 4) {
return 1; return 1;
} else { } else {
tmp = ntohs(all_options->as_mss.mss); tmp = ntohs(all_options->as_mss.mss);
if (tmp > 0 && tmp < cm_node->tcp_cntxt.mss) if (tmp > 0 && tmp <
cm_node->tcp_cntxt.mss = tmp; cm_node->tcp_cntxt.mss)
} cm_node->tcp_cntxt.mss = tmp;
break; }
case OPTION_NUMBER_WINDOW_SCALE: break;
cm_node->tcp_cntxt.snd_wscale = all_options->as_windowscale.shiftcount; case OPTION_NUMBER_WINDOW_SCALE:
break; cm_node->tcp_cntxt.snd_wscale =
case OPTION_NUMBER_WRITE0: all_options->as_windowscale.shiftcount;
cm_node->send_write0 = 1; break;
break; case OPTION_NUMBER_WRITE0:
default: cm_node->send_write0 = 1;
nes_debug(NES_DBG_CM, "TCP Option not understood: %x\n", break;
all_options->as_base.optionnum); default:
break; nes_debug(NES_DBG_CM, "TCP Option not understood: %x\n",
all_options->as_base.optionnum);
break;
} }
offset += all_options->as_base.length; offset += all_options->as_base.length;
} }
...@@ -1284,300 +1275,491 @@ static int process_options(struct nes_cm_node *cm_node, u8 *optionsloc, u32 opti ...@@ -1284,300 +1275,491 @@ static int process_options(struct nes_cm_node *cm_node, u8 *optionsloc, u32 opti
return 0; return 0;
} }
static void drop_packet(struct sk_buff *skb)
{
atomic_inc(&cm_accel_dropped_pkts);
dev_kfree_skb_any(skb);
}
/** static void handle_fin_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
* process_packet struct tcphdr *tcph)
*/
static int process_packet(struct nes_cm_node *cm_node, struct sk_buff *skb,
struct nes_cm_core *cm_core)
{ {
int optionsize; atomic_inc(&cm_resets_recvd);
int datasize; nes_debug(NES_DBG_CM, "Received FIN, cm_node = %p, state = %u. "
int ret = 0; "refcnt=%d\n", cm_node, cm_node->state,
struct tcphdr *tcph = tcp_hdr(skb); atomic_read(&cm_node->ref_count));
u32 inc_sequence; cm_node->tcp_cntxt.rcv_nxt++;
if (cm_node->state == NES_CM_STATE_SYN_SENT && tcph->syn) { cleanup_retrans_entry(cm_node);
inc_sequence = ntohl(tcph->seq); switch (cm_node->state) {
cm_node->tcp_cntxt.rcv_nxt = inc_sequence; case NES_CM_STATE_SYN_RCVD:
case NES_CM_STATE_SYN_SENT:
case NES_CM_STATE_ESTABLISHED:
case NES_CM_STATE_MPAREQ_SENT:
cm_node->state = NES_CM_STATE_LAST_ACK;
send_fin(cm_node, skb);
break;
case NES_CM_STATE_FIN_WAIT1:
cm_node->state = NES_CM_STATE_CLOSING;
send_ack(cm_node, skb);
break;
case NES_CM_STATE_FIN_WAIT2:
cm_node->state = NES_CM_STATE_TIME_WAIT;
send_ack(cm_node, skb);
cm_node->state = NES_CM_STATE_CLOSED;
break;
case NES_CM_STATE_TSA:
default:
nes_debug(NES_DBG_CM, "Error Rcvd FIN for node-%p state = %d\n",
cm_node, cm_node->state);
drop_packet(skb);
break;
} }
}
if ((!tcph) || (cm_node->state == NES_CM_STATE_TSA)) {
BUG_ON(!tcph);
atomic_inc(&cm_accel_dropped_pkts);
return -1;
}
if (tcph->rst) { static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
atomic_inc(&cm_resets_recvd); struct tcphdr *tcph)
nes_debug(NES_DBG_CM, "Received Reset, cm_node = %p, state = %u. refcnt=%d\n", {
cm_node, cm_node->state, atomic_read(&cm_node->ref_count));
switch (cm_node->state) {
case NES_CM_STATE_LISTENING:
rem_ref_cm_node(cm_core, cm_node);
break;
case NES_CM_STATE_TSA:
case NES_CM_STATE_CLOSED:
break;
case NES_CM_STATE_SYN_RCVD:
nes_debug(NES_DBG_CM, "Received a reset for local 0x%08X:%04X,"
" remote 0x%08X:%04X, node state = %u\n",
cm_node->loc_addr, cm_node->loc_port,
cm_node->rem_addr, cm_node->rem_port,
cm_node->state);
rem_ref_cm_node(cm_core, cm_node);
break;
case NES_CM_STATE_ONE_SIDE_ESTABLISHED:
case NES_CM_STATE_ESTABLISHED:
case NES_CM_STATE_MPAREQ_SENT:
default:
nes_debug(NES_DBG_CM, "Received a reset for local 0x%08X:%04X,"
" remote 0x%08X:%04X, node state = %u refcnt=%d\n",
cm_node->loc_addr, cm_node->loc_port,
cm_node->rem_addr, cm_node->rem_port,
cm_node->state, atomic_read(&cm_node->ref_count));
/* create event */
cm_node->state = NES_CM_STATE_CLOSED;
create_event(cm_node, NES_CM_EVENT_ABORTED); int reset = 0; /* whether to send reset in case of err.. */
break; atomic_inc(&cm_resets_recvd);
nes_debug(NES_DBG_CM, "Received Reset, cm_node = %p, state = %u."
" refcnt=%d\n", cm_node, cm_node->state,
atomic_read(&cm_node->ref_count));
cleanup_retrans_entry(cm_node);
switch (cm_node->state) {
case NES_CM_STATE_SYN_SENT:
case NES_CM_STATE_MPAREQ_SENT:
nes_debug(NES_DBG_CM, "%s[%u] create abort for cm_node=%p "
"listener=%p state=%d\n", __func__, __LINE__, cm_node,
cm_node->listener, cm_node->state);
active_open_err(cm_node, skb, reset);
break;
/* For PASSIVE open states, remove the cm_node event */
case NES_CM_STATE_ESTABLISHED:
case NES_CM_STATE_SYN_RCVD:
case NES_CM_STATE_LISTENING:
nes_debug(NES_DBG_CM, "Bad state %s[%u]\n", __func__, __LINE__);
passive_open_err(cm_node, skb, reset);
break;
case NES_CM_STATE_TSA:
default:
break;
}
}
static void handle_rcv_mpa(struct nes_cm_node *cm_node, struct sk_buff *skb,
enum nes_cm_event_type type)
{
int ret;
int datasize = skb->len;
u8 *dataloc = skb->data;
ret = parse_mpa(cm_node, dataloc, datasize);
if (ret < 0) {
nes_debug(NES_DBG_CM, "didn't like MPA Request\n");
if (type == NES_CM_EVENT_CONNECTED) {
nes_debug(NES_DBG_CM, "%s[%u] create abort for "
"cm_node=%p listener=%p state=%d\n", __func__,
__LINE__, cm_node, cm_node->listener,
cm_node->state);
active_open_err(cm_node, skb, 1);
} else {
passive_open_err(cm_node, skb, 1);
} }
return -1; } else {
cleanup_retrans_entry(cm_node);
dev_kfree_skb_any(skb);
if (type == NES_CM_EVENT_CONNECTED)
cm_node->state = NES_CM_STATE_TSA;
create_event(cm_node, type);
}
return ;
}
static void indicate_pkt_err(struct nes_cm_node *cm_node, struct sk_buff *skb)
{
switch (cm_node->state) {
case NES_CM_STATE_SYN_SENT:
case NES_CM_STATE_MPAREQ_SENT:
nes_debug(NES_DBG_CM, "%s[%u] create abort for cm_node=%p "
"listener=%p state=%d\n", __func__, __LINE__, cm_node,
cm_node->listener, cm_node->state);
active_open_err(cm_node, skb, 1);
break;
case NES_CM_STATE_ESTABLISHED:
case NES_CM_STATE_SYN_RCVD:
passive_open_err(cm_node, skb, 1);
break;
case NES_CM_STATE_TSA:
default:
drop_packet(skb);
} }
}
static int check_syn(struct nes_cm_node *cm_node, struct tcphdr *tcph,
struct sk_buff *skb)
{
int err;
err = ((ntohl(tcph->ack_seq) == cm_node->tcp_cntxt.loc_seq_num))? 0 : 1;
if (err)
active_open_err(cm_node, skb, 1);
return err;
}
static int check_seq(struct nes_cm_node *cm_node, struct tcphdr *tcph,
struct sk_buff *skb)
{
int err = 0;
u32 seq;
u32 ack_seq;
u32 loc_seq_num = cm_node->tcp_cntxt.loc_seq_num;
u32 rcv_nxt = cm_node->tcp_cntxt.rcv_nxt;
u32 rcv_wnd;
seq = ntohl(tcph->seq);
ack_seq = ntohl(tcph->ack_seq);
rcv_wnd = cm_node->tcp_cntxt.rcv_wnd;
if (ack_seq != loc_seq_num)
err = 1;
else if ((seq + rcv_wnd) < rcv_nxt)
err = 1;
if (err) {
nes_debug(NES_DBG_CM, "%s[%u] create abort for cm_node=%p "
"listener=%p state=%d\n", __func__, __LINE__, cm_node,
cm_node->listener, cm_node->state);
indicate_pkt_err(cm_node, skb);
nes_debug(NES_DBG_CM, "seq ERROR cm_node =%p seq=0x%08X "
"rcv_nxt=0x%08X rcv_wnd=0x%x\n", cm_node, seq, rcv_nxt,
rcv_wnd);
}
return err;
}
/*
* handle_syn_pkt() is for Passive node. The syn packet is received when a node
* is created with a listener or it may comein as rexmitted packet which in
* that case will be just dropped.
*/
static void handle_syn_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
struct tcphdr *tcph)
{
int ret;
u32 inc_sequence;
int optionsize;
optionsize = (tcph->doff << 2) - sizeof(struct tcphdr); optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
skb_pull(skb, tcph->doff << 2);
inc_sequence = ntohl(tcph->seq);
skb_pull(skb, ip_hdr(skb)->ihl << 2); switch (cm_node->state) {
case NES_CM_STATE_SYN_SENT:
case NES_CM_STATE_MPAREQ_SENT:
/* Rcvd syn on active open connection*/
active_open_err(cm_node, skb, 1);
break;
case NES_CM_STATE_LISTENING:
/* Passive OPEN */
cm_node->accept_pend = 1;
atomic_inc(&cm_node->listener->pend_accepts_cnt);
if (atomic_read(&cm_node->listener->pend_accepts_cnt) >
cm_node->listener->backlog) {
nes_debug(NES_DBG_CM, "drop syn due to backlog "
"pressure \n");
cm_backlog_drops++;
passive_open_err(cm_node, skb, 0);
break;
}
ret = handle_tcp_options(cm_node, tcph, skb, optionsize,
1);
if (ret) {
passive_open_err(cm_node, skb, 0);
/* drop pkt */
break;
}
cm_node->tcp_cntxt.rcv_nxt = inc_sequence + 1;
BUG_ON(cm_node->send_entry);
cm_node->state = NES_CM_STATE_SYN_RCVD;
send_syn(cm_node, 1, skb);
break;
case NES_CM_STATE_TSA:
case NES_CM_STATE_ESTABLISHED:
case NES_CM_STATE_FIN_WAIT1:
case NES_CM_STATE_FIN_WAIT2:
case NES_CM_STATE_MPAREQ_RCVD:
case NES_CM_STATE_LAST_ACK:
case NES_CM_STATE_CLOSING:
case NES_CM_STATE_UNKNOWN:
case NES_CM_STATE_CLOSED:
default:
drop_packet(skb);
break;
}
}
static void handle_synack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
struct tcphdr *tcph)
{
int ret;
u32 inc_sequence;
int optionsize;
optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);
skb_pull(skb, tcph->doff << 2); skb_pull(skb, tcph->doff << 2);
inc_sequence = ntohl(tcph->seq);
switch (cm_node->state) {
case NES_CM_STATE_SYN_SENT:
/* active open */
if (check_syn(cm_node, tcph, skb))
return;
cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);
/* setup options */
ret = handle_tcp_options(cm_node, tcph, skb, optionsize, 0);
if (ret) {
nes_debug(NES_DBG_CM, "cm_node=%p tcp_options failed\n",
cm_node);
break;
}
cleanup_retrans_entry(cm_node);
cm_node->tcp_cntxt.rcv_nxt = inc_sequence + 1;
send_mpa_request(cm_node, skb);
cm_node->state = NES_CM_STATE_MPAREQ_SENT;
break;
case NES_CM_STATE_MPAREQ_RCVD:
/* passive open, so should not be here */
passive_open_err(cm_node, skb, 1);
break;
case NES_CM_STATE_ESTABLISHED:
case NES_CM_STATE_FIN_WAIT1:
case NES_CM_STATE_FIN_WAIT2:
case NES_CM_STATE_LAST_ACK:
case NES_CM_STATE_TSA:
case NES_CM_STATE_CLOSING:
case NES_CM_STATE_UNKNOWN:
case NES_CM_STATE_CLOSED:
case NES_CM_STATE_MPAREQ_SENT:
default:
drop_packet(skb);
break;
}
}
datasize = skb->len; static void handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,
struct tcphdr *tcph)
{
int datasize = 0;
u32 inc_sequence;
u32 rem_seq_ack;
u32 rem_seq;
if (check_seq(cm_node, tcph, skb))
return;
skb_pull(skb, tcph->doff << 2);
inc_sequence = ntohl(tcph->seq); inc_sequence = ntohl(tcph->seq);
nes_debug(NES_DBG_CM, "datasize = %u, sequence = 0x%08X, ack_seq = 0x%08X," rem_seq = ntohl(tcph->seq);
" rcv_nxt = 0x%08X Flags: %s %s.\n", rem_seq_ack = ntohl(tcph->ack_seq);
datasize, inc_sequence, ntohl(tcph->ack_seq), datasize = skb->len;
cm_node->tcp_cntxt.rcv_nxt, (tcph->syn ? "SYN":""),
(tcph->ack ? "ACK":"")); switch (cm_node->state) {
case NES_CM_STATE_SYN_RCVD:
if (!tcph->syn && (inc_sequence != cm_node->tcp_cntxt.rcv_nxt) /* Passive OPEN */
) { cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);
nes_debug(NES_DBG_CM, "dropping packet, datasize = %u, sequence = 0x%08X," cm_node->state = NES_CM_STATE_ESTABLISHED;
" ack_seq = 0x%08X, rcv_nxt = 0x%08X Flags: %s.\n", if (datasize) {
datasize, inc_sequence, ntohl(tcph->ack_seq), cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
cm_node->tcp_cntxt.rcv_nxt, (tcph->ack ? "ACK":"")); cm_node->state = NES_CM_STATE_MPAREQ_RCVD;
if (cm_node->state == NES_CM_STATE_LISTENING) { handle_rcv_mpa(cm_node, skb, NES_CM_EVENT_MPA_REQ);
rem_ref_cm_node(cm_core, cm_node); } else { /* rcvd ACK only */
dev_kfree_skb_any(skb);
cleanup_retrans_entry(cm_node);
}
break;
case NES_CM_STATE_ESTABLISHED:
/* Passive OPEN */
/* We expect mpa frame to be received only */
if (datasize) {
cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
cm_node->state = NES_CM_STATE_MPAREQ_RCVD;
handle_rcv_mpa(cm_node, skb,
NES_CM_EVENT_MPA_REQ);
} else
drop_packet(skb);
break;
case NES_CM_STATE_MPAREQ_SENT:
cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);
if (datasize) {
cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
handle_rcv_mpa(cm_node, skb, NES_CM_EVENT_CONNECTED);
} else { /* Could be just an ack pkt.. */
cleanup_retrans_entry(cm_node);
dev_kfree_skb_any(skb);
} }
return -1; break;
case NES_CM_STATE_FIN_WAIT1:
case NES_CM_STATE_SYN_SENT:
case NES_CM_STATE_FIN_WAIT2:
case NES_CM_STATE_TSA:
case NES_CM_STATE_CLOSED:
case NES_CM_STATE_MPAREQ_RCVD:
case NES_CM_STATE_LAST_ACK:
case NES_CM_STATE_CLOSING:
case NES_CM_STATE_UNKNOWN:
default:
drop_packet(skb);
break;
} }
}
cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
static int handle_tcp_options(struct nes_cm_node *cm_node, struct tcphdr *tcph,
struct sk_buff *skb, int optionsize, int passive)
{
u8 *optionsloc = (u8 *)&tcph[1];
if (optionsize) { if (optionsize) {
u8 *optionsloc = (u8 *)&tcph[1]; if (process_options(cm_node, optionsloc, optionsize,
if (process_options(cm_node, optionsloc, optionsize, (u32)tcph->syn)) { (u32)tcph->syn)) {
nes_debug(NES_DBG_CM, "%s: Node %p, Sending RESET\n", __func__, cm_node); nes_debug(NES_DBG_CM, "%s: Node %p, Sending RESET\n",
send_reset(cm_node); __func__, cm_node);
if (cm_node->state != NES_CM_STATE_SYN_SENT) if (passive)
rem_ref_cm_node(cm_core, cm_node); passive_open_err(cm_node, skb, 0);
return 0; else
active_open_err(cm_node, skb, 0);
return 1;
} }
} else if (tcph->syn) }
cm_node->tcp_cntxt.mss = NES_CM_DEFAULT_MSS;
cm_node->tcp_cntxt.snd_wnd = ntohs(tcph->window) << cm_node->tcp_cntxt.snd_wnd = ntohs(tcph->window) <<
cm_node->tcp_cntxt.snd_wscale; cm_node->tcp_cntxt.snd_wscale;
if (cm_node->tcp_cntxt.snd_wnd > cm_node->tcp_cntxt.max_snd_wnd) { if (cm_node->tcp_cntxt.snd_wnd > cm_node->tcp_cntxt.max_snd_wnd)
cm_node->tcp_cntxt.max_snd_wnd = cm_node->tcp_cntxt.snd_wnd; cm_node->tcp_cntxt.max_snd_wnd = cm_node->tcp_cntxt.snd_wnd;
} return 0;
}
if (tcph->ack) { /*
cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq); * active_open_err() will send reset() if flag set..
switch (cm_node->state) { * It will also send ABORT event.
case NES_CM_STATE_SYN_RCVD: */
case NES_CM_STATE_SYN_SENT:
/* read and stash current sequence number */
if (cm_node->tcp_cntxt.rem_ack_num != cm_node->tcp_cntxt.loc_seq_num) {
nes_debug(NES_DBG_CM, "ERROR - cm_node->tcp_cntxt.rem_ack_num !="
" cm_node->tcp_cntxt.loc_seq_num\n");
send_reset(cm_node);
return 0;
}
if (cm_node->state == NES_CM_STATE_SYN_SENT)
cm_node->state = NES_CM_STATE_ONE_SIDE_ESTABLISHED;
else {
cm_node->state = NES_CM_STATE_ESTABLISHED;
}
break;
case NES_CM_STATE_LAST_ACK:
cm_node->state = NES_CM_STATE_CLOSED;
break;
case NES_CM_STATE_FIN_WAIT1:
cm_node->state = NES_CM_STATE_FIN_WAIT2;
break;
case NES_CM_STATE_CLOSING:
cm_node->state = NES_CM_STATE_TIME_WAIT;
/* need to schedule this to happen in 2MSL timeouts */
cm_node->state = NES_CM_STATE_CLOSED;
break;
case NES_CM_STATE_ONE_SIDE_ESTABLISHED:
case NES_CM_STATE_ESTABLISHED:
case NES_CM_STATE_MPAREQ_SENT:
case NES_CM_STATE_CLOSE_WAIT:
case NES_CM_STATE_TIME_WAIT:
case NES_CM_STATE_CLOSED:
break;
case NES_CM_STATE_LISTENING:
nes_debug(NES_DBG_CM, "Received an ACK on a listening port (SYN %d)\n", tcph->syn);
cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq);
send_reset(cm_node);
/* send_reset bumps refcount, this should have been a new node */
rem_ref_cm_node(cm_core, cm_node);
return -1;
break;
case NES_CM_STATE_TSA:
nes_debug(NES_DBG_CM, "Received a packet with the ack bit set while in TSA state\n");
break;
case NES_CM_STATE_UNKNOWN:
case NES_CM_STATE_INITED:
case NES_CM_STATE_ACCEPTING:
case NES_CM_STATE_FIN_WAIT2:
default:
nes_debug(NES_DBG_CM, "Received ack from unknown state: %x\n",
cm_node->state);
send_reset(cm_node);
break;
}
}
if (tcph->syn) { static void active_open_err(struct nes_cm_node *cm_node, struct sk_buff *skb,
if (cm_node->state == NES_CM_STATE_LISTENING) { int reset)
/* do not exceed backlog */ {
atomic_inc(&cm_node->listener->pend_accepts_cnt); cleanup_retrans_entry(cm_node);
if (atomic_read(&cm_node->listener->pend_accepts_cnt) > if (reset) {
cm_node->listener->backlog) { nes_debug(NES_DBG_CM, "ERROR active err called for cm_node=%p, "
nes_debug(NES_DBG_CM, "drop syn due to backlog pressure \n"); "state=%d\n", cm_node, cm_node->state);
cm_backlog_drops++; add_ref_cm_node(cm_node);
atomic_dec(&cm_node->listener->pend_accepts_cnt); send_reset(cm_node, skb);
rem_ref_cm_node(cm_core, cm_node); } else
return 0; dev_kfree_skb_any(skb);
}
cm_node->accept_pend = 1;
} cm_node->state = NES_CM_STATE_CLOSED;
if (datasize == 0) create_event(cm_node, NES_CM_EVENT_ABORTED);
cm_node->tcp_cntxt.rcv_nxt ++; }
if (cm_node->state == NES_CM_STATE_LISTENING) { /*
cm_node->state = NES_CM_STATE_SYN_RCVD; * passive_open_err() will either do a reset() or will free up the skb and
send_syn(cm_node, 1); * remove the cm_node.
} */
if (cm_node->state == NES_CM_STATE_ONE_SIDE_ESTABLISHED) {
cm_node->state = NES_CM_STATE_ESTABLISHED;
/* send final handshake ACK */
ret = send_ack(cm_node);
if (ret < 0)
return ret;
cm_node->state = NES_CM_STATE_MPAREQ_SENT; static void passive_open_err(struct nes_cm_node *cm_node, struct sk_buff *skb,
ret = send_mpa_request(cm_node); int reset)
if (ret < 0) {
return ret; cleanup_retrans_entry(cm_node);
} cm_node->state = NES_CM_STATE_CLOSED;
if (reset) {
nes_debug(NES_DBG_CM, "passive_open_err sending RST for "
"cm_node=%p state =%d\n", cm_node, cm_node->state);
send_reset(cm_node, skb);
} else {
dev_kfree_skb_any(skb);
rem_ref_cm_node(cm_node->cm_core, cm_node);
} }
}
if (tcph->fin) { /*
cm_node->tcp_cntxt.rcv_nxt++; * free_retrans_entry() routines assumes that the retrans_list_lock has
switch (cm_node->state) { * been acquired before calling.
case NES_CM_STATE_SYN_RCVD: */
case NES_CM_STATE_SYN_SENT: static void free_retrans_entry(struct nes_cm_node *cm_node)
case NES_CM_STATE_ONE_SIDE_ESTABLISHED: {
case NES_CM_STATE_ESTABLISHED: struct nes_timer_entry *send_entry;
case NES_CM_STATE_ACCEPTING: send_entry = cm_node->send_entry;
case NES_CM_STATE_MPAREQ_SENT: if (send_entry) {
cm_node->state = NES_CM_STATE_CLOSE_WAIT; cm_node->send_entry = NULL;
cm_node->state = NES_CM_STATE_LAST_ACK; dev_kfree_skb_any(send_entry->skb);
ret = send_fin(cm_node, NULL); kfree(send_entry);
break; rem_ref_cm_node(cm_node->cm_core, cm_node);
case NES_CM_STATE_FIN_WAIT1:
cm_node->state = NES_CM_STATE_CLOSING;
ret = send_ack(cm_node);
break;
case NES_CM_STATE_FIN_WAIT2:
cm_node->state = NES_CM_STATE_TIME_WAIT;
cm_node->tcp_cntxt.loc_seq_num ++;
ret = send_ack(cm_node);
/* need to schedule this to happen in 2MSL timeouts */
cm_node->state = NES_CM_STATE_CLOSED;
break;
case NES_CM_STATE_CLOSE_WAIT:
case NES_CM_STATE_LAST_ACK:
case NES_CM_STATE_CLOSING:
case NES_CM_STATE_TSA:
default:
nes_debug(NES_DBG_CM, "Received a fin while in %x state\n",
cm_node->state);
ret = -EINVAL;
break;
}
} }
}
if (datasize) { static void cleanup_retrans_entry(struct nes_cm_node *cm_node)
u8 *dataloc = skb->data; {
/* figure out what state we are in and handle transition to next state */ unsigned long flags;
switch (cm_node->state) {
case NES_CM_STATE_LISTENING:
case NES_CM_STATE_SYN_RCVD:
case NES_CM_STATE_SYN_SENT:
case NES_CM_STATE_FIN_WAIT1:
case NES_CM_STATE_FIN_WAIT2:
case NES_CM_STATE_CLOSE_WAIT:
case NES_CM_STATE_LAST_ACK:
case NES_CM_STATE_CLOSING:
break;
case NES_CM_STATE_MPAREQ_SENT:
/* recv the mpa res frame, ret=frame len (incl priv data) */
ret = parse_mpa(cm_node, dataloc, datasize);
if (ret < 0)
break;
/* set the req frame payload len in skb */
/* we are done handling this state, set node to a TSA state */
cm_node->state = NES_CM_STATE_TSA;
send_ack(cm_node);
create_event(cm_node, NES_CM_EVENT_CONNECTED);
break;
case NES_CM_STATE_ESTABLISHED:
/* we are expecting an MPA req frame */
ret = parse_mpa(cm_node, dataloc, datasize);
if (ret < 0) {
break;
}
cm_node->state = NES_CM_STATE_TSA;
send_ack(cm_node);
/* we got a valid MPA request, create an event */
create_event(cm_node, NES_CM_EVENT_MPA_REQ);
break;
case NES_CM_STATE_TSA:
handle_exception_pkt(cm_node, skb);
break;
case NES_CM_STATE_UNKNOWN:
case NES_CM_STATE_INITED:
default:
ret = -1;
}
}
return ret; spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
free_retrans_entry(cm_node);
spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
} }
/**
* process_packet
* Returns skb if to be freed, else it will return NULL if already used..
*/
static void process_packet(struct nes_cm_node *cm_node, struct sk_buff *skb,
struct nes_cm_core *cm_core)
{
enum nes_tcpip_pkt_type pkt_type = NES_PKT_TYPE_UNKNOWN;
struct tcphdr *tcph = tcp_hdr(skb);
skb_pull(skb, ip_hdr(skb)->ihl << 2);
nes_debug(NES_DBG_CM, "process_packet: cm_node=%p state =%d syn=%d "
"ack=%d rst=%d fin=%d\n", cm_node, cm_node->state, tcph->syn,
tcph->ack, tcph->rst, tcph->fin);
if (tcph->rst)
pkt_type = NES_PKT_TYPE_RST;
else if (tcph->syn) {
pkt_type = NES_PKT_TYPE_SYN;
if (tcph->ack)
pkt_type = NES_PKT_TYPE_SYNACK;
} else if (tcph->fin)
pkt_type = NES_PKT_TYPE_FIN;
else if (tcph->ack)
pkt_type = NES_PKT_TYPE_ACK;
switch (pkt_type) {
case NES_PKT_TYPE_SYN:
handle_syn_pkt(cm_node, skb, tcph);
break;
case NES_PKT_TYPE_SYNACK:
handle_synack_pkt(cm_node, skb, tcph);
break;
case NES_PKT_TYPE_ACK:
handle_ack_pkt(cm_node, skb, tcph);
break;
case NES_PKT_TYPE_RST:
handle_rst_pkt(cm_node, skb, tcph);
break;
case NES_PKT_TYPE_FIN:
handle_fin_pkt(cm_node, skb, tcph);
break;
default:
drop_packet(skb);
break;
}
}
/** /**
* mini_cm_listen - create a listen node with params * mini_cm_listen - create a listen node with params
*/ */
static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core, static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core,
struct nes_vnic *nesvnic, struct nes_cm_info *cm_info) struct nes_vnic *nesvnic, struct nes_cm_info *cm_info)
{ {
struct nes_cm_listener *listener; struct nes_cm_listener *listener;
unsigned long flags; unsigned long flags;
...@@ -1644,37 +1826,36 @@ static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core, ...@@ -1644,37 +1826,36 @@ static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core,
/** /**
* mini_cm_connect - make a connection node with params * mini_cm_connect - make a connection node with params
*/ */
static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core, struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core,
struct nes_vnic *nesvnic, struct nes_vnic *nesvnic, u16 private_data_len,
struct ietf_mpa_frame *mpa_frame, void *private_data, struct nes_cm_info *cm_info)
struct nes_cm_info *cm_info)
{ {
int ret = 0; int ret = 0;
struct nes_cm_node *cm_node; struct nes_cm_node *cm_node;
struct nes_cm_listener *loopbackremotelistener; struct nes_cm_listener *loopbackremotelistener;
struct nes_cm_node *loopbackremotenode; struct nes_cm_node *loopbackremotenode;
struct nes_cm_info loopback_cm_info; struct nes_cm_info loopback_cm_info;
u16 mpa_frame_size = sizeof(struct ietf_mpa_frame) + private_data_len;
u16 mpa_frame_size = sizeof(struct ietf_mpa_frame) + struct ietf_mpa_frame *mpa_frame = NULL;
ntohs(mpa_frame->priv_data_len);
cm_info->loc_addr = htonl(cm_info->loc_addr);
cm_info->rem_addr = htonl(cm_info->rem_addr);
cm_info->loc_port = htons(cm_info->loc_port);
cm_info->rem_port = htons(cm_info->rem_port);
/* create a CM connection node */ /* create a CM connection node */
cm_node = make_cm_node(cm_core, nesvnic, cm_info, NULL); cm_node = make_cm_node(cm_core, nesvnic, cm_info, NULL);
if (!cm_node) if (!cm_node)
return NULL; return NULL;
mpa_frame = &cm_node->mpa_frame;
strcpy(mpa_frame->key, IEFT_MPA_KEY_REQ);
mpa_frame->flags = IETF_MPA_FLAGS_CRC;
mpa_frame->rev = IETF_MPA_VERSION;
mpa_frame->priv_data_len = htons(private_data_len);
/* set our node side to client (active) side */ /* set our node side to client (active) side */
cm_node->tcp_cntxt.client = 1; cm_node->tcp_cntxt.client = 1;
cm_node->tcp_cntxt.rcv_wscale = NES_CM_DEFAULT_RCV_WND_SCALE; cm_node->tcp_cntxt.rcv_wscale = NES_CM_DEFAULT_RCV_WND_SCALE;
if (cm_info->loc_addr == cm_info->rem_addr) { if (cm_info->loc_addr == cm_info->rem_addr) {
loopbackremotelistener = find_listener(cm_core, cm_node->rem_addr, loopbackremotelistener = find_listener(cm_core,
cm_node->rem_port, NES_CM_LISTENER_ACTIVE_STATE); ntohl(nesvnic->local_ipaddr), cm_node->rem_port,
NES_CM_LISTENER_ACTIVE_STATE);
if (loopbackremotelistener == NULL) { if (loopbackremotelistener == NULL) {
create_event(cm_node, NES_CM_EVENT_ABORTED); create_event(cm_node, NES_CM_EVENT_ABORTED);
} else { } else {
...@@ -1683,26 +1864,35 @@ static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core, ...@@ -1683,26 +1864,35 @@ static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core,
loopback_cm_info.loc_port = cm_info->rem_port; loopback_cm_info.loc_port = cm_info->rem_port;
loopback_cm_info.rem_port = cm_info->loc_port; loopback_cm_info.rem_port = cm_info->loc_port;
loopback_cm_info.cm_id = loopbackremotelistener->cm_id; loopback_cm_info.cm_id = loopbackremotelistener->cm_id;
loopbackremotenode = make_cm_node(cm_core, nesvnic, &loopback_cm_info, loopbackremotenode = make_cm_node(cm_core, nesvnic,
loopbackremotelistener); &loopback_cm_info, loopbackremotelistener);
loopbackremotenode->loopbackpartner = cm_node; loopbackremotenode->loopbackpartner = cm_node;
loopbackremotenode->tcp_cntxt.rcv_wscale = NES_CM_DEFAULT_RCV_WND_SCALE; loopbackremotenode->tcp_cntxt.rcv_wscale =
NES_CM_DEFAULT_RCV_WND_SCALE;
cm_node->loopbackpartner = loopbackremotenode; cm_node->loopbackpartner = loopbackremotenode;
memcpy(loopbackremotenode->mpa_frame_buf, &mpa_frame->priv_data, memcpy(loopbackremotenode->mpa_frame_buf, private_data,
mpa_frame_size); private_data_len);
loopbackremotenode->mpa_frame_size = mpa_frame_size - loopbackremotenode->mpa_frame_size = private_data_len;
sizeof(struct ietf_mpa_frame);
/* we are done handling this state, set node to a TSA state */ /* we are done handling this state. */
/* set node to a TSA state */
cm_node->state = NES_CM_STATE_TSA; cm_node->state = NES_CM_STATE_TSA;
cm_node->tcp_cntxt.rcv_nxt = loopbackremotenode->tcp_cntxt.loc_seq_num; cm_node->tcp_cntxt.rcv_nxt =
loopbackremotenode->tcp_cntxt.rcv_nxt = cm_node->tcp_cntxt.loc_seq_num; loopbackremotenode->tcp_cntxt.loc_seq_num;
cm_node->tcp_cntxt.max_snd_wnd = loopbackremotenode->tcp_cntxt.rcv_wnd; loopbackremotenode->tcp_cntxt.rcv_nxt =
loopbackremotenode->tcp_cntxt.max_snd_wnd = cm_node->tcp_cntxt.rcv_wnd; cm_node->tcp_cntxt.loc_seq_num;
cm_node->tcp_cntxt.snd_wnd = loopbackremotenode->tcp_cntxt.rcv_wnd; cm_node->tcp_cntxt.max_snd_wnd =
loopbackremotenode->tcp_cntxt.snd_wnd = cm_node->tcp_cntxt.rcv_wnd; loopbackremotenode->tcp_cntxt.rcv_wnd;
cm_node->tcp_cntxt.snd_wscale = loopbackremotenode->tcp_cntxt.rcv_wscale; loopbackremotenode->tcp_cntxt.max_snd_wnd =
loopbackremotenode->tcp_cntxt.snd_wscale = cm_node->tcp_cntxt.rcv_wscale; cm_node->tcp_cntxt.rcv_wnd;
cm_node->tcp_cntxt.snd_wnd =
loopbackremotenode->tcp_cntxt.rcv_wnd;
loopbackremotenode->tcp_cntxt.snd_wnd =
cm_node->tcp_cntxt.rcv_wnd;
cm_node->tcp_cntxt.snd_wscale =
loopbackremotenode->tcp_cntxt.rcv_wscale;
loopbackremotenode->tcp_cntxt.snd_wscale =
cm_node->tcp_cntxt.rcv_wscale;
create_event(loopbackremotenode, NES_CM_EVENT_MPA_REQ); create_event(loopbackremotenode, NES_CM_EVENT_MPA_REQ);
} }
...@@ -1712,16 +1902,29 @@ static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core, ...@@ -1712,16 +1902,29 @@ static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core,
/* set our node side to client (active) side */ /* set our node side to client (active) side */
cm_node->tcp_cntxt.client = 1; cm_node->tcp_cntxt.client = 1;
/* init our MPA frame ptr */ /* init our MPA frame ptr */
memcpy(&cm_node->mpa_frame, mpa_frame, mpa_frame_size); memcpy(mpa_frame->priv_data, private_data, private_data_len);
cm_node->mpa_frame_size = mpa_frame_size; cm_node->mpa_frame_size = mpa_frame_size;
/* send a syn and goto syn sent state */ /* send a syn and goto syn sent state */
cm_node->state = NES_CM_STATE_SYN_SENT; cm_node->state = NES_CM_STATE_SYN_SENT;
ret = send_syn(cm_node, 0); ret = send_syn(cm_node, 0, NULL);
if (ret) {
/* error in sending the syn free up the cm_node struct */
nes_debug(NES_DBG_CM, "Api - connect() FAILED: dest "
"addr=0x%08X, port=0x%04x, cm_node=%p, cm_id = %p.\n",
cm_node->rem_addr, cm_node->rem_port, cm_node,
cm_node->cm_id);
rem_ref_cm_node(cm_node->cm_core, cm_node);
cm_node = NULL;
}
nes_debug(NES_DBG_CM, "Api - connect(): dest addr=0x%08X, port=0x%04x," if (cm_node)
" cm_node=%p, cm_id = %p.\n", nes_debug(NES_DBG_CM, "Api - connect(): dest addr=0x%08X,"
cm_node->rem_addr, cm_node->rem_port, cm_node, cm_node->cm_id); "port=0x%04x, cm_node=%p, cm_id = %p.\n",
cm_node->rem_addr, cm_node->rem_port, cm_node,
cm_node->cm_id);
return cm_node; return cm_node;
} }
...@@ -1731,8 +1934,8 @@ static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core, ...@@ -1731,8 +1934,8 @@ static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core,
* mini_cm_accept - accept a connection * mini_cm_accept - accept a connection
* This function is never called * This function is never called
*/ */
static int mini_cm_accept(struct nes_cm_core *cm_core, struct ietf_mpa_frame *mpa_frame, static int mini_cm_accept(struct nes_cm_core *cm_core,
struct nes_cm_node *cm_node) struct ietf_mpa_frame *mpa_frame, struct nes_cm_node *cm_node)
{ {
return 0; return 0;
} }
...@@ -1742,32 +1945,26 @@ static int mini_cm_accept(struct nes_cm_core *cm_core, struct ietf_mpa_frame *mp ...@@ -1742,32 +1945,26 @@ static int mini_cm_accept(struct nes_cm_core *cm_core, struct ietf_mpa_frame *mp
* mini_cm_reject - reject and teardown a connection * mini_cm_reject - reject and teardown a connection
*/ */
static int mini_cm_reject(struct nes_cm_core *cm_core, static int mini_cm_reject(struct nes_cm_core *cm_core,
struct ietf_mpa_frame *mpa_frame, struct ietf_mpa_frame *mpa_frame, struct nes_cm_node *cm_node)
struct nes_cm_node *cm_node)
{ {
int ret = 0; int ret = 0;
struct sk_buff *skb;
u16 mpa_frame_size = sizeof(struct ietf_mpa_frame) +
ntohs(mpa_frame->priv_data_len);
skb = get_free_pkt(cm_node); nes_debug(NES_DBG_CM, "%s cm_node=%p type=%d state=%d\n",
if (!skb) { __func__, cm_node, cm_node->tcp_cntxt.client, cm_node->state);
nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");
return -1;
}
/* send an MPA Request frame */
form_cm_frame(skb, cm_node, NULL, 0, mpa_frame, mpa_frame_size, SET_ACK | SET_FIN);
ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0);
if (cm_node->tcp_cntxt.client)
return ret;
cleanup_retrans_entry(cm_node);
cm_node->state = NES_CM_STATE_CLOSED; cm_node->state = NES_CM_STATE_CLOSED;
ret = send_fin(cm_node, NULL); ret = send_fin(cm_node, NULL);
if (ret < 0) { if (cm_node->accept_pend) {
printk(KERN_INFO PFX "failed to send MPA Reply (reject)\n"); BUG_ON(!cm_node->listener);
return ret; atomic_dec(&cm_node->listener->pend_accepts_cnt);
BUG_ON(atomic_read(&cm_node->listener->pend_accepts_cnt) < 0);
} }
ret = send_reset(cm_node, NULL);
return ret; return ret;
} }
...@@ -1783,35 +1980,39 @@ static int mini_cm_close(struct nes_cm_core *cm_core, struct nes_cm_node *cm_nod ...@@ -1783,35 +1980,39 @@ static int mini_cm_close(struct nes_cm_core *cm_core, struct nes_cm_node *cm_nod
return -EINVAL; return -EINVAL;
switch (cm_node->state) { switch (cm_node->state) {
/* if passed in node is null, create a reference key node for node search */ case NES_CM_STATE_SYN_RCVD:
/* check if we found an owner node for this pkt */ case NES_CM_STATE_SYN_SENT:
case NES_CM_STATE_SYN_RCVD: case NES_CM_STATE_ONE_SIDE_ESTABLISHED:
case NES_CM_STATE_SYN_SENT: case NES_CM_STATE_ESTABLISHED:
case NES_CM_STATE_ONE_SIDE_ESTABLISHED: case NES_CM_STATE_ACCEPTING:
case NES_CM_STATE_ESTABLISHED: case NES_CM_STATE_MPAREQ_SENT:
case NES_CM_STATE_ACCEPTING: case NES_CM_STATE_MPAREQ_RCVD:
case NES_CM_STATE_MPAREQ_SENT: cleanup_retrans_entry(cm_node);
cm_node->state = NES_CM_STATE_FIN_WAIT1; send_reset(cm_node, NULL);
send_fin(cm_node, NULL); break;
break; case NES_CM_STATE_CLOSE_WAIT:
case NES_CM_STATE_CLOSE_WAIT: cm_node->state = NES_CM_STATE_LAST_ACK;
cm_node->state = NES_CM_STATE_LAST_ACK; send_fin(cm_node, NULL);
send_fin(cm_node, NULL); break;
break; case NES_CM_STATE_FIN_WAIT1:
case NES_CM_STATE_FIN_WAIT1: case NES_CM_STATE_FIN_WAIT2:
case NES_CM_STATE_FIN_WAIT2: case NES_CM_STATE_LAST_ACK:
case NES_CM_STATE_LAST_ACK: case NES_CM_STATE_TIME_WAIT:
case NES_CM_STATE_TIME_WAIT: case NES_CM_STATE_CLOSING:
case NES_CM_STATE_CLOSING: ret = -1;
ret = -1; break;
break; case NES_CM_STATE_LISTENING:
case NES_CM_STATE_LISTENING: case NES_CM_STATE_UNKNOWN:
case NES_CM_STATE_UNKNOWN: case NES_CM_STATE_INITED:
case NES_CM_STATE_INITED: case NES_CM_STATE_CLOSED:
case NES_CM_STATE_CLOSED: ret = rem_ref_cm_node(cm_core, cm_node);
case NES_CM_STATE_TSA: break;
ret = rem_ref_cm_node(cm_core, cm_node); case NES_CM_STATE_TSA:
break; if (cm_node->send_entry)
printk(KERN_ERR "ERROR Close got called from STATE_TSA "
"send_entry=%p\n", cm_node->send_entry);
ret = rem_ref_cm_node(cm_core, cm_node);
break;
} }
cm_node->cm_id = NULL; cm_node->cm_id = NULL;
return ret; return ret;
...@@ -1822,25 +2023,30 @@ static int mini_cm_close(struct nes_cm_core *cm_core, struct nes_cm_node *cm_nod ...@@ -1822,25 +2023,30 @@ static int mini_cm_close(struct nes_cm_core *cm_core, struct nes_cm_node *cm_nod
* recv_pkt - recv an ETHERNET packet, and process it through CM * recv_pkt - recv an ETHERNET packet, and process it through CM
* node state machine * node state machine
*/ */
static int mini_cm_recv_pkt(struct nes_cm_core *cm_core, struct nes_vnic *nesvnic, static void mini_cm_recv_pkt(struct nes_cm_core *cm_core,
struct sk_buff *skb) struct nes_vnic *nesvnic, struct sk_buff *skb)
{ {
struct nes_cm_node *cm_node = NULL; struct nes_cm_node *cm_node = NULL;
struct nes_cm_listener *listener = NULL; struct nes_cm_listener *listener = NULL;
struct iphdr *iph; struct iphdr *iph;
struct tcphdr *tcph; struct tcphdr *tcph;
struct nes_cm_info nfo; struct nes_cm_info nfo;
int ret = 0;
if (!skb || skb->len < sizeof(struct iphdr) + sizeof(struct tcphdr)) { if (!skb)
ret = -EINVAL; return;
goto out; if (skb->len < sizeof(struct iphdr) + sizeof(struct tcphdr)) {
dev_kfree_skb_any(skb);
return;
} }
iph = (struct iphdr *)skb->data; iph = (struct iphdr *)skb->data;
tcph = (struct tcphdr *)(skb->data + sizeof(struct iphdr)); tcph = (struct tcphdr *)(skb->data + sizeof(struct iphdr));
skb_reset_network_header(skb); skb_reset_network_header(skb);
skb_set_transport_header(skb, sizeof(*tcph)); skb_set_transport_header(skb, sizeof(*tcph));
if (!tcph) {
dev_kfree_skb_any(skb);
return;
}
skb->len = ntohs(iph->tot_len); skb->len = ntohs(iph->tot_len);
nfo.loc_addr = ntohl(iph->daddr); nfo.loc_addr = ntohl(iph->daddr);
...@@ -1853,61 +2059,60 @@ static int mini_cm_recv_pkt(struct nes_cm_core *cm_core, struct nes_vnic *nesvni ...@@ -1853,61 +2059,60 @@ static int mini_cm_recv_pkt(struct nes_cm_core *cm_core, struct nes_vnic *nesvni
NIPQUAD(iph->daddr), tcph->dest, NIPQUAD(iph->daddr), tcph->dest,
NIPQUAD(iph->saddr), tcph->source); NIPQUAD(iph->saddr), tcph->source);
/* note: this call is going to increment cm_node ref count */ do {
cm_node = find_node(cm_core, cm_node = find_node(cm_core,
nfo.rem_port, nfo.rem_addr, nfo.rem_port, nfo.rem_addr,
nfo.loc_port, nfo.loc_addr); nfo.loc_port, nfo.loc_addr);
if (!cm_node) {
listener = find_listener(cm_core, nfo.loc_addr, nfo.loc_port,
NES_CM_LISTENER_ACTIVE_STATE);
if (listener) {
nfo.cm_id = listener->cm_id;
nfo.conn_type = listener->conn_type;
} else {
nfo.cm_id = NULL;
nfo.conn_type = 0;
}
cm_node = make_cm_node(cm_core, nesvnic, &nfo, listener);
if (!cm_node) { if (!cm_node) {
nes_debug(NES_DBG_CM, "Unable to allocate node\n"); /* Only type of packet accepted are for */
/* the PASSIVE open (syn only) */
if ((!tcph->syn) || (tcph->ack)) {
cm_packets_dropped++;
break;
}
listener = find_listener(cm_core, nfo.loc_addr,
nfo.loc_port,
NES_CM_LISTENER_ACTIVE_STATE);
if (listener) { if (listener) {
nes_debug(NES_DBG_CM, "unable to allocate node and decrementing listener refcount\n"); nfo.cm_id = listener->cm_id;
nfo.conn_type = listener->conn_type;
} else {
nes_debug(NES_DBG_CM, "Unable to find listener "
"for the pkt\n");
cm_packets_dropped++;
dev_kfree_skb_any(skb);
break;
}
cm_node = make_cm_node(cm_core, nesvnic, &nfo,
listener);
if (!cm_node) {
nes_debug(NES_DBG_CM, "Unable to allocate "
"node\n");
cm_packets_dropped++;
atomic_dec(&listener->ref_count); atomic_dec(&listener->ref_count);
dev_kfree_skb_any(skb);
break;
} }
ret = -1; if (!tcph->rst && !tcph->fin) {
goto out; cm_node->state = NES_CM_STATE_LISTENING;
} } else {
if (!listener) { cm_packets_dropped++;
nes_debug(NES_DBG_CM, "Packet found for unknown port %x refcnt=%d\n", rem_ref_cm_node(cm_core, cm_node);
nfo.loc_port, atomic_read(&cm_node->ref_count)); dev_kfree_skb_any(skb);
if (!tcph->rst) { break;
nes_debug(NES_DBG_CM, "Packet found for unknown port=%d"
" rem_port=%d refcnt=%d\n",
nfo.loc_port, nfo.rem_port, atomic_read(&cm_node->ref_count));
cm_node->tcp_cntxt.rcv_nxt = ntohl(tcph->seq);
cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq);
send_reset(cm_node);
} }
add_ref_cm_node(cm_node);
} else if (cm_node->state == NES_CM_STATE_TSA) {
rem_ref_cm_node(cm_core, cm_node); rem_ref_cm_node(cm_core, cm_node);
ret = -1; atomic_inc(&cm_accel_dropped_pkts);
goto out; dev_kfree_skb_any(skb);
break;
} }
add_ref_cm_node(cm_node); process_packet(cm_node, skb, cm_core);
cm_node->state = NES_CM_STATE_LISTENING; rem_ref_cm_node(cm_core, cm_node);
} } while (0);
nes_debug(NES_DBG_CM, "Processing Packet for node %p, data = (%p):\n",
cm_node, skb->data);
process_packet(cm_node, skb, cm_core);
rem_ref_cm_node(cm_core, cm_node);
out:
if (skb)
dev_kfree_skb_any(skb);
return ret;
} }
...@@ -2107,15 +2312,12 @@ int nes_cm_disconn(struct nes_qp *nesqp) ...@@ -2107,15 +2312,12 @@ int nes_cm_disconn(struct nes_qp *nesqp)
if (nesqp->disconn_pending == 0) { if (nesqp->disconn_pending == 0) {
nesqp->disconn_pending++; nesqp->disconn_pending++;
spin_unlock_irqrestore(&nesqp->lock, flags); spin_unlock_irqrestore(&nesqp->lock, flags);
/* nes_add_ref(&nesqp->ibqp); */
/* init our disconnect work element, to */ /* init our disconnect work element, to */
INIT_WORK(&nesqp->disconn_work, nes_disconnect_worker); INIT_WORK(&nesqp->disconn_work, nes_disconnect_worker);
queue_work(g_cm_core->disconn_wq, &nesqp->disconn_work); queue_work(g_cm_core->disconn_wq, &nesqp->disconn_work);
} else { } else
spin_unlock_irqrestore(&nesqp->lock, flags); spin_unlock_irqrestore(&nesqp->lock, flags);
nes_rem_ref(&nesqp->ibqp);
}
return 0; return 0;
} }
...@@ -2161,7 +2363,6 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp) ...@@ -2161,7 +2363,6 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp)
nes_debug(NES_DBG_CM, "QP%u disconnect_worker cmid is NULL\n", nes_debug(NES_DBG_CM, "QP%u disconnect_worker cmid is NULL\n",
nesqp->hwqp.qp_id); nesqp->hwqp.qp_id);
spin_unlock_irqrestore(&nesqp->lock, flags); spin_unlock_irqrestore(&nesqp->lock, flags);
nes_rem_ref(&nesqp->ibqp);
return -1; return -1;
} }
...@@ -2182,30 +2383,31 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp) ...@@ -2182,30 +2383,31 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp)
atomic_inc(&cm_disconnects); atomic_inc(&cm_disconnects);
cm_event.event = IW_CM_EVENT_DISCONNECT; cm_event.event = IW_CM_EVENT_DISCONNECT;
if (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET) { if (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET) {
issued_disconnect_reset = 1;
cm_event.status = IW_CM_EVENT_STATUS_RESET; cm_event.status = IW_CM_EVENT_STATUS_RESET;
nes_debug(NES_DBG_CM, "Generating a CM Disconnect Event (status reset) for " nes_debug(NES_DBG_CM, "Generating a CM "
" QP%u, cm_id = %p. \n", "Disconnect Event (status reset) for "
nesqp->hwqp.qp_id, cm_id); "QP%u, cm_id = %p. \n",
} else { nesqp->hwqp.qp_id, cm_id);
} else
cm_event.status = IW_CM_EVENT_STATUS_OK; cm_event.status = IW_CM_EVENT_STATUS_OK;
}
cm_event.local_addr = cm_id->local_addr; cm_event.local_addr = cm_id->local_addr;
cm_event.remote_addr = cm_id->remote_addr; cm_event.remote_addr = cm_id->remote_addr;
cm_event.private_data = NULL; cm_event.private_data = NULL;
cm_event.private_data_len = 0; cm_event.private_data_len = 0;
nes_debug(NES_DBG_CM, "Generating a CM Disconnect Event for " nes_debug(NES_DBG_CM, "Generating a CM Disconnect Event"
" QP%u, SQ Head = %u, SQ Tail = %u. cm_id = %p, refcount = %u.\n", " for QP%u, SQ Head = %u, SQ Tail = %u. "
nesqp->hwqp.qp_id, "cm_id = %p, refcount = %u.\n",
nesqp->hwqp.sq_head, nesqp->hwqp.sq_tail, cm_id, nesqp->hwqp.qp_id, nesqp->hwqp.sq_head,
atomic_read(&nesqp->refcount)); nesqp->hwqp.sq_tail, cm_id,
atomic_read(&nesqp->refcount));
spin_unlock_irqrestore(&nesqp->lock, flags); spin_unlock_irqrestore(&nesqp->lock, flags);
ret = cm_id->event_handler(cm_id, &cm_event); ret = cm_id->event_handler(cm_id, &cm_event);
if (ret) if (ret)
nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret); nes_debug(NES_DBG_CM, "OFA CM event_handler "
"returned, ret=%d\n", ret);
spin_lock_irqsave(&nesqp->lock, flags); spin_lock_irqsave(&nesqp->lock, flags);
} }
...@@ -2247,31 +2449,24 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp) ...@@ -2247,31 +2449,24 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp)
if (nesqp->flush_issued == 0) { if (nesqp->flush_issued == 0) {
nesqp->flush_issued = 1; nesqp->flush_issued = 1;
spin_unlock_irqrestore(&nesqp->lock, flags); spin_unlock_irqrestore(&nesqp->lock, flags);
flush_wqes(nesvnic->nesdev, nesqp, NES_CQP_FLUSH_RQ, 1); flush_wqes(nesvnic->nesdev, nesqp,
} else { NES_CQP_FLUSH_RQ, 1);
} else
spin_unlock_irqrestore(&nesqp->lock, flags); spin_unlock_irqrestore(&nesqp->lock, flags);
}
/* This reference is from either ModifyQP or the AE processing,
there is still a race here with modifyqp */
nes_rem_ref(&nesqp->ibqp);
} else { } else {
cm_id = nesqp->cm_id; cm_id = nesqp->cm_id;
spin_unlock_irqrestore(&nesqp->lock, flags); spin_unlock_irqrestore(&nesqp->lock, flags);
/* check to see if the inbound reset beat the outbound reset */ /* check to see if the inbound reset beat the outbound reset */
if ((!cm_id) && (last_ae==NES_AEQE_AEID_RESET_SENT)) { if ((!cm_id) && (last_ae==NES_AEQE_AEID_RESET_SENT)) {
nes_debug(NES_DBG_CM, "QP%u: Decing refcount due to inbound reset" nes_debug(NES_DBG_CM, "QP%u: Decing refcount "
" beating the outbound reset.\n", "due to inbound reset beating the "
nesqp->hwqp.qp_id); "outbound reset.\n", nesqp->hwqp.qp_id);
nes_rem_ref(&nesqp->ibqp);
} }
} }
} else { } else {
nesqp->disconn_pending = 0; nesqp->disconn_pending = 0;
spin_unlock_irqrestore(&nesqp->lock, flags); spin_unlock_irqrestore(&nesqp->lock, flags);
} }
nes_rem_ref(&nesqp->ibqp);
return 0; return 0;
} }
...@@ -2349,71 +2544,82 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) ...@@ -2349,71 +2544,82 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
nesdev = nesvnic->nesdev; nesdev = nesvnic->nesdev;
adapter = nesdev->nesadapter; adapter = nesdev->nesadapter;
nes_debug(NES_DBG_CM, "nesvnic=%p, netdev=%p, %s\n",
nesvnic, nesvnic->netdev, nesvnic->netdev->name);
/* since this is from a listen, we were able to put node handle into cm_id */
cm_node = (struct nes_cm_node *)cm_id->provider_data; cm_node = (struct nes_cm_node *)cm_id->provider_data;
nes_debug(NES_DBG_CM, "nes_accept: cm_node= %p nesvnic=%p, netdev=%p,"
"%s\n", cm_node, nesvnic, nesvnic->netdev,
nesvnic->netdev->name);
/* associate the node with the QP */ /* associate the node with the QP */
nesqp->cm_node = (void *)cm_node; nesqp->cm_node = (void *)cm_node;
cm_node->nesqp = nesqp;
nes_add_ref(&nesqp->ibqp);
nes_debug(NES_DBG_CM, "QP%u, cm_node=%p, jiffies = %lu\n", nes_debug(NES_DBG_CM, "QP%u, cm_node=%p, jiffies = %lu listener = %p\n",
nesqp->hwqp.qp_id, cm_node, jiffies); nesqp->hwqp.qp_id, cm_node, jiffies, cm_node->listener);
atomic_inc(&cm_accepts); atomic_inc(&cm_accepts);
nes_debug(NES_DBG_CM, "netdev refcnt = %u.\n", nes_debug(NES_DBG_CM, "netdev refcnt = %u.\n",
atomic_read(&nesvnic->netdev->refcnt)); atomic_read(&nesvnic->netdev->refcnt));
/* allocate the ietf frame and space for private data */ /* allocate the ietf frame and space for private data */
nesqp->ietf_frame = pci_alloc_consistent(nesdev->pcidev, nesqp->ietf_frame = pci_alloc_consistent(nesdev->pcidev,
sizeof(struct ietf_mpa_frame) + conn_param->private_data_len, sizeof(struct ietf_mpa_frame) + conn_param->private_data_len,
&nesqp->ietf_frame_pbase); &nesqp->ietf_frame_pbase);
if (!nesqp->ietf_frame) {
nes_debug(NES_DBG_CM, "Unable to allocate memory for private data\n");
return -ENOMEM;
}
if (!nesqp->ietf_frame) {
nes_debug(NES_DBG_CM, "Unable to allocate memory for private "
"data\n");
return -ENOMEM;
}
/* setup the MPA frame */
nesqp->private_data_len = conn_param->private_data_len;
memcpy(nesqp->ietf_frame->key, IEFT_MPA_KEY_REP, IETF_MPA_KEY_SIZE);
memcpy(nesqp->ietf_frame->priv_data, conn_param->private_data, /* setup the MPA frame */
conn_param->private_data_len); nesqp->private_data_len = conn_param->private_data_len;
memcpy(nesqp->ietf_frame->key, IEFT_MPA_KEY_REP, IETF_MPA_KEY_SIZE);
nesqp->ietf_frame->priv_data_len = cpu_to_be16(conn_param->private_data_len); memcpy(nesqp->ietf_frame->priv_data, conn_param->private_data,
nesqp->ietf_frame->rev = mpa_version; conn_param->private_data_len);
nesqp->ietf_frame->flags = IETF_MPA_FLAGS_CRC;
/* setup our first outgoing iWarp send WQE (the IETF frame response) */ nesqp->ietf_frame->priv_data_len =
wqe = &nesqp->hwqp.sq_vbase[0]; cpu_to_be16(conn_param->private_data_len);
nesqp->ietf_frame->rev = mpa_version;
nesqp->ietf_frame->flags = IETF_MPA_FLAGS_CRC;
if (cm_id->remote_addr.sin_addr.s_addr != cm_id->local_addr.sin_addr.s_addr) { /* setup our first outgoing iWarp send WQE (the IETF frame response) */
u64temp = (unsigned long)nesqp; wqe = &nesqp->hwqp.sq_vbase[0];
u64temp |= NES_SW_CONTEXT_ALIGN>>1;
set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX, if (cm_id->remote_addr.sin_addr.s_addr !=
u64temp); cm_id->local_addr.sin_addr.s_addr) {
wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] = u64temp = (unsigned long)nesqp;
cpu_to_le32(NES_IWARP_SQ_WQE_STREAMING | NES_IWARP_SQ_WQE_WRPDU); u64temp |= NES_SW_CONTEXT_ALIGN>>1;
wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] = set_wqe_64bit_value(wqe->wqe_words,
cpu_to_le32(conn_param->private_data_len + sizeof(struct ietf_mpa_frame)); NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX,
wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_LOW_IDX] = u64temp);
cpu_to_le32((u32)nesqp->ietf_frame_pbase); wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] =
wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_HIGH_IDX] = cpu_to_le32(NES_IWARP_SQ_WQE_STREAMING |
cpu_to_le32((u32)((u64)nesqp->ietf_frame_pbase >> 32)); NES_IWARP_SQ_WQE_WRPDU);
wqe->wqe_words[NES_IWARP_SQ_WQE_LENGTH0_IDX] = wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] =
cpu_to_le32(conn_param->private_data_len + sizeof(struct ietf_mpa_frame)); cpu_to_le32(conn_param->private_data_len +
wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = 0; sizeof(struct ietf_mpa_frame));
wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_LOW_IDX] =
nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32( cpu_to_le32((u32)nesqp->ietf_frame_pbase);
NES_QPCONTEXT_ORDIRD_LSMM_PRESENT | NES_QPCONTEXT_ORDIRD_WRPDU); wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_HIGH_IDX] =
} else { cpu_to_le32((u32)((u64)nesqp->ietf_frame_pbase >> 32));
nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32((NES_QPCONTEXT_ORDIRD_LSMM_PRESENT | wqe->wqe_words[NES_IWARP_SQ_WQE_LENGTH0_IDX] =
NES_QPCONTEXT_ORDIRD_WRPDU | NES_QPCONTEXT_ORDIRD_ALSMM)); cpu_to_le32(conn_param->private_data_len +
} sizeof(struct ietf_mpa_frame));
nesqp->skip_lsmm = 1; wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = 0;
nesqp->nesqp_context->ird_ord_sizes |=
cpu_to_le32(NES_QPCONTEXT_ORDIRD_LSMM_PRESENT |
NES_QPCONTEXT_ORDIRD_WRPDU);
} else {
nesqp->nesqp_context->ird_ord_sizes |=
cpu_to_le32((NES_QPCONTEXT_ORDIRD_LSMM_PRESENT |
NES_QPCONTEXT_ORDIRD_WRPDU |
NES_QPCONTEXT_ORDIRD_ALSMM));
}
nesqp->skip_lsmm = 1;
/* Cache the cm_id in the qp */ /* Cache the cm_id in the qp */
...@@ -2424,55 +2630,75 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) ...@@ -2424,55 +2630,75 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
cm_id->provider_data = nesqp; cm_id->provider_data = nesqp;
nesqp->active_conn = 0; nesqp->active_conn = 0;
if (cm_node->state == NES_CM_STATE_TSA)
nes_debug(NES_DBG_CM, "Already state = TSA for cm_node=%p\n",
cm_node);
nes_cm_init_tsa_conn(nesqp, cm_node); nes_cm_init_tsa_conn(nesqp, cm_node);
nesqp->nesqp_context->tcpPorts[0] = cpu_to_le16(ntohs(cm_id->local_addr.sin_port)); nesqp->nesqp_context->tcpPorts[0] =
nesqp->nesqp_context->tcpPorts[1] = cpu_to_le16(ntohs(cm_id->remote_addr.sin_port)); cpu_to_le16(ntohs(cm_id->local_addr.sin_port));
nesqp->nesqp_context->ip0 = cpu_to_le32(ntohl(cm_id->remote_addr.sin_addr.s_addr)); nesqp->nesqp_context->tcpPorts[1] =
cpu_to_le16(ntohs(cm_id->remote_addr.sin_port));
if (ipv4_is_loopback(cm_id->remote_addr.sin_addr.s_addr))
nesqp->nesqp_context->ip0 =
cpu_to_le32(ntohl(nesvnic->local_ipaddr));
else
nesqp->nesqp_context->ip0 =
cpu_to_le32(ntohl(cm_id->remote_addr.sin_addr.s_addr));
nesqp->nesqp_context->misc2 |= cpu_to_le32( nesqp->nesqp_context->misc2 |= cpu_to_le32(
(u32)PCI_FUNC(nesdev->pcidev->devfn) << NES_QPCONTEXT_MISC2_SRC_IP_SHIFT); (u32)PCI_FUNC(nesdev->pcidev->devfn) <<
NES_QPCONTEXT_MISC2_SRC_IP_SHIFT);
nesqp->nesqp_context->arp_index_vlan |= cpu_to_le32( nesqp->nesqp_context->arp_index_vlan |=
nes_arp_table(nesdev, le32_to_cpu(nesqp->nesqp_context->ip0), NULL, cpu_to_le32(nes_arp_table(nesdev,
le32_to_cpu(nesqp->nesqp_context->ip0), NULL,
NES_ARP_RESOLVE) << 16); NES_ARP_RESOLVE) << 16);
nesqp->nesqp_context->ts_val_delta = cpu_to_le32( nesqp->nesqp_context->ts_val_delta = cpu_to_le32(
jiffies - nes_read_indexed(nesdev, NES_IDX_TCP_NOW)); jiffies - nes_read_indexed(nesdev, NES_IDX_TCP_NOW));
nesqp->nesqp_context->ird_index = cpu_to_le32(nesqp->hwqp.qp_id); nesqp->nesqp_context->ird_index = cpu_to_le32(nesqp->hwqp.qp_id);
nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32( nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32(
((u32)1 << NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT)); ((u32)1 << NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT));
nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32((u32)conn_param->ord); nesqp->nesqp_context->ird_ord_sizes |=
cpu_to_le32((u32)conn_param->ord);
memset(&nes_quad, 0, sizeof(nes_quad)); memset(&nes_quad, 0, sizeof(nes_quad));
nes_quad.DstIpAdrIndex = cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24); nes_quad.DstIpAdrIndex =
nes_quad.SrcIpadr = cm_id->remote_addr.sin_addr.s_addr; cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24);
nes_quad.TcpPorts[0] = cm_id->remote_addr.sin_port; if (ipv4_is_loopback(cm_id->remote_addr.sin_addr.s_addr))
nes_quad.TcpPorts[1] = cm_id->local_addr.sin_port; nes_quad.SrcIpadr = nesvnic->local_ipaddr;
else
nes_quad.SrcIpadr = cm_id->remote_addr.sin_addr.s_addr;
nes_quad.TcpPorts[0] = cm_id->remote_addr.sin_port;
nes_quad.TcpPorts[1] = cm_id->local_addr.sin_port;
/* Produce hash key */ /* Produce hash key */
crc_value = get_crc_value(&nes_quad); crc_value = get_crc_value(&nes_quad);
nesqp->hte_index = cpu_to_be32(crc_value ^ 0xffffffff); nesqp->hte_index = cpu_to_be32(crc_value ^ 0xffffffff);
nes_debug(NES_DBG_CM, "HTE Index = 0x%08X, CRC = 0x%08X\n", nes_debug(NES_DBG_CM, "HTE Index = 0x%08X, CRC = 0x%08X\n",
nesqp->hte_index, nesqp->hte_index & adapter->hte_index_mask); nesqp->hte_index, nesqp->hte_index & adapter->hte_index_mask);
nesqp->hte_index &= adapter->hte_index_mask; nesqp->hte_index &= adapter->hte_index_mask;
nesqp->nesqp_context->hte_index = cpu_to_le32(nesqp->hte_index); nesqp->nesqp_context->hte_index = cpu_to_le32(nesqp->hte_index);
cm_node->cm_core->api->accelerated(cm_node->cm_core, cm_node); cm_node->cm_core->api->accelerated(cm_node->cm_core, cm_node);
nes_debug(NES_DBG_CM, "QP%u, Destination IP = 0x%08X:0x%04X, local = 0x%08X:0x%04X," nes_debug(NES_DBG_CM, "QP%u, Destination IP = 0x%08X:0x%04X, local = "
" rcv_nxt=0x%08X, snd_nxt=0x%08X, mpa + private data length=%zu.\n", "0x%08X:0x%04X, rcv_nxt=0x%08X, snd_nxt=0x%08X, mpa + "
nesqp->hwqp.qp_id, "private data length=%zu.\n", nesqp->hwqp.qp_id,
ntohl(cm_id->remote_addr.sin_addr.s_addr), ntohl(cm_id->remote_addr.sin_addr.s_addr),
ntohs(cm_id->remote_addr.sin_port), ntohs(cm_id->remote_addr.sin_port),
ntohl(cm_id->local_addr.sin_addr.s_addr), ntohl(cm_id->local_addr.sin_addr.s_addr),
ntohs(cm_id->local_addr.sin_port), ntohs(cm_id->local_addr.sin_port),
le32_to_cpu(nesqp->nesqp_context->rcv_nxt), le32_to_cpu(nesqp->nesqp_context->rcv_nxt),
le32_to_cpu(nesqp->nesqp_context->snd_nxt), le32_to_cpu(nesqp->nesqp_context->snd_nxt),
conn_param->private_data_len+sizeof(struct ietf_mpa_frame)); conn_param->private_data_len +
sizeof(struct ietf_mpa_frame));
attr.qp_state = IB_QPS_RTS; attr.qp_state = IB_QPS_RTS;
nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL); nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL);
...@@ -2489,15 +2715,16 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) ...@@ -2489,15 +2715,16 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
cm_event.private_data_len = 0; cm_event.private_data_len = 0;
ret = cm_id->event_handler(cm_id, &cm_event); ret = cm_id->event_handler(cm_id, &cm_event);
if (cm_node->loopbackpartner) { if (cm_node->loopbackpartner) {
cm_node->loopbackpartner->mpa_frame_size = nesqp->private_data_len; cm_node->loopbackpartner->mpa_frame_size =
nesqp->private_data_len;
/* copy entire MPA frame to our cm_node's frame */ /* copy entire MPA frame to our cm_node's frame */
memcpy(cm_node->loopbackpartner->mpa_frame_buf, nesqp->ietf_frame->priv_data, memcpy(cm_node->loopbackpartner->mpa_frame_buf,
nesqp->private_data_len); nesqp->ietf_frame->priv_data, nesqp->private_data_len);
create_event(cm_node->loopbackpartner, NES_CM_EVENT_CONNECTED); create_event(cm_node->loopbackpartner, NES_CM_EVENT_CONNECTED);
} }
if (ret) if (ret)
printk("%s[%u] OFA CM event_handler returned, ret=%d\n", printk(KERN_ERR "%s[%u] OFA CM event_handler returned, "
__func__, __LINE__, ret); "ret=%d\n", __func__, __LINE__, ret);
return 0; return 0;
} }
...@@ -2555,74 +2782,61 @@ int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) ...@@ -2555,74 +2782,61 @@ int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
if (!nesdev) if (!nesdev)
return -EINVAL; return -EINVAL;
atomic_inc(&cm_connects); nes_debug(NES_DBG_CM, "QP%u, current IP = 0x%08X, Destination IP = "
"0x%08X:0x%04X, local = 0x%08X:0x%04X.\n", nesqp->hwqp.qp_id,
nesqp->ietf_frame = kzalloc(sizeof(struct ietf_mpa_frame) + ntohl(nesvnic->local_ipaddr),
conn_param->private_data_len, GFP_KERNEL); ntohl(cm_id->remote_addr.sin_addr.s_addr),
if (!nesqp->ietf_frame) ntohs(cm_id->remote_addr.sin_port),
return -ENOMEM; ntohl(cm_id->local_addr.sin_addr.s_addr),
ntohs(cm_id->local_addr.sin_port));
/* set qp as having an active connection */ atomic_inc(&cm_connects);
nesqp->active_conn = 1; nesqp->active_conn = 1;
nes_debug(NES_DBG_CM, "QP%u, Destination IP = 0x%08X:0x%04X, local = 0x%08X:0x%04X.\n",
nesqp->hwqp.qp_id,
ntohl(cm_id->remote_addr.sin_addr.s_addr),
ntohs(cm_id->remote_addr.sin_port),
ntohl(cm_id->local_addr.sin_addr.s_addr),
ntohs(cm_id->local_addr.sin_port));
/* cache the cm_id in the qp */ /* cache the cm_id in the qp */
nesqp->cm_id = cm_id; nesqp->cm_id = cm_id;
cm_id->provider_data = nesqp; cm_id->provider_data = nesqp;
/* copy the private data */
if (conn_param->private_data_len) {
memcpy(nesqp->ietf_frame->priv_data, conn_param->private_data,
conn_param->private_data_len);
}
nesqp->private_data_len = conn_param->private_data_len; nesqp->private_data_len = conn_param->private_data_len;
nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32((u32)conn_param->ord); nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32((u32)conn_param->ord);
nes_debug(NES_DBG_CM, "requested ord = 0x%08X.\n", (u32)conn_param->ord); nes_debug(NES_DBG_CM, "requested ord = 0x%08X.\n", (u32)conn_param->ord);
nes_debug(NES_DBG_CM, "mpa private data len =%u\n", conn_param->private_data_len); nes_debug(NES_DBG_CM, "mpa private data len =%u\n",
conn_param->private_data_len);
strcpy(&nesqp->ietf_frame->key[0], IEFT_MPA_KEY_REQ);
nesqp->ietf_frame->flags = IETF_MPA_FLAGS_CRC;
nesqp->ietf_frame->rev = IETF_MPA_VERSION;
nesqp->ietf_frame->priv_data_len = htons(conn_param->private_data_len);
if (cm_id->local_addr.sin_addr.s_addr != cm_id->remote_addr.sin_addr.s_addr) if (cm_id->local_addr.sin_addr.s_addr !=
cm_id->remote_addr.sin_addr.s_addr)
nes_manage_apbvt(nesvnic, ntohs(cm_id->local_addr.sin_port), nes_manage_apbvt(nesvnic, ntohs(cm_id->local_addr.sin_port),
PCI_FUNC(nesdev->pcidev->devfn), NES_MANAGE_APBVT_ADD); PCI_FUNC(nesdev->pcidev->devfn), NES_MANAGE_APBVT_ADD);
/* set up the connection params for the node */ /* set up the connection params for the node */
cm_info.loc_addr = (cm_id->local_addr.sin_addr.s_addr); cm_info.loc_addr = htonl(cm_id->local_addr.sin_addr.s_addr);
cm_info.loc_port = (cm_id->local_addr.sin_port); cm_info.loc_port = htons(cm_id->local_addr.sin_port);
cm_info.rem_addr = (cm_id->remote_addr.sin_addr.s_addr); cm_info.rem_addr = htonl(cm_id->remote_addr.sin_addr.s_addr);
cm_info.rem_port = (cm_id->remote_addr.sin_port); cm_info.rem_port = htons(cm_id->remote_addr.sin_port);
cm_info.cm_id = cm_id; cm_info.cm_id = cm_id;
cm_info.conn_type = NES_CM_IWARP_CONN_TYPE; cm_info.conn_type = NES_CM_IWARP_CONN_TYPE;
cm_id->add_ref(cm_id); cm_id->add_ref(cm_id);
nes_add_ref(&nesqp->ibqp);
/* create a connect CM node connection */ /* create a connect CM node connection */
cm_node = g_cm_core->api->connect(g_cm_core, nesvnic, nesqp->ietf_frame, &cm_info); cm_node = g_cm_core->api->connect(g_cm_core, nesvnic,
conn_param->private_data_len, (void *)conn_param->private_data,
&cm_info);
if (!cm_node) { if (!cm_node) {
if (cm_id->local_addr.sin_addr.s_addr != cm_id->remote_addr.sin_addr.s_addr) if (cm_id->local_addr.sin_addr.s_addr !=
cm_id->remote_addr.sin_addr.s_addr)
nes_manage_apbvt(nesvnic, ntohs(cm_id->local_addr.sin_port), nes_manage_apbvt(nesvnic, ntohs(cm_id->local_addr.sin_port),
PCI_FUNC(nesdev->pcidev->devfn), NES_MANAGE_APBVT_DEL); PCI_FUNC(nesdev->pcidev->devfn),
nes_rem_ref(&nesqp->ibqp); NES_MANAGE_APBVT_DEL);
kfree(nesqp->ietf_frame);
nesqp->ietf_frame = NULL;
cm_id->rem_ref(cm_id); cm_id->rem_ref(cm_id);
return -ENOMEM; return -ENOMEM;
} }
cm_node->apbvt_set = 1; cm_node->apbvt_set = 1;
nesqp->cm_node = cm_node; nesqp->cm_node = cm_node;
cm_node->nesqp = nesqp;
return 0; return 0;
} }
...@@ -2664,7 +2878,7 @@ int nes_create_listen(struct iw_cm_id *cm_id, int backlog) ...@@ -2664,7 +2878,7 @@ int nes_create_listen(struct iw_cm_id *cm_id, int backlog)
cm_node = g_cm_core->api->listen(g_cm_core, nesvnic, &cm_info); cm_node = g_cm_core->api->listen(g_cm_core, nesvnic, &cm_info);
if (!cm_node) { if (!cm_node) {
printk("%s[%u] Error returned from listen API call\n", printk(KERN_ERR "%s[%u] Error returned from listen API call\n",
__func__, __LINE__); __func__, __LINE__);
return -ENOMEM; return -ENOMEM;
} }
...@@ -2672,10 +2886,13 @@ int nes_create_listen(struct iw_cm_id *cm_id, int backlog) ...@@ -2672,10 +2886,13 @@ int nes_create_listen(struct iw_cm_id *cm_id, int backlog)
cm_id->provider_data = cm_node; cm_id->provider_data = cm_node;
if (!cm_node->reused_node) { if (!cm_node->reused_node) {
err = nes_manage_apbvt(nesvnic, ntohs(cm_id->local_addr.sin_port), err = nes_manage_apbvt(nesvnic,
PCI_FUNC(nesvnic->nesdev->pcidev->devfn), NES_MANAGE_APBVT_ADD); ntohs(cm_id->local_addr.sin_port),
PCI_FUNC(nesvnic->nesdev->pcidev->devfn),
NES_MANAGE_APBVT_ADD);
if (err) { if (err) {
printk("nes_manage_apbvt call returned %d.\n", err); printk(KERN_ERR "nes_manage_apbvt call returned %d.\n",
err);
g_cm_core->api->stop_listener(g_cm_core, (void *)cm_node); g_cm_core->api->stop_listener(g_cm_core, (void *)cm_node);
return err; return err;
} }
...@@ -2795,53 +3012,70 @@ static void cm_event_connected(struct nes_cm_event *event) ...@@ -2795,53 +3012,70 @@ static void cm_event_connected(struct nes_cm_event *event)
nes_cm_init_tsa_conn(nesqp, cm_node); nes_cm_init_tsa_conn(nesqp, cm_node);
/* set the QP tsa context */ /* set the QP tsa context */
nesqp->nesqp_context->tcpPorts[0] = cpu_to_le16(ntohs(cm_id->local_addr.sin_port)); nesqp->nesqp_context->tcpPorts[0] =
nesqp->nesqp_context->tcpPorts[1] = cpu_to_le16(ntohs(cm_id->remote_addr.sin_port)); cpu_to_le16(ntohs(cm_id->local_addr.sin_port));
nesqp->nesqp_context->ip0 = cpu_to_le32(ntohl(cm_id->remote_addr.sin_addr.s_addr)); nesqp->nesqp_context->tcpPorts[1] =
cpu_to_le16(ntohs(cm_id->remote_addr.sin_port));
if (ipv4_is_loopback(cm_id->remote_addr.sin_addr.s_addr))
nesqp->nesqp_context->ip0 =
cpu_to_le32(ntohl(nesvnic->local_ipaddr));
else
nesqp->nesqp_context->ip0 =
cpu_to_le32(ntohl(cm_id->remote_addr.sin_addr.s_addr));
nesqp->nesqp_context->misc2 |= cpu_to_le32( nesqp->nesqp_context->misc2 |= cpu_to_le32(
(u32)PCI_FUNC(nesdev->pcidev->devfn) << NES_QPCONTEXT_MISC2_SRC_IP_SHIFT); (u32)PCI_FUNC(nesdev->pcidev->devfn) <<
NES_QPCONTEXT_MISC2_SRC_IP_SHIFT);
nesqp->nesqp_context->arp_index_vlan |= cpu_to_le32( nesqp->nesqp_context->arp_index_vlan |= cpu_to_le32(
nes_arp_table(nesdev, le32_to_cpu(nesqp->nesqp_context->ip0), nes_arp_table(nesdev,
le32_to_cpu(nesqp->nesqp_context->ip0),
NULL, NES_ARP_RESOLVE) << 16); NULL, NES_ARP_RESOLVE) << 16);
nesqp->nesqp_context->ts_val_delta = cpu_to_le32( nesqp->nesqp_context->ts_val_delta = cpu_to_le32(
jiffies - nes_read_indexed(nesdev, NES_IDX_TCP_NOW)); jiffies - nes_read_indexed(nesdev, NES_IDX_TCP_NOW));
nesqp->nesqp_context->ird_index = cpu_to_le32(nesqp->hwqp.qp_id); nesqp->nesqp_context->ird_index = cpu_to_le32(nesqp->hwqp.qp_id);
nesqp->nesqp_context->ird_ord_sizes |= nesqp->nesqp_context->ird_ord_sizes |=
cpu_to_le32((u32)1 << NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT); cpu_to_le32((u32)1 <<
NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT);
/* Adjust tail for not having a LSMM */ /* Adjust tail for not having a LSMM */
nesqp->hwqp.sq_tail = 1; nesqp->hwqp.sq_tail = 1;
#if defined(NES_SEND_FIRST_WRITE) #if defined(NES_SEND_FIRST_WRITE)
if (cm_node->send_write0) { if (cm_node->send_write0) {
nes_debug(NES_DBG_CM, "Sending first write.\n"); nes_debug(NES_DBG_CM, "Sending first write.\n");
wqe = &nesqp->hwqp.sq_vbase[0]; wqe = &nesqp->hwqp.sq_vbase[0];
u64temp = (unsigned long)nesqp; u64temp = (unsigned long)nesqp;
u64temp |= NES_SW_CONTEXT_ALIGN>>1; u64temp |= NES_SW_CONTEXT_ALIGN>>1;
set_wqe_64bit_value(wqe->wqe_words, NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX, set_wqe_64bit_value(wqe->wqe_words,
u64temp); NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX, u64temp);
wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] = cpu_to_le32(NES_IWARP_SQ_OP_RDMAW); wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] =
wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] = 0; cpu_to_le32(NES_IWARP_SQ_OP_RDMAW);
wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_LOW_IDX] = 0; wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] = 0;
wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_HIGH_IDX] = 0; wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_LOW_IDX] = 0;
wqe->wqe_words[NES_IWARP_SQ_WQE_LENGTH0_IDX] = 0; wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_HIGH_IDX] = 0;
wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = 0; wqe->wqe_words[NES_IWARP_SQ_WQE_LENGTH0_IDX] = 0;
wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = 0;
/* use the reserved spot on the WQ for the extra first WQE */
nesqp->nesqp_context->ird_ord_sizes &= cpu_to_le32(~(NES_QPCONTEXT_ORDIRD_LSMM_PRESENT | /* use the reserved spot on the WQ for the extra first WQE */
NES_QPCONTEXT_ORDIRD_WRPDU | NES_QPCONTEXT_ORDIRD_ALSMM)); nesqp->nesqp_context->ird_ord_sizes &=
nesqp->skip_lsmm = 1; cpu_to_le32(~(NES_QPCONTEXT_ORDIRD_LSMM_PRESENT |
nesqp->hwqp.sq_tail = 0; NES_QPCONTEXT_ORDIRD_WRPDU |
nes_write32(nesdev->regs + NES_WQE_ALLOC, NES_QPCONTEXT_ORDIRD_ALSMM));
(1 << 24) | 0x00800000 | nesqp->hwqp.qp_id); nesqp->skip_lsmm = 1;
} nesqp->hwqp.sq_tail = 0;
nes_write32(nesdev->regs + NES_WQE_ALLOC,
(1 << 24) | 0x00800000 | nesqp->hwqp.qp_id);
}
#endif #endif
memset(&nes_quad, 0, sizeof(nes_quad)); memset(&nes_quad, 0, sizeof(nes_quad));
nes_quad.DstIpAdrIndex = cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24); nes_quad.DstIpAdrIndex =
nes_quad.SrcIpadr = cm_id->remote_addr.sin_addr.s_addr; cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24);
if (ipv4_is_loopback(cm_id->remote_addr.sin_addr.s_addr))
nes_quad.SrcIpadr = nesvnic->local_ipaddr;
else
nes_quad.SrcIpadr = cm_id->remote_addr.sin_addr.s_addr;
nes_quad.TcpPorts[0] = cm_id->remote_addr.sin_port; nes_quad.TcpPorts[0] = cm_id->remote_addr.sin_port;
nes_quad.TcpPorts[1] = cm_id->local_addr.sin_port; nes_quad.TcpPorts[1] = cm_id->local_addr.sin_port;
...@@ -2858,10 +3092,6 @@ static void cm_event_connected(struct nes_cm_event *event) ...@@ -2858,10 +3092,6 @@ static void cm_event_connected(struct nes_cm_event *event)
nesqp->private_data_len = (u8) cm_node->mpa_frame_size; nesqp->private_data_len = (u8) cm_node->mpa_frame_size;
cm_node->cm_core->api->accelerated(cm_node->cm_core, cm_node); cm_node->cm_core->api->accelerated(cm_node->cm_core, cm_node);
/* modify QP state to rts */
attr.qp_state = IB_QPS_RTS;
nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL);
/* notify OF layer we successfully created the requested connection */ /* notify OF layer we successfully created the requested connection */
cm_event.event = IW_CM_EVENT_CONNECT_REPLY; cm_event.event = IW_CM_EVENT_CONNECT_REPLY;
cm_event.status = IW_CM_EVENT_STATUS_ACCEPTED; cm_event.status = IW_CM_EVENT_STATUS_ACCEPTED;
...@@ -2870,20 +3100,21 @@ static void cm_event_connected(struct nes_cm_event *event) ...@@ -2870,20 +3100,21 @@ static void cm_event_connected(struct nes_cm_event *event)
cm_event.local_addr.sin_port = cm_id->local_addr.sin_port; cm_event.local_addr.sin_port = cm_id->local_addr.sin_port;
cm_event.remote_addr = cm_id->remote_addr; cm_event.remote_addr = cm_id->remote_addr;
cm_event.private_data = (void *)event->cm_node->mpa_frame_buf; cm_event.private_data = (void *)event->cm_node->mpa_frame_buf;
cm_event.private_data_len = (u8) event->cm_node->mpa_frame_size; cm_event.private_data_len = (u8) event->cm_node->mpa_frame_size;
cm_event.local_addr.sin_addr.s_addr = event->cm_info.rem_addr; cm_event.local_addr.sin_addr.s_addr = event->cm_info.rem_addr;
ret = cm_id->event_handler(cm_id, &cm_event); ret = cm_id->event_handler(cm_id, &cm_event);
nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret); nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret);
if (ret) if (ret)
printk("%s[%u] OFA CM event_handler returned, ret=%d\n", printk(KERN_ERR "%s[%u] OFA CM event_handler returned, "
__func__, __LINE__, ret); "ret=%d\n", __func__, __LINE__, ret);
nes_debug(NES_DBG_CM, "Exiting connect thread for QP%u. jiffies = %lu\n", attr.qp_state = IB_QPS_RTS;
nesqp->hwqp.qp_id, jiffies ); nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL);
nes_rem_ref(&nesqp->ibqp); nes_debug(NES_DBG_CM, "Exiting connect thread for QP%u. jiffies = "
"%lu\n", nesqp->hwqp.qp_id, jiffies);
return; return;
} }
...@@ -2927,17 +3158,19 @@ static void cm_event_connect_error(struct nes_cm_event *event) ...@@ -2927,17 +3158,19 @@ static void cm_event_connect_error(struct nes_cm_event *event)
cm_event.private_data = NULL; cm_event.private_data = NULL;
cm_event.private_data_len = 0; cm_event.private_data_len = 0;
nes_debug(NES_DBG_CM, "call CM_EVENT REJECTED, local_addr=%08x, remove_addr=%08x\n", nes_debug(NES_DBG_CM, "call CM_EVENT REJECTED, local_addr=%08x, "
cm_event.local_addr.sin_addr.s_addr, cm_event.remote_addr.sin_addr.s_addr); "remove_addr=%08x\n", cm_event.local_addr.sin_addr.s_addr,
cm_event.remote_addr.sin_addr.s_addr);
ret = cm_id->event_handler(cm_id, &cm_event); ret = cm_id->event_handler(cm_id, &cm_event);
nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret); nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret);
if (ret) if (ret)
printk("%s[%u] OFA CM event_handler returned, ret=%d\n", printk(KERN_ERR "%s[%u] OFA CM event_handler returned, "
__func__, __LINE__, ret); "ret=%d\n", __func__, __LINE__, ret);
nes_rem_ref(&nesqp->ibqp); nes_rem_ref(&nesqp->ibqp);
cm_id->rem_ref(cm_id); cm_id->rem_ref(cm_id);
rem_ref_cm_node(event->cm_node->cm_core, event->cm_node);
return; return;
} }
...@@ -3040,7 +3273,8 @@ static int nes_cm_post_event(struct nes_cm_event *event) ...@@ -3040,7 +3273,8 @@ static int nes_cm_post_event(struct nes_cm_event *event)
add_ref_cm_node(event->cm_node); add_ref_cm_node(event->cm_node);
event->cm_info.cm_id->add_ref(event->cm_info.cm_id); event->cm_info.cm_id->add_ref(event->cm_info.cm_id);
INIT_WORK(&event->event_work, nes_cm_event_handler); INIT_WORK(&event->event_work, nes_cm_event_handler);
nes_debug(NES_DBG_CM, "queue_work, event=%p\n", event); nes_debug(NES_DBG_CM, "cm_node=%p queue_work, event=%p\n",
event->cm_node, event);
queue_work(event->cm_node->cm_core->event_wq, &event->event_work); queue_work(event->cm_node->cm_core->event_wq, &event->event_work);
...@@ -3056,46 +3290,48 @@ static int nes_cm_post_event(struct nes_cm_event *event) ...@@ -3056,46 +3290,48 @@ static int nes_cm_post_event(struct nes_cm_event *event)
*/ */
static void nes_cm_event_handler(struct work_struct *work) static void nes_cm_event_handler(struct work_struct *work)
{ {
struct nes_cm_event *event = container_of(work, struct nes_cm_event, event_work); struct nes_cm_event *event = container_of(work, struct nes_cm_event,
event_work);
struct nes_cm_core *cm_core; struct nes_cm_core *cm_core;
if ((!event) || (!event->cm_node) || (!event->cm_node->cm_core)) { if ((!event) || (!event->cm_node) || (!event->cm_node->cm_core))
return; return;
}
cm_core = event->cm_node->cm_core; cm_core = event->cm_node->cm_core;
nes_debug(NES_DBG_CM, "event=%p, event->type=%u, events posted=%u\n", nes_debug(NES_DBG_CM, "event=%p, event->type=%u, events posted=%u\n",
event, event->type, atomic_read(&cm_core->events_posted)); event, event->type, atomic_read(&cm_core->events_posted));
switch (event->type) { switch (event->type) {
case NES_CM_EVENT_MPA_REQ: case NES_CM_EVENT_MPA_REQ:
cm_event_mpa_req(event); cm_event_mpa_req(event);
nes_debug(NES_DBG_CM, "CM Event: MPA REQUEST\n"); nes_debug(NES_DBG_CM, "cm_node=%p CM Event: MPA REQUEST\n",
break; event->cm_node);
case NES_CM_EVENT_RESET: break;
nes_debug(NES_DBG_CM, "CM Event: RESET\n"); case NES_CM_EVENT_RESET:
cm_event_reset(event); nes_debug(NES_DBG_CM, "cm_node = %p CM Event: RESET\n",
break; event->cm_node);
case NES_CM_EVENT_CONNECTED: cm_event_reset(event);
if ((!event->cm_node->cm_id) || break;
(event->cm_node->state != NES_CM_STATE_TSA)) { case NES_CM_EVENT_CONNECTED:
break; if ((!event->cm_node->cm_id) ||
} (event->cm_node->state != NES_CM_STATE_TSA))
cm_event_connected(event);
nes_debug(NES_DBG_CM, "CM Event: CONNECTED\n");
break; break;
case NES_CM_EVENT_ABORTED: cm_event_connected(event);
if ((!event->cm_node->cm_id) || (event->cm_node->state == NES_CM_STATE_TSA)) { nes_debug(NES_DBG_CM, "CM Event: CONNECTED\n");
break; break;
} case NES_CM_EVENT_ABORTED:
cm_event_connect_error(event); if ((!event->cm_node->cm_id) ||
nes_debug(NES_DBG_CM, "CM Event: ABORTED\n"); (event->cm_node->state == NES_CM_STATE_TSA))
break;
case NES_CM_EVENT_DROPPED_PKT:
nes_debug(NES_DBG_CM, "CM Event: DROPPED PKT\n");
break;
default:
nes_debug(NES_DBG_CM, "CM Event: UNKNOWN EVENT TYPE\n");
break; break;
cm_event_connect_error(event);
nes_debug(NES_DBG_CM, "CM Event: ABORTED\n");
break;
case NES_CM_EVENT_DROPPED_PKT:
nes_debug(NES_DBG_CM, "CM Event: DROPPED PKT\n");
break;
default:
nes_debug(NES_DBG_CM, "CM Event: UNKNOWN EVENT TYPE\n");
break;
} }
atomic_dec(&cm_core->events_posted); atomic_dec(&cm_core->events_posted);
......
...@@ -83,6 +83,8 @@ enum nes_timer_type { ...@@ -83,6 +83,8 @@ enum nes_timer_type {
#define SET_FIN 4 #define SET_FIN 4
#define SET_RST 8 #define SET_RST 8
#define TCP_OPTIONS_PADDING 3
struct option_base { struct option_base {
u8 optionnum; u8 optionnum;
u8 length; u8 length;
...@@ -177,6 +179,7 @@ enum nes_cm_node_state { ...@@ -177,6 +179,7 @@ enum nes_cm_node_state {
NES_CM_STATE_ESTABLISHED, NES_CM_STATE_ESTABLISHED,
NES_CM_STATE_ACCEPTING, NES_CM_STATE_ACCEPTING,
NES_CM_STATE_MPAREQ_SENT, NES_CM_STATE_MPAREQ_SENT,
NES_CM_STATE_MPAREQ_RCVD,
NES_CM_STATE_TSA, NES_CM_STATE_TSA,
NES_CM_STATE_FIN_WAIT1, NES_CM_STATE_FIN_WAIT1,
NES_CM_STATE_FIN_WAIT2, NES_CM_STATE_FIN_WAIT2,
...@@ -187,6 +190,16 @@ enum nes_cm_node_state { ...@@ -187,6 +190,16 @@ enum nes_cm_node_state {
NES_CM_STATE_CLOSED NES_CM_STATE_CLOSED
}; };
enum nes_tcpip_pkt_type {
NES_PKT_TYPE_UNKNOWN,
NES_PKT_TYPE_SYN,
NES_PKT_TYPE_SYNACK,
NES_PKT_TYPE_ACK,
NES_PKT_TYPE_FIN,
NES_PKT_TYPE_RST
};
/* type of nes connection */ /* type of nes connection */
enum nes_cm_conn_type { enum nes_cm_conn_type {
NES_CM_IWARP_CONN_TYPE, NES_CM_IWARP_CONN_TYPE,
...@@ -257,7 +270,9 @@ struct nes_cm_node { ...@@ -257,7 +270,9 @@ struct nes_cm_node {
struct net_device *netdev; struct net_device *netdev;
struct nes_cm_node *loopbackpartner; struct nes_cm_node *loopbackpartner;
struct list_head retrans_list;
struct nes_timer_entry *send_entry;
spinlock_t retrans_list_lock; spinlock_t retrans_list_lock;
struct list_head recv_list; struct list_head recv_list;
spinlock_t recv_list_lock; spinlock_t recv_list_lock;
...@@ -276,6 +291,8 @@ struct nes_cm_node { ...@@ -276,6 +291,8 @@ struct nes_cm_node {
struct nes_vnic *nesvnic; struct nes_vnic *nesvnic;
int apbvt_set; int apbvt_set;
int accept_pend; int accept_pend;
int freed;
struct nes_qp *nesqp;
}; };
/* structure for client or CM to fill when making CM api calls. */ /* structure for client or CM to fill when making CM api calls. */
...@@ -366,14 +383,14 @@ struct nes_cm_ops { ...@@ -366,14 +383,14 @@ struct nes_cm_ops {
struct nes_cm_info *); struct nes_cm_info *);
int (*stop_listener)(struct nes_cm_core *, struct nes_cm_listener *); int (*stop_listener)(struct nes_cm_core *, struct nes_cm_listener *);
struct nes_cm_node * (*connect)(struct nes_cm_core *, struct nes_cm_node * (*connect)(struct nes_cm_core *,
struct nes_vnic *, struct ietf_mpa_frame *, struct nes_vnic *, u16, void *,
struct nes_cm_info *); struct nes_cm_info *);
int (*close)(struct nes_cm_core *, struct nes_cm_node *); int (*close)(struct nes_cm_core *, struct nes_cm_node *);
int (*accept)(struct nes_cm_core *, struct ietf_mpa_frame *, int (*accept)(struct nes_cm_core *, struct ietf_mpa_frame *,
struct nes_cm_node *); struct nes_cm_node *);
int (*reject)(struct nes_cm_core *, struct ietf_mpa_frame *, int (*reject)(struct nes_cm_core *, struct ietf_mpa_frame *,
struct nes_cm_node *); struct nes_cm_node *);
int (*recv_pkt)(struct nes_cm_core *, struct nes_vnic *, void (*recv_pkt)(struct nes_cm_core *, struct nes_vnic *,
struct sk_buff *); struct sk_buff *);
int (*destroy_cm_core)(struct nes_cm_core *); int (*destroy_cm_core)(struct nes_cm_core *);
int (*get)(struct nes_cm_core *); int (*get)(struct nes_cm_core *);
......
...@@ -2814,7 +2814,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, ...@@ -2814,7 +2814,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
nesqp = *((struct nes_qp **)&context); nesqp = *((struct nes_qp **)&context);
if (atomic_inc_return(&nesqp->close_timer_started) == 1) { if (atomic_inc_return(&nesqp->close_timer_started) == 1) {
nesqp->cm_id->add_ref(nesqp->cm_id); nesqp->cm_id->add_ref(nesqp->cm_id);
nes_add_ref(&nesqp->ibqp);
schedule_nes_timer(nesqp->cm_node, (struct sk_buff *)nesqp, schedule_nes_timer(nesqp->cm_node, (struct sk_buff *)nesqp,
NES_TIMER_TYPE_CLOSE, 1, 0); NES_TIMER_TYPE_CLOSE, 1, 0);
nes_debug(NES_DBG_AEQ, "QP%u Not decrementing QP refcount (%d)," nes_debug(NES_DBG_AEQ, "QP%u Not decrementing QP refcount (%d),"
...@@ -2838,7 +2837,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, ...@@ -2838,7 +2837,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
if (async_event_id == NES_AEQE_AEID_RESET_SENT) { if (async_event_id == NES_AEQE_AEID_RESET_SENT) {
tcp_state = NES_AEQE_TCP_STATE_CLOSED; tcp_state = NES_AEQE_TCP_STATE_CLOSED;
} }
nes_add_ref(&nesqp->ibqp);
spin_lock_irqsave(&nesqp->lock, flags); spin_lock_irqsave(&nesqp->lock, flags);
nesqp->hw_iwarp_state = iwarp_state; nesqp->hw_iwarp_state = iwarp_state;
nesqp->hw_tcp_state = tcp_state; nesqp->hw_tcp_state = tcp_state;
...@@ -2876,7 +2874,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, ...@@ -2876,7 +2874,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
} }
spin_unlock_irqrestore(&nesqp->lock, flags); spin_unlock_irqrestore(&nesqp->lock, flags);
if (next_iwarp_state) { if (next_iwarp_state) {
nes_add_ref(&nesqp->ibqp);
nes_debug(NES_DBG_AEQ, "issuing hw modifyqp for QP%u. next state = 0x%08X," nes_debug(NES_DBG_AEQ, "issuing hw modifyqp for QP%u. next state = 0x%08X,"
" also added another reference\n", " also added another reference\n",
nesqp->hwqp.qp_id, next_iwarp_state); nesqp->hwqp.qp_id, next_iwarp_state);
...@@ -2888,7 +2885,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, ...@@ -2888,7 +2885,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
/* FIN Received but ib state not RTS, /* FIN Received but ib state not RTS,
close complete will be on its way */ close complete will be on its way */
spin_unlock_irqrestore(&nesqp->lock, flags); spin_unlock_irqrestore(&nesqp->lock, flags);
nes_rem_ref(&nesqp->ibqp);
return; return;
} }
spin_unlock_irqrestore(&nesqp->lock, flags); spin_unlock_irqrestore(&nesqp->lock, flags);
...@@ -2922,7 +2918,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, ...@@ -2922,7 +2918,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
if ((tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) || if ((tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) ||
((nesqp->ibqp_state == IB_QPS_RTS)&& ((nesqp->ibqp_state == IB_QPS_RTS)&&
(async_event_id == NES_AEQE_AEID_LLP_CONNECTION_RESET))) { (async_event_id == NES_AEQE_AEID_LLP_CONNECTION_RESET))) {
nes_add_ref(&nesqp->ibqp);
nes_cm_disconn(nesqp); nes_cm_disconn(nesqp);
} else { } else {
nesqp->in_disconnect = 0; nesqp->in_disconnect = 0;
...@@ -2931,7 +2926,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, ...@@ -2931,7 +2926,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
break; break;
case NES_AEQE_AEID_LLP_TOO_MANY_RETRIES: case NES_AEQE_AEID_LLP_TOO_MANY_RETRIES:
nesqp = *((struct nes_qp **)&context); nesqp = *((struct nes_qp **)&context);
nes_add_ref(&nesqp->ibqp);
spin_lock_irqsave(&nesqp->lock, flags); spin_lock_irqsave(&nesqp->lock, flags);
nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_ERROR; nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_ERROR;
nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED; nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
...@@ -3042,7 +3036,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, ...@@ -3042,7 +3036,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
} }
/* tell cm to disconnect, cm will queue work to thread */ /* tell cm to disconnect, cm will queue work to thread */
nes_add_ref(&nesqp->ibqp);
nes_cm_disconn(nesqp); nes_cm_disconn(nesqp);
break; break;
case NES_AEQE_AEID_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE: case NES_AEQE_AEID_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE:
...@@ -3062,7 +3055,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, ...@@ -3062,7 +3055,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
} }
/* tell cm to disconnect, cm will queue work to thread */ /* tell cm to disconnect, cm will queue work to thread */
nes_add_ref(&nesqp->ibqp);
nes_cm_disconn(nesqp); nes_cm_disconn(nesqp);
break; break;
case NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR: case NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR:
...@@ -3082,7 +3074,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, ...@@ -3082,7 +3074,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context); nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
} }
/* tell cm to disconnect, cm will queue work to thread */ /* tell cm to disconnect, cm will queue work to thread */
nes_add_ref(&nesqp->ibqp);
nes_cm_disconn(nesqp); nes_cm_disconn(nesqp);
break; break;
/* TODO: additional AEs need to be here */ /* TODO: additional AEs need to be here */
......
...@@ -2867,7 +2867,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, ...@@ -2867,7 +2867,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
nesqp->hwqp.qp_id, attr->qp_state, nesqp->ibqp_state, nesqp->hwqp.qp_id, attr->qp_state, nesqp->ibqp_state,
nesqp->iwarp_state, atomic_read(&nesqp->refcount)); nesqp->iwarp_state, atomic_read(&nesqp->refcount));
nes_add_ref(&nesqp->ibqp);
spin_lock_irqsave(&nesqp->lock, qplockflags); spin_lock_irqsave(&nesqp->lock, qplockflags);
nes_debug(NES_DBG_MOD_QP, "QP%u: hw_iwarp_state=0x%X, hw_tcp_state=0x%X," nes_debug(NES_DBG_MOD_QP, "QP%u: hw_iwarp_state=0x%X, hw_tcp_state=0x%X,"
...@@ -2882,7 +2881,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, ...@@ -2882,7 +2881,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
nesqp->hwqp.qp_id); nesqp->hwqp.qp_id);
if (nesqp->iwarp_state > (u32)NES_CQP_QP_IWARP_STATE_IDLE) { if (nesqp->iwarp_state > (u32)NES_CQP_QP_IWARP_STATE_IDLE) {
spin_unlock_irqrestore(&nesqp->lock, qplockflags); spin_unlock_irqrestore(&nesqp->lock, qplockflags);
nes_rem_ref(&nesqp->ibqp);
return -EINVAL; return -EINVAL;
} }
next_iwarp_state = NES_CQP_QP_IWARP_STATE_IDLE; next_iwarp_state = NES_CQP_QP_IWARP_STATE_IDLE;
...@@ -2893,7 +2891,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, ...@@ -2893,7 +2891,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
nesqp->hwqp.qp_id); nesqp->hwqp.qp_id);
if (nesqp->iwarp_state>(u32)NES_CQP_QP_IWARP_STATE_IDLE) { if (nesqp->iwarp_state>(u32)NES_CQP_QP_IWARP_STATE_IDLE) {
spin_unlock_irqrestore(&nesqp->lock, qplockflags); spin_unlock_irqrestore(&nesqp->lock, qplockflags);
nes_rem_ref(&nesqp->ibqp);
return -EINVAL; return -EINVAL;
} }
next_iwarp_state = NES_CQP_QP_IWARP_STATE_IDLE; next_iwarp_state = NES_CQP_QP_IWARP_STATE_IDLE;
...@@ -2904,14 +2901,12 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, ...@@ -2904,14 +2901,12 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
nesqp->hwqp.qp_id); nesqp->hwqp.qp_id);
if (nesqp->iwarp_state>(u32)NES_CQP_QP_IWARP_STATE_RTS) { if (nesqp->iwarp_state>(u32)NES_CQP_QP_IWARP_STATE_RTS) {
spin_unlock_irqrestore(&nesqp->lock, qplockflags); spin_unlock_irqrestore(&nesqp->lock, qplockflags);
nes_rem_ref(&nesqp->ibqp);
return -EINVAL; return -EINVAL;
} }
if (nesqp->cm_id == NULL) { if (nesqp->cm_id == NULL) {
nes_debug(NES_DBG_MOD_QP, "QP%u: Failing attempt to move QP to RTS without a CM_ID. \n", nes_debug(NES_DBG_MOD_QP, "QP%u: Failing attempt to move QP to RTS without a CM_ID. \n",
nesqp->hwqp.qp_id ); nesqp->hwqp.qp_id );
spin_unlock_irqrestore(&nesqp->lock, qplockflags); spin_unlock_irqrestore(&nesqp->lock, qplockflags);
nes_rem_ref(&nesqp->ibqp);
return -EINVAL; return -EINVAL;
} }
next_iwarp_state = NES_CQP_QP_IWARP_STATE_RTS; next_iwarp_state = NES_CQP_QP_IWARP_STATE_RTS;
...@@ -2929,7 +2924,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, ...@@ -2929,7 +2924,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
nesqp->hwqp.qp_id, nesqp->hwqp.sq_head, nesqp->hwqp.sq_tail); nesqp->hwqp.qp_id, nesqp->hwqp.sq_head, nesqp->hwqp.sq_tail);
if (nesqp->iwarp_state == (u32)NES_CQP_QP_IWARP_STATE_CLOSING) { if (nesqp->iwarp_state == (u32)NES_CQP_QP_IWARP_STATE_CLOSING) {
spin_unlock_irqrestore(&nesqp->lock, qplockflags); spin_unlock_irqrestore(&nesqp->lock, qplockflags);
nes_rem_ref(&nesqp->ibqp);
return 0; return 0;
} else { } else {
if (nesqp->iwarp_state > (u32)NES_CQP_QP_IWARP_STATE_CLOSING) { if (nesqp->iwarp_state > (u32)NES_CQP_QP_IWARP_STATE_CLOSING) {
...@@ -2937,7 +2931,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, ...@@ -2937,7 +2931,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
" ignored due to current iWARP state\n", " ignored due to current iWARP state\n",
nesqp->hwqp.qp_id); nesqp->hwqp.qp_id);
spin_unlock_irqrestore(&nesqp->lock, qplockflags); spin_unlock_irqrestore(&nesqp->lock, qplockflags);
nes_rem_ref(&nesqp->ibqp);
return -EINVAL; return -EINVAL;
} }
if (nesqp->hw_iwarp_state != NES_AEQE_IWARP_STATE_RTS) { if (nesqp->hw_iwarp_state != NES_AEQE_IWARP_STATE_RTS) {
...@@ -2969,7 +2962,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, ...@@ -2969,7 +2962,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
nesqp->hwqp.qp_id); nesqp->hwqp.qp_id);
if (nesqp->iwarp_state>=(u32)NES_CQP_QP_IWARP_STATE_TERMINATE) { if (nesqp->iwarp_state>=(u32)NES_CQP_QP_IWARP_STATE_TERMINATE) {
spin_unlock_irqrestore(&nesqp->lock, qplockflags); spin_unlock_irqrestore(&nesqp->lock, qplockflags);
nes_rem_ref(&nesqp->ibqp);
return -EINVAL; return -EINVAL;
} }
/* next_iwarp_state = (NES_CQP_QP_IWARP_STATE_TERMINATE | 0x02000000); */ /* next_iwarp_state = (NES_CQP_QP_IWARP_STATE_TERMINATE | 0x02000000); */
...@@ -2982,7 +2974,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, ...@@ -2982,7 +2974,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
case IB_QPS_RESET: case IB_QPS_RESET:
if (nesqp->iwarp_state == (u32)NES_CQP_QP_IWARP_STATE_ERROR) { if (nesqp->iwarp_state == (u32)NES_CQP_QP_IWARP_STATE_ERROR) {
spin_unlock_irqrestore(&nesqp->lock, qplockflags); spin_unlock_irqrestore(&nesqp->lock, qplockflags);
nes_rem_ref(&nesqp->ibqp);
return -EINVAL; return -EINVAL;
} }
nes_debug(NES_DBG_MOD_QP, "QP%u: new state = error\n", nes_debug(NES_DBG_MOD_QP, "QP%u: new state = error\n",
...@@ -3008,7 +2999,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, ...@@ -3008,7 +2999,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
break; break;
default: default:
spin_unlock_irqrestore(&nesqp->lock, qplockflags); spin_unlock_irqrestore(&nesqp->lock, qplockflags);
nes_rem_ref(&nesqp->ibqp);
return -EINVAL; return -EINVAL;
break; break;
} }
...@@ -3088,7 +3078,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, ...@@ -3088,7 +3078,6 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount), nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount),
original_last_aeq, nesqp->last_aeq); original_last_aeq, nesqp->last_aeq);
/* this one is for the cm_disconnect thread */ /* this one is for the cm_disconnect thread */
nes_add_ref(&nesqp->ibqp);
spin_lock_irqsave(&nesqp->lock, qplockflags); spin_lock_irqsave(&nesqp->lock, qplockflags);
nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED; nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT; nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT;
...@@ -3097,14 +3086,12 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, ...@@ -3097,14 +3086,12 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
} else { } else {
nes_debug(NES_DBG_MOD_QP, "QP%u No fake disconnect, QP refcount=%d\n", nes_debug(NES_DBG_MOD_QP, "QP%u No fake disconnect, QP refcount=%d\n",
nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount)); nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount));
nes_rem_ref(&nesqp->ibqp);
} }
} else { } else {
spin_lock_irqsave(&nesqp->lock, qplockflags); spin_lock_irqsave(&nesqp->lock, qplockflags);
if (nesqp->cm_id) { if (nesqp->cm_id) {
/* These two are for the timer thread */ /* These two are for the timer thread */
if (atomic_inc_return(&nesqp->close_timer_started) == 1) { if (atomic_inc_return(&nesqp->close_timer_started) == 1) {
nes_add_ref(&nesqp->ibqp);
nesqp->cm_id->add_ref(nesqp->cm_id); nesqp->cm_id->add_ref(nesqp->cm_id);
nes_debug(NES_DBG_MOD_QP, "QP%u Not decrementing QP refcount (%d)," nes_debug(NES_DBG_MOD_QP, "QP%u Not decrementing QP refcount (%d),"
" need ae to finish up, original_last_aeq = 0x%04X." " need ae to finish up, original_last_aeq = 0x%04X."
...@@ -3128,14 +3115,12 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, ...@@ -3128,14 +3115,12 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
" original_last_aeq = 0x%04X. last_aeq = 0x%04X.\n", " original_last_aeq = 0x%04X. last_aeq = 0x%04X.\n",
nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount), nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount),
original_last_aeq, nesqp->last_aeq); original_last_aeq, nesqp->last_aeq);
nes_rem_ref(&nesqp->ibqp);
} }
} else { } else {
nes_debug(NES_DBG_MOD_QP, "QP%u Decrementing QP refcount (%d), No ae to finish up," nes_debug(NES_DBG_MOD_QP, "QP%u Decrementing QP refcount (%d), No ae to finish up,"
" original_last_aeq = 0x%04X. last_aeq = 0x%04X.\n", " original_last_aeq = 0x%04X. last_aeq = 0x%04X.\n",
nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount), nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount),
original_last_aeq, nesqp->last_aeq); original_last_aeq, nesqp->last_aeq);
nes_rem_ref(&nesqp->ibqp);
} }
err = 0; err = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment