1227064Sbz/*
2250340Sdavidcs * Copyright (c) 2011-2013 Qlogic Corporation
3227064Sbz * All rights reserved.
4227064Sbz *
5227064Sbz *  Redistribution and use in source and binary forms, with or without
6227064Sbz *  modification, are permitted provided that the following conditions
7227064Sbz *  are met:
8227064Sbz *
9227064Sbz *  1. Redistributions of source code must retain the above copyright
10227064Sbz *     notice, this list of conditions and the following disclaimer.
11227064Sbz *  2. Redistributions in binary form must reproduce the above copyright
12227064Sbz *     notice, this list of conditions and the following disclaimer in the
13227064Sbz *     documentation and/or other materials provided with the distribution.
14227064Sbz *
15227064Sbz *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16227064Sbz *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17227064Sbz *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18227064Sbz *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19227064Sbz *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20227064Sbz *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21227064Sbz *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22227064Sbz *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23227064Sbz *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24227064Sbz *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25227064Sbz *  POSSIBILITY OF SUCH DAMAGE.
26227064Sbz */
27227064Sbz
28227064Sbz/*
29227064Sbz * File: qla_os.c
30227064Sbz * Author : David C Somayajulu, Qlogic Corporation, Aliso Viejo, CA 92656.
31227064Sbz */
32227064Sbz
33227064Sbz#include <sys/cdefs.h>
34227064Sbz__FBSDID("$FreeBSD$");
35227064Sbz
36227064Sbz#include "qla_os.h"
37227064Sbz#include "qla_reg.h"
38227064Sbz#include "qla_hw.h"
39227064Sbz#include "qla_def.h"
40227064Sbz#include "qla_inline.h"
41227064Sbz#include "qla_ver.h"
42227064Sbz#include "qla_glbl.h"
43227064Sbz#include "qla_dbg.h"
44227064Sbz
45227064Sbz/*
46227064Sbz * Some PCI Configuration Space Related Defines
47227064Sbz */
48227064Sbz
49227064Sbz#ifndef PCI_VENDOR_QLOGIC
50227064Sbz#define PCI_VENDOR_QLOGIC	0x1077
51227064Sbz#endif
52227064Sbz
53227064Sbz#ifndef PCI_PRODUCT_QLOGIC_ISP8020
54227064Sbz#define PCI_PRODUCT_QLOGIC_ISP8020	0x8020
55227064Sbz#endif
56227064Sbz
57227064Sbz#define PCI_QLOGIC_ISP8020 \
58227064Sbz	((PCI_PRODUCT_QLOGIC_ISP8020 << 16) | PCI_VENDOR_QLOGIC)
59227064Sbz
60227064Sbz/*
61227064Sbz * static functions
62227064Sbz */
63227064Sbzstatic int qla_alloc_parent_dma_tag(qla_host_t *ha);
64227064Sbzstatic void qla_free_parent_dma_tag(qla_host_t *ha);
65227064Sbzstatic int qla_alloc_xmt_bufs(qla_host_t *ha);
66227064Sbzstatic void qla_free_xmt_bufs(qla_host_t *ha);
67227064Sbzstatic int qla_alloc_rcv_bufs(qla_host_t *ha);
68227064Sbzstatic void qla_free_rcv_bufs(qla_host_t *ha);
69227064Sbz
70227064Sbzstatic void qla_init_ifnet(device_t dev, qla_host_t *ha);
71227064Sbzstatic int qla_sysctl_get_stats(SYSCTL_HANDLER_ARGS);
72227064Sbzstatic void qla_release(qla_host_t *ha);
73227064Sbzstatic void qla_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nsegs,
74227064Sbz		int error);
75227064Sbzstatic void qla_stop(qla_host_t *ha);
76227064Sbzstatic int qla_send(qla_host_t *ha, struct mbuf **m_headp);
77227064Sbzstatic void qla_tx_done(void *context, int pending);
78227064Sbz
79227064Sbz/*
80227064Sbz * Hooks to the Operating Systems
81227064Sbz */
82227064Sbzstatic int qla_pci_probe (device_t);
83227064Sbzstatic int qla_pci_attach (device_t);
84227064Sbzstatic int qla_pci_detach (device_t);
85227064Sbz
86227064Sbzstatic void qla_init(void *arg);
87227064Sbzstatic int qla_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
88227064Sbzstatic int qla_media_change(struct ifnet *ifp);
89227064Sbzstatic void qla_media_status(struct ifnet *ifp, struct ifmediareq *ifmr);
90227064Sbz
91227064Sbzstatic device_method_t qla_pci_methods[] = {
92227064Sbz	/* Device interface */
93227064Sbz	DEVMETHOD(device_probe, qla_pci_probe),
94227064Sbz	DEVMETHOD(device_attach, qla_pci_attach),
95227064Sbz	DEVMETHOD(device_detach, qla_pci_detach),
96227064Sbz	{ 0, 0 }
97227064Sbz};
98227064Sbz
99227064Sbzstatic driver_t qla_pci_driver = {
100227064Sbz	"ql", qla_pci_methods, sizeof (qla_host_t),
101227064Sbz};
102227064Sbz
103227064Sbzstatic devclass_t qla80xx_devclass;
104227064Sbz
105227064SbzDRIVER_MODULE(qla80xx, pci, qla_pci_driver, qla80xx_devclass, 0, 0);
106227064Sbz
107227064SbzMODULE_DEPEND(qla80xx, pci, 1, 1, 1);
108227064SbzMODULE_DEPEND(qla80xx, ether, 1, 1, 1);
109227064Sbz
110227064SbzMALLOC_DEFINE(M_QLA8XXXBUF, "qla80xxbuf", "Buffers for qla80xx driver");
111227064Sbz
112227064Sbzuint32_t std_replenish = 8;
113227064Sbzuint32_t jumbo_replenish = 2;
114227064Sbzuint32_t rcv_pkt_thres = 128;
115227064Sbzuint32_t rcv_pkt_thres_d = 32;
116227064Sbzuint32_t snd_pkt_thres = 16;
117227064Sbzuint32_t free_pkt_thres = (NUM_TX_DESCRIPTORS / 2);
118227064Sbz
119227064Sbzstatic char dev_str[64];
120227064Sbz
121227064Sbz/*
122227064Sbz * Name:	qla_pci_probe
123227064Sbz * Function:	Validate the PCI device to be a QLA80XX device
124227064Sbz */
125227064Sbzstatic int
126227064Sbzqla_pci_probe(device_t dev)
127227064Sbz{
128227064Sbz        switch ((pci_get_device(dev) << 16) | (pci_get_vendor(dev))) {
129227064Sbz        case PCI_QLOGIC_ISP8020:
130227064Sbz		snprintf(dev_str, sizeof(dev_str), "%s v%d.%d.%d",
131227064Sbz			"Qlogic ISP 80xx PCI CNA Adapter-Ethernet Function",
132227064Sbz			QLA_VERSION_MAJOR, QLA_VERSION_MINOR,
133227064Sbz			QLA_VERSION_BUILD);
134227064Sbz                device_set_desc(dev, dev_str);
135227064Sbz                break;
136227064Sbz        default:
137227064Sbz                return (ENXIO);
138227064Sbz        }
139227064Sbz
140227064Sbz        if (bootverbose)
141227064Sbz                printf("%s: %s\n ", __func__, dev_str);
142227064Sbz
143227064Sbz        return (BUS_PROBE_DEFAULT);
144227064Sbz}
145227064Sbz
146227064Sbzstatic void
147227064Sbzqla_add_sysctls(qla_host_t *ha)
148227064Sbz{
149227064Sbz        device_t dev = ha->pci_dev;
150227064Sbz
151227064Sbz        SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
152227064Sbz                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
153227064Sbz                OID_AUTO, "stats", CTLTYPE_INT | CTLFLAG_RD,
154227064Sbz                (void *)ha, 0,
155227064Sbz                qla_sysctl_get_stats, "I", "Statistics");
156227064Sbz
157250340Sdavidcs	SYSCTL_ADD_STRING(device_get_sysctl_ctx(dev),
158250340Sdavidcs		SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
159250340Sdavidcs		OID_AUTO, "fw_version", CTLFLAG_RD,
160273736Shselasky		ha->fw_ver_str, 0, "firmware version");
161250340Sdavidcs
162227064Sbz	dbg_level = 0;
163227064Sbz        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
164227064Sbz                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
165227064Sbz                OID_AUTO, "debug", CTLFLAG_RW,
166227064Sbz                &dbg_level, dbg_level, "Debug Level");
167227064Sbz
168227064Sbz        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
169227064Sbz                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
170227064Sbz                OID_AUTO, "std_replenish", CTLFLAG_RW,
171227064Sbz                &std_replenish, std_replenish,
172227064Sbz                "Threshold for Replenishing Standard Frames");
173227064Sbz
174227064Sbz        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
175227064Sbz                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
176227064Sbz                OID_AUTO, "jumbo_replenish", CTLFLAG_RW,
177227064Sbz                &jumbo_replenish, jumbo_replenish,
178227064Sbz                "Threshold for Replenishing Jumbo Frames");
179227064Sbz
180227064Sbz        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
181227064Sbz                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
182227064Sbz                OID_AUTO, "rcv_pkt_thres",  CTLFLAG_RW,
183227064Sbz                &rcv_pkt_thres, rcv_pkt_thres,
184227064Sbz                "Threshold for # of rcv pkts to trigger indication isr");
185227064Sbz
186227064Sbz        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
187227064Sbz                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
188227064Sbz                OID_AUTO, "rcv_pkt_thres_d",  CTLFLAG_RW,
189227064Sbz                &rcv_pkt_thres_d, rcv_pkt_thres_d,
190227064Sbz                "Threshold for # of rcv pkts to trigger indication defered");
191227064Sbz
192227064Sbz        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
193227064Sbz                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
194227064Sbz                OID_AUTO, "snd_pkt_thres",  CTLFLAG_RW,
195227064Sbz                &snd_pkt_thres, snd_pkt_thres,
196227064Sbz                "Threshold for # of snd packets");
197227064Sbz
198227064Sbz        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
199227064Sbz                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
200227064Sbz                OID_AUTO, "free_pkt_thres",  CTLFLAG_RW,
201227064Sbz                &free_pkt_thres, free_pkt_thres,
202227064Sbz                "Threshold for # of packets to free at a time");
203227064Sbz
204227064Sbz        return;
205227064Sbz}
206227064Sbz
207227064Sbzstatic void
208227064Sbzqla_watchdog(void *arg)
209227064Sbz{
210227064Sbz	qla_host_t *ha = arg;
211227064Sbz	qla_hw_t *hw;
212227064Sbz	struct ifnet *ifp;
213227064Sbz
214227064Sbz	hw = &ha->hw;
215227064Sbz	ifp = ha->ifp;
216227064Sbz
217227064Sbz        if (ha->flags.qla_watchdog_exit)
218227064Sbz		return;
219227064Sbz
220227064Sbz	if (!ha->flags.qla_watchdog_pause) {
221227064Sbz		if (qla_le32_to_host(*(hw->tx_cons)) != hw->txr_comp) {
222227064Sbz			taskqueue_enqueue(ha->tx_tq, &ha->tx_task);
223227064Sbz		} else if ((ifp->if_snd.ifq_head != NULL) && QL_RUNNING(ifp)) {
224227064Sbz			taskqueue_enqueue(ha->tx_tq, &ha->tx_task);
225227064Sbz		}
226227064Sbz	}
227227064Sbz	ha->watchdog_ticks = ha->watchdog_ticks++ % 1000;
228227064Sbz	callout_reset(&ha->tx_callout, QLA_WATCHDOG_CALLOUT_TICKS,
229227064Sbz		qla_watchdog, ha);
230227064Sbz}
231227064Sbz
232227064Sbz/*
233227064Sbz * Name:	qla_pci_attach
234227064Sbz * Function:	attaches the device to the operating system
235227064Sbz */
236227064Sbzstatic int
237227064Sbzqla_pci_attach(device_t dev)
238227064Sbz{
239227064Sbz	qla_host_t *ha = NULL;
240227064Sbz	uint32_t rsrc_len, i;
241227064Sbz
242227064Sbz	QL_DPRINT2((dev, "%s: enter\n", __func__));
243227064Sbz
244227064Sbz        if ((ha = device_get_softc(dev)) == NULL) {
245227064Sbz                device_printf(dev, "cannot get softc\n");
246227064Sbz                return (ENOMEM);
247227064Sbz        }
248227064Sbz
249227064Sbz        memset(ha, 0, sizeof (qla_host_t));
250227064Sbz
251227064Sbz        if (pci_get_device(dev) != PCI_PRODUCT_QLOGIC_ISP8020) {
252227064Sbz                device_printf(dev, "device is not ISP8020\n");
253227064Sbz                return (ENXIO);
254227064Sbz	}
255227064Sbz
256227064Sbz        ha->pci_func = pci_get_function(dev);
257227064Sbz
258227064Sbz        ha->pci_dev = dev;
259227064Sbz
260227064Sbz	pci_enable_busmaster(dev);
261227064Sbz
262227064Sbz	ha->reg_rid = PCIR_BAR(0);
263227064Sbz	ha->pci_reg = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &ha->reg_rid,
264227064Sbz				RF_ACTIVE);
265227064Sbz
266227064Sbz        if (ha->pci_reg == NULL) {
267227064Sbz                device_printf(dev, "unable to map any ports\n");
268227064Sbz                goto qla_pci_attach_err;
269227064Sbz        }
270227064Sbz
271227064Sbz	rsrc_len = (uint32_t) bus_get_resource_count(dev, SYS_RES_MEMORY,
272227064Sbz					ha->reg_rid);
273227064Sbz
274227064Sbz	mtx_init(&ha->hw_lock, "qla80xx_hw_lock", MTX_NETWORK_LOCK, MTX_DEF);
275227064Sbz	mtx_init(&ha->tx_lock, "qla80xx_tx_lock", MTX_NETWORK_LOCK, MTX_DEF);
276227064Sbz	mtx_init(&ha->rx_lock, "qla80xx_rx_lock", MTX_NETWORK_LOCK, MTX_DEF);
277227064Sbz	mtx_init(&ha->rxj_lock, "qla80xx_rxj_lock", MTX_NETWORK_LOCK, MTX_DEF);
278227064Sbz	ha->flags.lock_init = 1;
279227064Sbz
280227064Sbz	ha->msix_count = pci_msix_count(dev);
281227064Sbz
282227064Sbz	if (ha->msix_count < qla_get_msix_count(ha)) {
283227064Sbz		device_printf(dev, "%s: msix_count[%d] not enough\n", __func__,
284227064Sbz			ha->msix_count);
285227064Sbz		goto qla_pci_attach_err;
286227064Sbz	}
287227064Sbz
288227064Sbz	QL_DPRINT2((dev, "%s: ha %p irq %p pci_func 0x%x rsrc_count 0x%08x"
289227064Sbz		" msix_count 0x%x pci_reg %p\n", __func__, ha,
290227064Sbz		ha->irq, ha->pci_func, rsrc_len, ha->msix_count, ha->pci_reg));
291227064Sbz
292227064Sbz	ha->msix_count = qla_get_msix_count(ha);
293227064Sbz
294227064Sbz	if (pci_alloc_msix(dev, &ha->msix_count)) {
295227064Sbz		device_printf(dev, "%s: pci_alloc_msi[%d] failed\n", __func__,
296227064Sbz			ha->msix_count);
297227064Sbz		ha->msix_count = 0;
298227064Sbz		goto qla_pci_attach_err;
299227064Sbz	}
300227064Sbz
301227064Sbz	TASK_INIT(&ha->tx_task, 0, qla_tx_done, ha);
302227064Sbz	ha->tx_tq = taskqueue_create_fast("qla_txq", M_NOWAIT,
303227064Sbz			taskqueue_thread_enqueue, &ha->tx_tq);
304227064Sbz	taskqueue_start_threads(&ha->tx_tq, 1, PI_NET, "%s txq",
305227064Sbz		device_get_nameunit(ha->pci_dev));
306227064Sbz
307227064Sbz        for (i = 0; i < ha->msix_count; i++) {
308227064Sbz                ha->irq_vec[i].irq_rid = i+1;
309227064Sbz                ha->irq_vec[i].ha = ha;
310227064Sbz
311227064Sbz                ha->irq_vec[i].irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
312227064Sbz                                        &ha->irq_vec[i].irq_rid,
313227064Sbz                                        (RF_ACTIVE | RF_SHAREABLE));
314227064Sbz
315227064Sbz                if (ha->irq_vec[i].irq == NULL) {
316227064Sbz                        device_printf(dev, "could not allocate interrupt\n");
317227064Sbz                        goto qla_pci_attach_err;
318227064Sbz                }
319227064Sbz
320227064Sbz                if (bus_setup_intr(dev, ha->irq_vec[i].irq,
321227064Sbz                        (INTR_TYPE_NET | INTR_MPSAFE),
322227064Sbz                        NULL, qla_isr, &ha->irq_vec[i],
323227064Sbz                        &ha->irq_vec[i].handle)) {
324227064Sbz                        device_printf(dev, "could not setup interrupt\n");
325227064Sbz                        goto qla_pci_attach_err;
326227064Sbz                }
327227064Sbz
328227064Sbz		TASK_INIT(&ha->irq_vec[i].rcv_task, 0, qla_rcv,\
329227064Sbz			&ha->irq_vec[i]);
330227064Sbz
331227064Sbz		ha->irq_vec[i].rcv_tq = taskqueue_create_fast("qla_rcvq",
332227064Sbz			M_NOWAIT, taskqueue_thread_enqueue,
333227064Sbz			&ha->irq_vec[i].rcv_tq);
334227064Sbz
335227064Sbz		taskqueue_start_threads(&ha->irq_vec[i].rcv_tq, 1, PI_NET,
336227064Sbz			"%s rcvq",
337227064Sbz			device_get_nameunit(ha->pci_dev));
338227064Sbz        }
339227064Sbz
340227064Sbz	qla_add_sysctls(ha);
341227064Sbz
342227064Sbz	/* add hardware specific sysctls */
343227064Sbz	qla_hw_add_sysctls(ha);
344227064Sbz
345227064Sbz	/* initialize hardware */
346227064Sbz	if (qla_init_hw(ha)) {
347227064Sbz		device_printf(dev, "%s: qla_init_hw failed\n", __func__);
348227064Sbz		goto qla_pci_attach_err;
349227064Sbz	}
350227064Sbz
351227064Sbz	device_printf(dev, "%s: firmware[%d.%d.%d.%d]\n", __func__,
352227064Sbz		ha->fw_ver_major, ha->fw_ver_minor, ha->fw_ver_sub,
353227064Sbz		ha->fw_ver_build);
354227064Sbz
355250340Sdavidcs	snprintf(ha->fw_ver_str, sizeof(ha->fw_ver_str), "%d.%d.%d.%d",
356250340Sdavidcs			ha->fw_ver_major, ha->fw_ver_minor, ha->fw_ver_sub,
357250340Sdavidcs			ha->fw_ver_build);
358250340Sdavidcs
359227064Sbz	//qla_get_hw_caps(ha);
360227064Sbz	qla_read_mac_addr(ha);
361227064Sbz
362227064Sbz	/* allocate parent dma tag */
363227064Sbz	if (qla_alloc_parent_dma_tag(ha)) {
364227064Sbz		device_printf(dev, "%s: qla_alloc_parent_dma_tag failed\n",
365227064Sbz			__func__);
366227064Sbz		goto qla_pci_attach_err;
367227064Sbz	}
368227064Sbz
369227064Sbz	/* alloc all dma buffers */
370227064Sbz	if (qla_alloc_dma(ha)) {
371227064Sbz		device_printf(dev, "%s: qla_alloc_dma failed\n", __func__);
372227064Sbz		goto qla_pci_attach_err;
373227064Sbz	}
374227064Sbz
375227064Sbz	/* create the o.s ethernet interface */
376227064Sbz	qla_init_ifnet(dev, ha);
377227064Sbz
378227064Sbz	ha->flags.qla_watchdog_active = 1;
379227064Sbz	ha->flags.qla_watchdog_pause = 1;
380227064Sbz
381227064Sbz	callout_init(&ha->tx_callout, TRUE);
382227064Sbz
383227064Sbz	/* create ioctl device interface */
384227064Sbz	if (qla_make_cdev(ha)) {
385227064Sbz		device_printf(dev, "%s: qla_make_cdev failed\n", __func__);
386227064Sbz		goto qla_pci_attach_err;
387227064Sbz	}
388227064Sbz
389227064Sbz	callout_reset(&ha->tx_callout, QLA_WATCHDOG_CALLOUT_TICKS,
390227064Sbz		qla_watchdog, ha);
391227064Sbz
392227064Sbz	QL_DPRINT2((dev, "%s: exit 0\n", __func__));
393227064Sbz        return (0);
394227064Sbz
395227064Sbzqla_pci_attach_err:
396227064Sbz
397227064Sbz	qla_release(ha);
398227064Sbz
399227064Sbz	QL_DPRINT2((dev, "%s: exit ENXIO\n", __func__));
400227064Sbz        return (ENXIO);
401227064Sbz}
402227064Sbz
403227064Sbz/*
404227064Sbz * Name:	qla_pci_detach
405227064Sbz * Function:	Unhooks the device from the operating system
406227064Sbz */
407227064Sbzstatic int
408227064Sbzqla_pci_detach(device_t dev)
409227064Sbz{
410227064Sbz	qla_host_t *ha = NULL;
411227064Sbz	struct ifnet *ifp;
412227064Sbz	int i;
413227064Sbz
414227064Sbz	QL_DPRINT2((dev, "%s: enter\n", __func__));
415227064Sbz
416227064Sbz        if ((ha = device_get_softc(dev)) == NULL) {
417227064Sbz                device_printf(dev, "cannot get softc\n");
418227064Sbz                return (ENOMEM);
419227064Sbz        }
420227064Sbz
421227064Sbz	ifp = ha->ifp;
422227064Sbz
423227064Sbz	QLA_LOCK(ha, __func__);
424227064Sbz	qla_stop(ha);
425227064Sbz	QLA_UNLOCK(ha, __func__);
426227064Sbz
427227064Sbz	if (ha->tx_tq) {
428227064Sbz		taskqueue_drain(ha->tx_tq, &ha->tx_task);
429227064Sbz		taskqueue_free(ha->tx_tq);
430227064Sbz	}
431227064Sbz
432227064Sbz        for (i = 0; i < ha->msix_count; i++) {
433227064Sbz		taskqueue_drain(ha->irq_vec[i].rcv_tq,
434227064Sbz			&ha->irq_vec[i].rcv_task);
435227064Sbz		taskqueue_free(ha->irq_vec[i].rcv_tq);
436227064Sbz	}
437227064Sbz
438227064Sbz	qla_release(ha);
439227064Sbz
440227064Sbz	QL_DPRINT2((dev, "%s: exit\n", __func__));
441227064Sbz
442227064Sbz        return (0);
443227064Sbz}
444227064Sbz
445227064Sbz/*
446227064Sbz * SYSCTL Related Callbacks
447227064Sbz */
448227064Sbzstatic int
449227064Sbzqla_sysctl_get_stats(SYSCTL_HANDLER_ARGS)
450227064Sbz{
451227064Sbz	int err, ret = 0;
452227064Sbz	qla_host_t *ha;
453227064Sbz
454227064Sbz	err = sysctl_handle_int(oidp, &ret, 0, req);
455227064Sbz
456227064Sbz	if (err)
457227064Sbz		return (err);
458227064Sbz
459227064Sbz	ha = (qla_host_t *)arg1;
460227064Sbz	//qla_get_stats(ha);
461227064Sbz	QL_DPRINT2((ha->pci_dev, "%s: called ret %d\n", __func__, ret));
462227064Sbz	return (err);
463227064Sbz}
464227064Sbz
465227064Sbz
466227064Sbz/*
467227064Sbz * Name:	qla_release
468227064Sbz * Function:	Releases the resources allocated for the device
469227064Sbz */
470227064Sbzstatic void
471227064Sbzqla_release(qla_host_t *ha)
472227064Sbz{
473227064Sbz	device_t dev;
474227064Sbz	int i;
475227064Sbz
476227064Sbz	dev = ha->pci_dev;
477227064Sbz
478227064Sbz	qla_del_cdev(ha);
479227064Sbz
480227064Sbz	if (ha->flags.qla_watchdog_active)
481227064Sbz		ha->flags.qla_watchdog_exit = 1;
482227064Sbz
483227064Sbz	callout_stop(&ha->tx_callout);
484227064Sbz	qla_mdelay(__func__, 100);
485227064Sbz
486227064Sbz	if (ha->ifp != NULL)
487227064Sbz		ether_ifdetach(ha->ifp);
488227064Sbz
489227064Sbz	qla_free_dma(ha);
490227064Sbz	qla_free_parent_dma_tag(ha);
491227064Sbz
492227064Sbz	for (i = 0; i < ha->msix_count; i++) {
493227064Sbz		if (ha->irq_vec[i].handle)
494227064Sbz			(void)bus_teardown_intr(dev, ha->irq_vec[i].irq,
495227064Sbz				ha->irq_vec[i].handle);
496227064Sbz		if (ha->irq_vec[i].irq)
497227064Sbz			(void) bus_release_resource(dev, SYS_RES_IRQ,
498227064Sbz				ha->irq_vec[i].irq_rid,
499227064Sbz				ha->irq_vec[i].irq);
500227064Sbz	}
501227064Sbz	if (ha->msix_count)
502227064Sbz		pci_release_msi(dev);
503227064Sbz
504227064Sbz	if (ha->flags.lock_init) {
505227064Sbz		mtx_destroy(&ha->tx_lock);
506227064Sbz		mtx_destroy(&ha->rx_lock);
507227064Sbz		mtx_destroy(&ha->rxj_lock);
508227064Sbz		mtx_destroy(&ha->hw_lock);
509227064Sbz	}
510227064Sbz
511227064Sbz        if (ha->pci_reg)
512227064Sbz                (void) bus_release_resource(dev, SYS_RES_MEMORY, ha->reg_rid,
513227064Sbz				ha->pci_reg);
514227064Sbz}
515227064Sbz
516227064Sbz/*
517227064Sbz * DMA Related Functions
518227064Sbz */
519227064Sbz
520227064Sbzstatic void
521227064Sbzqla_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
522227064Sbz{
523227064Sbz        *((bus_addr_t *)arg) = 0;
524227064Sbz
525227064Sbz        if (error) {
526227064Sbz                printf("%s: bus_dmamap_load failed (%d)\n", __func__, error);
527227064Sbz                return;
528227064Sbz	}
529227064Sbz
530227064Sbz        QL_ASSERT((nsegs == 1), ("%s: %d segments returned!", __func__, nsegs));
531227064Sbz
532227064Sbz        *((bus_addr_t *)arg) = segs[0].ds_addr;
533227064Sbz
534227064Sbz	return;
535227064Sbz}
536227064Sbz
537227064Sbzint
538227064Sbzqla_alloc_dmabuf(qla_host_t *ha, qla_dma_t *dma_buf)
539227064Sbz{
540227064Sbz        int             ret = 0;
541227064Sbz        device_t        dev;
542227064Sbz        bus_addr_t      b_addr;
543227064Sbz
544227064Sbz        dev = ha->pci_dev;
545227064Sbz
546227064Sbz        QL_DPRINT2((dev, "%s: enter\n", __func__));
547227064Sbz
548227064Sbz        ret = bus_dma_tag_create(
549227064Sbz                        ha->parent_tag,/* parent */
550227064Sbz                        dma_buf->alignment,
551227064Sbz                        ((bus_size_t)(1ULL << 32)),/* boundary */
552227064Sbz                        BUS_SPACE_MAXADDR,      /* lowaddr */
553227064Sbz                        BUS_SPACE_MAXADDR,      /* highaddr */
554227064Sbz                        NULL, NULL,             /* filter, filterarg */
555227064Sbz                        dma_buf->size,          /* maxsize */
556227064Sbz                        1,                      /* nsegments */
557227064Sbz                        dma_buf->size,          /* maxsegsize */
558227064Sbz                        0,                      /* flags */
559227064Sbz                        NULL, NULL,             /* lockfunc, lockarg */
560227064Sbz                        &dma_buf->dma_tag);
561227064Sbz
562227064Sbz        if (ret) {
563227064Sbz                device_printf(dev, "%s: could not create dma tag\n", __func__);
564227064Sbz                goto qla_alloc_dmabuf_exit;
565227064Sbz        }
566227064Sbz        ret = bus_dmamem_alloc(dma_buf->dma_tag,
567227064Sbz                        (void **)&dma_buf->dma_b,
568227064Sbz                        (BUS_DMA_ZERO | BUS_DMA_COHERENT | BUS_DMA_NOWAIT),
569227064Sbz                        &dma_buf->dma_map);
570227064Sbz        if (ret) {
571227064Sbz                bus_dma_tag_destroy(dma_buf->dma_tag);
572227064Sbz                device_printf(dev, "%s: bus_dmamem_alloc failed\n", __func__);
573227064Sbz                goto qla_alloc_dmabuf_exit;
574227064Sbz        }
575227064Sbz
576227064Sbz        ret = bus_dmamap_load(dma_buf->dma_tag,
577227064Sbz                        dma_buf->dma_map,
578227064Sbz                        dma_buf->dma_b,
579227064Sbz                        dma_buf->size,
580227064Sbz                        qla_dmamap_callback,
581227064Sbz                        &b_addr, BUS_DMA_NOWAIT);
582227064Sbz
583227064Sbz        if (ret || !b_addr) {
584227064Sbz                bus_dma_tag_destroy(dma_buf->dma_tag);
585227064Sbz                bus_dmamem_free(dma_buf->dma_tag, dma_buf->dma_b,
586227064Sbz                        dma_buf->dma_map);
587227064Sbz                ret = -1;
588227064Sbz                goto qla_alloc_dmabuf_exit;
589227064Sbz        }
590227064Sbz
591227064Sbz        dma_buf->dma_addr = b_addr;
592227064Sbz
593227064Sbzqla_alloc_dmabuf_exit:
594227064Sbz        QL_DPRINT2((dev, "%s: exit ret 0x%08x tag %p map %p b %p sz 0x%x\n",
595227064Sbz                __func__, ret, (void *)dma_buf->dma_tag,
596227064Sbz                (void *)dma_buf->dma_map, (void *)dma_buf->dma_b,
597227064Sbz		dma_buf->size));
598227064Sbz
599227064Sbz        return ret;
600227064Sbz}
601227064Sbz
602227064Sbzvoid
603227064Sbzqla_free_dmabuf(qla_host_t *ha, qla_dma_t *dma_buf)
604227064Sbz{
605227064Sbz        bus_dmamem_free(dma_buf->dma_tag, dma_buf->dma_b, dma_buf->dma_map);
606227064Sbz        bus_dma_tag_destroy(dma_buf->dma_tag);
607227064Sbz}
608227064Sbz
609227064Sbzstatic int
610227064Sbzqla_alloc_parent_dma_tag(qla_host_t *ha)
611227064Sbz{
612227064Sbz	int		ret;
613227064Sbz	device_t	dev;
614227064Sbz
615227064Sbz	dev = ha->pci_dev;
616227064Sbz
617227064Sbz        /*
618227064Sbz         * Allocate parent DMA Tag
619227064Sbz         */
620227064Sbz        ret = bus_dma_tag_create(
621227064Sbz                        bus_get_dma_tag(dev),   /* parent */
622227064Sbz                        1,((bus_size_t)(1ULL << 32)),/* alignment, boundary */
623227064Sbz                        BUS_SPACE_MAXADDR,      /* lowaddr */
624227064Sbz                        BUS_SPACE_MAXADDR,      /* highaddr */
625227064Sbz                        NULL, NULL,             /* filter, filterarg */
626227064Sbz                        BUS_SPACE_MAXSIZE_32BIT,/* maxsize */
627227064Sbz                        0,                      /* nsegments */
628227064Sbz                        BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
629227064Sbz                        0,                      /* flags */
630227064Sbz                        NULL, NULL,             /* lockfunc, lockarg */
631227064Sbz                        &ha->parent_tag);
632227064Sbz
633227064Sbz        if (ret) {
634227064Sbz                device_printf(dev, "%s: could not create parent dma tag\n",
635227064Sbz                        __func__);
636227064Sbz		return (-1);
637227064Sbz        }
638227064Sbz
639227064Sbz        ha->flags.parent_tag = 1;
640227064Sbz
641227064Sbz	return (0);
642227064Sbz}
643227064Sbz
644227064Sbzstatic void
645227064Sbzqla_free_parent_dma_tag(qla_host_t *ha)
646227064Sbz{
647227064Sbz        if (ha->flags.parent_tag) {
648227064Sbz                bus_dma_tag_destroy(ha->parent_tag);
649227064Sbz                ha->flags.parent_tag = 0;
650227064Sbz        }
651227064Sbz}
652227064Sbz
653227064Sbz/*
654227064Sbz * Name: qla_init_ifnet
655227064Sbz * Function: Creates the Network Device Interface and Registers it with the O.S
656227064Sbz */
657227064Sbz
658227064Sbzstatic void
659227064Sbzqla_init_ifnet(device_t dev, qla_host_t *ha)
660227064Sbz{
661227064Sbz	struct ifnet *ifp;
662227064Sbz
663227064Sbz	QL_DPRINT2((dev, "%s: enter\n", __func__));
664227064Sbz
665227064Sbz	ifp = ha->ifp = if_alloc(IFT_ETHER);
666227064Sbz
667227064Sbz	if (ifp == NULL)
668227064Sbz		panic("%s: cannot if_alloc()\n", device_get_nameunit(dev));
669227064Sbz
670227064Sbz	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
671227064Sbz
672250375Sdavidcs	if_initbaudrate(ifp, IF_Gbps(10));
673227064Sbz	ifp->if_init = qla_init;
674227064Sbz	ifp->if_softc = ha;
675227064Sbz	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
676227064Sbz	ifp->if_ioctl = qla_ioctl;
677227064Sbz	ifp->if_start = qla_start;
678227064Sbz
679227064Sbz	IFQ_SET_MAXLEN(&ifp->if_snd, qla_get_ifq_snd_maxlen(ha));
680227064Sbz	ifp->if_snd.ifq_drv_maxlen = qla_get_ifq_snd_maxlen(ha);
681227064Sbz	IFQ_SET_READY(&ifp->if_snd);
682227064Sbz
683227064Sbz	ha->max_frame_size = ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN;
684227064Sbz
685227064Sbz	ether_ifattach(ifp, qla_get_mac_addr(ha));
686227064Sbz
687227064Sbz	ifp->if_capabilities = IFCAP_HWCSUM |
688227064Sbz				IFCAP_TSO4 |
689227064Sbz				IFCAP_JUMBO_MTU;
690227064Sbz
691227064Sbz	ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
692250375Sdavidcs	ifp->if_capabilities |= IFCAP_LINKSTATE;
693227064Sbz
694227064Sbz#if defined(__FreeBSD_version) && (__FreeBSD_version < 900002)
695227064Sbz	ifp->if_timer = 0;
696227064Sbz	ifp->if_watchdog = NULL;
697227064Sbz#endif /* #if defined(__FreeBSD_version) && (__FreeBSD_version < 900002) */
698227064Sbz
699227064Sbz	ifp->if_capenable = ifp->if_capabilities;
700227064Sbz
701227064Sbz	ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
702227064Sbz
703227064Sbz	ifmedia_init(&ha->media, IFM_IMASK, qla_media_change, qla_media_status);
704227064Sbz
705227064Sbz	ifmedia_add(&ha->media, (IFM_ETHER | qla_get_optics(ha) | IFM_FDX), 0,
706227064Sbz		NULL);
707227064Sbz	ifmedia_add(&ha->media, (IFM_ETHER | IFM_AUTO), 0, NULL);
708227064Sbz
709227064Sbz	ifmedia_set(&ha->media, (IFM_ETHER | IFM_AUTO));
710227064Sbz
711227064Sbz	QL_DPRINT2((dev, "%s: exit\n", __func__));
712227064Sbz
713227064Sbz	return;
714227064Sbz}
715227064Sbz
716227064Sbzstatic void
717227064Sbzqla_init_locked(qla_host_t *ha)
718227064Sbz{
719227064Sbz	struct ifnet *ifp = ha->ifp;
720227064Sbz
721227064Sbz	qla_stop(ha);
722227064Sbz
723227064Sbz	if (qla_alloc_xmt_bufs(ha) != 0)
724227064Sbz		return;
725227064Sbz
726227064Sbz	if (qla_alloc_rcv_bufs(ha) != 0)
727227064Sbz		return;
728227064Sbz
729227064Sbz	if (qla_config_lro(ha))
730227064Sbz		return;
731227064Sbz
732227064Sbz	bcopy(IF_LLADDR(ha->ifp), ha->hw.mac_addr, ETHER_ADDR_LEN);
733227064Sbz
734227064Sbz	ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_TSO;
735227064Sbz
736227064Sbz	ha->flags.stop_rcv = 0;
737227064Sbz	if (qla_init_hw_if(ha) == 0) {
738227064Sbz		ifp = ha->ifp;
739227064Sbz		ifp->if_drv_flags |= IFF_DRV_RUNNING;
740227064Sbz		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
741227064Sbz		ha->flags.qla_watchdog_pause = 0;
742227064Sbz	}
743227064Sbz
744227064Sbz	return;
745227064Sbz}
746227064Sbz
747227064Sbzstatic void
748227064Sbzqla_init(void *arg)
749227064Sbz{
750227064Sbz	qla_host_t *ha;
751227064Sbz
752227064Sbz	ha = (qla_host_t *)arg;
753227064Sbz
754227064Sbz	QL_DPRINT2((ha->pci_dev, "%s: enter\n", __func__));
755227064Sbz
756227064Sbz	QLA_LOCK(ha, __func__);
757227064Sbz	qla_init_locked(ha);
758227064Sbz	QLA_UNLOCK(ha, __func__);
759227064Sbz
760227064Sbz	QL_DPRINT2((ha->pci_dev, "%s: exit\n", __func__));
761227064Sbz}
762227064Sbz
763227064Sbzstatic void
764227064Sbzqla_set_multi(qla_host_t *ha, uint32_t add_multi)
765227064Sbz{
766227064Sbz	uint8_t mta[Q8_MAX_NUM_MULTICAST_ADDRS * Q8_MAC_ADDR_LEN];
767227064Sbz	struct ifmultiaddr *ifma;
768227064Sbz	int mcnt = 0;
769227064Sbz	struct ifnet *ifp = ha->ifp;
770227064Sbz
771229613Sjhb	if_maddr_rlock(ifp);
772227064Sbz
773227064Sbz	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
774227064Sbz
775227064Sbz		if (ifma->ifma_addr->sa_family != AF_LINK)
776227064Sbz			continue;
777227064Sbz
778227064Sbz		if (mcnt == Q8_MAX_NUM_MULTICAST_ADDRS)
779227064Sbz			break;
780227064Sbz
781227064Sbz		bcopy(LLADDR((struct sockaddr_dl *) ifma->ifma_addr),
782227064Sbz			&mta[mcnt * Q8_MAC_ADDR_LEN], Q8_MAC_ADDR_LEN);
783227064Sbz
784227064Sbz		mcnt++;
785227064Sbz	}
786227064Sbz
787229613Sjhb	if_maddr_runlock(ifp);
788227064Sbz
789227064Sbz	qla_hw_set_multi(ha, mta, mcnt, add_multi);
790227064Sbz
791227064Sbz	return;
792227064Sbz}
793227064Sbz
794227064Sbzstatic int
795227064Sbzqla_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
796227064Sbz{
797227064Sbz	int ret = 0;
798227064Sbz	struct ifreq *ifr = (struct ifreq *)data;
799227064Sbz	struct ifaddr *ifa = (struct ifaddr *)data;
800227064Sbz	qla_host_t *ha;
801227064Sbz
802227064Sbz	ha = (qla_host_t *)ifp->if_softc;
803227064Sbz
804227064Sbz	switch (cmd) {
805227064Sbz	case SIOCSIFADDR:
806227064Sbz		QL_DPRINT4((ha->pci_dev, "%s: SIOCSIFADDR (0x%lx)\n",
807227064Sbz			__func__, cmd));
808227064Sbz
809227064Sbz		if (ifa->ifa_addr->sa_family == AF_INET) {
810227064Sbz			ifp->if_flags |= IFF_UP;
811227064Sbz			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
812227064Sbz				QLA_LOCK(ha, __func__);
813227064Sbz				qla_init_locked(ha);
814227064Sbz				QLA_UNLOCK(ha, __func__);
815227064Sbz			}
816227064Sbz		QL_DPRINT4((ha->pci_dev,
817227064Sbz			"%s: SIOCSIFADDR (0x%lx) ipv4 [0x%08x]\n",
818227064Sbz			__func__, cmd, ntohl(IA_SIN(ifa)->sin_addr.s_addr)));
819227064Sbz
820227064Sbz			arp_ifinit(ifp, ifa);
821227064Sbz			if (ntohl(IA_SIN(ifa)->sin_addr.s_addr) != INADDR_ANY) {
822227064Sbz				qla_config_ipv4_addr(ha,
823227064Sbz					(IA_SIN(ifa)->sin_addr.s_addr));
824227064Sbz			}
825227064Sbz		} else {
826227064Sbz			ether_ioctl(ifp, cmd, data);
827227064Sbz		}
828227064Sbz		break;
829227064Sbz
830227064Sbz	case SIOCSIFMTU:
831227064Sbz		QL_DPRINT4((ha->pci_dev, "%s: SIOCSIFMTU (0x%lx)\n",
832227064Sbz			__func__, cmd));
833227064Sbz
834227064Sbz		if (ifr->ifr_mtu > QLA_MAX_FRAME_SIZE - ETHER_HDR_LEN) {
835227064Sbz			ret = EINVAL;
836227064Sbz		} else {
837227064Sbz			QLA_LOCK(ha, __func__);
838227064Sbz			ifp->if_mtu = ifr->ifr_mtu;
839227064Sbz			ha->max_frame_size =
840227064Sbz				ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN;
841227064Sbz			if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) {
842227064Sbz				ret = qla_set_max_mtu(ha, ha->max_frame_size,
843227064Sbz					(ha->hw.rx_cntxt_rsp)->rx_rsp.cntxt_id);
844227064Sbz			}
845227064Sbz			QLA_UNLOCK(ha, __func__);
846227064Sbz
847227064Sbz			if (ret)
848227064Sbz				ret = EINVAL;
849227064Sbz		}
850227064Sbz
851227064Sbz		break;
852227064Sbz
853227064Sbz	case SIOCSIFFLAGS:
854227064Sbz		QL_DPRINT4((ha->pci_dev, "%s: SIOCSIFFLAGS (0x%lx)\n",
855227064Sbz			__func__, cmd));
856227064Sbz
857227064Sbz		if (ifp->if_flags & IFF_UP) {
858227064Sbz			if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) {
859227064Sbz				if ((ifp->if_flags ^ ha->if_flags) &
860227064Sbz					IFF_PROMISC) {
861227064Sbz					qla_set_promisc(ha);
862227064Sbz				} else if ((ifp->if_flags ^ ha->if_flags) &
863227064Sbz					IFF_ALLMULTI) {
864227064Sbz					qla_set_allmulti(ha);
865227064Sbz				}
866227064Sbz			} else {
867227064Sbz				QLA_LOCK(ha, __func__);
868227064Sbz				qla_init_locked(ha);
869227064Sbz				ha->max_frame_size = ifp->if_mtu +
870227064Sbz					ETHER_HDR_LEN + ETHER_CRC_LEN;
871227064Sbz				ret = qla_set_max_mtu(ha, ha->max_frame_size,
872227064Sbz					(ha->hw.rx_cntxt_rsp)->rx_rsp.cntxt_id);
873227064Sbz				QLA_UNLOCK(ha, __func__);
874227064Sbz			}
875227064Sbz		} else {
876227064Sbz			QLA_LOCK(ha, __func__);
877227064Sbz			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
878227064Sbz				qla_stop(ha);
879227064Sbz			ha->if_flags = ifp->if_flags;
880227064Sbz			QLA_UNLOCK(ha, __func__);
881227064Sbz		}
882227064Sbz		break;
883227064Sbz
884227064Sbz	case SIOCADDMULTI:
885227064Sbz		QL_DPRINT4((ha->pci_dev,
886227064Sbz			"%s: %s (0x%lx)\n", __func__, "SIOCADDMULTI", cmd));
887227064Sbz
888227064Sbz		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
889227064Sbz			qla_set_multi(ha, 1);
890227064Sbz		}
891227064Sbz		break;
892227064Sbz
893227064Sbz	case SIOCDELMULTI:
894227064Sbz		QL_DPRINT4((ha->pci_dev,
895227064Sbz			"%s: %s (0x%lx)\n", __func__, "SIOCDELMULTI", cmd));
896227064Sbz
897227064Sbz		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
898227064Sbz			qla_set_multi(ha, 0);
899227064Sbz		}
900227064Sbz		break;
901227064Sbz
902227064Sbz	case SIOCSIFMEDIA:
903227064Sbz	case SIOCGIFMEDIA:
904227064Sbz		QL_DPRINT4((ha->pci_dev,
905227064Sbz			"%s: SIOCSIFMEDIA/SIOCGIFMEDIA (0x%lx)\n",
906227064Sbz			__func__, cmd));
907227064Sbz		ret = ifmedia_ioctl(ifp, ifr, &ha->media, cmd);
908227064Sbz		break;
909227064Sbz
910227064Sbz	case SIOCSIFCAP:
911227064Sbz	{
912227064Sbz		int mask = ifr->ifr_reqcap ^ ifp->if_capenable;
913227064Sbz
914227064Sbz		QL_DPRINT4((ha->pci_dev, "%s: SIOCSIFCAP (0x%lx)\n",
915227064Sbz			__func__, cmd));
916227064Sbz
917227064Sbz		if (mask & IFCAP_HWCSUM)
918227064Sbz			ifp->if_capenable ^= IFCAP_HWCSUM;
919227064Sbz		if (mask & IFCAP_TSO4)
920227064Sbz			ifp->if_capenable ^= IFCAP_TSO4;
921227064Sbz		if (mask & IFCAP_TSO6)
922227064Sbz			ifp->if_capenable ^= IFCAP_TSO6;
923227064Sbz		if (mask & IFCAP_VLAN_HWTAGGING)
924227064Sbz			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
925227064Sbz
926227064Sbz		if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
927227064Sbz			qla_init(ha);
928227064Sbz
929227064Sbz		VLAN_CAPABILITIES(ifp);
930227064Sbz		break;
931227064Sbz	}
932227064Sbz
933227064Sbz	default:
934227064Sbz		QL_DPRINT4((ha->pci_dev, "%s: default (0x%lx)\n",
935227064Sbz			__func__, cmd));
936227064Sbz		ret = ether_ioctl(ifp, cmd, data);
937227064Sbz		break;
938227064Sbz	}
939227064Sbz
940227064Sbz	return (ret);
941227064Sbz}
942227064Sbz
943227064Sbzstatic int
944227064Sbzqla_media_change(struct ifnet *ifp)
945227064Sbz{
946227064Sbz	qla_host_t *ha;
947227064Sbz	struct ifmedia *ifm;
948227064Sbz	int ret = 0;
949227064Sbz
950227064Sbz	ha = (qla_host_t *)ifp->if_softc;
951227064Sbz
952227064Sbz	QL_DPRINT2((ha->pci_dev, "%s: enter\n", __func__));
953227064Sbz
954227064Sbz	ifm = &ha->media;
955227064Sbz
956227064Sbz	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
957227064Sbz		ret = EINVAL;
958227064Sbz
959227064Sbz	QL_DPRINT2((ha->pci_dev, "%s: exit\n", __func__));
960227064Sbz
961227064Sbz	return (ret);
962227064Sbz}
963227064Sbz
964227064Sbzstatic void
965227064Sbzqla_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
966227064Sbz{
967227064Sbz	qla_host_t *ha;
968227064Sbz
969227064Sbz	ha = (qla_host_t *)ifp->if_softc;
970227064Sbz
971227064Sbz	QL_DPRINT2((ha->pci_dev, "%s: enter\n", __func__));
972227064Sbz
973227064Sbz	ifmr->ifm_status = IFM_AVALID;
974227064Sbz	ifmr->ifm_active = IFM_ETHER;
975227064Sbz
976227064Sbz	qla_update_link_state(ha);
977227064Sbz	if (ha->hw.flags.link_up) {
978227064Sbz		ifmr->ifm_status |= IFM_ACTIVE;
979227064Sbz		ifmr->ifm_active |= (IFM_FDX | qla_get_optics(ha));
980227064Sbz	}
981227064Sbz
982227064Sbz	QL_DPRINT2((ha->pci_dev, "%s: exit (%s)\n", __func__,\
983227064Sbz		(ha->hw.flags.link_up ? "link_up" : "link_down")));
984227064Sbz
985227064Sbz	return;
986227064Sbz}
987227064Sbz
988227064Sbzvoid
989227064Sbzqla_start(struct ifnet *ifp)
990227064Sbz{
991227064Sbz	struct mbuf    *m_head;
992227064Sbz	qla_host_t *ha = (qla_host_t *)ifp->if_softc;
993227064Sbz
994227064Sbz	QL_DPRINT8((ha->pci_dev, "%s: enter\n", __func__));
995227064Sbz
996227064Sbz	if (!mtx_trylock(&ha->tx_lock)) {
997227064Sbz		QL_DPRINT8((ha->pci_dev,
998227064Sbz			"%s: mtx_trylock(&ha->tx_lock) failed\n", __func__));
999227064Sbz		return;
1000227064Sbz	}
1001227064Sbz
1002227064Sbz	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
1003227064Sbz		IFF_DRV_RUNNING) {
1004227064Sbz		QL_DPRINT8((ha->pci_dev, "%s: !IFF_DRV_RUNNING\n", __func__));
1005227064Sbz		QLA_TX_UNLOCK(ha);
1006227064Sbz		return;
1007227064Sbz	}
1008227064Sbz
1009227064Sbz	if (!ha->watchdog_ticks)
1010227064Sbz		qla_update_link_state(ha);
1011227064Sbz
1012227064Sbz	if (!ha->hw.flags.link_up) {
1013227064Sbz		QL_DPRINT8((ha->pci_dev, "%s: link down\n", __func__));
1014227064Sbz		QLA_TX_UNLOCK(ha);
1015227064Sbz		return;
1016227064Sbz	}
1017227064Sbz
1018227064Sbz	while (ifp->if_snd.ifq_head != NULL) {
1019227064Sbz		IF_DEQUEUE(&ifp->if_snd, m_head);
1020227064Sbz
1021227064Sbz		if (m_head == NULL) {
1022227064Sbz			QL_DPRINT8((ha->pci_dev, "%s: m_head == NULL\n",
1023227064Sbz				__func__));
1024227064Sbz			break;
1025227064Sbz		}
1026227064Sbz
1027227064Sbz		if (qla_send(ha, &m_head)) {
1028227064Sbz			if (m_head == NULL)
1029227064Sbz				break;
1030227064Sbz			QL_DPRINT8((ha->pci_dev, "%s: PREPEND\n", __func__));
1031227064Sbz			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1032227064Sbz			IF_PREPEND(&ifp->if_snd, m_head);
1033227064Sbz			break;
1034227064Sbz		}
1035227064Sbz		/* Send a copy of the frame to the BPF listener */
1036227064Sbz		ETHER_BPF_MTAP(ifp, m_head);
1037227064Sbz	}
1038227064Sbz	QLA_TX_UNLOCK(ha);
1039227064Sbz	QL_DPRINT8((ha->pci_dev, "%s: exit\n", __func__));
1040227064Sbz	return;
1041227064Sbz}
1042227064Sbz
1043227064Sbzstatic int
1044227064Sbzqla_send(qla_host_t *ha, struct mbuf **m_headp)
1045227064Sbz{
1046227064Sbz	bus_dma_segment_t	segs[QLA_MAX_SEGMENTS];
1047227064Sbz	bus_dmamap_t		map;
1048227064Sbz	int			nsegs;
1049227064Sbz	int			ret = -1;
1050227064Sbz	uint32_t		tx_idx;
1051227064Sbz	struct mbuf *m_head = *m_headp;
1052227064Sbz
1053227064Sbz	QL_DPRINT8((ha->pci_dev, "%s: enter\n", __func__));
1054227064Sbz
1055227064Sbz	if ((ret = bus_dmamap_create(ha->tx_tag, BUS_DMA_NOWAIT, &map))) {
1056227064Sbz		ha->err_tx_dmamap_create++;
1057227064Sbz		device_printf(ha->pci_dev,
1058227064Sbz			"%s: bus_dmamap_create failed[%d, %d]\n",
1059227064Sbz			__func__, ret, m_head->m_pkthdr.len);
1060227064Sbz		return (ret);
1061227064Sbz	}
1062227064Sbz
1063227064Sbz	ret = bus_dmamap_load_mbuf_sg(ha->tx_tag, map, m_head, segs, &nsegs,
1064227064Sbz			BUS_DMA_NOWAIT);
1065227064Sbz
1066261864Sdavidcs	if (ret == EFBIG) {
1067227064Sbz
1068227064Sbz		struct mbuf *m;
1069227064Sbz
1070227064Sbz		QL_DPRINT8((ha->pci_dev, "%s: EFBIG [%d]\n", __func__,
1071227064Sbz			m_head->m_pkthdr.len));
1072227064Sbz
1073243857Sglebius		m = m_defrag(m_head, M_NOWAIT);
1074227064Sbz		if (m == NULL) {
1075227064Sbz			ha->err_tx_defrag++;
1076227064Sbz			m_freem(m_head);
1077227064Sbz			*m_headp = NULL;
1078227064Sbz			device_printf(ha->pci_dev,
1079227064Sbz				"%s: m_defrag() = NULL [%d]\n",
1080227064Sbz				__func__, ret);
1081227064Sbz			return (ENOBUFS);
1082227064Sbz		}
1083227064Sbz		m_head = m;
1084227064Sbz
1085227064Sbz		if ((ret = bus_dmamap_load_mbuf_sg(ha->tx_tag, map, m_head,
1086227064Sbz					segs, &nsegs, BUS_DMA_NOWAIT))) {
1087227064Sbz
1088227064Sbz			ha->err_tx_dmamap_load++;
1089227064Sbz
1090227064Sbz			device_printf(ha->pci_dev,
1091227064Sbz				"%s: bus_dmamap_load_mbuf_sg failed0[%d, %d]\n",
1092227064Sbz				__func__, ret, m_head->m_pkthdr.len);
1093227064Sbz
1094227064Sbz			bus_dmamap_destroy(ha->tx_tag, map);
1095227064Sbz			if (ret != ENOMEM) {
1096227064Sbz				m_freem(m_head);
1097227064Sbz				*m_headp = NULL;
1098227064Sbz			}
1099227064Sbz			return (ret);
1100227064Sbz		}
1101227064Sbz	} else if (ret) {
1102227064Sbz		ha->err_tx_dmamap_load++;
1103227064Sbz
1104227064Sbz		device_printf(ha->pci_dev,
1105227064Sbz			"%s: bus_dmamap_load_mbuf_sg failed1[%d, %d]\n",
1106227064Sbz			__func__, ret, m_head->m_pkthdr.len);
1107227064Sbz
1108227064Sbz		bus_dmamap_destroy(ha->tx_tag, map);
1109227064Sbz
1110227064Sbz		if (ret != ENOMEM) {
1111227064Sbz			m_freem(m_head);
1112227064Sbz			*m_headp = NULL;
1113227064Sbz		}
1114227064Sbz		return (ret);
1115227064Sbz	}
1116227064Sbz
1117227064Sbz	QL_ASSERT((nsegs != 0), ("qla_send: empty packet"));
1118227064Sbz
1119227064Sbz	bus_dmamap_sync(ha->tx_tag, map, BUS_DMASYNC_PREWRITE);
1120227064Sbz
1121227064Sbz	if (!(ret = qla_hw_send(ha, segs, nsegs, &tx_idx, m_head))) {
1122227064Sbz		ha->tx_buf[tx_idx].m_head = m_head;
1123227064Sbz		ha->tx_buf[tx_idx].map = map;
1124227064Sbz	} else {
1125227064Sbz		if (ret == EINVAL) {
1126227064Sbz			m_freem(m_head);
1127227064Sbz			*m_headp = NULL;
1128227064Sbz		}
1129227064Sbz	}
1130227064Sbz
1131227064Sbz	QL_DPRINT8((ha->pci_dev, "%s: exit\n", __func__));
1132227064Sbz	return (ret);
1133227064Sbz}
1134227064Sbz
1135227064Sbzstatic void
1136227064Sbzqla_stop(qla_host_t *ha)
1137227064Sbz{
1138227064Sbz	struct ifnet *ifp = ha->ifp;
1139227064Sbz	device_t	dev;
1140227064Sbz
1141227064Sbz	dev = ha->pci_dev;
1142227064Sbz
1143227064Sbz	ha->flags.qla_watchdog_pause = 1;
1144227064Sbz	qla_mdelay(__func__, 100);
1145227064Sbz
1146227064Sbz	ha->flags.stop_rcv = 1;
1147227064Sbz	qla_hw_stop_rcv(ha);
1148227064Sbz
1149227064Sbz	qla_del_hw_if(ha);
1150227064Sbz
1151227064Sbz	qla_free_lro(ha);
1152227064Sbz
1153227064Sbz	qla_free_xmt_bufs(ha);
1154227064Sbz	qla_free_rcv_bufs(ha);
1155227064Sbz
1156227064Sbz	ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE | IFF_DRV_RUNNING);
1157227064Sbz
1158227064Sbz	return;
1159227064Sbz}
1160227064Sbz
1161227064Sbz/*
1162227064Sbz * Buffer Management Functions for Transmit and Receive Rings
1163227064Sbz */
1164227064Sbzstatic int
1165227064Sbzqla_alloc_xmt_bufs(qla_host_t *ha)
1166227064Sbz{
1167227064Sbz	if (bus_dma_tag_create(NULL,    /* parent */
1168227064Sbz		1, 0,    /* alignment, bounds */
1169227064Sbz		BUS_SPACE_MAXADDR,       /* lowaddr */
1170227064Sbz		BUS_SPACE_MAXADDR,       /* highaddr */
1171227064Sbz		NULL, NULL,      /* filter, filterarg */
1172227064Sbz		QLA_MAX_TSO_FRAME_SIZE,     /* maxsize */
1173227064Sbz		QLA_MAX_SEGMENTS,        /* nsegments */
1174227064Sbz		PAGE_SIZE,        /* maxsegsize */
1175227064Sbz		BUS_DMA_ALLOCNOW,        /* flags */
1176227064Sbz		NULL,    /* lockfunc */
1177227064Sbz		NULL,    /* lockfuncarg */
1178227064Sbz		&ha->tx_tag)) {
1179227064Sbz		device_printf(ha->pci_dev, "%s: tx_tag alloc failed\n",
1180227064Sbz			__func__);
1181227064Sbz		return (ENOMEM);
1182227064Sbz	}
1183227064Sbz	bzero((void *)ha->tx_buf, (sizeof(qla_tx_buf_t) * NUM_TX_DESCRIPTORS));
1184227064Sbz
1185227064Sbz	return 0;
1186227064Sbz}
1187227064Sbz
1188227064Sbz/*
1189227064Sbz * Release mbuf after it sent on the wire
1190227064Sbz */
1191227064Sbzstatic void
1192227064Sbzqla_clear_tx_buf(qla_host_t *ha, qla_tx_buf_t *txb)
1193227064Sbz{
1194227064Sbz	QL_DPRINT2((ha->pci_dev, "%s: enter\n", __func__));
1195227064Sbz
1196227064Sbz	if (txb->m_head) {
1197227064Sbz
1198227064Sbz		bus_dmamap_unload(ha->tx_tag, txb->map);
1199227064Sbz		bus_dmamap_destroy(ha->tx_tag, txb->map);
1200227064Sbz
1201227064Sbz		m_freem(txb->m_head);
1202227064Sbz		txb->m_head = NULL;
1203227064Sbz	}
1204227064Sbz
1205227064Sbz	QL_DPRINT2((ha->pci_dev, "%s: exit\n", __func__));
1206227064Sbz}
1207227064Sbz
1208227064Sbzstatic void
1209227064Sbzqla_free_xmt_bufs(qla_host_t *ha)
1210227064Sbz{
1211227064Sbz	int		i;
1212227064Sbz
1213227064Sbz	for (i = 0; i < NUM_TX_DESCRIPTORS; i++)
1214227064Sbz		qla_clear_tx_buf(ha, &ha->tx_buf[i]);
1215227064Sbz
1216227064Sbz	if (ha->tx_tag != NULL) {
1217227064Sbz		bus_dma_tag_destroy(ha->tx_tag);
1218227064Sbz		ha->tx_tag = NULL;
1219227064Sbz	}
1220227064Sbz	bzero((void *)ha->tx_buf, (sizeof(qla_tx_buf_t) * NUM_TX_DESCRIPTORS));
1221227064Sbz
1222227064Sbz	return;
1223227064Sbz}
1224227064Sbz
1225227064Sbz
1226227064Sbzstatic int
1227227064Sbzqla_alloc_rcv_bufs(qla_host_t *ha)
1228227064Sbz{
1229227064Sbz	int		i, j, ret = 0;
1230227064Sbz	qla_rx_buf_t	*rxb;
1231227064Sbz
1232227064Sbz	if (bus_dma_tag_create(NULL,    /* parent */
1233227064Sbz			1, 0,    /* alignment, bounds */
1234227064Sbz			BUS_SPACE_MAXADDR,       /* lowaddr */
1235227064Sbz			BUS_SPACE_MAXADDR,       /* highaddr */
1236227064Sbz			NULL, NULL,      /* filter, filterarg */
1237227064Sbz			MJUM9BYTES,     /* maxsize */
1238227064Sbz			1,        /* nsegments */
1239227064Sbz			MJUM9BYTES,        /* maxsegsize */
1240227064Sbz			BUS_DMA_ALLOCNOW,        /* flags */
1241227064Sbz			NULL,    /* lockfunc */
1242227064Sbz			NULL,    /* lockfuncarg */
1243227064Sbz			&ha->rx_tag)) {
1244227064Sbz
1245227064Sbz		device_printf(ha->pci_dev, "%s: rx_tag alloc failed\n",
1246227064Sbz			__func__);
1247227064Sbz
1248227064Sbz		return (ENOMEM);
1249227064Sbz	}
1250227064Sbz
1251227064Sbz	bzero((void *)ha->rx_buf, (sizeof(qla_rx_buf_t) * NUM_RX_DESCRIPTORS));
1252227064Sbz	bzero((void *)ha->rx_jbuf,
1253227064Sbz		(sizeof(qla_rx_buf_t) * NUM_RX_JUMBO_DESCRIPTORS));
1254227064Sbz
1255227064Sbz	for (i = 0; i < MAX_SDS_RINGS; i++) {
1256227064Sbz		ha->hw.sds[i].sdsr_next = 0;
1257227064Sbz		ha->hw.sds[i].rxb_free = NULL;
1258227064Sbz		ha->hw.sds[i].rx_free = 0;
1259227064Sbz		ha->hw.sds[i].rxjb_free = NULL;
1260227064Sbz		ha->hw.sds[i].rxj_free = 0;
1261227064Sbz	}
1262227064Sbz
1263227064Sbz	for (i = 0; i < NUM_RX_DESCRIPTORS; i++) {
1264227064Sbz
1265227064Sbz		rxb = &ha->rx_buf[i];
1266227064Sbz
1267227064Sbz		ret = bus_dmamap_create(ha->rx_tag, BUS_DMA_NOWAIT, &rxb->map);
1268227064Sbz
1269227064Sbz		if (ret) {
1270227064Sbz			device_printf(ha->pci_dev,
1271227064Sbz				"%s: dmamap[%d] failed\n", __func__, i);
1272227064Sbz
1273227064Sbz			for (j = 0; j < i; j++) {
1274227064Sbz				bus_dmamap_destroy(ha->rx_tag,
1275227064Sbz					ha->rx_buf[j].map);
1276227064Sbz			}
1277227064Sbz			goto qla_alloc_rcv_bufs_failed;
1278227064Sbz		}
1279227064Sbz	}
1280227064Sbz
1281227064Sbz	qla_init_hw_rcv_descriptors(ha, RDS_RING_INDEX_NORMAL);
1282227064Sbz
1283227064Sbz	for (i = 0; i < NUM_RX_DESCRIPTORS; i++) {
1284227064Sbz		rxb = &ha->rx_buf[i];
1285227064Sbz		rxb->handle = i;
1286227064Sbz		if (!(ret = qla_get_mbuf(ha, rxb, NULL, 0))) {
1287227064Sbz			/*
1288227064Sbz		 	 * set the physical address in the corresponding
1289227064Sbz			 * descriptor entry in the receive ring/queue for the
1290227064Sbz			 * hba
1291227064Sbz			 */
1292227064Sbz			qla_set_hw_rcv_desc(ha, RDS_RING_INDEX_NORMAL, i,
1293227064Sbz				rxb->handle, rxb->paddr,
1294227064Sbz				(rxb->m_head)->m_pkthdr.len);
1295227064Sbz		} else {
1296227064Sbz			device_printf(ha->pci_dev,
1297227064Sbz				"%s: qla_get_mbuf [standard(%d)] failed\n",
1298227064Sbz				__func__, i);
1299227064Sbz			bus_dmamap_destroy(ha->rx_tag, rxb->map);
1300227064Sbz			goto qla_alloc_rcv_bufs_failed;
1301227064Sbz		}
1302227064Sbz	}
1303227064Sbz
1304227064Sbz
1305227064Sbz	for (i = 0; i < NUM_RX_JUMBO_DESCRIPTORS; i++) {
1306227064Sbz
1307227064Sbz		rxb = &ha->rx_jbuf[i];
1308227064Sbz
1309227064Sbz		ret = bus_dmamap_create(ha->rx_tag, BUS_DMA_NOWAIT, &rxb->map);
1310227064Sbz
1311227064Sbz		if (ret) {
1312227064Sbz			device_printf(ha->pci_dev,
1313227064Sbz				"%s: dmamap[%d] failed\n", __func__, i);
1314227064Sbz
1315227064Sbz			for (j = 0; j < i; j++) {
1316227064Sbz				bus_dmamap_destroy(ha->rx_tag,
1317227064Sbz					ha->rx_jbuf[j].map);
1318227064Sbz			}
1319227064Sbz			goto qla_alloc_rcv_bufs_failed;
1320227064Sbz		}
1321227064Sbz	}
1322227064Sbz
1323227064Sbz	qla_init_hw_rcv_descriptors(ha, RDS_RING_INDEX_JUMBO);
1324227064Sbz
1325227064Sbz	for (i = 0; i < NUM_RX_JUMBO_DESCRIPTORS; i++) {
1326227064Sbz		rxb = &ha->rx_jbuf[i];
1327227064Sbz		rxb->handle = i;
1328227064Sbz		if (!(ret = qla_get_mbuf(ha, rxb, NULL, 1))) {
1329227064Sbz			/*
1330227064Sbz		 	 * set the physical address in the corresponding
1331227064Sbz			 * descriptor entry in the receive ring/queue for the
1332227064Sbz			 * hba
1333227064Sbz			 */
1334227064Sbz			qla_set_hw_rcv_desc(ha, RDS_RING_INDEX_JUMBO, i,
1335227064Sbz				rxb->handle, rxb->paddr,
1336227064Sbz				(rxb->m_head)->m_pkthdr.len);
1337227064Sbz		} else {
1338227064Sbz			device_printf(ha->pci_dev,
1339227064Sbz				"%s: qla_get_mbuf [jumbo(%d)] failed\n",
1340227064Sbz				__func__, i);
1341227064Sbz			bus_dmamap_destroy(ha->rx_tag, rxb->map);
1342227064Sbz			goto qla_alloc_rcv_bufs_failed;
1343227064Sbz		}
1344227064Sbz	}
1345227064Sbz
1346227064Sbz	return (0);
1347227064Sbz
1348227064Sbzqla_alloc_rcv_bufs_failed:
1349227064Sbz	qla_free_rcv_bufs(ha);
1350227064Sbz	return (ret);
1351227064Sbz}
1352227064Sbz
1353227064Sbzstatic void
1354227064Sbzqla_free_rcv_bufs(qla_host_t *ha)
1355227064Sbz{
1356227064Sbz	int		i;
1357227064Sbz	qla_rx_buf_t	*rxb;
1358227064Sbz
1359227064Sbz	for (i = 0; i < NUM_RX_DESCRIPTORS; i++) {
1360227064Sbz		rxb = &ha->rx_buf[i];
1361227064Sbz		if (rxb->m_head != NULL) {
1362227064Sbz			bus_dmamap_unload(ha->rx_tag, rxb->map);
1363227064Sbz			bus_dmamap_destroy(ha->rx_tag, rxb->map);
1364227064Sbz			m_freem(rxb->m_head);
1365227064Sbz			rxb->m_head = NULL;
1366227064Sbz		}
1367227064Sbz	}
1368227064Sbz
1369227064Sbz	for (i = 0; i < NUM_RX_JUMBO_DESCRIPTORS; i++) {
1370227064Sbz		rxb = &ha->rx_jbuf[i];
1371227064Sbz		if (rxb->m_head != NULL) {
1372227064Sbz			bus_dmamap_unload(ha->rx_tag, rxb->map);
1373227064Sbz			bus_dmamap_destroy(ha->rx_tag, rxb->map);
1374227064Sbz			m_freem(rxb->m_head);
1375227064Sbz			rxb->m_head = NULL;
1376227064Sbz		}
1377227064Sbz	}
1378227064Sbz
1379227064Sbz	if (ha->rx_tag != NULL) {
1380227064Sbz		bus_dma_tag_destroy(ha->rx_tag);
1381227064Sbz		ha->rx_tag = NULL;
1382227064Sbz	}
1383227064Sbz
1384227064Sbz	bzero((void *)ha->rx_buf, (sizeof(qla_rx_buf_t) * NUM_RX_DESCRIPTORS));
1385227064Sbz	bzero((void *)ha->rx_jbuf,
1386227064Sbz		(sizeof(qla_rx_buf_t) * NUM_RX_JUMBO_DESCRIPTORS));
1387227064Sbz
1388227064Sbz	for (i = 0; i < MAX_SDS_RINGS; i++) {
1389227064Sbz		ha->hw.sds[i].sdsr_next = 0;
1390227064Sbz		ha->hw.sds[i].rxb_free = NULL;
1391227064Sbz		ha->hw.sds[i].rx_free = 0;
1392227064Sbz		ha->hw.sds[i].rxjb_free = NULL;
1393227064Sbz		ha->hw.sds[i].rxj_free = 0;
1394227064Sbz	}
1395227064Sbz
1396227064Sbz	return;
1397227064Sbz}
1398227064Sbz
1399227064Sbzint
1400227064Sbzqla_get_mbuf(qla_host_t *ha, qla_rx_buf_t *rxb, struct mbuf *nmp,
1401227064Sbz	uint32_t jumbo)
1402227064Sbz{
1403227064Sbz	register struct mbuf *mp = nmp;
1404227064Sbz	struct ifnet   *ifp;
1405227064Sbz	int             ret = 0;
1406227064Sbz	uint32_t	offset;
1407227064Sbz
1408227064Sbz	QL_DPRINT2((ha->pci_dev, "%s: jumbo(0x%x) enter\n", __func__, jumbo));
1409227064Sbz
1410227064Sbz	ifp = ha->ifp;
1411227064Sbz
1412227064Sbz	if (mp == NULL) {
1413227064Sbz
1414227064Sbz		if (!jumbo) {
1415243857Sglebius			mp = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
1416227064Sbz
1417227064Sbz			if (mp == NULL) {
1418227064Sbz				ha->err_m_getcl++;
1419227064Sbz				ret = ENOBUFS;
1420227064Sbz				device_printf(ha->pci_dev,
1421227064Sbz					"%s: m_getcl failed\n", __func__);
1422227064Sbz				goto exit_qla_get_mbuf;
1423227064Sbz			}
1424227064Sbz			mp->m_len = mp->m_pkthdr.len = MCLBYTES;
1425227064Sbz		} else {
1426243857Sglebius			mp = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR,
1427227064Sbz				MJUM9BYTES);
1428227064Sbz			if (mp == NULL) {
1429227064Sbz				ha->err_m_getjcl++;
1430227064Sbz				ret = ENOBUFS;
1431227064Sbz				device_printf(ha->pci_dev,
1432227064Sbz					"%s: m_getjcl failed\n", __func__);
1433227064Sbz				goto exit_qla_get_mbuf;
1434227064Sbz			}
1435227064Sbz			mp->m_len = mp->m_pkthdr.len = MJUM9BYTES;
1436227064Sbz		}
1437227064Sbz	} else {
1438227064Sbz		if (!jumbo)
1439227064Sbz			mp->m_len = mp->m_pkthdr.len = MCLBYTES;
1440227064Sbz		else
1441227064Sbz			mp->m_len = mp->m_pkthdr.len = MJUM9BYTES;
1442227064Sbz
1443227064Sbz		mp->m_data = mp->m_ext.ext_buf;
1444227064Sbz		mp->m_next = NULL;
1445227064Sbz	}
1446227064Sbz
1447227064Sbz
1448227064Sbz	offset = (uint32_t)((unsigned long long)mp->m_data & 0x7ULL);
1449227064Sbz	if (offset) {
1450227064Sbz		offset = 8 - offset;
1451227064Sbz		m_adj(mp, offset);
1452227064Sbz	}
1453227064Sbz
1454227064Sbz	/*
1455227064Sbz	 * Using memory from the mbuf cluster pool, invoke the bus_dma
1456227064Sbz	 * machinery to arrange the memory mapping.
1457227064Sbz	 */
1458227064Sbz	ret = bus_dmamap_load(ha->rx_tag, rxb->map,
1459227064Sbz				mtod(mp, void *), mp->m_len,
1460227064Sbz				qla_dmamap_callback, &rxb->paddr,
1461227064Sbz				BUS_DMA_NOWAIT);
1462227064Sbz	if (ret || !rxb->paddr) {
1463227064Sbz		m_free(mp);
1464227064Sbz		rxb->m_head = NULL;
1465227064Sbz		device_printf(ha->pci_dev,
1466227064Sbz			"%s: bus_dmamap_load failed\n", __func__);
1467227064Sbz                ret = -1;
1468227064Sbz		goto exit_qla_get_mbuf;
1469227064Sbz	}
1470227064Sbz	rxb->m_head = mp;
1471227064Sbz	bus_dmamap_sync(ha->rx_tag, rxb->map, BUS_DMASYNC_PREREAD);
1472227064Sbz
1473227064Sbzexit_qla_get_mbuf:
1474227064Sbz	QL_DPRINT2((ha->pci_dev, "%s: exit ret = 0x%08x\n", __func__, ret));
1475227064Sbz	return (ret);
1476227064Sbz}
1477227064Sbz
1478227064Sbzstatic void
1479227064Sbzqla_tx_done(void *context, int pending)
1480227064Sbz{
1481227064Sbz	qla_host_t *ha = context;
1482227064Sbz
1483227064Sbz	qla_hw_tx_done(ha);
1484227064Sbz	qla_start(ha->ifp);
1485227064Sbz}
1486227064Sbz
1487