<commit_before>
/**************************************************************************

Copyright (c) 2007, Chelsio Inc.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 1. Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.

 2. Neither the name of the Chelsio Corporation nor the names of its
    contributors may be used to endorse or promote products derived from
    this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.


***************************************************************************/


#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/module.h>
#include <sys/pciio.h>
#include <sys/conf.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <sys/bus_dma.h>
#include <sys/rman.h>
#include <sys/ioccom.h>
#include <sys/mbuf.h>
#include <sys/linker.h>
#include <sys/firmware.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/smp.h>
#include <sys/sysctl.h>
#include <sys/syslog.h>
#include <sys/queue.h>
#include <sys/taskqueue.h>
#include <sys/proc.h>

#ifdef CONFIG_DEFINED
#include <cxgb_include.h>
#else
#include <dev/cxgb/cxgb_include.h>
#endif

#include <net/route.h>

#define VALIDATE_TID 0
MALLOC_DEFINE(M_CXGB, "cxgb", "Chelsio 10 Gigabit Ethernet and services");

TAILQ_HEAD(, cxgb_client) client_list;
TAILQ_HEAD(, t3cdev) ofld_dev_list;


static struct mtx cxgb_db_lock;


static int inited = 0;

static inline int
offload_activated(struct t3cdev *tdev)
{
	struct adapter *adapter = tdev2adap(tdev);
	
	return (isset(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT));
}

static inline void
register_tdev(struct t3cdev *tdev)
{
	static int unit;

	mtx_lock(&cxgb_db_lock);
	snprintf(tdev->name, sizeof(tdev->name), "ofld_dev%d", unit++);
	TAILQ_INSERT_TAIL(&ofld_dev_list, tdev, entry);
	mtx_unlock(&cxgb_db_lock);
}

static inline void
unregister_tdev(struct t3cdev *tdev)
{
	mtx_lock(&cxgb_db_lock);
	TAILQ_REMOVE(&ofld_dev_list, tdev, entry);
	mtx_unlock(&cxgb_db_lock);	
}

#ifdef TOE_ENABLED
/**
 *	cxgb_register_client - register an offload client
 *	@client: the client
 *
 *	Add the client to the client list,
 *	and call backs the client for each activated offload device
 */
void
cxgb_register_client(struct cxgb_client *client)
{
	struct t3cdev *tdev;

	mtx_lock(&cxgb_db_lock);
	TAILQ_INSERT_TAIL(&client_list, client, client_entry);

	if (client->add) {
		TAILQ_FOREACH(tdev, &ofld_dev_list, entry) {
			if (offload_activated(tdev)) {
				client->add(tdev);
			} else
				CTR1(KTR_CXGB,
				    "cxgb_register_client: %p not activated", tdev);
			
		}
	}
	mtx_unlock(&cxgb_db_lock);
}

/**
 *	cxgb_unregister_client - unregister an offload client
 *	@client: the client
 *
 *	Remove the client to the client list,
 *	and call backs the client for each activated offload device.
 */
void
cxgb_unregister_client(struct cxgb_client *client)
{
	struct t3cdev *tdev;

	mtx_lock(&cxgb_db_lock);
	TAILQ_REMOVE(&client_list, client, client_entry);

	if (client->remove) {
		TAILQ_FOREACH(tdev, &ofld_dev_list, entry) {
			if (offload_activated(tdev))
				client->remove(tdev);
		}
	}
	mtx_unlock(&cxgb_db_lock);
}

/**
 *	cxgb_add_clients - activate register clients for an offload device
 *	@tdev: the offload device
 *
 *	Call backs all registered clients once a offload device is activated 
 */
void
cxgb_add_clients(struct t3cdev *tdev)
{
	struct cxgb_client *client;

	mtx_lock(&cxgb_db_lock);
	TAILQ_FOREACH(client, &client_list, client_entry) {
		if (client->add)
			client->add(tdev);
	}
	mtx_unlock(&cxgb_db_lock);
}

/**
 *	cxgb_remove_clients - activate register clients for an offload device
 *	@tdev: the offload device
 *
 *	Call backs all registered clients once a offload device is deactivated 
 */
void
cxgb_remove_clients(struct t3cdev *tdev)
{
	struct cxgb_client *client;

	mtx_lock(&cxgb_db_lock);
	TAILQ_FOREACH(client, &client_list, client_entry) {
		if (client->remove)
			client->remove(tdev);
	}
	mtx_unlock(&cxgb_db_lock);
}
#endif

