xref: /freebsd/sys/dev/qlxgb/qla_os.c (revision aa3860851b9f6a6002d135b1cac7736e0995eedc)
1718cf2ccSPedro F. Giffuni /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni  *
4088fc971SDavid C Somayajulu  * Copyright (c) 2011-2013 Qlogic Corporation
50bc7cf6fSBjoern A. Zeeb  * All rights reserved.
60bc7cf6fSBjoern A. Zeeb  *
70bc7cf6fSBjoern A. Zeeb  *  Redistribution and use in source and binary forms, with or without
80bc7cf6fSBjoern A. Zeeb  *  modification, are permitted provided that the following conditions
90bc7cf6fSBjoern A. Zeeb  *  are met:
100bc7cf6fSBjoern A. Zeeb  *
110bc7cf6fSBjoern A. Zeeb  *  1. Redistributions of source code must retain the above copyright
120bc7cf6fSBjoern A. Zeeb  *     notice, this list of conditions and the following disclaimer.
130bc7cf6fSBjoern A. Zeeb  *  2. Redistributions in binary form must reproduce the above copyright
140bc7cf6fSBjoern A. Zeeb  *     notice, this list of conditions and the following disclaimer in the
150bc7cf6fSBjoern A. Zeeb  *     documentation and/or other materials provided with the distribution.
160bc7cf6fSBjoern A. Zeeb  *
170bc7cf6fSBjoern A. Zeeb  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
180bc7cf6fSBjoern A. Zeeb  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
190bc7cf6fSBjoern A. Zeeb  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
200bc7cf6fSBjoern A. Zeeb  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
210bc7cf6fSBjoern A. Zeeb  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
220bc7cf6fSBjoern A. Zeeb  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
230bc7cf6fSBjoern A. Zeeb  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
240bc7cf6fSBjoern A. Zeeb  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
250bc7cf6fSBjoern A. Zeeb  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
260bc7cf6fSBjoern A. Zeeb  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
270bc7cf6fSBjoern A. Zeeb  *  POSSIBILITY OF SUCH DAMAGE.
280bc7cf6fSBjoern A. Zeeb  */
290bc7cf6fSBjoern A. Zeeb 
300bc7cf6fSBjoern A. Zeeb /*
310bc7cf6fSBjoern A. Zeeb  * File: qla_os.c
320bc7cf6fSBjoern A. Zeeb  * Author : David C Somayajulu, Qlogic Corporation, Aliso Viejo, CA 92656.
330bc7cf6fSBjoern A. Zeeb  */
340bc7cf6fSBjoern A. Zeeb 
350bc7cf6fSBjoern A. Zeeb #include <sys/cdefs.h>
360bc7cf6fSBjoern A. Zeeb #include "qla_os.h"
370bc7cf6fSBjoern A. Zeeb #include "qla_reg.h"
380bc7cf6fSBjoern A. Zeeb #include "qla_hw.h"
390bc7cf6fSBjoern A. Zeeb #include "qla_def.h"
400bc7cf6fSBjoern A. Zeeb #include "qla_inline.h"
410bc7cf6fSBjoern A. Zeeb #include "qla_ver.h"
420bc7cf6fSBjoern A. Zeeb #include "qla_glbl.h"
430bc7cf6fSBjoern A. Zeeb #include "qla_dbg.h"
440bc7cf6fSBjoern A. Zeeb 
450bc7cf6fSBjoern A. Zeeb /*
460bc7cf6fSBjoern A. Zeeb  * Some PCI Configuration Space Related Defines
470bc7cf6fSBjoern A. Zeeb  */
480bc7cf6fSBjoern A. Zeeb 
490bc7cf6fSBjoern A. Zeeb #ifndef PCI_VENDOR_QLOGIC
500bc7cf6fSBjoern A. Zeeb #define PCI_VENDOR_QLOGIC	0x1077
510bc7cf6fSBjoern A. Zeeb #endif
520bc7cf6fSBjoern A. Zeeb 
530bc7cf6fSBjoern A. Zeeb #ifndef PCI_PRODUCT_QLOGIC_ISP8020
540bc7cf6fSBjoern A. Zeeb #define PCI_PRODUCT_QLOGIC_ISP8020	0x8020
550bc7cf6fSBjoern A. Zeeb #endif
560bc7cf6fSBjoern A. Zeeb 
570bc7cf6fSBjoern A. Zeeb #define PCI_QLOGIC_ISP8020 \
580bc7cf6fSBjoern A. Zeeb 	((PCI_PRODUCT_QLOGIC_ISP8020 << 16) | PCI_VENDOR_QLOGIC)
590bc7cf6fSBjoern A. Zeeb 
600bc7cf6fSBjoern A. Zeeb /*
610bc7cf6fSBjoern A. Zeeb  * static functions
620bc7cf6fSBjoern A. Zeeb  */
630bc7cf6fSBjoern A. Zeeb static int qla_alloc_parent_dma_tag(qla_host_t *ha);
640bc7cf6fSBjoern A. Zeeb static void qla_free_parent_dma_tag(qla_host_t *ha);
650bc7cf6fSBjoern A. Zeeb static int qla_alloc_xmt_bufs(qla_host_t *ha);
660bc7cf6fSBjoern A. Zeeb static void qla_free_xmt_bufs(qla_host_t *ha);
670bc7cf6fSBjoern A. Zeeb static int qla_alloc_rcv_bufs(qla_host_t *ha);
680bc7cf6fSBjoern A. Zeeb static void qla_free_rcv_bufs(qla_host_t *ha);
690bc7cf6fSBjoern A. Zeeb 
700bc7cf6fSBjoern A. Zeeb static void qla_init_ifnet(device_t dev, qla_host_t *ha);
710bc7cf6fSBjoern A. Zeeb static int qla_sysctl_get_stats(SYSCTL_HANDLER_ARGS);
720bc7cf6fSBjoern A. Zeeb static void qla_release(qla_host_t *ha);
730bc7cf6fSBjoern A. Zeeb static void qla_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nsegs,
740bc7cf6fSBjoern A. Zeeb 		int error);
750bc7cf6fSBjoern A. Zeeb static void qla_stop(qla_host_t *ha);
760bc7cf6fSBjoern A. Zeeb static int qla_send(qla_host_t *ha, struct mbuf **m_headp);
770bc7cf6fSBjoern A. Zeeb static void qla_tx_done(void *context, int pending);
780bc7cf6fSBjoern A. Zeeb 
790bc7cf6fSBjoern A. Zeeb /*
800bc7cf6fSBjoern A. Zeeb  * Hooks to the Operating Systems
810bc7cf6fSBjoern A. Zeeb  */
820bc7cf6fSBjoern A. Zeeb static int qla_pci_probe (device_t);
830bc7cf6fSBjoern A. Zeeb static int qla_pci_attach (device_t);
840bc7cf6fSBjoern A. Zeeb static int qla_pci_detach (device_t);
850bc7cf6fSBjoern A. Zeeb 
860bc7cf6fSBjoern A. Zeeb static void qla_init(void *arg);
875b587352SJustin Hibbits static int qla_ioctl(if_t ifp, u_long cmd, caddr_t data);
885b587352SJustin Hibbits static int qla_media_change(if_t ifp);
895b587352SJustin Hibbits static void qla_media_status(if_t ifp, struct ifmediareq *ifmr);
900bc7cf6fSBjoern A. Zeeb 
910bc7cf6fSBjoern A. Zeeb static device_method_t qla_pci_methods[] = {
920bc7cf6fSBjoern A. Zeeb 	/* Device interface */
930bc7cf6fSBjoern A. Zeeb 	DEVMETHOD(device_probe, qla_pci_probe),
940bc7cf6fSBjoern A. Zeeb 	DEVMETHOD(device_attach, qla_pci_attach),
950bc7cf6fSBjoern A. Zeeb 	DEVMETHOD(device_detach, qla_pci_detach),
960bc7cf6fSBjoern A. Zeeb 	{ 0, 0 }
970bc7cf6fSBjoern A. Zeeb };
980bc7cf6fSBjoern A. Zeeb 
990bc7cf6fSBjoern A. Zeeb static driver_t qla_pci_driver = {
1000bc7cf6fSBjoern A. Zeeb 	"ql", qla_pci_methods, sizeof (qla_host_t),
1010bc7cf6fSBjoern A. Zeeb };
1020bc7cf6fSBjoern A. Zeeb 
1032f87208eSJohn Baldwin DRIVER_MODULE(qla80xx, pci, qla_pci_driver, 0, 0);
1040bc7cf6fSBjoern A. Zeeb 
1050bc7cf6fSBjoern A. Zeeb MODULE_DEPEND(qla80xx, pci, 1, 1, 1);
1060bc7cf6fSBjoern A. Zeeb MODULE_DEPEND(qla80xx, ether, 1, 1, 1);
1070bc7cf6fSBjoern A. Zeeb 
1080bc7cf6fSBjoern A. Zeeb MALLOC_DEFINE(M_QLA8XXXBUF, "qla80xxbuf", "Buffers for qla80xx driver");
1090bc7cf6fSBjoern A. Zeeb 
1100bc7cf6fSBjoern A. Zeeb uint32_t std_replenish = 8;
1110bc7cf6fSBjoern A. Zeeb uint32_t jumbo_replenish = 2;
1120bc7cf6fSBjoern A. Zeeb uint32_t rcv_pkt_thres = 128;
1130bc7cf6fSBjoern A. Zeeb uint32_t rcv_pkt_thres_d = 32;
1140bc7cf6fSBjoern A. Zeeb uint32_t snd_pkt_thres = 16;
1150bc7cf6fSBjoern A. Zeeb uint32_t free_pkt_thres = (NUM_TX_DESCRIPTORS / 2);
1160bc7cf6fSBjoern A. Zeeb 
1170bc7cf6fSBjoern A. Zeeb static char dev_str[64];
1180bc7cf6fSBjoern A. Zeeb 
1190bc7cf6fSBjoern A. Zeeb /*
1200bc7cf6fSBjoern A. Zeeb  * Name:	qla_pci_probe
1210bc7cf6fSBjoern A. Zeeb  * Function:	Validate the PCI device to be a QLA80XX device
1220bc7cf6fSBjoern A. Zeeb  */
1230bc7cf6fSBjoern A. Zeeb static int
qla_pci_probe(device_t dev)1240bc7cf6fSBjoern A. Zeeb qla_pci_probe(device_t dev)
1250bc7cf6fSBjoern A. Zeeb {
1260bc7cf6fSBjoern A. Zeeb         switch ((pci_get_device(dev) << 16) | (pci_get_vendor(dev))) {
1270bc7cf6fSBjoern A. Zeeb         case PCI_QLOGIC_ISP8020:
1280bc7cf6fSBjoern A. Zeeb 		snprintf(dev_str, sizeof(dev_str), "%s v%d.%d.%d",
1290bc7cf6fSBjoern A. Zeeb 			"Qlogic ISP 80xx PCI CNA Adapter-Ethernet Function",
1300bc7cf6fSBjoern A. Zeeb 			QLA_VERSION_MAJOR, QLA_VERSION_MINOR,
1310bc7cf6fSBjoern A. Zeeb 			QLA_VERSION_BUILD);
1320bc7cf6fSBjoern A. Zeeb                 device_set_desc(dev, dev_str);
1330bc7cf6fSBjoern A. Zeeb                 break;
1340bc7cf6fSBjoern A. Zeeb         default:
1350bc7cf6fSBjoern A. Zeeb                 return (ENXIO);
1360bc7cf6fSBjoern A. Zeeb         }
1370bc7cf6fSBjoern A. Zeeb 
1380bc7cf6fSBjoern A. Zeeb         if (bootverbose)
1390bc7cf6fSBjoern A. Zeeb                 printf("%s: %s\n ", __func__, dev_str);
1400bc7cf6fSBjoern A. Zeeb 
1410bc7cf6fSBjoern A. Zeeb         return (BUS_PROBE_DEFAULT);
1420bc7cf6fSBjoern A. Zeeb }
1430bc7cf6fSBjoern A. Zeeb 
1440bc7cf6fSBjoern A. Zeeb static void
qla_add_sysctls(qla_host_t * ha)1450bc7cf6fSBjoern A. Zeeb qla_add_sysctls(qla_host_t *ha)
1460bc7cf6fSBjoern A. Zeeb {
1470bc7cf6fSBjoern A. Zeeb         device_t dev = ha->pci_dev;
1480bc7cf6fSBjoern A. Zeeb 
1490bc7cf6fSBjoern A. Zeeb         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
1500bc7cf6fSBjoern A. Zeeb             SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1517029da5cSPawel Biernacki             OID_AUTO, "stats", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
1527029da5cSPawel Biernacki 	    (void *)ha, 0, qla_sysctl_get_stats, "I", "Statistics");
1530bc7cf6fSBjoern A. Zeeb 
154088fc971SDavid C Somayajulu 	SYSCTL_ADD_STRING(device_get_sysctl_ctx(dev),
155088fc971SDavid C Somayajulu 		SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
156088fc971SDavid C Somayajulu 		OID_AUTO, "fw_version", CTLFLAG_RD,
157f0188618SHans Petter Selasky 		ha->fw_ver_str, 0, "firmware version");
158088fc971SDavid C Somayajulu 
1590bc7cf6fSBjoern A. Zeeb 	dbg_level = 0;
1600bc7cf6fSBjoern A. Zeeb         SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
1610bc7cf6fSBjoern A. Zeeb                 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1620bc7cf6fSBjoern A. Zeeb                 OID_AUTO, "debug", CTLFLAG_RW,
1630bc7cf6fSBjoern A. Zeeb                 &dbg_level, dbg_level, "Debug Level");
1640bc7cf6fSBjoern A. Zeeb 
1650bc7cf6fSBjoern A. Zeeb         SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
1660bc7cf6fSBjoern A. Zeeb                 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1670bc7cf6fSBjoern A. Zeeb                 OID_AUTO, "std_replenish", CTLFLAG_RW,
1680bc7cf6fSBjoern A. Zeeb                 &std_replenish, std_replenish,
1690bc7cf6fSBjoern A. Zeeb                 "Threshold for Replenishing Standard Frames");
1700bc7cf6fSBjoern A. Zeeb 
1710bc7cf6fSBjoern A. Zeeb         SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
1720bc7cf6fSBjoern A. Zeeb                 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1730bc7cf6fSBjoern A. Zeeb                 OID_AUTO, "jumbo_replenish", CTLFLAG_RW,
1740bc7cf6fSBjoern A. Zeeb                 &jumbo_replenish, jumbo_replenish,
1750bc7cf6fSBjoern A. Zeeb                 "Threshold for Replenishing Jumbo Frames");
1760bc7cf6fSBjoern A. Zeeb 
1770bc7cf6fSBjoern A. Zeeb         SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
1780bc7cf6fSBjoern A. Zeeb                 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1790bc7cf6fSBjoern A. Zeeb                 OID_AUTO, "rcv_pkt_thres",  CTLFLAG_RW,
1800bc7cf6fSBjoern A. Zeeb                 &rcv_pkt_thres, rcv_pkt_thres,
1810bc7cf6fSBjoern A. Zeeb                 "Threshold for # of rcv pkts to trigger indication isr");
1820bc7cf6fSBjoern A. Zeeb 
1830bc7cf6fSBjoern A. Zeeb         SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
1840bc7cf6fSBjoern A. Zeeb                 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1850bc7cf6fSBjoern A. Zeeb                 OID_AUTO, "rcv_pkt_thres_d",  CTLFLAG_RW,
1860bc7cf6fSBjoern A. Zeeb                 &rcv_pkt_thres_d, rcv_pkt_thres_d,
1870bc7cf6fSBjoern A. Zeeb                 "Threshold for # of rcv pkts to trigger indication defered");
1880bc7cf6fSBjoern A. Zeeb 
1890bc7cf6fSBjoern A. Zeeb         SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
1900bc7cf6fSBjoern A. Zeeb                 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1910bc7cf6fSBjoern A. Zeeb                 OID_AUTO, "snd_pkt_thres",  CTLFLAG_RW,
1920bc7cf6fSBjoern A. Zeeb                 &snd_pkt_thres, snd_pkt_thres,
1930bc7cf6fSBjoern A. Zeeb                 "Threshold for # of snd packets");
1940bc7cf6fSBjoern A. Zeeb 
1950bc7cf6fSBjoern A. Zeeb         SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
1960bc7cf6fSBjoern A. Zeeb                 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1970bc7cf6fSBjoern A. Zeeb                 OID_AUTO, "free_pkt_thres",  CTLFLAG_RW,
1980bc7cf6fSBjoern A. Zeeb                 &free_pkt_thres, free_pkt_thres,
1990bc7cf6fSBjoern A. Zeeb                 "Threshold for # of packets to free at a time");
2000bc7cf6fSBjoern A. Zeeb 
2010bc7cf6fSBjoern A. Zeeb         return;
2020bc7cf6fSBjoern A. Zeeb }
2030bc7cf6fSBjoern A. Zeeb 
2040bc7cf6fSBjoern A. Zeeb static void
qla_watchdog(void * arg)2050bc7cf6fSBjoern A. Zeeb qla_watchdog(void *arg)
2060bc7cf6fSBjoern A. Zeeb {
2070bc7cf6fSBjoern A. Zeeb 	qla_host_t *ha = arg;
2080bc7cf6fSBjoern A. Zeeb 	qla_hw_t *hw;
2095b587352SJustin Hibbits 	if_t ifp;
2100bc7cf6fSBjoern A. Zeeb 
2110bc7cf6fSBjoern A. Zeeb 	hw = &ha->hw;
2120bc7cf6fSBjoern A. Zeeb 	ifp = ha->ifp;
2130bc7cf6fSBjoern A. Zeeb 
2140bc7cf6fSBjoern A. Zeeb         if (ha->flags.qla_watchdog_exit)
2150bc7cf6fSBjoern A. Zeeb 		return;
2160bc7cf6fSBjoern A. Zeeb 
2170bc7cf6fSBjoern A. Zeeb 	if (!ha->flags.qla_watchdog_pause) {
2180bc7cf6fSBjoern A. Zeeb 		if (qla_le32_to_host(*(hw->tx_cons)) != hw->txr_comp) {
2190bc7cf6fSBjoern A. Zeeb 			taskqueue_enqueue(ha->tx_tq, &ha->tx_task);
2205b587352SJustin Hibbits 		} else if (!if_sendq_empty(ifp) && QL_RUNNING(ifp)) {
2210bc7cf6fSBjoern A. Zeeb 			taskqueue_enqueue(ha->tx_tq, &ha->tx_task);
2220bc7cf6fSBjoern A. Zeeb 		}
2230bc7cf6fSBjoern A. Zeeb 	}
224bf66c12eSConrad Meyer 	ha->watchdog_ticks = (ha->watchdog_ticks + 1) % 1000;
2250bc7cf6fSBjoern A. Zeeb 	callout_reset(&ha->tx_callout, QLA_WATCHDOG_CALLOUT_TICKS,
2260bc7cf6fSBjoern A. Zeeb 		qla_watchdog, ha);
2270bc7cf6fSBjoern A. Zeeb }
2280bc7cf6fSBjoern A. Zeeb 
2290bc7cf6fSBjoern A. Zeeb /*
2300bc7cf6fSBjoern A. Zeeb  * Name:	qla_pci_attach
2310bc7cf6fSBjoern A. Zeeb  * Function:	attaches the device to the operating system
2320bc7cf6fSBjoern A. Zeeb  */
2330bc7cf6fSBjoern A. Zeeb static int
qla_pci_attach(device_t dev)2340bc7cf6fSBjoern A. Zeeb qla_pci_attach(device_t dev)
2350bc7cf6fSBjoern A. Zeeb {
2360bc7cf6fSBjoern A. Zeeb 	qla_host_t *ha = NULL;
2370bc7cf6fSBjoern A. Zeeb 	uint32_t rsrc_len, i;
2380bc7cf6fSBjoern A. Zeeb 
2390bc7cf6fSBjoern A. Zeeb 	QL_DPRINT2((dev, "%s: enter\n", __func__));
2400bc7cf6fSBjoern A. Zeeb 
2410bc7cf6fSBjoern A. Zeeb         if ((ha = device_get_softc(dev)) == NULL) {
2420bc7cf6fSBjoern A. Zeeb                 device_printf(dev, "cannot get softc\n");
2430bc7cf6fSBjoern A. Zeeb                 return (ENOMEM);
2440bc7cf6fSBjoern A. Zeeb         }
2450bc7cf6fSBjoern A. Zeeb 
2460bc7cf6fSBjoern A. Zeeb         memset(ha, 0, sizeof (qla_host_t));
2470bc7cf6fSBjoern A. Zeeb 
2480bc7cf6fSBjoern A. Zeeb         if (pci_get_device(dev) != PCI_PRODUCT_QLOGIC_ISP8020) {
2490bc7cf6fSBjoern A. Zeeb                 device_printf(dev, "device is not ISP8020\n");
2500bc7cf6fSBjoern A. Zeeb                 return (ENXIO);
2510bc7cf6fSBjoern A. Zeeb 	}
2520bc7cf6fSBjoern A. Zeeb 
2530bc7cf6fSBjoern A. Zeeb         ha->pci_func = pci_get_function(dev);
2540bc7cf6fSBjoern A. Zeeb 
2550bc7cf6fSBjoern A. Zeeb         ha->pci_dev = dev;
2560bc7cf6fSBjoern A. Zeeb 
2570bc7cf6fSBjoern A. Zeeb 	pci_enable_busmaster(dev);
2580bc7cf6fSBjoern A. Zeeb 
2590bc7cf6fSBjoern A. Zeeb 	ha->reg_rid = PCIR_BAR(0);
2600bc7cf6fSBjoern A. Zeeb 	ha->pci_reg = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &ha->reg_rid,
2610bc7cf6fSBjoern A. Zeeb 				RF_ACTIVE);
2620bc7cf6fSBjoern A. Zeeb 
2630bc7cf6fSBjoern A. Zeeb         if (ha->pci_reg == NULL) {
2640bc7cf6fSBjoern A. Zeeb                 device_printf(dev, "unable to map any ports\n");
2650bc7cf6fSBjoern A. Zeeb                 goto qla_pci_attach_err;
2660bc7cf6fSBjoern A. Zeeb         }
2670bc7cf6fSBjoern A. Zeeb 
2680bc7cf6fSBjoern A. Zeeb 	rsrc_len = (uint32_t) bus_get_resource_count(dev, SYS_RES_MEMORY,
2690bc7cf6fSBjoern A. Zeeb 					ha->reg_rid);
2700bc7cf6fSBjoern A. Zeeb 
2710bc7cf6fSBjoern A. Zeeb 	mtx_init(&ha->hw_lock, "qla80xx_hw_lock", MTX_NETWORK_LOCK, MTX_DEF);
2720bc7cf6fSBjoern A. Zeeb 	mtx_init(&ha->tx_lock, "qla80xx_tx_lock", MTX_NETWORK_LOCK, MTX_DEF);
2730bc7cf6fSBjoern A. Zeeb 	mtx_init(&ha->rx_lock, "qla80xx_rx_lock", MTX_NETWORK_LOCK, MTX_DEF);
2740bc7cf6fSBjoern A. Zeeb 	mtx_init(&ha->rxj_lock, "qla80xx_rxj_lock", MTX_NETWORK_LOCK, MTX_DEF);
2750bc7cf6fSBjoern A. Zeeb 	ha->flags.lock_init = 1;
2760bc7cf6fSBjoern A. Zeeb 
2770bc7cf6fSBjoern A. Zeeb 	ha->msix_count = pci_msix_count(dev);
2780bc7cf6fSBjoern A. Zeeb 
2790bc7cf6fSBjoern A. Zeeb 	if (ha->msix_count < qla_get_msix_count(ha)) {
2800bc7cf6fSBjoern A. Zeeb 		device_printf(dev, "%s: msix_count[%d] not enough\n", __func__,
2810bc7cf6fSBjoern A. Zeeb 			ha->msix_count);
2820bc7cf6fSBjoern A. Zeeb 		goto qla_pci_attach_err;
2830bc7cf6fSBjoern A. Zeeb 	}
2840bc7cf6fSBjoern A. Zeeb 
2850bc7cf6fSBjoern A. Zeeb 	QL_DPRINT2((dev, "%s: ha %p irq %p pci_func 0x%x rsrc_count 0x%08x"
2860bc7cf6fSBjoern A. Zeeb 		" msix_count 0x%x pci_reg %p\n", __func__, ha,
2870bc7cf6fSBjoern A. Zeeb 		ha->irq, ha->pci_func, rsrc_len, ha->msix_count, ha->pci_reg));
2880bc7cf6fSBjoern A. Zeeb 
2890bc7cf6fSBjoern A. Zeeb 	ha->msix_count = qla_get_msix_count(ha);
2900bc7cf6fSBjoern A. Zeeb 
2910bc7cf6fSBjoern A. Zeeb 	if (pci_alloc_msix(dev, &ha->msix_count)) {
2920bc7cf6fSBjoern A. Zeeb 		device_printf(dev, "%s: pci_alloc_msi[%d] failed\n", __func__,
2930bc7cf6fSBjoern A. Zeeb 			ha->msix_count);
2940bc7cf6fSBjoern A. Zeeb 		ha->msix_count = 0;
2950bc7cf6fSBjoern A. Zeeb 		goto qla_pci_attach_err;
2960bc7cf6fSBjoern A. Zeeb 	}
2970bc7cf6fSBjoern A. Zeeb 
2980bc7cf6fSBjoern A. Zeeb 	TASK_INIT(&ha->tx_task, 0, qla_tx_done, ha);
2990bc7cf6fSBjoern A. Zeeb 	ha->tx_tq = taskqueue_create_fast("qla_txq", M_NOWAIT,
3000bc7cf6fSBjoern A. Zeeb 			taskqueue_thread_enqueue, &ha->tx_tq);
3010bc7cf6fSBjoern A. Zeeb 	taskqueue_start_threads(&ha->tx_tq, 1, PI_NET, "%s txq",
3020bc7cf6fSBjoern A. Zeeb 		device_get_nameunit(ha->pci_dev));
3030bc7cf6fSBjoern A. Zeeb 
3040bc7cf6fSBjoern A. Zeeb         for (i = 0; i < ha->msix_count; i++) {
3050bc7cf6fSBjoern A. Zeeb                 ha->irq_vec[i].irq_rid = i+1;
3060bc7cf6fSBjoern A. Zeeb                 ha->irq_vec[i].ha = ha;
3070bc7cf6fSBjoern A. Zeeb 
3080bc7cf6fSBjoern A. Zeeb                 ha->irq_vec[i].irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
3090bc7cf6fSBjoern A. Zeeb                                         &ha->irq_vec[i].irq_rid,
3100bc7cf6fSBjoern A. Zeeb                                         (RF_ACTIVE | RF_SHAREABLE));
3110bc7cf6fSBjoern A. Zeeb 
3120bc7cf6fSBjoern A. Zeeb                 if (ha->irq_vec[i].irq == NULL) {
3130bc7cf6fSBjoern A. Zeeb                         device_printf(dev, "could not allocate interrupt\n");
3140bc7cf6fSBjoern A. Zeeb                         goto qla_pci_attach_err;
3150bc7cf6fSBjoern A. Zeeb                 }
3160bc7cf6fSBjoern A. Zeeb 
3170bc7cf6fSBjoern A. Zeeb                 if (bus_setup_intr(dev, ha->irq_vec[i].irq,
3180bc7cf6fSBjoern A. Zeeb                         (INTR_TYPE_NET | INTR_MPSAFE),
3190bc7cf6fSBjoern A. Zeeb                         NULL, qla_isr, &ha->irq_vec[i],
3200bc7cf6fSBjoern A. Zeeb                         &ha->irq_vec[i].handle)) {
3210bc7cf6fSBjoern A. Zeeb                         device_printf(dev, "could not setup interrupt\n");
3220bc7cf6fSBjoern A. Zeeb                         goto qla_pci_attach_err;
3230bc7cf6fSBjoern A. Zeeb                 }
3240bc7cf6fSBjoern A. Zeeb 
3250bc7cf6fSBjoern A. Zeeb 		TASK_INIT(&ha->irq_vec[i].rcv_task, 0, qla_rcv,\
3260bc7cf6fSBjoern A. Zeeb 			&ha->irq_vec[i]);
3270bc7cf6fSBjoern A. Zeeb 
3280bc7cf6fSBjoern A. Zeeb 		ha->irq_vec[i].rcv_tq = taskqueue_create_fast("qla_rcvq",
3290bc7cf6fSBjoern A. Zeeb 			M_NOWAIT, taskqueue_thread_enqueue,
3300bc7cf6fSBjoern A. Zeeb 			&ha->irq_vec[i].rcv_tq);
3310bc7cf6fSBjoern A. Zeeb 
3320bc7cf6fSBjoern A. Zeeb 		taskqueue_start_threads(&ha->irq_vec[i].rcv_tq, 1, PI_NET,
3330bc7cf6fSBjoern A. Zeeb 			"%s rcvq",
3340bc7cf6fSBjoern A. Zeeb 			device_get_nameunit(ha->pci_dev));
3350bc7cf6fSBjoern A. Zeeb         }
3360bc7cf6fSBjoern A. Zeeb 
3370bc7cf6fSBjoern A. Zeeb 	qla_add_sysctls(ha);
3380bc7cf6fSBjoern A. Zeeb 
3390bc7cf6fSBjoern A. Zeeb 	/* add hardware specific sysctls */
3400bc7cf6fSBjoern A. Zeeb 	qla_hw_add_sysctls(ha);
3410bc7cf6fSBjoern A. Zeeb 
3420bc7cf6fSBjoern A. Zeeb 	/* initialize hardware */
3430bc7cf6fSBjoern A. Zeeb 	if (qla_init_hw(ha)) {
3440bc7cf6fSBjoern A. Zeeb 		device_printf(dev, "%s: qla_init_hw failed\n", __func__);
3450bc7cf6fSBjoern A. Zeeb 		goto qla_pci_attach_err;
3460bc7cf6fSBjoern A. Zeeb 	}
3470bc7cf6fSBjoern A. Zeeb 
3480bc7cf6fSBjoern A. Zeeb 	device_printf(dev, "%s: firmware[%d.%d.%d.%d]\n", __func__,
3490bc7cf6fSBjoern A. Zeeb 		ha->fw_ver_major, ha->fw_ver_minor, ha->fw_ver_sub,
3500bc7cf6fSBjoern A. Zeeb 		ha->fw_ver_build);
3510bc7cf6fSBjoern A. Zeeb 
352088fc971SDavid C Somayajulu 	snprintf(ha->fw_ver_str, sizeof(ha->fw_ver_str), "%d.%d.%d.%d",
353088fc971SDavid C Somayajulu 			ha->fw_ver_major, ha->fw_ver_minor, ha->fw_ver_sub,
354088fc971SDavid C Somayajulu 			ha->fw_ver_build);
355088fc971SDavid C Somayajulu 
3560bc7cf6fSBjoern A. Zeeb 	//qla_get_hw_caps(ha);
3570bc7cf6fSBjoern A. Zeeb 	qla_read_mac_addr(ha);
3580bc7cf6fSBjoern A. Zeeb 
3590bc7cf6fSBjoern A. Zeeb 	/* allocate parent dma tag */
3600bc7cf6fSBjoern A. Zeeb 	if (qla_alloc_parent_dma_tag(ha)) {
3610bc7cf6fSBjoern A. Zeeb 		device_printf(dev, "%s: qla_alloc_parent_dma_tag failed\n",
3620bc7cf6fSBjoern A. Zeeb 			__func__);
3630bc7cf6fSBjoern A. Zeeb 		goto qla_pci_attach_err;
3640bc7cf6fSBjoern A. Zeeb 	}
3650bc7cf6fSBjoern A. Zeeb 
3660bc7cf6fSBjoern A. Zeeb 	/* alloc all dma buffers */
3670bc7cf6fSBjoern A. Zeeb 	if (qla_alloc_dma(ha)) {
3680bc7cf6fSBjoern A. Zeeb 		device_printf(dev, "%s: qla_alloc_dma failed\n", __func__);
3690bc7cf6fSBjoern A. Zeeb 		goto qla_pci_attach_err;
3700bc7cf6fSBjoern A. Zeeb 	}
3710bc7cf6fSBjoern A. Zeeb 
3720bc7cf6fSBjoern A. Zeeb 	/* create the o.s ethernet interface */
3730bc7cf6fSBjoern A. Zeeb 	qla_init_ifnet(dev, ha);
3740bc7cf6fSBjoern A. Zeeb 
3750bc7cf6fSBjoern A. Zeeb 	ha->flags.qla_watchdog_active = 1;
3760bc7cf6fSBjoern A. Zeeb 	ha->flags.qla_watchdog_pause = 1;
3770bc7cf6fSBjoern A. Zeeb 
378fd90e2edSJung-uk Kim 	callout_init(&ha->tx_callout, 1);
3790bc7cf6fSBjoern A. Zeeb 
3800bc7cf6fSBjoern A. Zeeb 	/* create ioctl device interface */
3810bc7cf6fSBjoern A. Zeeb 	if (qla_make_cdev(ha)) {
3820bc7cf6fSBjoern A. Zeeb 		device_printf(dev, "%s: qla_make_cdev failed\n", __func__);
3830bc7cf6fSBjoern A. Zeeb 		goto qla_pci_attach_err;
3840bc7cf6fSBjoern A. Zeeb 	}
3850bc7cf6fSBjoern A. Zeeb 
3860bc7cf6fSBjoern A. Zeeb 	callout_reset(&ha->tx_callout, QLA_WATCHDOG_CALLOUT_TICKS,
3870bc7cf6fSBjoern A. Zeeb 		qla_watchdog, ha);
3880bc7cf6fSBjoern A. Zeeb 
3890bc7cf6fSBjoern A. Zeeb 	QL_DPRINT2((dev, "%s: exit 0\n", __func__));
3900bc7cf6fSBjoern A. Zeeb         return (0);
3910bc7cf6fSBjoern A. Zeeb 
3920bc7cf6fSBjoern A. Zeeb qla_pci_attach_err:
3930bc7cf6fSBjoern A. Zeeb 
3940bc7cf6fSBjoern A. Zeeb 	qla_release(ha);
3950bc7cf6fSBjoern A. Zeeb 
3960bc7cf6fSBjoern A. Zeeb 	QL_DPRINT2((dev, "%s: exit ENXIO\n", __func__));
3970bc7cf6fSBjoern A. Zeeb         return (ENXIO);
3980bc7cf6fSBjoern A. Zeeb }
3990bc7cf6fSBjoern A. Zeeb 
4000bc7cf6fSBjoern A. Zeeb /*
4010bc7cf6fSBjoern A. Zeeb  * Name:	qla_pci_detach
4020bc7cf6fSBjoern A. Zeeb  * Function:	Unhooks the device from the operating system
4030bc7cf6fSBjoern A. Zeeb  */
4040bc7cf6fSBjoern A. Zeeb static int
qla_pci_detach(device_t dev)4050bc7cf6fSBjoern A. Zeeb qla_pci_detach(device_t dev)
4060bc7cf6fSBjoern A. Zeeb {
4070bc7cf6fSBjoern A. Zeeb 	qla_host_t *ha = NULL;
4080bc7cf6fSBjoern A. Zeeb 	int i;
4090bc7cf6fSBjoern A. Zeeb 
4100bc7cf6fSBjoern A. Zeeb 	QL_DPRINT2((dev, "%s: enter\n", __func__));
4110bc7cf6fSBjoern A. Zeeb 
4120bc7cf6fSBjoern A. Zeeb         if ((ha = device_get_softc(dev)) == NULL) {
4130bc7cf6fSBjoern A. Zeeb                 device_printf(dev, "cannot get softc\n");
4140bc7cf6fSBjoern A. Zeeb                 return (ENOMEM);
4150bc7cf6fSBjoern A. Zeeb         }
4160bc7cf6fSBjoern A. Zeeb 
4170bc7cf6fSBjoern A. Zeeb 	QLA_LOCK(ha, __func__);
4180bc7cf6fSBjoern A. Zeeb 	qla_stop(ha);
4190bc7cf6fSBjoern A. Zeeb 	QLA_UNLOCK(ha, __func__);
4200bc7cf6fSBjoern A. Zeeb 
4210bc7cf6fSBjoern A. Zeeb 	if (ha->tx_tq) {
4220bc7cf6fSBjoern A. Zeeb 		taskqueue_drain(ha->tx_tq, &ha->tx_task);
4230bc7cf6fSBjoern A. Zeeb 		taskqueue_free(ha->tx_tq);
4240bc7cf6fSBjoern A. Zeeb 	}
4250bc7cf6fSBjoern A. Zeeb 
4260bc7cf6fSBjoern A. Zeeb         for (i = 0; i < ha->msix_count; i++) {
4270bc7cf6fSBjoern A. Zeeb 		taskqueue_drain(ha->irq_vec[i].rcv_tq,
4280bc7cf6fSBjoern A. Zeeb 			&ha->irq_vec[i].rcv_task);
4290bc7cf6fSBjoern A. Zeeb 		taskqueue_free(ha->irq_vec[i].rcv_tq);
4300bc7cf6fSBjoern A. Zeeb 	}
4310bc7cf6fSBjoern A. Zeeb 
4320bc7cf6fSBjoern A. Zeeb 	qla_release(ha);
4330bc7cf6fSBjoern A. Zeeb 
4340bc7cf6fSBjoern A. Zeeb 	QL_DPRINT2((dev, "%s: exit\n", __func__));
4350bc7cf6fSBjoern A. Zeeb 
4360bc7cf6fSBjoern A. Zeeb         return (0);
4370bc7cf6fSBjoern A. Zeeb }
4380bc7cf6fSBjoern A. Zeeb 
4390bc7cf6fSBjoern A. Zeeb /*
4400bc7cf6fSBjoern A. Zeeb  * SYSCTL Related Callbacks
4410bc7cf6fSBjoern A. Zeeb  */
4420bc7cf6fSBjoern A. Zeeb static int
qla_sysctl_get_stats(SYSCTL_HANDLER_ARGS)4430bc7cf6fSBjoern A. Zeeb qla_sysctl_get_stats(SYSCTL_HANDLER_ARGS)
4440bc7cf6fSBjoern A. Zeeb {
4450bc7cf6fSBjoern A. Zeeb 	int err, ret = 0;
4460bc7cf6fSBjoern A. Zeeb 	qla_host_t *ha;
4470bc7cf6fSBjoern A. Zeeb 
4480bc7cf6fSBjoern A. Zeeb 	err = sysctl_handle_int(oidp, &ret, 0, req);
4490bc7cf6fSBjoern A. Zeeb 
4500bc7cf6fSBjoern A. Zeeb 	if (err)
4510bc7cf6fSBjoern A. Zeeb 		return (err);
4520bc7cf6fSBjoern A. Zeeb 
4530bc7cf6fSBjoern A. Zeeb 	ha = (qla_host_t *)arg1;
4540bc7cf6fSBjoern A. Zeeb 	//qla_get_stats(ha);
4550bc7cf6fSBjoern A. Zeeb 	QL_DPRINT2((ha->pci_dev, "%s: called ret %d\n", __func__, ret));
4560bc7cf6fSBjoern A. Zeeb 	return (err);
4570bc7cf6fSBjoern A. Zeeb }
4580bc7cf6fSBjoern A. Zeeb 
4590bc7cf6fSBjoern A. Zeeb /*
4600bc7cf6fSBjoern A. Zeeb  * Name:	qla_release
4610bc7cf6fSBjoern A. Zeeb  * Function:	Releases the resources allocated for the device
4620bc7cf6fSBjoern A. Zeeb  */
4630bc7cf6fSBjoern A. Zeeb static void
qla_release(qla_host_t * ha)4640bc7cf6fSBjoern A. Zeeb qla_release(qla_host_t *ha)
4650bc7cf6fSBjoern A. Zeeb {
4660bc7cf6fSBjoern A. Zeeb 	device_t dev;
4670bc7cf6fSBjoern A. Zeeb 	int i;
4680bc7cf6fSBjoern A. Zeeb 
4690bc7cf6fSBjoern A. Zeeb 	dev = ha->pci_dev;
4700bc7cf6fSBjoern A. Zeeb 
4710bc7cf6fSBjoern A. Zeeb 	qla_del_cdev(ha);
4720bc7cf6fSBjoern A. Zeeb 
4730bc7cf6fSBjoern A. Zeeb 	if (ha->flags.qla_watchdog_active)
4740bc7cf6fSBjoern A. Zeeb 		ha->flags.qla_watchdog_exit = 1;
4750bc7cf6fSBjoern A. Zeeb 
4760bc7cf6fSBjoern A. Zeeb 	callout_stop(&ha->tx_callout);
4770bc7cf6fSBjoern A. Zeeb 	qla_mdelay(__func__, 100);
4780bc7cf6fSBjoern A. Zeeb 
4790bc7cf6fSBjoern A. Zeeb 	if (ha->ifp != NULL)
4800bc7cf6fSBjoern A. Zeeb 		ether_ifdetach(ha->ifp);
4810bc7cf6fSBjoern A. Zeeb 
4820bc7cf6fSBjoern A. Zeeb 	qla_free_dma(ha);
4830bc7cf6fSBjoern A. Zeeb 	qla_free_parent_dma_tag(ha);
4840bc7cf6fSBjoern A. Zeeb 
4850bc7cf6fSBjoern A. Zeeb 	for (i = 0; i < ha->msix_count; i++) {
4860bc7cf6fSBjoern A. Zeeb 		if (ha->irq_vec[i].handle)
4870bc7cf6fSBjoern A. Zeeb 			(void)bus_teardown_intr(dev, ha->irq_vec[i].irq,
4880bc7cf6fSBjoern A. Zeeb 				ha->irq_vec[i].handle);
4890bc7cf6fSBjoern A. Zeeb 		if (ha->irq_vec[i].irq)
4900bc7cf6fSBjoern A. Zeeb 			(void) bus_release_resource(dev, SYS_RES_IRQ,
4910bc7cf6fSBjoern A. Zeeb 				ha->irq_vec[i].irq_rid,
4920bc7cf6fSBjoern A. Zeeb 				ha->irq_vec[i].irq);
4930bc7cf6fSBjoern A. Zeeb 	}
4940bc7cf6fSBjoern A. Zeeb 	if (ha->msix_count)
4950bc7cf6fSBjoern A. Zeeb 		pci_release_msi(dev);
4960bc7cf6fSBjoern A. Zeeb 
4970bc7cf6fSBjoern A. Zeeb 	if (ha->flags.lock_init) {
4980bc7cf6fSBjoern A. Zeeb 		mtx_destroy(&ha->tx_lock);
4990bc7cf6fSBjoern A. Zeeb 		mtx_destroy(&ha->rx_lock);
5000bc7cf6fSBjoern A. Zeeb 		mtx_destroy(&ha->rxj_lock);
5010bc7cf6fSBjoern A. Zeeb 		mtx_destroy(&ha->hw_lock);
5020bc7cf6fSBjoern A. Zeeb 	}
5030bc7cf6fSBjoern A. Zeeb 
5040bc7cf6fSBjoern A. Zeeb         if (ha->pci_reg)
5050bc7cf6fSBjoern A. Zeeb                 (void) bus_release_resource(dev, SYS_RES_MEMORY, ha->reg_rid,
5060bc7cf6fSBjoern A. Zeeb 				ha->pci_reg);
5070bc7cf6fSBjoern A. Zeeb }
5080bc7cf6fSBjoern A. Zeeb 
5090bc7cf6fSBjoern A. Zeeb /*
5100bc7cf6fSBjoern A. Zeeb  * DMA Related Functions
5110bc7cf6fSBjoern A. Zeeb  */
5120bc7cf6fSBjoern A. Zeeb 
5130bc7cf6fSBjoern A. Zeeb static void
qla_dmamap_callback(void * arg,bus_dma_segment_t * segs,int nsegs,int error)5140bc7cf6fSBjoern A. Zeeb qla_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
5150bc7cf6fSBjoern A. Zeeb {
5160bc7cf6fSBjoern A. Zeeb         *((bus_addr_t *)arg) = 0;
5170bc7cf6fSBjoern A. Zeeb 
5180bc7cf6fSBjoern A. Zeeb         if (error) {
5190bc7cf6fSBjoern A. Zeeb                 printf("%s: bus_dmamap_load failed (%d)\n", __func__, error);
5200bc7cf6fSBjoern A. Zeeb                 return;
5210bc7cf6fSBjoern A. Zeeb 	}
5220bc7cf6fSBjoern A. Zeeb 
5230bc7cf6fSBjoern A. Zeeb         QL_ASSERT((nsegs == 1), ("%s: %d segments returned!", __func__, nsegs));
5240bc7cf6fSBjoern A. Zeeb 
5250bc7cf6fSBjoern A. Zeeb         *((bus_addr_t *)arg) = segs[0].ds_addr;
5260bc7cf6fSBjoern A. Zeeb 
5270bc7cf6fSBjoern A. Zeeb 	return;
5280bc7cf6fSBjoern A. Zeeb }
5290bc7cf6fSBjoern A. Zeeb 
5300bc7cf6fSBjoern A. Zeeb int
qla_alloc_dmabuf(qla_host_t * ha,qla_dma_t * dma_buf)5310bc7cf6fSBjoern A. Zeeb qla_alloc_dmabuf(qla_host_t *ha, qla_dma_t *dma_buf)
5320bc7cf6fSBjoern A. Zeeb {
5330bc7cf6fSBjoern A. Zeeb         int             ret = 0;
5340bc7cf6fSBjoern A. Zeeb         device_t        dev;
5350bc7cf6fSBjoern A. Zeeb         bus_addr_t      b_addr;
5360bc7cf6fSBjoern A. Zeeb 
5370bc7cf6fSBjoern A. Zeeb         dev = ha->pci_dev;
5380bc7cf6fSBjoern A. Zeeb 
5390bc7cf6fSBjoern A. Zeeb         QL_DPRINT2((dev, "%s: enter\n", __func__));
5400bc7cf6fSBjoern A. Zeeb 
5410bc7cf6fSBjoern A. Zeeb         ret = bus_dma_tag_create(
5420bc7cf6fSBjoern A. Zeeb                         ha->parent_tag,/* parent */
5430bc7cf6fSBjoern A. Zeeb                         dma_buf->alignment,
5440bc7cf6fSBjoern A. Zeeb                         ((bus_size_t)(1ULL << 32)),/* boundary */
5450bc7cf6fSBjoern A. Zeeb                         BUS_SPACE_MAXADDR,      /* lowaddr */
5460bc7cf6fSBjoern A. Zeeb                         BUS_SPACE_MAXADDR,      /* highaddr */
5470bc7cf6fSBjoern A. Zeeb                         NULL, NULL,             /* filter, filterarg */
5480bc7cf6fSBjoern A. Zeeb                         dma_buf->size,          /* maxsize */
5490bc7cf6fSBjoern A. Zeeb                         1,                      /* nsegments */
5500bc7cf6fSBjoern A. Zeeb                         dma_buf->size,          /* maxsegsize */
5510bc7cf6fSBjoern A. Zeeb                         0,                      /* flags */
5520bc7cf6fSBjoern A. Zeeb                         NULL, NULL,             /* lockfunc, lockarg */
5530bc7cf6fSBjoern A. Zeeb                         &dma_buf->dma_tag);
5540bc7cf6fSBjoern A. Zeeb 
5550bc7cf6fSBjoern A. Zeeb         if (ret) {
5560bc7cf6fSBjoern A. Zeeb                 device_printf(dev, "%s: could not create dma tag\n", __func__);
5570bc7cf6fSBjoern A. Zeeb                 goto qla_alloc_dmabuf_exit;
5580bc7cf6fSBjoern A. Zeeb         }
5590bc7cf6fSBjoern A. Zeeb         ret = bus_dmamem_alloc(dma_buf->dma_tag,
5600bc7cf6fSBjoern A. Zeeb                         (void **)&dma_buf->dma_b,
5610bc7cf6fSBjoern A. Zeeb                         (BUS_DMA_ZERO | BUS_DMA_COHERENT | BUS_DMA_NOWAIT),
5620bc7cf6fSBjoern A. Zeeb                         &dma_buf->dma_map);
5630bc7cf6fSBjoern A. Zeeb         if (ret) {
5640bc7cf6fSBjoern A. Zeeb                 bus_dma_tag_destroy(dma_buf->dma_tag);
5650bc7cf6fSBjoern A. Zeeb                 device_printf(dev, "%s: bus_dmamem_alloc failed\n", __func__);
5660bc7cf6fSBjoern A. Zeeb                 goto qla_alloc_dmabuf_exit;
5670bc7cf6fSBjoern A. Zeeb         }
5680bc7cf6fSBjoern A. Zeeb 
5690bc7cf6fSBjoern A. Zeeb         ret = bus_dmamap_load(dma_buf->dma_tag,
5700bc7cf6fSBjoern A. Zeeb                         dma_buf->dma_map,
5710bc7cf6fSBjoern A. Zeeb                         dma_buf->dma_b,
5720bc7cf6fSBjoern A. Zeeb                         dma_buf->size,
5730bc7cf6fSBjoern A. Zeeb                         qla_dmamap_callback,
5740bc7cf6fSBjoern A. Zeeb                         &b_addr, BUS_DMA_NOWAIT);
5750bc7cf6fSBjoern A. Zeeb 
5760bc7cf6fSBjoern A. Zeeb         if (ret || !b_addr) {
5770bc7cf6fSBjoern A. Zeeb                 bus_dma_tag_destroy(dma_buf->dma_tag);
5780bc7cf6fSBjoern A. Zeeb                 bus_dmamem_free(dma_buf->dma_tag, dma_buf->dma_b,
5790bc7cf6fSBjoern A. Zeeb                         dma_buf->dma_map);
5800bc7cf6fSBjoern A. Zeeb                 ret = -1;
5810bc7cf6fSBjoern A. Zeeb                 goto qla_alloc_dmabuf_exit;
5820bc7cf6fSBjoern A. Zeeb         }
5830bc7cf6fSBjoern A. Zeeb 
5840bc7cf6fSBjoern A. Zeeb         dma_buf->dma_addr = b_addr;
5850bc7cf6fSBjoern A. Zeeb 
5860bc7cf6fSBjoern A. Zeeb qla_alloc_dmabuf_exit:
5870bc7cf6fSBjoern A. Zeeb         QL_DPRINT2((dev, "%s: exit ret 0x%08x tag %p map %p b %p sz 0x%x\n",
5880bc7cf6fSBjoern A. Zeeb                 __func__, ret, (void *)dma_buf->dma_tag,
5890bc7cf6fSBjoern A. Zeeb                 (void *)dma_buf->dma_map, (void *)dma_buf->dma_b,
5900bc7cf6fSBjoern A. Zeeb 		dma_buf->size));
5910bc7cf6fSBjoern A. Zeeb 
5920bc7cf6fSBjoern A. Zeeb         return ret;
5930bc7cf6fSBjoern A. Zeeb }
5940bc7cf6fSBjoern A. Zeeb 
5950bc7cf6fSBjoern A. Zeeb void
qla_free_dmabuf(qla_host_t * ha,qla_dma_t * dma_buf)5960bc7cf6fSBjoern A. Zeeb qla_free_dmabuf(qla_host_t *ha, qla_dma_t *dma_buf)
5970bc7cf6fSBjoern A. Zeeb {
598aeeb653cSJohn Baldwin         bus_dmamap_unload(dma_buf->dma_tag, dma_buf->dma_map);
5990bc7cf6fSBjoern A. Zeeb         bus_dmamem_free(dma_buf->dma_tag, dma_buf->dma_b, dma_buf->dma_map);
6000bc7cf6fSBjoern A. Zeeb         bus_dma_tag_destroy(dma_buf->dma_tag);
6010bc7cf6fSBjoern A. Zeeb }
6020bc7cf6fSBjoern A. Zeeb 
6030bc7cf6fSBjoern A. Zeeb static int
qla_alloc_parent_dma_tag(qla_host_t * ha)6040bc7cf6fSBjoern A. Zeeb qla_alloc_parent_dma_tag(qla_host_t *ha)
6050bc7cf6fSBjoern A. Zeeb {
6060bc7cf6fSBjoern A. Zeeb 	int		ret;
6070bc7cf6fSBjoern A. Zeeb 	device_t	dev;
6080bc7cf6fSBjoern A. Zeeb 
6090bc7cf6fSBjoern A. Zeeb 	dev = ha->pci_dev;
6100bc7cf6fSBjoern A. Zeeb 
6110bc7cf6fSBjoern A. Zeeb         /*
6120bc7cf6fSBjoern A. Zeeb          * Allocate parent DMA Tag
6130bc7cf6fSBjoern A. Zeeb          */
6140bc7cf6fSBjoern A. Zeeb         ret = bus_dma_tag_create(
6150bc7cf6fSBjoern A. Zeeb                         bus_get_dma_tag(dev),   /* parent */
6160bc7cf6fSBjoern A. Zeeb                         1,((bus_size_t)(1ULL << 32)),/* alignment, boundary */
6170bc7cf6fSBjoern A. Zeeb                         BUS_SPACE_MAXADDR,      /* lowaddr */
6180bc7cf6fSBjoern A. Zeeb                         BUS_SPACE_MAXADDR,      /* highaddr */
6190bc7cf6fSBjoern A. Zeeb                         NULL, NULL,             /* filter, filterarg */
6200bc7cf6fSBjoern A. Zeeb                         BUS_SPACE_MAXSIZE_32BIT,/* maxsize */
6210bc7cf6fSBjoern A. Zeeb                         0,                      /* nsegments */
6220bc7cf6fSBjoern A. Zeeb                         BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
6230bc7cf6fSBjoern A. Zeeb                         0,                      /* flags */
6240bc7cf6fSBjoern A. Zeeb                         NULL, NULL,             /* lockfunc, lockarg */
6250bc7cf6fSBjoern A. Zeeb                         &ha->parent_tag);
6260bc7cf6fSBjoern A. Zeeb 
6270bc7cf6fSBjoern A. Zeeb         if (ret) {
6280bc7cf6fSBjoern A. Zeeb                 device_printf(dev, "%s: could not create parent dma tag\n",
6290bc7cf6fSBjoern A. Zeeb                         __func__);
6300bc7cf6fSBjoern A. Zeeb 		return (-1);
6310bc7cf6fSBjoern A. Zeeb         }
6320bc7cf6fSBjoern A. Zeeb 
6330bc7cf6fSBjoern A. Zeeb         ha->flags.parent_tag = 1;
6340bc7cf6fSBjoern A. Zeeb 
6350bc7cf6fSBjoern A. Zeeb 	return (0);
6360bc7cf6fSBjoern A. Zeeb }
6370bc7cf6fSBjoern A. Zeeb 
6380bc7cf6fSBjoern A. Zeeb static void
qla_free_parent_dma_tag(qla_host_t * ha)6390bc7cf6fSBjoern A. Zeeb qla_free_parent_dma_tag(qla_host_t *ha)
6400bc7cf6fSBjoern A. Zeeb {
6410bc7cf6fSBjoern A. Zeeb         if (ha->flags.parent_tag) {
6420bc7cf6fSBjoern A. Zeeb                 bus_dma_tag_destroy(ha->parent_tag);
6430bc7cf6fSBjoern A. Zeeb                 ha->flags.parent_tag = 0;
6440bc7cf6fSBjoern A. Zeeb         }
6450bc7cf6fSBjoern A. Zeeb }
6460bc7cf6fSBjoern A. Zeeb 
6470bc7cf6fSBjoern A. Zeeb /*
6480bc7cf6fSBjoern A. Zeeb  * Name: qla_init_ifnet
6490bc7cf6fSBjoern A. Zeeb  * Function: Creates the Network Device Interface and Registers it with the O.S
6500bc7cf6fSBjoern A. Zeeb  */
6510bc7cf6fSBjoern A. Zeeb 
6520bc7cf6fSBjoern A. Zeeb static void
qla_init_ifnet(device_t dev,qla_host_t * ha)6530bc7cf6fSBjoern A. Zeeb qla_init_ifnet(device_t dev, qla_host_t *ha)
6540bc7cf6fSBjoern A. Zeeb {
6555b587352SJustin Hibbits 	if_t ifp;
6560bc7cf6fSBjoern A. Zeeb 
6570bc7cf6fSBjoern A. Zeeb 	QL_DPRINT2((dev, "%s: enter\n", __func__));
6580bc7cf6fSBjoern A. Zeeb 
6590bc7cf6fSBjoern A. Zeeb 	ifp = ha->ifp = if_alloc(IFT_ETHER);
6600bc7cf6fSBjoern A. Zeeb 
6610bc7cf6fSBjoern A. Zeeb 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
6620bc7cf6fSBjoern A. Zeeb 
6635b587352SJustin Hibbits 	if_setmtu(ifp, ETHERMTU);
6645b587352SJustin Hibbits 	if_setbaudrate(ifp, IF_Gbps(10));
6655b587352SJustin Hibbits 	if_setinitfn(ifp, qla_init);
6665b587352SJustin Hibbits 	if_setsoftc(ifp, ha);
6675b587352SJustin Hibbits 	if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
6685b587352SJustin Hibbits 	if_setioctlfn(ifp, qla_ioctl);
6695b587352SJustin Hibbits 	if_setstartfn(ifp, qla_start);
6700bc7cf6fSBjoern A. Zeeb 
6715b587352SJustin Hibbits 	if_setsendqlen(ifp, qla_get_ifq_snd_maxlen(ha));
6725b587352SJustin Hibbits 	if_setsendqready(ifp);
6730bc7cf6fSBjoern A. Zeeb 
6745b587352SJustin Hibbits 	ha->max_frame_size = if_getmtu(ifp) + ETHER_HDR_LEN + ETHER_CRC_LEN;
6750bc7cf6fSBjoern A. Zeeb 
6760bc7cf6fSBjoern A. Zeeb 	ether_ifattach(ifp, qla_get_mac_addr(ha));
6770bc7cf6fSBjoern A. Zeeb 
6785b587352SJustin Hibbits 	if_setcapabilities(ifp, IFCAP_HWCSUM |
6790bc7cf6fSBjoern A. Zeeb 				IFCAP_TSO4 |
6805b587352SJustin Hibbits 				IFCAP_JUMBO_MTU);
6810bc7cf6fSBjoern A. Zeeb 
6825b587352SJustin Hibbits 	if_setcapabilitiesbit(ifp, IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU, 0);
6835b587352SJustin Hibbits 	if_setcapabilitiesbit(ifp, IFCAP_LINKSTATE, 0);
6840bc7cf6fSBjoern A. Zeeb 
6855b587352SJustin Hibbits 	if_setcapenable(ifp, if_getcapabilities(ifp));
6860bc7cf6fSBjoern A. Zeeb 
6875b587352SJustin Hibbits 	if_setifheaderlen(ifp, sizeof(struct ether_vlan_header));
6880bc7cf6fSBjoern A. Zeeb 
6890bc7cf6fSBjoern A. Zeeb 	ifmedia_init(&ha->media, IFM_IMASK, qla_media_change, qla_media_status);
6900bc7cf6fSBjoern A. Zeeb 
6910bc7cf6fSBjoern A. Zeeb 	ifmedia_add(&ha->media, (IFM_ETHER | qla_get_optics(ha) | IFM_FDX), 0,
6920bc7cf6fSBjoern A. Zeeb 		NULL);
6930bc7cf6fSBjoern A. Zeeb 	ifmedia_add(&ha->media, (IFM_ETHER | IFM_AUTO), 0, NULL);
6940bc7cf6fSBjoern A. Zeeb 
6950bc7cf6fSBjoern A. Zeeb 	ifmedia_set(&ha->media, (IFM_ETHER | IFM_AUTO));
6960bc7cf6fSBjoern A. Zeeb 
6970bc7cf6fSBjoern A. Zeeb 	QL_DPRINT2((dev, "%s: exit\n", __func__));
6980bc7cf6fSBjoern A. Zeeb 
6990bc7cf6fSBjoern A. Zeeb 	return;
7000bc7cf6fSBjoern A. Zeeb }
7010bc7cf6fSBjoern A. Zeeb 
7020bc7cf6fSBjoern A. Zeeb static void
qla_init_locked(qla_host_t * ha)7030bc7cf6fSBjoern A. Zeeb qla_init_locked(qla_host_t *ha)
7040bc7cf6fSBjoern A. Zeeb {
7055b587352SJustin Hibbits 	if_t ifp = ha->ifp;
7060bc7cf6fSBjoern A. Zeeb 
7070bc7cf6fSBjoern A. Zeeb 	qla_stop(ha);
7080bc7cf6fSBjoern A. Zeeb 
7090bc7cf6fSBjoern A. Zeeb 	if (qla_alloc_xmt_bufs(ha) != 0)
7100bc7cf6fSBjoern A. Zeeb 		return;
7110bc7cf6fSBjoern A. Zeeb 
7120bc7cf6fSBjoern A. Zeeb 	if (qla_alloc_rcv_bufs(ha) != 0)
7130bc7cf6fSBjoern A. Zeeb 		return;
7140bc7cf6fSBjoern A. Zeeb 
7150bc7cf6fSBjoern A. Zeeb 	if (qla_config_lro(ha))
7160bc7cf6fSBjoern A. Zeeb 		return;
7170bc7cf6fSBjoern A. Zeeb 
7185b587352SJustin Hibbits 	bcopy(if_getlladdr(ha->ifp), ha->hw.mac_addr, ETHER_ADDR_LEN);
7190bc7cf6fSBjoern A. Zeeb 
7205b587352SJustin Hibbits 	if_sethwassist(ifp, CSUM_TCP | CSUM_UDP | CSUM_TSO);
7210bc7cf6fSBjoern A. Zeeb 
7220bc7cf6fSBjoern A. Zeeb 	ha->flags.stop_rcv = 0;
7230bc7cf6fSBjoern A. Zeeb 	if (qla_init_hw_if(ha) == 0) {
7240bc7cf6fSBjoern A. Zeeb 		ifp = ha->ifp;
7255b587352SJustin Hibbits 		if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0);
7265b587352SJustin Hibbits 		if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
7270bc7cf6fSBjoern A. Zeeb 		ha->flags.qla_watchdog_pause = 0;
7280bc7cf6fSBjoern A. Zeeb 	}
7290bc7cf6fSBjoern A. Zeeb 
7300bc7cf6fSBjoern A. Zeeb 	return;
7310bc7cf6fSBjoern A. Zeeb }
7320bc7cf6fSBjoern A. Zeeb 
7330bc7cf6fSBjoern A. Zeeb static void
qla_init(void * arg)7340bc7cf6fSBjoern A. Zeeb qla_init(void *arg)
7350bc7cf6fSBjoern A. Zeeb {
7360bc7cf6fSBjoern A. Zeeb 	qla_host_t *ha;
7370bc7cf6fSBjoern A. Zeeb 
7380bc7cf6fSBjoern A. Zeeb 	ha = (qla_host_t *)arg;
7390bc7cf6fSBjoern A. Zeeb 
7400bc7cf6fSBjoern A. Zeeb 	QL_DPRINT2((ha->pci_dev, "%s: enter\n", __func__));
7410bc7cf6fSBjoern A. Zeeb 
7420bc7cf6fSBjoern A. Zeeb 	QLA_LOCK(ha, __func__);
7430bc7cf6fSBjoern A. Zeeb 	qla_init_locked(ha);
7440bc7cf6fSBjoern A. Zeeb 	QLA_UNLOCK(ha, __func__);
7450bc7cf6fSBjoern A. Zeeb 
7460bc7cf6fSBjoern A. Zeeb 	QL_DPRINT2((ha->pci_dev, "%s: exit\n", __func__));
7470bc7cf6fSBjoern A. Zeeb }
7480bc7cf6fSBjoern A. Zeeb 
749854d87acSGleb Smirnoff static u_int
qla_copy_maddr(void * arg,struct sockaddr_dl * sdl,u_int mcnt)750854d87acSGleb Smirnoff qla_copy_maddr(void *arg, struct sockaddr_dl *sdl, u_int mcnt)
751854d87acSGleb Smirnoff {
752854d87acSGleb Smirnoff 	uint8_t *mta = arg;
753854d87acSGleb Smirnoff 
754854d87acSGleb Smirnoff 	if (mcnt == Q8_MAX_NUM_MULTICAST_ADDRS)
755854d87acSGleb Smirnoff 		return (0);
756854d87acSGleb Smirnoff 	bcopy(LLADDR(sdl), &mta[mcnt * Q8_MAC_ADDR_LEN], Q8_MAC_ADDR_LEN);
757854d87acSGleb Smirnoff 
758854d87acSGleb Smirnoff 	return (1);
759854d87acSGleb Smirnoff }
760854d87acSGleb Smirnoff 
7610bc7cf6fSBjoern A. Zeeb static void
qla_set_multi(qla_host_t * ha,uint32_t add_multi)7620bc7cf6fSBjoern A. Zeeb qla_set_multi(qla_host_t *ha, uint32_t add_multi)
7630bc7cf6fSBjoern A. Zeeb {
7640bc7cf6fSBjoern A. Zeeb 	uint8_t mta[Q8_MAX_NUM_MULTICAST_ADDRS * Q8_MAC_ADDR_LEN];
7655b587352SJustin Hibbits 	if_t ifp = ha->ifp;
766854d87acSGleb Smirnoff 	int mcnt;
7670bc7cf6fSBjoern A. Zeeb 
768854d87acSGleb Smirnoff 	mcnt = if_foreach_llmaddr(ifp, qla_copy_maddr, mta);
7690bc7cf6fSBjoern A. Zeeb 	qla_hw_set_multi(ha, mta, mcnt, add_multi);
7700bc7cf6fSBjoern A. Zeeb 
7710bc7cf6fSBjoern A. Zeeb 	return;
7720bc7cf6fSBjoern A. Zeeb }
7730bc7cf6fSBjoern A. Zeeb 
7740bc7cf6fSBjoern A. Zeeb static int
qla_ioctl(if_t ifp,u_long cmd,caddr_t data)7755b587352SJustin Hibbits qla_ioctl(if_t ifp, u_long cmd, caddr_t data)
7760bc7cf6fSBjoern A. Zeeb {
7770bc7cf6fSBjoern A. Zeeb 	int ret = 0;
7780bc7cf6fSBjoern A. Zeeb 	struct ifreq *ifr = (struct ifreq *)data;
779618aa8cdSJohn Baldwin #ifdef INET
7800bc7cf6fSBjoern A. Zeeb 	struct ifaddr *ifa = (struct ifaddr *)data;
781618aa8cdSJohn Baldwin #endif
7820bc7cf6fSBjoern A. Zeeb 	qla_host_t *ha;
7830bc7cf6fSBjoern A. Zeeb 
7845b587352SJustin Hibbits 	ha = (qla_host_t *)if_getsoftc(ifp);
7850bc7cf6fSBjoern A. Zeeb 
7860bc7cf6fSBjoern A. Zeeb 	switch (cmd) {
7870bc7cf6fSBjoern A. Zeeb 	case SIOCSIFADDR:
7880bc7cf6fSBjoern A. Zeeb 		QL_DPRINT4((ha->pci_dev, "%s: SIOCSIFADDR (0x%lx)\n",
7890bc7cf6fSBjoern A. Zeeb 			__func__, cmd));
7900bc7cf6fSBjoern A. Zeeb 
791618aa8cdSJohn Baldwin #ifdef INET
7920bc7cf6fSBjoern A. Zeeb 		if (ifa->ifa_addr->sa_family == AF_INET) {
7935b587352SJustin Hibbits 			if_setflagbits(ifp, IFF_UP, 0);
7945b587352SJustin Hibbits 			if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING)) {
7950bc7cf6fSBjoern A. Zeeb 				QLA_LOCK(ha, __func__);
7960bc7cf6fSBjoern A. Zeeb 				qla_init_locked(ha);
7970bc7cf6fSBjoern A. Zeeb 				QLA_UNLOCK(ha, __func__);
7980bc7cf6fSBjoern A. Zeeb 			}
7990bc7cf6fSBjoern A. Zeeb 		QL_DPRINT4((ha->pci_dev,
8000bc7cf6fSBjoern A. Zeeb 			"%s: SIOCSIFADDR (0x%lx) ipv4 [0x%08x]\n",
8010bc7cf6fSBjoern A. Zeeb 			__func__, cmd, ntohl(IA_SIN(ifa)->sin_addr.s_addr)));
8020bc7cf6fSBjoern A. Zeeb 
8030bc7cf6fSBjoern A. Zeeb 			arp_ifinit(ifp, ifa);
8040bc7cf6fSBjoern A. Zeeb 			if (ntohl(IA_SIN(ifa)->sin_addr.s_addr) != INADDR_ANY) {
8050bc7cf6fSBjoern A. Zeeb 				qla_config_ipv4_addr(ha,
8060bc7cf6fSBjoern A. Zeeb 					(IA_SIN(ifa)->sin_addr.s_addr));
8070bc7cf6fSBjoern A. Zeeb 			}
808618aa8cdSJohn Baldwin 			break;
8090bc7cf6fSBjoern A. Zeeb 		}
810618aa8cdSJohn Baldwin #endif
811618aa8cdSJohn Baldwin 		ether_ioctl(ifp, cmd, data);
8120bc7cf6fSBjoern A. Zeeb 		break;
8130bc7cf6fSBjoern A. Zeeb 
8140bc7cf6fSBjoern A. Zeeb 	case SIOCSIFMTU:
8150bc7cf6fSBjoern A. Zeeb 		QL_DPRINT4((ha->pci_dev, "%s: SIOCSIFMTU (0x%lx)\n",
8160bc7cf6fSBjoern A. Zeeb 			__func__, cmd));
8170bc7cf6fSBjoern A. Zeeb 
8180bc7cf6fSBjoern A. Zeeb 		if (ifr->ifr_mtu > QLA_MAX_FRAME_SIZE - ETHER_HDR_LEN) {
8190bc7cf6fSBjoern A. Zeeb 			ret = EINVAL;
8200bc7cf6fSBjoern A. Zeeb 		} else {
8210bc7cf6fSBjoern A. Zeeb 			QLA_LOCK(ha, __func__);
8225b587352SJustin Hibbits 			if_setmtu(ifp, ifr->ifr_mtu);
8230bc7cf6fSBjoern A. Zeeb 			ha->max_frame_size =
8245b587352SJustin Hibbits 				if_getmtu(ifp) + ETHER_HDR_LEN + ETHER_CRC_LEN;
8255b587352SJustin Hibbits 			if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING)) {
8260bc7cf6fSBjoern A. Zeeb 				ret = qla_set_max_mtu(ha, ha->max_frame_size,
8270bc7cf6fSBjoern A. Zeeb 					(ha->hw.rx_cntxt_rsp)->rx_rsp.cntxt_id);
8280bc7cf6fSBjoern A. Zeeb 			}
8290bc7cf6fSBjoern A. Zeeb 			QLA_UNLOCK(ha, __func__);
8300bc7cf6fSBjoern A. Zeeb 
8310bc7cf6fSBjoern A. Zeeb 			if (ret)
8320bc7cf6fSBjoern A. Zeeb 				ret = EINVAL;
8330bc7cf6fSBjoern A. Zeeb 		}
8340bc7cf6fSBjoern A. Zeeb 
8350bc7cf6fSBjoern A. Zeeb 		break;
8360bc7cf6fSBjoern A. Zeeb 
8370bc7cf6fSBjoern A. Zeeb 	case SIOCSIFFLAGS:
8380bc7cf6fSBjoern A. Zeeb 		QL_DPRINT4((ha->pci_dev, "%s: SIOCSIFFLAGS (0x%lx)\n",
8390bc7cf6fSBjoern A. Zeeb 			__func__, cmd));
8400bc7cf6fSBjoern A. Zeeb 
8415b587352SJustin Hibbits 		if (if_getflags(ifp) & IFF_UP) {
8425b587352SJustin Hibbits 			if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING)) {
8435b587352SJustin Hibbits 				if ((if_getflags(ifp) ^ ha->if_flags) &
8440bc7cf6fSBjoern A. Zeeb 					IFF_PROMISC) {
8450bc7cf6fSBjoern A. Zeeb 					qla_set_promisc(ha);
8465b587352SJustin Hibbits 				} else if ((if_getflags(ifp) ^ ha->if_flags) &
8470bc7cf6fSBjoern A. Zeeb 					IFF_ALLMULTI) {
8480bc7cf6fSBjoern A. Zeeb 					qla_set_allmulti(ha);
8490bc7cf6fSBjoern A. Zeeb 				}
8500bc7cf6fSBjoern A. Zeeb 			} else {
8510bc7cf6fSBjoern A. Zeeb 				QLA_LOCK(ha, __func__);
8520bc7cf6fSBjoern A. Zeeb 				qla_init_locked(ha);
8535b587352SJustin Hibbits 				ha->max_frame_size = if_getmtu(ifp) +
8540bc7cf6fSBjoern A. Zeeb 					ETHER_HDR_LEN + ETHER_CRC_LEN;
8550bc7cf6fSBjoern A. Zeeb 				ret = qla_set_max_mtu(ha, ha->max_frame_size,
8560bc7cf6fSBjoern A. Zeeb 					(ha->hw.rx_cntxt_rsp)->rx_rsp.cntxt_id);
8570bc7cf6fSBjoern A. Zeeb 				QLA_UNLOCK(ha, __func__);
8580bc7cf6fSBjoern A. Zeeb 			}
8590bc7cf6fSBjoern A. Zeeb 		} else {
8600bc7cf6fSBjoern A. Zeeb 			QLA_LOCK(ha, __func__);
8615b587352SJustin Hibbits 			if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
8620bc7cf6fSBjoern A. Zeeb 				qla_stop(ha);
8635b587352SJustin Hibbits 			ha->if_flags = if_getflags(ifp);
8640bc7cf6fSBjoern A. Zeeb 			QLA_UNLOCK(ha, __func__);
8650bc7cf6fSBjoern A. Zeeb 		}
8660bc7cf6fSBjoern A. Zeeb 		break;
8670bc7cf6fSBjoern A. Zeeb 
8680bc7cf6fSBjoern A. Zeeb 	case SIOCADDMULTI:
8690bc7cf6fSBjoern A. Zeeb 		QL_DPRINT4((ha->pci_dev,
8700bc7cf6fSBjoern A. Zeeb 			"%s: %s (0x%lx)\n", __func__, "SIOCADDMULTI", cmd));
8710bc7cf6fSBjoern A. Zeeb 
8725b587352SJustin Hibbits 		if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
8730bc7cf6fSBjoern A. Zeeb 			qla_set_multi(ha, 1);
8740bc7cf6fSBjoern A. Zeeb 		}
8750bc7cf6fSBjoern A. Zeeb 		break;
8760bc7cf6fSBjoern A. Zeeb 
8770bc7cf6fSBjoern A. Zeeb 	case SIOCDELMULTI:
8780bc7cf6fSBjoern A. Zeeb 		QL_DPRINT4((ha->pci_dev,
8790bc7cf6fSBjoern A. Zeeb 			"%s: %s (0x%lx)\n", __func__, "SIOCDELMULTI", cmd));
8800bc7cf6fSBjoern A. Zeeb 
8815b587352SJustin Hibbits 		if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
8820bc7cf6fSBjoern A. Zeeb 			qla_set_multi(ha, 0);
8830bc7cf6fSBjoern A. Zeeb 		}
8840bc7cf6fSBjoern A. Zeeb 		break;
8850bc7cf6fSBjoern A. Zeeb 
8860bc7cf6fSBjoern A. Zeeb 	case SIOCSIFMEDIA:
8870bc7cf6fSBjoern A. Zeeb 	case SIOCGIFMEDIA:
8880bc7cf6fSBjoern A. Zeeb 		QL_DPRINT4((ha->pci_dev,
8890bc7cf6fSBjoern A. Zeeb 			"%s: SIOCSIFMEDIA/SIOCGIFMEDIA (0x%lx)\n",
8900bc7cf6fSBjoern A. Zeeb 			__func__, cmd));
8910bc7cf6fSBjoern A. Zeeb 		ret = ifmedia_ioctl(ifp, ifr, &ha->media, cmd);
8920bc7cf6fSBjoern A. Zeeb 		break;
8930bc7cf6fSBjoern A. Zeeb 
8940bc7cf6fSBjoern A. Zeeb 	case SIOCSIFCAP:
8950bc7cf6fSBjoern A. Zeeb 	{
8965b587352SJustin Hibbits 		int mask = ifr->ifr_reqcap ^ if_getcapenable(ifp);
8970bc7cf6fSBjoern A. Zeeb 
8980bc7cf6fSBjoern A. Zeeb 		QL_DPRINT4((ha->pci_dev, "%s: SIOCSIFCAP (0x%lx)\n",
8990bc7cf6fSBjoern A. Zeeb 			__func__, cmd));
9000bc7cf6fSBjoern A. Zeeb 
9010bc7cf6fSBjoern A. Zeeb 		if (mask & IFCAP_HWCSUM)
9025b587352SJustin Hibbits 			if_togglecapenable(ifp, IFCAP_HWCSUM);
9030bc7cf6fSBjoern A. Zeeb 		if (mask & IFCAP_TSO4)
9045b587352SJustin Hibbits 			if_togglecapenable(ifp, IFCAP_TSO4);
9050bc7cf6fSBjoern A. Zeeb 		if (mask & IFCAP_TSO6)
9065b587352SJustin Hibbits 			if_togglecapenable(ifp, IFCAP_TSO6);
9070bc7cf6fSBjoern A. Zeeb 		if (mask & IFCAP_VLAN_HWTAGGING)
9085b587352SJustin Hibbits 			if_togglecapenable(ifp, IFCAP_VLAN_HWTAGGING);
9090bc7cf6fSBjoern A. Zeeb 
9105b587352SJustin Hibbits 		if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING))
9110bc7cf6fSBjoern A. Zeeb 			qla_init(ha);
9120bc7cf6fSBjoern A. Zeeb 
9130bc7cf6fSBjoern A. Zeeb 		VLAN_CAPABILITIES(ifp);
9140bc7cf6fSBjoern A. Zeeb 		break;
9150bc7cf6fSBjoern A. Zeeb 	}
9160bc7cf6fSBjoern A. Zeeb 
9170bc7cf6fSBjoern A. Zeeb 	default:
9180bc7cf6fSBjoern A. Zeeb 		QL_DPRINT4((ha->pci_dev, "%s: default (0x%lx)\n",
9190bc7cf6fSBjoern A. Zeeb 			__func__, cmd));
9200bc7cf6fSBjoern A. Zeeb 		ret = ether_ioctl(ifp, cmd, data);
9210bc7cf6fSBjoern A. Zeeb 		break;
9220bc7cf6fSBjoern A. Zeeb 	}
9230bc7cf6fSBjoern A. Zeeb 
9240bc7cf6fSBjoern A. Zeeb 	return (ret);
9250bc7cf6fSBjoern A. Zeeb }
9260bc7cf6fSBjoern A. Zeeb 
9270bc7cf6fSBjoern A. Zeeb static int
qla_media_change(if_t ifp)9285b587352SJustin Hibbits qla_media_change(if_t ifp)
9290bc7cf6fSBjoern A. Zeeb {
9300bc7cf6fSBjoern A. Zeeb 	qla_host_t *ha;
9310bc7cf6fSBjoern A. Zeeb 	struct ifmedia *ifm;
9320bc7cf6fSBjoern A. Zeeb 	int ret = 0;
9330bc7cf6fSBjoern A. Zeeb 
9345b587352SJustin Hibbits 	ha = (qla_host_t *)if_getsoftc(ifp);
9350bc7cf6fSBjoern A. Zeeb 
9360bc7cf6fSBjoern A. Zeeb 	QL_DPRINT2((ha->pci_dev, "%s: enter\n", __func__));
9370bc7cf6fSBjoern A. Zeeb 
9380bc7cf6fSBjoern A. Zeeb 	ifm = &ha->media;
9390bc7cf6fSBjoern A. Zeeb 
9400bc7cf6fSBjoern A. Zeeb 	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
9410bc7cf6fSBjoern A. Zeeb 		ret = EINVAL;
9420bc7cf6fSBjoern A. Zeeb 
9430bc7cf6fSBjoern A. Zeeb 	QL_DPRINT2((ha->pci_dev, "%s: exit\n", __func__));
9440bc7cf6fSBjoern A. Zeeb 
9450bc7cf6fSBjoern A. Zeeb 	return (ret);
9460bc7cf6fSBjoern A. Zeeb }
9470bc7cf6fSBjoern A. Zeeb 
9480bc7cf6fSBjoern A. Zeeb static void
qla_media_status(if_t ifp,struct ifmediareq * ifmr)9495b587352SJustin Hibbits qla_media_status(if_t ifp, struct ifmediareq *ifmr)
9500bc7cf6fSBjoern A. Zeeb {
9510bc7cf6fSBjoern A. Zeeb 	qla_host_t *ha;
9520bc7cf6fSBjoern A. Zeeb 
9535b587352SJustin Hibbits 	ha = (qla_host_t *)if_getsoftc(ifp);
9540bc7cf6fSBjoern A. Zeeb 
9550bc7cf6fSBjoern A. Zeeb 	QL_DPRINT2((ha->pci_dev, "%s: enter\n", __func__));
9560bc7cf6fSBjoern A. Zeeb 
9570bc7cf6fSBjoern A. Zeeb 	ifmr->ifm_status = IFM_AVALID;
9580bc7cf6fSBjoern A. Zeeb 	ifmr->ifm_active = IFM_ETHER;
9590bc7cf6fSBjoern A. Zeeb 
9600bc7cf6fSBjoern A. Zeeb 	qla_update_link_state(ha);
9610bc7cf6fSBjoern A. Zeeb 	if (ha->hw.flags.link_up) {
9620bc7cf6fSBjoern A. Zeeb 		ifmr->ifm_status |= IFM_ACTIVE;
9630bc7cf6fSBjoern A. Zeeb 		ifmr->ifm_active |= (IFM_FDX | qla_get_optics(ha));
9640bc7cf6fSBjoern A. Zeeb 	}
9650bc7cf6fSBjoern A. Zeeb 
9660bc7cf6fSBjoern A. Zeeb 	QL_DPRINT2((ha->pci_dev, "%s: exit (%s)\n", __func__,\
9670bc7cf6fSBjoern A. Zeeb 		(ha->hw.flags.link_up ? "link_up" : "link_down")));
9680bc7cf6fSBjoern A. Zeeb 
9690bc7cf6fSBjoern A. Zeeb 	return;
9700bc7cf6fSBjoern A. Zeeb }
9710bc7cf6fSBjoern A. Zeeb 
9720bc7cf6fSBjoern A. Zeeb void
qla_start(if_t ifp)9735b587352SJustin Hibbits qla_start(if_t ifp)
9740bc7cf6fSBjoern A. Zeeb {
9750bc7cf6fSBjoern A. Zeeb 	struct mbuf    *m_head;
9765b587352SJustin Hibbits 	qla_host_t *ha = (qla_host_t *)if_getsoftc(ifp);
9770bc7cf6fSBjoern A. Zeeb 
9780bc7cf6fSBjoern A. Zeeb 	QL_DPRINT8((ha->pci_dev, "%s: enter\n", __func__));
9790bc7cf6fSBjoern A. Zeeb 
9800bc7cf6fSBjoern A. Zeeb 	if (!mtx_trylock(&ha->tx_lock)) {
9810bc7cf6fSBjoern A. Zeeb 		QL_DPRINT8((ha->pci_dev,
9820bc7cf6fSBjoern A. Zeeb 			"%s: mtx_trylock(&ha->tx_lock) failed\n", __func__));
9830bc7cf6fSBjoern A. Zeeb 		return;
9840bc7cf6fSBjoern A. Zeeb 	}
9850bc7cf6fSBjoern A. Zeeb 
9865b587352SJustin Hibbits 	if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
9870bc7cf6fSBjoern A. Zeeb 		IFF_DRV_RUNNING) {
9880bc7cf6fSBjoern A. Zeeb 		QL_DPRINT8((ha->pci_dev, "%s: !IFF_DRV_RUNNING\n", __func__));
9890bc7cf6fSBjoern A. Zeeb 		QLA_TX_UNLOCK(ha);
9900bc7cf6fSBjoern A. Zeeb 		return;
9910bc7cf6fSBjoern A. Zeeb 	}
9920bc7cf6fSBjoern A. Zeeb 
9930bc7cf6fSBjoern A. Zeeb 	if (!ha->watchdog_ticks)
9940bc7cf6fSBjoern A. Zeeb 		qla_update_link_state(ha);
9950bc7cf6fSBjoern A. Zeeb 
9960bc7cf6fSBjoern A. Zeeb 	if (!ha->hw.flags.link_up) {
9970bc7cf6fSBjoern A. Zeeb 		QL_DPRINT8((ha->pci_dev, "%s: link down\n", __func__));
9980bc7cf6fSBjoern A. Zeeb 		QLA_TX_UNLOCK(ha);
9990bc7cf6fSBjoern A. Zeeb 		return;
10000bc7cf6fSBjoern A. Zeeb 	}
10010bc7cf6fSBjoern A. Zeeb 
10025b587352SJustin Hibbits 	while (!if_sendq_empty(ifp)) {
10035b587352SJustin Hibbits 		m_head = if_dequeue(ifp);
10040bc7cf6fSBjoern A. Zeeb 
10050bc7cf6fSBjoern A. Zeeb 		if (m_head == NULL) {
10060bc7cf6fSBjoern A. Zeeb 			QL_DPRINT8((ha->pci_dev, "%s: m_head == NULL\n",
10070bc7cf6fSBjoern A. Zeeb 				__func__));
10080bc7cf6fSBjoern A. Zeeb 			break;
10090bc7cf6fSBjoern A. Zeeb 		}
10100bc7cf6fSBjoern A. Zeeb 
10110bc7cf6fSBjoern A. Zeeb 		if (qla_send(ha, &m_head)) {
10120bc7cf6fSBjoern A. Zeeb 			if (m_head == NULL)
10130bc7cf6fSBjoern A. Zeeb 				break;
10140bc7cf6fSBjoern A. Zeeb 			QL_DPRINT8((ha->pci_dev, "%s: PREPEND\n", __func__));
10155b587352SJustin Hibbits 			if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0);
10165b587352SJustin Hibbits 			if_sendq_prepend(ifp, m_head);
10170bc7cf6fSBjoern A. Zeeb 			break;
10180bc7cf6fSBjoern A. Zeeb 		}
10190bc7cf6fSBjoern A. Zeeb 		/* Send a copy of the frame to the BPF listener */
10200bc7cf6fSBjoern A. Zeeb 		ETHER_BPF_MTAP(ifp, m_head);
10210bc7cf6fSBjoern A. Zeeb 	}
10220bc7cf6fSBjoern A. Zeeb 	QLA_TX_UNLOCK(ha);
10230bc7cf6fSBjoern A. Zeeb 	QL_DPRINT8((ha->pci_dev, "%s: exit\n", __func__));
10240bc7cf6fSBjoern A. Zeeb 	return;
10250bc7cf6fSBjoern A. Zeeb }
10260bc7cf6fSBjoern A. Zeeb 
10270bc7cf6fSBjoern A. Zeeb static int
qla_send(qla_host_t * ha,struct mbuf ** m_headp)10280bc7cf6fSBjoern A. Zeeb qla_send(qla_host_t *ha, struct mbuf **m_headp)
10290bc7cf6fSBjoern A. Zeeb {
10300bc7cf6fSBjoern A. Zeeb 	bus_dma_segment_t	segs[QLA_MAX_SEGMENTS];
10310bc7cf6fSBjoern A. Zeeb 	bus_dmamap_t		map;
10320bc7cf6fSBjoern A. Zeeb 	int			nsegs;
10330bc7cf6fSBjoern A. Zeeb 	int			ret = -1;
10340bc7cf6fSBjoern A. Zeeb 	uint32_t		tx_idx;
10350bc7cf6fSBjoern A. Zeeb 	struct mbuf *m_head = *m_headp;
10360bc7cf6fSBjoern A. Zeeb 
10370bc7cf6fSBjoern A. Zeeb 	QL_DPRINT8((ha->pci_dev, "%s: enter\n", __func__));
10380bc7cf6fSBjoern A. Zeeb 
10390bc7cf6fSBjoern A. Zeeb 	if ((ret = bus_dmamap_create(ha->tx_tag, BUS_DMA_NOWAIT, &map))) {
10400bc7cf6fSBjoern A. Zeeb 		ha->err_tx_dmamap_create++;
10410bc7cf6fSBjoern A. Zeeb 		device_printf(ha->pci_dev,
10420bc7cf6fSBjoern A. Zeeb 			"%s: bus_dmamap_create failed[%d, %d]\n",
10430bc7cf6fSBjoern A. Zeeb 			__func__, ret, m_head->m_pkthdr.len);
10440bc7cf6fSBjoern A. Zeeb 		return (ret);
10450bc7cf6fSBjoern A. Zeeb 	}
10460bc7cf6fSBjoern A. Zeeb 
10470bc7cf6fSBjoern A. Zeeb 	ret = bus_dmamap_load_mbuf_sg(ha->tx_tag, map, m_head, segs, &nsegs,
10480bc7cf6fSBjoern A. Zeeb 			BUS_DMA_NOWAIT);
10490bc7cf6fSBjoern A. Zeeb 
1050b23deb27SDavid C Somayajulu 	if (ret == EFBIG) {
10510bc7cf6fSBjoern A. Zeeb 		struct mbuf *m;
10520bc7cf6fSBjoern A. Zeeb 
10530bc7cf6fSBjoern A. Zeeb 		QL_DPRINT8((ha->pci_dev, "%s: EFBIG [%d]\n", __func__,
10540bc7cf6fSBjoern A. Zeeb 			m_head->m_pkthdr.len));
10550bc7cf6fSBjoern A. Zeeb 
1056c6499eccSGleb Smirnoff 		m = m_defrag(m_head, M_NOWAIT);
10570bc7cf6fSBjoern A. Zeeb 		if (m == NULL) {
10580bc7cf6fSBjoern A. Zeeb 			ha->err_tx_defrag++;
10590bc7cf6fSBjoern A. Zeeb 			m_freem(m_head);
10600bc7cf6fSBjoern A. Zeeb 			*m_headp = NULL;
10610bc7cf6fSBjoern A. Zeeb 			device_printf(ha->pci_dev,
10620bc7cf6fSBjoern A. Zeeb 				"%s: m_defrag() = NULL [%d]\n",
10630bc7cf6fSBjoern A. Zeeb 				__func__, ret);
10640bc7cf6fSBjoern A. Zeeb 			return (ENOBUFS);
10650bc7cf6fSBjoern A. Zeeb 		}
10660bc7cf6fSBjoern A. Zeeb 		m_head = m;
10670bc7cf6fSBjoern A. Zeeb 
10680bc7cf6fSBjoern A. Zeeb 		if ((ret = bus_dmamap_load_mbuf_sg(ha->tx_tag, map, m_head,
10690bc7cf6fSBjoern A. Zeeb 					segs, &nsegs, BUS_DMA_NOWAIT))) {
10700bc7cf6fSBjoern A. Zeeb 			ha->err_tx_dmamap_load++;
10710bc7cf6fSBjoern A. Zeeb 
10720bc7cf6fSBjoern A. Zeeb 			device_printf(ha->pci_dev,
10730bc7cf6fSBjoern A. Zeeb 				"%s: bus_dmamap_load_mbuf_sg failed0[%d, %d]\n",
10740bc7cf6fSBjoern A. Zeeb 				__func__, ret, m_head->m_pkthdr.len);
10750bc7cf6fSBjoern A. Zeeb 
10760bc7cf6fSBjoern A. Zeeb 			bus_dmamap_destroy(ha->tx_tag, map);
10770bc7cf6fSBjoern A. Zeeb 			if (ret != ENOMEM) {
10780bc7cf6fSBjoern A. Zeeb 				m_freem(m_head);
10790bc7cf6fSBjoern A. Zeeb 				*m_headp = NULL;
10800bc7cf6fSBjoern A. Zeeb 			}
10810bc7cf6fSBjoern A. Zeeb 			return (ret);
10820bc7cf6fSBjoern A. Zeeb 		}
10830bc7cf6fSBjoern A. Zeeb 	} else if (ret) {
10840bc7cf6fSBjoern A. Zeeb 		ha->err_tx_dmamap_load++;
10850bc7cf6fSBjoern A. Zeeb 
10860bc7cf6fSBjoern A. Zeeb 		device_printf(ha->pci_dev,
10870bc7cf6fSBjoern A. Zeeb 			"%s: bus_dmamap_load_mbuf_sg failed1[%d, %d]\n",
10880bc7cf6fSBjoern A. Zeeb 			__func__, ret, m_head->m_pkthdr.len);
10890bc7cf6fSBjoern A. Zeeb 
10900bc7cf6fSBjoern A. Zeeb 		bus_dmamap_destroy(ha->tx_tag, map);
10910bc7cf6fSBjoern A. Zeeb 
10920bc7cf6fSBjoern A. Zeeb 		if (ret != ENOMEM) {
10930bc7cf6fSBjoern A. Zeeb 			m_freem(m_head);
10940bc7cf6fSBjoern A. Zeeb 			*m_headp = NULL;
10950bc7cf6fSBjoern A. Zeeb 		}
10960bc7cf6fSBjoern A. Zeeb 		return (ret);
10970bc7cf6fSBjoern A. Zeeb 	}
10980bc7cf6fSBjoern A. Zeeb 
10990bc7cf6fSBjoern A. Zeeb 	QL_ASSERT((nsegs != 0), ("qla_send: empty packet"));
11000bc7cf6fSBjoern A. Zeeb 
11010bc7cf6fSBjoern A. Zeeb 	bus_dmamap_sync(ha->tx_tag, map, BUS_DMASYNC_PREWRITE);
11020bc7cf6fSBjoern A. Zeeb 
11030bc7cf6fSBjoern A. Zeeb 	if (!(ret = qla_hw_send(ha, segs, nsegs, &tx_idx, m_head))) {
11040bc7cf6fSBjoern A. Zeeb 		ha->tx_buf[tx_idx].m_head = m_head;
11050bc7cf6fSBjoern A. Zeeb 		ha->tx_buf[tx_idx].map = map;
11060bc7cf6fSBjoern A. Zeeb 	} else {
11070bc7cf6fSBjoern A. Zeeb 		if (ret == EINVAL) {
11080bc7cf6fSBjoern A. Zeeb 			m_freem(m_head);
11090bc7cf6fSBjoern A. Zeeb 			*m_headp = NULL;
11100bc7cf6fSBjoern A. Zeeb 		}
11110bc7cf6fSBjoern A. Zeeb 	}
11120bc7cf6fSBjoern A. Zeeb 
11130bc7cf6fSBjoern A. Zeeb 	QL_DPRINT8((ha->pci_dev, "%s: exit\n", __func__));
11140bc7cf6fSBjoern A. Zeeb 	return (ret);
11150bc7cf6fSBjoern A. Zeeb }
11160bc7cf6fSBjoern A. Zeeb 
11170bc7cf6fSBjoern A. Zeeb static void
qla_stop(qla_host_t * ha)11180bc7cf6fSBjoern A. Zeeb qla_stop(qla_host_t *ha)
11190bc7cf6fSBjoern A. Zeeb {
11205b587352SJustin Hibbits 	if_t ifp = ha->ifp;
11210bc7cf6fSBjoern A. Zeeb 
11220bc7cf6fSBjoern A. Zeeb 	ha->flags.qla_watchdog_pause = 1;
11230bc7cf6fSBjoern A. Zeeb 	qla_mdelay(__func__, 100);
11240bc7cf6fSBjoern A. Zeeb 
11250bc7cf6fSBjoern A. Zeeb 	ha->flags.stop_rcv = 1;
11260bc7cf6fSBjoern A. Zeeb 	qla_hw_stop_rcv(ha);
11270bc7cf6fSBjoern A. Zeeb 
11280bc7cf6fSBjoern A. Zeeb 	qla_del_hw_if(ha);
11290bc7cf6fSBjoern A. Zeeb 
11300bc7cf6fSBjoern A. Zeeb 	qla_free_lro(ha);
11310bc7cf6fSBjoern A. Zeeb 
11320bc7cf6fSBjoern A. Zeeb 	qla_free_xmt_bufs(ha);
11330bc7cf6fSBjoern A. Zeeb 	qla_free_rcv_bufs(ha);
11340bc7cf6fSBjoern A. Zeeb 
11355b587352SJustin Hibbits 	if_setdrvflagbits(ifp, 0, (IFF_DRV_OACTIVE | IFF_DRV_RUNNING));
11360bc7cf6fSBjoern A. Zeeb 
11370bc7cf6fSBjoern A. Zeeb 	return;
11380bc7cf6fSBjoern A. Zeeb }
11390bc7cf6fSBjoern A. Zeeb 
11400bc7cf6fSBjoern A. Zeeb /*
11410bc7cf6fSBjoern A. Zeeb  * Buffer Management Functions for Transmit and Receive Rings
11420bc7cf6fSBjoern A. Zeeb  */
11430bc7cf6fSBjoern A. Zeeb static int
qla_alloc_xmt_bufs(qla_host_t * ha)11440bc7cf6fSBjoern A. Zeeb qla_alloc_xmt_bufs(qla_host_t *ha)
11450bc7cf6fSBjoern A. Zeeb {
11460bc7cf6fSBjoern A. Zeeb 	if (bus_dma_tag_create(NULL,    /* parent */
11470bc7cf6fSBjoern A. Zeeb 		1, 0,    /* alignment, bounds */
11480bc7cf6fSBjoern A. Zeeb 		BUS_SPACE_MAXADDR,       /* lowaddr */
11490bc7cf6fSBjoern A. Zeeb 		BUS_SPACE_MAXADDR,       /* highaddr */
11500bc7cf6fSBjoern A. Zeeb 		NULL, NULL,      /* filter, filterarg */
11510bc7cf6fSBjoern A. Zeeb 		QLA_MAX_TSO_FRAME_SIZE,     /* maxsize */
11520bc7cf6fSBjoern A. Zeeb 		QLA_MAX_SEGMENTS,        /* nsegments */
11530bc7cf6fSBjoern A. Zeeb 		PAGE_SIZE,        /* maxsegsize */
11540bc7cf6fSBjoern A. Zeeb 		BUS_DMA_ALLOCNOW,        /* flags */
11550bc7cf6fSBjoern A. Zeeb 		NULL,    /* lockfunc */
11560bc7cf6fSBjoern A. Zeeb 		NULL,    /* lockfuncarg */
11570bc7cf6fSBjoern A. Zeeb 		&ha->tx_tag)) {
11580bc7cf6fSBjoern A. Zeeb 		device_printf(ha->pci_dev, "%s: tx_tag alloc failed\n",
11590bc7cf6fSBjoern A. Zeeb 			__func__);
11600bc7cf6fSBjoern A. Zeeb 		return (ENOMEM);
11610bc7cf6fSBjoern A. Zeeb 	}
11620bc7cf6fSBjoern A. Zeeb 	bzero((void *)ha->tx_buf, (sizeof(qla_tx_buf_t) * NUM_TX_DESCRIPTORS));
11630bc7cf6fSBjoern A. Zeeb 
11640bc7cf6fSBjoern A. Zeeb 	return 0;
11650bc7cf6fSBjoern A. Zeeb }
11660bc7cf6fSBjoern A. Zeeb 
11670bc7cf6fSBjoern A. Zeeb /*
11680bc7cf6fSBjoern A. Zeeb  * Release mbuf after it sent on the wire
11690bc7cf6fSBjoern A. Zeeb  */
11700bc7cf6fSBjoern A. Zeeb static void
qla_clear_tx_buf(qla_host_t * ha,qla_tx_buf_t * txb)11710bc7cf6fSBjoern A. Zeeb qla_clear_tx_buf(qla_host_t *ha, qla_tx_buf_t *txb)
11720bc7cf6fSBjoern A. Zeeb {
11730bc7cf6fSBjoern A. Zeeb 	QL_DPRINT2((ha->pci_dev, "%s: enter\n", __func__));
11740bc7cf6fSBjoern A. Zeeb 
11750bc7cf6fSBjoern A. Zeeb 	if (txb->m_head) {
11760bc7cf6fSBjoern A. Zeeb 		bus_dmamap_unload(ha->tx_tag, txb->map);
11770bc7cf6fSBjoern A. Zeeb 		bus_dmamap_destroy(ha->tx_tag, txb->map);
11780bc7cf6fSBjoern A. Zeeb 
11790bc7cf6fSBjoern A. Zeeb 		m_freem(txb->m_head);
11800bc7cf6fSBjoern A. Zeeb 		txb->m_head = NULL;
11810bc7cf6fSBjoern A. Zeeb 	}
11820bc7cf6fSBjoern A. Zeeb 
11830bc7cf6fSBjoern A. Zeeb 	QL_DPRINT2((ha->pci_dev, "%s: exit\n", __func__));
11840bc7cf6fSBjoern A. Zeeb }
11850bc7cf6fSBjoern A. Zeeb 
11860bc7cf6fSBjoern A. Zeeb static void
qla_free_xmt_bufs(qla_host_t * ha)11870bc7cf6fSBjoern A. Zeeb qla_free_xmt_bufs(qla_host_t *ha)
11880bc7cf6fSBjoern A. Zeeb {
11890bc7cf6fSBjoern A. Zeeb 	int		i;
11900bc7cf6fSBjoern A. Zeeb 
11910bc7cf6fSBjoern A. Zeeb 	for (i = 0; i < NUM_TX_DESCRIPTORS; i++)
11920bc7cf6fSBjoern A. Zeeb 		qla_clear_tx_buf(ha, &ha->tx_buf[i]);
11930bc7cf6fSBjoern A. Zeeb 
11940bc7cf6fSBjoern A. Zeeb 	if (ha->tx_tag != NULL) {
11950bc7cf6fSBjoern A. Zeeb 		bus_dma_tag_destroy(ha->tx_tag);
11960bc7cf6fSBjoern A. Zeeb 		ha->tx_tag = NULL;
11970bc7cf6fSBjoern A. Zeeb 	}
11980bc7cf6fSBjoern A. Zeeb 	bzero((void *)ha->tx_buf, (sizeof(qla_tx_buf_t) * NUM_TX_DESCRIPTORS));
11990bc7cf6fSBjoern A. Zeeb 
12000bc7cf6fSBjoern A. Zeeb 	return;
12010bc7cf6fSBjoern A. Zeeb }
12020bc7cf6fSBjoern A. Zeeb 
12030bc7cf6fSBjoern A. Zeeb static int
qla_alloc_rcv_bufs(qla_host_t * ha)12040bc7cf6fSBjoern A. Zeeb qla_alloc_rcv_bufs(qla_host_t *ha)
12050bc7cf6fSBjoern A. Zeeb {
12060bc7cf6fSBjoern A. Zeeb 	int		i, j, ret = 0;
12070bc7cf6fSBjoern A. Zeeb 	qla_rx_buf_t	*rxb;
12080bc7cf6fSBjoern A. Zeeb 
12090bc7cf6fSBjoern A. Zeeb 	if (bus_dma_tag_create(NULL,    /* parent */
12100bc7cf6fSBjoern A. Zeeb 			1, 0,    /* alignment, bounds */
12110bc7cf6fSBjoern A. Zeeb 			BUS_SPACE_MAXADDR,       /* lowaddr */
12120bc7cf6fSBjoern A. Zeeb 			BUS_SPACE_MAXADDR,       /* highaddr */
12130bc7cf6fSBjoern A. Zeeb 			NULL, NULL,      /* filter, filterarg */
12140bc7cf6fSBjoern A. Zeeb 			MJUM9BYTES,     /* maxsize */
12150bc7cf6fSBjoern A. Zeeb 			1,        /* nsegments */
12160bc7cf6fSBjoern A. Zeeb 			MJUM9BYTES,        /* maxsegsize */
12170bc7cf6fSBjoern A. Zeeb 			BUS_DMA_ALLOCNOW,        /* flags */
12180bc7cf6fSBjoern A. Zeeb 			NULL,    /* lockfunc */
12190bc7cf6fSBjoern A. Zeeb 			NULL,    /* lockfuncarg */
12200bc7cf6fSBjoern A. Zeeb 			&ha->rx_tag)) {
12210bc7cf6fSBjoern A. Zeeb 		device_printf(ha->pci_dev, "%s: rx_tag alloc failed\n",
12220bc7cf6fSBjoern A. Zeeb 			__func__);
12230bc7cf6fSBjoern A. Zeeb 
12240bc7cf6fSBjoern A. Zeeb 		return (ENOMEM);
12250bc7cf6fSBjoern A. Zeeb 	}
12260bc7cf6fSBjoern A. Zeeb 
12270bc7cf6fSBjoern A. Zeeb 	bzero((void *)ha->rx_buf, (sizeof(qla_rx_buf_t) * NUM_RX_DESCRIPTORS));
12280bc7cf6fSBjoern A. Zeeb 	bzero((void *)ha->rx_jbuf,
12290bc7cf6fSBjoern A. Zeeb 		(sizeof(qla_rx_buf_t) * NUM_RX_JUMBO_DESCRIPTORS));
12300bc7cf6fSBjoern A. Zeeb 
12310bc7cf6fSBjoern A. Zeeb 	for (i = 0; i < MAX_SDS_RINGS; i++) {
12320bc7cf6fSBjoern A. Zeeb 		ha->hw.sds[i].sdsr_next = 0;
12330bc7cf6fSBjoern A. Zeeb 		ha->hw.sds[i].rxb_free = NULL;
12340bc7cf6fSBjoern A. Zeeb 		ha->hw.sds[i].rx_free = 0;
12350bc7cf6fSBjoern A. Zeeb 		ha->hw.sds[i].rxjb_free = NULL;
12360bc7cf6fSBjoern A. Zeeb 		ha->hw.sds[i].rxj_free = 0;
12370bc7cf6fSBjoern A. Zeeb 	}
12380bc7cf6fSBjoern A. Zeeb 
12390bc7cf6fSBjoern A. Zeeb 	for (i = 0; i < NUM_RX_DESCRIPTORS; i++) {
12400bc7cf6fSBjoern A. Zeeb 		rxb = &ha->rx_buf[i];
12410bc7cf6fSBjoern A. Zeeb 
12420bc7cf6fSBjoern A. Zeeb 		ret = bus_dmamap_create(ha->rx_tag, BUS_DMA_NOWAIT, &rxb->map);
12430bc7cf6fSBjoern A. Zeeb 
12440bc7cf6fSBjoern A. Zeeb 		if (ret) {
12450bc7cf6fSBjoern A. Zeeb 			device_printf(ha->pci_dev,
12460bc7cf6fSBjoern A. Zeeb 				"%s: dmamap[%d] failed\n", __func__, i);
12470bc7cf6fSBjoern A. Zeeb 
12480bc7cf6fSBjoern A. Zeeb 			for (j = 0; j < i; j++) {
12490bc7cf6fSBjoern A. Zeeb 				bus_dmamap_destroy(ha->rx_tag,
12500bc7cf6fSBjoern A. Zeeb 					ha->rx_buf[j].map);
12510bc7cf6fSBjoern A. Zeeb 			}
12520bc7cf6fSBjoern A. Zeeb 			goto qla_alloc_rcv_bufs_failed;
12530bc7cf6fSBjoern A. Zeeb 		}
12540bc7cf6fSBjoern A. Zeeb 	}
12550bc7cf6fSBjoern A. Zeeb 
12560bc7cf6fSBjoern A. Zeeb 	qla_init_hw_rcv_descriptors(ha, RDS_RING_INDEX_NORMAL);
12570bc7cf6fSBjoern A. Zeeb 
12580bc7cf6fSBjoern A. Zeeb 	for (i = 0; i < NUM_RX_DESCRIPTORS; i++) {
12590bc7cf6fSBjoern A. Zeeb 		rxb = &ha->rx_buf[i];
12600bc7cf6fSBjoern A. Zeeb 		rxb->handle = i;
12610bc7cf6fSBjoern A. Zeeb 		if (!(ret = qla_get_mbuf(ha, rxb, NULL, 0))) {
12620bc7cf6fSBjoern A. Zeeb 			/*
12630bc7cf6fSBjoern A. Zeeb 		 	 * set the physical address in the corresponding
12640bc7cf6fSBjoern A. Zeeb 			 * descriptor entry in the receive ring/queue for the
12650bc7cf6fSBjoern A. Zeeb 			 * hba
12660bc7cf6fSBjoern A. Zeeb 			 */
12670bc7cf6fSBjoern A. Zeeb 			qla_set_hw_rcv_desc(ha, RDS_RING_INDEX_NORMAL, i,
12680bc7cf6fSBjoern A. Zeeb 				rxb->handle, rxb->paddr,
12690bc7cf6fSBjoern A. Zeeb 				(rxb->m_head)->m_pkthdr.len);
12700bc7cf6fSBjoern A. Zeeb 		} else {
12710bc7cf6fSBjoern A. Zeeb 			device_printf(ha->pci_dev,
12720bc7cf6fSBjoern A. Zeeb 				"%s: qla_get_mbuf [standard(%d)] failed\n",
12730bc7cf6fSBjoern A. Zeeb 				__func__, i);
12740bc7cf6fSBjoern A. Zeeb 			bus_dmamap_destroy(ha->rx_tag, rxb->map);
12750bc7cf6fSBjoern A. Zeeb 			goto qla_alloc_rcv_bufs_failed;
12760bc7cf6fSBjoern A. Zeeb 		}
12770bc7cf6fSBjoern A. Zeeb 	}
12780bc7cf6fSBjoern A. Zeeb 
12790bc7cf6fSBjoern A. Zeeb 	for (i = 0; i < NUM_RX_JUMBO_DESCRIPTORS; i++) {
12800bc7cf6fSBjoern A. Zeeb 		rxb = &ha->rx_jbuf[i];
12810bc7cf6fSBjoern A. Zeeb 
12820bc7cf6fSBjoern A. Zeeb 		ret = bus_dmamap_create(ha->rx_tag, BUS_DMA_NOWAIT, &rxb->map);
12830bc7cf6fSBjoern A. Zeeb 
12840bc7cf6fSBjoern A. Zeeb 		if (ret) {
12850bc7cf6fSBjoern A. Zeeb 			device_printf(ha->pci_dev,
12860bc7cf6fSBjoern A. Zeeb 				"%s: dmamap[%d] failed\n", __func__, i);
12870bc7cf6fSBjoern A. Zeeb 
12880bc7cf6fSBjoern A. Zeeb 			for (j = 0; j < i; j++) {
12890bc7cf6fSBjoern A. Zeeb 				bus_dmamap_destroy(ha->rx_tag,
12900bc7cf6fSBjoern A. Zeeb 					ha->rx_jbuf[j].map);
12910bc7cf6fSBjoern A. Zeeb 			}
12920bc7cf6fSBjoern A. Zeeb 			goto qla_alloc_rcv_bufs_failed;
12930bc7cf6fSBjoern A. Zeeb 		}
12940bc7cf6fSBjoern A. Zeeb 	}
12950bc7cf6fSBjoern A. Zeeb 
12960bc7cf6fSBjoern A. Zeeb 	qla_init_hw_rcv_descriptors(ha, RDS_RING_INDEX_JUMBO);
12970bc7cf6fSBjoern A. Zeeb 
12980bc7cf6fSBjoern A. Zeeb 	for (i = 0; i < NUM_RX_JUMBO_DESCRIPTORS; i++) {
12990bc7cf6fSBjoern A. Zeeb 		rxb = &ha->rx_jbuf[i];
13000bc7cf6fSBjoern A. Zeeb 		rxb->handle = i;
13010bc7cf6fSBjoern A. Zeeb 		if (!(ret = qla_get_mbuf(ha, rxb, NULL, 1))) {
13020bc7cf6fSBjoern A. Zeeb 			/*
13030bc7cf6fSBjoern A. Zeeb 		 	 * set the physical address in the corresponding
13040bc7cf6fSBjoern A. Zeeb 			 * descriptor entry in the receive ring/queue for the
13050bc7cf6fSBjoern A. Zeeb 			 * hba
13060bc7cf6fSBjoern A. Zeeb 			 */
13070bc7cf6fSBjoern A. Zeeb 			qla_set_hw_rcv_desc(ha, RDS_RING_INDEX_JUMBO, i,
13080bc7cf6fSBjoern A. Zeeb 				rxb->handle, rxb->paddr,
13090bc7cf6fSBjoern A. Zeeb 				(rxb->m_head)->m_pkthdr.len);
13100bc7cf6fSBjoern A. Zeeb 		} else {
13110bc7cf6fSBjoern A. Zeeb 			device_printf(ha->pci_dev,
13120bc7cf6fSBjoern A. Zeeb 				"%s: qla_get_mbuf [jumbo(%d)] failed\n",
13130bc7cf6fSBjoern A. Zeeb 				__func__, i);
13140bc7cf6fSBjoern A. Zeeb 			bus_dmamap_destroy(ha->rx_tag, rxb->map);
13150bc7cf6fSBjoern A. Zeeb 			goto qla_alloc_rcv_bufs_failed;
13160bc7cf6fSBjoern A. Zeeb 		}
13170bc7cf6fSBjoern A. Zeeb 	}
13180bc7cf6fSBjoern A. Zeeb 
13190bc7cf6fSBjoern A. Zeeb 	return (0);
13200bc7cf6fSBjoern A. Zeeb 
13210bc7cf6fSBjoern A. Zeeb qla_alloc_rcv_bufs_failed:
13220bc7cf6fSBjoern A. Zeeb 	qla_free_rcv_bufs(ha);
13230bc7cf6fSBjoern A. Zeeb 	return (ret);
13240bc7cf6fSBjoern A. Zeeb }
13250bc7cf6fSBjoern A. Zeeb 
13260bc7cf6fSBjoern A. Zeeb static void
qla_free_rcv_bufs(qla_host_t * ha)13270bc7cf6fSBjoern A. Zeeb qla_free_rcv_bufs(qla_host_t *ha)
13280bc7cf6fSBjoern A. Zeeb {
13290bc7cf6fSBjoern A. Zeeb 	int		i;
13300bc7cf6fSBjoern A. Zeeb 	qla_rx_buf_t	*rxb;
13310bc7cf6fSBjoern A. Zeeb 
13320bc7cf6fSBjoern A. Zeeb 	for (i = 0; i < NUM_RX_DESCRIPTORS; i++) {
13330bc7cf6fSBjoern A. Zeeb 		rxb = &ha->rx_buf[i];
13340bc7cf6fSBjoern A. Zeeb 		if (rxb->m_head != NULL) {
13350bc7cf6fSBjoern A. Zeeb 			bus_dmamap_unload(ha->rx_tag, rxb->map);
13360bc7cf6fSBjoern A. Zeeb 			bus_dmamap_destroy(ha->rx_tag, rxb->map);
13370bc7cf6fSBjoern A. Zeeb 			m_freem(rxb->m_head);
13380bc7cf6fSBjoern A. Zeeb 			rxb->m_head = NULL;
13390bc7cf6fSBjoern A. Zeeb 		}
13400bc7cf6fSBjoern A. Zeeb 	}
13410bc7cf6fSBjoern A. Zeeb 
13420bc7cf6fSBjoern A. Zeeb 	for (i = 0; i < NUM_RX_JUMBO_DESCRIPTORS; i++) {
13430bc7cf6fSBjoern A. Zeeb 		rxb = &ha->rx_jbuf[i];
13440bc7cf6fSBjoern A. Zeeb 		if (rxb->m_head != NULL) {
13450bc7cf6fSBjoern A. Zeeb 			bus_dmamap_unload(ha->rx_tag, rxb->map);
13460bc7cf6fSBjoern A. Zeeb 			bus_dmamap_destroy(ha->rx_tag, rxb->map);
13470bc7cf6fSBjoern A. Zeeb 			m_freem(rxb->m_head);
13480bc7cf6fSBjoern A. Zeeb 			rxb->m_head = NULL;
13490bc7cf6fSBjoern A. Zeeb 		}
13500bc7cf6fSBjoern A. Zeeb 	}
13510bc7cf6fSBjoern A. Zeeb 
13520bc7cf6fSBjoern A. Zeeb 	if (ha->rx_tag != NULL) {
13530bc7cf6fSBjoern A. Zeeb 		bus_dma_tag_destroy(ha->rx_tag);
13540bc7cf6fSBjoern A. Zeeb 		ha->rx_tag = NULL;
13550bc7cf6fSBjoern A. Zeeb 	}
13560bc7cf6fSBjoern A. Zeeb 
13570bc7cf6fSBjoern A. Zeeb 	bzero((void *)ha->rx_buf, (sizeof(qla_rx_buf_t) * NUM_RX_DESCRIPTORS));
13580bc7cf6fSBjoern A. Zeeb 	bzero((void *)ha->rx_jbuf,
13590bc7cf6fSBjoern A. Zeeb 		(sizeof(qla_rx_buf_t) * NUM_RX_JUMBO_DESCRIPTORS));
13600bc7cf6fSBjoern A. Zeeb 
13610bc7cf6fSBjoern A. Zeeb 	for (i = 0; i < MAX_SDS_RINGS; i++) {
13620bc7cf6fSBjoern A. Zeeb 		ha->hw.sds[i].sdsr_next = 0;
13630bc7cf6fSBjoern A. Zeeb 		ha->hw.sds[i].rxb_free = NULL;
13640bc7cf6fSBjoern A. Zeeb 		ha->hw.sds[i].rx_free = 0;
13650bc7cf6fSBjoern A. Zeeb 		ha->hw.sds[i].rxjb_free = NULL;
13660bc7cf6fSBjoern A. Zeeb 		ha->hw.sds[i].rxj_free = 0;
13670bc7cf6fSBjoern A. Zeeb 	}
13680bc7cf6fSBjoern A. Zeeb 
13690bc7cf6fSBjoern A. Zeeb 	return;
13700bc7cf6fSBjoern A. Zeeb }
13710bc7cf6fSBjoern A. Zeeb 
13720bc7cf6fSBjoern A. Zeeb int
qla_get_mbuf(qla_host_t * ha,qla_rx_buf_t * rxb,struct mbuf * nmp,uint32_t jumbo)13730bc7cf6fSBjoern A. Zeeb qla_get_mbuf(qla_host_t *ha, qla_rx_buf_t *rxb, struct mbuf *nmp,
13740bc7cf6fSBjoern A. Zeeb 	uint32_t jumbo)
13750bc7cf6fSBjoern A. Zeeb {
13763e85b721SEd Maste 	struct mbuf *mp = nmp;
13770bc7cf6fSBjoern A. Zeeb 	int             ret = 0;
13780bc7cf6fSBjoern A. Zeeb 	uint32_t	offset;
13790bc7cf6fSBjoern A. Zeeb 
13800bc7cf6fSBjoern A. Zeeb 	QL_DPRINT2((ha->pci_dev, "%s: jumbo(0x%x) enter\n", __func__, jumbo));
13810bc7cf6fSBjoern A. Zeeb 
13820bc7cf6fSBjoern A. Zeeb 	if (mp == NULL) {
13830bc7cf6fSBjoern A. Zeeb 		if (!jumbo) {
1384c6499eccSGleb Smirnoff 			mp = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
13850bc7cf6fSBjoern A. Zeeb 
13860bc7cf6fSBjoern A. Zeeb 			if (mp == NULL) {
13870bc7cf6fSBjoern A. Zeeb 				ha->err_m_getcl++;
13880bc7cf6fSBjoern A. Zeeb 				ret = ENOBUFS;
13890bc7cf6fSBjoern A. Zeeb 				device_printf(ha->pci_dev,
13900bc7cf6fSBjoern A. Zeeb 					"%s: m_getcl failed\n", __func__);
13910bc7cf6fSBjoern A. Zeeb 				goto exit_qla_get_mbuf;
13920bc7cf6fSBjoern A. Zeeb 			}
13930bc7cf6fSBjoern A. Zeeb 			mp->m_len = mp->m_pkthdr.len = MCLBYTES;
13940bc7cf6fSBjoern A. Zeeb 		} else {
1395c6499eccSGleb Smirnoff 			mp = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR,
13960bc7cf6fSBjoern A. Zeeb 				MJUM9BYTES);
13970bc7cf6fSBjoern A. Zeeb 			if (mp == NULL) {
13980bc7cf6fSBjoern A. Zeeb 				ha->err_m_getjcl++;
13990bc7cf6fSBjoern A. Zeeb 				ret = ENOBUFS;
14000bc7cf6fSBjoern A. Zeeb 				device_printf(ha->pci_dev,
14010bc7cf6fSBjoern A. Zeeb 					"%s: m_getjcl failed\n", __func__);
14020bc7cf6fSBjoern A. Zeeb 				goto exit_qla_get_mbuf;
14030bc7cf6fSBjoern A. Zeeb 			}
14040bc7cf6fSBjoern A. Zeeb 			mp->m_len = mp->m_pkthdr.len = MJUM9BYTES;
14050bc7cf6fSBjoern A. Zeeb 		}
14060bc7cf6fSBjoern A. Zeeb 	} else {
14070bc7cf6fSBjoern A. Zeeb 		if (!jumbo)
14080bc7cf6fSBjoern A. Zeeb 			mp->m_len = mp->m_pkthdr.len = MCLBYTES;
14090bc7cf6fSBjoern A. Zeeb 		else
14100bc7cf6fSBjoern A. Zeeb 			mp->m_len = mp->m_pkthdr.len = MJUM9BYTES;
14110bc7cf6fSBjoern A. Zeeb 
14120bc7cf6fSBjoern A. Zeeb 		mp->m_data = mp->m_ext.ext_buf;
14130bc7cf6fSBjoern A. Zeeb 		mp->m_next = NULL;
14140bc7cf6fSBjoern A. Zeeb 	}
14150bc7cf6fSBjoern A. Zeeb 
14160bc7cf6fSBjoern A. Zeeb 	offset = (uint32_t)((unsigned long long)mp->m_data & 0x7ULL);
14170bc7cf6fSBjoern A. Zeeb 	if (offset) {
14180bc7cf6fSBjoern A. Zeeb 		offset = 8 - offset;
14190bc7cf6fSBjoern A. Zeeb 		m_adj(mp, offset);
14200bc7cf6fSBjoern A. Zeeb 	}
14210bc7cf6fSBjoern A. Zeeb 
14220bc7cf6fSBjoern A. Zeeb 	/*
14230bc7cf6fSBjoern A. Zeeb 	 * Using memory from the mbuf cluster pool, invoke the bus_dma
14240bc7cf6fSBjoern A. Zeeb 	 * machinery to arrange the memory mapping.
14250bc7cf6fSBjoern A. Zeeb 	 */
14260bc7cf6fSBjoern A. Zeeb 	ret = bus_dmamap_load(ha->rx_tag, rxb->map,
14270bc7cf6fSBjoern A. Zeeb 				mtod(mp, void *), mp->m_len,
14280bc7cf6fSBjoern A. Zeeb 				qla_dmamap_callback, &rxb->paddr,
14290bc7cf6fSBjoern A. Zeeb 				BUS_DMA_NOWAIT);
14300bc7cf6fSBjoern A. Zeeb 	if (ret || !rxb->paddr) {
14310bc7cf6fSBjoern A. Zeeb 		m_free(mp);
14320bc7cf6fSBjoern A. Zeeb 		rxb->m_head = NULL;
14330bc7cf6fSBjoern A. Zeeb 		device_printf(ha->pci_dev,
14340bc7cf6fSBjoern A. Zeeb 			"%s: bus_dmamap_load failed\n", __func__);
14350bc7cf6fSBjoern A. Zeeb                 ret = -1;
14360bc7cf6fSBjoern A. Zeeb 		goto exit_qla_get_mbuf;
14370bc7cf6fSBjoern A. Zeeb 	}
14380bc7cf6fSBjoern A. Zeeb 	rxb->m_head = mp;
14390bc7cf6fSBjoern A. Zeeb 	bus_dmamap_sync(ha->rx_tag, rxb->map, BUS_DMASYNC_PREREAD);
14400bc7cf6fSBjoern A. Zeeb 
14410bc7cf6fSBjoern A. Zeeb exit_qla_get_mbuf:
14420bc7cf6fSBjoern A. Zeeb 	QL_DPRINT2((ha->pci_dev, "%s: exit ret = 0x%08x\n", __func__, ret));
14430bc7cf6fSBjoern A. Zeeb 	return (ret);
14440bc7cf6fSBjoern A. Zeeb }
14450bc7cf6fSBjoern A. Zeeb 
14460bc7cf6fSBjoern A. Zeeb static void
qla_tx_done(void * context,int pending)14470bc7cf6fSBjoern A. Zeeb qla_tx_done(void *context, int pending)
14480bc7cf6fSBjoern A. Zeeb {
14490bc7cf6fSBjoern A. Zeeb 	qla_host_t *ha = context;
14500bc7cf6fSBjoern A. Zeeb 
14510bc7cf6fSBjoern A. Zeeb 	qla_hw_tx_done(ha);
14520bc7cf6fSBjoern A. Zeeb 	qla_start(ha->ifp);
14530bc7cf6fSBjoern A. Zeeb }
1454