Path: blob/master/drivers/infiniband/hw/nes/nes_cm.c
15112 views
/*1* Copyright (c) 2006 - 2009 Intel Corporation. All rights reserved.2*3* This software is available to you under a choice of one of two4* licenses. You may choose to be licensed under the terms of the GNU5* General Public License (GPL) Version 2, available from the file6* COPYING in the main directory of this source tree, or the7* OpenIB.org BSD license below:8*9* Redistribution and use in source and binary forms, with or10* without modification, are permitted provided that the following11* conditions are met:12*13* - Redistributions of source code must retain the above14* copyright notice, this list of conditions and the following15* disclaimer.16*17* - Redistributions in binary form must reproduce the above18* copyright notice, this list of conditions and the following19* disclaimer in the documentation and/or other materials20* provided with the distribution.21*22* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,23* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF24* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND25* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS26* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN27* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN28* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE29* SOFTWARE.30*31*/323334#define TCPOPT_TIMESTAMP 83536#include <asm/atomic.h>37#include <linux/skbuff.h>38#include <linux/ip.h>39#include <linux/tcp.h>40#include <linux/init.h>41#include <linux/if_arp.h>42#include <linux/if_vlan.h>43#include <linux/notifier.h>44#include <linux/net.h>45#include <linux/types.h>46#include <linux/timer.h>47#include <linux/time.h>48#include <linux/delay.h>49#include <linux/etherdevice.h>50#include <linux/netdevice.h>51#include <linux/random.h>52#include <linux/list.h>53#include <linux/threads.h>54#include <linux/highmem.h>55#include <linux/slab.h>56#include <net/arp.h>57#include <net/neighbour.h>58#include <net/route.h>59#include <net/ip_fib.h>60#include <net/tcp.h>6162#include "nes.h"6364u32 cm_packets_sent;65u32 cm_packets_bounced;66u32 cm_packets_dropped;67u32 cm_packets_retrans;68u32 cm_packets_created;69u32 cm_packets_received;70atomic_t cm_listens_created;71atomic_t cm_listens_destroyed;72u32 cm_backlog_drops;73atomic_t cm_loopbacks;74atomic_t cm_nodes_created;75atomic_t cm_nodes_destroyed;76atomic_t cm_accel_dropped_pkts;77atomic_t cm_resets_recvd;7879static inline int mini_cm_accelerated(struct nes_cm_core *,80struct nes_cm_node *);81static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *,82struct nes_vnic *, struct nes_cm_info *);83static int mini_cm_del_listen(struct nes_cm_core *, struct nes_cm_listener *);84static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *,85struct nes_vnic *, u16, void *, struct nes_cm_info *);86static int mini_cm_close(struct nes_cm_core *, struct nes_cm_node *);87static int mini_cm_accept(struct nes_cm_core *, struct ietf_mpa_frame *,88struct nes_cm_node *);89static int mini_cm_reject(struct nes_cm_core *, struct ietf_mpa_frame *,90struct nes_cm_node *);91static int mini_cm_recv_pkt(struct nes_cm_core *, struct nes_vnic *,92struct sk_buff *);93static int mini_cm_dealloc_core(struct nes_cm_core *);94static int mini_cm_get(struct nes_cm_core *);95static int mini_cm_set(struct nes_cm_core *, u32, u32);9697static void form_cm_frame(struct sk_buff *, struct nes_cm_node *,98void *, u32, void *, u32, u8);99static int add_ref_cm_node(struct nes_cm_node *);100static int rem_ref_cm_node(struct nes_cm_core *, struct nes_cm_node *);101102static int nes_cm_disconn_true(struct nes_qp *);103static int nes_cm_post_event(struct nes_cm_event *event);104static int nes_disconnect(struct nes_qp *nesqp, int abrupt);105static void nes_disconnect_worker(struct work_struct *work);106107static int send_mpa_request(struct nes_cm_node *, struct sk_buff *);108static int send_mpa_reject(struct nes_cm_node *);109static int send_syn(struct nes_cm_node *, u32, struct sk_buff *);110static int send_reset(struct nes_cm_node *, struct sk_buff *);111static int send_ack(struct nes_cm_node *cm_node, struct sk_buff *skb);112static int send_fin(struct nes_cm_node *cm_node, struct sk_buff *skb);113static void process_packet(struct nes_cm_node *, struct sk_buff *,114struct nes_cm_core *);115116static void active_open_err(struct nes_cm_node *, struct sk_buff *, int);117static void passive_open_err(struct nes_cm_node *, struct sk_buff *, int);118static void cleanup_retrans_entry(struct nes_cm_node *);119static void handle_rcv_mpa(struct nes_cm_node *, struct sk_buff *);120static void free_retrans_entry(struct nes_cm_node *cm_node);121static int handle_tcp_options(struct nes_cm_node *cm_node, struct tcphdr *tcph,122struct sk_buff *skb, int optionsize, int passive);123124/* CM event handler functions */125static void cm_event_connected(struct nes_cm_event *);126static void cm_event_connect_error(struct nes_cm_event *);127static void cm_event_reset(struct nes_cm_event *);128static void cm_event_mpa_req(struct nes_cm_event *);129static void cm_event_mpa_reject(struct nes_cm_event *);130static void handle_recv_entry(struct nes_cm_node *cm_node, u32 rem_node);131132static void print_core(struct nes_cm_core *core);133134/* External CM API Interface */135/* instance of function pointers for client API */136/* set address of this instance to cm_core->cm_ops at cm_core alloc */137static struct nes_cm_ops nes_cm_api = {138mini_cm_accelerated,139mini_cm_listen,140mini_cm_del_listen,141mini_cm_connect,142mini_cm_close,143mini_cm_accept,144mini_cm_reject,145mini_cm_recv_pkt,146mini_cm_dealloc_core,147mini_cm_get,148mini_cm_set149};150151static struct nes_cm_core *g_cm_core;152153atomic_t cm_connects;154atomic_t cm_accepts;155atomic_t cm_disconnects;156atomic_t cm_closes;157atomic_t cm_connecteds;158atomic_t cm_connect_reqs;159atomic_t cm_rejects;160161162/**163* create_event164*/165static struct nes_cm_event *create_event(struct nes_cm_node *cm_node,166enum nes_cm_event_type type)167{168struct nes_cm_event *event;169170if (!cm_node->cm_id)171return NULL;172173/* allocate an empty event */174event = kzalloc(sizeof(*event), GFP_ATOMIC);175176if (!event)177return NULL;178179event->type = type;180event->cm_node = cm_node;181event->cm_info.rem_addr = cm_node->rem_addr;182event->cm_info.loc_addr = cm_node->loc_addr;183event->cm_info.rem_port = cm_node->rem_port;184event->cm_info.loc_port = cm_node->loc_port;185event->cm_info.cm_id = cm_node->cm_id;186187nes_debug(NES_DBG_CM, "cm_node=%p Created event=%p, type=%u, "188"dst_addr=%08x[%x], src_addr=%08x[%x]\n",189cm_node, event, type, event->cm_info.loc_addr,190event->cm_info.loc_port, event->cm_info.rem_addr,191event->cm_info.rem_port);192193nes_cm_post_event(event);194return event;195}196197198/**199* send_mpa_request200*/201static int send_mpa_request(struct nes_cm_node *cm_node, struct sk_buff *skb)202{203if (!skb) {204nes_debug(NES_DBG_CM, "skb set to NULL\n");205return -1;206}207208/* send an MPA Request frame */209form_cm_frame(skb, cm_node, NULL, 0, &cm_node->mpa_frame,210cm_node->mpa_frame_size, SET_ACK);211212return schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0);213}214215216217static int send_mpa_reject(struct nes_cm_node *cm_node)218{219struct sk_buff *skb = NULL;220221skb = dev_alloc_skb(MAX_CM_BUFFER);222if (!skb) {223nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");224return -ENOMEM;225}226227/* send an MPA reject frame */228form_cm_frame(skb, cm_node, NULL, 0, &cm_node->mpa_frame,229cm_node->mpa_frame_size, SET_ACK | SET_FIN);230231cm_node->state = NES_CM_STATE_FIN_WAIT1;232return schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0);233}234235236/**237* recv_mpa - process a received TCP pkt, we are expecting an238* IETF MPA frame239*/240static int parse_mpa(struct nes_cm_node *cm_node, u8 *buffer, u32 *type,241u32 len)242{243struct ietf_mpa_frame *mpa_frame;244245*type = NES_MPA_REQUEST_ACCEPT;246247/* assume req frame is in tcp data payload */248if (len < sizeof(struct ietf_mpa_frame)) {249nes_debug(NES_DBG_CM, "The received ietf buffer was too small (%x)\n", len);250return -EINVAL;251}252253mpa_frame = (struct ietf_mpa_frame *)buffer;254cm_node->mpa_frame_size = ntohs(mpa_frame->priv_data_len);255/* make sure mpa private data len is less than 512 bytes */256if (cm_node->mpa_frame_size > IETF_MAX_PRIV_DATA_LEN) {257nes_debug(NES_DBG_CM, "The received Length of Private"258" Data field exceeds 512 octets\n");259return -EINVAL;260}261/*262* make sure MPA receiver interoperate with the263* received MPA version and MPA key information264*265*/266if (mpa_frame->rev != mpa_version) {267nes_debug(NES_DBG_CM, "The received mpa version"268" can not be interoperated\n");269return -EINVAL;270}271if (cm_node->state != NES_CM_STATE_MPAREQ_SENT) {272if (memcmp(mpa_frame->key, IEFT_MPA_KEY_REQ, IETF_MPA_KEY_SIZE)) {273nes_debug(NES_DBG_CM, "Unexpected MPA Key received \n");274return -EINVAL;275}276} else {277if (memcmp(mpa_frame->key, IEFT_MPA_KEY_REP, IETF_MPA_KEY_SIZE)) {278nes_debug(NES_DBG_CM, "Unexpected MPA Key received \n");279return -EINVAL;280}281}282283if (cm_node->mpa_frame_size + sizeof(struct ietf_mpa_frame) != len) {284nes_debug(NES_DBG_CM, "The received ietf buffer was not right"285" complete (%x + %x != %x)\n",286cm_node->mpa_frame_size,287(u32)sizeof(struct ietf_mpa_frame), len);288return -EINVAL;289}290/* make sure it does not exceed the max size */291if (len > MAX_CM_BUFFER) {292nes_debug(NES_DBG_CM, "The received ietf buffer was too large"293" (%x + %x != %x)\n",294cm_node->mpa_frame_size,295(u32)sizeof(struct ietf_mpa_frame), len);296return -EINVAL;297}298299/* copy entire MPA frame to our cm_node's frame */300memcpy(cm_node->mpa_frame_buf, buffer + sizeof(struct ietf_mpa_frame),301cm_node->mpa_frame_size);302303if (mpa_frame->flags & IETF_MPA_FLAGS_REJECT)304*type = NES_MPA_REQUEST_REJECT;305return 0;306}307308309/**310* form_cm_frame - get a free packet and build empty frame Use311* node info to build.312*/313static void form_cm_frame(struct sk_buff *skb,314struct nes_cm_node *cm_node, void *options, u32 optionsize,315void *data, u32 datasize, u8 flags)316{317struct tcphdr *tcph;318struct iphdr *iph;319struct ethhdr *ethh;320u8 *buf;321u16 packetsize = sizeof(*iph);322323packetsize += sizeof(*tcph);324packetsize += optionsize + datasize;325326memset(skb->data, 0x00, ETH_HLEN + sizeof(*iph) + sizeof(*tcph));327328skb->len = 0;329buf = skb_put(skb, packetsize + ETH_HLEN);330331ethh = (struct ethhdr *) buf;332buf += ETH_HLEN;333334iph = (struct iphdr *)buf;335buf += sizeof(*iph);336tcph = (struct tcphdr *)buf;337skb_reset_mac_header(skb);338skb_set_network_header(skb, ETH_HLEN);339skb_set_transport_header(skb, ETH_HLEN+sizeof(*iph));340buf += sizeof(*tcph);341342skb->ip_summed = CHECKSUM_PARTIAL;343skb->protocol = htons(0x800);344skb->data_len = 0;345skb->mac_len = ETH_HLEN;346347memcpy(ethh->h_dest, cm_node->rem_mac, ETH_ALEN);348memcpy(ethh->h_source, cm_node->loc_mac, ETH_ALEN);349ethh->h_proto = htons(0x0800);350351iph->version = IPVERSION;352iph->ihl = 5; /* 5 * 4Byte words, IP headr len */353iph->tos = 0;354iph->tot_len = htons(packetsize);355iph->id = htons(++cm_node->tcp_cntxt.loc_id);356357iph->frag_off = htons(0x4000);358iph->ttl = 0x40;359iph->protocol = 0x06; /* IPPROTO_TCP */360361iph->saddr = htonl(cm_node->loc_addr);362iph->daddr = htonl(cm_node->rem_addr);363364tcph->source = htons(cm_node->loc_port);365tcph->dest = htons(cm_node->rem_port);366tcph->seq = htonl(cm_node->tcp_cntxt.loc_seq_num);367368if (flags & SET_ACK) {369cm_node->tcp_cntxt.loc_ack_num = cm_node->tcp_cntxt.rcv_nxt;370tcph->ack_seq = htonl(cm_node->tcp_cntxt.loc_ack_num);371tcph->ack = 1;372} else373tcph->ack_seq = 0;374375if (flags & SET_SYN) {376cm_node->tcp_cntxt.loc_seq_num++;377tcph->syn = 1;378} else379cm_node->tcp_cntxt.loc_seq_num += datasize;380381if (flags & SET_FIN) {382cm_node->tcp_cntxt.loc_seq_num++;383tcph->fin = 1;384}385386if (flags & SET_RST)387tcph->rst = 1;388389tcph->doff = (u16)((sizeof(*tcph) + optionsize + 3) >> 2);390tcph->window = htons(cm_node->tcp_cntxt.rcv_wnd);391tcph->urg_ptr = 0;392if (optionsize)393memcpy(buf, options, optionsize);394buf += optionsize;395if (datasize)396memcpy(buf, data, datasize);397398skb_shinfo(skb)->nr_frags = 0;399cm_packets_created++;400401}402403404/**405* print_core - dump a cm core406*/407static void print_core(struct nes_cm_core *core)408{409nes_debug(NES_DBG_CM, "---------------------------------------------\n");410nes_debug(NES_DBG_CM, "CM Core -- (core = %p )\n", core);411if (!core)412return;413nes_debug(NES_DBG_CM, "---------------------------------------------\n");414415nes_debug(NES_DBG_CM, "State : %u \n", core->state);416417nes_debug(NES_DBG_CM, "Listen Nodes : %u \n", atomic_read(&core->listen_node_cnt));418nes_debug(NES_DBG_CM, "Active Nodes : %u \n", atomic_read(&core->node_cnt));419420nes_debug(NES_DBG_CM, "core : %p \n", core);421422nes_debug(NES_DBG_CM, "-------------- end core ---------------\n");423}424425426/**427* schedule_nes_timer428* note - cm_node needs to be protected before calling this. Encase in:429* rem_ref_cm_node(cm_core, cm_node);add_ref_cm_node(cm_node);430*/431int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb,432enum nes_timer_type type, int send_retrans,433int close_when_complete)434{435unsigned long flags;436struct nes_cm_core *cm_core = cm_node->cm_core;437struct nes_timer_entry *new_send;438int ret = 0;439u32 was_timer_set;440441new_send = kzalloc(sizeof(*new_send), GFP_ATOMIC);442if (!new_send)443return -ENOMEM;444445/* new_send->timetosend = currenttime */446new_send->retrycount = NES_DEFAULT_RETRYS;447new_send->retranscount = NES_DEFAULT_RETRANS;448new_send->skb = skb;449new_send->timetosend = jiffies;450new_send->type = type;451new_send->netdev = cm_node->netdev;452new_send->send_retrans = send_retrans;453new_send->close_when_complete = close_when_complete;454455if (type == NES_TIMER_TYPE_CLOSE) {456new_send->timetosend += (HZ/10);457if (cm_node->recv_entry) {458kfree(new_send);459WARN_ON(1);460return -EINVAL;461}462cm_node->recv_entry = new_send;463}464465if (type == NES_TIMER_TYPE_SEND) {466new_send->seq_num = ntohl(tcp_hdr(skb)->seq);467atomic_inc(&new_send->skb->users);468spin_lock_irqsave(&cm_node->retrans_list_lock, flags);469cm_node->send_entry = new_send;470add_ref_cm_node(cm_node);471spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);472new_send->timetosend = jiffies + NES_RETRY_TIMEOUT;473474ret = nes_nic_cm_xmit(new_send->skb, cm_node->netdev);475if (ret != NETDEV_TX_OK) {476nes_debug(NES_DBG_CM, "Error sending packet %p "477"(jiffies = %lu)\n", new_send, jiffies);478new_send->timetosend = jiffies;479ret = NETDEV_TX_OK;480} else {481cm_packets_sent++;482if (!send_retrans) {483cleanup_retrans_entry(cm_node);484if (close_when_complete)485rem_ref_cm_node(cm_core, cm_node);486return ret;487}488}489}490491was_timer_set = timer_pending(&cm_core->tcp_timer);492493if (!was_timer_set) {494cm_core->tcp_timer.expires = new_send->timetosend;495add_timer(&cm_core->tcp_timer);496}497498return ret;499}500501static void nes_retrans_expired(struct nes_cm_node *cm_node)502{503struct iw_cm_id *cm_id = cm_node->cm_id;504enum nes_cm_node_state state = cm_node->state;505cm_node->state = NES_CM_STATE_CLOSED;506switch (state) {507case NES_CM_STATE_SYN_RCVD:508case NES_CM_STATE_CLOSING:509rem_ref_cm_node(cm_node->cm_core, cm_node);510break;511case NES_CM_STATE_LAST_ACK:512case NES_CM_STATE_FIN_WAIT1:513if (cm_node->cm_id)514cm_id->rem_ref(cm_id);515send_reset(cm_node, NULL);516break;517default:518add_ref_cm_node(cm_node);519send_reset(cm_node, NULL);520create_event(cm_node, NES_CM_EVENT_ABORTED);521}522}523524static void handle_recv_entry(struct nes_cm_node *cm_node, u32 rem_node)525{526struct nes_timer_entry *recv_entry = cm_node->recv_entry;527struct iw_cm_id *cm_id = cm_node->cm_id;528struct nes_qp *nesqp;529unsigned long qplockflags;530531if (!recv_entry)532return;533nesqp = (struct nes_qp *)recv_entry->skb;534if (nesqp) {535spin_lock_irqsave(&nesqp->lock, qplockflags);536if (nesqp->cm_id) {537nes_debug(NES_DBG_CM, "QP%u: cm_id = %p, "538"refcount = %d: HIT A "539"NES_TIMER_TYPE_CLOSE with something "540"to do!!!\n", nesqp->hwqp.qp_id, cm_id,541atomic_read(&nesqp->refcount));542nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;543nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT;544nesqp->ibqp_state = IB_QPS_ERR;545spin_unlock_irqrestore(&nesqp->lock, qplockflags);546nes_cm_disconn(nesqp);547} else {548spin_unlock_irqrestore(&nesqp->lock, qplockflags);549nes_debug(NES_DBG_CM, "QP%u: cm_id = %p, "550"refcount = %d: HIT A "551"NES_TIMER_TYPE_CLOSE with nothing "552"to do!!!\n", nesqp->hwqp.qp_id, cm_id,553atomic_read(&nesqp->refcount));554}555} else if (rem_node) {556/* TIME_WAIT state */557rem_ref_cm_node(cm_node->cm_core, cm_node);558}559if (cm_node->cm_id)560cm_id->rem_ref(cm_id);561kfree(recv_entry);562cm_node->recv_entry = NULL;563}564565/**566* nes_cm_timer_tick567*/568static void nes_cm_timer_tick(unsigned long pass)569{570unsigned long flags;571unsigned long nexttimeout = jiffies + NES_LONG_TIME;572struct nes_cm_node *cm_node;573struct nes_timer_entry *send_entry, *recv_entry;574struct list_head *list_core_temp;575struct list_head *list_node;576struct nes_cm_core *cm_core = g_cm_core;577u32 settimer = 0;578unsigned long timetosend;579int ret = NETDEV_TX_OK;580581struct list_head timer_list;582INIT_LIST_HEAD(&timer_list);583spin_lock_irqsave(&cm_core->ht_lock, flags);584585list_for_each_safe(list_node, list_core_temp,586&cm_core->connected_nodes) {587cm_node = container_of(list_node, struct nes_cm_node, list);588if ((cm_node->recv_entry) || (cm_node->send_entry)) {589add_ref_cm_node(cm_node);590list_add(&cm_node->timer_entry, &timer_list);591}592}593spin_unlock_irqrestore(&cm_core->ht_lock, flags);594595list_for_each_safe(list_node, list_core_temp, &timer_list) {596cm_node = container_of(list_node, struct nes_cm_node,597timer_entry);598recv_entry = cm_node->recv_entry;599600if (recv_entry) {601if (time_after(recv_entry->timetosend, jiffies)) {602if (nexttimeout > recv_entry->timetosend ||603!settimer) {604nexttimeout = recv_entry->timetosend;605settimer = 1;606}607} else608handle_recv_entry(cm_node, 1);609}610611spin_lock_irqsave(&cm_node->retrans_list_lock, flags);612do {613send_entry = cm_node->send_entry;614if (!send_entry)615break;616if (time_after(send_entry->timetosend, jiffies)) {617if (cm_node->state != NES_CM_STATE_TSA) {618if ((nexttimeout >619send_entry->timetosend) ||620!settimer) {621nexttimeout =622send_entry->timetosend;623settimer = 1;624}625} else {626free_retrans_entry(cm_node);627}628break;629}630631if ((cm_node->state == NES_CM_STATE_TSA) ||632(cm_node->state == NES_CM_STATE_CLOSED)) {633free_retrans_entry(cm_node);634break;635}636637if (!send_entry->retranscount ||638!send_entry->retrycount) {639cm_packets_dropped++;640free_retrans_entry(cm_node);641642spin_unlock_irqrestore(643&cm_node->retrans_list_lock, flags);644nes_retrans_expired(cm_node);645cm_node->state = NES_CM_STATE_CLOSED;646spin_lock_irqsave(&cm_node->retrans_list_lock,647flags);648break;649}650atomic_inc(&send_entry->skb->users);651cm_packets_retrans++;652nes_debug(NES_DBG_CM, "Retransmitting send_entry %p "653"for node %p, jiffies = %lu, time to send = "654"%lu, retranscount = %u, send_entry->seq_num = "655"0x%08X, cm_node->tcp_cntxt.rem_ack_num = "656"0x%08X\n", send_entry, cm_node, jiffies,657send_entry->timetosend,658send_entry->retranscount,659send_entry->seq_num,660cm_node->tcp_cntxt.rem_ack_num);661662spin_unlock_irqrestore(&cm_node->retrans_list_lock,663flags);664ret = nes_nic_cm_xmit(send_entry->skb, cm_node->netdev);665spin_lock_irqsave(&cm_node->retrans_list_lock, flags);666if (ret != NETDEV_TX_OK) {667nes_debug(NES_DBG_CM, "rexmit failed for "668"node=%p\n", cm_node);669cm_packets_bounced++;670send_entry->retrycount--;671nexttimeout = jiffies + NES_SHORT_TIME;672settimer = 1;673break;674} else {675cm_packets_sent++;676}677nes_debug(NES_DBG_CM, "Packet Sent: retrans count = "678"%u, retry count = %u.\n",679send_entry->retranscount,680send_entry->retrycount);681if (send_entry->send_retrans) {682send_entry->retranscount--;683timetosend = (NES_RETRY_TIMEOUT <<684(NES_DEFAULT_RETRANS - send_entry->retranscount));685686send_entry->timetosend = jiffies +687min(timetosend, NES_MAX_TIMEOUT);688if (nexttimeout > send_entry->timetosend ||689!settimer) {690nexttimeout = send_entry->timetosend;691settimer = 1;692}693} else {694int close_when_complete;695close_when_complete =696send_entry->close_when_complete;697nes_debug(NES_DBG_CM, "cm_node=%p state=%d\n",698cm_node, cm_node->state);699free_retrans_entry(cm_node);700if (close_when_complete)701rem_ref_cm_node(cm_node->cm_core,702cm_node);703}704} while (0);705706spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);707rem_ref_cm_node(cm_node->cm_core, cm_node);708}709710if (settimer) {711if (!timer_pending(&cm_core->tcp_timer)) {712cm_core->tcp_timer.expires = nexttimeout;713add_timer(&cm_core->tcp_timer);714}715}716}717718719/**720* send_syn721*/722static int send_syn(struct nes_cm_node *cm_node, u32 sendack,723struct sk_buff *skb)724{725int ret;726int flags = SET_SYN;727char optionsbuffer[sizeof(struct option_mss) +728sizeof(struct option_windowscale) + sizeof(struct option_base) +729TCP_OPTIONS_PADDING];730731int optionssize = 0;732/* Sending MSS option */733union all_known_options *options;734735if (!cm_node)736return -EINVAL;737738options = (union all_known_options *)&optionsbuffer[optionssize];739options->as_mss.optionnum = OPTION_NUMBER_MSS;740options->as_mss.length = sizeof(struct option_mss);741options->as_mss.mss = htons(cm_node->tcp_cntxt.mss);742optionssize += sizeof(struct option_mss);743744options = (union all_known_options *)&optionsbuffer[optionssize];745options->as_windowscale.optionnum = OPTION_NUMBER_WINDOW_SCALE;746options->as_windowscale.length = sizeof(struct option_windowscale);747options->as_windowscale.shiftcount = cm_node->tcp_cntxt.rcv_wscale;748optionssize += sizeof(struct option_windowscale);749750if (sendack && !(NES_DRV_OPT_SUPRESS_OPTION_BC & nes_drv_opt)) {751options = (union all_known_options *)&optionsbuffer[optionssize];752options->as_base.optionnum = OPTION_NUMBER_WRITE0;753options->as_base.length = sizeof(struct option_base);754optionssize += sizeof(struct option_base);755/* we need the size to be a multiple of 4 */756options = (union all_known_options *)&optionsbuffer[optionssize];757options->as_end = 1;758optionssize += 1;759options = (union all_known_options *)&optionsbuffer[optionssize];760options->as_end = 1;761optionssize += 1;762}763764options = (union all_known_options *)&optionsbuffer[optionssize];765options->as_end = OPTION_NUMBER_END;766optionssize += 1;767768if (!skb)769skb = dev_alloc_skb(MAX_CM_BUFFER);770if (!skb) {771nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");772return -1;773}774775if (sendack)776flags |= SET_ACK;777778form_cm_frame(skb, cm_node, optionsbuffer, optionssize, NULL, 0, flags);779ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0);780781return ret;782}783784785/**786* send_reset787*/788static int send_reset(struct nes_cm_node *cm_node, struct sk_buff *skb)789{790int ret;791int flags = SET_RST | SET_ACK;792793if (!skb)794skb = dev_alloc_skb(MAX_CM_BUFFER);795if (!skb) {796nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");797return -ENOMEM;798}799800form_cm_frame(skb, cm_node, NULL, 0, NULL, 0, flags);801ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 0, 1);802803return ret;804}805806807/**808* send_ack809*/810static int send_ack(struct nes_cm_node *cm_node, struct sk_buff *skb)811{812int ret;813814if (!skb)815skb = dev_alloc_skb(MAX_CM_BUFFER);816817if (!skb) {818nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");819return -1;820}821822form_cm_frame(skb, cm_node, NULL, 0, NULL, 0, SET_ACK);823ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 0, 0);824825return ret;826}827828829/**830* send_fin831*/832static int send_fin(struct nes_cm_node *cm_node, struct sk_buff *skb)833{834int ret;835836/* if we didn't get a frame get one */837if (!skb)838skb = dev_alloc_skb(MAX_CM_BUFFER);839840if (!skb) {841nes_debug(NES_DBG_CM, "Failed to get a Free pkt\n");842return -1;843}844845form_cm_frame(skb, cm_node, NULL, 0, NULL, 0, SET_ACK | SET_FIN);846ret = schedule_nes_timer(cm_node, skb, NES_TIMER_TYPE_SEND, 1, 0);847848return ret;849}850851852/**853* find_node - find a cm node that matches the reference cm node854*/855static struct nes_cm_node *find_node(struct nes_cm_core *cm_core,856u16 rem_port, nes_addr_t rem_addr, u16 loc_port, nes_addr_t loc_addr)857{858unsigned long flags;859struct list_head *hte;860struct nes_cm_node *cm_node;861862/* get a handle on the hte */863hte = &cm_core->connected_nodes;864865/* walk list and find cm_node associated with this session ID */866spin_lock_irqsave(&cm_core->ht_lock, flags);867list_for_each_entry(cm_node, hte, list) {868/* compare quad, return node handle if a match */869nes_debug(NES_DBG_CM, "finding node %x:%x =? %x:%x ^ %x:%x =? %x:%x\n",870cm_node->loc_addr, cm_node->loc_port,871loc_addr, loc_port,872cm_node->rem_addr, cm_node->rem_port,873rem_addr, rem_port);874if ((cm_node->loc_addr == loc_addr) && (cm_node->loc_port == loc_port) &&875(cm_node->rem_addr == rem_addr) && (cm_node->rem_port == rem_port)) {876add_ref_cm_node(cm_node);877spin_unlock_irqrestore(&cm_core->ht_lock, flags);878return cm_node;879}880}881spin_unlock_irqrestore(&cm_core->ht_lock, flags);882883/* no owner node */884return NULL;885}886887888/**889* find_listener - find a cm node listening on this addr-port pair890*/891static struct nes_cm_listener *find_listener(struct nes_cm_core *cm_core,892nes_addr_t dst_addr, u16 dst_port, enum nes_cm_listener_state listener_state)893{894unsigned long flags;895struct nes_cm_listener *listen_node;896897/* walk list and find cm_node associated with this session ID */898spin_lock_irqsave(&cm_core->listen_list_lock, flags);899list_for_each_entry(listen_node, &cm_core->listen_list.list, list) {900/* compare node pair, return node handle if a match */901if (((listen_node->loc_addr == dst_addr) ||902listen_node->loc_addr == 0x00000000) &&903(listen_node->loc_port == dst_port) &&904(listener_state & listen_node->listener_state)) {905atomic_inc(&listen_node->ref_count);906spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);907return listen_node;908}909}910spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);911912/* no listener */913return NULL;914}915916917/**918* add_hte_node - add a cm node to the hash table919*/920static int add_hte_node(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node)921{922unsigned long flags;923struct list_head *hte;924925if (!cm_node || !cm_core)926return -EINVAL;927928nes_debug(NES_DBG_CM, "Adding Node %p to Active Connection HT\n",929cm_node);930931spin_lock_irqsave(&cm_core->ht_lock, flags);932933/* get a handle on the hash table element (list head for this slot) */934hte = &cm_core->connected_nodes;935list_add_tail(&cm_node->list, hte);936atomic_inc(&cm_core->ht_node_cnt);937938spin_unlock_irqrestore(&cm_core->ht_lock, flags);939940return 0;941}942943944/**945* mini_cm_dec_refcnt_listen946*/947static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,948struct nes_cm_listener *listener, int free_hanging_nodes)949{950int ret = -EINVAL;951int err = 0;952unsigned long flags;953struct list_head *list_pos = NULL;954struct list_head *list_temp = NULL;955struct nes_cm_node *cm_node = NULL;956struct list_head reset_list;957958nes_debug(NES_DBG_CM, "attempting listener= %p free_nodes= %d, "959"refcnt=%d\n", listener, free_hanging_nodes,960atomic_read(&listener->ref_count));961/* free non-accelerated child nodes for this listener */962INIT_LIST_HEAD(&reset_list);963if (free_hanging_nodes) {964spin_lock_irqsave(&cm_core->ht_lock, flags);965list_for_each_safe(list_pos, list_temp,966&g_cm_core->connected_nodes) {967cm_node = container_of(list_pos, struct nes_cm_node,968list);969if ((cm_node->listener == listener) &&970(!cm_node->accelerated)) {971add_ref_cm_node(cm_node);972list_add(&cm_node->reset_entry, &reset_list);973}974}975spin_unlock_irqrestore(&cm_core->ht_lock, flags);976}977978list_for_each_safe(list_pos, list_temp, &reset_list) {979cm_node = container_of(list_pos, struct nes_cm_node,980reset_entry);981{982struct nes_cm_node *loopback = cm_node->loopbackpartner;983enum nes_cm_node_state old_state;984if (NES_CM_STATE_FIN_WAIT1 <= cm_node->state) {985rem_ref_cm_node(cm_node->cm_core, cm_node);986} else {987if (!loopback) {988cleanup_retrans_entry(cm_node);989err = send_reset(cm_node, NULL);990if (err) {991cm_node->state =992NES_CM_STATE_CLOSED;993WARN_ON(1);994} else {995old_state = cm_node->state;996cm_node->state = NES_CM_STATE_LISTENER_DESTROYED;997if (old_state != NES_CM_STATE_MPAREQ_RCVD)998rem_ref_cm_node(999cm_node->cm_core,1000cm_node);1001}1002} else {1003struct nes_cm_event event;10041005event.cm_node = loopback;1006event.cm_info.rem_addr =1007loopback->rem_addr;1008event.cm_info.loc_addr =1009loopback->loc_addr;1010event.cm_info.rem_port =1011loopback->rem_port;1012event.cm_info.loc_port =1013loopback->loc_port;1014event.cm_info.cm_id = loopback->cm_id;1015add_ref_cm_node(loopback);1016loopback->state = NES_CM_STATE_CLOSED;1017cm_event_connect_error(&event);1018cm_node->state = NES_CM_STATE_LISTENER_DESTROYED;10191020rem_ref_cm_node(cm_node->cm_core,1021cm_node);10221023}1024}1025}1026}10271028spin_lock_irqsave(&cm_core->listen_list_lock, flags);1029if (!atomic_dec_return(&listener->ref_count)) {1030list_del(&listener->list);10311032/* decrement our listen node count */1033atomic_dec(&cm_core->listen_node_cnt);10341035spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);10361037if (listener->nesvnic) {1038nes_manage_apbvt(listener->nesvnic, listener->loc_port,1039PCI_FUNC(listener->nesvnic->nesdev->pcidev->devfn), NES_MANAGE_APBVT_DEL);1040}10411042nes_debug(NES_DBG_CM, "destroying listener (%p)\n", listener);10431044kfree(listener);1045listener = NULL;1046ret = 0;1047atomic_inc(&cm_listens_destroyed);1048} else {1049spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);1050}1051if (listener) {1052if (atomic_read(&listener->pend_accepts_cnt) > 0)1053nes_debug(NES_DBG_CM, "destroying listener (%p)"1054" with non-zero pending accepts=%u\n",1055listener, atomic_read(&listener->pend_accepts_cnt));1056}10571058return ret;1059}106010611062/**1063* mini_cm_del_listen1064*/1065static int mini_cm_del_listen(struct nes_cm_core *cm_core,1066struct nes_cm_listener *listener)1067{1068listener->listener_state = NES_CM_LISTENER_PASSIVE_STATE;1069listener->cm_id = NULL; /* going to be destroyed pretty soon */1070return mini_cm_dec_refcnt_listen(cm_core, listener, 1);1071}107210731074/**1075* mini_cm_accelerated1076*/1077static inline int mini_cm_accelerated(struct nes_cm_core *cm_core,1078struct nes_cm_node *cm_node)1079{1080u32 was_timer_set;1081cm_node->accelerated = 1;10821083if (cm_node->accept_pend) {1084BUG_ON(!cm_node->listener);1085atomic_dec(&cm_node->listener->pend_accepts_cnt);1086cm_node->accept_pend = 0;1087BUG_ON(atomic_read(&cm_node->listener->pend_accepts_cnt) < 0);1088}10891090was_timer_set = timer_pending(&cm_core->tcp_timer);1091if (!was_timer_set) {1092cm_core->tcp_timer.expires = jiffies + NES_SHORT_TIME;1093add_timer(&cm_core->tcp_timer);1094}10951096return 0;1097}109810991100/**1101* nes_addr_resolve_neigh1102*/1103static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip, int arpindex)1104{1105struct rtable *rt;1106struct neighbour *neigh;1107int rc = arpindex;1108struct net_device *netdev;1109struct nes_adapter *nesadapter = nesvnic->nesdev->nesadapter;11101111rt = ip_route_output(&init_net, htonl(dst_ip), 0, 0, 0);1112if (IS_ERR(rt)) {1113printk(KERN_ERR "%s: ip_route_output_key failed for 0x%08X\n",1114__func__, dst_ip);1115return rc;1116}11171118if (netif_is_bond_slave(nesvnic->netdev))1119netdev = nesvnic->netdev->master;1120else1121netdev = nesvnic->netdev;11221123neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, netdev);1124if (neigh) {1125if (neigh->nud_state & NUD_VALID) {1126nes_debug(NES_DBG_CM, "Neighbor MAC address for 0x%08X"1127" is %pM, Gateway is 0x%08X \n", dst_ip,1128neigh->ha, ntohl(rt->rt_gateway));11291130if (arpindex >= 0) {1131if (!memcmp(nesadapter->arp_table[arpindex].mac_addr,1132neigh->ha, ETH_ALEN)){1133/* Mac address same as in nes_arp_table */1134neigh_release(neigh);1135ip_rt_put(rt);1136return rc;1137}11381139nes_manage_arp_cache(nesvnic->netdev,1140nesadapter->arp_table[arpindex].mac_addr,1141dst_ip, NES_ARP_DELETE);1142}11431144nes_manage_arp_cache(nesvnic->netdev, neigh->ha,1145dst_ip, NES_ARP_ADD);1146rc = nes_arp_table(nesvnic->nesdev, dst_ip, NULL,1147NES_ARP_RESOLVE);1148}1149neigh_release(neigh);1150}11511152if ((neigh == NULL) || (!(neigh->nud_state & NUD_VALID)))1153neigh_event_send(rt->dst.neighbour, NULL);11541155ip_rt_put(rt);1156return rc;1157}11581159/**1160* make_cm_node - create a new instance of a cm node1161*/1162static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core,1163struct nes_vnic *nesvnic, struct nes_cm_info *cm_info,1164struct nes_cm_listener *listener)1165{1166struct nes_cm_node *cm_node;1167struct timespec ts;1168int oldarpindex = 0;1169int arpindex = 0;1170struct nes_device *nesdev;1171struct nes_adapter *nesadapter;11721173/* create an hte and cm_node for this instance */1174cm_node = kzalloc(sizeof(*cm_node), GFP_ATOMIC);1175if (!cm_node)1176return NULL;11771178/* set our node specific transport info */1179cm_node->loc_addr = cm_info->loc_addr;1180cm_node->rem_addr = cm_info->rem_addr;1181cm_node->loc_port = cm_info->loc_port;1182cm_node->rem_port = cm_info->rem_port;1183cm_node->send_write0 = send_first;1184nes_debug(NES_DBG_CM, "Make node addresses : loc = %pI4:%x, rem = %pI4:%x\n",1185&cm_node->loc_addr, cm_node->loc_port,1186&cm_node->rem_addr, cm_node->rem_port);1187cm_node->listener = listener;1188cm_node->netdev = nesvnic->netdev;1189cm_node->cm_id = cm_info->cm_id;1190memcpy(cm_node->loc_mac, nesvnic->netdev->dev_addr, ETH_ALEN);11911192nes_debug(NES_DBG_CM, "listener=%p, cm_id=%p\n", cm_node->listener,1193cm_node->cm_id);11941195spin_lock_init(&cm_node->retrans_list_lock);11961197cm_node->loopbackpartner = NULL;1198atomic_set(&cm_node->ref_count, 1);1199/* associate our parent CM core */1200cm_node->cm_core = cm_core;1201cm_node->tcp_cntxt.loc_id = NES_CM_DEF_LOCAL_ID;1202cm_node->tcp_cntxt.rcv_wscale = NES_CM_DEFAULT_RCV_WND_SCALE;1203cm_node->tcp_cntxt.rcv_wnd = NES_CM_DEFAULT_RCV_WND_SCALED >>1204NES_CM_DEFAULT_RCV_WND_SCALE;1205ts = current_kernel_time();1206cm_node->tcp_cntxt.loc_seq_num = htonl(ts.tv_nsec);1207cm_node->tcp_cntxt.mss = nesvnic->max_frame_size - sizeof(struct iphdr) -1208sizeof(struct tcphdr) - ETH_HLEN - VLAN_HLEN;1209cm_node->tcp_cntxt.rcv_nxt = 0;1210/* get a unique session ID , add thread_id to an upcounter to handle race */1211atomic_inc(&cm_core->node_cnt);1212cm_node->conn_type = cm_info->conn_type;1213cm_node->apbvt_set = 0;1214cm_node->accept_pend = 0;12151216cm_node->nesvnic = nesvnic;1217/* get some device handles, for arp lookup */1218nesdev = nesvnic->nesdev;1219nesadapter = nesdev->nesadapter;12201221cm_node->loopbackpartner = NULL;12221223/* get the mac addr for the remote node */1224if (ipv4_is_loopback(htonl(cm_node->rem_addr)))1225arpindex = nes_arp_table(nesdev, ntohl(nesvnic->local_ipaddr), NULL, NES_ARP_RESOLVE);1226else {1227oldarpindex = nes_arp_table(nesdev, cm_node->rem_addr, NULL, NES_ARP_RESOLVE);1228arpindex = nes_addr_resolve_neigh(nesvnic, cm_info->rem_addr, oldarpindex);12291230}1231if (arpindex < 0) {1232kfree(cm_node);1233return NULL;1234}12351236/* copy the mac addr to node context */1237memcpy(cm_node->rem_mac, nesadapter->arp_table[arpindex].mac_addr, ETH_ALEN);1238nes_debug(NES_DBG_CM, "Remote mac addr from arp table: %pM\n",1239cm_node->rem_mac);12401241add_hte_node(cm_core, cm_node);1242atomic_inc(&cm_nodes_created);12431244return cm_node;1245}124612471248/**1249* add_ref_cm_node - destroy an instance of a cm node1250*/1251static int add_ref_cm_node(struct nes_cm_node *cm_node)1252{1253atomic_inc(&cm_node->ref_count);1254return 0;1255}125612571258/**1259* rem_ref_cm_node - destroy an instance of a cm node1260*/1261static int rem_ref_cm_node(struct nes_cm_core *cm_core,1262struct nes_cm_node *cm_node)1263{1264unsigned long flags;1265struct nes_qp *nesqp;12661267if (!cm_node)1268return -EINVAL;12691270spin_lock_irqsave(&cm_node->cm_core->ht_lock, flags);1271if (atomic_dec_return(&cm_node->ref_count)) {1272spin_unlock_irqrestore(&cm_node->cm_core->ht_lock, flags);1273return 0;1274}1275list_del(&cm_node->list);1276atomic_dec(&cm_core->ht_node_cnt);1277spin_unlock_irqrestore(&cm_node->cm_core->ht_lock, flags);12781279/* if the node is destroyed before connection was accelerated */1280if (!cm_node->accelerated && cm_node->accept_pend) {1281BUG_ON(!cm_node->listener);1282atomic_dec(&cm_node->listener->pend_accepts_cnt);1283BUG_ON(atomic_read(&cm_node->listener->pend_accepts_cnt) < 0);1284}1285WARN_ON(cm_node->send_entry);1286if (cm_node->recv_entry)1287handle_recv_entry(cm_node, 0);1288if (cm_node->listener) {1289mini_cm_dec_refcnt_listen(cm_core, cm_node->listener, 0);1290} else {1291if (cm_node->apbvt_set && cm_node->nesvnic) {1292nes_manage_apbvt(cm_node->nesvnic, cm_node->loc_port,1293PCI_FUNC(1294cm_node->nesvnic->nesdev->pcidev->devfn),1295NES_MANAGE_APBVT_DEL);1296}1297}12981299atomic_dec(&cm_core->node_cnt);1300atomic_inc(&cm_nodes_destroyed);1301nesqp = cm_node->nesqp;1302if (nesqp) {1303nesqp->cm_node = NULL;1304nes_rem_ref(&nesqp->ibqp);1305cm_node->nesqp = NULL;1306}13071308kfree(cm_node);1309return 0;1310}13111312/**1313* process_options1314*/1315static int process_options(struct nes_cm_node *cm_node, u8 *optionsloc,1316u32 optionsize, u32 syn_packet)1317{1318u32 tmp;1319u32 offset = 0;1320union all_known_options *all_options;1321char got_mss_option = 0;13221323while (offset < optionsize) {1324all_options = (union all_known_options *)(optionsloc + offset);1325switch (all_options->as_base.optionnum) {1326case OPTION_NUMBER_END:1327offset = optionsize;1328break;1329case OPTION_NUMBER_NONE:1330offset += 1;1331continue;1332case OPTION_NUMBER_MSS:1333nes_debug(NES_DBG_CM, "%s: MSS Length: %d Offset: %d "1334"Size: %d\n", __func__,1335all_options->as_mss.length, offset, optionsize);1336got_mss_option = 1;1337if (all_options->as_mss.length != 4) {1338return 1;1339} else {1340tmp = ntohs(all_options->as_mss.mss);1341if (tmp > 0 && tmp <1342cm_node->tcp_cntxt.mss)1343cm_node->tcp_cntxt.mss = tmp;1344}1345break;1346case OPTION_NUMBER_WINDOW_SCALE:1347cm_node->tcp_cntxt.snd_wscale =1348all_options->as_windowscale.shiftcount;1349break;1350case OPTION_NUMBER_WRITE0:1351cm_node->send_write0 = 1;1352break;1353default:1354nes_debug(NES_DBG_CM, "TCP Option not understood: %x\n",1355all_options->as_base.optionnum);1356break;1357}1358offset += all_options->as_base.length;1359}1360if ((!got_mss_option) && (syn_packet))1361cm_node->tcp_cntxt.mss = NES_CM_DEFAULT_MSS;1362return 0;1363}13641365static void drop_packet(struct sk_buff *skb)1366{1367atomic_inc(&cm_accel_dropped_pkts);1368dev_kfree_skb_any(skb);1369}13701371static void handle_fin_pkt(struct nes_cm_node *cm_node)1372{1373nes_debug(NES_DBG_CM, "Received FIN, cm_node = %p, state = %u. "1374"refcnt=%d\n", cm_node, cm_node->state,1375atomic_read(&cm_node->ref_count));1376switch (cm_node->state) {1377case NES_CM_STATE_SYN_RCVD:1378case NES_CM_STATE_SYN_SENT:1379case NES_CM_STATE_ESTABLISHED:1380case NES_CM_STATE_MPAREJ_RCVD:1381cm_node->tcp_cntxt.rcv_nxt++;1382cleanup_retrans_entry(cm_node);1383cm_node->state = NES_CM_STATE_LAST_ACK;1384send_fin(cm_node, NULL);1385break;1386case NES_CM_STATE_MPAREQ_SENT:1387create_event(cm_node, NES_CM_EVENT_ABORTED);1388cm_node->tcp_cntxt.rcv_nxt++;1389cleanup_retrans_entry(cm_node);1390cm_node->state = NES_CM_STATE_CLOSED;1391add_ref_cm_node(cm_node);1392send_reset(cm_node, NULL);1393break;1394case NES_CM_STATE_FIN_WAIT1:1395cm_node->tcp_cntxt.rcv_nxt++;1396cleanup_retrans_entry(cm_node);1397cm_node->state = NES_CM_STATE_CLOSING;1398send_ack(cm_node, NULL);1399/* Wait for ACK as this is simultaneous close..1400* After we receive ACK, do not send anything..1401* Just rm the node.. Done.. */1402break;1403case NES_CM_STATE_FIN_WAIT2:1404cm_node->tcp_cntxt.rcv_nxt++;1405cleanup_retrans_entry(cm_node);1406cm_node->state = NES_CM_STATE_TIME_WAIT;1407send_ack(cm_node, NULL);1408schedule_nes_timer(cm_node, NULL, NES_TIMER_TYPE_CLOSE, 1, 0);1409break;1410case NES_CM_STATE_TIME_WAIT:1411cm_node->tcp_cntxt.rcv_nxt++;1412cleanup_retrans_entry(cm_node);1413cm_node->state = NES_CM_STATE_CLOSED;1414rem_ref_cm_node(cm_node->cm_core, cm_node);1415break;1416case NES_CM_STATE_TSA:1417default:1418nes_debug(NES_DBG_CM, "Error Rcvd FIN for node-%p state = %d\n",1419cm_node, cm_node->state);1420break;1421}1422}142314241425static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,1426struct tcphdr *tcph)1427{14281429int reset = 0; /* whether to send reset in case of err.. */1430atomic_inc(&cm_resets_recvd);1431nes_debug(NES_DBG_CM, "Received Reset, cm_node = %p, state = %u."1432" refcnt=%d\n", cm_node, cm_node->state,1433atomic_read(&cm_node->ref_count));1434cleanup_retrans_entry(cm_node);1435switch (cm_node->state) {1436case NES_CM_STATE_SYN_SENT:1437case NES_CM_STATE_MPAREQ_SENT:1438nes_debug(NES_DBG_CM, "%s[%u] create abort for cm_node=%p "1439"listener=%p state=%d\n", __func__, __LINE__, cm_node,1440cm_node->listener, cm_node->state);1441active_open_err(cm_node, skb, reset);1442break;1443case NES_CM_STATE_MPAREQ_RCVD:1444atomic_inc(&cm_node->passive_state);1445dev_kfree_skb_any(skb);1446break;1447case NES_CM_STATE_ESTABLISHED:1448case NES_CM_STATE_SYN_RCVD:1449case NES_CM_STATE_LISTENING:1450nes_debug(NES_DBG_CM, "Bad state %s[%u]\n", __func__, __LINE__);1451passive_open_err(cm_node, skb, reset);1452break;1453case NES_CM_STATE_TSA:1454active_open_err(cm_node, skb, reset);1455break;1456case NES_CM_STATE_CLOSED:1457drop_packet(skb);1458break;1459case NES_CM_STATE_FIN_WAIT2:1460case NES_CM_STATE_FIN_WAIT1:1461case NES_CM_STATE_LAST_ACK:1462cm_node->cm_id->rem_ref(cm_node->cm_id);1463case NES_CM_STATE_TIME_WAIT:1464cm_node->state = NES_CM_STATE_CLOSED;1465rem_ref_cm_node(cm_node->cm_core, cm_node);1466drop_packet(skb);1467break;1468default:1469drop_packet(skb);1470break;1471}1472}147314741475static void handle_rcv_mpa(struct nes_cm_node *cm_node, struct sk_buff *skb)1476{14771478int ret = 0;1479int datasize = skb->len;1480u8 *dataloc = skb->data;14811482enum nes_cm_event_type type = NES_CM_EVENT_UNKNOWN;1483u32 res_type;1484ret = parse_mpa(cm_node, dataloc, &res_type, datasize);1485if (ret) {1486nes_debug(NES_DBG_CM, "didn't like MPA Request\n");1487if (cm_node->state == NES_CM_STATE_MPAREQ_SENT) {1488nes_debug(NES_DBG_CM, "%s[%u] create abort for "1489"cm_node=%p listener=%p state=%d\n", __func__,1490__LINE__, cm_node, cm_node->listener,1491cm_node->state);1492active_open_err(cm_node, skb, 1);1493} else {1494passive_open_err(cm_node, skb, 1);1495}1496return;1497}14981499switch (cm_node->state) {1500case NES_CM_STATE_ESTABLISHED:1501if (res_type == NES_MPA_REQUEST_REJECT) {1502/*BIG problem as we are receiving the MPA.. So should1503* not be REJECT.. This is Passive Open.. We can1504* only receive it Reject for Active Open...*/1505WARN_ON(1);1506}1507cm_node->state = NES_CM_STATE_MPAREQ_RCVD;1508type = NES_CM_EVENT_MPA_REQ;1509atomic_set(&cm_node->passive_state,1510NES_PASSIVE_STATE_INDICATED);1511break;1512case NES_CM_STATE_MPAREQ_SENT:1513cleanup_retrans_entry(cm_node);1514if (res_type == NES_MPA_REQUEST_REJECT) {1515type = NES_CM_EVENT_MPA_REJECT;1516cm_node->state = NES_CM_STATE_MPAREJ_RCVD;1517} else {1518type = NES_CM_EVENT_CONNECTED;1519cm_node->state = NES_CM_STATE_TSA;1520}15211522break;1523default:1524WARN_ON(1);1525break;1526}1527dev_kfree_skb_any(skb);1528create_event(cm_node, type);1529}15301531static void indicate_pkt_err(struct nes_cm_node *cm_node, struct sk_buff *skb)1532{1533switch (cm_node->state) {1534case NES_CM_STATE_SYN_SENT:1535case NES_CM_STATE_MPAREQ_SENT:1536nes_debug(NES_DBG_CM, "%s[%u] create abort for cm_node=%p "1537"listener=%p state=%d\n", __func__, __LINE__, cm_node,1538cm_node->listener, cm_node->state);1539active_open_err(cm_node, skb, 1);1540break;1541case NES_CM_STATE_ESTABLISHED:1542case NES_CM_STATE_SYN_RCVD:1543passive_open_err(cm_node, skb, 1);1544break;1545case NES_CM_STATE_TSA:1546default:1547drop_packet(skb);1548}1549}15501551static int check_syn(struct nes_cm_node *cm_node, struct tcphdr *tcph,1552struct sk_buff *skb)1553{1554int err;15551556err = ((ntohl(tcph->ack_seq) == cm_node->tcp_cntxt.loc_seq_num))? 0 : 1;1557if (err)1558active_open_err(cm_node, skb, 1);15591560return err;1561}15621563static int check_seq(struct nes_cm_node *cm_node, struct tcphdr *tcph,1564struct sk_buff *skb)1565{1566int err = 0;1567u32 seq;1568u32 ack_seq;1569u32 loc_seq_num = cm_node->tcp_cntxt.loc_seq_num;1570u32 rcv_nxt = cm_node->tcp_cntxt.rcv_nxt;1571u32 rcv_wnd;1572seq = ntohl(tcph->seq);1573ack_seq = ntohl(tcph->ack_seq);1574rcv_wnd = cm_node->tcp_cntxt.rcv_wnd;1575if (ack_seq != loc_seq_num)1576err = 1;1577else if (!between(seq, rcv_nxt, (rcv_nxt+rcv_wnd)))1578err = 1;1579if (err) {1580nes_debug(NES_DBG_CM, "%s[%u] create abort for cm_node=%p "1581"listener=%p state=%d\n", __func__, __LINE__, cm_node,1582cm_node->listener, cm_node->state);1583indicate_pkt_err(cm_node, skb);1584nes_debug(NES_DBG_CM, "seq ERROR cm_node =%p seq=0x%08X "1585"rcv_nxt=0x%08X rcv_wnd=0x%x\n", cm_node, seq, rcv_nxt,1586rcv_wnd);1587}1588return err;1589}15901591/*1592* handle_syn_pkt() is for Passive node. The syn packet is received when a node1593* is created with a listener or it may comein as rexmitted packet which in1594* that case will be just dropped.1595*/15961597static void handle_syn_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,1598struct tcphdr *tcph)1599{1600int ret;1601u32 inc_sequence;1602int optionsize;16031604optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);1605skb_trim(skb, 0);1606inc_sequence = ntohl(tcph->seq);16071608switch (cm_node->state) {1609case NES_CM_STATE_SYN_SENT:1610case NES_CM_STATE_MPAREQ_SENT:1611/* Rcvd syn on active open connection*/1612active_open_err(cm_node, skb, 1);1613break;1614case NES_CM_STATE_LISTENING:1615/* Passive OPEN */1616if (atomic_read(&cm_node->listener->pend_accepts_cnt) >1617cm_node->listener->backlog) {1618nes_debug(NES_DBG_CM, "drop syn due to backlog "1619"pressure \n");1620cm_backlog_drops++;1621passive_open_err(cm_node, skb, 0);1622break;1623}1624ret = handle_tcp_options(cm_node, tcph, skb, optionsize,16251);1626if (ret) {1627passive_open_err(cm_node, skb, 0);1628/* drop pkt */1629break;1630}1631cm_node->tcp_cntxt.rcv_nxt = inc_sequence + 1;1632BUG_ON(cm_node->send_entry);1633cm_node->accept_pend = 1;1634atomic_inc(&cm_node->listener->pend_accepts_cnt);16351636cm_node->state = NES_CM_STATE_SYN_RCVD;1637send_syn(cm_node, 1, skb);1638break;1639case NES_CM_STATE_CLOSED:1640cleanup_retrans_entry(cm_node);1641add_ref_cm_node(cm_node);1642send_reset(cm_node, skb);1643break;1644case NES_CM_STATE_TSA:1645case NES_CM_STATE_ESTABLISHED:1646case NES_CM_STATE_FIN_WAIT1:1647case NES_CM_STATE_FIN_WAIT2:1648case NES_CM_STATE_MPAREQ_RCVD:1649case NES_CM_STATE_LAST_ACK:1650case NES_CM_STATE_CLOSING:1651case NES_CM_STATE_UNKNOWN:1652default:1653drop_packet(skb);1654break;1655}1656}16571658static void handle_synack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,1659struct tcphdr *tcph)1660{16611662int ret;1663u32 inc_sequence;1664int optionsize;16651666optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);1667skb_trim(skb, 0);1668inc_sequence = ntohl(tcph->seq);1669switch (cm_node->state) {1670case NES_CM_STATE_SYN_SENT:1671cleanup_retrans_entry(cm_node);1672/* active open */1673if (check_syn(cm_node, tcph, skb))1674return;1675cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);1676/* setup options */1677ret = handle_tcp_options(cm_node, tcph, skb, optionsize, 0);1678if (ret) {1679nes_debug(NES_DBG_CM, "cm_node=%p tcp_options failed\n",1680cm_node);1681break;1682}1683cleanup_retrans_entry(cm_node);1684cm_node->tcp_cntxt.rcv_nxt = inc_sequence + 1;1685send_mpa_request(cm_node, skb);1686cm_node->state = NES_CM_STATE_MPAREQ_SENT;1687break;1688case NES_CM_STATE_MPAREQ_RCVD:1689/* passive open, so should not be here */1690passive_open_err(cm_node, skb, 1);1691break;1692case NES_CM_STATE_LISTENING:1693cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq);1694cleanup_retrans_entry(cm_node);1695cm_node->state = NES_CM_STATE_CLOSED;1696send_reset(cm_node, skb);1697break;1698case NES_CM_STATE_CLOSED:1699cm_node->tcp_cntxt.loc_seq_num = ntohl(tcph->ack_seq);1700cleanup_retrans_entry(cm_node);1701add_ref_cm_node(cm_node);1702send_reset(cm_node, skb);1703break;1704case NES_CM_STATE_ESTABLISHED:1705case NES_CM_STATE_FIN_WAIT1:1706case NES_CM_STATE_FIN_WAIT2:1707case NES_CM_STATE_LAST_ACK:1708case NES_CM_STATE_TSA:1709case NES_CM_STATE_CLOSING:1710case NES_CM_STATE_UNKNOWN:1711case NES_CM_STATE_MPAREQ_SENT:1712default:1713drop_packet(skb);1714break;1715}1716}17171718static int handle_ack_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb,1719struct tcphdr *tcph)1720{1721int datasize = 0;1722u32 inc_sequence;1723int ret = 0;1724int optionsize;1725optionsize = (tcph->doff << 2) - sizeof(struct tcphdr);17261727if (check_seq(cm_node, tcph, skb))1728return -EINVAL;17291730skb_pull(skb, tcph->doff << 2);1731inc_sequence = ntohl(tcph->seq);1732datasize = skb->len;1733switch (cm_node->state) {1734case NES_CM_STATE_SYN_RCVD:1735/* Passive OPEN */1736cleanup_retrans_entry(cm_node);1737ret = handle_tcp_options(cm_node, tcph, skb, optionsize, 1);1738if (ret)1739break;1740cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);1741cm_node->state = NES_CM_STATE_ESTABLISHED;1742if (datasize) {1743cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;1744handle_rcv_mpa(cm_node, skb);1745} else /* rcvd ACK only */1746dev_kfree_skb_any(skb);1747break;1748case NES_CM_STATE_ESTABLISHED:1749/* Passive OPEN */1750cleanup_retrans_entry(cm_node);1751if (datasize) {1752cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;1753handle_rcv_mpa(cm_node, skb);1754} else1755drop_packet(skb);1756break;1757case NES_CM_STATE_MPAREQ_SENT:1758cm_node->tcp_cntxt.rem_ack_num = ntohl(tcph->ack_seq);1759if (datasize) {1760cm_node->tcp_cntxt.rcv_nxt = inc_sequence + datasize;1761handle_rcv_mpa(cm_node, skb);1762} else /* Could be just an ack pkt.. */1763dev_kfree_skb_any(skb);1764break;1765case NES_CM_STATE_LISTENING:1766cleanup_retrans_entry(cm_node);1767cm_node->state = NES_CM_STATE_CLOSED;1768send_reset(cm_node, skb);1769break;1770case NES_CM_STATE_CLOSED:1771cleanup_retrans_entry(cm_node);1772add_ref_cm_node(cm_node);1773send_reset(cm_node, skb);1774break;1775case NES_CM_STATE_LAST_ACK:1776case NES_CM_STATE_CLOSING:1777cleanup_retrans_entry(cm_node);1778cm_node->state = NES_CM_STATE_CLOSED;1779cm_node->cm_id->rem_ref(cm_node->cm_id);1780rem_ref_cm_node(cm_node->cm_core, cm_node);1781drop_packet(skb);1782break;1783case NES_CM_STATE_FIN_WAIT1:1784cleanup_retrans_entry(cm_node);1785drop_packet(skb);1786cm_node->state = NES_CM_STATE_FIN_WAIT2;1787break;1788case NES_CM_STATE_SYN_SENT:1789case NES_CM_STATE_FIN_WAIT2:1790case NES_CM_STATE_TSA:1791case NES_CM_STATE_MPAREQ_RCVD:1792case NES_CM_STATE_UNKNOWN:1793default:1794cleanup_retrans_entry(cm_node);1795drop_packet(skb);1796break;1797}1798return ret;1799}1800180118021803static int handle_tcp_options(struct nes_cm_node *cm_node, struct tcphdr *tcph,1804struct sk_buff *skb, int optionsize, int passive)1805{1806u8 *optionsloc = (u8 *)&tcph[1];1807if (optionsize) {1808if (process_options(cm_node, optionsloc, optionsize,1809(u32)tcph->syn)) {1810nes_debug(NES_DBG_CM, "%s: Node %p, Sending RESET\n",1811__func__, cm_node);1812if (passive)1813passive_open_err(cm_node, skb, 1);1814else1815active_open_err(cm_node, skb, 1);1816return 1;1817}1818}18191820cm_node->tcp_cntxt.snd_wnd = ntohs(tcph->window) <<1821cm_node->tcp_cntxt.snd_wscale;18221823if (cm_node->tcp_cntxt.snd_wnd > cm_node->tcp_cntxt.max_snd_wnd)1824cm_node->tcp_cntxt.max_snd_wnd = cm_node->tcp_cntxt.snd_wnd;1825return 0;1826}18271828/*1829* active_open_err() will send reset() if flag set..1830* It will also send ABORT event.1831*/18321833static void active_open_err(struct nes_cm_node *cm_node, struct sk_buff *skb,1834int reset)1835{1836cleanup_retrans_entry(cm_node);1837if (reset) {1838nes_debug(NES_DBG_CM, "ERROR active err called for cm_node=%p, "1839"state=%d\n", cm_node, cm_node->state);1840add_ref_cm_node(cm_node);1841send_reset(cm_node, skb);1842} else1843dev_kfree_skb_any(skb);18441845cm_node->state = NES_CM_STATE_CLOSED;1846create_event(cm_node, NES_CM_EVENT_ABORTED);1847}18481849/*1850* passive_open_err() will either do a reset() or will free up the skb and1851* remove the cm_node.1852*/18531854static void passive_open_err(struct nes_cm_node *cm_node, struct sk_buff *skb,1855int reset)1856{1857cleanup_retrans_entry(cm_node);1858cm_node->state = NES_CM_STATE_CLOSED;1859if (reset) {1860nes_debug(NES_DBG_CM, "passive_open_err sending RST for "1861"cm_node=%p state =%d\n", cm_node, cm_node->state);1862send_reset(cm_node, skb);1863} else {1864dev_kfree_skb_any(skb);1865rem_ref_cm_node(cm_node->cm_core, cm_node);1866}1867}18681869/*1870* free_retrans_entry() routines assumes that the retrans_list_lock has1871* been acquired before calling.1872*/1873static void free_retrans_entry(struct nes_cm_node *cm_node)1874{1875struct nes_timer_entry *send_entry;1876send_entry = cm_node->send_entry;1877if (send_entry) {1878cm_node->send_entry = NULL;1879dev_kfree_skb_any(send_entry->skb);1880kfree(send_entry);1881rem_ref_cm_node(cm_node->cm_core, cm_node);1882}1883}18841885static void cleanup_retrans_entry(struct nes_cm_node *cm_node)1886{1887unsigned long flags;18881889spin_lock_irqsave(&cm_node->retrans_list_lock, flags);1890free_retrans_entry(cm_node);1891spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);1892}18931894/**1895* process_packet1896* Returns skb if to be freed, else it will return NULL if already used..1897*/1898static void process_packet(struct nes_cm_node *cm_node, struct sk_buff *skb,1899struct nes_cm_core *cm_core)1900{1901enum nes_tcpip_pkt_type pkt_type = NES_PKT_TYPE_UNKNOWN;1902struct tcphdr *tcph = tcp_hdr(skb);1903u32 fin_set = 0;1904int ret = 0;1905skb_pull(skb, ip_hdr(skb)->ihl << 2);19061907nes_debug(NES_DBG_CM, "process_packet: cm_node=%p state =%d syn=%d "1908"ack=%d rst=%d fin=%d\n", cm_node, cm_node->state, tcph->syn,1909tcph->ack, tcph->rst, tcph->fin);19101911if (tcph->rst)1912pkt_type = NES_PKT_TYPE_RST;1913else if (tcph->syn) {1914pkt_type = NES_PKT_TYPE_SYN;1915if (tcph->ack)1916pkt_type = NES_PKT_TYPE_SYNACK;1917} else if (tcph->ack)1918pkt_type = NES_PKT_TYPE_ACK;1919if (tcph->fin)1920fin_set = 1;19211922switch (pkt_type) {1923case NES_PKT_TYPE_SYN:1924handle_syn_pkt(cm_node, skb, tcph);1925break;1926case NES_PKT_TYPE_SYNACK:1927handle_synack_pkt(cm_node, skb, tcph);1928break;1929case NES_PKT_TYPE_ACK:1930ret = handle_ack_pkt(cm_node, skb, tcph);1931if (fin_set && !ret)1932handle_fin_pkt(cm_node);1933break;1934case NES_PKT_TYPE_RST:1935handle_rst_pkt(cm_node, skb, tcph);1936break;1937default:1938if ((fin_set) && (!check_seq(cm_node, tcph, skb)))1939handle_fin_pkt(cm_node);1940drop_packet(skb);1941break;1942}1943}19441945/**1946* mini_cm_listen - create a listen node with params1947*/1948static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core,1949struct nes_vnic *nesvnic, struct nes_cm_info *cm_info)1950{1951struct nes_cm_listener *listener;1952unsigned long flags;19531954nes_debug(NES_DBG_CM, "Search for 0x%08x : 0x%04x\n",1955cm_info->loc_addr, cm_info->loc_port);19561957/* cannot have multiple matching listeners */1958listener = find_listener(cm_core, htonl(cm_info->loc_addr),1959htons(cm_info->loc_port), NES_CM_LISTENER_EITHER_STATE);1960if (listener && listener->listener_state == NES_CM_LISTENER_ACTIVE_STATE) {1961/* find automatically incs ref count ??? */1962atomic_dec(&listener->ref_count);1963nes_debug(NES_DBG_CM, "Not creating listener since it already exists\n");1964return NULL;1965}19661967if (!listener) {1968/* create a CM listen node (1/2 node to compare incoming traffic to) */1969listener = kzalloc(sizeof(*listener), GFP_ATOMIC);1970if (!listener) {1971nes_debug(NES_DBG_CM, "Not creating listener memory allocation failed\n");1972return NULL;1973}19741975listener->loc_addr = htonl(cm_info->loc_addr);1976listener->loc_port = htons(cm_info->loc_port);1977listener->reused_node = 0;19781979atomic_set(&listener->ref_count, 1);1980}1981/* pasive case */1982/* find already inc'ed the ref count */1983else {1984listener->reused_node = 1;1985}19861987listener->cm_id = cm_info->cm_id;1988atomic_set(&listener->pend_accepts_cnt, 0);1989listener->cm_core = cm_core;1990listener->nesvnic = nesvnic;1991atomic_inc(&cm_core->node_cnt);19921993listener->conn_type = cm_info->conn_type;1994listener->backlog = cm_info->backlog;1995listener->listener_state = NES_CM_LISTENER_ACTIVE_STATE;19961997if (!listener->reused_node) {1998spin_lock_irqsave(&cm_core->listen_list_lock, flags);1999list_add(&listener->list, &cm_core->listen_list.list);2000spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);2001atomic_inc(&cm_core->listen_node_cnt);2002}20032004nes_debug(NES_DBG_CM, "Api - listen(): addr=0x%08X, port=0x%04x,"2005" listener = %p, backlog = %d, cm_id = %p.\n",2006cm_info->loc_addr, cm_info->loc_port,2007listener, listener->backlog, listener->cm_id);20082009return listener;2010}201120122013/**2014* mini_cm_connect - make a connection node with params2015*/2016static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core,2017struct nes_vnic *nesvnic, u16 private_data_len,2018void *private_data, struct nes_cm_info *cm_info)2019{2020int ret = 0;2021struct nes_cm_node *cm_node;2022struct nes_cm_listener *loopbackremotelistener;2023struct nes_cm_node *loopbackremotenode;2024struct nes_cm_info loopback_cm_info;2025u16 mpa_frame_size = sizeof(struct ietf_mpa_frame) + private_data_len;2026struct ietf_mpa_frame *mpa_frame = NULL;20272028/* create a CM connection node */2029cm_node = make_cm_node(cm_core, nesvnic, cm_info, NULL);2030if (!cm_node)2031return NULL;2032mpa_frame = &cm_node->mpa_frame;2033memcpy(mpa_frame->key, IEFT_MPA_KEY_REQ, IETF_MPA_KEY_SIZE);2034mpa_frame->flags = IETF_MPA_FLAGS_CRC;2035mpa_frame->rev = IETF_MPA_VERSION;2036mpa_frame->priv_data_len = htons(private_data_len);20372038/* set our node side to client (active) side */2039cm_node->tcp_cntxt.client = 1;2040cm_node->tcp_cntxt.rcv_wscale = NES_CM_DEFAULT_RCV_WND_SCALE;20412042if (cm_info->loc_addr == cm_info->rem_addr) {2043loopbackremotelistener = find_listener(cm_core,2044ntohl(nesvnic->local_ipaddr), cm_node->rem_port,2045NES_CM_LISTENER_ACTIVE_STATE);2046if (loopbackremotelistener == NULL) {2047create_event(cm_node, NES_CM_EVENT_ABORTED);2048} else {2049loopback_cm_info = *cm_info;2050loopback_cm_info.loc_port = cm_info->rem_port;2051loopback_cm_info.rem_port = cm_info->loc_port;2052loopback_cm_info.cm_id = loopbackremotelistener->cm_id;2053loopbackremotenode = make_cm_node(cm_core, nesvnic,2054&loopback_cm_info, loopbackremotelistener);2055if (!loopbackremotenode) {2056rem_ref_cm_node(cm_node->cm_core, cm_node);2057return NULL;2058}2059atomic_inc(&cm_loopbacks);2060loopbackremotenode->loopbackpartner = cm_node;2061loopbackremotenode->tcp_cntxt.rcv_wscale =2062NES_CM_DEFAULT_RCV_WND_SCALE;2063cm_node->loopbackpartner = loopbackremotenode;2064memcpy(loopbackremotenode->mpa_frame_buf, private_data,2065private_data_len);2066loopbackremotenode->mpa_frame_size = private_data_len;20672068/* we are done handling this state. */2069/* set node to a TSA state */2070cm_node->state = NES_CM_STATE_TSA;2071cm_node->tcp_cntxt.rcv_nxt =2072loopbackremotenode->tcp_cntxt.loc_seq_num;2073loopbackremotenode->tcp_cntxt.rcv_nxt =2074cm_node->tcp_cntxt.loc_seq_num;2075cm_node->tcp_cntxt.max_snd_wnd =2076loopbackremotenode->tcp_cntxt.rcv_wnd;2077loopbackremotenode->tcp_cntxt.max_snd_wnd =2078cm_node->tcp_cntxt.rcv_wnd;2079cm_node->tcp_cntxt.snd_wnd =2080loopbackremotenode->tcp_cntxt.rcv_wnd;2081loopbackremotenode->tcp_cntxt.snd_wnd =2082cm_node->tcp_cntxt.rcv_wnd;2083cm_node->tcp_cntxt.snd_wscale =2084loopbackremotenode->tcp_cntxt.rcv_wscale;2085loopbackremotenode->tcp_cntxt.snd_wscale =2086cm_node->tcp_cntxt.rcv_wscale;2087loopbackremotenode->state = NES_CM_STATE_MPAREQ_RCVD;2088create_event(loopbackremotenode, NES_CM_EVENT_MPA_REQ);2089}2090return cm_node;2091}20922093/* set our node side to client (active) side */2094cm_node->tcp_cntxt.client = 1;2095/* init our MPA frame ptr */2096memcpy(mpa_frame->priv_data, private_data, private_data_len);20972098cm_node->mpa_frame_size = mpa_frame_size;20992100/* send a syn and goto syn sent state */2101cm_node->state = NES_CM_STATE_SYN_SENT;2102ret = send_syn(cm_node, 0, NULL);21032104if (ret) {2105/* error in sending the syn free up the cm_node struct */2106nes_debug(NES_DBG_CM, "Api - connect() FAILED: dest "2107"addr=0x%08X, port=0x%04x, cm_node=%p, cm_id = %p.\n",2108cm_node->rem_addr, cm_node->rem_port, cm_node,2109cm_node->cm_id);2110rem_ref_cm_node(cm_node->cm_core, cm_node);2111cm_node = NULL;2112}21132114if (cm_node)2115nes_debug(NES_DBG_CM, "Api - connect(): dest addr=0x%08X,"2116"port=0x%04x, cm_node=%p, cm_id = %p.\n",2117cm_node->rem_addr, cm_node->rem_port, cm_node,2118cm_node->cm_id);21192120return cm_node;2121}212221232124/**2125* mini_cm_accept - accept a connection2126* This function is never called2127*/2128static int mini_cm_accept(struct nes_cm_core *cm_core,2129struct ietf_mpa_frame *mpa_frame, struct nes_cm_node *cm_node)2130{2131return 0;2132}213321342135/**2136* mini_cm_reject - reject and teardown a connection2137*/2138static int mini_cm_reject(struct nes_cm_core *cm_core,2139struct ietf_mpa_frame *mpa_frame, struct nes_cm_node *cm_node)2140{2141int ret = 0;2142int err = 0;2143int passive_state;2144struct nes_cm_event event;2145struct iw_cm_id *cm_id = cm_node->cm_id;2146struct nes_cm_node *loopback = cm_node->loopbackpartner;21472148nes_debug(NES_DBG_CM, "%s cm_node=%p type=%d state=%d\n",2149__func__, cm_node, cm_node->tcp_cntxt.client, cm_node->state);21502151if (cm_node->tcp_cntxt.client)2152return ret;2153cleanup_retrans_entry(cm_node);21542155if (!loopback) {2156passive_state = atomic_add_return(1, &cm_node->passive_state);2157if (passive_state == NES_SEND_RESET_EVENT) {2158cm_node->state = NES_CM_STATE_CLOSED;2159rem_ref_cm_node(cm_core, cm_node);2160} else {2161if (cm_node->state == NES_CM_STATE_LISTENER_DESTROYED) {2162rem_ref_cm_node(cm_core, cm_node);2163} else {2164ret = send_mpa_reject(cm_node);2165if (ret) {2166cm_node->state = NES_CM_STATE_CLOSED;2167err = send_reset(cm_node, NULL);2168if (err)2169WARN_ON(1);2170} else2171cm_id->add_ref(cm_id);2172}2173}2174} else {2175cm_node->cm_id = NULL;2176if (cm_node->state == NES_CM_STATE_LISTENER_DESTROYED) {2177rem_ref_cm_node(cm_core, cm_node);2178rem_ref_cm_node(cm_core, loopback);2179} else {2180event.cm_node = loopback;2181event.cm_info.rem_addr = loopback->rem_addr;2182event.cm_info.loc_addr = loopback->loc_addr;2183event.cm_info.rem_port = loopback->rem_port;2184event.cm_info.loc_port = loopback->loc_port;2185event.cm_info.cm_id = loopback->cm_id;2186cm_event_mpa_reject(&event);2187rem_ref_cm_node(cm_core, cm_node);2188loopback->state = NES_CM_STATE_CLOSING;21892190cm_id = loopback->cm_id;2191rem_ref_cm_node(cm_core, loopback);2192cm_id->rem_ref(cm_id);2193}2194}21952196return ret;2197}219821992200/**2201* mini_cm_close2202*/2203static int mini_cm_close(struct nes_cm_core *cm_core, struct nes_cm_node *cm_node)2204{2205int ret = 0;22062207if (!cm_core || !cm_node)2208return -EINVAL;22092210switch (cm_node->state) {2211case NES_CM_STATE_SYN_RCVD:2212case NES_CM_STATE_SYN_SENT:2213case NES_CM_STATE_ONE_SIDE_ESTABLISHED:2214case NES_CM_STATE_ESTABLISHED:2215case NES_CM_STATE_ACCEPTING:2216case NES_CM_STATE_MPAREQ_SENT:2217case NES_CM_STATE_MPAREQ_RCVD:2218cleanup_retrans_entry(cm_node);2219send_reset(cm_node, NULL);2220break;2221case NES_CM_STATE_CLOSE_WAIT:2222cm_node->state = NES_CM_STATE_LAST_ACK;2223send_fin(cm_node, NULL);2224break;2225case NES_CM_STATE_FIN_WAIT1:2226case NES_CM_STATE_FIN_WAIT2:2227case NES_CM_STATE_LAST_ACK:2228case NES_CM_STATE_TIME_WAIT:2229case NES_CM_STATE_CLOSING:2230ret = -1;2231break;2232case NES_CM_STATE_LISTENING:2233cleanup_retrans_entry(cm_node);2234send_reset(cm_node, NULL);2235break;2236case NES_CM_STATE_MPAREJ_RCVD:2237case NES_CM_STATE_UNKNOWN:2238case NES_CM_STATE_INITED:2239case NES_CM_STATE_CLOSED:2240case NES_CM_STATE_LISTENER_DESTROYED:2241ret = rem_ref_cm_node(cm_core, cm_node);2242break;2243case NES_CM_STATE_TSA:2244if (cm_node->send_entry)2245printk(KERN_ERR "ERROR Close got called from STATE_TSA "2246"send_entry=%p\n", cm_node->send_entry);2247ret = rem_ref_cm_node(cm_core, cm_node);2248break;2249}2250return ret;2251}225222532254/**2255* recv_pkt - recv an ETHERNET packet, and process it through CM2256* node state machine2257*/2258static int mini_cm_recv_pkt(struct nes_cm_core *cm_core,2259struct nes_vnic *nesvnic, struct sk_buff *skb)2260{2261struct nes_cm_node *cm_node = NULL;2262struct nes_cm_listener *listener = NULL;2263struct iphdr *iph;2264struct tcphdr *tcph;2265struct nes_cm_info nfo;2266int skb_handled = 1;2267__be32 tmp_daddr, tmp_saddr;22682269if (!skb)2270return 0;2271if (skb->len < sizeof(struct iphdr) + sizeof(struct tcphdr)) {2272return 0;2273}22742275iph = (struct iphdr *)skb->data;2276tcph = (struct tcphdr *)(skb->data + sizeof(struct iphdr));22772278nfo.loc_addr = ntohl(iph->daddr);2279nfo.loc_port = ntohs(tcph->dest);2280nfo.rem_addr = ntohl(iph->saddr);2281nfo.rem_port = ntohs(tcph->source);22822283tmp_daddr = cpu_to_be32(iph->daddr);2284tmp_saddr = cpu_to_be32(iph->saddr);22852286nes_debug(NES_DBG_CM, "Received packet: dest=%pI4:0x%04X src=%pI4:0x%04X\n",2287&tmp_daddr, tcph->dest, &tmp_saddr, tcph->source);22882289do {2290cm_node = find_node(cm_core,2291nfo.rem_port, nfo.rem_addr,2292nfo.loc_port, nfo.loc_addr);22932294if (!cm_node) {2295/* Only type of packet accepted are for */2296/* the PASSIVE open (syn only) */2297if ((!tcph->syn) || (tcph->ack)) {2298skb_handled = 0;2299break;2300}2301listener = find_listener(cm_core, nfo.loc_addr,2302nfo.loc_port,2303NES_CM_LISTENER_ACTIVE_STATE);2304if (!listener) {2305nfo.cm_id = NULL;2306nfo.conn_type = 0;2307nes_debug(NES_DBG_CM, "Unable to find listener for the pkt\n");2308skb_handled = 0;2309break;2310}2311nfo.cm_id = listener->cm_id;2312nfo.conn_type = listener->conn_type;2313cm_node = make_cm_node(cm_core, nesvnic, &nfo,2314listener);2315if (!cm_node) {2316nes_debug(NES_DBG_CM, "Unable to allocate "2317"node\n");2318cm_packets_dropped++;2319atomic_dec(&listener->ref_count);2320dev_kfree_skb_any(skb);2321break;2322}2323if (!tcph->rst && !tcph->fin) {2324cm_node->state = NES_CM_STATE_LISTENING;2325} else {2326cm_packets_dropped++;2327rem_ref_cm_node(cm_core, cm_node);2328dev_kfree_skb_any(skb);2329break;2330}2331add_ref_cm_node(cm_node);2332} else if (cm_node->state == NES_CM_STATE_TSA) {2333rem_ref_cm_node(cm_core, cm_node);2334atomic_inc(&cm_accel_dropped_pkts);2335dev_kfree_skb_any(skb);2336break;2337}2338skb_reset_network_header(skb);2339skb_set_transport_header(skb, sizeof(*tcph));2340skb->len = ntohs(iph->tot_len);2341process_packet(cm_node, skb, cm_core);2342rem_ref_cm_node(cm_core, cm_node);2343} while (0);2344return skb_handled;2345}234623472348/**2349* nes_cm_alloc_core - allocate a top level instance of a cm core2350*/2351static struct nes_cm_core *nes_cm_alloc_core(void)2352{2353struct nes_cm_core *cm_core;23542355/* setup the CM core */2356/* alloc top level core control structure */2357cm_core = kzalloc(sizeof(*cm_core), GFP_KERNEL);2358if (!cm_core)2359return NULL;23602361INIT_LIST_HEAD(&cm_core->connected_nodes);2362init_timer(&cm_core->tcp_timer);2363cm_core->tcp_timer.function = nes_cm_timer_tick;23642365cm_core->mtu = NES_CM_DEFAULT_MTU;2366cm_core->state = NES_CM_STATE_INITED;2367cm_core->free_tx_pkt_max = NES_CM_DEFAULT_FREE_PKTS;23682369atomic_set(&cm_core->events_posted, 0);23702371cm_core->api = &nes_cm_api;23722373spin_lock_init(&cm_core->ht_lock);2374spin_lock_init(&cm_core->listen_list_lock);23752376INIT_LIST_HEAD(&cm_core->listen_list.list);23772378nes_debug(NES_DBG_CM, "Init CM Core completed -- cm_core=%p\n", cm_core);23792380nes_debug(NES_DBG_CM, "Enable QUEUE EVENTS\n");2381cm_core->event_wq = create_singlethread_workqueue("nesewq");2382cm_core->post_event = nes_cm_post_event;2383nes_debug(NES_DBG_CM, "Enable QUEUE DISCONNECTS\n");2384cm_core->disconn_wq = create_singlethread_workqueue("nesdwq");23852386print_core(cm_core);2387return cm_core;2388}238923902391/**2392* mini_cm_dealloc_core - deallocate a top level instance of a cm core2393*/2394static int mini_cm_dealloc_core(struct nes_cm_core *cm_core)2395{2396nes_debug(NES_DBG_CM, "De-Alloc CM Core (%p)\n", cm_core);23972398if (!cm_core)2399return -EINVAL;24002401barrier();24022403if (timer_pending(&cm_core->tcp_timer)) {2404del_timer(&cm_core->tcp_timer);2405}24062407destroy_workqueue(cm_core->event_wq);2408destroy_workqueue(cm_core->disconn_wq);2409nes_debug(NES_DBG_CM, "\n");2410kfree(cm_core);24112412return 0;2413}241424152416/**2417* mini_cm_get2418*/2419static int mini_cm_get(struct nes_cm_core *cm_core)2420{2421return cm_core->state;2422}242324242425/**2426* mini_cm_set2427*/2428static int mini_cm_set(struct nes_cm_core *cm_core, u32 type, u32 value)2429{2430int ret = 0;24312432switch (type) {2433case NES_CM_SET_PKT_SIZE:2434cm_core->mtu = value;2435break;2436case NES_CM_SET_FREE_PKT_Q_SIZE:2437cm_core->free_tx_pkt_max = value;2438break;2439default:2440/* unknown set option */2441ret = -EINVAL;2442}24432444return ret;2445}244624472448/**2449* nes_cm_init_tsa_conn setup HW; MPA frames must be2450* successfully exchanged when this is called2451*/2452static int nes_cm_init_tsa_conn(struct nes_qp *nesqp, struct nes_cm_node *cm_node)2453{2454int ret = 0;24552456if (!nesqp)2457return -EINVAL;24582459nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_IPV4 |2460NES_QPCONTEXT_MISC_NO_NAGLE | NES_QPCONTEXT_MISC_DO_NOT_FRAG |2461NES_QPCONTEXT_MISC_DROS);24622463if (cm_node->tcp_cntxt.snd_wscale || cm_node->tcp_cntxt.rcv_wscale)2464nesqp->nesqp_context->misc |= cpu_to_le32(NES_QPCONTEXT_MISC_WSCALE);24652466nesqp->nesqp_context->misc2 |= cpu_to_le32(64 << NES_QPCONTEXT_MISC2_TTL_SHIFT);24672468nesqp->nesqp_context->mss |= cpu_to_le32(((u32)cm_node->tcp_cntxt.mss) << 16);24692470nesqp->nesqp_context->tcp_state_flow_label |= cpu_to_le32(2471(u32)NES_QPCONTEXT_TCPSTATE_EST << NES_QPCONTEXT_TCPFLOW_TCP_STATE_SHIFT);24722473nesqp->nesqp_context->pd_index_wscale |= cpu_to_le32(2474(cm_node->tcp_cntxt.snd_wscale << NES_QPCONTEXT_PDWSCALE_SND_WSCALE_SHIFT) &2475NES_QPCONTEXT_PDWSCALE_SND_WSCALE_MASK);24762477nesqp->nesqp_context->pd_index_wscale |= cpu_to_le32(2478(cm_node->tcp_cntxt.rcv_wscale << NES_QPCONTEXT_PDWSCALE_RCV_WSCALE_SHIFT) &2479NES_QPCONTEXT_PDWSCALE_RCV_WSCALE_MASK);24802481nesqp->nesqp_context->keepalive = cpu_to_le32(0x80);2482nesqp->nesqp_context->ts_recent = 0;2483nesqp->nesqp_context->ts_age = 0;2484nesqp->nesqp_context->snd_nxt = cpu_to_le32(cm_node->tcp_cntxt.loc_seq_num);2485nesqp->nesqp_context->snd_wnd = cpu_to_le32(cm_node->tcp_cntxt.snd_wnd);2486nesqp->nesqp_context->rcv_nxt = cpu_to_le32(cm_node->tcp_cntxt.rcv_nxt);2487nesqp->nesqp_context->rcv_wnd = cpu_to_le32(cm_node->tcp_cntxt.rcv_wnd <<2488cm_node->tcp_cntxt.rcv_wscale);2489nesqp->nesqp_context->snd_max = cpu_to_le32(cm_node->tcp_cntxt.loc_seq_num);2490nesqp->nesqp_context->snd_una = cpu_to_le32(cm_node->tcp_cntxt.loc_seq_num);2491nesqp->nesqp_context->srtt = 0;2492nesqp->nesqp_context->rttvar = cpu_to_le32(0x6);2493nesqp->nesqp_context->ssthresh = cpu_to_le32(0x3FFFC000);2494nesqp->nesqp_context->cwnd = cpu_to_le32(2*cm_node->tcp_cntxt.mss);2495nesqp->nesqp_context->snd_wl1 = cpu_to_le32(cm_node->tcp_cntxt.rcv_nxt);2496nesqp->nesqp_context->snd_wl2 = cpu_to_le32(cm_node->tcp_cntxt.loc_seq_num);2497nesqp->nesqp_context->max_snd_wnd = cpu_to_le32(cm_node->tcp_cntxt.max_snd_wnd);24982499nes_debug(NES_DBG_CM, "QP%u: rcv_nxt = 0x%08X, snd_nxt = 0x%08X,"2500" Setting MSS to %u, PDWscale = 0x%08X, rcv_wnd = %u, context misc = 0x%08X.\n",2501nesqp->hwqp.qp_id, le32_to_cpu(nesqp->nesqp_context->rcv_nxt),2502le32_to_cpu(nesqp->nesqp_context->snd_nxt),2503cm_node->tcp_cntxt.mss, le32_to_cpu(nesqp->nesqp_context->pd_index_wscale),2504le32_to_cpu(nesqp->nesqp_context->rcv_wnd),2505le32_to_cpu(nesqp->nesqp_context->misc));2506nes_debug(NES_DBG_CM, " snd_wnd = 0x%08X.\n", le32_to_cpu(nesqp->nesqp_context->snd_wnd));2507nes_debug(NES_DBG_CM, " snd_cwnd = 0x%08X.\n", le32_to_cpu(nesqp->nesqp_context->cwnd));2508nes_debug(NES_DBG_CM, " max_swnd = 0x%08X.\n", le32_to_cpu(nesqp->nesqp_context->max_snd_wnd));25092510nes_debug(NES_DBG_CM, "Change cm_node state to TSA\n");2511cm_node->state = NES_CM_STATE_TSA;25122513return ret;2514}251525162517/**2518* nes_cm_disconn2519*/2520int nes_cm_disconn(struct nes_qp *nesqp)2521{2522struct disconn_work *work;25232524work = kzalloc(sizeof *work, GFP_ATOMIC);2525if (!work)2526return -ENOMEM; /* Timer will clean up */25272528nes_add_ref(&nesqp->ibqp);2529work->nesqp = nesqp;2530INIT_WORK(&work->work, nes_disconnect_worker);2531queue_work(g_cm_core->disconn_wq, &work->work);2532return 0;2533}253425352536/**2537* nes_disconnect_worker2538*/2539static void nes_disconnect_worker(struct work_struct *work)2540{2541struct disconn_work *dwork = container_of(work, struct disconn_work, work);2542struct nes_qp *nesqp = dwork->nesqp;25432544kfree(dwork);2545nes_debug(NES_DBG_CM, "processing AEQE id 0x%04X for QP%u.\n",2546nesqp->last_aeq, nesqp->hwqp.qp_id);2547nes_cm_disconn_true(nesqp);2548nes_rem_ref(&nesqp->ibqp);2549}255025512552/**2553* nes_cm_disconn_true2554*/2555static int nes_cm_disconn_true(struct nes_qp *nesqp)2556{2557unsigned long flags;2558int ret = 0;2559struct iw_cm_id *cm_id;2560struct iw_cm_event cm_event;2561struct nes_vnic *nesvnic;2562u16 last_ae;2563u8 original_hw_tcp_state;2564u8 original_ibqp_state;2565int disconn_status = 0;2566int issue_disconn = 0;2567int issue_close = 0;2568int issue_flush = 0;2569u32 flush_q = NES_CQP_FLUSH_RQ;2570struct ib_event ibevent;25712572if (!nesqp) {2573nes_debug(NES_DBG_CM, "disconnect_worker nesqp is NULL\n");2574return -1;2575}25762577spin_lock_irqsave(&nesqp->lock, flags);2578cm_id = nesqp->cm_id;2579/* make sure we havent already closed this connection */2580if (!cm_id) {2581nes_debug(NES_DBG_CM, "QP%u disconnect_worker cmid is NULL\n",2582nesqp->hwqp.qp_id);2583spin_unlock_irqrestore(&nesqp->lock, flags);2584return -1;2585}25862587nesvnic = to_nesvnic(nesqp->ibqp.device);2588nes_debug(NES_DBG_CM, "Disconnecting QP%u\n", nesqp->hwqp.qp_id);25892590original_hw_tcp_state = nesqp->hw_tcp_state;2591original_ibqp_state = nesqp->ibqp_state;2592last_ae = nesqp->last_aeq;25932594if (nesqp->term_flags) {2595issue_disconn = 1;2596issue_close = 1;2597nesqp->cm_id = NULL;2598if (nesqp->flush_issued == 0) {2599nesqp->flush_issued = 1;2600issue_flush = 1;2601}2602} else if ((original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) ||2603((original_ibqp_state == IB_QPS_RTS) &&2604(last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET))) {2605issue_disconn = 1;2606if (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET)2607disconn_status = -ECONNRESET;2608}26092610if (((original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSED) ||2611(original_hw_tcp_state == NES_AEQE_TCP_STATE_TIME_WAIT) ||2612(last_ae == NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) ||2613(last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET))) {2614issue_close = 1;2615nesqp->cm_id = NULL;2616if (nesqp->flush_issued == 0) {2617nesqp->flush_issued = 1;2618issue_flush = 1;2619}2620}26212622spin_unlock_irqrestore(&nesqp->lock, flags);26232624if ((issue_flush) && (nesqp->destroyed == 0)) {2625/* Flush the queue(s) */2626if (nesqp->hw_iwarp_state >= NES_AEQE_IWARP_STATE_TERMINATE)2627flush_q |= NES_CQP_FLUSH_SQ;2628flush_wqes(nesvnic->nesdev, nesqp, flush_q, 1);26292630if (nesqp->term_flags) {2631ibevent.device = nesqp->ibqp.device;2632ibevent.event = nesqp->terminate_eventtype;2633ibevent.element.qp = &nesqp->ibqp;2634nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);2635}2636}26372638if ((cm_id) && (cm_id->event_handler)) {2639if (issue_disconn) {2640atomic_inc(&cm_disconnects);2641cm_event.event = IW_CM_EVENT_DISCONNECT;2642cm_event.status = disconn_status;2643cm_event.local_addr = cm_id->local_addr;2644cm_event.remote_addr = cm_id->remote_addr;2645cm_event.private_data = NULL;2646cm_event.private_data_len = 0;26472648nes_debug(NES_DBG_CM, "Generating a CM Disconnect Event"2649" for QP%u, SQ Head = %u, SQ Tail = %u. "2650"cm_id = %p, refcount = %u.\n",2651nesqp->hwqp.qp_id, nesqp->hwqp.sq_head,2652nesqp->hwqp.sq_tail, cm_id,2653atomic_read(&nesqp->refcount));26542655ret = cm_id->event_handler(cm_id, &cm_event);2656if (ret)2657nes_debug(NES_DBG_CM, "OFA CM event_handler "2658"returned, ret=%d\n", ret);2659}26602661if (issue_close) {2662atomic_inc(&cm_closes);2663nes_disconnect(nesqp, 1);26642665cm_id->provider_data = nesqp;2666/* Send up the close complete event */2667cm_event.event = IW_CM_EVENT_CLOSE;2668cm_event.status = 0;2669cm_event.provider_data = cm_id->provider_data;2670cm_event.local_addr = cm_id->local_addr;2671cm_event.remote_addr = cm_id->remote_addr;2672cm_event.private_data = NULL;2673cm_event.private_data_len = 0;26742675ret = cm_id->event_handler(cm_id, &cm_event);2676if (ret) {2677nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret);2678}26792680cm_id->rem_ref(cm_id);2681}2682}26832684return 0;2685}268626872688/**2689* nes_disconnect2690*/2691static int nes_disconnect(struct nes_qp *nesqp, int abrupt)2692{2693int ret = 0;2694struct nes_vnic *nesvnic;2695struct nes_device *nesdev;2696struct nes_ib_device *nesibdev;26972698nesvnic = to_nesvnic(nesqp->ibqp.device);2699if (!nesvnic)2700return -EINVAL;27012702nesdev = nesvnic->nesdev;2703nesibdev = nesvnic->nesibdev;27042705nes_debug(NES_DBG_CM, "netdev refcnt = %u.\n",2706netdev_refcnt_read(nesvnic->netdev));27072708if (nesqp->active_conn) {27092710/* indicate this connection is NOT active */2711nesqp->active_conn = 0;2712} else {2713/* Need to free the Last Streaming Mode Message */2714if (nesqp->ietf_frame) {2715if (nesqp->lsmm_mr)2716nesibdev->ibdev.dereg_mr(nesqp->lsmm_mr);2717pci_free_consistent(nesdev->pcidev,2718nesqp->private_data_len+sizeof(struct ietf_mpa_frame),2719nesqp->ietf_frame, nesqp->ietf_frame_pbase);2720}2721}27222723/* close the CM node down if it is still active */2724if (nesqp->cm_node) {2725nes_debug(NES_DBG_CM, "Call close API\n");27262727g_cm_core->api->close(g_cm_core, nesqp->cm_node);2728}27292730return ret;2731}273227332734/**2735* nes_accept2736*/2737int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)2738{2739u64 u64temp;2740struct ib_qp *ibqp;2741struct nes_qp *nesqp;2742struct nes_vnic *nesvnic;2743struct nes_device *nesdev;2744struct nes_cm_node *cm_node;2745struct nes_adapter *adapter;2746struct ib_qp_attr attr;2747struct iw_cm_event cm_event;2748struct nes_hw_qp_wqe *wqe;2749struct nes_v4_quad nes_quad;2750u32 crc_value;2751int ret;2752int passive_state;2753struct nes_ib_device *nesibdev;2754struct ib_mr *ibmr = NULL;2755struct ib_phys_buf ibphysbuf;2756struct nes_pd *nespd;2757u64 tagged_offset;27582759ibqp = nes_get_qp(cm_id->device, conn_param->qpn);2760if (!ibqp)2761return -EINVAL;27622763/* get all our handles */2764nesqp = to_nesqp(ibqp);2765nesvnic = to_nesvnic(nesqp->ibqp.device);2766nesdev = nesvnic->nesdev;2767adapter = nesdev->nesadapter;27682769cm_node = (struct nes_cm_node *)cm_id->provider_data;2770nes_debug(NES_DBG_CM, "nes_accept: cm_node= %p nesvnic=%p, netdev=%p,"2771"%s\n", cm_node, nesvnic, nesvnic->netdev,2772nesvnic->netdev->name);27732774if (NES_CM_STATE_LISTENER_DESTROYED == cm_node->state) {2775if (cm_node->loopbackpartner)2776rem_ref_cm_node(cm_node->cm_core, cm_node->loopbackpartner);2777rem_ref_cm_node(cm_node->cm_core, cm_node);2778return -EINVAL;2779}27802781passive_state = atomic_add_return(1, &cm_node->passive_state);2782if (passive_state == NES_SEND_RESET_EVENT) {2783rem_ref_cm_node(cm_node->cm_core, cm_node);2784return -ECONNRESET;2785}27862787/* associate the node with the QP */2788nesqp->cm_node = (void *)cm_node;2789cm_node->nesqp = nesqp;27902791nes_debug(NES_DBG_CM, "QP%u, cm_node=%p, jiffies = %lu listener = %p\n",2792nesqp->hwqp.qp_id, cm_node, jiffies, cm_node->listener);2793atomic_inc(&cm_accepts);27942795nes_debug(NES_DBG_CM, "netdev refcnt = %u.\n",2796netdev_refcnt_read(nesvnic->netdev));27972798/* allocate the ietf frame and space for private data */2799nesqp->ietf_frame = pci_alloc_consistent(nesdev->pcidev,2800sizeof(struct ietf_mpa_frame) + conn_param->private_data_len,2801&nesqp->ietf_frame_pbase);28022803if (!nesqp->ietf_frame) {2804nes_debug(NES_DBG_CM, "Unable to allocate memory for private "2805"data\n");2806return -ENOMEM;2807}280828092810/* setup the MPA frame */2811nesqp->private_data_len = conn_param->private_data_len;2812memcpy(nesqp->ietf_frame->key, IEFT_MPA_KEY_REP, IETF_MPA_KEY_SIZE);28132814memcpy(nesqp->ietf_frame->priv_data, conn_param->private_data,2815conn_param->private_data_len);28162817nesqp->ietf_frame->priv_data_len =2818cpu_to_be16(conn_param->private_data_len);2819nesqp->ietf_frame->rev = mpa_version;2820nesqp->ietf_frame->flags = IETF_MPA_FLAGS_CRC;28212822/* setup our first outgoing iWarp send WQE (the IETF frame response) */2823wqe = &nesqp->hwqp.sq_vbase[0];28242825if (cm_id->remote_addr.sin_addr.s_addr !=2826cm_id->local_addr.sin_addr.s_addr) {2827u64temp = (unsigned long)nesqp;2828nesibdev = nesvnic->nesibdev;2829nespd = nesqp->nespd;2830ibphysbuf.addr = nesqp->ietf_frame_pbase;2831ibphysbuf.size = conn_param->private_data_len +2832sizeof(struct ietf_mpa_frame);2833tagged_offset = (u64)(unsigned long)nesqp->ietf_frame;2834ibmr = nesibdev->ibdev.reg_phys_mr((struct ib_pd *)nespd,2835&ibphysbuf, 1,2836IB_ACCESS_LOCAL_WRITE,2837&tagged_offset);2838if (!ibmr) {2839nes_debug(NES_DBG_CM, "Unable to register memory region"2840"for lSMM for cm_node = %p \n",2841cm_node);2842pci_free_consistent(nesdev->pcidev,2843nesqp->private_data_len+sizeof(struct ietf_mpa_frame),2844nesqp->ietf_frame, nesqp->ietf_frame_pbase);2845return -ENOMEM;2846}28472848ibmr->pd = &nespd->ibpd;2849ibmr->device = nespd->ibpd.device;2850nesqp->lsmm_mr = ibmr;28512852u64temp |= NES_SW_CONTEXT_ALIGN>>1;2853set_wqe_64bit_value(wqe->wqe_words,2854NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX,2855u64temp);2856wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] =2857cpu_to_le32(NES_IWARP_SQ_WQE_STREAMING |2858NES_IWARP_SQ_WQE_WRPDU);2859wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] =2860cpu_to_le32(conn_param->private_data_len +2861sizeof(struct ietf_mpa_frame));2862set_wqe_64bit_value(wqe->wqe_words,2863NES_IWARP_SQ_WQE_FRAG0_LOW_IDX,2864(u64)(unsigned long)nesqp->ietf_frame);2865wqe->wqe_words[NES_IWARP_SQ_WQE_LENGTH0_IDX] =2866cpu_to_le32(conn_param->private_data_len +2867sizeof(struct ietf_mpa_frame));2868wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = ibmr->lkey;2869if (nesqp->sq_kmapped) {2870nesqp->sq_kmapped = 0;2871kunmap(nesqp->page);2872}28732874nesqp->nesqp_context->ird_ord_sizes |=2875cpu_to_le32(NES_QPCONTEXT_ORDIRD_LSMM_PRESENT |2876NES_QPCONTEXT_ORDIRD_WRPDU);2877} else {2878nesqp->nesqp_context->ird_ord_sizes |=2879cpu_to_le32(NES_QPCONTEXT_ORDIRD_WRPDU);2880}2881nesqp->skip_lsmm = 1;288228832884/* Cache the cm_id in the qp */2885nesqp->cm_id = cm_id;2886cm_node->cm_id = cm_id;28872888/* nesqp->cm_node = (void *)cm_id->provider_data; */2889cm_id->provider_data = nesqp;2890nesqp->active_conn = 0;28912892if (cm_node->state == NES_CM_STATE_TSA)2893nes_debug(NES_DBG_CM, "Already state = TSA for cm_node=%p\n",2894cm_node);28952896nes_cm_init_tsa_conn(nesqp, cm_node);28972898nesqp->nesqp_context->tcpPorts[0] =2899cpu_to_le16(ntohs(cm_id->local_addr.sin_port));2900nesqp->nesqp_context->tcpPorts[1] =2901cpu_to_le16(ntohs(cm_id->remote_addr.sin_port));29022903if (ipv4_is_loopback(cm_id->remote_addr.sin_addr.s_addr))2904nesqp->nesqp_context->ip0 =2905cpu_to_le32(ntohl(nesvnic->local_ipaddr));2906else2907nesqp->nesqp_context->ip0 =2908cpu_to_le32(ntohl(cm_id->remote_addr.sin_addr.s_addr));29092910nesqp->nesqp_context->misc2 |= cpu_to_le32(2911(u32)PCI_FUNC(nesdev->pcidev->devfn) <<2912NES_QPCONTEXT_MISC2_SRC_IP_SHIFT);29132914nesqp->nesqp_context->arp_index_vlan |=2915cpu_to_le32(nes_arp_table(nesdev,2916le32_to_cpu(nesqp->nesqp_context->ip0), NULL,2917NES_ARP_RESOLVE) << 16);29182919nesqp->nesqp_context->ts_val_delta = cpu_to_le32(2920jiffies - nes_read_indexed(nesdev, NES_IDX_TCP_NOW));29212922nesqp->nesqp_context->ird_index = cpu_to_le32(nesqp->hwqp.qp_id);29232924nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32(2925((u32)1 << NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT));2926nesqp->nesqp_context->ird_ord_sizes |=2927cpu_to_le32((u32)conn_param->ord);29282929memset(&nes_quad, 0, sizeof(nes_quad));2930nes_quad.DstIpAdrIndex =2931cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24);2932if (ipv4_is_loopback(cm_id->remote_addr.sin_addr.s_addr))2933nes_quad.SrcIpadr = nesvnic->local_ipaddr;2934else2935nes_quad.SrcIpadr = cm_id->remote_addr.sin_addr.s_addr;2936nes_quad.TcpPorts[0] = cm_id->remote_addr.sin_port;2937nes_quad.TcpPorts[1] = cm_id->local_addr.sin_port;29382939/* Produce hash key */2940crc_value = get_crc_value(&nes_quad);2941nesqp->hte_index = cpu_to_be32(crc_value ^ 0xffffffff);2942nes_debug(NES_DBG_CM, "HTE Index = 0x%08X, CRC = 0x%08X\n",2943nesqp->hte_index, nesqp->hte_index & adapter->hte_index_mask);29442945nesqp->hte_index &= adapter->hte_index_mask;2946nesqp->nesqp_context->hte_index = cpu_to_le32(nesqp->hte_index);29472948cm_node->cm_core->api->accelerated(cm_node->cm_core, cm_node);29492950nes_debug(NES_DBG_CM, "QP%u, Destination IP = 0x%08X:0x%04X, local = "2951"0x%08X:0x%04X, rcv_nxt=0x%08X, snd_nxt=0x%08X, mpa + "2952"private data length=%zu.\n", nesqp->hwqp.qp_id,2953ntohl(cm_id->remote_addr.sin_addr.s_addr),2954ntohs(cm_id->remote_addr.sin_port),2955ntohl(cm_id->local_addr.sin_addr.s_addr),2956ntohs(cm_id->local_addr.sin_port),2957le32_to_cpu(nesqp->nesqp_context->rcv_nxt),2958le32_to_cpu(nesqp->nesqp_context->snd_nxt),2959conn_param->private_data_len +2960sizeof(struct ietf_mpa_frame));296129622963/* notify OF layer that accept event was successful */2964cm_id->add_ref(cm_id);2965nes_add_ref(&nesqp->ibqp);29662967cm_event.event = IW_CM_EVENT_ESTABLISHED;2968cm_event.status = 0;2969cm_event.provider_data = (void *)nesqp;2970cm_event.local_addr = cm_id->local_addr;2971cm_event.remote_addr = cm_id->remote_addr;2972cm_event.private_data = NULL;2973cm_event.private_data_len = 0;2974ret = cm_id->event_handler(cm_id, &cm_event);2975attr.qp_state = IB_QPS_RTS;2976nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL);2977if (cm_node->loopbackpartner) {2978cm_node->loopbackpartner->mpa_frame_size =2979nesqp->private_data_len;2980/* copy entire MPA frame to our cm_node's frame */2981memcpy(cm_node->loopbackpartner->mpa_frame_buf,2982nesqp->ietf_frame->priv_data, nesqp->private_data_len);2983create_event(cm_node->loopbackpartner, NES_CM_EVENT_CONNECTED);2984}2985if (ret)2986printk(KERN_ERR "%s[%u] OFA CM event_handler returned, "2987"ret=%d\n", __func__, __LINE__, ret);29882989return 0;2990}299129922993/**2994* nes_reject2995*/2996int nes_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)2997{2998struct nes_cm_node *cm_node;2999struct nes_cm_node *loopback;30003001struct nes_cm_core *cm_core;30023003atomic_inc(&cm_rejects);3004cm_node = (struct nes_cm_node *) cm_id->provider_data;3005loopback = cm_node->loopbackpartner;3006cm_core = cm_node->cm_core;3007cm_node->cm_id = cm_id;3008cm_node->mpa_frame_size = sizeof(struct ietf_mpa_frame) + pdata_len;30093010if (cm_node->mpa_frame_size > MAX_CM_BUFFER)3011return -EINVAL;30123013memcpy(&cm_node->mpa_frame.key[0], IEFT_MPA_KEY_REP, IETF_MPA_KEY_SIZE);3014if (loopback) {3015memcpy(&loopback->mpa_frame.priv_data, pdata, pdata_len);3016loopback->mpa_frame.priv_data_len = pdata_len;3017loopback->mpa_frame_size = sizeof(struct ietf_mpa_frame) +3018pdata_len;3019} else {3020memcpy(&cm_node->mpa_frame.priv_data, pdata, pdata_len);3021cm_node->mpa_frame.priv_data_len = cpu_to_be16(pdata_len);3022}30233024cm_node->mpa_frame.rev = mpa_version;3025cm_node->mpa_frame.flags = IETF_MPA_FLAGS_CRC | IETF_MPA_FLAGS_REJECT;30263027return cm_core->api->reject(cm_core, &cm_node->mpa_frame, cm_node);3028}302930303031/**3032* nes_connect3033* setup and launch cm connect node3034*/3035int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)3036{3037struct ib_qp *ibqp;3038struct nes_qp *nesqp;3039struct nes_vnic *nesvnic;3040struct nes_device *nesdev;3041struct nes_cm_node *cm_node;3042struct nes_cm_info cm_info;3043int apbvt_set = 0;30443045ibqp = nes_get_qp(cm_id->device, conn_param->qpn);3046if (!ibqp)3047return -EINVAL;3048nesqp = to_nesqp(ibqp);3049if (!nesqp)3050return -EINVAL;3051nesvnic = to_nesvnic(nesqp->ibqp.device);3052if (!nesvnic)3053return -EINVAL;3054nesdev = nesvnic->nesdev;3055if (!nesdev)3056return -EINVAL;30573058if (!(cm_id->local_addr.sin_port) || !(cm_id->remote_addr.sin_port))3059return -EINVAL;30603061nes_debug(NES_DBG_CM, "QP%u, current IP = 0x%08X, Destination IP = "3062"0x%08X:0x%04X, local = 0x%08X:0x%04X.\n", nesqp->hwqp.qp_id,3063ntohl(nesvnic->local_ipaddr),3064ntohl(cm_id->remote_addr.sin_addr.s_addr),3065ntohs(cm_id->remote_addr.sin_port),3066ntohl(cm_id->local_addr.sin_addr.s_addr),3067ntohs(cm_id->local_addr.sin_port));30683069atomic_inc(&cm_connects);3070nesqp->active_conn = 1;30713072/* cache the cm_id in the qp */3073nesqp->cm_id = cm_id;30743075cm_id->provider_data = nesqp;30763077nesqp->private_data_len = conn_param->private_data_len;3078nesqp->nesqp_context->ird_ord_sizes |= cpu_to_le32((u32)conn_param->ord);3079nes_debug(NES_DBG_CM, "requested ord = 0x%08X.\n", (u32)conn_param->ord);3080nes_debug(NES_DBG_CM, "mpa private data len =%u\n",3081conn_param->private_data_len);30823083if (cm_id->local_addr.sin_addr.s_addr !=3084cm_id->remote_addr.sin_addr.s_addr) {3085nes_manage_apbvt(nesvnic, ntohs(cm_id->local_addr.sin_port),3086PCI_FUNC(nesdev->pcidev->devfn), NES_MANAGE_APBVT_ADD);3087apbvt_set = 1;3088}30893090/* set up the connection params for the node */3091cm_info.loc_addr = htonl(cm_id->local_addr.sin_addr.s_addr);3092cm_info.loc_port = htons(cm_id->local_addr.sin_port);3093cm_info.rem_addr = htonl(cm_id->remote_addr.sin_addr.s_addr);3094cm_info.rem_port = htons(cm_id->remote_addr.sin_port);3095cm_info.cm_id = cm_id;3096cm_info.conn_type = NES_CM_IWARP_CONN_TYPE;30973098cm_id->add_ref(cm_id);30993100/* create a connect CM node connection */3101cm_node = g_cm_core->api->connect(g_cm_core, nesvnic,3102conn_param->private_data_len, (void *)conn_param->private_data,3103&cm_info);3104if (!cm_node) {3105if (apbvt_set)3106nes_manage_apbvt(nesvnic, ntohs(cm_id->local_addr.sin_port),3107PCI_FUNC(nesdev->pcidev->devfn),3108NES_MANAGE_APBVT_DEL);31093110cm_id->rem_ref(cm_id);3111return -ENOMEM;3112}31133114cm_node->apbvt_set = apbvt_set;3115nesqp->cm_node = cm_node;3116cm_node->nesqp = nesqp;3117nes_add_ref(&nesqp->ibqp);31183119return 0;3120}312131223123/**3124* nes_create_listen3125*/3126int nes_create_listen(struct iw_cm_id *cm_id, int backlog)3127{3128struct nes_vnic *nesvnic;3129struct nes_cm_listener *cm_node;3130struct nes_cm_info cm_info;3131int err;31323133nes_debug(NES_DBG_CM, "cm_id = %p, local port = 0x%04X.\n",3134cm_id, ntohs(cm_id->local_addr.sin_port));31353136nesvnic = to_nesvnic(cm_id->device);3137if (!nesvnic)3138return -EINVAL;31393140nes_debug(NES_DBG_CM, "nesvnic=%p, netdev=%p, %s\n",3141nesvnic, nesvnic->netdev, nesvnic->netdev->name);31423143nes_debug(NES_DBG_CM, "nesvnic->local_ipaddr=0x%08x, sin_addr.s_addr=0x%08x\n",3144nesvnic->local_ipaddr, cm_id->local_addr.sin_addr.s_addr);31453146/* setup listen params in our api call struct */3147cm_info.loc_addr = nesvnic->local_ipaddr;3148cm_info.loc_port = cm_id->local_addr.sin_port;3149cm_info.backlog = backlog;3150cm_info.cm_id = cm_id;31513152cm_info.conn_type = NES_CM_IWARP_CONN_TYPE;315331543155cm_node = g_cm_core->api->listen(g_cm_core, nesvnic, &cm_info);3156if (!cm_node) {3157printk(KERN_ERR "%s[%u] Error returned from listen API call\n",3158__func__, __LINE__);3159return -ENOMEM;3160}31613162cm_id->provider_data = cm_node;31633164if (!cm_node->reused_node) {3165err = nes_manage_apbvt(nesvnic,3166ntohs(cm_id->local_addr.sin_port),3167PCI_FUNC(nesvnic->nesdev->pcidev->devfn),3168NES_MANAGE_APBVT_ADD);3169if (err) {3170printk(KERN_ERR "nes_manage_apbvt call returned %d.\n",3171err);3172g_cm_core->api->stop_listener(g_cm_core, (void *)cm_node);3173return err;3174}3175atomic_inc(&cm_listens_created);3176}31773178cm_id->add_ref(cm_id);3179cm_id->provider_data = (void *)cm_node;318031813182return 0;3183}318431853186/**3187* nes_destroy_listen3188*/3189int nes_destroy_listen(struct iw_cm_id *cm_id)3190{3191if (cm_id->provider_data)3192g_cm_core->api->stop_listener(g_cm_core, cm_id->provider_data);3193else3194nes_debug(NES_DBG_CM, "cm_id->provider_data was NULL\n");31953196cm_id->rem_ref(cm_id);31973198return 0;3199}320032013202/**3203* nes_cm_recv3204*/3205int nes_cm_recv(struct sk_buff *skb, struct net_device *netdevice)3206{3207int rc = 0;3208cm_packets_received++;3209if ((g_cm_core) && (g_cm_core->api)) {3210rc = g_cm_core->api->recv_pkt(g_cm_core, netdev_priv(netdevice), skb);3211} else {3212nes_debug(NES_DBG_CM, "Unable to process packet for CM,"3213" cm is not setup properly.\n");3214}32153216return rc;3217}321832193220/**3221* nes_cm_start3222* Start and init a cm core module3223*/3224int nes_cm_start(void)3225{3226nes_debug(NES_DBG_CM, "\n");3227/* create the primary CM core, pass this handle to subsequent core inits */3228g_cm_core = nes_cm_alloc_core();3229if (g_cm_core) {3230return 0;3231} else {3232return -ENOMEM;3233}3234}323532363237/**3238* nes_cm_stop3239* stop and dealloc all cm core instances3240*/3241int nes_cm_stop(void)3242{3243g_cm_core->api->destroy_cm_core(g_cm_core);3244return 0;3245}324632473248/**3249* cm_event_connected3250* handle a connected event, setup QPs and HW3251*/3252static void cm_event_connected(struct nes_cm_event *event)3253{3254u64 u64temp;3255struct nes_qp *nesqp;3256struct nes_vnic *nesvnic;3257struct nes_device *nesdev;3258struct nes_cm_node *cm_node;3259struct nes_adapter *nesadapter;3260struct ib_qp_attr attr;3261struct iw_cm_id *cm_id;3262struct iw_cm_event cm_event;3263struct nes_hw_qp_wqe *wqe;3264struct nes_v4_quad nes_quad;3265u32 crc_value;3266int ret;32673268/* get all our handles */3269cm_node = event->cm_node;3270cm_id = cm_node->cm_id;3271nes_debug(NES_DBG_CM, "cm_event_connected - %p - cm_id = %p\n", cm_node, cm_id);3272nesqp = (struct nes_qp *)cm_id->provider_data;3273nesvnic = to_nesvnic(nesqp->ibqp.device);3274nesdev = nesvnic->nesdev;3275nesadapter = nesdev->nesadapter;32763277if (nesqp->destroyed) {3278return;3279}3280atomic_inc(&cm_connecteds);3281nes_debug(NES_DBG_CM, "QP%u attempting to connect to 0x%08X:0x%04X on"3282" local port 0x%04X. jiffies = %lu.\n",3283nesqp->hwqp.qp_id,3284ntohl(cm_id->remote_addr.sin_addr.s_addr),3285ntohs(cm_id->remote_addr.sin_port),3286ntohs(cm_id->local_addr.sin_port),3287jiffies);32883289nes_cm_init_tsa_conn(nesqp, cm_node);32903291/* set the QP tsa context */3292nesqp->nesqp_context->tcpPorts[0] =3293cpu_to_le16(ntohs(cm_id->local_addr.sin_port));3294nesqp->nesqp_context->tcpPorts[1] =3295cpu_to_le16(ntohs(cm_id->remote_addr.sin_port));3296if (ipv4_is_loopback(cm_id->remote_addr.sin_addr.s_addr))3297nesqp->nesqp_context->ip0 =3298cpu_to_le32(ntohl(nesvnic->local_ipaddr));3299else3300nesqp->nesqp_context->ip0 =3301cpu_to_le32(ntohl(cm_id->remote_addr.sin_addr.s_addr));33023303nesqp->nesqp_context->misc2 |= cpu_to_le32(3304(u32)PCI_FUNC(nesdev->pcidev->devfn) <<3305NES_QPCONTEXT_MISC2_SRC_IP_SHIFT);3306nesqp->nesqp_context->arp_index_vlan |= cpu_to_le32(3307nes_arp_table(nesdev,3308le32_to_cpu(nesqp->nesqp_context->ip0),3309NULL, NES_ARP_RESOLVE) << 16);3310nesqp->nesqp_context->ts_val_delta = cpu_to_le32(3311jiffies - nes_read_indexed(nesdev, NES_IDX_TCP_NOW));3312nesqp->nesqp_context->ird_index = cpu_to_le32(nesqp->hwqp.qp_id);3313nesqp->nesqp_context->ird_ord_sizes |=3314cpu_to_le32((u32)1 <<3315NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT);33163317/* Adjust tail for not having a LSMM */3318nesqp->hwqp.sq_tail = 1;33193320#if defined(NES_SEND_FIRST_WRITE)3321if (cm_node->send_write0) {3322nes_debug(NES_DBG_CM, "Sending first write.\n");3323wqe = &nesqp->hwqp.sq_vbase[0];3324u64temp = (unsigned long)nesqp;3325u64temp |= NES_SW_CONTEXT_ALIGN>>1;3326set_wqe_64bit_value(wqe->wqe_words,3327NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX, u64temp);3328wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] =3329cpu_to_le32(NES_IWARP_SQ_OP_RDMAW);3330wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] = 0;3331wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_LOW_IDX] = 0;3332wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_HIGH_IDX] = 0;3333wqe->wqe_words[NES_IWARP_SQ_WQE_LENGTH0_IDX] = 0;3334wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = 0;33353336if (nesqp->sq_kmapped) {3337nesqp->sq_kmapped = 0;3338kunmap(nesqp->page);3339}33403341/* use the reserved spot on the WQ for the extra first WQE */3342nesqp->nesqp_context->ird_ord_sizes &=3343cpu_to_le32(~(NES_QPCONTEXT_ORDIRD_LSMM_PRESENT |3344NES_QPCONTEXT_ORDIRD_WRPDU |3345NES_QPCONTEXT_ORDIRD_ALSMM));3346nesqp->skip_lsmm = 1;3347nesqp->hwqp.sq_tail = 0;3348nes_write32(nesdev->regs + NES_WQE_ALLOC,3349(1 << 24) | 0x00800000 | nesqp->hwqp.qp_id);3350}3351#endif33523353memset(&nes_quad, 0, sizeof(nes_quad));33543355nes_quad.DstIpAdrIndex =3356cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24);3357if (ipv4_is_loopback(cm_id->remote_addr.sin_addr.s_addr))3358nes_quad.SrcIpadr = nesvnic->local_ipaddr;3359else3360nes_quad.SrcIpadr = cm_id->remote_addr.sin_addr.s_addr;3361nes_quad.TcpPorts[0] = cm_id->remote_addr.sin_port;3362nes_quad.TcpPorts[1] = cm_id->local_addr.sin_port;33633364/* Produce hash key */3365crc_value = get_crc_value(&nes_quad);3366nesqp->hte_index = cpu_to_be32(crc_value ^ 0xffffffff);3367nes_debug(NES_DBG_CM, "HTE Index = 0x%08X, After CRC = 0x%08X\n",3368nesqp->hte_index, nesqp->hte_index & nesadapter->hte_index_mask);33693370nesqp->hte_index &= nesadapter->hte_index_mask;3371nesqp->nesqp_context->hte_index = cpu_to_le32(nesqp->hte_index);33723373nesqp->ietf_frame = &cm_node->mpa_frame;3374nesqp->private_data_len = (u8) cm_node->mpa_frame_size;3375cm_node->cm_core->api->accelerated(cm_node->cm_core, cm_node);33763377/* notify OF layer we successfully created the requested connection */3378cm_event.event = IW_CM_EVENT_CONNECT_REPLY;3379cm_event.status = 0;3380cm_event.provider_data = cm_id->provider_data;3381cm_event.local_addr.sin_family = AF_INET;3382cm_event.local_addr.sin_port = cm_id->local_addr.sin_port;3383cm_event.remote_addr = cm_id->remote_addr;33843385cm_event.private_data = (void *)event->cm_node->mpa_frame_buf;3386cm_event.private_data_len = (u8) event->cm_node->mpa_frame_size;33873388cm_event.local_addr.sin_addr.s_addr = event->cm_info.rem_addr;3389ret = cm_id->event_handler(cm_id, &cm_event);3390nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret);33913392if (ret)3393printk(KERN_ERR "%s[%u] OFA CM event_handler returned, "3394"ret=%d\n", __func__, __LINE__, ret);3395attr.qp_state = IB_QPS_RTS;3396nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL);33973398nes_debug(NES_DBG_CM, "Exiting connect thread for QP%u. jiffies = "3399"%lu\n", nesqp->hwqp.qp_id, jiffies);34003401return;3402}340334043405/**3406* cm_event_connect_error3407*/3408static void cm_event_connect_error(struct nes_cm_event *event)3409{3410struct nes_qp *nesqp;3411struct iw_cm_id *cm_id;3412struct iw_cm_event cm_event;3413/* struct nes_cm_info cm_info; */3414int ret;34153416if (!event->cm_node)3417return;34183419cm_id = event->cm_node->cm_id;3420if (!cm_id) {3421return;3422}34233424nes_debug(NES_DBG_CM, "cm_node=%p, cm_id=%p\n", event->cm_node, cm_id);3425nesqp = cm_id->provider_data;34263427if (!nesqp) {3428return;3429}34303431/* notify OF layer about this connection error event */3432/* cm_id->rem_ref(cm_id); */3433nesqp->cm_id = NULL;3434cm_id->provider_data = NULL;3435cm_event.event = IW_CM_EVENT_CONNECT_REPLY;3436cm_event.status = -ECONNRESET;3437cm_event.provider_data = cm_id->provider_data;3438cm_event.local_addr = cm_id->local_addr;3439cm_event.remote_addr = cm_id->remote_addr;3440cm_event.private_data = NULL;3441cm_event.private_data_len = 0;34423443nes_debug(NES_DBG_CM, "call CM_EVENT REJECTED, local_addr=%08x, "3444"remove_addr=%08x\n", cm_event.local_addr.sin_addr.s_addr,3445cm_event.remote_addr.sin_addr.s_addr);34463447ret = cm_id->event_handler(cm_id, &cm_event);3448nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret);3449if (ret)3450printk(KERN_ERR "%s[%u] OFA CM event_handler returned, "3451"ret=%d\n", __func__, __LINE__, ret);3452cm_id->rem_ref(cm_id);34533454rem_ref_cm_node(event->cm_node->cm_core, event->cm_node);3455return;3456}345734583459/**3460* cm_event_reset3461*/3462static void cm_event_reset(struct nes_cm_event *event)3463{3464struct nes_qp *nesqp;3465struct iw_cm_id *cm_id;3466struct iw_cm_event cm_event;3467/* struct nes_cm_info cm_info; */3468int ret;34693470if (!event->cm_node)3471return;34723473if (!event->cm_node->cm_id)3474return;34753476cm_id = event->cm_node->cm_id;34773478nes_debug(NES_DBG_CM, "%p - cm_id = %p\n", event->cm_node, cm_id);3479nesqp = cm_id->provider_data;3480if (!nesqp)3481return;34823483nesqp->cm_id = NULL;3484/* cm_id->provider_data = NULL; */3485cm_event.event = IW_CM_EVENT_DISCONNECT;3486cm_event.status = -ECONNRESET;3487cm_event.provider_data = cm_id->provider_data;3488cm_event.local_addr = cm_id->local_addr;3489cm_event.remote_addr = cm_id->remote_addr;3490cm_event.private_data = NULL;3491cm_event.private_data_len = 0;34923493cm_id->add_ref(cm_id);3494ret = cm_id->event_handler(cm_id, &cm_event);3495atomic_inc(&cm_closes);3496cm_event.event = IW_CM_EVENT_CLOSE;3497cm_event.status = 0;3498cm_event.provider_data = cm_id->provider_data;3499cm_event.local_addr = cm_id->local_addr;3500cm_event.remote_addr = cm_id->remote_addr;3501cm_event.private_data = NULL;3502cm_event.private_data_len = 0;3503nes_debug(NES_DBG_CM, "NODE %p Generating CLOSE\n", event->cm_node);3504ret = cm_id->event_handler(cm_id, &cm_event);35053506nes_debug(NES_DBG_CM, "OFA CM event_handler returned, ret=%d\n", ret);350735083509/* notify OF layer about this connection error event */3510cm_id->rem_ref(cm_id);35113512return;3513}351435153516/**3517* cm_event_mpa_req3518*/3519static void cm_event_mpa_req(struct nes_cm_event *event)3520{3521struct iw_cm_id *cm_id;3522struct iw_cm_event cm_event;3523int ret;3524struct nes_cm_node *cm_node;35253526cm_node = event->cm_node;3527if (!cm_node)3528return;3529cm_id = cm_node->cm_id;35303531atomic_inc(&cm_connect_reqs);3532nes_debug(NES_DBG_CM, "cm_node = %p - cm_id = %p, jiffies = %lu\n",3533cm_node, cm_id, jiffies);35343535cm_event.event = IW_CM_EVENT_CONNECT_REQUEST;3536cm_event.status = 0;3537cm_event.provider_data = (void *)cm_node;35383539cm_event.local_addr.sin_family = AF_INET;3540cm_event.local_addr.sin_port = htons(event->cm_info.loc_port);3541cm_event.local_addr.sin_addr.s_addr = htonl(event->cm_info.loc_addr);35423543cm_event.remote_addr.sin_family = AF_INET;3544cm_event.remote_addr.sin_port = htons(event->cm_info.rem_port);3545cm_event.remote_addr.sin_addr.s_addr = htonl(event->cm_info.rem_addr);3546cm_event.private_data = cm_node->mpa_frame_buf;3547cm_event.private_data_len = (u8) cm_node->mpa_frame_size;35483549ret = cm_id->event_handler(cm_id, &cm_event);3550if (ret)3551printk(KERN_ERR "%s[%u] OFA CM event_handler returned, ret=%d\n",3552__func__, __LINE__, ret);3553return;3554}355535563557static void cm_event_mpa_reject(struct nes_cm_event *event)3558{3559struct iw_cm_id *cm_id;3560struct iw_cm_event cm_event;3561struct nes_cm_node *cm_node;3562int ret;35633564cm_node = event->cm_node;3565if (!cm_node)3566return;3567cm_id = cm_node->cm_id;35683569atomic_inc(&cm_connect_reqs);3570nes_debug(NES_DBG_CM, "cm_node = %p - cm_id = %p, jiffies = %lu\n",3571cm_node, cm_id, jiffies);35723573cm_event.event = IW_CM_EVENT_CONNECT_REPLY;3574cm_event.status = -ECONNREFUSED;3575cm_event.provider_data = cm_id->provider_data;35763577cm_event.local_addr.sin_family = AF_INET;3578cm_event.local_addr.sin_port = htons(event->cm_info.loc_port);3579cm_event.local_addr.sin_addr.s_addr = htonl(event->cm_info.loc_addr);35803581cm_event.remote_addr.sin_family = AF_INET;3582cm_event.remote_addr.sin_port = htons(event->cm_info.rem_port);3583cm_event.remote_addr.sin_addr.s_addr = htonl(event->cm_info.rem_addr);35843585cm_event.private_data = cm_node->mpa_frame_buf;3586cm_event.private_data_len = (u8) cm_node->mpa_frame_size;35873588nes_debug(NES_DBG_CM, "call CM_EVENT_MPA_REJECTED, local_addr=%08x, "3589"remove_addr=%08x\n",3590cm_event.local_addr.sin_addr.s_addr,3591cm_event.remote_addr.sin_addr.s_addr);35923593ret = cm_id->event_handler(cm_id, &cm_event);3594if (ret)3595printk(KERN_ERR "%s[%u] OFA CM event_handler returned, ret=%d\n",3596__func__, __LINE__, ret);35973598return;3599}360036013602static void nes_cm_event_handler(struct work_struct *);36033604/**3605* nes_cm_post_event3606* post an event to the cm event handler3607*/3608static int nes_cm_post_event(struct nes_cm_event *event)3609{3610atomic_inc(&event->cm_node->cm_core->events_posted);3611add_ref_cm_node(event->cm_node);3612event->cm_info.cm_id->add_ref(event->cm_info.cm_id);3613INIT_WORK(&event->event_work, nes_cm_event_handler);3614nes_debug(NES_DBG_CM, "cm_node=%p queue_work, event=%p\n",3615event->cm_node, event);36163617queue_work(event->cm_node->cm_core->event_wq, &event->event_work);36183619nes_debug(NES_DBG_CM, "Exit\n");3620return 0;3621}362236233624/**3625* nes_cm_event_handler3626* worker function to handle cm events3627* will free instance of nes_cm_event3628*/3629static void nes_cm_event_handler(struct work_struct *work)3630{3631struct nes_cm_event *event = container_of(work, struct nes_cm_event,3632event_work);3633struct nes_cm_core *cm_core;36343635if ((!event) || (!event->cm_node) || (!event->cm_node->cm_core))3636return;36373638cm_core = event->cm_node->cm_core;3639nes_debug(NES_DBG_CM, "event=%p, event->type=%u, events posted=%u\n",3640event, event->type, atomic_read(&cm_core->events_posted));36413642switch (event->type) {3643case NES_CM_EVENT_MPA_REQ:3644cm_event_mpa_req(event);3645nes_debug(NES_DBG_CM, "cm_node=%p CM Event: MPA REQUEST\n",3646event->cm_node);3647break;3648case NES_CM_EVENT_RESET:3649nes_debug(NES_DBG_CM, "cm_node = %p CM Event: RESET\n",3650event->cm_node);3651cm_event_reset(event);3652break;3653case NES_CM_EVENT_CONNECTED:3654if ((!event->cm_node->cm_id) ||3655(event->cm_node->state != NES_CM_STATE_TSA))3656break;3657cm_event_connected(event);3658nes_debug(NES_DBG_CM, "CM Event: CONNECTED\n");3659break;3660case NES_CM_EVENT_MPA_REJECT:3661if ((!event->cm_node->cm_id) ||3662(event->cm_node->state == NES_CM_STATE_TSA))3663break;3664cm_event_mpa_reject(event);3665nes_debug(NES_DBG_CM, "CM Event: REJECT\n");3666break;36673668case NES_CM_EVENT_ABORTED:3669if ((!event->cm_node->cm_id) ||3670(event->cm_node->state == NES_CM_STATE_TSA))3671break;3672cm_event_connect_error(event);3673nes_debug(NES_DBG_CM, "CM Event: ABORTED\n");3674break;3675case NES_CM_EVENT_DROPPED_PKT:3676nes_debug(NES_DBG_CM, "CM Event: DROPPED PKT\n");3677break;3678default:3679nes_debug(NES_DBG_CM, "CM Event: UNKNOWN EVENT TYPE\n");3680break;3681}36823683atomic_dec(&cm_core->events_posted);3684event->cm_info.cm_id->rem_ref(event->cm_info.cm_id);3685rem_ref_cm_node(cm_core, event->cm_node);3686kfree(event);36873688return;3689}369036913692