xref: /freebsd/sys/dev/cxgbe/t4_tracer.c (revision aa3860851b9f6a6002d135b1cac7736e0995eedc)
1caf20efcSNavdeep Parhar /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni  *
4caf20efcSNavdeep Parhar  * Copyright (c) 2013 Chelsio Communications, Inc.
5caf20efcSNavdeep Parhar  * All rights reserved.
6caf20efcSNavdeep Parhar  * Written by: Navdeep Parhar <np@FreeBSD.org>
7caf20efcSNavdeep Parhar  *
8caf20efcSNavdeep Parhar  * Redistribution and use in source and binary forms, with or without
9caf20efcSNavdeep Parhar  * modification, are permitted provided that the following conditions
10caf20efcSNavdeep Parhar  * are met:
11caf20efcSNavdeep Parhar  * 1. Redistributions of source code must retain the above copyright
12caf20efcSNavdeep Parhar  *    notice, this list of conditions and the following disclaimer.
13caf20efcSNavdeep Parhar  * 2. Redistributions in binary form must reproduce the above copyright
14caf20efcSNavdeep Parhar  *    notice, this list of conditions and the following disclaimer in the
15caf20efcSNavdeep Parhar  *    documentation and/or other materials provided with the distribution.
16caf20efcSNavdeep Parhar  *
17caf20efcSNavdeep Parhar  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18caf20efcSNavdeep Parhar  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19caf20efcSNavdeep Parhar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20caf20efcSNavdeep Parhar  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21caf20efcSNavdeep Parhar  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22caf20efcSNavdeep Parhar  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23caf20efcSNavdeep Parhar  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24caf20efcSNavdeep Parhar  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25caf20efcSNavdeep Parhar  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26caf20efcSNavdeep Parhar  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27caf20efcSNavdeep Parhar  * SUCH DAMAGE.
28caf20efcSNavdeep Parhar  */
29caf20efcSNavdeep Parhar 
30caf20efcSNavdeep Parhar #include <sys/cdefs.h>
31caf20efcSNavdeep Parhar #include "opt_inet.h"
32caf20efcSNavdeep Parhar #include "opt_inet6.h"
33caf20efcSNavdeep Parhar 
34caf20efcSNavdeep Parhar #include <sys/param.h>
35c3322cb9SGleb Smirnoff #include <sys/eventhandler.h>
36caf20efcSNavdeep Parhar #include <sys/lock.h>
37caf20efcSNavdeep Parhar #include <sys/types.h>
38caf20efcSNavdeep Parhar #include <sys/mbuf.h>
39caf20efcSNavdeep Parhar #include <sys/socket.h>
40caf20efcSNavdeep Parhar #include <sys/sockio.h>
41caf20efcSNavdeep Parhar #include <sys/sx.h>
42caf20efcSNavdeep Parhar #include <net/bpf.h>
43caf20efcSNavdeep Parhar #include <net/ethernet.h>
44caf20efcSNavdeep Parhar #include <net/if.h>
45caf20efcSNavdeep Parhar #include <net/if_clone.h>
46caf20efcSNavdeep Parhar #include <net/if_types.h>
47caf20efcSNavdeep Parhar 
48caf20efcSNavdeep Parhar #include "common/common.h"
49caf20efcSNavdeep Parhar #include "common/t4_msg.h"
50caf20efcSNavdeep Parhar #include "common/t4_regs.h"
51caf20efcSNavdeep Parhar #include "t4_ioctl.h"
52caf20efcSNavdeep Parhar 
53caf20efcSNavdeep Parhar /*
54caf20efcSNavdeep Parhar  * Locking notes
55caf20efcSNavdeep Parhar  * =============
56caf20efcSNavdeep Parhar  *
57caf20efcSNavdeep Parhar  * An interface cloner is registered during mod_load and it can be used to
58caf20efcSNavdeep Parhar  * create or destroy the tracing ifnet for an adapter at any time.  It is
59caf20efcSNavdeep Parhar  * possible for the cloned interface to outlive the adapter (adapter disappears
60caf20efcSNavdeep Parhar  * in t4_detach but the tracing ifnet may live till mod_unload when removal of
61caf20efcSNavdeep Parhar  * the cloner finally destroys any remaining cloned interfaces).  When tracing
62caf20efcSNavdeep Parhar  * filters are active, this ifnet is also receiving data.  There are potential
63caf20efcSNavdeep Parhar  * bad races between ifnet create, ifnet destroy, ifnet rx, ifnet ioctl,
64caf20efcSNavdeep Parhar  * cxgbe_detach/t4_detach, mod_unload.
65caf20efcSNavdeep Parhar  *
66caf20efcSNavdeep Parhar  * a) The driver selects an iq for tracing (sc->traceq) inside a synch op.  The
67caf20efcSNavdeep Parhar  *    iq is destroyed inside a synch op too (and sc->traceq updated).
68caf20efcSNavdeep Parhar  * b) The cloner looks for an adapter that matches the name of the ifnet it's
69caf20efcSNavdeep Parhar  *    been asked to create, starts a synch op on that adapter, and proceeds only
70caf20efcSNavdeep Parhar  *    if the adapter has a tracing iq.
71caf20efcSNavdeep Parhar  * c) The cloned ifnet and the adapter are coupled to each other via
72caf20efcSNavdeep Parhar  *    ifp->if_softc and sc->ifp.  These can be modified only with the global
73caf20efcSNavdeep Parhar  *    t4_trace_lock sx as well as the sc->ifp_lock mutex held.  Holding either
74caf20efcSNavdeep Parhar  *    of these will prevent any change.
75caf20efcSNavdeep Parhar  *
76caf20efcSNavdeep Parhar  * The order in which all the locks involved should be acquired are:
77caf20efcSNavdeep Parhar  * t4_list_lock
78caf20efcSNavdeep Parhar  * adapter lock
79caf20efcSNavdeep Parhar  * (begin synch op and let go of the above two)
80caf20efcSNavdeep Parhar  * t4_trace_lock
81caf20efcSNavdeep Parhar  * sc->ifp_lock
82caf20efcSNavdeep Parhar  */
83caf20efcSNavdeep Parhar 
84caf20efcSNavdeep Parhar static struct sx t4_trace_lock;
85caf20efcSNavdeep Parhar static const char *t4_cloner_name = "tXnex";
86caf20efcSNavdeep Parhar static struct if_clone *t4_cloner;
87caf20efcSNavdeep Parhar 
88caf20efcSNavdeep Parhar /* tracer ifnet routines.  mostly no-ops. */
89caf20efcSNavdeep Parhar static void tracer_init(void *);
90954712e8SJustin Hibbits static int tracer_ioctl(if_t, unsigned long, caddr_t);
91954712e8SJustin Hibbits static int tracer_transmit(if_t, struct mbuf *);
92954712e8SJustin Hibbits static void tracer_qflush(if_t);
93954712e8SJustin Hibbits static int tracer_media_change(if_t);
94954712e8SJustin Hibbits static void tracer_media_status(if_t, struct ifmediareq *);
95caf20efcSNavdeep Parhar 
96caf20efcSNavdeep Parhar /* match name (request/response) */
97caf20efcSNavdeep Parhar struct match_rr {
98caf20efcSNavdeep Parhar 	const char *name;
99caf20efcSNavdeep Parhar 	int lock;	/* set to 1 to returned sc locked. */
100caf20efcSNavdeep Parhar 	struct adapter *sc;
101caf20efcSNavdeep Parhar 	int rc;
102caf20efcSNavdeep Parhar };
103caf20efcSNavdeep Parhar 
104caf20efcSNavdeep Parhar static void
match_name(struct adapter * sc,void * arg)105caf20efcSNavdeep Parhar match_name(struct adapter *sc, void *arg)
106caf20efcSNavdeep Parhar {
107caf20efcSNavdeep Parhar 	struct match_rr *mrr = arg;
108caf20efcSNavdeep Parhar 
109caf20efcSNavdeep Parhar 	if (strcmp(device_get_nameunit(sc->dev), mrr->name) != 0)
110caf20efcSNavdeep Parhar 		return;
111caf20efcSNavdeep Parhar 
112caf20efcSNavdeep Parhar 	KASSERT(mrr->sc == NULL, ("%s: multiple matches (%p, %p) for %s",
113caf20efcSNavdeep Parhar 	    __func__, mrr->sc, sc, mrr->name));
114caf20efcSNavdeep Parhar 
115caf20efcSNavdeep Parhar 	mrr->sc = sc;
116caf20efcSNavdeep Parhar 	if (mrr->lock)
117caf20efcSNavdeep Parhar 		mrr->rc = begin_synchronized_op(mrr->sc, NULL, 0, "t4clon");
118caf20efcSNavdeep Parhar 	else
119caf20efcSNavdeep Parhar 		mrr->rc = 0;
120caf20efcSNavdeep Parhar }
121caf20efcSNavdeep Parhar 
122caf20efcSNavdeep Parhar static int
t4_cloner_match(struct if_clone * ifc,const char * name)123caf20efcSNavdeep Parhar t4_cloner_match(struct if_clone *ifc, const char *name)
124caf20efcSNavdeep Parhar {
125caf20efcSNavdeep Parhar 
126319a31eaSNavdeep Parhar 	if (strncmp(name, "t4nex", 5) != 0 &&
127e6b81479SNavdeep Parhar 	    strncmp(name, "t5nex", 5) != 0 &&
128e6b81479SNavdeep Parhar 	    strncmp(name, "t6nex", 5) != 0)
129319a31eaSNavdeep Parhar 		return (0);
130319a31eaSNavdeep Parhar 	if (name[5] < '0' || name[5] > '9')
131319a31eaSNavdeep Parhar 		return (0);
132319a31eaSNavdeep Parhar 	return (1);
133caf20efcSNavdeep Parhar }
134caf20efcSNavdeep Parhar 
135caf20efcSNavdeep Parhar static int
t4_cloner_create(struct if_clone * ifc,char * name,size_t len,caddr_t params)136caf20efcSNavdeep Parhar t4_cloner_create(struct if_clone *ifc, char *name, size_t len, caddr_t params)
137caf20efcSNavdeep Parhar {
138caf20efcSNavdeep Parhar 	struct match_rr mrr;
139caf20efcSNavdeep Parhar 	struct adapter *sc;
140954712e8SJustin Hibbits 	if_t ifp;
141*e203cb39SNavdeep Parhar 	int rc;
142caf20efcSNavdeep Parhar 	const uint8_t lla[ETHER_ADDR_LEN] = {0, 0, 0, 0, 0, 0};
143caf20efcSNavdeep Parhar 
144caf20efcSNavdeep Parhar 	mrr.name = name;
145caf20efcSNavdeep Parhar 	mrr.lock = 1;
146caf20efcSNavdeep Parhar 	mrr.sc = NULL;
147caf20efcSNavdeep Parhar 	mrr.rc = ENOENT;
148caf20efcSNavdeep Parhar 	t4_iterate(match_name, &mrr);
149caf20efcSNavdeep Parhar 
150caf20efcSNavdeep Parhar 	if (mrr.rc != 0)
151caf20efcSNavdeep Parhar 		return (mrr.rc);
152caf20efcSNavdeep Parhar 	sc = mrr.sc;
153caf20efcSNavdeep Parhar 
154caf20efcSNavdeep Parhar 	KASSERT(sc != NULL, ("%s: name (%s) matched but softc is NULL",
155caf20efcSNavdeep Parhar 	    __func__, name));
156caf20efcSNavdeep Parhar 	ASSERT_SYNCHRONIZED_OP(sc);
157caf20efcSNavdeep Parhar 
158caf20efcSNavdeep Parhar 	sx_xlock(&t4_trace_lock);
159caf20efcSNavdeep Parhar 
160caf20efcSNavdeep Parhar 	if (sc->ifp != NULL) {
161caf20efcSNavdeep Parhar 		rc = EEXIST;
162caf20efcSNavdeep Parhar 		goto done;
163caf20efcSNavdeep Parhar 	}
164caf20efcSNavdeep Parhar 	if (sc->traceq < 0) {
165caf20efcSNavdeep Parhar 		rc = EAGAIN;
166caf20efcSNavdeep Parhar 		goto done;
167caf20efcSNavdeep Parhar 	}
168caf20efcSNavdeep Parhar 
169caf20efcSNavdeep Parhar 	ifp = if_alloc(IFT_ETHER);
170*e203cb39SNavdeep Parhar 	/* Note that if_xname is identical to the nexus nameunit */
171*e203cb39SNavdeep Parhar 	if_initname(ifp, name, -1);
172954712e8SJustin Hibbits 	if_setdname(ifp, t4_cloner_name);
173954712e8SJustin Hibbits 	if_setinitfn(ifp, tracer_init);
174954712e8SJustin Hibbits 	if_setflags(ifp, IFF_SIMPLEX | IFF_DRV_RUNNING);
175954712e8SJustin Hibbits 	if_setioctlfn(ifp, tracer_ioctl);
176954712e8SJustin Hibbits 	if_settransmitfn(ifp, tracer_transmit);
177954712e8SJustin Hibbits 	if_setqflushfn(ifp, tracer_qflush);
178954712e8SJustin Hibbits 	if_setcapabilities(ifp, IFCAP_JUMBO_MTU | IFCAP_VLAN_MTU);
179caf20efcSNavdeep Parhar 	ifmedia_init(&sc->media, IFM_IMASK, tracer_media_change,
180caf20efcSNavdeep Parhar 	    tracer_media_status);
181caf20efcSNavdeep Parhar 	ifmedia_add(&sc->media, IFM_ETHER | IFM_FDX | IFM_NONE, 0, NULL);
182caf20efcSNavdeep Parhar 	ifmedia_set(&sc->media, IFM_ETHER | IFM_FDX | IFM_NONE);
183*e203cb39SNavdeep Parhar 	sx_xunlock(&t4_trace_lock);
184caf20efcSNavdeep Parhar 	ether_ifattach(ifp, lla);
185*e203cb39SNavdeep Parhar 	sx_xlock(&t4_trace_lock);
186caf20efcSNavdeep Parhar 	mtx_lock(&sc->ifp_lock);
187954712e8SJustin Hibbits 	if_setsoftc(ifp, sc);
188caf20efcSNavdeep Parhar 	sc->ifp = ifp;
189caf20efcSNavdeep Parhar 	mtx_unlock(&sc->ifp_lock);
190*e203cb39SNavdeep Parhar 	rc = 0;
191caf20efcSNavdeep Parhar done:
192caf20efcSNavdeep Parhar 	sx_xunlock(&t4_trace_lock);
193caf20efcSNavdeep Parhar 	end_synchronized_op(sc, 0);
194caf20efcSNavdeep Parhar 	return (rc);
195caf20efcSNavdeep Parhar }
196caf20efcSNavdeep Parhar 
197caf20efcSNavdeep Parhar static int
t4_cloner_destroy(struct if_clone * ifc,if_t ifp)198954712e8SJustin Hibbits t4_cloner_destroy(struct if_clone *ifc, if_t ifp)
199caf20efcSNavdeep Parhar {
200caf20efcSNavdeep Parhar 	struct adapter *sc;
201caf20efcSNavdeep Parhar 
202caf20efcSNavdeep Parhar 	sx_xlock(&t4_trace_lock);
203954712e8SJustin Hibbits 	sc = if_getsoftc(ifp);
204caf20efcSNavdeep Parhar 	if (sc != NULL) {
205caf20efcSNavdeep Parhar 		mtx_lock(&sc->ifp_lock);
206caf20efcSNavdeep Parhar 		sc->ifp = NULL;
207954712e8SJustin Hibbits 		if_setsoftc(ifp, NULL);
208caf20efcSNavdeep Parhar 		mtx_unlock(&sc->ifp_lock);
209caf20efcSNavdeep Parhar 		ifmedia_removeall(&sc->media);
210caf20efcSNavdeep Parhar 	}
211*e203cb39SNavdeep Parhar 	sx_xunlock(&t4_trace_lock);
212caf20efcSNavdeep Parhar 	ether_ifdetach(ifp);
213caf20efcSNavdeep Parhar 	if_free(ifp);
214caf20efcSNavdeep Parhar 
215caf20efcSNavdeep Parhar 	return (0);
216caf20efcSNavdeep Parhar }
217caf20efcSNavdeep Parhar 
218caf20efcSNavdeep Parhar void
t4_tracer_modload(void)21954e5efb2SDimitry Andric t4_tracer_modload(void)
220caf20efcSNavdeep Parhar {
221caf20efcSNavdeep Parhar 
222caf20efcSNavdeep Parhar 	sx_init(&t4_trace_lock, "T4/T5 tracer lock");
223caf20efcSNavdeep Parhar 	t4_cloner = if_clone_advanced(t4_cloner_name, 0, t4_cloner_match,
224caf20efcSNavdeep Parhar 	    t4_cloner_create, t4_cloner_destroy);
225caf20efcSNavdeep Parhar }
226caf20efcSNavdeep Parhar 
227caf20efcSNavdeep Parhar void
t4_tracer_modunload(void)22854e5efb2SDimitry Andric t4_tracer_modunload(void)
229caf20efcSNavdeep Parhar {
230caf20efcSNavdeep Parhar 
231caf20efcSNavdeep Parhar 	if (t4_cloner != NULL) {
232caf20efcSNavdeep Parhar 		/*
233caf20efcSNavdeep Parhar 		 * The module is being unloaded so the nexus drivers have
234caf20efcSNavdeep Parhar 		 * detached.  The tracing interfaces can not outlive the nexus
235caf20efcSNavdeep Parhar 		 * (ifp->if_softc is the nexus) and must have been destroyed
236caf20efcSNavdeep Parhar 		 * already.  XXX: but if_clone is opaque to us and we can't
237caf20efcSNavdeep Parhar 		 * assert LIST_EMPTY(&t4_cloner->ifc_iflist) at this time.
238caf20efcSNavdeep Parhar 		 */
239caf20efcSNavdeep Parhar 		if_clone_detach(t4_cloner);
240caf20efcSNavdeep Parhar 	}
241caf20efcSNavdeep Parhar 	sx_destroy(&t4_trace_lock);
242caf20efcSNavdeep Parhar }
243caf20efcSNavdeep Parhar 
244caf20efcSNavdeep Parhar void
t4_tracer_port_detach(struct adapter * sc)245caf20efcSNavdeep Parhar t4_tracer_port_detach(struct adapter *sc)
246caf20efcSNavdeep Parhar {
247caf20efcSNavdeep Parhar 
248caf20efcSNavdeep Parhar 	sx_xlock(&t4_trace_lock);
249caf20efcSNavdeep Parhar 	if (sc->ifp != NULL) {
250caf20efcSNavdeep Parhar 		mtx_lock(&sc->ifp_lock);
251954712e8SJustin Hibbits 		if_setsoftc(sc->ifp, NULL);
252caf20efcSNavdeep Parhar 		sc->ifp = NULL;
253caf20efcSNavdeep Parhar 		mtx_unlock(&sc->ifp_lock);
254caf20efcSNavdeep Parhar 	}
255caf20efcSNavdeep Parhar 	ifmedia_removeall(&sc->media);
256caf20efcSNavdeep Parhar 	sx_xunlock(&t4_trace_lock);
257caf20efcSNavdeep Parhar }
258caf20efcSNavdeep Parhar 
259caf20efcSNavdeep Parhar int
t4_get_tracer(struct adapter * sc,struct t4_tracer * t)260caf20efcSNavdeep Parhar t4_get_tracer(struct adapter *sc, struct t4_tracer *t)
261caf20efcSNavdeep Parhar {
262caf20efcSNavdeep Parhar 	int rc, i, enabled;
263caf20efcSNavdeep Parhar 	struct trace_params tp;
264caf20efcSNavdeep Parhar 
265caf20efcSNavdeep Parhar 	if (t->idx >= NTRACE) {
266caf20efcSNavdeep Parhar 		t->idx = 0xff;
267caf20efcSNavdeep Parhar 		t->enabled = 0;
268caf20efcSNavdeep Parhar 		t->valid = 0;
269caf20efcSNavdeep Parhar 		return (0);
270caf20efcSNavdeep Parhar 	}
271caf20efcSNavdeep Parhar 
272caf20efcSNavdeep Parhar 	rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK,
273caf20efcSNavdeep Parhar 	    "t4gett");
274caf20efcSNavdeep Parhar 	if (rc)
275caf20efcSNavdeep Parhar 		return (rc);
276caf20efcSNavdeep Parhar 
27783b5cda1SNavdeep Parhar 	if (hw_off_limits(sc)) {
27883b5cda1SNavdeep Parhar 		rc = ENXIO;
27983b5cda1SNavdeep Parhar 		goto done;
28083b5cda1SNavdeep Parhar 	}
28183b5cda1SNavdeep Parhar 
282caf20efcSNavdeep Parhar 	for (i = t->idx; i < NTRACE; i++) {
283caf20efcSNavdeep Parhar 		if (isset(&sc->tracer_valid, t->idx)) {
284caf20efcSNavdeep Parhar 			t4_get_trace_filter(sc, &tp, i, &enabled);
285caf20efcSNavdeep Parhar 			t->idx = i;
286caf20efcSNavdeep Parhar 			t->enabled = enabled;
287caf20efcSNavdeep Parhar 			t->valid = 1;
288caf20efcSNavdeep Parhar 			memcpy(&t->tp.data[0], &tp.data[0], sizeof(t->tp.data));
289caf20efcSNavdeep Parhar 			memcpy(&t->tp.mask[0], &tp.mask[0], sizeof(t->tp.mask));
290caf20efcSNavdeep Parhar 			t->tp.snap_len = tp.snap_len;
291caf20efcSNavdeep Parhar 			t->tp.min_len = tp.min_len;
292caf20efcSNavdeep Parhar 			t->tp.skip_ofst = tp.skip_ofst;
293caf20efcSNavdeep Parhar 			t->tp.skip_len = tp.skip_len;
294caf20efcSNavdeep Parhar 			t->tp.invert = tp.invert;
295caf20efcSNavdeep Parhar 
296caf20efcSNavdeep Parhar 			/* convert channel to port iff 0 <= port < 8. */
297caf20efcSNavdeep Parhar 			if (tp.port < 4)
298caf20efcSNavdeep Parhar 				t->tp.port = sc->chan_map[tp.port];
299caf20efcSNavdeep Parhar 			else if (tp.port < 8)
300caf20efcSNavdeep Parhar 				t->tp.port = sc->chan_map[tp.port - 4] + 4;
301caf20efcSNavdeep Parhar 			else
302caf20efcSNavdeep Parhar 				t->tp.port = tp.port;
303caf20efcSNavdeep Parhar 
304caf20efcSNavdeep Parhar 			goto done;
305caf20efcSNavdeep Parhar 		}
306caf20efcSNavdeep Parhar 	}
307caf20efcSNavdeep Parhar 
308caf20efcSNavdeep Parhar 	t->idx = 0xff;
309caf20efcSNavdeep Parhar 	t->enabled = 0;
310caf20efcSNavdeep Parhar 	t->valid = 0;
311caf20efcSNavdeep Parhar done:
312caf20efcSNavdeep Parhar 	end_synchronized_op(sc, LOCK_HELD);
313caf20efcSNavdeep Parhar 
314caf20efcSNavdeep Parhar 	return (rc);
315caf20efcSNavdeep Parhar }
316caf20efcSNavdeep Parhar 
317caf20efcSNavdeep Parhar int
t4_set_tracer(struct adapter * sc,struct t4_tracer * t)318caf20efcSNavdeep Parhar t4_set_tracer(struct adapter *sc, struct t4_tracer *t)
319caf20efcSNavdeep Parhar {
320caf20efcSNavdeep Parhar 	int rc;
321caf20efcSNavdeep Parhar 	struct trace_params tp, *tpp;
322caf20efcSNavdeep Parhar 
323caf20efcSNavdeep Parhar 	if (t->idx >= NTRACE)
324caf20efcSNavdeep Parhar 		return (EINVAL);
325caf20efcSNavdeep Parhar 
326caf20efcSNavdeep Parhar 	rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK,
327caf20efcSNavdeep Parhar 	    "t4sett");
328caf20efcSNavdeep Parhar 	if (rc)
329caf20efcSNavdeep Parhar 		return (rc);
330caf20efcSNavdeep Parhar 
33183b5cda1SNavdeep Parhar 	if (hw_off_limits(sc)) {
33283b5cda1SNavdeep Parhar 		rc = ENXIO;
33383b5cda1SNavdeep Parhar 		goto done;
33483b5cda1SNavdeep Parhar 	}
33583b5cda1SNavdeep Parhar 
336caf20efcSNavdeep Parhar 	/*
337caf20efcSNavdeep Parhar 	 * If no tracing filter is specified this time then check if the filter
338caf20efcSNavdeep Parhar 	 * at the index is valid anyway because it was set previously.  If so
339caf20efcSNavdeep Parhar 	 * then this is a legitimate enable/disable operation.
340caf20efcSNavdeep Parhar 	 */
341caf20efcSNavdeep Parhar 	if (t->valid == 0) {
342caf20efcSNavdeep Parhar 		if (isset(&sc->tracer_valid, t->idx))
343caf20efcSNavdeep Parhar 			tpp = NULL;
344caf20efcSNavdeep Parhar 		else
345caf20efcSNavdeep Parhar 			rc = EINVAL;
346caf20efcSNavdeep Parhar 		goto done;
347caf20efcSNavdeep Parhar 	}
348caf20efcSNavdeep Parhar 
349caf20efcSNavdeep Parhar 	if (t->tp.port > 19 || t->tp.snap_len > 9600 ||
350caf20efcSNavdeep Parhar 	    t->tp.min_len > M_TFMINPKTSIZE || t->tp.skip_len > M_TFLENGTH ||
351caf20efcSNavdeep Parhar 	    t->tp.skip_ofst > M_TFOFFSET) {
352caf20efcSNavdeep Parhar 		rc = EINVAL;
353caf20efcSNavdeep Parhar 		goto done;
354caf20efcSNavdeep Parhar 	}
355caf20efcSNavdeep Parhar 
356caf20efcSNavdeep Parhar 	memcpy(&tp.data[0], &t->tp.data[0], sizeof(tp.data));
357caf20efcSNavdeep Parhar 	memcpy(&tp.mask[0], &t->tp.mask[0], sizeof(tp.mask));
358caf20efcSNavdeep Parhar 	tp.snap_len = t->tp.snap_len;
359caf20efcSNavdeep Parhar 	tp.min_len = t->tp.min_len;
360caf20efcSNavdeep Parhar 	tp.skip_ofst = t->tp.skip_ofst;
361caf20efcSNavdeep Parhar 	tp.skip_len = t->tp.skip_len;
362caf20efcSNavdeep Parhar 	tp.invert = !!t->tp.invert;
363caf20efcSNavdeep Parhar 
364caf20efcSNavdeep Parhar 	/* convert port to channel iff 0 <= port < 8. */
365caf20efcSNavdeep Parhar 	if (t->tp.port < 4) {
366caf20efcSNavdeep Parhar 		if (sc->port[t->tp.port] == NULL) {
367caf20efcSNavdeep Parhar 			rc = EINVAL;
368caf20efcSNavdeep Parhar 			goto done;
369caf20efcSNavdeep Parhar 		}
370caf20efcSNavdeep Parhar 		tp.port = sc->port[t->tp.port]->tx_chan;
371caf20efcSNavdeep Parhar 	} else if (t->tp.port < 8) {
372caf20efcSNavdeep Parhar 		if (sc->port[t->tp.port - 4] == NULL) {
373caf20efcSNavdeep Parhar 			rc = EINVAL;
374caf20efcSNavdeep Parhar 			goto done;
375caf20efcSNavdeep Parhar 		}
376caf20efcSNavdeep Parhar 		tp.port = sc->port[t->tp.port - 4]->tx_chan + 4;
3779f354cd3SNavdeep Parhar 	} else
3789f354cd3SNavdeep Parhar 		tp.port = t->tp.port;
379caf20efcSNavdeep Parhar 	tpp = &tp;
380caf20efcSNavdeep Parhar done:
381caf20efcSNavdeep Parhar 	if (rc == 0) {
382caf20efcSNavdeep Parhar 		rc = -t4_set_trace_filter(sc, tpp, t->idx, t->enabled);
383caf20efcSNavdeep Parhar 		if (rc == 0) {
384caf20efcSNavdeep Parhar 			if (t->enabled) {
385caf20efcSNavdeep Parhar 				setbit(&sc->tracer_valid, t->idx);
386caf20efcSNavdeep Parhar 				if (sc->tracer_enabled == 0) {
387caf20efcSNavdeep Parhar 					t4_set_reg_field(sc, A_MPS_TRC_CFG,
388caf20efcSNavdeep Parhar 					    F_TRCEN, F_TRCEN);
389caf20efcSNavdeep Parhar 				}
390caf20efcSNavdeep Parhar 				setbit(&sc->tracer_enabled, t->idx);
391caf20efcSNavdeep Parhar 			} else {
392caf20efcSNavdeep Parhar 				clrbit(&sc->tracer_enabled, t->idx);
393caf20efcSNavdeep Parhar 				if (sc->tracer_enabled == 0) {
394caf20efcSNavdeep Parhar 					t4_set_reg_field(sc, A_MPS_TRC_CFG,
395caf20efcSNavdeep Parhar 					    F_TRCEN, 0);
396caf20efcSNavdeep Parhar 				}
397caf20efcSNavdeep Parhar 			}
398caf20efcSNavdeep Parhar 		}
399caf20efcSNavdeep Parhar 	}
400caf20efcSNavdeep Parhar 	end_synchronized_op(sc, LOCK_HELD);
401caf20efcSNavdeep Parhar 
402caf20efcSNavdeep Parhar 	return (rc);
403caf20efcSNavdeep Parhar }
404caf20efcSNavdeep Parhar 
405caf20efcSNavdeep Parhar int
t4_trace_pkt(struct sge_iq * iq,const struct rss_header * rss,struct mbuf * m)406caf20efcSNavdeep Parhar t4_trace_pkt(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m)
407caf20efcSNavdeep Parhar {
408caf20efcSNavdeep Parhar 	struct adapter *sc = iq->adapter;
409954712e8SJustin Hibbits 	if_t ifp;
410caf20efcSNavdeep Parhar 
411caf20efcSNavdeep Parhar 	KASSERT(m != NULL, ("%s: no payload with opcode %02x", __func__,
412caf20efcSNavdeep Parhar 	    rss->opcode));
413caf20efcSNavdeep Parhar 
414caf20efcSNavdeep Parhar 	mtx_lock(&sc->ifp_lock);
415caf20efcSNavdeep Parhar 	ifp = sc->ifp;
416caf20efcSNavdeep Parhar 	if (sc->ifp) {
417caf20efcSNavdeep Parhar 		m_adj(m, sizeof(struct cpl_trace_pkt));
418caf20efcSNavdeep Parhar 		m->m_pkthdr.rcvif = ifp;
419caf20efcSNavdeep Parhar 		ETHER_BPF_MTAP(ifp, m);
420caf20efcSNavdeep Parhar 	}
421caf20efcSNavdeep Parhar 	mtx_unlock(&sc->ifp_lock);
422caf20efcSNavdeep Parhar 	m_freem(m);
423caf20efcSNavdeep Parhar 
424caf20efcSNavdeep Parhar 	return (0);
425caf20efcSNavdeep Parhar }
426caf20efcSNavdeep Parhar 
427caf20efcSNavdeep Parhar int
t5_trace_pkt(struct sge_iq * iq,const struct rss_header * rss,struct mbuf * m)428caf20efcSNavdeep Parhar t5_trace_pkt(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m)
429caf20efcSNavdeep Parhar {
430caf20efcSNavdeep Parhar 	struct adapter *sc = iq->adapter;
431954712e8SJustin Hibbits 	if_t ifp;
432caf20efcSNavdeep Parhar 
433caf20efcSNavdeep Parhar 	KASSERT(m != NULL, ("%s: no payload with opcode %02x", __func__,
434caf20efcSNavdeep Parhar 	    rss->opcode));
435caf20efcSNavdeep Parhar 
436caf20efcSNavdeep Parhar 	mtx_lock(&sc->ifp_lock);
437caf20efcSNavdeep Parhar 	ifp = sc->ifp;
438caf20efcSNavdeep Parhar 	if (ifp != NULL) {
439caf20efcSNavdeep Parhar 		m_adj(m, sizeof(struct cpl_t5_trace_pkt));
440caf20efcSNavdeep Parhar 		m->m_pkthdr.rcvif = ifp;
441caf20efcSNavdeep Parhar 		ETHER_BPF_MTAP(ifp, m);
442caf20efcSNavdeep Parhar 	}
443caf20efcSNavdeep Parhar 	mtx_unlock(&sc->ifp_lock);
444caf20efcSNavdeep Parhar 	m_freem(m);
445caf20efcSNavdeep Parhar 
446caf20efcSNavdeep Parhar 	return (0);
447caf20efcSNavdeep Parhar }
448caf20efcSNavdeep Parhar 
449caf20efcSNavdeep Parhar 
450caf20efcSNavdeep Parhar static void
tracer_init(void * arg)451caf20efcSNavdeep Parhar tracer_init(void *arg)
452caf20efcSNavdeep Parhar {
453caf20efcSNavdeep Parhar 
454caf20efcSNavdeep Parhar 	return;
455caf20efcSNavdeep Parhar }
456caf20efcSNavdeep Parhar 
457caf20efcSNavdeep Parhar static int
tracer_ioctl(if_t ifp,unsigned long cmd,caddr_t data)458954712e8SJustin Hibbits tracer_ioctl(if_t ifp, unsigned long cmd, caddr_t data)
459caf20efcSNavdeep Parhar {
460caf20efcSNavdeep Parhar 	int rc = 0;
461caf20efcSNavdeep Parhar 	struct adapter *sc;
462caf20efcSNavdeep Parhar 	struct ifreq *ifr = (struct ifreq *)data;
463caf20efcSNavdeep Parhar 
464caf20efcSNavdeep Parhar 	switch (cmd) {
465caf20efcSNavdeep Parhar 	case SIOCSIFMTU:
466caf20efcSNavdeep Parhar 	case SIOCSIFFLAGS:
467caf20efcSNavdeep Parhar 	case SIOCADDMULTI:
468caf20efcSNavdeep Parhar 	case SIOCDELMULTI:
469caf20efcSNavdeep Parhar 	case SIOCSIFCAP:
470caf20efcSNavdeep Parhar 		break;
471caf20efcSNavdeep Parhar 	case SIOCSIFMEDIA:
472caf20efcSNavdeep Parhar 	case SIOCGIFMEDIA:
473d44268d1SNavdeep Parhar 	case SIOCGIFXMEDIA:
474caf20efcSNavdeep Parhar 		sx_xlock(&t4_trace_lock);
475954712e8SJustin Hibbits 		sc = if_getsoftc(ifp);
476caf20efcSNavdeep Parhar 		if (sc == NULL)
477caf20efcSNavdeep Parhar 			rc = EIO;
478caf20efcSNavdeep Parhar 		else
479caf20efcSNavdeep Parhar 			rc = ifmedia_ioctl(ifp, ifr, &sc->media, cmd);
480caf20efcSNavdeep Parhar 		sx_xunlock(&t4_trace_lock);
481caf20efcSNavdeep Parhar 		break;
482caf20efcSNavdeep Parhar 	default:
483caf20efcSNavdeep Parhar 		rc = ether_ioctl(ifp, cmd, data);
484caf20efcSNavdeep Parhar 	}
485caf20efcSNavdeep Parhar 
486caf20efcSNavdeep Parhar 	return (rc);
487caf20efcSNavdeep Parhar }
488caf20efcSNavdeep Parhar 
489caf20efcSNavdeep Parhar static int
tracer_transmit(if_t ifp,struct mbuf * m)490954712e8SJustin Hibbits tracer_transmit(if_t ifp, struct mbuf *m)
491caf20efcSNavdeep Parhar {
492caf20efcSNavdeep Parhar 
493caf20efcSNavdeep Parhar 	m_freem(m);
494caf20efcSNavdeep Parhar 	return (0);
495caf20efcSNavdeep Parhar }
496caf20efcSNavdeep Parhar 
497caf20efcSNavdeep Parhar static void
tracer_qflush(if_t ifp)498954712e8SJustin Hibbits tracer_qflush(if_t ifp)
499caf20efcSNavdeep Parhar {
500caf20efcSNavdeep Parhar 
501caf20efcSNavdeep Parhar 	return;
502caf20efcSNavdeep Parhar }
503caf20efcSNavdeep Parhar 
504caf20efcSNavdeep Parhar static int
tracer_media_change(if_t ifp)505954712e8SJustin Hibbits tracer_media_change(if_t ifp)
506caf20efcSNavdeep Parhar {
507caf20efcSNavdeep Parhar 
508caf20efcSNavdeep Parhar 	return (EOPNOTSUPP);
509caf20efcSNavdeep Parhar }
510caf20efcSNavdeep Parhar 
511caf20efcSNavdeep Parhar static void
tracer_media_status(if_t ifp,struct ifmediareq * ifmr)512954712e8SJustin Hibbits tracer_media_status(if_t ifp, struct ifmediareq *ifmr)
513caf20efcSNavdeep Parhar {
514caf20efcSNavdeep Parhar 
515caf20efcSNavdeep Parhar 	ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
516caf20efcSNavdeep Parhar 
517caf20efcSNavdeep Parhar 	return;
518caf20efcSNavdeep Parhar }
519