162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (c) 2006-2008 Chelsio, Inc. All rights reserved.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * This software is available to you under a choice of one of two
562306a36Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
662306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
762306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the
862306a36Sopenharmony_ci * OpenIB.org BSD license below:
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
1162306a36Sopenharmony_ci *     without modification, are permitted provided that the following
1262306a36Sopenharmony_ci *     conditions are met:
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci *      - Redistributions of source code must retain the above
1562306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
1662306a36Sopenharmony_ci *        disclaimer.
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
1962306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
2062306a36Sopenharmony_ci *        disclaimer in the documentation and/or other materials
2162306a36Sopenharmony_ci *        provided with the distribution.
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2462306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2562306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2662306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2762306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
2862306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2962306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3062306a36Sopenharmony_ci * SOFTWARE.
3162306a36Sopenharmony_ci */
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#include <linux/list.h>
3662306a36Sopenharmony_ci#include <linux/slab.h>
3762306a36Sopenharmony_ci#include <net/neighbour.h>
3862306a36Sopenharmony_ci#include <linux/notifier.h>
3962306a36Sopenharmony_ci#include <linux/atomic.h>
4062306a36Sopenharmony_ci#include <linux/proc_fs.h>
4162306a36Sopenharmony_ci#include <linux/if_vlan.h>
4262306a36Sopenharmony_ci#include <net/netevent.h>
4362306a36Sopenharmony_ci#include <linux/highmem.h>
4462306a36Sopenharmony_ci#include <linux/vmalloc.h>
4562306a36Sopenharmony_ci#include <linux/export.h>
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#include "common.h"
4862306a36Sopenharmony_ci#include "regs.h"
4962306a36Sopenharmony_ci#include "cxgb3_ioctl.h"
5062306a36Sopenharmony_ci#include "cxgb3_ctl_defs.h"
5162306a36Sopenharmony_ci#include "cxgb3_defs.h"
5262306a36Sopenharmony_ci#include "l2t.h"
5362306a36Sopenharmony_ci#include "firmware_exports.h"
5462306a36Sopenharmony_ci#include "cxgb3_offload.h"
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic LIST_HEAD(client_list);
5762306a36Sopenharmony_cistatic LIST_HEAD(ofld_dev_list);
5862306a36Sopenharmony_cistatic DEFINE_MUTEX(cxgb3_db_lock);
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic DEFINE_RWLOCK(adapter_list_lock);
6162306a36Sopenharmony_cistatic LIST_HEAD(adapter_list);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic const unsigned int MAX_ATIDS = 64 * 1024;
6462306a36Sopenharmony_cistatic const unsigned int ATID_BASE = 0x10000;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistatic void cxgb_neigh_update(struct neighbour *neigh);
6762306a36Sopenharmony_cistatic void cxgb_redirect(struct dst_entry *old, struct dst_entry *new,
6862306a36Sopenharmony_ci			  struct neighbour *neigh, const void *daddr);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic inline int offload_activated(struct t3cdev *tdev)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	const struct adapter *adapter = tdev2adap(tdev);
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	return test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci/**
7862306a36Sopenharmony_ci *	cxgb3_register_client - register an offload client
7962306a36Sopenharmony_ci *	@client: the client
8062306a36Sopenharmony_ci *
8162306a36Sopenharmony_ci *	Add the client to the client list,
8262306a36Sopenharmony_ci *	and call backs the client for each activated offload device
8362306a36Sopenharmony_ci */
8462306a36Sopenharmony_civoid cxgb3_register_client(struct cxgb3_client *client)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	struct t3cdev *tdev;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	mutex_lock(&cxgb3_db_lock);
8962306a36Sopenharmony_ci	list_add_tail(&client->client_list, &client_list);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	if (client->add) {
9262306a36Sopenharmony_ci		list_for_each_entry(tdev, &ofld_dev_list, ofld_dev_list) {
9362306a36Sopenharmony_ci			if (offload_activated(tdev))
9462306a36Sopenharmony_ci				client->add(tdev);
9562306a36Sopenharmony_ci		}
9662306a36Sopenharmony_ci	}
9762306a36Sopenharmony_ci	mutex_unlock(&cxgb3_db_lock);
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb3_register_client);
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci/**
10362306a36Sopenharmony_ci *	cxgb3_unregister_client - unregister an offload client
10462306a36Sopenharmony_ci *	@client: the client
10562306a36Sopenharmony_ci *
10662306a36Sopenharmony_ci *	Remove the client to the client list,
10762306a36Sopenharmony_ci *	and call backs the client for each activated offload device.
10862306a36Sopenharmony_ci */
10962306a36Sopenharmony_civoid cxgb3_unregister_client(struct cxgb3_client *client)
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	struct t3cdev *tdev;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	mutex_lock(&cxgb3_db_lock);
11462306a36Sopenharmony_ci	list_del(&client->client_list);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	if (client->remove) {
11762306a36Sopenharmony_ci		list_for_each_entry(tdev, &ofld_dev_list, ofld_dev_list) {
11862306a36Sopenharmony_ci			if (offload_activated(tdev))
11962306a36Sopenharmony_ci				client->remove(tdev);
12062306a36Sopenharmony_ci		}
12162306a36Sopenharmony_ci	}
12262306a36Sopenharmony_ci	mutex_unlock(&cxgb3_db_lock);
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb3_unregister_client);
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci/**
12862306a36Sopenharmony_ci *	cxgb3_add_clients - activate registered clients for an offload device
12962306a36Sopenharmony_ci *	@tdev: the offload device
13062306a36Sopenharmony_ci *
13162306a36Sopenharmony_ci *	Call backs all registered clients once a offload device is activated
13262306a36Sopenharmony_ci */
13362306a36Sopenharmony_civoid cxgb3_add_clients(struct t3cdev *tdev)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	struct cxgb3_client *client;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	mutex_lock(&cxgb3_db_lock);
13862306a36Sopenharmony_ci	list_for_each_entry(client, &client_list, client_list) {
13962306a36Sopenharmony_ci		if (client->add)
14062306a36Sopenharmony_ci			client->add(tdev);
14162306a36Sopenharmony_ci	}
14262306a36Sopenharmony_ci	mutex_unlock(&cxgb3_db_lock);
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci/**
14662306a36Sopenharmony_ci *	cxgb3_remove_clients - deactivates registered clients
14762306a36Sopenharmony_ci *			       for an offload device
14862306a36Sopenharmony_ci *	@tdev: the offload device
14962306a36Sopenharmony_ci *
15062306a36Sopenharmony_ci *	Call backs all registered clients once a offload device is deactivated
15162306a36Sopenharmony_ci */
15262306a36Sopenharmony_civoid cxgb3_remove_clients(struct t3cdev *tdev)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	struct cxgb3_client *client;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	mutex_lock(&cxgb3_db_lock);
15762306a36Sopenharmony_ci	list_for_each_entry(client, &client_list, client_list) {
15862306a36Sopenharmony_ci		if (client->remove)
15962306a36Sopenharmony_ci			client->remove(tdev);
16062306a36Sopenharmony_ci	}
16162306a36Sopenharmony_ci	mutex_unlock(&cxgb3_db_lock);
16262306a36Sopenharmony_ci}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_civoid cxgb3_event_notify(struct t3cdev *tdev, u32 event, u32 port)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	struct cxgb3_client *client;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	mutex_lock(&cxgb3_db_lock);
16962306a36Sopenharmony_ci	list_for_each_entry(client, &client_list, client_list) {
17062306a36Sopenharmony_ci		if (client->event_handler)
17162306a36Sopenharmony_ci			client->event_handler(tdev, event, port);
17262306a36Sopenharmony_ci	}
17362306a36Sopenharmony_ci	mutex_unlock(&cxgb3_db_lock);
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic struct net_device *get_iff_from_mac(struct adapter *adapter,
17762306a36Sopenharmony_ci					   const unsigned char *mac,
17862306a36Sopenharmony_ci					   unsigned int vlan)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	int i;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	for_each_port(adapter, i) {
18362306a36Sopenharmony_ci		struct net_device *dev = adapter->port[i];
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci		if (ether_addr_equal(dev->dev_addr, mac)) {
18662306a36Sopenharmony_ci			rcu_read_lock();
18762306a36Sopenharmony_ci			if (vlan && vlan != VLAN_VID_MASK) {
18862306a36Sopenharmony_ci				dev = __vlan_find_dev_deep_rcu(dev, htons(ETH_P_8021Q), vlan);
18962306a36Sopenharmony_ci			} else if (netif_is_bond_slave(dev)) {
19062306a36Sopenharmony_ci				struct net_device *upper_dev;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci				while ((upper_dev =
19362306a36Sopenharmony_ci					netdev_master_upper_dev_get_rcu(dev)))
19462306a36Sopenharmony_ci					dev = upper_dev;
19562306a36Sopenharmony_ci			}
19662306a36Sopenharmony_ci			rcu_read_unlock();
19762306a36Sopenharmony_ci			return dev;
19862306a36Sopenharmony_ci		}
19962306a36Sopenharmony_ci	}
20062306a36Sopenharmony_ci	return NULL;
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_cistatic int cxgb_ulp_iscsi_ctl(struct adapter *adapter, unsigned int req,
20462306a36Sopenharmony_ci			      void *data)
20562306a36Sopenharmony_ci{
20662306a36Sopenharmony_ci	int i;
20762306a36Sopenharmony_ci	int ret = 0;
20862306a36Sopenharmony_ci	unsigned int val = 0;
20962306a36Sopenharmony_ci	struct ulp_iscsi_info *uiip = data;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	switch (req) {
21262306a36Sopenharmony_ci	case ULP_ISCSI_GET_PARAMS:
21362306a36Sopenharmony_ci		uiip->pdev = adapter->pdev;
21462306a36Sopenharmony_ci		uiip->llimit = t3_read_reg(adapter, A_ULPRX_ISCSI_LLIMIT);
21562306a36Sopenharmony_ci		uiip->ulimit = t3_read_reg(adapter, A_ULPRX_ISCSI_ULIMIT);
21662306a36Sopenharmony_ci		uiip->tagmask = t3_read_reg(adapter, A_ULPRX_ISCSI_TAGMASK);
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci		val = t3_read_reg(adapter, A_ULPRX_ISCSI_PSZ);
21962306a36Sopenharmony_ci		for (i = 0; i < 4; i++, val >>= 8)
22062306a36Sopenharmony_ci			uiip->pgsz_factor[i] = val & 0xFF;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci		val = t3_read_reg(adapter, A_TP_PARA_REG7);
22362306a36Sopenharmony_ci		uiip->max_txsz =
22462306a36Sopenharmony_ci		uiip->max_rxsz = min((val >> S_PMMAXXFERLEN0)&M_PMMAXXFERLEN0,
22562306a36Sopenharmony_ci				     (val >> S_PMMAXXFERLEN1)&M_PMMAXXFERLEN1);
22662306a36Sopenharmony_ci		/*
22762306a36Sopenharmony_ci		 * On tx, the iscsi pdu has to be <= tx page size and has to
22862306a36Sopenharmony_ci		 * fit into the Tx PM FIFO.
22962306a36Sopenharmony_ci		 */
23062306a36Sopenharmony_ci		val = min(adapter->params.tp.tx_pg_size,
23162306a36Sopenharmony_ci			  t3_read_reg(adapter, A_PM1_TX_CFG) >> 17);
23262306a36Sopenharmony_ci		uiip->max_txsz = min(val, uiip->max_txsz);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci		/* set MaxRxData to 16224 */
23562306a36Sopenharmony_ci		val = t3_read_reg(adapter, A_TP_PARA_REG2);
23662306a36Sopenharmony_ci		if ((val >> S_MAXRXDATA) != 0x3f60) {
23762306a36Sopenharmony_ci			val &= (M_RXCOALESCESIZE << S_RXCOALESCESIZE);
23862306a36Sopenharmony_ci			val |= V_MAXRXDATA(0x3f60);
23962306a36Sopenharmony_ci			pr_info("%s, iscsi set MaxRxData to 16224 (0x%x)\n",
24062306a36Sopenharmony_ci				adapter->name, val);
24162306a36Sopenharmony_ci			t3_write_reg(adapter, A_TP_PARA_REG2, val);
24262306a36Sopenharmony_ci		}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci		/*
24562306a36Sopenharmony_ci		 * on rx, the iscsi pdu has to be < rx page size and the
24662306a36Sopenharmony_ci		 * max rx data length programmed in TP
24762306a36Sopenharmony_ci		 */
24862306a36Sopenharmony_ci		val = min(adapter->params.tp.rx_pg_size,
24962306a36Sopenharmony_ci			  ((t3_read_reg(adapter, A_TP_PARA_REG2)) >>
25062306a36Sopenharmony_ci				S_MAXRXDATA) & M_MAXRXDATA);
25162306a36Sopenharmony_ci		uiip->max_rxsz = min(val, uiip->max_rxsz);
25262306a36Sopenharmony_ci		break;
25362306a36Sopenharmony_ci	case ULP_ISCSI_SET_PARAMS:
25462306a36Sopenharmony_ci		t3_write_reg(adapter, A_ULPRX_ISCSI_TAGMASK, uiip->tagmask);
25562306a36Sopenharmony_ci		/* program the ddp page sizes */
25662306a36Sopenharmony_ci		for (i = 0; i < 4; i++)
25762306a36Sopenharmony_ci			val |= (uiip->pgsz_factor[i] & 0xF) << (8 * i);
25862306a36Sopenharmony_ci		if (val && (val != t3_read_reg(adapter, A_ULPRX_ISCSI_PSZ))) {
25962306a36Sopenharmony_ci			pr_info("%s, setting iscsi pgsz 0x%x, %u,%u,%u,%u\n",
26062306a36Sopenharmony_ci				adapter->name, val, uiip->pgsz_factor[0],
26162306a36Sopenharmony_ci				uiip->pgsz_factor[1], uiip->pgsz_factor[2],
26262306a36Sopenharmony_ci				uiip->pgsz_factor[3]);
26362306a36Sopenharmony_ci			t3_write_reg(adapter, A_ULPRX_ISCSI_PSZ, val);
26462306a36Sopenharmony_ci		}
26562306a36Sopenharmony_ci		break;
26662306a36Sopenharmony_ci	default:
26762306a36Sopenharmony_ci		ret = -EOPNOTSUPP;
26862306a36Sopenharmony_ci	}
26962306a36Sopenharmony_ci	return ret;
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci/* Response queue used for RDMA events. */
27362306a36Sopenharmony_ci#define ASYNC_NOTIF_RSPQ 0
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_cistatic int cxgb_rdma_ctl(struct adapter *adapter, unsigned int req, void *data)
27662306a36Sopenharmony_ci{
27762306a36Sopenharmony_ci	int ret = 0;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	switch (req) {
28062306a36Sopenharmony_ci	case RDMA_GET_PARAMS: {
28162306a36Sopenharmony_ci		struct rdma_info *rdma = data;
28262306a36Sopenharmony_ci		struct pci_dev *pdev = adapter->pdev;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci		rdma->udbell_physbase = pci_resource_start(pdev, 2);
28562306a36Sopenharmony_ci		rdma->udbell_len = pci_resource_len(pdev, 2);
28662306a36Sopenharmony_ci		rdma->tpt_base =
28762306a36Sopenharmony_ci			t3_read_reg(adapter, A_ULPTX_TPT_LLIMIT);
28862306a36Sopenharmony_ci		rdma->tpt_top = t3_read_reg(adapter, A_ULPTX_TPT_ULIMIT);
28962306a36Sopenharmony_ci		rdma->pbl_base =
29062306a36Sopenharmony_ci			t3_read_reg(adapter, A_ULPTX_PBL_LLIMIT);
29162306a36Sopenharmony_ci		rdma->pbl_top = t3_read_reg(adapter, A_ULPTX_PBL_ULIMIT);
29262306a36Sopenharmony_ci		rdma->rqt_base = t3_read_reg(adapter, A_ULPRX_RQ_LLIMIT);
29362306a36Sopenharmony_ci		rdma->rqt_top = t3_read_reg(adapter, A_ULPRX_RQ_ULIMIT);
29462306a36Sopenharmony_ci		rdma->kdb_addr = adapter->regs + A_SG_KDOORBELL;
29562306a36Sopenharmony_ci		rdma->pdev = pdev;
29662306a36Sopenharmony_ci		break;
29762306a36Sopenharmony_ci	}
29862306a36Sopenharmony_ci	case RDMA_CQ_OP:{
29962306a36Sopenharmony_ci		unsigned long flags;
30062306a36Sopenharmony_ci		struct rdma_cq_op *rdma = data;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci		/* may be called in any context */
30362306a36Sopenharmony_ci		spin_lock_irqsave(&adapter->sge.reg_lock, flags);
30462306a36Sopenharmony_ci		ret = t3_sge_cqcntxt_op(adapter, rdma->id, rdma->op,
30562306a36Sopenharmony_ci					rdma->credits);
30662306a36Sopenharmony_ci		spin_unlock_irqrestore(&adapter->sge.reg_lock, flags);
30762306a36Sopenharmony_ci		break;
30862306a36Sopenharmony_ci	}
30962306a36Sopenharmony_ci	case RDMA_GET_MEM:{
31062306a36Sopenharmony_ci		struct ch_mem_range *t = data;
31162306a36Sopenharmony_ci		struct mc7 *mem;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci		if ((t->addr & 7) || (t->len & 7))
31462306a36Sopenharmony_ci			return -EINVAL;
31562306a36Sopenharmony_ci		if (t->mem_id == MEM_CM)
31662306a36Sopenharmony_ci			mem = &adapter->cm;
31762306a36Sopenharmony_ci		else if (t->mem_id == MEM_PMRX)
31862306a36Sopenharmony_ci			mem = &adapter->pmrx;
31962306a36Sopenharmony_ci		else if (t->mem_id == MEM_PMTX)
32062306a36Sopenharmony_ci			mem = &adapter->pmtx;
32162306a36Sopenharmony_ci		else
32262306a36Sopenharmony_ci			return -EINVAL;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci		ret =
32562306a36Sopenharmony_ci			t3_mc7_bd_read(mem, t->addr / 8, t->len / 8,
32662306a36Sopenharmony_ci					(u64 *) t->buf);
32762306a36Sopenharmony_ci		if (ret)
32862306a36Sopenharmony_ci			return ret;
32962306a36Sopenharmony_ci		break;
33062306a36Sopenharmony_ci	}
33162306a36Sopenharmony_ci	case RDMA_CQ_SETUP:{
33262306a36Sopenharmony_ci		struct rdma_cq_setup *rdma = data;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci		spin_lock_irq(&adapter->sge.reg_lock);
33562306a36Sopenharmony_ci		ret =
33662306a36Sopenharmony_ci			t3_sge_init_cqcntxt(adapter, rdma->id,
33762306a36Sopenharmony_ci					rdma->base_addr, rdma->size,
33862306a36Sopenharmony_ci					ASYNC_NOTIF_RSPQ,
33962306a36Sopenharmony_ci					rdma->ovfl_mode, rdma->credits,
34062306a36Sopenharmony_ci					rdma->credit_thres);
34162306a36Sopenharmony_ci		spin_unlock_irq(&adapter->sge.reg_lock);
34262306a36Sopenharmony_ci		break;
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci	case RDMA_CQ_DISABLE:
34562306a36Sopenharmony_ci		spin_lock_irq(&adapter->sge.reg_lock);
34662306a36Sopenharmony_ci		ret = t3_sge_disable_cqcntxt(adapter, *(unsigned int *)data);
34762306a36Sopenharmony_ci		spin_unlock_irq(&adapter->sge.reg_lock);
34862306a36Sopenharmony_ci		break;
34962306a36Sopenharmony_ci	case RDMA_CTRL_QP_SETUP:{
35062306a36Sopenharmony_ci		struct rdma_ctrlqp_setup *rdma = data;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci		spin_lock_irq(&adapter->sge.reg_lock);
35362306a36Sopenharmony_ci		ret = t3_sge_init_ecntxt(adapter, FW_RI_SGEEC_START, 0,
35462306a36Sopenharmony_ci						SGE_CNTXT_RDMA,
35562306a36Sopenharmony_ci						ASYNC_NOTIF_RSPQ,
35662306a36Sopenharmony_ci						rdma->base_addr, rdma->size,
35762306a36Sopenharmony_ci						FW_RI_TID_START, 1, 0);
35862306a36Sopenharmony_ci		spin_unlock_irq(&adapter->sge.reg_lock);
35962306a36Sopenharmony_ci		break;
36062306a36Sopenharmony_ci	}
36162306a36Sopenharmony_ci	case RDMA_GET_MIB: {
36262306a36Sopenharmony_ci		spin_lock(&adapter->stats_lock);
36362306a36Sopenharmony_ci		t3_tp_get_mib_stats(adapter, (struct tp_mib_stats *)data);
36462306a36Sopenharmony_ci		spin_unlock(&adapter->stats_lock);
36562306a36Sopenharmony_ci		break;
36662306a36Sopenharmony_ci	}
36762306a36Sopenharmony_ci	default:
36862306a36Sopenharmony_ci		ret = -EOPNOTSUPP;
36962306a36Sopenharmony_ci	}
37062306a36Sopenharmony_ci	return ret;
37162306a36Sopenharmony_ci}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_cistatic int cxgb_offload_ctl(struct t3cdev *tdev, unsigned int req, void *data)
37462306a36Sopenharmony_ci{
37562306a36Sopenharmony_ci	struct adapter *adapter = tdev2adap(tdev);
37662306a36Sopenharmony_ci	struct tid_range *tid;
37762306a36Sopenharmony_ci	struct mtutab *mtup;
37862306a36Sopenharmony_ci	struct iff_mac *iffmacp;
37962306a36Sopenharmony_ci	struct ddp_params *ddpp;
38062306a36Sopenharmony_ci	struct adap_ports *ports;
38162306a36Sopenharmony_ci	struct ofld_page_info *rx_page_info;
38262306a36Sopenharmony_ci	struct tp_params *tp = &adapter->params.tp;
38362306a36Sopenharmony_ci	int i;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	switch (req) {
38662306a36Sopenharmony_ci	case GET_MAX_OUTSTANDING_WR:
38762306a36Sopenharmony_ci		*(unsigned int *)data = FW_WR_NUM;
38862306a36Sopenharmony_ci		break;
38962306a36Sopenharmony_ci	case GET_WR_LEN:
39062306a36Sopenharmony_ci		*(unsigned int *)data = WR_FLITS;
39162306a36Sopenharmony_ci		break;
39262306a36Sopenharmony_ci	case GET_TX_MAX_CHUNK:
39362306a36Sopenharmony_ci		*(unsigned int *)data = 1 << 20;	/* 1MB */
39462306a36Sopenharmony_ci		break;
39562306a36Sopenharmony_ci	case GET_TID_RANGE:
39662306a36Sopenharmony_ci		tid = data;
39762306a36Sopenharmony_ci		tid->num = t3_mc5_size(&adapter->mc5) -
39862306a36Sopenharmony_ci		    adapter->params.mc5.nroutes -
39962306a36Sopenharmony_ci		    adapter->params.mc5.nfilters - adapter->params.mc5.nservers;
40062306a36Sopenharmony_ci		tid->base = 0;
40162306a36Sopenharmony_ci		break;
40262306a36Sopenharmony_ci	case GET_STID_RANGE:
40362306a36Sopenharmony_ci		tid = data;
40462306a36Sopenharmony_ci		tid->num = adapter->params.mc5.nservers;
40562306a36Sopenharmony_ci		tid->base = t3_mc5_size(&adapter->mc5) - tid->num -
40662306a36Sopenharmony_ci		    adapter->params.mc5.nfilters - adapter->params.mc5.nroutes;
40762306a36Sopenharmony_ci		break;
40862306a36Sopenharmony_ci	case GET_L2T_CAPACITY:
40962306a36Sopenharmony_ci		*(unsigned int *)data = 2048;
41062306a36Sopenharmony_ci		break;
41162306a36Sopenharmony_ci	case GET_MTUS:
41262306a36Sopenharmony_ci		mtup = data;
41362306a36Sopenharmony_ci		mtup->size = NMTUS;
41462306a36Sopenharmony_ci		mtup->mtus = adapter->params.mtus;
41562306a36Sopenharmony_ci		break;
41662306a36Sopenharmony_ci	case GET_IFF_FROM_MAC:
41762306a36Sopenharmony_ci		iffmacp = data;
41862306a36Sopenharmony_ci		iffmacp->dev = get_iff_from_mac(adapter, iffmacp->mac_addr,
41962306a36Sopenharmony_ci						iffmacp->vlan_tag &
42062306a36Sopenharmony_ci						VLAN_VID_MASK);
42162306a36Sopenharmony_ci		break;
42262306a36Sopenharmony_ci	case GET_DDP_PARAMS:
42362306a36Sopenharmony_ci		ddpp = data;
42462306a36Sopenharmony_ci		ddpp->llimit = t3_read_reg(adapter, A_ULPRX_TDDP_LLIMIT);
42562306a36Sopenharmony_ci		ddpp->ulimit = t3_read_reg(adapter, A_ULPRX_TDDP_ULIMIT);
42662306a36Sopenharmony_ci		ddpp->tag_mask = t3_read_reg(adapter, A_ULPRX_TDDP_TAGMASK);
42762306a36Sopenharmony_ci		break;
42862306a36Sopenharmony_ci	case GET_PORTS:
42962306a36Sopenharmony_ci		ports = data;
43062306a36Sopenharmony_ci		ports->nports = adapter->params.nports;
43162306a36Sopenharmony_ci		for_each_port(adapter, i)
43262306a36Sopenharmony_ci			ports->lldevs[i] = adapter->port[i];
43362306a36Sopenharmony_ci		break;
43462306a36Sopenharmony_ci	case ULP_ISCSI_GET_PARAMS:
43562306a36Sopenharmony_ci	case ULP_ISCSI_SET_PARAMS:
43662306a36Sopenharmony_ci		if (!offload_running(adapter))
43762306a36Sopenharmony_ci			return -EAGAIN;
43862306a36Sopenharmony_ci		return cxgb_ulp_iscsi_ctl(adapter, req, data);
43962306a36Sopenharmony_ci	case RDMA_GET_PARAMS:
44062306a36Sopenharmony_ci	case RDMA_CQ_OP:
44162306a36Sopenharmony_ci	case RDMA_CQ_SETUP:
44262306a36Sopenharmony_ci	case RDMA_CQ_DISABLE:
44362306a36Sopenharmony_ci	case RDMA_CTRL_QP_SETUP:
44462306a36Sopenharmony_ci	case RDMA_GET_MEM:
44562306a36Sopenharmony_ci	case RDMA_GET_MIB:
44662306a36Sopenharmony_ci		if (!offload_running(adapter))
44762306a36Sopenharmony_ci			return -EAGAIN;
44862306a36Sopenharmony_ci		return cxgb_rdma_ctl(adapter, req, data);
44962306a36Sopenharmony_ci	case GET_RX_PAGE_INFO:
45062306a36Sopenharmony_ci		rx_page_info = data;
45162306a36Sopenharmony_ci		rx_page_info->page_size = tp->rx_pg_size;
45262306a36Sopenharmony_ci		rx_page_info->num = tp->rx_num_pgs;
45362306a36Sopenharmony_ci		break;
45462306a36Sopenharmony_ci	case GET_ISCSI_IPV4ADDR: {
45562306a36Sopenharmony_ci		struct iscsi_ipv4addr *p = data;
45662306a36Sopenharmony_ci		struct port_info *pi = netdev_priv(p->dev);
45762306a36Sopenharmony_ci		p->ipv4addr = pi->iscsi_ipv4addr;
45862306a36Sopenharmony_ci		break;
45962306a36Sopenharmony_ci	}
46062306a36Sopenharmony_ci	case GET_EMBEDDED_INFO: {
46162306a36Sopenharmony_ci		struct ch_embedded_info *e = data;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci		spin_lock(&adapter->stats_lock);
46462306a36Sopenharmony_ci		t3_get_fw_version(adapter, &e->fw_vers);
46562306a36Sopenharmony_ci		t3_get_tp_version(adapter, &e->tp_vers);
46662306a36Sopenharmony_ci		spin_unlock(&adapter->stats_lock);
46762306a36Sopenharmony_ci		break;
46862306a36Sopenharmony_ci	}
46962306a36Sopenharmony_ci	default:
47062306a36Sopenharmony_ci		return -EOPNOTSUPP;
47162306a36Sopenharmony_ci	}
47262306a36Sopenharmony_ci	return 0;
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci/*
47662306a36Sopenharmony_ci * Dummy handler for Rx offload packets in case we get an offload packet before
47762306a36Sopenharmony_ci * proper processing is setup.  This complains and drops the packet as it isn't
47862306a36Sopenharmony_ci * normal to get offload packets at this stage.
47962306a36Sopenharmony_ci */
48062306a36Sopenharmony_cistatic int rx_offload_blackhole(struct t3cdev *dev, struct sk_buff **skbs,
48162306a36Sopenharmony_ci				int n)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	while (n--)
48462306a36Sopenharmony_ci		dev_kfree_skb_any(skbs[n]);
48562306a36Sopenharmony_ci	return 0;
48662306a36Sopenharmony_ci}
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_cistatic void dummy_neigh_update(struct t3cdev *dev, struct neighbour *neigh)
48962306a36Sopenharmony_ci{
49062306a36Sopenharmony_ci}
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_civoid cxgb3_set_dummy_ops(struct t3cdev *dev)
49362306a36Sopenharmony_ci{
49462306a36Sopenharmony_ci	dev->recv = rx_offload_blackhole;
49562306a36Sopenharmony_ci	dev->neigh_update = dummy_neigh_update;
49662306a36Sopenharmony_ci}
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci/*
49962306a36Sopenharmony_ci * Free an active-open TID.
50062306a36Sopenharmony_ci */
50162306a36Sopenharmony_civoid *cxgb3_free_atid(struct t3cdev *tdev, int atid)
50262306a36Sopenharmony_ci{
50362306a36Sopenharmony_ci	struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
50462306a36Sopenharmony_ci	union active_open_entry *p = atid2entry(t, atid);
50562306a36Sopenharmony_ci	void *ctx = p->t3c_tid.ctx;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	spin_lock_bh(&t->atid_lock);
50862306a36Sopenharmony_ci	p->next = t->afree;
50962306a36Sopenharmony_ci	t->afree = p;
51062306a36Sopenharmony_ci	t->atids_in_use--;
51162306a36Sopenharmony_ci	spin_unlock_bh(&t->atid_lock);
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	return ctx;
51462306a36Sopenharmony_ci}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb3_free_atid);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci/*
51962306a36Sopenharmony_ci * Free a server TID and return it to the free pool.
52062306a36Sopenharmony_ci */
52162306a36Sopenharmony_civoid cxgb3_free_stid(struct t3cdev *tdev, int stid)
52262306a36Sopenharmony_ci{
52362306a36Sopenharmony_ci	struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
52462306a36Sopenharmony_ci	union listen_entry *p = stid2entry(t, stid);
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	spin_lock_bh(&t->stid_lock);
52762306a36Sopenharmony_ci	p->next = t->sfree;
52862306a36Sopenharmony_ci	t->sfree = p;
52962306a36Sopenharmony_ci	t->stids_in_use--;
53062306a36Sopenharmony_ci	spin_unlock_bh(&t->stid_lock);
53162306a36Sopenharmony_ci}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb3_free_stid);
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_civoid cxgb3_insert_tid(struct t3cdev *tdev, struct cxgb3_client *client,
53662306a36Sopenharmony_ci		      void *ctx, unsigned int tid)
53762306a36Sopenharmony_ci{
53862306a36Sopenharmony_ci	struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	t->tid_tab[tid].client = client;
54162306a36Sopenharmony_ci	t->tid_tab[tid].ctx = ctx;
54262306a36Sopenharmony_ci	atomic_inc(&t->tids_in_use);
54362306a36Sopenharmony_ci}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb3_insert_tid);
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci/*
54862306a36Sopenharmony_ci * Populate a TID_RELEASE WR.  The skb must be already propely sized.
54962306a36Sopenharmony_ci */
55062306a36Sopenharmony_cistatic inline void mk_tid_release(struct sk_buff *skb, unsigned int tid)
55162306a36Sopenharmony_ci{
55262306a36Sopenharmony_ci	struct cpl_tid_release *req;
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	skb->priority = CPL_PRIORITY_SETUP;
55562306a36Sopenharmony_ci	req = __skb_put(skb, sizeof(*req));
55662306a36Sopenharmony_ci	req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
55762306a36Sopenharmony_ci	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_TID_RELEASE, tid));
55862306a36Sopenharmony_ci}
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_cistatic void t3_process_tid_release_list(struct work_struct *work)
56162306a36Sopenharmony_ci{
56262306a36Sopenharmony_ci	struct t3c_data *td = container_of(work, struct t3c_data,
56362306a36Sopenharmony_ci					   tid_release_task);
56462306a36Sopenharmony_ci	struct sk_buff *skb;
56562306a36Sopenharmony_ci	struct t3cdev *tdev = td->dev;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	spin_lock_bh(&td->tid_release_lock);
56962306a36Sopenharmony_ci	while (td->tid_release_list) {
57062306a36Sopenharmony_ci		struct t3c_tid_entry *p = td->tid_release_list;
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci		td->tid_release_list = p->ctx;
57362306a36Sopenharmony_ci		spin_unlock_bh(&td->tid_release_lock);
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci		skb = alloc_skb(sizeof(struct cpl_tid_release),
57662306a36Sopenharmony_ci				GFP_KERNEL);
57762306a36Sopenharmony_ci		if (!skb)
57862306a36Sopenharmony_ci			skb = td->nofail_skb;
57962306a36Sopenharmony_ci		if (!skb) {
58062306a36Sopenharmony_ci			spin_lock_bh(&td->tid_release_lock);
58162306a36Sopenharmony_ci			p->ctx = (void *)td->tid_release_list;
58262306a36Sopenharmony_ci			td->tid_release_list = p;
58362306a36Sopenharmony_ci			break;
58462306a36Sopenharmony_ci		}
58562306a36Sopenharmony_ci		mk_tid_release(skb, p - td->tid_maps.tid_tab);
58662306a36Sopenharmony_ci		cxgb3_ofld_send(tdev, skb);
58762306a36Sopenharmony_ci		p->ctx = NULL;
58862306a36Sopenharmony_ci		if (skb == td->nofail_skb)
58962306a36Sopenharmony_ci			td->nofail_skb =
59062306a36Sopenharmony_ci				alloc_skb(sizeof(struct cpl_tid_release),
59162306a36Sopenharmony_ci					GFP_KERNEL);
59262306a36Sopenharmony_ci		spin_lock_bh(&td->tid_release_lock);
59362306a36Sopenharmony_ci	}
59462306a36Sopenharmony_ci	td->release_list_incomplete = (td->tid_release_list == NULL) ? 0 : 1;
59562306a36Sopenharmony_ci	spin_unlock_bh(&td->tid_release_lock);
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	if (!td->nofail_skb)
59862306a36Sopenharmony_ci		td->nofail_skb =
59962306a36Sopenharmony_ci			alloc_skb(sizeof(struct cpl_tid_release),
60062306a36Sopenharmony_ci				GFP_KERNEL);
60162306a36Sopenharmony_ci}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci/* use ctx as a next pointer in the tid release list */
60462306a36Sopenharmony_civoid cxgb3_queue_tid_release(struct t3cdev *tdev, unsigned int tid)
60562306a36Sopenharmony_ci{
60662306a36Sopenharmony_ci	struct t3c_data *td = T3C_DATA(tdev);
60762306a36Sopenharmony_ci	struct t3c_tid_entry *p = &td->tid_maps.tid_tab[tid];
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	spin_lock_bh(&td->tid_release_lock);
61062306a36Sopenharmony_ci	p->ctx = (void *)td->tid_release_list;
61162306a36Sopenharmony_ci	p->client = NULL;
61262306a36Sopenharmony_ci	td->tid_release_list = p;
61362306a36Sopenharmony_ci	if (!p->ctx || td->release_list_incomplete)
61462306a36Sopenharmony_ci		schedule_work(&td->tid_release_task);
61562306a36Sopenharmony_ci	spin_unlock_bh(&td->tid_release_lock);
61662306a36Sopenharmony_ci}
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb3_queue_tid_release);
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci/*
62162306a36Sopenharmony_ci * Remove a tid from the TID table.  A client may defer processing its last
62262306a36Sopenharmony_ci * CPL message if it is locked at the time it arrives, and while the message
62362306a36Sopenharmony_ci * sits in the client's backlog the TID may be reused for another connection.
62462306a36Sopenharmony_ci * To handle this we atomically switch the TID association if it still points
62562306a36Sopenharmony_ci * to the original client context.
62662306a36Sopenharmony_ci */
62762306a36Sopenharmony_civoid cxgb3_remove_tid(struct t3cdev *tdev, void *ctx, unsigned int tid)
62862306a36Sopenharmony_ci{
62962306a36Sopenharmony_ci	struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	BUG_ON(tid >= t->ntids);
63262306a36Sopenharmony_ci	if (tdev->type == T3A)
63362306a36Sopenharmony_ci		(void)cmpxchg(&t->tid_tab[tid].ctx, ctx, NULL);
63462306a36Sopenharmony_ci	else {
63562306a36Sopenharmony_ci		struct sk_buff *skb;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci		skb = alloc_skb(sizeof(struct cpl_tid_release), GFP_ATOMIC);
63862306a36Sopenharmony_ci		if (likely(skb)) {
63962306a36Sopenharmony_ci			mk_tid_release(skb, tid);
64062306a36Sopenharmony_ci			cxgb3_ofld_send(tdev, skb);
64162306a36Sopenharmony_ci			t->tid_tab[tid].ctx = NULL;
64262306a36Sopenharmony_ci		} else
64362306a36Sopenharmony_ci			cxgb3_queue_tid_release(tdev, tid);
64462306a36Sopenharmony_ci	}
64562306a36Sopenharmony_ci	atomic_dec(&t->tids_in_use);
64662306a36Sopenharmony_ci}
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb3_remove_tid);
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ciint cxgb3_alloc_atid(struct t3cdev *tdev, struct cxgb3_client *client,
65162306a36Sopenharmony_ci		     void *ctx)
65262306a36Sopenharmony_ci{
65362306a36Sopenharmony_ci	int atid = -1;
65462306a36Sopenharmony_ci	struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	spin_lock_bh(&t->atid_lock);
65762306a36Sopenharmony_ci	if (t->afree &&
65862306a36Sopenharmony_ci	    t->atids_in_use + atomic_read(&t->tids_in_use) + MC5_MIN_TIDS <=
65962306a36Sopenharmony_ci	    t->ntids) {
66062306a36Sopenharmony_ci		union active_open_entry *p = t->afree;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci		atid = (p - t->atid_tab) + t->atid_base;
66362306a36Sopenharmony_ci		t->afree = p->next;
66462306a36Sopenharmony_ci		p->t3c_tid.ctx = ctx;
66562306a36Sopenharmony_ci		p->t3c_tid.client = client;
66662306a36Sopenharmony_ci		t->atids_in_use++;
66762306a36Sopenharmony_ci	}
66862306a36Sopenharmony_ci	spin_unlock_bh(&t->atid_lock);
66962306a36Sopenharmony_ci	return atid;
67062306a36Sopenharmony_ci}
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb3_alloc_atid);
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ciint cxgb3_alloc_stid(struct t3cdev *tdev, struct cxgb3_client *client,
67562306a36Sopenharmony_ci		     void *ctx)
67662306a36Sopenharmony_ci{
67762306a36Sopenharmony_ci	int stid = -1;
67862306a36Sopenharmony_ci	struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	spin_lock_bh(&t->stid_lock);
68162306a36Sopenharmony_ci	if (t->sfree) {
68262306a36Sopenharmony_ci		union listen_entry *p = t->sfree;
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci		stid = (p - t->stid_tab) + t->stid_base;
68562306a36Sopenharmony_ci		t->sfree = p->next;
68662306a36Sopenharmony_ci		p->t3c_tid.ctx = ctx;
68762306a36Sopenharmony_ci		p->t3c_tid.client = client;
68862306a36Sopenharmony_ci		t->stids_in_use++;
68962306a36Sopenharmony_ci	}
69062306a36Sopenharmony_ci	spin_unlock_bh(&t->stid_lock);
69162306a36Sopenharmony_ci	return stid;
69262306a36Sopenharmony_ci}
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb3_alloc_stid);
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci/* Get the t3cdev associated with a net_device */
69762306a36Sopenharmony_cistruct t3cdev *dev2t3cdev(struct net_device *dev)
69862306a36Sopenharmony_ci{
69962306a36Sopenharmony_ci	const struct port_info *pi = netdev_priv(dev);
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	return (struct t3cdev *)pi->adapter;
70262306a36Sopenharmony_ci}
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ciEXPORT_SYMBOL(dev2t3cdev);
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_cistatic int do_smt_write_rpl(struct t3cdev *dev, struct sk_buff *skb)
70762306a36Sopenharmony_ci{
70862306a36Sopenharmony_ci	struct cpl_smt_write_rpl *rpl = cplhdr(skb);
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	if (rpl->status != CPL_ERR_NONE)
71162306a36Sopenharmony_ci		pr_err("Unexpected SMT_WRITE_RPL status %u for entry %u\n",
71262306a36Sopenharmony_ci		       rpl->status, GET_TID(rpl));
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	return CPL_RET_BUF_DONE;
71562306a36Sopenharmony_ci}
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_cistatic int do_l2t_write_rpl(struct t3cdev *dev, struct sk_buff *skb)
71862306a36Sopenharmony_ci{
71962306a36Sopenharmony_ci	struct cpl_l2t_write_rpl *rpl = cplhdr(skb);
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	if (rpl->status != CPL_ERR_NONE)
72262306a36Sopenharmony_ci		pr_err("Unexpected L2T_WRITE_RPL status %u for entry %u\n",
72362306a36Sopenharmony_ci		       rpl->status, GET_TID(rpl));
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	return CPL_RET_BUF_DONE;
72662306a36Sopenharmony_ci}
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_cistatic int do_rte_write_rpl(struct t3cdev *dev, struct sk_buff *skb)
72962306a36Sopenharmony_ci{
73062306a36Sopenharmony_ci	struct cpl_rte_write_rpl *rpl = cplhdr(skb);
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	if (rpl->status != CPL_ERR_NONE)
73362306a36Sopenharmony_ci		pr_err("Unexpected RTE_WRITE_RPL status %u for entry %u\n",
73462306a36Sopenharmony_ci		       rpl->status, GET_TID(rpl));
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	return CPL_RET_BUF_DONE;
73762306a36Sopenharmony_ci}
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_cistatic int do_act_open_rpl(struct t3cdev *dev, struct sk_buff *skb)
74062306a36Sopenharmony_ci{
74162306a36Sopenharmony_ci	struct cpl_act_open_rpl *rpl = cplhdr(skb);
74262306a36Sopenharmony_ci	unsigned int atid = G_TID(ntohl(rpl->atid));
74362306a36Sopenharmony_ci	struct t3c_tid_entry *t3c_tid;
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	t3c_tid = lookup_atid(&(T3C_DATA(dev))->tid_maps, atid);
74662306a36Sopenharmony_ci	if (t3c_tid && t3c_tid->ctx && t3c_tid->client &&
74762306a36Sopenharmony_ci	    t3c_tid->client->handlers &&
74862306a36Sopenharmony_ci	    t3c_tid->client->handlers[CPL_ACT_OPEN_RPL]) {
74962306a36Sopenharmony_ci		return t3c_tid->client->handlers[CPL_ACT_OPEN_RPL] (dev, skb,
75062306a36Sopenharmony_ci								    t3c_tid->
75162306a36Sopenharmony_ci								    ctx);
75262306a36Sopenharmony_ci	} else {
75362306a36Sopenharmony_ci		pr_err("%s: received clientless CPL command 0x%x\n",
75462306a36Sopenharmony_ci		       dev->name, CPL_ACT_OPEN_RPL);
75562306a36Sopenharmony_ci		return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
75662306a36Sopenharmony_ci	}
75762306a36Sopenharmony_ci}
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_cistatic int do_stid_rpl(struct t3cdev *dev, struct sk_buff *skb)
76062306a36Sopenharmony_ci{
76162306a36Sopenharmony_ci	union opcode_tid *p = cplhdr(skb);
76262306a36Sopenharmony_ci	unsigned int stid = G_TID(ntohl(p->opcode_tid));
76362306a36Sopenharmony_ci	struct t3c_tid_entry *t3c_tid;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	t3c_tid = lookup_stid(&(T3C_DATA(dev))->tid_maps, stid);
76662306a36Sopenharmony_ci	if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers &&
76762306a36Sopenharmony_ci	    t3c_tid->client->handlers[p->opcode]) {
76862306a36Sopenharmony_ci		return t3c_tid->client->handlers[p->opcode] (dev, skb,
76962306a36Sopenharmony_ci							     t3c_tid->ctx);
77062306a36Sopenharmony_ci	} else {
77162306a36Sopenharmony_ci		pr_err("%s: received clientless CPL command 0x%x\n",
77262306a36Sopenharmony_ci		       dev->name, p->opcode);
77362306a36Sopenharmony_ci		return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
77462306a36Sopenharmony_ci	}
77562306a36Sopenharmony_ci}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_cistatic int do_hwtid_rpl(struct t3cdev *dev, struct sk_buff *skb)
77862306a36Sopenharmony_ci{
77962306a36Sopenharmony_ci	union opcode_tid *p = cplhdr(skb);
78062306a36Sopenharmony_ci	unsigned int hwtid = G_TID(ntohl(p->opcode_tid));
78162306a36Sopenharmony_ci	struct t3c_tid_entry *t3c_tid;
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid);
78462306a36Sopenharmony_ci	if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers &&
78562306a36Sopenharmony_ci	    t3c_tid->client->handlers[p->opcode]) {
78662306a36Sopenharmony_ci		return t3c_tid->client->handlers[p->opcode]
78762306a36Sopenharmony_ci		    (dev, skb, t3c_tid->ctx);
78862306a36Sopenharmony_ci	} else {
78962306a36Sopenharmony_ci		pr_err("%s: received clientless CPL command 0x%x\n",
79062306a36Sopenharmony_ci		       dev->name, p->opcode);
79162306a36Sopenharmony_ci		return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
79262306a36Sopenharmony_ci	}
79362306a36Sopenharmony_ci}
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_cistatic int do_cr(struct t3cdev *dev, struct sk_buff *skb)
79662306a36Sopenharmony_ci{
79762306a36Sopenharmony_ci	struct cpl_pass_accept_req *req = cplhdr(skb);
79862306a36Sopenharmony_ci	unsigned int stid = G_PASS_OPEN_TID(ntohl(req->tos_tid));
79962306a36Sopenharmony_ci	struct tid_info *t = &(T3C_DATA(dev))->tid_maps;
80062306a36Sopenharmony_ci	struct t3c_tid_entry *t3c_tid;
80162306a36Sopenharmony_ci	unsigned int tid = GET_TID(req);
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	if (unlikely(tid >= t->ntids)) {
80462306a36Sopenharmony_ci		printk("%s: passive open TID %u too large\n",
80562306a36Sopenharmony_ci		       dev->name, tid);
80662306a36Sopenharmony_ci		t3_fatal_err(tdev2adap(dev));
80762306a36Sopenharmony_ci		return CPL_RET_BUF_DONE;
80862306a36Sopenharmony_ci	}
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	t3c_tid = lookup_stid(t, stid);
81162306a36Sopenharmony_ci	if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers &&
81262306a36Sopenharmony_ci	    t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ]) {
81362306a36Sopenharmony_ci		return t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ]
81462306a36Sopenharmony_ci		    (dev, skb, t3c_tid->ctx);
81562306a36Sopenharmony_ci	} else {
81662306a36Sopenharmony_ci		pr_err("%s: received clientless CPL command 0x%x\n",
81762306a36Sopenharmony_ci		       dev->name, CPL_PASS_ACCEPT_REQ);
81862306a36Sopenharmony_ci		return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
81962306a36Sopenharmony_ci	}
82062306a36Sopenharmony_ci}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci/*
82362306a36Sopenharmony_ci * Returns an sk_buff for a reply CPL message of size len.  If the input
82462306a36Sopenharmony_ci * sk_buff has no other users it is trimmed and reused, otherwise a new buffer
82562306a36Sopenharmony_ci * is allocated.  The input skb must be of size at least len.  Note that this
82662306a36Sopenharmony_ci * operation does not destroy the original skb data even if it decides to reuse
82762306a36Sopenharmony_ci * the buffer.
82862306a36Sopenharmony_ci */
82962306a36Sopenharmony_cistatic struct sk_buff *cxgb3_get_cpl_reply_skb(struct sk_buff *skb, size_t len,
83062306a36Sopenharmony_ci					       gfp_t gfp)
83162306a36Sopenharmony_ci{
83262306a36Sopenharmony_ci	if (likely(!skb_cloned(skb))) {
83362306a36Sopenharmony_ci		BUG_ON(skb->len < len);
83462306a36Sopenharmony_ci		__skb_trim(skb, len);
83562306a36Sopenharmony_ci		skb_get(skb);
83662306a36Sopenharmony_ci	} else {
83762306a36Sopenharmony_ci		skb = alloc_skb(len, gfp);
83862306a36Sopenharmony_ci		if (skb)
83962306a36Sopenharmony_ci			__skb_put(skb, len);
84062306a36Sopenharmony_ci	}
84162306a36Sopenharmony_ci	return skb;
84262306a36Sopenharmony_ci}
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_cistatic int do_abort_req_rss(struct t3cdev *dev, struct sk_buff *skb)
84562306a36Sopenharmony_ci{
84662306a36Sopenharmony_ci	union opcode_tid *p = cplhdr(skb);
84762306a36Sopenharmony_ci	unsigned int hwtid = G_TID(ntohl(p->opcode_tid));
84862306a36Sopenharmony_ci	struct t3c_tid_entry *t3c_tid;
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid);
85162306a36Sopenharmony_ci	if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers &&
85262306a36Sopenharmony_ci	    t3c_tid->client->handlers[p->opcode]) {
85362306a36Sopenharmony_ci		return t3c_tid->client->handlers[p->opcode]
85462306a36Sopenharmony_ci		    (dev, skb, t3c_tid->ctx);
85562306a36Sopenharmony_ci	} else {
85662306a36Sopenharmony_ci		struct cpl_abort_req_rss *req = cplhdr(skb);
85762306a36Sopenharmony_ci		struct cpl_abort_rpl *rpl;
85862306a36Sopenharmony_ci		struct sk_buff *reply_skb;
85962306a36Sopenharmony_ci		unsigned int tid = GET_TID(req);
86062306a36Sopenharmony_ci		u8 cmd = req->status;
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci		if (req->status == CPL_ERR_RTX_NEG_ADVICE ||
86362306a36Sopenharmony_ci		    req->status == CPL_ERR_PERSIST_NEG_ADVICE)
86462306a36Sopenharmony_ci			goto out;
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci		reply_skb = cxgb3_get_cpl_reply_skb(skb,
86762306a36Sopenharmony_ci						    sizeof(struct
86862306a36Sopenharmony_ci							   cpl_abort_rpl),
86962306a36Sopenharmony_ci						    GFP_ATOMIC);
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci		if (!reply_skb) {
87262306a36Sopenharmony_ci			printk("do_abort_req_rss: couldn't get skb!\n");
87362306a36Sopenharmony_ci			goto out;
87462306a36Sopenharmony_ci		}
87562306a36Sopenharmony_ci		reply_skb->priority = CPL_PRIORITY_DATA;
87662306a36Sopenharmony_ci		__skb_put(reply_skb, sizeof(struct cpl_abort_rpl));
87762306a36Sopenharmony_ci		rpl = cplhdr(reply_skb);
87862306a36Sopenharmony_ci		rpl->wr.wr_hi =
87962306a36Sopenharmony_ci		    htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL));
88062306a36Sopenharmony_ci		rpl->wr.wr_lo = htonl(V_WR_TID(tid));
88162306a36Sopenharmony_ci		OPCODE_TID(rpl) = htonl(MK_OPCODE_TID(CPL_ABORT_RPL, tid));
88262306a36Sopenharmony_ci		rpl->cmd = cmd;
88362306a36Sopenharmony_ci		cxgb3_ofld_send(dev, reply_skb);
88462306a36Sopenharmony_ciout:
88562306a36Sopenharmony_ci		return CPL_RET_BUF_DONE;
88662306a36Sopenharmony_ci	}
88762306a36Sopenharmony_ci}
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_cistatic int do_act_establish(struct t3cdev *dev, struct sk_buff *skb)
89062306a36Sopenharmony_ci{
89162306a36Sopenharmony_ci	struct cpl_act_establish *req = cplhdr(skb);
89262306a36Sopenharmony_ci	unsigned int atid = G_PASS_OPEN_TID(ntohl(req->tos_tid));
89362306a36Sopenharmony_ci	struct tid_info *t = &(T3C_DATA(dev))->tid_maps;
89462306a36Sopenharmony_ci	struct t3c_tid_entry *t3c_tid;
89562306a36Sopenharmony_ci	unsigned int tid = GET_TID(req);
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	if (unlikely(tid >= t->ntids)) {
89862306a36Sopenharmony_ci		printk("%s: active establish TID %u too large\n",
89962306a36Sopenharmony_ci		       dev->name, tid);
90062306a36Sopenharmony_ci		t3_fatal_err(tdev2adap(dev));
90162306a36Sopenharmony_ci		return CPL_RET_BUF_DONE;
90262306a36Sopenharmony_ci	}
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	t3c_tid = lookup_atid(t, atid);
90562306a36Sopenharmony_ci	if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers &&
90662306a36Sopenharmony_ci	    t3c_tid->client->handlers[CPL_ACT_ESTABLISH]) {
90762306a36Sopenharmony_ci		return t3c_tid->client->handlers[CPL_ACT_ESTABLISH]
90862306a36Sopenharmony_ci		    (dev, skb, t3c_tid->ctx);
90962306a36Sopenharmony_ci	} else {
91062306a36Sopenharmony_ci		pr_err("%s: received clientless CPL command 0x%x\n",
91162306a36Sopenharmony_ci		       dev->name, CPL_ACT_ESTABLISH);
91262306a36Sopenharmony_ci		return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
91362306a36Sopenharmony_ci	}
91462306a36Sopenharmony_ci}
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_cistatic int do_trace(struct t3cdev *dev, struct sk_buff *skb)
91762306a36Sopenharmony_ci{
91862306a36Sopenharmony_ci	struct cpl_trace_pkt *p = cplhdr(skb);
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	skb->protocol = htons(0xffff);
92162306a36Sopenharmony_ci	skb->dev = dev->lldev;
92262306a36Sopenharmony_ci	skb_pull(skb, sizeof(*p));
92362306a36Sopenharmony_ci	skb_reset_mac_header(skb);
92462306a36Sopenharmony_ci	netif_receive_skb(skb);
92562306a36Sopenharmony_ci	return 0;
92662306a36Sopenharmony_ci}
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci/*
92962306a36Sopenharmony_ci * That skb would better have come from process_responses() where we abuse
93062306a36Sopenharmony_ci * ->priority and ->csum to carry our data.  NB: if we get to per-arch
93162306a36Sopenharmony_ci * ->csum, the things might get really interesting here.
93262306a36Sopenharmony_ci */
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_cistatic inline u32 get_hwtid(struct sk_buff *skb)
93562306a36Sopenharmony_ci{
93662306a36Sopenharmony_ci	return ntohl((__force __be32)skb->priority) >> 8 & 0xfffff;
93762306a36Sopenharmony_ci}
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_cistatic inline u32 get_opcode(struct sk_buff *skb)
94062306a36Sopenharmony_ci{
94162306a36Sopenharmony_ci	return G_OPCODE(ntohl((__force __be32)skb->csum));
94262306a36Sopenharmony_ci}
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_cistatic int do_term(struct t3cdev *dev, struct sk_buff *skb)
94562306a36Sopenharmony_ci{
94662306a36Sopenharmony_ci	unsigned int hwtid = get_hwtid(skb);
94762306a36Sopenharmony_ci	unsigned int opcode = get_opcode(skb);
94862306a36Sopenharmony_ci	struct t3c_tid_entry *t3c_tid;
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid);
95162306a36Sopenharmony_ci	if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers &&
95262306a36Sopenharmony_ci	    t3c_tid->client->handlers[opcode]) {
95362306a36Sopenharmony_ci		return t3c_tid->client->handlers[opcode] (dev, skb,
95462306a36Sopenharmony_ci							  t3c_tid->ctx);
95562306a36Sopenharmony_ci	} else {
95662306a36Sopenharmony_ci		pr_err("%s: received clientless CPL command 0x%x\n",
95762306a36Sopenharmony_ci		       dev->name, opcode);
95862306a36Sopenharmony_ci		return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
95962306a36Sopenharmony_ci	}
96062306a36Sopenharmony_ci}
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_cistatic int nb_callback(struct notifier_block *self, unsigned long event,
96362306a36Sopenharmony_ci		       void *ctx)
96462306a36Sopenharmony_ci{
96562306a36Sopenharmony_ci	switch (event) {
96662306a36Sopenharmony_ci	case (NETEVENT_NEIGH_UPDATE):{
96762306a36Sopenharmony_ci		cxgb_neigh_update((struct neighbour *)ctx);
96862306a36Sopenharmony_ci		break;
96962306a36Sopenharmony_ci	}
97062306a36Sopenharmony_ci	case (NETEVENT_REDIRECT):{
97162306a36Sopenharmony_ci		struct netevent_redirect *nr = ctx;
97262306a36Sopenharmony_ci		cxgb_redirect(nr->old, nr->new, nr->neigh,
97362306a36Sopenharmony_ci			      nr->daddr);
97462306a36Sopenharmony_ci		cxgb_neigh_update(nr->neigh);
97562306a36Sopenharmony_ci		break;
97662306a36Sopenharmony_ci	}
97762306a36Sopenharmony_ci	default:
97862306a36Sopenharmony_ci		break;
97962306a36Sopenharmony_ci	}
98062306a36Sopenharmony_ci	return 0;
98162306a36Sopenharmony_ci}
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_cistatic struct notifier_block nb = {
98462306a36Sopenharmony_ci	.notifier_call = nb_callback
98562306a36Sopenharmony_ci};
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci/*
98862306a36Sopenharmony_ci * Process a received packet with an unknown/unexpected CPL opcode.
98962306a36Sopenharmony_ci */
99062306a36Sopenharmony_cistatic int do_bad_cpl(struct t3cdev *dev, struct sk_buff *skb)
99162306a36Sopenharmony_ci{
99262306a36Sopenharmony_ci	pr_err("%s: received bad CPL command 0x%x\n", dev->name, *skb->data);
99362306a36Sopenharmony_ci	return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
99462306a36Sopenharmony_ci}
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci/*
99762306a36Sopenharmony_ci * Handlers for each CPL opcode
99862306a36Sopenharmony_ci */
99962306a36Sopenharmony_cistatic cpl_handler_func cpl_handlers[NUM_CPL_CMDS];
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci/*
100262306a36Sopenharmony_ci * Add a new handler to the CPL dispatch table.  A NULL handler may be supplied
100362306a36Sopenharmony_ci * to unregister an existing handler.
100462306a36Sopenharmony_ci */
100562306a36Sopenharmony_civoid t3_register_cpl_handler(unsigned int opcode, cpl_handler_func h)
100662306a36Sopenharmony_ci{
100762306a36Sopenharmony_ci	if (opcode < NUM_CPL_CMDS)
100862306a36Sopenharmony_ci		cpl_handlers[opcode] = h ? h : do_bad_cpl;
100962306a36Sopenharmony_ci	else
101062306a36Sopenharmony_ci		pr_err("T3C: handler registration for opcode %x failed\n",
101162306a36Sopenharmony_ci		       opcode);
101262306a36Sopenharmony_ci}
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ciEXPORT_SYMBOL(t3_register_cpl_handler);
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci/*
101762306a36Sopenharmony_ci * T3CDEV's receive method.
101862306a36Sopenharmony_ci */
101962306a36Sopenharmony_cistatic int process_rx(struct t3cdev *dev, struct sk_buff **skbs, int n)
102062306a36Sopenharmony_ci{
102162306a36Sopenharmony_ci	while (n--) {
102262306a36Sopenharmony_ci		struct sk_buff *skb = *skbs++;
102362306a36Sopenharmony_ci		unsigned int opcode = get_opcode(skb);
102462306a36Sopenharmony_ci		int ret = cpl_handlers[opcode] (dev, skb);
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci#if VALIDATE_TID
102762306a36Sopenharmony_ci		if (ret & CPL_RET_UNKNOWN_TID) {
102862306a36Sopenharmony_ci			union opcode_tid *p = cplhdr(skb);
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci			pr_err("%s: CPL message (opcode %u) had unknown TID %u\n",
103162306a36Sopenharmony_ci			       dev->name, opcode, G_TID(ntohl(p->opcode_tid)));
103262306a36Sopenharmony_ci		}
103362306a36Sopenharmony_ci#endif
103462306a36Sopenharmony_ci		if (ret & CPL_RET_BUF_DONE)
103562306a36Sopenharmony_ci			kfree_skb(skb);
103662306a36Sopenharmony_ci	}
103762306a36Sopenharmony_ci	return 0;
103862306a36Sopenharmony_ci}
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci/*
104162306a36Sopenharmony_ci * Sends an sk_buff to a T3C driver after dealing with any active network taps.
104262306a36Sopenharmony_ci */
104362306a36Sopenharmony_ciint cxgb3_ofld_send(struct t3cdev *dev, struct sk_buff *skb)
104462306a36Sopenharmony_ci{
104562306a36Sopenharmony_ci	int r;
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci	local_bh_disable();
104862306a36Sopenharmony_ci	r = dev->send(dev, skb);
104962306a36Sopenharmony_ci	local_bh_enable();
105062306a36Sopenharmony_ci	return r;
105162306a36Sopenharmony_ci}
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ciEXPORT_SYMBOL(cxgb3_ofld_send);
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_cistatic int is_offloading(struct net_device *dev)
105662306a36Sopenharmony_ci{
105762306a36Sopenharmony_ci	struct adapter *adapter;
105862306a36Sopenharmony_ci	int i;
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	read_lock_bh(&adapter_list_lock);
106162306a36Sopenharmony_ci	list_for_each_entry(adapter, &adapter_list, adapter_list) {
106262306a36Sopenharmony_ci		for_each_port(adapter, i) {
106362306a36Sopenharmony_ci			if (dev == adapter->port[i]) {
106462306a36Sopenharmony_ci				read_unlock_bh(&adapter_list_lock);
106562306a36Sopenharmony_ci				return 1;
106662306a36Sopenharmony_ci			}
106762306a36Sopenharmony_ci		}
106862306a36Sopenharmony_ci	}
106962306a36Sopenharmony_ci	read_unlock_bh(&adapter_list_lock);
107062306a36Sopenharmony_ci	return 0;
107162306a36Sopenharmony_ci}
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_cistatic void cxgb_neigh_update(struct neighbour *neigh)
107462306a36Sopenharmony_ci{
107562306a36Sopenharmony_ci	struct net_device *dev;
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	if (!neigh)
107862306a36Sopenharmony_ci		return;
107962306a36Sopenharmony_ci	dev = neigh->dev;
108062306a36Sopenharmony_ci	if (dev && (is_offloading(dev))) {
108162306a36Sopenharmony_ci		struct t3cdev *tdev = dev2t3cdev(dev);
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci		BUG_ON(!tdev);
108462306a36Sopenharmony_ci		t3_l2t_update(tdev, neigh);
108562306a36Sopenharmony_ci	}
108662306a36Sopenharmony_ci}
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_cistatic void set_l2t_ix(struct t3cdev *tdev, u32 tid, struct l2t_entry *e)
108962306a36Sopenharmony_ci{
109062306a36Sopenharmony_ci	struct sk_buff *skb;
109162306a36Sopenharmony_ci	struct cpl_set_tcb_field *req;
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci	skb = alloc_skb(sizeof(*req), GFP_ATOMIC);
109462306a36Sopenharmony_ci	if (!skb) {
109562306a36Sopenharmony_ci		pr_err("%s: cannot allocate skb!\n", __func__);
109662306a36Sopenharmony_ci		return;
109762306a36Sopenharmony_ci	}
109862306a36Sopenharmony_ci	skb->priority = CPL_PRIORITY_CONTROL;
109962306a36Sopenharmony_ci	req = skb_put(skb, sizeof(*req));
110062306a36Sopenharmony_ci	req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
110162306a36Sopenharmony_ci	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid));
110262306a36Sopenharmony_ci	req->reply = 0;
110362306a36Sopenharmony_ci	req->cpu_idx = 0;
110462306a36Sopenharmony_ci	req->word = htons(W_TCB_L2T_IX);
110562306a36Sopenharmony_ci	req->mask = cpu_to_be64(V_TCB_L2T_IX(M_TCB_L2T_IX));
110662306a36Sopenharmony_ci	req->val = cpu_to_be64(V_TCB_L2T_IX(e->idx));
110762306a36Sopenharmony_ci	tdev->send(tdev, skb);
110862306a36Sopenharmony_ci}
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_cistatic void cxgb_redirect(struct dst_entry *old, struct dst_entry *new,
111162306a36Sopenharmony_ci			  struct neighbour *neigh,
111262306a36Sopenharmony_ci			  const void *daddr)
111362306a36Sopenharmony_ci{
111462306a36Sopenharmony_ci	struct net_device *dev;
111562306a36Sopenharmony_ci	struct tid_info *ti;
111662306a36Sopenharmony_ci	struct t3cdev *tdev;
111762306a36Sopenharmony_ci	u32 tid;
111862306a36Sopenharmony_ci	int update_tcb;
111962306a36Sopenharmony_ci	struct l2t_entry *e;
112062306a36Sopenharmony_ci	struct t3c_tid_entry *te;
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	dev = neigh->dev;
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	if (!is_offloading(dev))
112562306a36Sopenharmony_ci		return;
112662306a36Sopenharmony_ci	tdev = dev2t3cdev(dev);
112762306a36Sopenharmony_ci	BUG_ON(!tdev);
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	/* Add new L2T entry */
113062306a36Sopenharmony_ci	e = t3_l2t_get(tdev, new, dev, daddr);
113162306a36Sopenharmony_ci	if (!e) {
113262306a36Sopenharmony_ci		pr_err("%s: couldn't allocate new l2t entry!\n", __func__);
113362306a36Sopenharmony_ci		return;
113462306a36Sopenharmony_ci	}
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	/* Walk tid table and notify clients of dst change. */
113762306a36Sopenharmony_ci	ti = &(T3C_DATA(tdev))->tid_maps;
113862306a36Sopenharmony_ci	for (tid = 0; tid < ti->ntids; tid++) {
113962306a36Sopenharmony_ci		te = lookup_tid(ti, tid);
114062306a36Sopenharmony_ci		BUG_ON(!te);
114162306a36Sopenharmony_ci		if (te && te->ctx && te->client && te->client->redirect) {
114262306a36Sopenharmony_ci			update_tcb = te->client->redirect(te->ctx, old, new, e);
114362306a36Sopenharmony_ci			if (update_tcb) {
114462306a36Sopenharmony_ci				rcu_read_lock();
114562306a36Sopenharmony_ci				l2t_hold(L2DATA(tdev), e);
114662306a36Sopenharmony_ci				rcu_read_unlock();
114762306a36Sopenharmony_ci				set_l2t_ix(tdev, tid, e);
114862306a36Sopenharmony_ci			}
114962306a36Sopenharmony_ci		}
115062306a36Sopenharmony_ci	}
115162306a36Sopenharmony_ci	l2t_release(tdev, e);
115262306a36Sopenharmony_ci}
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci/*
115562306a36Sopenharmony_ci * Allocate and initialize the TID tables.  Returns 0 on success.
115662306a36Sopenharmony_ci */
115762306a36Sopenharmony_cistatic int init_tid_tabs(struct tid_info *t, unsigned int ntids,
115862306a36Sopenharmony_ci			 unsigned int natids, unsigned int nstids,
115962306a36Sopenharmony_ci			 unsigned int atid_base, unsigned int stid_base)
116062306a36Sopenharmony_ci{
116162306a36Sopenharmony_ci	unsigned long size = ntids * sizeof(*t->tid_tab) +
116262306a36Sopenharmony_ci	    natids * sizeof(*t->atid_tab) + nstids * sizeof(*t->stid_tab);
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	t->tid_tab = kvzalloc(size, GFP_KERNEL);
116562306a36Sopenharmony_ci	if (!t->tid_tab)
116662306a36Sopenharmony_ci		return -ENOMEM;
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	t->stid_tab = (union listen_entry *)&t->tid_tab[ntids];
116962306a36Sopenharmony_ci	t->atid_tab = (union active_open_entry *)&t->stid_tab[nstids];
117062306a36Sopenharmony_ci	t->ntids = ntids;
117162306a36Sopenharmony_ci	t->nstids = nstids;
117262306a36Sopenharmony_ci	t->stid_base = stid_base;
117362306a36Sopenharmony_ci	t->sfree = NULL;
117462306a36Sopenharmony_ci	t->natids = natids;
117562306a36Sopenharmony_ci	t->atid_base = atid_base;
117662306a36Sopenharmony_ci	t->afree = NULL;
117762306a36Sopenharmony_ci	t->stids_in_use = t->atids_in_use = 0;
117862306a36Sopenharmony_ci	atomic_set(&t->tids_in_use, 0);
117962306a36Sopenharmony_ci	spin_lock_init(&t->stid_lock);
118062306a36Sopenharmony_ci	spin_lock_init(&t->atid_lock);
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	/*
118362306a36Sopenharmony_ci	 * Setup the free lists for stid_tab and atid_tab.
118462306a36Sopenharmony_ci	 */
118562306a36Sopenharmony_ci	if (nstids) {
118662306a36Sopenharmony_ci		while (--nstids)
118762306a36Sopenharmony_ci			t->stid_tab[nstids - 1].next = &t->stid_tab[nstids];
118862306a36Sopenharmony_ci		t->sfree = t->stid_tab;
118962306a36Sopenharmony_ci	}
119062306a36Sopenharmony_ci	if (natids) {
119162306a36Sopenharmony_ci		while (--natids)
119262306a36Sopenharmony_ci			t->atid_tab[natids - 1].next = &t->atid_tab[natids];
119362306a36Sopenharmony_ci		t->afree = t->atid_tab;
119462306a36Sopenharmony_ci	}
119562306a36Sopenharmony_ci	return 0;
119662306a36Sopenharmony_ci}
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_cistatic void free_tid_maps(struct tid_info *t)
119962306a36Sopenharmony_ci{
120062306a36Sopenharmony_ci	kvfree(t->tid_tab);
120162306a36Sopenharmony_ci}
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_cistatic inline void add_adapter(struct adapter *adap)
120462306a36Sopenharmony_ci{
120562306a36Sopenharmony_ci	write_lock_bh(&adapter_list_lock);
120662306a36Sopenharmony_ci	list_add_tail(&adap->adapter_list, &adapter_list);
120762306a36Sopenharmony_ci	write_unlock_bh(&adapter_list_lock);
120862306a36Sopenharmony_ci}
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_cistatic inline void remove_adapter(struct adapter *adap)
121162306a36Sopenharmony_ci{
121262306a36Sopenharmony_ci	write_lock_bh(&adapter_list_lock);
121362306a36Sopenharmony_ci	list_del(&adap->adapter_list);
121462306a36Sopenharmony_ci	write_unlock_bh(&adapter_list_lock);
121562306a36Sopenharmony_ci}
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ciint cxgb3_offload_activate(struct adapter *adapter)
121862306a36Sopenharmony_ci{
121962306a36Sopenharmony_ci	struct t3cdev *dev = &adapter->tdev;
122062306a36Sopenharmony_ci	int natids, err;
122162306a36Sopenharmony_ci	struct t3c_data *t;
122262306a36Sopenharmony_ci	struct tid_range stid_range, tid_range;
122362306a36Sopenharmony_ci	struct mtutab mtutab;
122462306a36Sopenharmony_ci	unsigned int l2t_capacity;
122562306a36Sopenharmony_ci	struct l2t_data *l2td;
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci	t = kzalloc(sizeof(*t), GFP_KERNEL);
122862306a36Sopenharmony_ci	if (!t)
122962306a36Sopenharmony_ci		return -ENOMEM;
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	err = -EOPNOTSUPP;
123262306a36Sopenharmony_ci	if (dev->ctl(dev, GET_TX_MAX_CHUNK, &t->tx_max_chunk) < 0 ||
123362306a36Sopenharmony_ci	    dev->ctl(dev, GET_MAX_OUTSTANDING_WR, &t->max_wrs) < 0 ||
123462306a36Sopenharmony_ci	    dev->ctl(dev, GET_L2T_CAPACITY, &l2t_capacity) < 0 ||
123562306a36Sopenharmony_ci	    dev->ctl(dev, GET_MTUS, &mtutab) < 0 ||
123662306a36Sopenharmony_ci	    dev->ctl(dev, GET_TID_RANGE, &tid_range) < 0 ||
123762306a36Sopenharmony_ci	    dev->ctl(dev, GET_STID_RANGE, &stid_range) < 0)
123862306a36Sopenharmony_ci		goto out_free;
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	err = -ENOMEM;
124162306a36Sopenharmony_ci	l2td = t3_init_l2t(l2t_capacity);
124262306a36Sopenharmony_ci	if (!l2td)
124362306a36Sopenharmony_ci		goto out_free;
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	natids = min(tid_range.num / 2, MAX_ATIDS);
124662306a36Sopenharmony_ci	err = init_tid_tabs(&t->tid_maps, tid_range.num, natids,
124762306a36Sopenharmony_ci			    stid_range.num, ATID_BASE, stid_range.base);
124862306a36Sopenharmony_ci	if (err)
124962306a36Sopenharmony_ci		goto out_free_l2t;
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci	t->mtus = mtutab.mtus;
125262306a36Sopenharmony_ci	t->nmtus = mtutab.size;
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci	INIT_WORK(&t->tid_release_task, t3_process_tid_release_list);
125562306a36Sopenharmony_ci	spin_lock_init(&t->tid_release_lock);
125662306a36Sopenharmony_ci	INIT_LIST_HEAD(&t->list_node);
125762306a36Sopenharmony_ci	t->dev = dev;
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	RCU_INIT_POINTER(dev->l2opt, l2td);
126062306a36Sopenharmony_ci	T3C_DATA(dev) = t;
126162306a36Sopenharmony_ci	dev->recv = process_rx;
126262306a36Sopenharmony_ci	dev->neigh_update = t3_l2t_update;
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci	/* Register netevent handler once */
126562306a36Sopenharmony_ci	if (list_empty(&adapter_list))
126662306a36Sopenharmony_ci		register_netevent_notifier(&nb);
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	t->nofail_skb = alloc_skb(sizeof(struct cpl_tid_release), GFP_KERNEL);
126962306a36Sopenharmony_ci	t->release_list_incomplete = 0;
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	add_adapter(adapter);
127262306a36Sopenharmony_ci	return 0;
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ciout_free_l2t:
127562306a36Sopenharmony_ci	kvfree(l2td);
127662306a36Sopenharmony_ciout_free:
127762306a36Sopenharmony_ci	kfree(t);
127862306a36Sopenharmony_ci	return err;
127962306a36Sopenharmony_ci}
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_cistatic void clean_l2_data(struct rcu_head *head)
128262306a36Sopenharmony_ci{
128362306a36Sopenharmony_ci	struct l2t_data *d = container_of(head, struct l2t_data, rcu_head);
128462306a36Sopenharmony_ci	kvfree(d);
128562306a36Sopenharmony_ci}
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_civoid cxgb3_offload_deactivate(struct adapter *adapter)
128962306a36Sopenharmony_ci{
129062306a36Sopenharmony_ci	struct t3cdev *tdev = &adapter->tdev;
129162306a36Sopenharmony_ci	struct t3c_data *t = T3C_DATA(tdev);
129262306a36Sopenharmony_ci	struct l2t_data *d;
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci	remove_adapter(adapter);
129562306a36Sopenharmony_ci	if (list_empty(&adapter_list))
129662306a36Sopenharmony_ci		unregister_netevent_notifier(&nb);
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci	free_tid_maps(&t->tid_maps);
129962306a36Sopenharmony_ci	T3C_DATA(tdev) = NULL;
130062306a36Sopenharmony_ci	rcu_read_lock();
130162306a36Sopenharmony_ci	d = L2DATA(tdev);
130262306a36Sopenharmony_ci	rcu_read_unlock();
130362306a36Sopenharmony_ci	RCU_INIT_POINTER(tdev->l2opt, NULL);
130462306a36Sopenharmony_ci	call_rcu(&d->rcu_head, clean_l2_data);
130562306a36Sopenharmony_ci	kfree_skb(t->nofail_skb);
130662306a36Sopenharmony_ci	kfree(t);
130762306a36Sopenharmony_ci}
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_cistatic inline void register_tdev(struct t3cdev *tdev)
131062306a36Sopenharmony_ci{
131162306a36Sopenharmony_ci	static int unit;
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	mutex_lock(&cxgb3_db_lock);
131462306a36Sopenharmony_ci	snprintf(tdev->name, sizeof(tdev->name), "ofld_dev%d", unit++);
131562306a36Sopenharmony_ci	list_add_tail(&tdev->ofld_dev_list, &ofld_dev_list);
131662306a36Sopenharmony_ci	mutex_unlock(&cxgb3_db_lock);
131762306a36Sopenharmony_ci}
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_cistatic inline void unregister_tdev(struct t3cdev *tdev)
132062306a36Sopenharmony_ci{
132162306a36Sopenharmony_ci	mutex_lock(&cxgb3_db_lock);
132262306a36Sopenharmony_ci	list_del(&tdev->ofld_dev_list);
132362306a36Sopenharmony_ci	mutex_unlock(&cxgb3_db_lock);
132462306a36Sopenharmony_ci}
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_cistatic inline int adap2type(struct adapter *adapter)
132762306a36Sopenharmony_ci{
132862306a36Sopenharmony_ci	int type = 0;
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci	switch (adapter->params.rev) {
133162306a36Sopenharmony_ci	case T3_REV_A:
133262306a36Sopenharmony_ci		type = T3A;
133362306a36Sopenharmony_ci		break;
133462306a36Sopenharmony_ci	case T3_REV_B:
133562306a36Sopenharmony_ci	case T3_REV_B2:
133662306a36Sopenharmony_ci		type = T3B;
133762306a36Sopenharmony_ci		break;
133862306a36Sopenharmony_ci	case T3_REV_C:
133962306a36Sopenharmony_ci		type = T3C;
134062306a36Sopenharmony_ci		break;
134162306a36Sopenharmony_ci	}
134262306a36Sopenharmony_ci	return type;
134362306a36Sopenharmony_ci}
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_civoid cxgb3_adapter_ofld(struct adapter *adapter)
134662306a36Sopenharmony_ci{
134762306a36Sopenharmony_ci	struct t3cdev *tdev = &adapter->tdev;
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci	INIT_LIST_HEAD(&tdev->ofld_dev_list);
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci	cxgb3_set_dummy_ops(tdev);
135262306a36Sopenharmony_ci	tdev->send = t3_offload_tx;
135362306a36Sopenharmony_ci	tdev->ctl = cxgb_offload_ctl;
135462306a36Sopenharmony_ci	tdev->type = adap2type(adapter);
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci	register_tdev(tdev);
135762306a36Sopenharmony_ci}
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_civoid cxgb3_adapter_unofld(struct adapter *adapter)
136062306a36Sopenharmony_ci{
136162306a36Sopenharmony_ci	struct t3cdev *tdev = &adapter->tdev;
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	tdev->recv = NULL;
136462306a36Sopenharmony_ci	tdev->neigh_update = NULL;
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci	unregister_tdev(tdev);
136762306a36Sopenharmony_ci}
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_civoid __init cxgb3_offload_init(void)
137062306a36Sopenharmony_ci{
137162306a36Sopenharmony_ci	int i;
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	for (i = 0; i < NUM_CPL_CMDS; ++i)
137462306a36Sopenharmony_ci		cpl_handlers[i] = do_bad_cpl;
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	t3_register_cpl_handler(CPL_SMT_WRITE_RPL, do_smt_write_rpl);
137762306a36Sopenharmony_ci	t3_register_cpl_handler(CPL_L2T_WRITE_RPL, do_l2t_write_rpl);
137862306a36Sopenharmony_ci	t3_register_cpl_handler(CPL_RTE_WRITE_RPL, do_rte_write_rpl);
137962306a36Sopenharmony_ci	t3_register_cpl_handler(CPL_PASS_OPEN_RPL, do_stid_rpl);
138062306a36Sopenharmony_ci	t3_register_cpl_handler(CPL_CLOSE_LISTSRV_RPL, do_stid_rpl);
138162306a36Sopenharmony_ci	t3_register_cpl_handler(CPL_PASS_ACCEPT_REQ, do_cr);
138262306a36Sopenharmony_ci	t3_register_cpl_handler(CPL_PASS_ESTABLISH, do_hwtid_rpl);
138362306a36Sopenharmony_ci	t3_register_cpl_handler(CPL_ABORT_RPL_RSS, do_hwtid_rpl);
138462306a36Sopenharmony_ci	t3_register_cpl_handler(CPL_ABORT_RPL, do_hwtid_rpl);
138562306a36Sopenharmony_ci	t3_register_cpl_handler(CPL_RX_URG_NOTIFY, do_hwtid_rpl);
138662306a36Sopenharmony_ci	t3_register_cpl_handler(CPL_RX_DATA, do_hwtid_rpl);
138762306a36Sopenharmony_ci	t3_register_cpl_handler(CPL_TX_DATA_ACK, do_hwtid_rpl);
138862306a36Sopenharmony_ci	t3_register_cpl_handler(CPL_TX_DMA_ACK, do_hwtid_rpl);
138962306a36Sopenharmony_ci	t3_register_cpl_handler(CPL_ACT_OPEN_RPL, do_act_open_rpl);
139062306a36Sopenharmony_ci	t3_register_cpl_handler(CPL_PEER_CLOSE, do_hwtid_rpl);
139162306a36Sopenharmony_ci	t3_register_cpl_handler(CPL_CLOSE_CON_RPL, do_hwtid_rpl);
139262306a36Sopenharmony_ci	t3_register_cpl_handler(CPL_ABORT_REQ_RSS, do_abort_req_rss);
139362306a36Sopenharmony_ci	t3_register_cpl_handler(CPL_ACT_ESTABLISH, do_act_establish);
139462306a36Sopenharmony_ci	t3_register_cpl_handler(CPL_SET_TCB_RPL, do_hwtid_rpl);
139562306a36Sopenharmony_ci	t3_register_cpl_handler(CPL_GET_TCB_RPL, do_hwtid_rpl);
139662306a36Sopenharmony_ci	t3_register_cpl_handler(CPL_RDMA_TERMINATE, do_term);
139762306a36Sopenharmony_ci	t3_register_cpl_handler(CPL_RDMA_EC_STATUS, do_hwtid_rpl);
139862306a36Sopenharmony_ci	t3_register_cpl_handler(CPL_TRACE_PKT, do_trace);
139962306a36Sopenharmony_ci	t3_register_cpl_handler(CPL_RX_DATA_DDP, do_hwtid_rpl);
140062306a36Sopenharmony_ci	t3_register_cpl_handler(CPL_RX_DDP_COMPLETE, do_hwtid_rpl);
140162306a36Sopenharmony_ci	t3_register_cpl_handler(CPL_ISCSI_HDR, do_hwtid_rpl);
140262306a36Sopenharmony_ci}
1403