/**
 * cxgb_ofld_recv - process n received offload packets
 * @dev: the offload device
 * @m: an array of offload packets
 * @n: the number of offload packets
 *
 * Process an array of ingress offload packets.  Each packet is forwarded
 * to any active network taps and then passed to the offload device's receive
 * method.  We optimize passing packets to the receive method by passing
 * it the whole array at once except when there are active taps.
 */
int
cxgb_ofld_recv(struct t3cdev *dev, struct mbuf **m, int n)
{

	return dev->recv(dev, m, n);
}

/*
 * Dummy handler for Rx offload packets in case we get an offload packet before
 * proper processing is setup.  This complains and drops the packet as it isn't
 * normal to get offload packets at this stage.
 */
static int
rx_offload_blackhole(struct t3cdev *dev, struct mbuf **m, int n)
{
	while (n--)
		m_freem(m[n]);
	return 0;
}

static void
dummy_neigh_update(struct t3cdev *dev, struct rtentry *neigh, uint8_t *enaddr,
    struct sockaddr *sa)
{
}

void
cxgb_set_dummy_ops(struct t3cdev *dev)
{
	dev->recv         = rx_offload_blackhole;
	dev->arp_update = dummy_neigh_update;
}

static int
do_smt_write_rpl(struct t3cdev *dev, struct mbuf *m)
{
	struct cpl_smt_write_rpl *rpl = cplhdr(m);

	if (rpl->status != CPL_ERR_NONE)
		log(LOG_ERR,
		       "Unexpected SMT_WRITE_RPL status %u for entry %u\n",
		       rpl->status, GET_TID(rpl));

	return CPL_RET_BUF_DONE;
}

static int
do_l2t_write_rpl(struct t3cdev *dev, struct mbuf *m)
{
	struct cpl_l2t_write_rpl *rpl = cplhdr(m);

	if (rpl->status != CPL_ERR_NONE)
		log(LOG_ERR,
		       "Unexpected L2T_WRITE_RPL status %u for entry %u\n",
		       rpl->status, GET_TID(rpl));

	return CPL_RET_BUF_DONE;
}

static int
do_rte_write_rpl(struct t3cdev *dev, struct mbuf *m)
{
	struct cpl_rte_write_rpl *rpl = cplhdr(m);

	if (rpl->status != CPL_ERR_NONE)
		log(LOG_ERR,
		       "Unexpected L2T_WRITE_RPL status %u for entry %u\n",
		       rpl->status, GET_TID(rpl));

	return CPL_RET_BUF_DONE;
}

static int
do_set_tcb_rpl(struct t3cdev *dev, struct mbuf *m)
{
	struct cpl_set_tcb_rpl *rpl = cplhdr(m);

	if (rpl->status != CPL_ERR_NONE)
		log(LOG_ERR,
		    "Unexpected SET_TCB_RPL status %u for tid %u\n",
			rpl->status, GET_TID(rpl));
	return CPL_RET_BUF_DONE;
}

static int
do_trace(struct t3cdev *dev, struct mbuf *m)
{
#if 0
	struct cpl_trace_pkt *p = cplhdr(m);


	skb->protocol = 0xffff;
	skb->dev = dev->lldev;
	skb_pull(skb, sizeof(*p));
	skb->mac.raw = mtod(m, (char *));
	netif_receive_skb(skb);
#endif	
	return 0;
}

/*
 * Process a received packet with an unknown/unexpected CPL opcode.
 */
static int
do_bad_cpl(struct t3cdev *dev, struct mbuf *m)
{
	log(LOG_ERR, "%s: received bad CPL command 0x%x\n", dev->name,
	    0xFF & *mtod(m, uint32_t *));
	kdb_backtrace();
	return (CPL_RET_BUF_DONE | CPL_RET_BAD_MSG);
}

/*
 * Handlers for each CPL opcode
 */
static cpl_handler_func cpl_handlers[256];

/*
 * T3CDEV's receive method.
 */
