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