xref: /freebsd/sys/dev/firewire/if_fwip.c (revision 4d47c7ca7baa1ae76cc1fc72ec85b475f1efd41d)
1098ca2bdSWarner Losh /*-
2df57947fSPedro F. Giffuni  * SPDX-License-Identifier: BSD-4-Clause
3df57947fSPedro F. Giffuni  *
4b8b33234SDoug Rabson  * Copyright (c) 2004
5b8b33234SDoug Rabson  *	Doug Rabson
6b8b33234SDoug Rabson  * Copyright (c) 2002-2003
7b8b33234SDoug Rabson  * 	Hidetoshi Shimokawa. All rights reserved.
8b8b33234SDoug Rabson  *
9b8b33234SDoug Rabson  * Redistribution and use in source and binary forms, with or without
10b8b33234SDoug Rabson  * modification, are permitted provided that the following conditions
11b8b33234SDoug Rabson  * are met:
12b8b33234SDoug Rabson  * 1. Redistributions of source code must retain the above copyright
13b8b33234SDoug Rabson  *    notice, this list of conditions and the following disclaimer.
14b8b33234SDoug Rabson  * 2. Redistributions in binary form must reproduce the above copyright
15b8b33234SDoug Rabson  *    notice, this list of conditions and the following disclaimer in the
16b8b33234SDoug Rabson  *    documentation and/or other materials provided with the distribution.
17b8b33234SDoug Rabson  * 3. All advertising materials mentioning features or use of this software
18b8b33234SDoug Rabson  *    must display the following acknowledgement:
19b8b33234SDoug Rabson  *
20b8b33234SDoug Rabson  *	This product includes software developed by Hidetoshi Shimokawa.
21b8b33234SDoug Rabson  *
22b8b33234SDoug Rabson  * 4. Neither the name of the author nor the names of its contributors
23b8b33234SDoug Rabson  *    may be used to endorse or promote products derived from this software
24b8b33234SDoug Rabson  *    without specific prior written permission.
25b8b33234SDoug Rabson  *
26b8b33234SDoug Rabson  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27b8b33234SDoug Rabson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28b8b33234SDoug Rabson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29b8b33234SDoug Rabson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30b8b33234SDoug Rabson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31b8b33234SDoug Rabson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32b8b33234SDoug Rabson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33b8b33234SDoug Rabson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34b8b33234SDoug Rabson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35b8b33234SDoug Rabson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36b8b33234SDoug Rabson  * SUCH DAMAGE.
37b8b33234SDoug Rabson  *
38b8b33234SDoug Rabson  */
39b8b33234SDoug Rabson 
40f0796cd2SGleb Smirnoff #ifdef HAVE_KERNEL_OPTION_HEADERS
41f0796cd2SGleb Smirnoff #include "opt_device_polling.h"
42b8b33234SDoug Rabson #include "opt_inet.h"
43f0796cd2SGleb Smirnoff #endif
44b8b33234SDoug Rabson 
45b8b33234SDoug Rabson #include <sys/param.h>
46b8b33234SDoug Rabson #include <sys/kernel.h>
47b8b33234SDoug Rabson #include <sys/malloc.h>
48b8b33234SDoug Rabson #include <sys/mbuf.h>
49b8b33234SDoug Rabson #include <sys/socket.h>
50b8b33234SDoug Rabson #include <sys/sockio.h>
51b8b33234SDoug Rabson #include <sys/sysctl.h>
52b8b33234SDoug Rabson #include <sys/systm.h>
53b8b33234SDoug Rabson #include <sys/taskqueue.h>
54b8b33234SDoug Rabson #include <sys/module.h>
55b8b33234SDoug Rabson #include <sys/bus.h>
56b8b33234SDoug Rabson #include <machine/bus.h>
57b8b33234SDoug Rabson 
58b8b33234SDoug Rabson #include <net/bpf.h>
59b8b33234SDoug Rabson #include <net/if.h>
6076039bc8SGleb Smirnoff #include <net/if_var.h>
61b8b33234SDoug Rabson #include <net/firewire.h>
62b8b33234SDoug Rabson #include <net/if_arp.h>
63fc74a9f9SBrooks Davis #include <net/if_types.h>
64b8b33234SDoug Rabson #include <dev/firewire/firewire.h>
65b8b33234SDoug Rabson #include <dev/firewire/firewirereg.h>
6604fa3b29SDoug Rabson #include <dev/firewire/iec13213.h>
67b8b33234SDoug Rabson #include <dev/firewire/if_fwipvar.h>
68b8b33234SDoug Rabson 
69b8b33234SDoug Rabson /*
70b8b33234SDoug Rabson  * We really need a mechanism for allocating regions in the FIFO
71b8b33234SDoug Rabson  * address space. We pick a address in the OHCI controller's 'middle'
72b8b33234SDoug Rabson  * address space. This means that the controller will automatically
73b8b33234SDoug Rabson  * send responses for us, which is fine since we don't have any
74b8b33234SDoug Rabson  * important information to put in the response anyway.
75b8b33234SDoug Rabson  */
76b8b33234SDoug Rabson #define INET_FIFO	0xfffe00000000LL
77b8b33234SDoug Rabson 
78b8b33234SDoug Rabson #define FWIPDEBUG	if (fwipdebug) if_printf
79b8b33234SDoug Rabson #define TX_MAX_QUEUE	(FWMAXQUEUE - 1)
80b8b33234SDoug Rabson 
81b8b33234SDoug Rabson /* network interface */
8261c05f13SJustin Hibbits static void fwip_start (if_t);
8361c05f13SJustin Hibbits static int fwip_ioctl (if_t, u_long, caddr_t);
84b8b33234SDoug Rabson static void fwip_init (void *);
85b8b33234SDoug Rabson 
86b8b33234SDoug Rabson static void fwip_post_busreset (void *);
87b8b33234SDoug Rabson static void fwip_output_callback (struct fw_xfer *);
8861c05f13SJustin Hibbits static void fwip_async_output (struct fwip_softc *, if_t);
89b8b33234SDoug Rabson static void fwip_start_send (void *, int);
90b8b33234SDoug Rabson static void fwip_stream_input (struct fw_xferq *);
91b8b33234SDoug Rabson static void fwip_unicast_input(struct fw_xfer *);
92b8b33234SDoug Rabson 
93b8b33234SDoug Rabson static int fwipdebug = 0;
942f8e2ebbSDoug Rabson static int broadcast_channel = 0xc0 | 0x1f; /*  tag | channel(XXX) */
95b8b33234SDoug Rabson static int tx_speed = 2;
96b8b33234SDoug Rabson static int rx_queue_len = FWMAXQUEUE;
97b8b33234SDoug Rabson 
98d745c852SEd Schouten static MALLOC_DEFINE(M_FWIP, "if_fwip", "IP over FireWire interface");
99b8b33234SDoug Rabson SYSCTL_INT(_debug, OID_AUTO, if_fwip_debug, CTLFLAG_RW, &fwipdebug, 0, "");
100b8b33234SDoug Rabson SYSCTL_DECL(_hw_firewire);
1017029da5cSPawel Biernacki static SYSCTL_NODE(_hw_firewire, OID_AUTO, fwip, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
102b8b33234SDoug Rabson 	"Firewire ip subsystem");
103af3b2549SHans Petter Selasky SYSCTL_INT(_hw_firewire_fwip, OID_AUTO, rx_queue_len, CTLFLAG_RWTUN, &rx_queue_len,
104b8b33234SDoug Rabson 	0, "Length of the receive queue");
105b8b33234SDoug Rabson 
106b8b33234SDoug Rabson #ifdef DEVICE_POLLING
107b8b33234SDoug Rabson static poll_handler_t fwip_poll;
108b8b33234SDoug Rabson 
1091abcdbd1SAttilio Rao static int
fwip_poll(if_t ifp,enum poll_cmd cmd,int count)11061c05f13SJustin Hibbits fwip_poll(if_t ifp, enum poll_cmd cmd, int count)
111b8b33234SDoug Rabson {
112b8b33234SDoug Rabson 	struct fwip_softc *fwip;
113b8b33234SDoug Rabson 	struct firewire_comm *fc;
114b8b33234SDoug Rabson 
11561c05f13SJustin Hibbits 	if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING))
1161abcdbd1SAttilio Rao 		return (0);
11740929967SGleb Smirnoff 
11861c05f13SJustin Hibbits 	fwip = ((struct fwip_eth_softc *)if_getsoftc(ifp))->fwip;
119b8b33234SDoug Rabson 	fc = fwip->fd.fc;
120b8b33234SDoug Rabson 	fc->poll(fc, (cmd == POLL_AND_CHECK_STATUS)?0:1, count);
1211abcdbd1SAttilio Rao 	return (0);
122b8b33234SDoug Rabson }
12340929967SGleb Smirnoff #endif /* DEVICE_POLLING */
12440929967SGleb Smirnoff 
125b8b33234SDoug Rabson static void
fwip_identify(driver_t * driver,device_t parent)126b8b33234SDoug Rabson fwip_identify(driver_t *driver, device_t parent)
127b8b33234SDoug Rabson {
128b8b33234SDoug Rabson 	BUS_ADD_CHILD(parent, 0, "fwip", device_get_unit(parent));
129b8b33234SDoug Rabson }
130b8b33234SDoug Rabson 
131b8b33234SDoug Rabson static int
fwip_probe(device_t dev)132b8b33234SDoug Rabson fwip_probe(device_t dev)
133b8b33234SDoug Rabson {
134b8b33234SDoug Rabson 	device_t pa;
135b8b33234SDoug Rabson 
136b8b33234SDoug Rabson 	pa = device_get_parent(dev);
137b8b33234SDoug Rabson 	if (device_get_unit(dev) != device_get_unit(pa)) {
138b8b33234SDoug Rabson 		return (ENXIO);
139b8b33234SDoug Rabson 	}
140b8b33234SDoug Rabson 
141b8b33234SDoug Rabson 	device_set_desc(dev, "IP over FireWire");
142b8b33234SDoug Rabson 	return (0);
143b8b33234SDoug Rabson }
144b8b33234SDoug Rabson 
145b8b33234SDoug Rabson static int
fwip_attach(device_t dev)146b8b33234SDoug Rabson fwip_attach(device_t dev)
147b8b33234SDoug Rabson {
148b8b33234SDoug Rabson 	struct fwip_softc *fwip;
14961c05f13SJustin Hibbits 	if_t ifp;
150b8b33234SDoug Rabson 	int unit, s;
151b8b33234SDoug Rabson 	struct fw_hwaddr *hwaddr;
152b8b33234SDoug Rabson 
153b8b33234SDoug Rabson 	fwip = ((struct fwip_softc *)device_get_softc(dev));
154b8b33234SDoug Rabson 	unit = device_get_unit(dev);
155fc74a9f9SBrooks Davis 	ifp = fwip->fw_softc.fwip_ifp = if_alloc(IFT_IEEE1394);
156b8b33234SDoug Rabson 
1579950b741SHidetoshi Shimokawa 	mtx_init(&fwip->mtx, "fwip", NULL, MTX_DEF);
158b8b33234SDoug Rabson 	/* XXX */
159b8b33234SDoug Rabson 	fwip->dma_ch = -1;
160b8b33234SDoug Rabson 
161b8b33234SDoug Rabson 	fwip->fd.fc = device_get_ivars(dev);
162b8b33234SDoug Rabson 	if (tx_speed < 0)
163b8b33234SDoug Rabson 		tx_speed = fwip->fd.fc->speed;
164b8b33234SDoug Rabson 
165b8b33234SDoug Rabson 	fwip->fd.dev = dev;
166b8b33234SDoug Rabson 	fwip->fd.post_explore = NULL;
167b8b33234SDoug Rabson 	fwip->fd.post_busreset = fwip_post_busreset;
168b8b33234SDoug Rabson 	fwip->fw_softc.fwip = fwip;
169b8b33234SDoug Rabson 	TASK_INIT(&fwip->start_send, 0, fwip_start_send, fwip);
170b8b33234SDoug Rabson 
171b8b33234SDoug Rabson 	/*
172b8b33234SDoug Rabson 	 * Encode our hardware the way that arp likes it.
173b8b33234SDoug Rabson 	 */
174fc74a9f9SBrooks Davis 	hwaddr = &IFP2FWC(fwip->fw_softc.fwip_ifp)->fc_hwaddr;
175b8b33234SDoug Rabson 	hwaddr->sender_unique_ID_hi = htonl(fwip->fd.fc->eui.hi);
176b8b33234SDoug Rabson 	hwaddr->sender_unique_ID_lo = htonl(fwip->fd.fc->eui.lo);
177b8b33234SDoug Rabson 	hwaddr->sender_max_rec = fwip->fd.fc->maxrec;
178b8b33234SDoug Rabson 	hwaddr->sspd = fwip->fd.fc->speed;
179b8b33234SDoug Rabson 	hwaddr->sender_unicast_FIFO_hi = htons((uint16_t)(INET_FIFO >> 32));
180b8b33234SDoug Rabson 	hwaddr->sender_unicast_FIFO_lo = htonl((uint32_t)INET_FIFO);
181b8b33234SDoug Rabson 
182b8b33234SDoug Rabson 	/* fill the rest and attach interface */
18361c05f13SJustin Hibbits 	if_setsoftc(ifp, &fwip->fw_softc);
184b8b33234SDoug Rabson 
185b8b33234SDoug Rabson 	if_initname(ifp, device_get_name(dev), unit);
18661c05f13SJustin Hibbits 	if_setinitfn(ifp, fwip_init);
18761c05f13SJustin Hibbits 	if_setstartfn(ifp, fwip_start);
18861c05f13SJustin Hibbits 	if_setioctlfn(ifp, fwip_ioctl);
18961c05f13SJustin Hibbits 	if_setflags(ifp, (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST));
19061c05f13SJustin Hibbits 	if_setsendqlen(ifp, TX_MAX_QUEUE);
19140929967SGleb Smirnoff #ifdef DEVICE_POLLING
19261c05f13SJustin Hibbits 	if_setcapabilitiesbit(ifp, IFCAP_POLLING, 0);
19340929967SGleb Smirnoff #endif
194b8b33234SDoug Rabson 
195b8b33234SDoug Rabson 	s = splimp();
196b8b33234SDoug Rabson 	firewire_ifattach(ifp, hwaddr);
197b8b33234SDoug Rabson 	splx(s);
198b8b33234SDoug Rabson 
199b8b33234SDoug Rabson 	FWIPDEBUG(ifp, "interface created\n");
200aa386085SZhenlei Huang 	return (0);
201b8b33234SDoug Rabson }
202b8b33234SDoug Rabson 
203b8b33234SDoug Rabson static void
fwip_stop(struct fwip_softc * fwip)204b8b33234SDoug Rabson fwip_stop(struct fwip_softc *fwip)
205b8b33234SDoug Rabson {
206b8b33234SDoug Rabson 	struct firewire_comm *fc;
207b8b33234SDoug Rabson 	struct fw_xferq *xferq;
20861c05f13SJustin Hibbits 	if_t ifp = fwip->fw_softc.fwip_ifp;
209b8b33234SDoug Rabson 	struct fw_xfer *xfer, *next;
210b8b33234SDoug Rabson 	int i;
211b8b33234SDoug Rabson 
212b8b33234SDoug Rabson 	fc = fwip->fd.fc;
213b8b33234SDoug Rabson 
214b8b33234SDoug Rabson 	if (fwip->dma_ch >= 0) {
215b8b33234SDoug Rabson 		xferq = fc->ir[fwip->dma_ch];
216b8b33234SDoug Rabson 
217b8b33234SDoug Rabson 		if (xferq->flag & FWXFERQ_RUNNING)
218b8b33234SDoug Rabson 			fc->irx_disable(fc, fwip->dma_ch);
219b8b33234SDoug Rabson 		xferq->flag &=
220b8b33234SDoug Rabson 			~(FWXFERQ_MODEMASK | FWXFERQ_OPEN | FWXFERQ_STREAM |
221b8b33234SDoug Rabson 			FWXFERQ_EXTBUF | FWXFERQ_HANDLER | FWXFERQ_CHTAGMASK);
222b8b33234SDoug Rabson 		xferq->hand =  NULL;
223b8b33234SDoug Rabson 
224b8b33234SDoug Rabson 		for (i = 0; i < xferq->bnchunk; i++)
225b8b33234SDoug Rabson 			m_freem(xferq->bulkxfer[i].mbuf);
226b8b33234SDoug Rabson 		free(xferq->bulkxfer, M_FWIP);
227b8b33234SDoug Rabson 
228b8b33234SDoug Rabson 		fw_bindremove(fc, &fwip->fwb);
229b8b33234SDoug Rabson 		for (xfer = STAILQ_FIRST(&fwip->fwb.xferlist); xfer != NULL;
230b8b33234SDoug Rabson 					xfer = next) {
231b8b33234SDoug Rabson 			next = STAILQ_NEXT(xfer, link);
232b8b33234SDoug Rabson 			fw_xfer_free(xfer);
233b8b33234SDoug Rabson 		}
234b8b33234SDoug Rabson 
235b8b33234SDoug Rabson 		for (xfer = STAILQ_FIRST(&fwip->xferlist); xfer != NULL;
236b8b33234SDoug Rabson 					xfer = next) {
237b8b33234SDoug Rabson 			next = STAILQ_NEXT(xfer, link);
238b8b33234SDoug Rabson 			fw_xfer_free(xfer);
239b8b33234SDoug Rabson 		}
240b8b33234SDoug Rabson 		STAILQ_INIT(&fwip->xferlist);
241b8b33234SDoug Rabson 
242b8b33234SDoug Rabson 		xferq->bulkxfer =  NULL;
243b8b33234SDoug Rabson 		fwip->dma_ch = -1;
244b8b33234SDoug Rabson 	}
245b8b33234SDoug Rabson 
24661c05f13SJustin Hibbits 	if_setdrvflagbits(ifp, 0, (IFF_DRV_RUNNING | IFF_DRV_OACTIVE));
247b8b33234SDoug Rabson }
248b8b33234SDoug Rabson 
249b8b33234SDoug Rabson static int
fwip_detach(device_t dev)250b8b33234SDoug Rabson fwip_detach(device_t dev)
251b8b33234SDoug Rabson {
252b8b33234SDoug Rabson 	struct fwip_softc *fwip;
25361c05f13SJustin Hibbits 	if_t ifp;
254b8b33234SDoug Rabson 	int s;
255b8b33234SDoug Rabson 
256b8b33234SDoug Rabson 	fwip = (struct fwip_softc *)device_get_softc(dev);
25740929967SGleb Smirnoff 	ifp = fwip->fw_softc.fwip_ifp;
25840929967SGleb Smirnoff 
25940929967SGleb Smirnoff #ifdef DEVICE_POLLING
26061c05f13SJustin Hibbits 	if (if_getcapenable(ifp) & IFCAP_POLLING)
26140929967SGleb Smirnoff 		ether_poll_deregister(ifp);
26240929967SGleb Smirnoff #endif
26340929967SGleb Smirnoff 
264b8b33234SDoug Rabson 	s = splimp();
265b8b33234SDoug Rabson 
266b8b33234SDoug Rabson 	fwip_stop(fwip);
26740929967SGleb Smirnoff 	firewire_ifdetach(ifp);
26840929967SGleb Smirnoff 	if_free(ifp);
2699950b741SHidetoshi Shimokawa 	mtx_destroy(&fwip->mtx);
270b8b33234SDoug Rabson 
271b8b33234SDoug Rabson 	splx(s);
272b8b33234SDoug Rabson 	return 0;
273b8b33234SDoug Rabson }
274b8b33234SDoug Rabson 
275b8b33234SDoug Rabson static void
fwip_init(void * arg)276b8b33234SDoug Rabson fwip_init(void *arg)
277b8b33234SDoug Rabson {
278b8b33234SDoug Rabson 	struct fwip_softc *fwip = ((struct fwip_eth_softc *)arg)->fwip;
279b8b33234SDoug Rabson 	struct firewire_comm *fc;
28061c05f13SJustin Hibbits 	if_t ifp = fwip->fw_softc.fwip_ifp;
281b8b33234SDoug Rabson 	struct fw_xferq *xferq;
282b8b33234SDoug Rabson 	struct fw_xfer *xfer;
283b8b33234SDoug Rabson 	struct mbuf *m;
284b8b33234SDoug Rabson 	int i;
285b8b33234SDoug Rabson 
286b8b33234SDoug Rabson 	FWIPDEBUG(ifp, "initializing\n");
287b8b33234SDoug Rabson 
288b8b33234SDoug Rabson 	fc = fwip->fd.fc;
289b8b33234SDoug Rabson #define START 0
290b8b33234SDoug Rabson 	if (fwip->dma_ch < 0) {
2919950b741SHidetoshi Shimokawa 		fwip->dma_ch = fw_open_isodma(fc, /* tx */0);
2929950b741SHidetoshi Shimokawa 		if (fwip->dma_ch < 0)
293b8b33234SDoug Rabson 			return;
2949950b741SHidetoshi Shimokawa 		xferq = fc->ir[fwip->dma_ch];
2959950b741SHidetoshi Shimokawa 		xferq->flag |= FWXFERQ_EXTBUF |
296b8b33234SDoug Rabson 				FWXFERQ_HANDLER | FWXFERQ_STREAM;
297b8b33234SDoug Rabson 		xferq->flag &= ~0xff;
298b8b33234SDoug Rabson 		xferq->flag |= broadcast_channel & 0xff;
299b8b33234SDoug Rabson 		/* register fwip_input handler */
300b8b33234SDoug Rabson 		xferq->sc = (caddr_t) fwip;
301b8b33234SDoug Rabson 		xferq->hand = fwip_stream_input;
302b8b33234SDoug Rabson 		xferq->bnchunk = rx_queue_len;
303b8b33234SDoug Rabson 		xferq->bnpacket = 1;
304b8b33234SDoug Rabson 		xferq->psize = MCLBYTES;
305b8b33234SDoug Rabson 		xferq->queued = 0;
306b8b33234SDoug Rabson 		xferq->buf = NULL;
307*4d47c7caSZhenlei Huang 		xferq->bulkxfer = malloc(
308b8b33234SDoug Rabson 			sizeof(struct fw_bulkxfer) * xferq->bnchunk,
309b8b33234SDoug Rabson 							M_FWIP, M_WAITOK);
310b8b33234SDoug Rabson 		STAILQ_INIT(&xferq->stvalid);
311b8b33234SDoug Rabson 		STAILQ_INIT(&xferq->stfree);
312b8b33234SDoug Rabson 		STAILQ_INIT(&xferq->stdma);
313b8b33234SDoug Rabson 		xferq->stproc = NULL;
314b8b33234SDoug Rabson 		for (i = 0; i < xferq->bnchunk; i++) {
315c6499eccSGleb Smirnoff 			m = m_getcl(M_WAITOK, MT_DATA, M_PKTHDR);
316b8b33234SDoug Rabson 			xferq->bulkxfer[i].mbuf = m;
317b8b33234SDoug Rabson 			m->m_len = m->m_pkthdr.len = m->m_ext.ext_size;
318b8b33234SDoug Rabson 			STAILQ_INSERT_TAIL(&xferq->stfree,
319b8b33234SDoug Rabson 					&xferq->bulkxfer[i], link);
320b8b33234SDoug Rabson 		}
321b8b33234SDoug Rabson 
322b8b33234SDoug Rabson 		fwip->fwb.start = INET_FIFO;
323b8b33234SDoug Rabson 		fwip->fwb.end = INET_FIFO + 16384; /* S3200 packet size */
324b8b33234SDoug Rabson 
325b8b33234SDoug Rabson 		/* pre-allocate xfer */
326b8b33234SDoug Rabson 		STAILQ_INIT(&fwip->fwb.xferlist);
327b8b33234SDoug Rabson 		for (i = 0; i < rx_queue_len; i++) {
328b8b33234SDoug Rabson 			xfer = fw_xfer_alloc(M_FWIP);
329b8b33234SDoug Rabson 			if (xfer == NULL)
330b8b33234SDoug Rabson 				break;
331c6499eccSGleb Smirnoff 			m = m_getcl(M_WAITOK, MT_DATA, M_PKTHDR);
332b8b33234SDoug Rabson 			xfer->recv.payload = mtod(m, uint32_t *);
333b8b33234SDoug Rabson 			xfer->recv.pay_len = MCLBYTES;
334801167a8SHidetoshi Shimokawa 			xfer->hand = fwip_unicast_input;
335b8b33234SDoug Rabson 			xfer->fc = fc;
336b8b33234SDoug Rabson 			xfer->sc = (caddr_t)fwip;
337b8b33234SDoug Rabson 			xfer->mbuf = m;
338b8b33234SDoug Rabson 			STAILQ_INSERT_TAIL(&fwip->fwb.xferlist, xfer, link);
339b8b33234SDoug Rabson 		}
340b8b33234SDoug Rabson 		fw_bindadd(fc, &fwip->fwb);
341b8b33234SDoug Rabson 
342b8b33234SDoug Rabson 		STAILQ_INIT(&fwip->xferlist);
343b8b33234SDoug Rabson 		for (i = 0; i < TX_MAX_QUEUE; i++) {
344b8b33234SDoug Rabson 			xfer = fw_xfer_alloc(M_FWIP);
345b8b33234SDoug Rabson 			if (xfer == NULL)
346b8b33234SDoug Rabson 				break;
347b8b33234SDoug Rabson 			xfer->send.spd = tx_speed;
348b8b33234SDoug Rabson 			xfer->fc = fwip->fd.fc;
349b8b33234SDoug Rabson 			xfer->sc = (caddr_t)fwip;
350801167a8SHidetoshi Shimokawa 			xfer->hand = fwip_output_callback;
351b8b33234SDoug Rabson 			STAILQ_INSERT_TAIL(&fwip->xferlist, xfer, link);
352b8b33234SDoug Rabson 		}
353b8b33234SDoug Rabson 	} else
354b8b33234SDoug Rabson 		xferq = fc->ir[fwip->dma_ch];
355b8b33234SDoug Rabson 
356b8b33234SDoug Rabson 	fwip->last_dest.hi = 0;
357b8b33234SDoug Rabson 	fwip->last_dest.lo = 0;
358b8b33234SDoug Rabson 
359b8b33234SDoug Rabson 	/* start dma */
360b8b33234SDoug Rabson 	if ((xferq->flag & FWXFERQ_RUNNING) == 0)
361b8b33234SDoug Rabson 		fc->irx_enable(fc, fwip->dma_ch);
362b8b33234SDoug Rabson 
36361c05f13SJustin Hibbits 	if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0);
36461c05f13SJustin Hibbits 	if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
365b8b33234SDoug Rabson 
366b8b33234SDoug Rabson #if 0
367b8b33234SDoug Rabson 	/* attempt to start output */
368b8b33234SDoug Rabson 	fwip_start(ifp);
369b8b33234SDoug Rabson #endif
370b8b33234SDoug Rabson }
371b8b33234SDoug Rabson 
372b8b33234SDoug Rabson static int
fwip_ioctl(if_t ifp,u_long cmd,caddr_t data)37361c05f13SJustin Hibbits fwip_ioctl(if_t ifp, u_long cmd, caddr_t data)
374b8b33234SDoug Rabson {
37561c05f13SJustin Hibbits 	struct fwip_softc *fwip = ((struct fwip_eth_softc *)if_getsoftc(ifp))->fwip;
376b8b33234SDoug Rabson 	int s, error;
377b8b33234SDoug Rabson 
378b8b33234SDoug Rabson 	switch (cmd) {
379b8b33234SDoug Rabson 	case SIOCSIFFLAGS:
380b8b33234SDoug Rabson 		s = splimp();
38161c05f13SJustin Hibbits 		if (if_getflags(ifp) & IFF_UP) {
38261c05f13SJustin Hibbits 			if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING))
383b8b33234SDoug Rabson 				fwip_init(&fwip->fw_softc);
384b8b33234SDoug Rabson 		} else {
38561c05f13SJustin Hibbits 			if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
386b8b33234SDoug Rabson 				fwip_stop(fwip);
387b8b33234SDoug Rabson 		}
388b8b33234SDoug Rabson 		splx(s);
389b8b33234SDoug Rabson 		break;
390b8b33234SDoug Rabson 	case SIOCADDMULTI:
391b8b33234SDoug Rabson 	case SIOCDELMULTI:
392b8b33234SDoug Rabson 		break;
39340929967SGleb Smirnoff 	case SIOCSIFCAP:
39440929967SGleb Smirnoff #ifdef DEVICE_POLLING
39540929967SGleb Smirnoff 	    {
39640929967SGleb Smirnoff 		struct ifreq *ifr = (struct ifreq *) data;
3970a5eaa9dSMax Khon 		struct firewire_comm *fc = fwip->fd.fc;
398b8b33234SDoug Rabson 
39940929967SGleb Smirnoff 		if (ifr->ifr_reqcap & IFCAP_POLLING &&
40061c05f13SJustin Hibbits 		    !(if_getcapenable(ifp) & IFCAP_POLLING)) {
40140929967SGleb Smirnoff 			error = ether_poll_register(fwip_poll, ifp);
40240929967SGleb Smirnoff 			if (error)
40340929967SGleb Smirnoff 				return (error);
40440929967SGleb Smirnoff 			/* Disable interrupts */
40540929967SGleb Smirnoff 			fc->set_intr(fc, 0);
40661c05f13SJustin Hibbits 			if_setcapenablebit(ifp, IFCAP_POLLING, 0);
40740929967SGleb Smirnoff 			return (error);
40840929967SGleb Smirnoff 		}
40940929967SGleb Smirnoff 		if (!(ifr->ifr_reqcap & IFCAP_POLLING) &&
41061c05f13SJustin Hibbits 		    if_getcapenable(ifp) & IFCAP_POLLING) {
41140929967SGleb Smirnoff 			error = ether_poll_deregister(ifp);
41240929967SGleb Smirnoff 			/* Enable interrupts. */
41340929967SGleb Smirnoff 			fc->set_intr(fc, 1);
41461c05f13SJustin Hibbits 			if_setcapenablebit(ifp, 0, IFCAP_POLLING);
41540929967SGleb Smirnoff 			return (error);
41640929967SGleb Smirnoff 		}
41740929967SGleb Smirnoff 	    }
41840929967SGleb Smirnoff #endif /* DEVICE_POLLING */
41940929967SGleb Smirnoff 		break;
420b8b33234SDoug Rabson 	default:
421b8b33234SDoug Rabson 		s = splimp();
422b8b33234SDoug Rabson 		error = firewire_ioctl(ifp, cmd, data);
423b8b33234SDoug Rabson 		splx(s);
424b8b33234SDoug Rabson 		return (error);
425b8b33234SDoug Rabson 	}
426b8b33234SDoug Rabson 
427b8b33234SDoug Rabson 	return (0);
428b8b33234SDoug Rabson }
429b8b33234SDoug Rabson 
430b8b33234SDoug Rabson static void
fwip_post_busreset(void * arg)431b8b33234SDoug Rabson fwip_post_busreset(void *arg)
432b8b33234SDoug Rabson {
433b8b33234SDoug Rabson 	struct fwip_softc *fwip = arg;
43404fa3b29SDoug Rabson 	struct crom_src *src;
43504fa3b29SDoug Rabson 	struct crom_chunk *root;
43604fa3b29SDoug Rabson 
43704fa3b29SDoug Rabson 	src = fwip->fd.fc->crom_src;
43804fa3b29SDoug Rabson 	root = fwip->fd.fc->crom_root;
43904fa3b29SDoug Rabson 
44004fa3b29SDoug Rabson 	/* RFC2734 IPv4 over IEEE1394 */
44104fa3b29SDoug Rabson 	bzero(&fwip->unit4, sizeof(struct crom_chunk));
44204fa3b29SDoug Rabson 	crom_add_chunk(src, root, &fwip->unit4, CROM_UDIR);
44304fa3b29SDoug Rabson 	crom_add_entry(&fwip->unit4, CSRKEY_SPEC, CSRVAL_IETF);
44404fa3b29SDoug Rabson 	crom_add_simple_text(src, &fwip->unit4, &fwip->spec4, "IANA");
44504fa3b29SDoug Rabson 	crom_add_entry(&fwip->unit4, CSRKEY_VER, 1);
44604fa3b29SDoug Rabson 	crom_add_simple_text(src, &fwip->unit4, &fwip->ver4, "IPv4");
44704fa3b29SDoug Rabson 
44804fa3b29SDoug Rabson 	/* RFC3146 IPv6 over IEEE1394 */
44904fa3b29SDoug Rabson 	bzero(&fwip->unit6, sizeof(struct crom_chunk));
45004fa3b29SDoug Rabson 	crom_add_chunk(src, root, &fwip->unit6, CROM_UDIR);
45104fa3b29SDoug Rabson 	crom_add_entry(&fwip->unit6, CSRKEY_SPEC, CSRVAL_IETF);
45204fa3b29SDoug Rabson 	crom_add_simple_text(src, &fwip->unit6, &fwip->spec6, "IANA");
45304fa3b29SDoug Rabson 	crom_add_entry(&fwip->unit6, CSRKEY_VER, 2);
45404fa3b29SDoug Rabson 	crom_add_simple_text(src, &fwip->unit6, &fwip->ver6, "IPv6");
455b8b33234SDoug Rabson 
456b8b33234SDoug Rabson 	fwip->last_dest.hi = 0;
457b8b33234SDoug Rabson 	fwip->last_dest.lo = 0;
458fc74a9f9SBrooks Davis 	firewire_busreset(fwip->fw_softc.fwip_ifp);
459b8b33234SDoug Rabson }
460b8b33234SDoug Rabson 
461b8b33234SDoug Rabson static void
fwip_output_callback(struct fw_xfer * xfer)462b8b33234SDoug Rabson fwip_output_callback(struct fw_xfer *xfer)
463b8b33234SDoug Rabson {
464b8b33234SDoug Rabson 	struct fwip_softc *fwip;
46561c05f13SJustin Hibbits 	if_t ifp;
466b8b33234SDoug Rabson 	int s;
467b8b33234SDoug Rabson 
468b8b33234SDoug Rabson 	fwip = (struct fwip_softc *)xfer->sc;
469fc74a9f9SBrooks Davis 	ifp = fwip->fw_softc.fwip_ifp;
470b8b33234SDoug Rabson 	/* XXX error check */
471b8b33234SDoug Rabson 	FWIPDEBUG(ifp, "resp = %d\n", xfer->resp);
472b8b33234SDoug Rabson 	if (xfer->resp != 0)
473c8dfaf38SGleb Smirnoff 		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
474b8b33234SDoug Rabson 	m_freem(xfer->mbuf);
475b8b33234SDoug Rabson 	fw_xfer_unload(xfer);
476b8b33234SDoug Rabson 
477b8b33234SDoug Rabson 	s = splimp();
4789950b741SHidetoshi Shimokawa 	FWIP_LOCK(fwip);
479b8b33234SDoug Rabson 	STAILQ_INSERT_TAIL(&fwip->xferlist, xfer, link);
4809950b741SHidetoshi Shimokawa 	FWIP_UNLOCK(fwip);
481b8b33234SDoug Rabson 	splx(s);
482b8b33234SDoug Rabson 
483b8b33234SDoug Rabson 	/* for queue full */
48461c05f13SJustin Hibbits 	if (!if_sendq_empty(ifp)) {
485b8b33234SDoug Rabson 		fwip_start(ifp);
486b8b33234SDoug Rabson 	}
4879950b741SHidetoshi Shimokawa }
488b8b33234SDoug Rabson 
489b8b33234SDoug Rabson static void
fwip_start(if_t ifp)49061c05f13SJustin Hibbits fwip_start(if_t ifp)
491b8b33234SDoug Rabson {
49261c05f13SJustin Hibbits 	struct fwip_softc *fwip = ((struct fwip_eth_softc *)if_getsoftc(ifp))->fwip;
493b8b33234SDoug Rabson 	int s;
494b8b33234SDoug Rabson 
495b8b33234SDoug Rabson 	FWIPDEBUG(ifp, "starting\n");
496b8b33234SDoug Rabson 
497b8b33234SDoug Rabson 	if (fwip->dma_ch < 0) {
498b8b33234SDoug Rabson 		struct mbuf	*m = NULL;
499b8b33234SDoug Rabson 
500b8b33234SDoug Rabson 		FWIPDEBUG(ifp, "not ready\n");
501b8b33234SDoug Rabson 
502b8b33234SDoug Rabson 		s = splimp();
503b8b33234SDoug Rabson 		do {
50461c05f13SJustin Hibbits 			m = if_dequeue(ifp);
505b8b33234SDoug Rabson 			if (m != NULL)
506b8b33234SDoug Rabson 				m_freem(m);
507c8dfaf38SGleb Smirnoff 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
508b8b33234SDoug Rabson 		} while (m != NULL);
509b8b33234SDoug Rabson 		splx(s);
510b8b33234SDoug Rabson 
511b8b33234SDoug Rabson 		return;
512b8b33234SDoug Rabson 	}
513b8b33234SDoug Rabson 
514b8b33234SDoug Rabson 	s = splimp();
51561c05f13SJustin Hibbits 	if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0);
516b8b33234SDoug Rabson 
51761c05f13SJustin Hibbits 	if (!if_sendq_empty(ifp))
518b8b33234SDoug Rabson 		fwip_async_output(fwip, ifp);
519b8b33234SDoug Rabson 
52061c05f13SJustin Hibbits 	if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
521b8b33234SDoug Rabson 	splx(s);
522b8b33234SDoug Rabson }
523b8b33234SDoug Rabson 
524b8b33234SDoug Rabson /* Async. stream output */
525b8b33234SDoug Rabson static void
fwip_async_output(struct fwip_softc * fwip,if_t ifp)52661c05f13SJustin Hibbits fwip_async_output(struct fwip_softc *fwip, if_t ifp)
527b8b33234SDoug Rabson {
528b8b33234SDoug Rabson 	struct firewire_comm *fc = fwip->fd.fc;
529b8b33234SDoug Rabson 	struct mbuf *m;
530b8b33234SDoug Rabson 	struct m_tag *mtag;
531b8b33234SDoug Rabson 	struct fw_hwaddr *destfw;
532b8b33234SDoug Rabson 	struct fw_xfer *xfer;
533b8b33234SDoug Rabson 	struct fw_xferq *xferq;
534b8b33234SDoug Rabson 	struct fw_pkt *fp;
535b8b33234SDoug Rabson 	uint16_t nodeid;
536ee2f2cccSDoug Rabson 	int error;
537b8b33234SDoug Rabson 	int i = 0;
538b8b33234SDoug Rabson 
539b8b33234SDoug Rabson 	xfer = NULL;
5409950b741SHidetoshi Shimokawa 	xferq = fc->atq;
5419950b741SHidetoshi Shimokawa 	while ((xferq->queued < xferq->maxq - 1) &&
54261c05f13SJustin Hibbits 			!if_sendq_empty(ifp)) {
5439950b741SHidetoshi Shimokawa 		FWIP_LOCK(fwip);
544b8b33234SDoug Rabson 		xfer = STAILQ_FIRST(&fwip->xferlist);
545b8b33234SDoug Rabson 		if (xfer == NULL) {
5469950b741SHidetoshi Shimokawa 			FWIP_UNLOCK(fwip);
5479950b741SHidetoshi Shimokawa #if 0
548b8b33234SDoug Rabson 			printf("if_fwip: lack of xfer\n");
5499950b741SHidetoshi Shimokawa #endif
550b8b33234SDoug Rabson 			break;
5519950b741SHidetoshi Shimokawa 		}
5529950b741SHidetoshi Shimokawa 		STAILQ_REMOVE_HEAD(&fwip->xferlist, link);
5539950b741SHidetoshi Shimokawa 		FWIP_UNLOCK(fwip);
5549950b741SHidetoshi Shimokawa 
55561c05f13SJustin Hibbits 		m = if_dequeue(ifp);
5569950b741SHidetoshi Shimokawa 		if (m == NULL) {
5579950b741SHidetoshi Shimokawa 			FWIP_LOCK(fwip);
5589950b741SHidetoshi Shimokawa 			STAILQ_INSERT_HEAD(&fwip->xferlist, xfer, link);
5599950b741SHidetoshi Shimokawa 			FWIP_UNLOCK(fwip);
5609950b741SHidetoshi Shimokawa 			break;
5619950b741SHidetoshi Shimokawa 		}
562b8b33234SDoug Rabson 
563b8b33234SDoug Rabson 		/*
564b8b33234SDoug Rabson 		 * Dig out the link-level address which
565b8b33234SDoug Rabson 		 * firewire_output got via arp or neighbour
566b8b33234SDoug Rabson 		 * discovery. If we don't have a link-level address,
567b8b33234SDoug Rabson 		 * just stick the thing on the broadcast channel.
568b8b33234SDoug Rabson 		 */
569b8b33234SDoug Rabson 		mtag = m_tag_locate(m, MTAG_FIREWIRE, MTAG_FIREWIRE_HWADDR, 0);
570b8b33234SDoug Rabson 		if (mtag == NULL)
5714d24901aSPedro F. Giffuni 			destfw = NULL;
572b8b33234SDoug Rabson 		else
573b8b33234SDoug Rabson 			destfw = (struct fw_hwaddr *) (mtag + 1);
574b8b33234SDoug Rabson 
575b8b33234SDoug Rabson 
576b8b33234SDoug Rabson 		/*
577b8b33234SDoug Rabson 		 * We don't do any bpf stuff here - the generic code
578b8b33234SDoug Rabson 		 * in firewire_output gives the packet to bpf before
579b8b33234SDoug Rabson 		 * it adds the link-level encapsulation.
580b8b33234SDoug Rabson 		 */
581b8b33234SDoug Rabson 
582b8b33234SDoug Rabson 		/*
583b8b33234SDoug Rabson 		 * Put the mbuf in the xfer early in case we hit an
584b8b33234SDoug Rabson 		 * error case below - fwip_output_callback will free
585b8b33234SDoug Rabson 		 * the mbuf.
586b8b33234SDoug Rabson 		 */
587b8b33234SDoug Rabson 		xfer->mbuf = m;
588b8b33234SDoug Rabson 
589b8b33234SDoug Rabson 		/*
590b8b33234SDoug Rabson 		 * We use the arp result (if any) to add a suitable firewire
591b8b33234SDoug Rabson 		 * packet header before handing off to the bus.
592b8b33234SDoug Rabson 		 */
593b8b33234SDoug Rabson 		fp = &xfer->send.hdr;
594b8b33234SDoug Rabson 		nodeid = FWLOCALBUS | fc->nodeid;
595b8b33234SDoug Rabson 		if ((m->m_flags & M_BCAST) || !destfw) {
596b8b33234SDoug Rabson 			/*
597b8b33234SDoug Rabson 			 * Broadcast packets are sent as GASP packets with
598b8b33234SDoug Rabson 			 * specifier ID 0x00005e, version 1 on the broadcast
599b8b33234SDoug Rabson 			 * channel. To be conservative, we send at the
600b8b33234SDoug Rabson 			 * slowest possible speed.
601b8b33234SDoug Rabson 			 */
602b8b33234SDoug Rabson 			uint32_t *p;
603b8b33234SDoug Rabson 
604c6499eccSGleb Smirnoff 			M_PREPEND(m, 2*sizeof(uint32_t), M_NOWAIT);
605b8b33234SDoug Rabson 			p = mtod(m, uint32_t *);
606b8b33234SDoug Rabson 			fp->mode.stream.len = m->m_pkthdr.len;
607b8b33234SDoug Rabson 			fp->mode.stream.chtag = broadcast_channel;
608b8b33234SDoug Rabson 			fp->mode.stream.tcode = FWTCODE_STREAM;
609b8b33234SDoug Rabson 			fp->mode.stream.sy = 0;
610b8b33234SDoug Rabson 			xfer->send.spd = 0;
611b8b33234SDoug Rabson 			p[0] = htonl(nodeid << 16);
612b8b33234SDoug Rabson 			p[1] = htonl((0x5e << 24) | 1);
613b8b33234SDoug Rabson 		} else {
614b8b33234SDoug Rabson 			/*
615b8b33234SDoug Rabson 			 * Unicast packets are sent as block writes to the
616b8b33234SDoug Rabson 			 * target's unicast fifo address. If we can't
617b8b33234SDoug Rabson 			 * find the node address, we just give up. We
618b8b33234SDoug Rabson 			 * could broadcast it but that might overflow
619b8b33234SDoug Rabson 			 * the packet size limitations due to the
620b8b33234SDoug Rabson 			 * extra GASP header. Note: the hardware
621b8b33234SDoug Rabson 			 * address is stored in network byte order to
622b8b33234SDoug Rabson 			 * make life easier for ARP.
623b8b33234SDoug Rabson 			 */
624b8b33234SDoug Rabson 			struct fw_device *fd;
625b8b33234SDoug Rabson 			struct fw_eui64 eui;
626b8b33234SDoug Rabson 
627b8b33234SDoug Rabson 			eui.hi = ntohl(destfw->sender_unique_ID_hi);
628b8b33234SDoug Rabson 			eui.lo = ntohl(destfw->sender_unique_ID_lo);
629b8b33234SDoug Rabson 			if (fwip->last_dest.hi != eui.hi ||
630b8b33234SDoug Rabson 			    fwip->last_dest.lo != eui.lo) {
631b8b33234SDoug Rabson 				fd = fw_noderesolve_eui64(fc, &eui);
632b8b33234SDoug Rabson 				if (!fd) {
633b8b33234SDoug Rabson 					/* error */
634c8dfaf38SGleb Smirnoff 					if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
635b8b33234SDoug Rabson 					/* XXX set error code */
636b8b33234SDoug Rabson 					fwip_output_callback(xfer);
637b8b33234SDoug Rabson 					continue;
638b8b33234SDoug Rabson 
639b8b33234SDoug Rabson 				}
640b8b33234SDoug Rabson 				fwip->last_hdr.mode.wreqb.dst = FWLOCALBUS | fd->dst;
641b8b33234SDoug Rabson 				fwip->last_hdr.mode.wreqb.tlrt = 0;
642b8b33234SDoug Rabson 				fwip->last_hdr.mode.wreqb.tcode = FWTCODE_WREQB;
643b8b33234SDoug Rabson 				fwip->last_hdr.mode.wreqb.pri = 0;
644b8b33234SDoug Rabson 				fwip->last_hdr.mode.wreqb.src = nodeid;
645b8b33234SDoug Rabson 				fwip->last_hdr.mode.wreqb.dest_hi =
646b8b33234SDoug Rabson 					ntohs(destfw->sender_unicast_FIFO_hi);
647b8b33234SDoug Rabson 				fwip->last_hdr.mode.wreqb.dest_lo =
648b8b33234SDoug Rabson 					ntohl(destfw->sender_unicast_FIFO_lo);
649b8b33234SDoug Rabson 				fwip->last_hdr.mode.wreqb.extcode = 0;
650b8b33234SDoug Rabson 				fwip->last_dest = eui;
651b8b33234SDoug Rabson 			}
652b8b33234SDoug Rabson 
653b8b33234SDoug Rabson 			fp->mode.wreqb = fwip->last_hdr.mode.wreqb;
654b8b33234SDoug Rabson 			fp->mode.wreqb.len = m->m_pkthdr.len;
655b8b33234SDoug Rabson 			xfer->send.spd = min(destfw->sspd, fc->speed);
656b8b33234SDoug Rabson 		}
657b8b33234SDoug Rabson 
658b8b33234SDoug Rabson 		xfer->send.pay_len = m->m_pkthdr.len;
659b8b33234SDoug Rabson 
660ee2f2cccSDoug Rabson 		error = fw_asyreq(fc, -1, xfer);
661ee2f2cccSDoug Rabson 		if (error == EAGAIN) {
662ee2f2cccSDoug Rabson 			/*
663ee2f2cccSDoug Rabson 			 * We ran out of tlabels - requeue the packet
664ee2f2cccSDoug Rabson 			 * for later transmission.
665ee2f2cccSDoug Rabson 			 */
666ee2f2cccSDoug Rabson 			xfer->mbuf = 0;
6679950b741SHidetoshi Shimokawa 			FWIP_LOCK(fwip);
668ee2f2cccSDoug Rabson 			STAILQ_INSERT_TAIL(&fwip->xferlist, xfer, link);
6699950b741SHidetoshi Shimokawa 			FWIP_UNLOCK(fwip);
67061c05f13SJustin Hibbits 			if_sendq_prepend(ifp, m);
671ee2f2cccSDoug Rabson 			break;
672ee2f2cccSDoug Rabson 		}
673ee2f2cccSDoug Rabson 		if (error) {
674b8b33234SDoug Rabson 			/* error */
675c8dfaf38SGleb Smirnoff 			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
676b8b33234SDoug Rabson 			/* XXX set error code */
677b8b33234SDoug Rabson 			fwip_output_callback(xfer);
678b8b33234SDoug Rabson 			continue;
679b8b33234SDoug Rabson 		} else {
680c8dfaf38SGleb Smirnoff 			if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
681b8b33234SDoug Rabson 			i++;
682b8b33234SDoug Rabson 		}
683b8b33234SDoug Rabson 	}
684b8b33234SDoug Rabson #if 0
685b8b33234SDoug Rabson 	if (i > 1)
686b8b33234SDoug Rabson 		printf("%d queued\n", i);
687b8b33234SDoug Rabson #endif
6889950b741SHidetoshi Shimokawa 	if (i > 0)
689b8b33234SDoug Rabson 		xferq->start(fc);
690b8b33234SDoug Rabson }
691b8b33234SDoug Rabson 
692b8b33234SDoug Rabson static void
fwip_start_send(void * arg,int count)693b8b33234SDoug Rabson fwip_start_send (void *arg, int count)
694b8b33234SDoug Rabson {
695b8b33234SDoug Rabson 	struct fwip_softc *fwip = arg;
696b8b33234SDoug Rabson 
697b8b33234SDoug Rabson 	fwip->fd.fc->atq->start(fwip->fd.fc);
698b8b33234SDoug Rabson }
699b8b33234SDoug Rabson 
700b8b33234SDoug Rabson /* Async. stream output */
701b8b33234SDoug Rabson static void
fwip_stream_input(struct fw_xferq * xferq)702b8b33234SDoug Rabson fwip_stream_input(struct fw_xferq *xferq)
703b8b33234SDoug Rabson {
704b8a6e03fSGleb Smirnoff 	struct epoch_tracker et;
705b8b33234SDoug Rabson 	struct mbuf *m, *m0;
706b8b33234SDoug Rabson 	struct m_tag *mtag;
70761c05f13SJustin Hibbits 	if_t ifp;
708b8b33234SDoug Rabson 	struct fwip_softc *fwip;
709b8b33234SDoug Rabson 	struct fw_bulkxfer *sxfer;
710b8b33234SDoug Rabson 	struct fw_pkt *fp;
711b8b33234SDoug Rabson 	uint16_t src;
712b8b33234SDoug Rabson 	uint32_t *p;
713b8b33234SDoug Rabson 
714b8b33234SDoug Rabson 	fwip = (struct fwip_softc *)xferq->sc;
715fc74a9f9SBrooks Davis 	ifp = fwip->fw_softc.fwip_ifp;
71640929967SGleb Smirnoff 
717b8a6e03fSGleb Smirnoff 	NET_EPOCH_ENTER(et);
718b8b33234SDoug Rabson 	while ((sxfer = STAILQ_FIRST(&xferq->stvalid)) != NULL) {
719b8b33234SDoug Rabson 		STAILQ_REMOVE_HEAD(&xferq->stvalid, link);
720b8b33234SDoug Rabson 		fp = mtod(sxfer->mbuf, struct fw_pkt *);
721b8b33234SDoug Rabson 		if (fwip->fd.fc->irx_post != NULL)
722b8b33234SDoug Rabson 			fwip->fd.fc->irx_post(fwip->fd.fc, fp->mode.ld);
723b8b33234SDoug Rabson 		m = sxfer->mbuf;
724b8b33234SDoug Rabson 
725b8b33234SDoug Rabson 		/* insert new rbuf */
726c6499eccSGleb Smirnoff 		sxfer->mbuf = m0 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
727b8b33234SDoug Rabson 		if (m0 != NULL) {
728b8b33234SDoug Rabson 			m0->m_len = m0->m_pkthdr.len = m0->m_ext.ext_size;
729b8b33234SDoug Rabson 			STAILQ_INSERT_TAIL(&xferq->stfree, sxfer, link);
730b8b33234SDoug Rabson 		} else
731b8b33234SDoug Rabson 			printf("fwip_as_input: m_getcl failed\n");
732b8b33234SDoug Rabson 
733b8b33234SDoug Rabson 		/*
734b8b33234SDoug Rabson 		 * We must have a GASP header - leave the
735b8b33234SDoug Rabson 		 * encapsulation sanity checks to the generic
736453130d9SPedro F. Giffuni 		 * code. Remember that we also have the firewire async
737b8b33234SDoug Rabson 		 * stream header even though that isn't accounted for
738b8b33234SDoug Rabson 		 * in mode.stream.len.
739b8b33234SDoug Rabson 		 */
740b8b33234SDoug Rabson 		if (sxfer->resp != 0 || fp->mode.stream.len <
741b8b33234SDoug Rabson 		    2*sizeof(uint32_t)) {
742b8b33234SDoug Rabson 			m_freem(m);
743c8dfaf38SGleb Smirnoff 			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
744b8b33234SDoug Rabson 			continue;
745b8b33234SDoug Rabson 		}
746b8b33234SDoug Rabson 		m->m_len = m->m_pkthdr.len = fp->mode.stream.len
747b8b33234SDoug Rabson 			+ sizeof(fp->mode.stream);
748b8b33234SDoug Rabson 
749b8b33234SDoug Rabson 		/*
750b8b33234SDoug Rabson 		 * If we received the packet on the broadcast channel,
751b8b33234SDoug Rabson 		 * mark it as broadcast, otherwise we assume it must
752b8b33234SDoug Rabson 		 * be multicast.
753b8b33234SDoug Rabson 		 */
754b8b33234SDoug Rabson 		if (fp->mode.stream.chtag == broadcast_channel)
755b8b33234SDoug Rabson 			m->m_flags |= M_BCAST;
756b8b33234SDoug Rabson 		else
757b8b33234SDoug Rabson 			m->m_flags |= M_MCAST;
758b8b33234SDoug Rabson 
759b8b33234SDoug Rabson 		/*
760b8b33234SDoug Rabson 		 * Make sure we recognise the GASP specifier and
761b8b33234SDoug Rabson 		 * version.
762b8b33234SDoug Rabson 		 */
763b8b33234SDoug Rabson 		p = mtod(m, uint32_t *);
764b8b33234SDoug Rabson 		if ((((ntohl(p[1]) & 0xffff) << 8) | ntohl(p[2]) >> 24) != 0x00005e
765b8b33234SDoug Rabson 		    || (ntohl(p[2]) & 0xffffff) != 1) {
766b8b33234SDoug Rabson 			FWIPDEBUG(ifp, "Unrecognised GASP header %#08x %#08x\n",
767b8b33234SDoug Rabson 			    ntohl(p[1]), ntohl(p[2]));
768b8b33234SDoug Rabson 			m_freem(m);
769c8dfaf38SGleb Smirnoff 			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
770b8b33234SDoug Rabson 			continue;
771b8b33234SDoug Rabson 		}
772b8b33234SDoug Rabson 
773b8b33234SDoug Rabson 		/*
774b8b33234SDoug Rabson 		 * Record the sender ID for possible BPF usage.
775b8b33234SDoug Rabson 		 */
776b8b33234SDoug Rabson 		src = ntohl(p[1]) >> 16;
7778f31b879SJustin Hibbits 		if (bpf_peers_present_if(ifp)) {
778b8b33234SDoug Rabson 			mtag = m_tag_alloc(MTAG_FIREWIRE,
779b8b33234SDoug Rabson 			    MTAG_FIREWIRE_SENDER_EUID,
780b8b33234SDoug Rabson 			    2*sizeof(uint32_t), M_NOWAIT);
781b8b33234SDoug Rabson 			if (mtag) {
782b8b33234SDoug Rabson 				/* bpf wants it in network byte order */
783b8b33234SDoug Rabson 				struct fw_device *fd;
784b8b33234SDoug Rabson 				uint32_t *p = (uint32_t *) (mtag + 1);
785b8b33234SDoug Rabson 				fd = fw_noderesolve_nodeid(fwip->fd.fc,
786b8b33234SDoug Rabson 				    src & 0x3f);
787b8b33234SDoug Rabson 				if (fd) {
788b8b33234SDoug Rabson 					p[0] = htonl(fd->eui.hi);
789b8b33234SDoug Rabson 					p[1] = htonl(fd->eui.lo);
790b8b33234SDoug Rabson 				} else {
791b8b33234SDoug Rabson 					p[0] = 0;
792b8b33234SDoug Rabson 					p[1] = 0;
793b8b33234SDoug Rabson 				}
794b8b33234SDoug Rabson 				m_tag_prepend(m, mtag);
795b8b33234SDoug Rabson 			}
796b8b33234SDoug Rabson 		}
797b8b33234SDoug Rabson 
798b8b33234SDoug Rabson 		/*
799b8b33234SDoug Rabson 		 * Trim off the GASP header
800b8b33234SDoug Rabson 		 */
801b8b33234SDoug Rabson 		m_adj(m, 3*sizeof(uint32_t));
802b8b33234SDoug Rabson 		m->m_pkthdr.rcvif = ifp;
803b8b33234SDoug Rabson 		firewire_input(ifp, m, src);
804c8dfaf38SGleb Smirnoff 		if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
805b8b33234SDoug Rabson 	}
806b8a6e03fSGleb Smirnoff 	NET_EPOCH_EXIT(et);
807b8b33234SDoug Rabson 	if (STAILQ_FIRST(&xferq->stfree) != NULL)
808b8b33234SDoug Rabson 		fwip->fd.fc->irx_enable(fwip->fd.fc, fwip->dma_ch);
809b8b33234SDoug Rabson }
810b8b33234SDoug Rabson 
811b8b33234SDoug Rabson static __inline void
fwip_unicast_input_recycle(struct fwip_softc * fwip,struct fw_xfer * xfer)812b8b33234SDoug Rabson fwip_unicast_input_recycle(struct fwip_softc *fwip, struct fw_xfer *xfer)
813b8b33234SDoug Rabson {
814b8b33234SDoug Rabson 	struct mbuf *m;
815b8b33234SDoug Rabson 
816b8b33234SDoug Rabson 	/*
817b8b33234SDoug Rabson 	 * We have finished with a unicast xfer. Allocate a new
818b8b33234SDoug Rabson 	 * cluster and stick it on the back of the input queue.
819b8b33234SDoug Rabson 	 */
820c6499eccSGleb Smirnoff 	m = m_getcl(M_WAITOK, MT_DATA, M_PKTHDR);
821b8b33234SDoug Rabson 	xfer->mbuf = m;
822b8b33234SDoug Rabson 	xfer->recv.payload = mtod(m, uint32_t *);
823b8b33234SDoug Rabson 	xfer->recv.pay_len = MCLBYTES;
824b8b33234SDoug Rabson 	xfer->mbuf = m;
825b8b33234SDoug Rabson 	STAILQ_INSERT_TAIL(&fwip->fwb.xferlist, xfer, link);
826b8b33234SDoug Rabson }
827b8b33234SDoug Rabson 
828b8b33234SDoug Rabson static void
fwip_unicast_input(struct fw_xfer * xfer)829b8b33234SDoug Rabson fwip_unicast_input(struct fw_xfer *xfer)
830b8b33234SDoug Rabson {
831b8b33234SDoug Rabson 	uint64_t address;
832b8b33234SDoug Rabson 	struct mbuf *m;
833b8b33234SDoug Rabson 	struct m_tag *mtag;
834bdf316e8STai-hwa Liang 	struct epoch_tracker et;
83561c05f13SJustin Hibbits 	if_t ifp;
836b8b33234SDoug Rabson 	struct fwip_softc *fwip;
837b8b33234SDoug Rabson 	struct fw_pkt *fp;
838b8b33234SDoug Rabson 	//struct fw_pkt *sfp;
839b8b33234SDoug Rabson 	int rtcode;
840b8b33234SDoug Rabson 
841b8b33234SDoug Rabson 	fwip = (struct fwip_softc *)xfer->sc;
842fc74a9f9SBrooks Davis 	ifp = fwip->fw_softc.fwip_ifp;
843b8b33234SDoug Rabson 	m = xfer->mbuf;
844b8b33234SDoug Rabson 	xfer->mbuf = 0;
845b8b33234SDoug Rabson 	fp = &xfer->recv.hdr;
846b8b33234SDoug Rabson 
847b8b33234SDoug Rabson 	/*
848b8b33234SDoug Rabson 	 * Check the fifo address - we only accept addresses of
849b8b33234SDoug Rabson 	 * exactly INET_FIFO.
850b8b33234SDoug Rabson 	 */
851b8b33234SDoug Rabson 	address = ((uint64_t)fp->mode.wreqb.dest_hi << 32)
852b8b33234SDoug Rabson 		| fp->mode.wreqb.dest_lo;
853b8b33234SDoug Rabson 	if (fp->mode.wreqb.tcode != FWTCODE_WREQB) {
854b8b33234SDoug Rabson 		rtcode = FWRCODE_ER_TYPE;
855b8b33234SDoug Rabson 	} else if (address != INET_FIFO) {
856b8b33234SDoug Rabson 		rtcode = FWRCODE_ER_ADDR;
857b8b33234SDoug Rabson 	} else {
858b8b33234SDoug Rabson 		rtcode = FWRCODE_COMPLETE;
859b8b33234SDoug Rabson 	}
860bdf316e8STai-hwa Liang 	NET_EPOCH_ENTER(et);
861b8b33234SDoug Rabson 
862b8b33234SDoug Rabson 	/*
863b8b33234SDoug Rabson 	 * Pick up a new mbuf and stick it on the back of the receive
864b8b33234SDoug Rabson 	 * queue.
865b8b33234SDoug Rabson 	 */
866b8b33234SDoug Rabson 	fwip_unicast_input_recycle(fwip, xfer);
867b8b33234SDoug Rabson 
868b8b33234SDoug Rabson 	/*
869b8b33234SDoug Rabson 	 * If we've already rejected the packet, give up now.
870b8b33234SDoug Rabson 	 */
871b8b33234SDoug Rabson 	if (rtcode != FWRCODE_COMPLETE) {
872b8b33234SDoug Rabson 		m_freem(m);
873c8dfaf38SGleb Smirnoff 		if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
874bdf316e8STai-hwa Liang 		goto done;
875b8b33234SDoug Rabson 	}
876b8b33234SDoug Rabson 
8778f31b879SJustin Hibbits 	if (bpf_peers_present_if(ifp)) {
878b8b33234SDoug Rabson 		/*
879b8b33234SDoug Rabson 		 * Record the sender ID for possible BPF usage.
880b8b33234SDoug Rabson 		 */
881b8b33234SDoug Rabson 		mtag = m_tag_alloc(MTAG_FIREWIRE, MTAG_FIREWIRE_SENDER_EUID,
882b8b33234SDoug Rabson 		    2*sizeof(uint32_t), M_NOWAIT);
883b8b33234SDoug Rabson 		if (mtag) {
884b8b33234SDoug Rabson 			/* bpf wants it in network byte order */
885b8b33234SDoug Rabson 			struct fw_device *fd;
886b8b33234SDoug Rabson 			uint32_t *p = (uint32_t *) (mtag + 1);
887b8b33234SDoug Rabson 			fd = fw_noderesolve_nodeid(fwip->fd.fc,
888b8b33234SDoug Rabson 			    fp->mode.wreqb.src & 0x3f);
889b8b33234SDoug Rabson 			if (fd) {
890b8b33234SDoug Rabson 				p[0] = htonl(fd->eui.hi);
891b8b33234SDoug Rabson 				p[1] = htonl(fd->eui.lo);
892b8b33234SDoug Rabson 			} else {
893b8b33234SDoug Rabson 				p[0] = 0;
894b8b33234SDoug Rabson 				p[1] = 0;
895b8b33234SDoug Rabson 			}
896b8b33234SDoug Rabson 			m_tag_prepend(m, mtag);
897b8b33234SDoug Rabson 		}
898b8b33234SDoug Rabson 	}
899b8b33234SDoug Rabson 
900b8b33234SDoug Rabson 	/*
901b8b33234SDoug Rabson 	 * Hand off to the generic encapsulation code. We don't use
902b8b33234SDoug Rabson 	 * ifp->if_input so that we can pass the source nodeid as an
903b8b33234SDoug Rabson 	 * argument to facilitate link-level fragment reassembly.
904b8b33234SDoug Rabson 	 */
905b8b33234SDoug Rabson 	m->m_len = m->m_pkthdr.len = fp->mode.wreqb.len;
906b8b33234SDoug Rabson 	m->m_pkthdr.rcvif = ifp;
907b8b33234SDoug Rabson 	firewire_input(ifp, m, fp->mode.wreqb.src);
908c8dfaf38SGleb Smirnoff 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
909bdf316e8STai-hwa Liang done:
910bdf316e8STai-hwa Liang 	NET_EPOCH_EXIT(et);
911b8b33234SDoug Rabson }
912b8b33234SDoug Rabson 
913b8b33234SDoug Rabson static device_method_t fwip_methods[] = {
914b8b33234SDoug Rabson 	/* device interface */
915b8b33234SDoug Rabson 	DEVMETHOD(device_identify,	fwip_identify),
916b8b33234SDoug Rabson 	DEVMETHOD(device_probe,		fwip_probe),
917b8b33234SDoug Rabson 	DEVMETHOD(device_attach,	fwip_attach),
918b8b33234SDoug Rabson 	DEVMETHOD(device_detach,	fwip_detach),
919b8b33234SDoug Rabson 	{ 0, 0 }
920b8b33234SDoug Rabson };
921b8b33234SDoug Rabson 
922b8b33234SDoug Rabson static driver_t fwip_driver = {
923b8b33234SDoug Rabson         "fwip",
924b8b33234SDoug Rabson 	fwip_methods,
925b8b33234SDoug Rabson 	sizeof(struct fwip_softc),
926b8b33234SDoug Rabson };
927b8b33234SDoug Rabson 
928b8b33234SDoug Rabson 
9298984411bSJohn Baldwin DRIVER_MODULE(fwip, firewire, fwip_driver, 0, 0);
930b8b33234SDoug Rabson MODULE_VERSION(fwip, 1);
931b8b33234SDoug Rabson MODULE_DEPEND(fwip, firewire, 1, 1, 1);
932