int
process_rx(struct t3cdev *dev, struct mbuf **m, int n)
{
	while (n--) {
		struct mbuf *m0 = *m++;
		unsigned int opcode = G_OPCODE(ntohl(m0->m_pkthdr.csum_data));
		int ret;

		DPRINTF("processing op=0x%x m=%p data=%p\n", opcode, m0, m0->m_data);
		
		ret = cpl_handlers[opcode] (dev, m0);

#if VALIDATE_TID
		if (ret & CPL_RET_UNKNOWN_TID) {
			union opcode_tid *p = cplhdr(m0);

			log(LOG_ERR, "%s: CPL message (opcode %u) had "
			       "unknown TID %u\n", dev->name, opcode,<commit_msg>fix build breakage caused by undeclared kdb_backtrace()<commit_after>
/**************************************************************************

Copyright (c) 2007, Chelsio Inc.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 1. Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.

 2. Neither the name of the Chelsio Corporation nor the names of its
    contributors may be used to endorse or promote products derived from
    this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.


***************************************************************************/


#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/module.h>
#include <sys/pciio.h>
#include <sys/conf.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <sys/bus_dma.h>
#include <sys/rman.h>
#include <sys/ioccom.h>
#include <sys/mbuf.h>
#include <sys/linker.h>
#include <sys/firmware.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/smp.h>
#include <sys/sysctl.h>
#include <sys/syslog.h>
#include <sys/queue.h>
#include <sys/taskqueue.h>
#include <sys/proc.h>

#ifdef CONFIG_DEFINED
#include <cxgb_include.h>
#else
#include <dev/cxgb/cxgb_include.h>
#endif

#include <net/route.h>

#define VALIDATE_TID 0
MALLOC_DEFINE(M_CXGB, "cxgb", "Chelsio 10 Gigabit Ethernet and services");

TAILQ_HEAD(, cxgb_client) client_list;
TAILQ_HEAD(, t3cdev) ofld_dev_list;


static struct mtx cxgb_db_lock;


static int inited = 0;

static inline int
offload_activated(struct t3cdev *tdev)
{
	struct adapter *adapter = tdev2adap(tdev);
	
	return (isset(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT));
}

static inline void
register_tdev(struct t3cdev *tdev)
{
	static int unit;

	mtx_lock(&cxgb_db_lock);
	snprintf(tdev->name, sizeof(tdev->name), "ofld_dev%d", unit++);
	TAILQ_INSERT_TAIL(&ofld_dev_list, tdev, entry);
	mtx_unlock(&cxgb_db_lock);
}

static inline void
unregister_tdev(struct t3cdev *tdev)
{
	mtx_lock(&cxgb_db_lock);
	TAILQ_REMOVE(&ofld_dev_list, tdev, entry);
	mtx_unlock(&cxgb_db_lock);	
}

#ifdef TOE_ENABLED
/**
 *	cxgb_register_client - register an offload client
 *	@client: the client
 *
 *	Add the client to the client list,
 *	and call backs the client for each activated offload device
 */
void
cxgb_register_client(struct cxgb_client *client)
{
	struct t3cdev *tdev;

	mtx_lock(&cxgb_db_lock);
	TAILQ_INSERT_TAIL(&client_list, client, client_entry);

	if (client->add) {
		TAILQ_FOREACH(tdev, &ofld_dev_list, entry) {
			if (offload_activated(tdev)) {
				client->add(tdev);
			} else
				CTR1(KTR_CXGB,
				    "cxgb_register_client: %p not activated", tdev);
			
		}
	}
	mtx_unlock(&cxgb_db_lock);
}

/**
 *	cxgb_unregister_client - unregister an offload client
 *	@client: the client
 *
 *	Remove the client to the client list,
 *	and call backs the client for each activated offload device.
 */
void
cxgb_unregister_client(struct cxgb_client *client)
{
	struct t3cdev *tdev;

	mtx_lock(&cxgb_db_lock);
	TAILQ_REMOVE(&client_list, client, client_entry);

	if (client->remove) {
		TAILQ_FOREACH(tdev, &ofld_dev_list, entry) {
			if (offload_activated(tdev))
				client->remove(tdev);
		}
	}
	mtx_unlock(&cxgb_db_lock);
}

/**
 *	cxgb_add_clients - activate register clients for an offload device
 *	@tdev: the offload device
 *
 *	Call backs all registered clients once a offload device is activated 
 */
void
cxgb_add_clients(struct t3cdev *tdev)
{
	struct cxgb_client *client;

	mtx_lock(&cxgb_db_lock);
	TAILQ_FOREACH(client, &client_list, client_entry) {
		if (client->add)
			client->add(tdev);
	}
	mtx_unlock(&cxgb_db_lock);
}

/**
 *	cxgb_remove_clients - activate register clients for an offload device
 *	@tdev: the offload device
 *
 *	Call backs all registered clients once a offload device is deactivated 
 */
void
cxgb_remove_clients(struct t3cdev *tdev)
{
	struct cxgb_client *client;

	mtx_lock(&cxgb_db_lock);
	TAILQ_FOREACH(client, &client_list, client_entry) {
		if (client->remove)
			client->remove(tdev);
	}
	mtx_unlock(&cxgb_db_lock);
}
#endif

/**
 * cxgb_ofld_recv - process n received offload packets
 * @dev: the offload device
 * @m: an array of offload packets
 * @n: the number of offload packets
 *
 * Process an array of ingress offload packets.  Each packet is forwarded
 * to any active network taps and then passed to the offload device's receive
 * method.  We optimize passing packets to the receive method by passing
 * it the whole array at once except when there are active taps.
 */
int
cxgb_ofld_recv(struct t3cdev *dev, struct mbuf **m, int n)
{

	return dev->recv(dev, m, n);
}

/*
 * Dummy handler for Rx offload packets in case we get an offload packet before
 * proper processing is setup.  This complains and drops the packet as it isn't
 * normal to get offload packets at this stage.
 */
static int
rx_offload_blackhole(struct t3cdev *dev, struct mbuf **m, int n)
{
	while (n--)
		m_freem(m[n]);
	return 0;
}

static void
dummy_neigh_update(struct t3cdev *dev, struct rtentry *neigh, uint8_t *enaddr,
    struct sockaddr *sa)
{
}

void
cxgb_set_dummy_ops(struct t3cdev *dev)
{
	dev->recv         = rx_offload_blackhole;
	dev->arp_update = dummy_neigh_update;
}

static int
do_smt_write_rpl(struct t3cdev *dev, struct mbuf *m)
{
	struct cpl_smt_write_rpl *rpl = cplhdr(m);

	if (rpl->status != CPL_ERR_NONE)
		log(LOG_ERR,
		       "Unexpected SMT_WRITE_RPL status %u for entry %u\n",
		       rpl->status, GET_TID(rpl));

	return CPL_RET_BUF_DONE;
}

static int
do_l2t_write_rpl(struct t3cdev *dev, struct mbuf *m)
{
	struct cpl_l2t_write_rpl *rpl = cplhdr(m);

	if (rpl->status != CPL_ERR_NONE)
		log(LOG_ERR,
		       "Unexpected L2T_WRITE_RPL status %u for entry %u\n",
		       rpl->status, GET_TID(rpl));

	return CPL_RET_BUF_DONE;
}

static int
do_rte_write_rpl(struct t3cdev *dev, struct mbuf *m)
{
	struct cpl_rte_write_rpl *rpl = cplhdr(m);

	if (rpl->status != CPL_ERR_NONE)
		log(LOG_ERR,
		       "Unexpected L2T_WRITE_RPL status %u for entry %u\n",
		       rpl->status, GET_TID(rpl));

	return CPL_RET_BUF_DONE;
}

static int
do_set_tcb_rpl(struct t3cdev *dev, struct mbuf *m)
{
	struct cpl_set_tcb_rpl *rpl = cplhdr(m);

	if (rpl->status != CPL_ERR_NONE)
		log(LOG_ERR,
		    "Unexpected SET_TCB_RPL status %u for tid %u\n",
			rpl->status, GET_TID(rpl));
	return CPL_RET_BUF_DONE;
}

static int
do_trace(struct t3cdev *dev, struct mbuf *m)
{
#if 0
	struct cpl_trace_pkt *p = cplhdr(m);


	skb->protocol = 0xffff;
	skb->dev = dev->lldev;
	skb_pull(skb, sizeof(*p));
	skb->mac.raw = mtod(m, (char *));
	netif_receive_skb(skb);
#endif	
	return 0;
}

/*
 * Process a received packet with an unknown/unexpected CPL opcode.
 */
static int
do_bad_cpl(struct t3cdev *dev, struct mbuf *m)
{
	log(LOG_ERR, "%s: received bad CPL command 0x%x\n", dev->name,
	    0xFF & *mtod(m, uint32_t *));
	return (CPL_RET_BUF_DONE | CPL_RET_BAD_MSG);
}

/*
 * Handlers for each CPL opcode
 */
static cpl_handler_func cpl_handlers[256];

/*
 * T3CDEV's receive method.
 */
int
process_rx(struct t3cdev *dev, struct mbuf **m, int n)
{
	while (n--) {
		struct mbuf *m0 = *m++;
		unsigned int opcode = G_OPCODE(ntohl(m0->m_pkthdr.csum_data));
		int ret;

		DPRINTF("processing op=0x%x m=%p data=%p\n", opcode, m0, m0->m_data);
		
		ret = cpl_handlers[opcode] (dev, m0);

#if VALIDATE_TID
		if (ret & CPL_RET_UNKNOWN_TID) {
			union opcode_tid *p = cplhdr(m0);

			log(LOG_ERR, "%s: CPL message (opcode %u) had "
			       "unknown TID %u\n", dev->name, opcode,
{'fraction_non_alphanumeric': 0.12545841713001302, 'fraction_numerical': 0.006506565716313735, 'mean_word_length': 4.592788620575587, 'pattern_counts': {'":': 0, '<': 57, '<?xml version=': 0, '>': 117, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7458463', 'n_tokens_mistral': 6634, 'n_tokens_neox': 6270, 'n_words': 1768}