xref: /freebsd/sys/dev/qlxge/qls_os.c (revision aa3860851b9f6a6002d135b1cac7736e0995eedc)
1718cf2ccSPedro F. Giffuni /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni  *
4711bcba0SDavid C Somayajulu  * Copyright (c) 2013-2014 Qlogic Corporation
5711bcba0SDavid C Somayajulu  * All rights reserved.
6711bcba0SDavid C Somayajulu  *
7711bcba0SDavid C Somayajulu  *  Redistribution and use in source and binary forms, with or without
8711bcba0SDavid C Somayajulu  *  modification, are permitted provided that the following conditions
9711bcba0SDavid C Somayajulu  *  are met:
10711bcba0SDavid C Somayajulu  *
11711bcba0SDavid C Somayajulu  *  1. Redistributions of source code must retain the above copyright
12711bcba0SDavid C Somayajulu  *     notice, this list of conditions and the following disclaimer.
13711bcba0SDavid C Somayajulu  *  2. Redistributions in binary form must reproduce the above copyright
14711bcba0SDavid C Somayajulu  *     notice, this list of conditions and the following disclaimer in the
15711bcba0SDavid C Somayajulu  *     documentation and/or other materials provided with the distribution.
16711bcba0SDavid C Somayajulu  *
17711bcba0SDavid C Somayajulu  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18711bcba0SDavid C Somayajulu  *  and ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19711bcba0SDavid C Somayajulu  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20711bcba0SDavid C Somayajulu  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21711bcba0SDavid C Somayajulu  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22711bcba0SDavid C Somayajulu  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23711bcba0SDavid C Somayajulu  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24711bcba0SDavid C Somayajulu  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25711bcba0SDavid C Somayajulu  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26711bcba0SDavid C Somayajulu  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27711bcba0SDavid C Somayajulu  *  POSSIBILITY OF SUCH DAMAGE.
28711bcba0SDavid C Somayajulu  */
29711bcba0SDavid C Somayajulu 
30711bcba0SDavid C Somayajulu /*
31711bcba0SDavid C Somayajulu  * File: qls_os.c
32711bcba0SDavid C Somayajulu  * Author : David C Somayajulu, Qlogic Corporation, Aliso Viejo, CA 92656.
33711bcba0SDavid C Somayajulu  */
34711bcba0SDavid C Somayajulu 
35711bcba0SDavid C Somayajulu #include <sys/cdefs.h>
36711bcba0SDavid C Somayajulu #include "qls_os.h"
37711bcba0SDavid C Somayajulu #include "qls_hw.h"
38711bcba0SDavid C Somayajulu #include "qls_def.h"
39711bcba0SDavid C Somayajulu #include "qls_inline.h"
40711bcba0SDavid C Somayajulu #include "qls_ver.h"
41711bcba0SDavid C Somayajulu #include "qls_glbl.h"
42711bcba0SDavid C Somayajulu #include "qls_dbg.h"
43711bcba0SDavid C Somayajulu #include <sys/smp.h>
44711bcba0SDavid C Somayajulu 
45711bcba0SDavid C Somayajulu /*
46711bcba0SDavid C Somayajulu  * Some PCI Configuration Space Related Defines
47711bcba0SDavid C Somayajulu  */
48711bcba0SDavid C Somayajulu 
49711bcba0SDavid C Somayajulu #ifndef PCI_VENDOR_QLOGIC
50711bcba0SDavid C Somayajulu #define PCI_VENDOR_QLOGIC	0x1077
51711bcba0SDavid C Somayajulu #endif
52711bcba0SDavid C Somayajulu 
53711bcba0SDavid C Somayajulu #ifndef PCI_DEVICE_QLOGIC_8000
54711bcba0SDavid C Somayajulu #define PCI_DEVICE_QLOGIC_8000	0x8000
55711bcba0SDavid C Somayajulu #endif
56711bcba0SDavid C Somayajulu 
57711bcba0SDavid C Somayajulu #define PCI_QLOGIC_DEV8000 \
58711bcba0SDavid C Somayajulu 	((PCI_DEVICE_QLOGIC_8000 << 16) | PCI_VENDOR_QLOGIC)
59711bcba0SDavid C Somayajulu 
60711bcba0SDavid C Somayajulu /*
61711bcba0SDavid C Somayajulu  * static functions
62711bcba0SDavid C Somayajulu  */
63711bcba0SDavid C Somayajulu static int qls_alloc_parent_dma_tag(qla_host_t *ha);
64711bcba0SDavid C Somayajulu static void qls_free_parent_dma_tag(qla_host_t *ha);
65711bcba0SDavid C Somayajulu 
66711bcba0SDavid C Somayajulu static void qls_flush_xmt_bufs(qla_host_t *ha);
67711bcba0SDavid C Somayajulu 
68711bcba0SDavid C Somayajulu static int qls_alloc_rcv_bufs(qla_host_t *ha);
69711bcba0SDavid C Somayajulu static void qls_free_rcv_bufs(qla_host_t *ha);
70711bcba0SDavid C Somayajulu 
71711bcba0SDavid C Somayajulu static void qls_init_ifnet(device_t dev, qla_host_t *ha);
72711bcba0SDavid C Somayajulu static void qls_release(qla_host_t *ha);
73711bcba0SDavid C Somayajulu static void qls_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nsegs,
74711bcba0SDavid C Somayajulu 		int error);
75711bcba0SDavid C Somayajulu static void qls_stop(qla_host_t *ha);
76711bcba0SDavid C Somayajulu static int qls_send(qla_host_t *ha, struct mbuf **m_headp);
77711bcba0SDavid C Somayajulu static void qls_tx_done(void *context, int pending);
78711bcba0SDavid C Somayajulu 
79711bcba0SDavid C Somayajulu static int qls_config_lro(qla_host_t *ha);
80711bcba0SDavid C Somayajulu static void qls_free_lro(qla_host_t *ha);
81711bcba0SDavid C Somayajulu 
82711bcba0SDavid C Somayajulu static void qls_error_recovery(void *context, int pending);
83711bcba0SDavid C Somayajulu 
84711bcba0SDavid C Somayajulu /*
85711bcba0SDavid C Somayajulu  * Hooks to the Operating Systems
86711bcba0SDavid C Somayajulu  */
87711bcba0SDavid C Somayajulu static int qls_pci_probe (device_t);
88711bcba0SDavid C Somayajulu static int qls_pci_attach (device_t);
89711bcba0SDavid C Somayajulu static int qls_pci_detach (device_t);
90711bcba0SDavid C Somayajulu 
9164c618edSJustin Hibbits static void qls_start(if_t ifp);
92711bcba0SDavid C Somayajulu static void qls_init(void *arg);
9364c618edSJustin Hibbits static int qls_ioctl(if_t ifp, u_long cmd, caddr_t data);
9464c618edSJustin Hibbits static int qls_media_change(if_t ifp);
9564c618edSJustin Hibbits static void qls_media_status(if_t ifp, struct ifmediareq *ifmr);
96711bcba0SDavid C Somayajulu 
97711bcba0SDavid C Somayajulu static device_method_t qla_pci_methods[] = {
98711bcba0SDavid C Somayajulu 	/* Device interface */
99711bcba0SDavid C Somayajulu 	DEVMETHOD(device_probe, qls_pci_probe),
100711bcba0SDavid C Somayajulu 	DEVMETHOD(device_attach, qls_pci_attach),
101711bcba0SDavid C Somayajulu 	DEVMETHOD(device_detach, qls_pci_detach),
102711bcba0SDavid C Somayajulu 	{ 0, 0 }
103711bcba0SDavid C Somayajulu };
104711bcba0SDavid C Somayajulu 
105711bcba0SDavid C Somayajulu static driver_t qla_pci_driver = {
106711bcba0SDavid C Somayajulu 	"ql", qla_pci_methods, sizeof (qla_host_t),
107711bcba0SDavid C Somayajulu };
108711bcba0SDavid C Somayajulu 
1092f87208eSJohn Baldwin DRIVER_MODULE(qla8000, pci, qla_pci_driver, 0, 0);
110711bcba0SDavid C Somayajulu 
111711bcba0SDavid C Somayajulu MODULE_DEPEND(qla8000, pci, 1, 1, 1);
112711bcba0SDavid C Somayajulu MODULE_DEPEND(qla8000, ether, 1, 1, 1);
113711bcba0SDavid C Somayajulu 
114711bcba0SDavid C Somayajulu MALLOC_DEFINE(M_QLA8000BUF, "qla8000buf", "Buffers for qla8000 driver");
115711bcba0SDavid C Somayajulu 
116711bcba0SDavid C Somayajulu static char dev_str[64];
117711bcba0SDavid C Somayajulu static char ver_str[64];
118711bcba0SDavid C Somayajulu 
119711bcba0SDavid C Somayajulu /*
120711bcba0SDavid C Somayajulu  * Name:	qls_pci_probe
121711bcba0SDavid C Somayajulu  * Function:	Validate the PCI device to be a QLA80XX device
122711bcba0SDavid C Somayajulu  */
123711bcba0SDavid C Somayajulu static int
qls_pci_probe(device_t dev)124711bcba0SDavid C Somayajulu qls_pci_probe(device_t dev)
125711bcba0SDavid C Somayajulu {
126711bcba0SDavid C Somayajulu         switch ((pci_get_device(dev) << 16) | (pci_get_vendor(dev))) {
127711bcba0SDavid C Somayajulu         case PCI_QLOGIC_DEV8000:
128711bcba0SDavid C Somayajulu 		snprintf(dev_str, sizeof(dev_str), "%s v%d.%d.%d",
129711bcba0SDavid C Somayajulu 			"Qlogic ISP 8000 PCI CNA Adapter-Ethernet Function",
130711bcba0SDavid C Somayajulu 			QLA_VERSION_MAJOR, QLA_VERSION_MINOR,
131711bcba0SDavid C Somayajulu 			QLA_VERSION_BUILD);
132711bcba0SDavid C Somayajulu 		snprintf(ver_str, sizeof(ver_str), "v%d.%d.%d",
133711bcba0SDavid C Somayajulu 			QLA_VERSION_MAJOR, QLA_VERSION_MINOR,
134711bcba0SDavid C Somayajulu 			QLA_VERSION_BUILD);
135711bcba0SDavid C Somayajulu                 device_set_desc(dev, dev_str);
136711bcba0SDavid C Somayajulu                 break;
137711bcba0SDavid C Somayajulu         default:
138711bcba0SDavid C Somayajulu                 return (ENXIO);
139711bcba0SDavid C Somayajulu         }
140711bcba0SDavid C Somayajulu 
141711bcba0SDavid C Somayajulu         if (bootverbose)
142711bcba0SDavid C Somayajulu                 printf("%s: %s\n ", __func__, dev_str);
143711bcba0SDavid C Somayajulu 
144711bcba0SDavid C Somayajulu         return (BUS_PROBE_DEFAULT);
145711bcba0SDavid C Somayajulu }
146711bcba0SDavid C Somayajulu 
147711bcba0SDavid C Somayajulu static int
qls_sysctl_get_drvr_stats(SYSCTL_HANDLER_ARGS)148711bcba0SDavid C Somayajulu qls_sysctl_get_drvr_stats(SYSCTL_HANDLER_ARGS)
149711bcba0SDavid C Somayajulu {
150711bcba0SDavid C Somayajulu         int err = 0, ret;
151711bcba0SDavid C Somayajulu         qla_host_t *ha;
152711bcba0SDavid C Somayajulu         uint32_t i;
153711bcba0SDavid C Somayajulu 
154711bcba0SDavid C Somayajulu         err = sysctl_handle_int(oidp, &ret, 0, req);
155711bcba0SDavid C Somayajulu 
156711bcba0SDavid C Somayajulu         if (err || !req->newptr)
157711bcba0SDavid C Somayajulu                 return (err);
158711bcba0SDavid C Somayajulu 
159711bcba0SDavid C Somayajulu         if (ret == 1) {
160711bcba0SDavid C Somayajulu                 ha = (qla_host_t *)arg1;
161711bcba0SDavid C Somayajulu 
162711bcba0SDavid C Somayajulu                 for (i = 0; i < ha->num_tx_rings; i++) {
163*ae389777SFuqian Huang                         QL_DPRINT2((ha->pci_dev,
164711bcba0SDavid C Somayajulu                                 "%s: tx_ring[%d].tx_frames= %p\n",
165711bcba0SDavid C Somayajulu 				__func__, i,
166*ae389777SFuqian Huang                                 (void *)ha->tx_ring[i].tx_frames));
167711bcba0SDavid C Somayajulu 
168*ae389777SFuqian Huang                         QL_DPRINT2((ha->pci_dev,
169711bcba0SDavid C Somayajulu                                 "%s: tx_ring[%d].tx_tso_frames= %p\n",
170711bcba0SDavid C Somayajulu 				__func__, i,
171*ae389777SFuqian Huang                                 (void *)ha->tx_ring[i].tx_tso_frames));
172711bcba0SDavid C Somayajulu 
173*ae389777SFuqian Huang                         QL_DPRINT2((ha->pci_dev,
174711bcba0SDavid C Somayajulu                                 "%s: tx_ring[%d].tx_vlan_frames= %p\n",
175711bcba0SDavid C Somayajulu 				__func__, i,
176*ae389777SFuqian Huang                                 (void *)ha->tx_ring[i].tx_vlan_frames));
177711bcba0SDavid C Somayajulu 
178711bcba0SDavid C Somayajulu                         device_printf(ha->pci_dev,
179711bcba0SDavid C Somayajulu                                 "%s: tx_ring[%d].txr_free= 0x%08x\n",
180711bcba0SDavid C Somayajulu 				__func__, i,
181711bcba0SDavid C Somayajulu                                 ha->tx_ring[i].txr_free);
182711bcba0SDavid C Somayajulu 
183711bcba0SDavid C Somayajulu                         device_printf(ha->pci_dev,
184711bcba0SDavid C Somayajulu                                 "%s: tx_ring[%d].txr_next= 0x%08x\n",
185711bcba0SDavid C Somayajulu 				__func__, i,
186711bcba0SDavid C Somayajulu                                 ha->tx_ring[i].txr_next);
187711bcba0SDavid C Somayajulu 
188711bcba0SDavid C Somayajulu                         device_printf(ha->pci_dev,
189711bcba0SDavid C Somayajulu                                 "%s: tx_ring[%d].txr_done= 0x%08x\n",
190711bcba0SDavid C Somayajulu 				__func__, i,
191711bcba0SDavid C Somayajulu                                 ha->tx_ring[i].txr_done);
192711bcba0SDavid C Somayajulu 
193711bcba0SDavid C Somayajulu                         device_printf(ha->pci_dev,
194711bcba0SDavid C Somayajulu                                 "%s: tx_ring[%d].txr_cons_idx= 0x%08x\n",
195711bcba0SDavid C Somayajulu 				__func__, i,
196711bcba0SDavid C Somayajulu                                 *(ha->tx_ring[i].txr_cons_vaddr));
197711bcba0SDavid C Somayajulu 		}
198711bcba0SDavid C Somayajulu 
199711bcba0SDavid C Somayajulu                 for (i = 0; i < ha->num_rx_rings; i++) {
200*ae389777SFuqian Huang                         QL_DPRINT2((ha->pci_dev,
201711bcba0SDavid C Somayajulu                                 "%s: rx_ring[%d].rx_int= %p\n",
202711bcba0SDavid C Somayajulu 				__func__, i,
203*ae389777SFuqian Huang                                 (void *)ha->rx_ring[i].rx_int));
204711bcba0SDavid C Somayajulu 
205*ae389777SFuqian Huang                         QL_DPRINT2((ha->pci_dev,
206711bcba0SDavid C Somayajulu                                 "%s: rx_ring[%d].rss_int= %p\n",
207711bcba0SDavid C Somayajulu 				__func__, i,
208*ae389777SFuqian Huang                                 (void *)ha->rx_ring[i].rss_int));
209711bcba0SDavid C Somayajulu 
210711bcba0SDavid C Somayajulu                         device_printf(ha->pci_dev,
211711bcba0SDavid C Somayajulu                                 "%s: rx_ring[%d].lbq_next= 0x%08x\n",
212711bcba0SDavid C Somayajulu 				__func__, i,
213711bcba0SDavid C Somayajulu                                 ha->rx_ring[i].lbq_next);
214711bcba0SDavid C Somayajulu 
215711bcba0SDavid C Somayajulu                         device_printf(ha->pci_dev,
216711bcba0SDavid C Somayajulu                                 "%s: rx_ring[%d].lbq_free= 0x%08x\n",
217711bcba0SDavid C Somayajulu 				__func__, i,
218711bcba0SDavid C Somayajulu                                 ha->rx_ring[i].lbq_free);
219711bcba0SDavid C Somayajulu 
220711bcba0SDavid C Somayajulu                         device_printf(ha->pci_dev,
221711bcba0SDavid C Somayajulu                                 "%s: rx_ring[%d].lbq_in= 0x%08x\n",
222711bcba0SDavid C Somayajulu 				__func__, i,
223711bcba0SDavid C Somayajulu                                 ha->rx_ring[i].lbq_in);
224711bcba0SDavid C Somayajulu 
225711bcba0SDavid C Somayajulu                         device_printf(ha->pci_dev,
226711bcba0SDavid C Somayajulu                                 "%s: rx_ring[%d].sbq_next= 0x%08x\n",
227711bcba0SDavid C Somayajulu 				__func__, i,
228711bcba0SDavid C Somayajulu                                 ha->rx_ring[i].sbq_next);
229711bcba0SDavid C Somayajulu 
230711bcba0SDavid C Somayajulu                         device_printf(ha->pci_dev,
231711bcba0SDavid C Somayajulu                                 "%s: rx_ring[%d].sbq_free= 0x%08x\n",
232711bcba0SDavid C Somayajulu 				__func__, i,
233711bcba0SDavid C Somayajulu                                 ha->rx_ring[i].sbq_free);
234711bcba0SDavid C Somayajulu 
235711bcba0SDavid C Somayajulu                         device_printf(ha->pci_dev,
236711bcba0SDavid C Somayajulu                                 "%s: rx_ring[%d].sbq_in= 0x%08x\n",
237711bcba0SDavid C Somayajulu 				__func__, i,
238711bcba0SDavid C Somayajulu                                 ha->rx_ring[i].sbq_in);
239711bcba0SDavid C Somayajulu 		}
240711bcba0SDavid C Somayajulu 
241711bcba0SDavid C Somayajulu 		device_printf(ha->pci_dev, "%s: err_m_getcl = 0x%08x\n",
242711bcba0SDavid C Somayajulu 				__func__, ha->err_m_getcl);
243711bcba0SDavid C Somayajulu 		device_printf(ha->pci_dev, "%s: err_m_getjcl = 0x%08x\n",
244711bcba0SDavid C Somayajulu 				__func__, ha->err_m_getjcl);
245711bcba0SDavid C Somayajulu 		device_printf(ha->pci_dev,
246711bcba0SDavid C Somayajulu 				"%s: err_tx_dmamap_create = 0x%08x\n",
247711bcba0SDavid C Somayajulu 				__func__, ha->err_tx_dmamap_create);
248711bcba0SDavid C Somayajulu 		device_printf(ha->pci_dev,
249711bcba0SDavid C Somayajulu 				"%s: err_tx_dmamap_load = 0x%08x\n",
250711bcba0SDavid C Somayajulu 				__func__, ha->err_tx_dmamap_load);
251711bcba0SDavid C Somayajulu 		device_printf(ha->pci_dev,
252711bcba0SDavid C Somayajulu 				"%s: err_tx_defrag = 0x%08x\n",
253711bcba0SDavid C Somayajulu 				__func__, ha->err_tx_defrag);
254711bcba0SDavid C Somayajulu         }
255711bcba0SDavid C Somayajulu         return (err);
256711bcba0SDavid C Somayajulu }
257711bcba0SDavid C Somayajulu 
258711bcba0SDavid C Somayajulu static void
qls_add_sysctls(qla_host_t * ha)259711bcba0SDavid C Somayajulu qls_add_sysctls(qla_host_t *ha)
260711bcba0SDavid C Somayajulu {
261711bcba0SDavid C Somayajulu         device_t dev = ha->pci_dev;
262711bcba0SDavid C Somayajulu 
263711bcba0SDavid C Somayajulu 	SYSCTL_ADD_STRING(device_get_sysctl_ctx(dev),
264711bcba0SDavid C Somayajulu 		SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
265711bcba0SDavid C Somayajulu 		OID_AUTO, "version", CTLFLAG_RD,
266711bcba0SDavid C Somayajulu 		ver_str, 0, "Driver Version");
267711bcba0SDavid C Somayajulu 
268711bcba0SDavid C Somayajulu 	qls_dbg_level = 0;
269711bcba0SDavid C Somayajulu         SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
270711bcba0SDavid C Somayajulu                 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
271711bcba0SDavid C Somayajulu                 OID_AUTO, "debug", CTLFLAG_RW,
272711bcba0SDavid C Somayajulu                 &qls_dbg_level, qls_dbg_level, "Debug Level");
273711bcba0SDavid C Somayajulu 
274711bcba0SDavid C Somayajulu         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
275711bcba0SDavid C Somayajulu             SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
2767029da5cSPawel Biernacki             OID_AUTO, "drvr_stats",
2777029da5cSPawel Biernacki 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, (void *)ha, 0,
278711bcba0SDavid C Somayajulu 	    qls_sysctl_get_drvr_stats, "I", "Driver Maintained Statistics");
279711bcba0SDavid C Somayajulu 
280711bcba0SDavid C Somayajulu         return;
281711bcba0SDavid C Somayajulu }
282711bcba0SDavid C Somayajulu 
283711bcba0SDavid C Somayajulu static void
qls_watchdog(void * arg)284711bcba0SDavid C Somayajulu qls_watchdog(void *arg)
285711bcba0SDavid C Somayajulu {
286711bcba0SDavid C Somayajulu 	qla_host_t *ha = arg;
28764c618edSJustin Hibbits 	if_t ifp;
288711bcba0SDavid C Somayajulu 
289711bcba0SDavid C Somayajulu 	ifp = ha->ifp;
290711bcba0SDavid C Somayajulu 
291711bcba0SDavid C Somayajulu         if (ha->flags.qla_watchdog_exit) {
292711bcba0SDavid C Somayajulu 		ha->qla_watchdog_exited = 1;
293711bcba0SDavid C Somayajulu 		return;
294711bcba0SDavid C Somayajulu 	}
295711bcba0SDavid C Somayajulu 	ha->qla_watchdog_exited = 0;
296711bcba0SDavid C Somayajulu 
297711bcba0SDavid C Somayajulu 	if (!ha->flags.qla_watchdog_pause) {
298711bcba0SDavid C Somayajulu 		if (ha->qla_initiate_recovery) {
299711bcba0SDavid C Somayajulu 			ha->qla_watchdog_paused = 1;
300711bcba0SDavid C Somayajulu 			ha->qla_initiate_recovery = 0;
301711bcba0SDavid C Somayajulu 			ha->err_inject = 0;
302711bcba0SDavid C Somayajulu 			taskqueue_enqueue(ha->err_tq, &ha->err_task);
303711bcba0SDavid C Somayajulu 
30464c618edSJustin Hibbits 		} else if (!if_sendq_empty(ifp) && QL_RUNNING(ifp)) {
305711bcba0SDavid C Somayajulu 			taskqueue_enqueue(ha->tx_tq, &ha->tx_task);
306711bcba0SDavid C Somayajulu 		}
307711bcba0SDavid C Somayajulu 
308711bcba0SDavid C Somayajulu 		ha->qla_watchdog_paused = 0;
309711bcba0SDavid C Somayajulu 	} else {
310711bcba0SDavid C Somayajulu 		ha->qla_watchdog_paused = 1;
311711bcba0SDavid C Somayajulu 	}
312711bcba0SDavid C Somayajulu 
31382b5e644SConrad Meyer 	ha->watchdog_ticks = (ha->watchdog_ticks + 1) % 1000;
314711bcba0SDavid C Somayajulu 	callout_reset(&ha->tx_callout, QLA_WATCHDOG_CALLOUT_TICKS,
315711bcba0SDavid C Somayajulu 		qls_watchdog, ha);
316711bcba0SDavid C Somayajulu 
317711bcba0SDavid C Somayajulu 	return;
318711bcba0SDavid C Somayajulu }
319711bcba0SDavid C Somayajulu 
320711bcba0SDavid C Somayajulu /*
321711bcba0SDavid C Somayajulu  * Name:	qls_pci_attach
322711bcba0SDavid C Somayajulu  * Function:	attaches the device to the operating system
323711bcba0SDavid C Somayajulu  */
324711bcba0SDavid C Somayajulu static int
qls_pci_attach(device_t dev)325711bcba0SDavid C Somayajulu qls_pci_attach(device_t dev)
326711bcba0SDavid C Somayajulu {
327711bcba0SDavid C Somayajulu 	qla_host_t *ha = NULL;
328711bcba0SDavid C Somayajulu 	int i;
329711bcba0SDavid C Somayajulu 
330711bcba0SDavid C Somayajulu 	QL_DPRINT2((dev, "%s: enter\n", __func__));
331711bcba0SDavid C Somayajulu 
332711bcba0SDavid C Somayajulu         if ((ha = device_get_softc(dev)) == NULL) {
333711bcba0SDavid C Somayajulu                 device_printf(dev, "cannot get softc\n");
334711bcba0SDavid C Somayajulu                 return (ENOMEM);
335711bcba0SDavid C Somayajulu         }
336711bcba0SDavid C Somayajulu 
337711bcba0SDavid C Somayajulu         memset(ha, 0, sizeof (qla_host_t));
338711bcba0SDavid C Somayajulu 
339711bcba0SDavid C Somayajulu         if (pci_get_device(dev) != PCI_DEVICE_QLOGIC_8000) {
340711bcba0SDavid C Somayajulu                 device_printf(dev, "device is not QLE8000\n");
341711bcba0SDavid C Somayajulu                 return (ENXIO);
342711bcba0SDavid C Somayajulu 	}
343711bcba0SDavid C Somayajulu 
344711bcba0SDavid C Somayajulu         ha->pci_func = pci_get_function(dev);
345711bcba0SDavid C Somayajulu 
346711bcba0SDavid C Somayajulu         ha->pci_dev = dev;
347711bcba0SDavid C Somayajulu 
348711bcba0SDavid C Somayajulu 	pci_enable_busmaster(dev);
349711bcba0SDavid C Somayajulu 
350711bcba0SDavid C Somayajulu 	ha->reg_rid = PCIR_BAR(1);
351711bcba0SDavid C Somayajulu 	ha->pci_reg = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &ha->reg_rid,
352711bcba0SDavid C Somayajulu 				RF_ACTIVE);
353711bcba0SDavid C Somayajulu 
354711bcba0SDavid C Somayajulu         if (ha->pci_reg == NULL) {
355711bcba0SDavid C Somayajulu                 device_printf(dev, "unable to map any ports\n");
356711bcba0SDavid C Somayajulu                 goto qls_pci_attach_err;
357711bcba0SDavid C Somayajulu         }
358711bcba0SDavid C Somayajulu 
359711bcba0SDavid C Somayajulu 	ha->reg_rid1 = PCIR_BAR(3);
360711bcba0SDavid C Somayajulu 	ha->pci_reg1 = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
361711bcba0SDavid C Somayajulu 			&ha->reg_rid1, RF_ACTIVE);
362711bcba0SDavid C Somayajulu 
363711bcba0SDavid C Somayajulu         if (ha->pci_reg1 == NULL) {
364711bcba0SDavid C Somayajulu                 device_printf(dev, "unable to map any ports\n");
365711bcba0SDavid C Somayajulu                 goto qls_pci_attach_err;
366711bcba0SDavid C Somayajulu         }
367711bcba0SDavid C Somayajulu 
368711bcba0SDavid C Somayajulu 	mtx_init(&ha->hw_lock, "qla80xx_hw_lock", MTX_NETWORK_LOCK, MTX_DEF);
369711bcba0SDavid C Somayajulu 	mtx_init(&ha->tx_lock, "qla80xx_tx_lock", MTX_NETWORK_LOCK, MTX_DEF);
370711bcba0SDavid C Somayajulu 
371711bcba0SDavid C Somayajulu 	qls_add_sysctls(ha);
372711bcba0SDavid C Somayajulu 	qls_hw_add_sysctls(ha);
373711bcba0SDavid C Somayajulu 
374711bcba0SDavid C Somayajulu 	ha->flags.lock_init = 1;
375711bcba0SDavid C Somayajulu 
376711bcba0SDavid C Somayajulu 	ha->msix_count = pci_msix_count(dev);
377711bcba0SDavid C Somayajulu 
378711bcba0SDavid C Somayajulu 	if (ha->msix_count < qls_get_msix_count(ha)) {
379711bcba0SDavid C Somayajulu 		device_printf(dev, "%s: msix_count[%d] not enough\n", __func__,
380711bcba0SDavid C Somayajulu 			ha->msix_count);
381711bcba0SDavid C Somayajulu 		goto qls_pci_attach_err;
382711bcba0SDavid C Somayajulu 	}
383711bcba0SDavid C Somayajulu 
384711bcba0SDavid C Somayajulu 	ha->msix_count = qls_get_msix_count(ha);
385711bcba0SDavid C Somayajulu 
386*ae389777SFuqian Huang 	QL_DPRINT2((dev, "\n%s: ha %p pci_func 0x%x  msix_count 0x%x"
387711bcba0SDavid C Somayajulu 		" pci_reg %p pci_reg1 %p\n", __func__, ha,
388*ae389777SFuqian Huang 		ha->pci_func, ha->msix_count, ha->pci_reg, ha->pci_reg1));
389711bcba0SDavid C Somayajulu 
390711bcba0SDavid C Somayajulu 	if (pci_alloc_msix(dev, &ha->msix_count)) {
391711bcba0SDavid C Somayajulu 		device_printf(dev, "%s: pci_alloc_msi[%d] failed\n", __func__,
392711bcba0SDavid C Somayajulu 			ha->msix_count);
393711bcba0SDavid C Somayajulu 		ha->msix_count = 0;
394711bcba0SDavid C Somayajulu 		goto qls_pci_attach_err;
395711bcba0SDavid C Somayajulu 	}
396711bcba0SDavid C Somayajulu 
397711bcba0SDavid C Somayajulu         for (i = 0; i < ha->num_rx_rings; i++) {
398711bcba0SDavid C Somayajulu                 ha->irq_vec[i].cq_idx = i;
399711bcba0SDavid C Somayajulu                 ha->irq_vec[i].ha = ha;
400711bcba0SDavid C Somayajulu                 ha->irq_vec[i].irq_rid = 1 + i;
401711bcba0SDavid C Somayajulu 
402711bcba0SDavid C Somayajulu                 ha->irq_vec[i].irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
403711bcba0SDavid C Somayajulu                                 &ha->irq_vec[i].irq_rid,
404711bcba0SDavid C Somayajulu                                 (RF_ACTIVE | RF_SHAREABLE));
405711bcba0SDavid C Somayajulu 
406711bcba0SDavid C Somayajulu                 if (ha->irq_vec[i].irq == NULL) {
407711bcba0SDavid C Somayajulu                         device_printf(dev, "could not allocate interrupt\n");
408711bcba0SDavid C Somayajulu                         goto qls_pci_attach_err;
409711bcba0SDavid C Somayajulu                 }
410711bcba0SDavid C Somayajulu 
411711bcba0SDavid C Somayajulu 		if (bus_setup_intr(dev, ha->irq_vec[i].irq,
412711bcba0SDavid C Somayajulu 			(INTR_TYPE_NET | INTR_MPSAFE), NULL, qls_isr,
413711bcba0SDavid C Somayajulu 			&ha->irq_vec[i], &ha->irq_vec[i].handle)) {
414711bcba0SDavid C Somayajulu 				device_printf(dev,
415711bcba0SDavid C Somayajulu 					"could not setup interrupt\n");
416711bcba0SDavid C Somayajulu 			goto qls_pci_attach_err;
417711bcba0SDavid C Somayajulu 		}
418711bcba0SDavid C Somayajulu         }
419711bcba0SDavid C Somayajulu 
420711bcba0SDavid C Somayajulu 	qls_rd_nic_params(ha);
421711bcba0SDavid C Somayajulu 
422711bcba0SDavid C Somayajulu 	/* allocate parent dma tag */
423711bcba0SDavid C Somayajulu 	if (qls_alloc_parent_dma_tag(ha)) {
424711bcba0SDavid C Somayajulu 		device_printf(dev, "%s: qls_alloc_parent_dma_tag failed\n",
425711bcba0SDavid C Somayajulu 			__func__);
426711bcba0SDavid C Somayajulu 		goto qls_pci_attach_err;
427711bcba0SDavid C Somayajulu 	}
428711bcba0SDavid C Somayajulu 
429711bcba0SDavid C Somayajulu 	/* alloc all dma buffers */
430711bcba0SDavid C Somayajulu 	if (qls_alloc_dma(ha)) {
431711bcba0SDavid C Somayajulu 		device_printf(dev, "%s: qls_alloc_dma failed\n", __func__);
432711bcba0SDavid C Somayajulu 		goto qls_pci_attach_err;
433711bcba0SDavid C Somayajulu 	}
434711bcba0SDavid C Somayajulu 
435711bcba0SDavid C Somayajulu 	/* create the o.s ethernet interface */
436711bcba0SDavid C Somayajulu 	qls_init_ifnet(dev, ha);
437711bcba0SDavid C Somayajulu 
438711bcba0SDavid C Somayajulu 	ha->flags.qla_watchdog_active = 1;
439711bcba0SDavid C Somayajulu 	ha->flags.qla_watchdog_pause = 1;
440711bcba0SDavid C Somayajulu 
441711bcba0SDavid C Somayajulu 	TASK_INIT(&ha->tx_task, 0, qls_tx_done, ha);
442711bcba0SDavid C Somayajulu 	ha->tx_tq = taskqueue_create_fast("qla_txq", M_NOWAIT,
443711bcba0SDavid C Somayajulu 			taskqueue_thread_enqueue, &ha->tx_tq);
444711bcba0SDavid C Somayajulu 	taskqueue_start_threads(&ha->tx_tq, 1, PI_NET, "%s txq",
445711bcba0SDavid C Somayajulu 		device_get_nameunit(ha->pci_dev));
446711bcba0SDavid C Somayajulu 
447fd90e2edSJung-uk Kim 	callout_init(&ha->tx_callout, 1);
448711bcba0SDavid C Somayajulu 	ha->flags.qla_callout_init = 1;
449711bcba0SDavid C Somayajulu 
450711bcba0SDavid C Somayajulu         /* create ioctl device interface */
451711bcba0SDavid C Somayajulu         if (qls_make_cdev(ha)) {
452711bcba0SDavid C Somayajulu                 device_printf(dev, "%s: qls_make_cdev failed\n", __func__);
453711bcba0SDavid C Somayajulu                 goto qls_pci_attach_err;
454711bcba0SDavid C Somayajulu         }
455711bcba0SDavid C Somayajulu 
456711bcba0SDavid C Somayajulu 	callout_reset(&ha->tx_callout, QLA_WATCHDOG_CALLOUT_TICKS,
457711bcba0SDavid C Somayajulu 		qls_watchdog, ha);
458711bcba0SDavid C Somayajulu 
459711bcba0SDavid C Somayajulu         TASK_INIT(&ha->err_task, 0, qls_error_recovery, ha);
460711bcba0SDavid C Somayajulu         ha->err_tq = taskqueue_create_fast("qla_errq", M_NOWAIT,
461711bcba0SDavid C Somayajulu                         taskqueue_thread_enqueue, &ha->err_tq);
462711bcba0SDavid C Somayajulu         taskqueue_start_threads(&ha->err_tq, 1, PI_NET, "%s errq",
463711bcba0SDavid C Somayajulu                 device_get_nameunit(ha->pci_dev));
464711bcba0SDavid C Somayajulu 
465711bcba0SDavid C Somayajulu 	QL_DPRINT2((dev, "%s: exit 0\n", __func__));
466711bcba0SDavid C Somayajulu         return (0);
467711bcba0SDavid C Somayajulu 
468711bcba0SDavid C Somayajulu qls_pci_attach_err:
469711bcba0SDavid C Somayajulu 
470711bcba0SDavid C Somayajulu 	qls_release(ha);
471711bcba0SDavid C Somayajulu 
472711bcba0SDavid C Somayajulu 	QL_DPRINT2((dev, "%s: exit ENXIO\n", __func__));
473711bcba0SDavid C Somayajulu         return (ENXIO);
474711bcba0SDavid C Somayajulu }
475711bcba0SDavid C Somayajulu 
476711bcba0SDavid C Somayajulu /*
477711bcba0SDavid C Somayajulu  * Name:	qls_pci_detach
478711bcba0SDavid C Somayajulu  * Function:	Unhooks the device from the operating system
479711bcba0SDavid C Somayajulu  */
480711bcba0SDavid C Somayajulu static int
qls_pci_detach(device_t dev)481711bcba0SDavid C Somayajulu qls_pci_detach(device_t dev)
482711bcba0SDavid C Somayajulu {
483711bcba0SDavid C Somayajulu 	qla_host_t *ha = NULL;
484711bcba0SDavid C Somayajulu 
485711bcba0SDavid C Somayajulu 	QL_DPRINT2((dev, "%s: enter\n", __func__));
486711bcba0SDavid C Somayajulu 
487711bcba0SDavid C Somayajulu         if ((ha = device_get_softc(dev)) == NULL) {
488711bcba0SDavid C Somayajulu                 device_printf(dev, "cannot get softc\n");
489711bcba0SDavid C Somayajulu                 return (ENOMEM);
490711bcba0SDavid C Somayajulu         }
491711bcba0SDavid C Somayajulu 
492711bcba0SDavid C Somayajulu 	(void)QLA_LOCK(ha, __func__, 0);
493711bcba0SDavid C Somayajulu 	qls_stop(ha);
494711bcba0SDavid C Somayajulu 	QLA_UNLOCK(ha, __func__);
495711bcba0SDavid C Somayajulu 
496711bcba0SDavid C Somayajulu 	qls_release(ha);
497711bcba0SDavid C Somayajulu 
498711bcba0SDavid C Somayajulu 	QL_DPRINT2((dev, "%s: exit\n", __func__));
499711bcba0SDavid C Somayajulu 
500711bcba0SDavid C Somayajulu         return (0);
501711bcba0SDavid C Somayajulu }
502711bcba0SDavid C Somayajulu 
503711bcba0SDavid C Somayajulu /*
504711bcba0SDavid C Somayajulu  * Name:	qls_release
505711bcba0SDavid C Somayajulu  * Function:	Releases the resources allocated for the device
506711bcba0SDavid C Somayajulu  */
507711bcba0SDavid C Somayajulu static void
qls_release(qla_host_t * ha)508711bcba0SDavid C Somayajulu qls_release(qla_host_t *ha)
509711bcba0SDavid C Somayajulu {
510711bcba0SDavid C Somayajulu 	device_t dev;
511711bcba0SDavid C Somayajulu 	int i;
512711bcba0SDavid C Somayajulu 
513711bcba0SDavid C Somayajulu 	dev = ha->pci_dev;
514711bcba0SDavid C Somayajulu 
515711bcba0SDavid C Somayajulu 	if (ha->err_tq) {
516711bcba0SDavid C Somayajulu 		taskqueue_drain(ha->err_tq, &ha->err_task);
517711bcba0SDavid C Somayajulu 		taskqueue_free(ha->err_tq);
518711bcba0SDavid C Somayajulu 	}
519711bcba0SDavid C Somayajulu 
520711bcba0SDavid C Somayajulu 	if (ha->tx_tq) {
521711bcba0SDavid C Somayajulu 		taskqueue_drain(ha->tx_tq, &ha->tx_task);
522711bcba0SDavid C Somayajulu 		taskqueue_free(ha->tx_tq);
523711bcba0SDavid C Somayajulu 	}
524711bcba0SDavid C Somayajulu 
525711bcba0SDavid C Somayajulu 	qls_del_cdev(ha);
526711bcba0SDavid C Somayajulu 
527711bcba0SDavid C Somayajulu 	if (ha->flags.qla_watchdog_active) {
528711bcba0SDavid C Somayajulu 		ha->flags.qla_watchdog_exit = 1;
529711bcba0SDavid C Somayajulu 
530711bcba0SDavid C Somayajulu 		while (ha->qla_watchdog_exited == 0)
531711bcba0SDavid C Somayajulu 			qls_mdelay(__func__, 1);
532711bcba0SDavid C Somayajulu 	}
533711bcba0SDavid C Somayajulu 
534711bcba0SDavid C Somayajulu 	if (ha->flags.qla_callout_init)
535711bcba0SDavid C Somayajulu 		callout_stop(&ha->tx_callout);
536711bcba0SDavid C Somayajulu 
537711bcba0SDavid C Somayajulu 	if (ha->ifp != NULL)
538711bcba0SDavid C Somayajulu 		ether_ifdetach(ha->ifp);
539711bcba0SDavid C Somayajulu 
540711bcba0SDavid C Somayajulu 	qls_free_dma(ha);
541711bcba0SDavid C Somayajulu 	qls_free_parent_dma_tag(ha);
542711bcba0SDavid C Somayajulu 
543711bcba0SDavid C Somayajulu         for (i = 0; i < ha->num_rx_rings; i++) {
544711bcba0SDavid C Somayajulu                 if (ha->irq_vec[i].handle) {
545711bcba0SDavid C Somayajulu                         (void)bus_teardown_intr(dev, ha->irq_vec[i].irq,
546711bcba0SDavid C Somayajulu                                         ha->irq_vec[i].handle);
547711bcba0SDavid C Somayajulu                 }
548711bcba0SDavid C Somayajulu 
549711bcba0SDavid C Somayajulu                 if (ha->irq_vec[i].irq) {
550711bcba0SDavid C Somayajulu                         (void)bus_release_resource(dev, SYS_RES_IRQ,
551711bcba0SDavid C Somayajulu                                 ha->irq_vec[i].irq_rid,
552711bcba0SDavid C Somayajulu                                 ha->irq_vec[i].irq);
553711bcba0SDavid C Somayajulu                 }
554711bcba0SDavid C Somayajulu         }
555711bcba0SDavid C Somayajulu 
556711bcba0SDavid C Somayajulu 	if (ha->msix_count)
557711bcba0SDavid C Somayajulu 		pci_release_msi(dev);
558711bcba0SDavid C Somayajulu 
559711bcba0SDavid C Somayajulu 	if (ha->flags.lock_init) {
560711bcba0SDavid C Somayajulu 		mtx_destroy(&ha->tx_lock);
561711bcba0SDavid C Somayajulu 		mtx_destroy(&ha->hw_lock);
562711bcba0SDavid C Somayajulu 	}
563711bcba0SDavid C Somayajulu 
564711bcba0SDavid C Somayajulu         if (ha->pci_reg)
565711bcba0SDavid C Somayajulu                 (void) bus_release_resource(dev, SYS_RES_MEMORY, ha->reg_rid,
566711bcba0SDavid C Somayajulu 				ha->pci_reg);
567711bcba0SDavid C Somayajulu 
568711bcba0SDavid C Somayajulu         if (ha->pci_reg1)
569711bcba0SDavid C Somayajulu                 (void) bus_release_resource(dev, SYS_RES_MEMORY, ha->reg_rid1,
570711bcba0SDavid C Somayajulu 				ha->pci_reg1);
571711bcba0SDavid C Somayajulu }
572711bcba0SDavid C Somayajulu 
573711bcba0SDavid C Somayajulu /*
574711bcba0SDavid C Somayajulu  * DMA Related Functions
575711bcba0SDavid C Somayajulu  */
576711bcba0SDavid C Somayajulu 
577711bcba0SDavid C Somayajulu static void
qls_dmamap_callback(void * arg,bus_dma_segment_t * segs,int nsegs,int error)578711bcba0SDavid C Somayajulu qls_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
579711bcba0SDavid C Somayajulu {
580711bcba0SDavid C Somayajulu         *((bus_addr_t *)arg) = 0;
581711bcba0SDavid C Somayajulu 
582711bcba0SDavid C Somayajulu         if (error) {
583711bcba0SDavid C Somayajulu                 printf("%s: bus_dmamap_load failed (%d)\n", __func__, error);
584711bcba0SDavid C Somayajulu                 return;
585711bcba0SDavid C Somayajulu 	}
586711bcba0SDavid C Somayajulu 
587711bcba0SDavid C Somayajulu         *((bus_addr_t *)arg) = segs[0].ds_addr;
588711bcba0SDavid C Somayajulu 
589711bcba0SDavid C Somayajulu 	return;
590711bcba0SDavid C Somayajulu }
591711bcba0SDavid C Somayajulu 
592711bcba0SDavid C Somayajulu int
qls_alloc_dmabuf(qla_host_t * ha,qla_dma_t * dma_buf)593711bcba0SDavid C Somayajulu qls_alloc_dmabuf(qla_host_t *ha, qla_dma_t *dma_buf)
594711bcba0SDavid C Somayajulu {
595711bcba0SDavid C Somayajulu         int             ret = 0;
596711bcba0SDavid C Somayajulu         device_t        dev;
597711bcba0SDavid C Somayajulu         bus_addr_t      b_addr;
598711bcba0SDavid C Somayajulu 
599711bcba0SDavid C Somayajulu         dev = ha->pci_dev;
600711bcba0SDavid C Somayajulu 
601711bcba0SDavid C Somayajulu         QL_DPRINT2((dev, "%s: enter\n", __func__));
602711bcba0SDavid C Somayajulu 
603711bcba0SDavid C Somayajulu         ret = bus_dma_tag_create(
604711bcba0SDavid C Somayajulu                         ha->parent_tag,/* parent */
605711bcba0SDavid C Somayajulu                         dma_buf->alignment,
606711bcba0SDavid C Somayajulu                         ((bus_size_t)(1ULL << 32)),/* boundary */
607711bcba0SDavid C Somayajulu                         BUS_SPACE_MAXADDR,      /* lowaddr */
608711bcba0SDavid C Somayajulu                         BUS_SPACE_MAXADDR,      /* highaddr */
609711bcba0SDavid C Somayajulu                         NULL, NULL,             /* filter, filterarg */
610711bcba0SDavid C Somayajulu                         dma_buf->size,          /* maxsize */
611711bcba0SDavid C Somayajulu                         1,                      /* nsegments */
612711bcba0SDavid C Somayajulu                         dma_buf->size,          /* maxsegsize */
613711bcba0SDavid C Somayajulu                         0,                      /* flags */
614711bcba0SDavid C Somayajulu                         NULL, NULL,             /* lockfunc, lockarg */
615711bcba0SDavid C Somayajulu                         &dma_buf->dma_tag);
616711bcba0SDavid C Somayajulu 
617711bcba0SDavid C Somayajulu         if (ret) {
618711bcba0SDavid C Somayajulu                 device_printf(dev, "%s: could not create dma tag\n", __func__);
619711bcba0SDavid C Somayajulu                 goto qls_alloc_dmabuf_exit;
620711bcba0SDavid C Somayajulu         }
621711bcba0SDavid C Somayajulu         ret = bus_dmamem_alloc(dma_buf->dma_tag,
622711bcba0SDavid C Somayajulu                         (void **)&dma_buf->dma_b,
623711bcba0SDavid C Somayajulu                         (BUS_DMA_ZERO | BUS_DMA_COHERENT | BUS_DMA_NOWAIT),
624711bcba0SDavid C Somayajulu                         &dma_buf->dma_map);
625711bcba0SDavid C Somayajulu         if (ret) {
626711bcba0SDavid C Somayajulu                 bus_dma_tag_destroy(dma_buf->dma_tag);
627711bcba0SDavid C Somayajulu                 device_printf(dev, "%s: bus_dmamem_alloc failed\n", __func__);
628711bcba0SDavid C Somayajulu                 goto qls_alloc_dmabuf_exit;
629711bcba0SDavid C Somayajulu         }
630711bcba0SDavid C Somayajulu 
631711bcba0SDavid C Somayajulu         ret = bus_dmamap_load(dma_buf->dma_tag,
632711bcba0SDavid C Somayajulu                         dma_buf->dma_map,
633711bcba0SDavid C Somayajulu                         dma_buf->dma_b,
634711bcba0SDavid C Somayajulu                         dma_buf->size,
635711bcba0SDavid C Somayajulu                         qls_dmamap_callback,
636711bcba0SDavid C Somayajulu                         &b_addr, BUS_DMA_NOWAIT);
637711bcba0SDavid C Somayajulu 
638711bcba0SDavid C Somayajulu         if (ret || !b_addr) {
639711bcba0SDavid C Somayajulu                 bus_dma_tag_destroy(dma_buf->dma_tag);
640711bcba0SDavid C Somayajulu                 bus_dmamem_free(dma_buf->dma_tag, dma_buf->dma_b,
641711bcba0SDavid C Somayajulu                         dma_buf->dma_map);
642711bcba0SDavid C Somayajulu                 ret = -1;
643711bcba0SDavid C Somayajulu                 goto qls_alloc_dmabuf_exit;
644711bcba0SDavid C Somayajulu         }
645711bcba0SDavid C Somayajulu 
646711bcba0SDavid C Somayajulu         dma_buf->dma_addr = b_addr;
647711bcba0SDavid C Somayajulu 
648711bcba0SDavid C Somayajulu qls_alloc_dmabuf_exit:
649711bcba0SDavid C Somayajulu         QL_DPRINT2((dev, "%s: exit ret 0x%08x tag %p map %p b %p sz 0x%x\n",
650711bcba0SDavid C Somayajulu                 __func__, ret, (void *)dma_buf->dma_tag,
651711bcba0SDavid C Somayajulu                 (void *)dma_buf->dma_map, (void *)dma_buf->dma_b,
652711bcba0SDavid C Somayajulu 		dma_buf->size));
653711bcba0SDavid C Somayajulu 
654711bcba0SDavid C Somayajulu         return ret;
655711bcba0SDavid C Somayajulu }
656711bcba0SDavid C Somayajulu 
657711bcba0SDavid C Somayajulu void
qls_free_dmabuf(qla_host_t * ha,qla_dma_t * dma_buf)658711bcba0SDavid C Somayajulu qls_free_dmabuf(qla_host_t *ha, qla_dma_t *dma_buf)
659711bcba0SDavid C Somayajulu {
660aeeb653cSJohn Baldwin         bus_dmamap_unload(dma_buf->dma_tag, dma_buf->dma_map);
661711bcba0SDavid C Somayajulu         bus_dmamem_free(dma_buf->dma_tag, dma_buf->dma_b, dma_buf->dma_map);
662711bcba0SDavid C Somayajulu         bus_dma_tag_destroy(dma_buf->dma_tag);
663711bcba0SDavid C Somayajulu }
664711bcba0SDavid C Somayajulu 
665711bcba0SDavid C Somayajulu static int
qls_alloc_parent_dma_tag(qla_host_t * ha)666711bcba0SDavid C Somayajulu qls_alloc_parent_dma_tag(qla_host_t *ha)
667711bcba0SDavid C Somayajulu {
668711bcba0SDavid C Somayajulu 	int		ret;
669711bcba0SDavid C Somayajulu 	device_t	dev;
670711bcba0SDavid C Somayajulu 
671711bcba0SDavid C Somayajulu 	dev = ha->pci_dev;
672711bcba0SDavid C Somayajulu 
673711bcba0SDavid C Somayajulu         /*
674711bcba0SDavid C Somayajulu          * Allocate parent DMA Tag
675711bcba0SDavid C Somayajulu          */
676711bcba0SDavid C Somayajulu         ret = bus_dma_tag_create(
677711bcba0SDavid C Somayajulu                         bus_get_dma_tag(dev),   /* parent */
678711bcba0SDavid C Somayajulu                         1,((bus_size_t)(1ULL << 32)),/* alignment, boundary */
679711bcba0SDavid C Somayajulu                         BUS_SPACE_MAXADDR,      /* lowaddr */
680711bcba0SDavid C Somayajulu                         BUS_SPACE_MAXADDR,      /* highaddr */
681711bcba0SDavid C Somayajulu                         NULL, NULL,             /* filter, filterarg */
682711bcba0SDavid C Somayajulu                         BUS_SPACE_MAXSIZE_32BIT,/* maxsize */
683711bcba0SDavid C Somayajulu                         0,                      /* nsegments */
684711bcba0SDavid C Somayajulu                         BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
685711bcba0SDavid C Somayajulu                         0,                      /* flags */
686711bcba0SDavid C Somayajulu                         NULL, NULL,             /* lockfunc, lockarg */
687711bcba0SDavid C Somayajulu                         &ha->parent_tag);
688711bcba0SDavid C Somayajulu 
689711bcba0SDavid C Somayajulu         if (ret) {
690711bcba0SDavid C Somayajulu                 device_printf(dev, "%s: could not create parent dma tag\n",
691711bcba0SDavid C Somayajulu                         __func__);
692711bcba0SDavid C Somayajulu 		return (-1);
693711bcba0SDavid C Somayajulu         }
694711bcba0SDavid C Somayajulu 
695711bcba0SDavid C Somayajulu         ha->flags.parent_tag = 1;
696711bcba0SDavid C Somayajulu 
697711bcba0SDavid C Somayajulu 	return (0);
698711bcba0SDavid C Somayajulu }
699711bcba0SDavid C Somayajulu 
700711bcba0SDavid C Somayajulu static void
qls_free_parent_dma_tag(qla_host_t * ha)701711bcba0SDavid C Somayajulu qls_free_parent_dma_tag(qla_host_t *ha)
702711bcba0SDavid C Somayajulu {
703711bcba0SDavid C Somayajulu         if (ha->flags.parent_tag) {
704711bcba0SDavid C Somayajulu                 bus_dma_tag_destroy(ha->parent_tag);
705711bcba0SDavid C Somayajulu                 ha->flags.parent_tag = 0;
706711bcba0SDavid C Somayajulu         }
707711bcba0SDavid C Somayajulu }
708711bcba0SDavid C Somayajulu 
709711bcba0SDavid C Somayajulu /*
710711bcba0SDavid C Somayajulu  * Name: qls_init_ifnet
711711bcba0SDavid C Somayajulu  * Function: Creates the Network Device Interface and Registers it with the O.S
712711bcba0SDavid C Somayajulu  */
713711bcba0SDavid C Somayajulu 
714711bcba0SDavid C Somayajulu static void
qls_init_ifnet(device_t dev,qla_host_t * ha)715711bcba0SDavid C Somayajulu qls_init_ifnet(device_t dev, qla_host_t *ha)
716711bcba0SDavid C Somayajulu {
71764c618edSJustin Hibbits 	if_t ifp;
718711bcba0SDavid C Somayajulu 
719711bcba0SDavid C Somayajulu 	QL_DPRINT2((dev, "%s: enter\n", __func__));
720711bcba0SDavid C Somayajulu 
721711bcba0SDavid C Somayajulu 	ifp = ha->ifp = if_alloc(IFT_ETHER);
722711bcba0SDavid C Somayajulu 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
72364c618edSJustin Hibbits 	if_setbaudrate(ifp, IF_Gbps(10));
72464c618edSJustin Hibbits 	if_setinitfn(ifp, qls_init);
72564c618edSJustin Hibbits 	if_setsoftc(ifp, ha);
72664c618edSJustin Hibbits 	if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
72764c618edSJustin Hibbits 	if_setioctlfn(ifp, qls_ioctl);
72864c618edSJustin Hibbits 	if_setstartfn(ifp, qls_start);
729711bcba0SDavid C Somayajulu 
73064c618edSJustin Hibbits 	if_setsendqlen(ifp, qls_get_ifq_snd_maxlen(ha));
73164c618edSJustin Hibbits 	if_setsendqready(ifp);
732711bcba0SDavid C Somayajulu 
73364c618edSJustin Hibbits 	ha->max_frame_size = if_getmtu(ifp) + ETHER_HDR_LEN + ETHER_CRC_LEN;
734711bcba0SDavid C Somayajulu 	if (ha->max_frame_size <= MCLBYTES) {
735711bcba0SDavid C Somayajulu 		ha->msize = MCLBYTES;
736711bcba0SDavid C Somayajulu 	} else if (ha->max_frame_size <= MJUMPAGESIZE) {
737711bcba0SDavid C Somayajulu 		ha->msize = MJUMPAGESIZE;
738711bcba0SDavid C Somayajulu 	} else
739711bcba0SDavid C Somayajulu 		ha->msize = MJUM9BYTES;
740711bcba0SDavid C Somayajulu 
741711bcba0SDavid C Somayajulu 	ether_ifattach(ifp, qls_get_mac_addr(ha));
742711bcba0SDavid C Somayajulu 
74364c618edSJustin Hibbits 	if_setcapabilities(ifp, IFCAP_JUMBO_MTU);
744711bcba0SDavid C Somayajulu 
74564c618edSJustin Hibbits 	if_setcapabilitiesbit(ifp, IFCAP_HWCSUM, 0);
74664c618edSJustin Hibbits 	if_setcapabilitiesbit(ifp, IFCAP_VLAN_MTU, 0);
747711bcba0SDavid C Somayajulu 
74864c618edSJustin Hibbits 	if_setcapabilitiesbit(ifp, IFCAP_TSO4, 0);
74964c618edSJustin Hibbits 	if_setcapabilitiesbit(ifp, IFCAP_VLAN_HWTAGGING, 0);
75064c618edSJustin Hibbits 	if_setcapabilitiesbit(ifp, IFCAP_VLAN_HWTSO, 0);
75164c618edSJustin Hibbits 	if_setcapabilitiesbit(ifp, IFCAP_LINKSTATE, 0);
752711bcba0SDavid C Somayajulu 
75364c618edSJustin Hibbits 	if_setcapenable(ifp, if_getcapabilities(ifp));
754711bcba0SDavid C Somayajulu 
75564c618edSJustin Hibbits 	if_setifheaderlen(ifp, sizeof(struct ether_vlan_header));
756711bcba0SDavid C Somayajulu 
757711bcba0SDavid C Somayajulu 	ifmedia_init(&ha->media, IFM_IMASK, qls_media_change, qls_media_status);
758711bcba0SDavid C Somayajulu 
759711bcba0SDavid C Somayajulu 	ifmedia_add(&ha->media, (IFM_ETHER | qls_get_optics(ha) | IFM_FDX), 0,
760711bcba0SDavid C Somayajulu 		NULL);
761711bcba0SDavid C Somayajulu 	ifmedia_add(&ha->media, (IFM_ETHER | IFM_AUTO), 0, NULL);
762711bcba0SDavid C Somayajulu 
763711bcba0SDavid C Somayajulu 	ifmedia_set(&ha->media, (IFM_ETHER | IFM_AUTO));
764711bcba0SDavid C Somayajulu 
765711bcba0SDavid C Somayajulu 	QL_DPRINT2((dev, "%s: exit\n", __func__));
766711bcba0SDavid C Somayajulu 
767711bcba0SDavid C Somayajulu 	return;
768711bcba0SDavid C Somayajulu }
769711bcba0SDavid C Somayajulu 
770711bcba0SDavid C Somayajulu static void
qls_init_locked(qla_host_t * ha)771711bcba0SDavid C Somayajulu qls_init_locked(qla_host_t *ha)
772711bcba0SDavid C Somayajulu {
77364c618edSJustin Hibbits 	if_t ifp = ha->ifp;
774711bcba0SDavid C Somayajulu 
775711bcba0SDavid C Somayajulu 	qls_stop(ha);
776711bcba0SDavid C Somayajulu 
777711bcba0SDavid C Somayajulu 	qls_flush_xmt_bufs(ha);
778711bcba0SDavid C Somayajulu 
779711bcba0SDavid C Somayajulu 	if (qls_alloc_rcv_bufs(ha) != 0)
780711bcba0SDavid C Somayajulu 		return;
781711bcba0SDavid C Somayajulu 
782711bcba0SDavid C Somayajulu 	if (qls_config_lro(ha))
783711bcba0SDavid C Somayajulu 		return;
784711bcba0SDavid C Somayajulu 
78564c618edSJustin Hibbits 	bcopy(if_getlladdr(ha->ifp), ha->mac_addr, ETHER_ADDR_LEN);
786711bcba0SDavid C Somayajulu 
78764c618edSJustin Hibbits 	if_sethwassist(ifp, CSUM_IP);
78864c618edSJustin Hibbits 	if_sethwassistbits(ifp, CSUM_TCP, 0);
78964c618edSJustin Hibbits 	if_sethwassistbits(ifp, CSUM_UDP, 0);
79064c618edSJustin Hibbits 	if_sethwassistbits(ifp, CSUM_TSO, 0);
791711bcba0SDavid C Somayajulu 
792711bcba0SDavid C Somayajulu  	if (qls_init_hw_if(ha) == 0) {
793711bcba0SDavid C Somayajulu 		ifp = ha->ifp;
79464c618edSJustin Hibbits 		if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0);
79564c618edSJustin Hibbits 		if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
796711bcba0SDavid C Somayajulu 		ha->flags.qla_watchdog_pause = 0;
797711bcba0SDavid C Somayajulu 	}
798711bcba0SDavid C Somayajulu 
799711bcba0SDavid C Somayajulu 	return;
800711bcba0SDavid C Somayajulu }
801711bcba0SDavid C Somayajulu 
802711bcba0SDavid C Somayajulu static void
qls_init(void * arg)803711bcba0SDavid C Somayajulu qls_init(void *arg)
804711bcba0SDavid C Somayajulu {
805711bcba0SDavid C Somayajulu 	qla_host_t *ha;
806711bcba0SDavid C Somayajulu 
807711bcba0SDavid C Somayajulu 	ha = (qla_host_t *)arg;
808711bcba0SDavid C Somayajulu 
809711bcba0SDavid C Somayajulu 	QL_DPRINT2((ha->pci_dev, "%s: enter\n", __func__));
810711bcba0SDavid C Somayajulu 
811711bcba0SDavid C Somayajulu 	(void)QLA_LOCK(ha, __func__, 0);
812711bcba0SDavid C Somayajulu 	qls_init_locked(ha);
813711bcba0SDavid C Somayajulu 	QLA_UNLOCK(ha, __func__);
814711bcba0SDavid C Somayajulu 
815711bcba0SDavid C Somayajulu 	QL_DPRINT2((ha->pci_dev, "%s: exit\n", __func__));
816711bcba0SDavid C Somayajulu }
817711bcba0SDavid C Somayajulu 
8186dfd0870SGleb Smirnoff static u_int
qls_copy_maddr(void * arg,struct sockaddr_dl * sdl,u_int mcnt)8196dfd0870SGleb Smirnoff qls_copy_maddr(void *arg, struct sockaddr_dl *sdl, u_int mcnt)
8206dfd0870SGleb Smirnoff {
8216dfd0870SGleb Smirnoff 	uint8_t *mta = arg;
8226dfd0870SGleb Smirnoff 
8236dfd0870SGleb Smirnoff 	if (mcnt == Q8_MAX_NUM_MULTICAST_ADDRS)
8246dfd0870SGleb Smirnoff 		return (0);
8256dfd0870SGleb Smirnoff 
8266dfd0870SGleb Smirnoff 	bcopy(LLADDR(sdl), &mta[mcnt * Q8_MAC_ADDR_LEN], Q8_MAC_ADDR_LEN);
8276dfd0870SGleb Smirnoff 
8286dfd0870SGleb Smirnoff 	return (1);
8296dfd0870SGleb Smirnoff }
8306dfd0870SGleb Smirnoff 
831711bcba0SDavid C Somayajulu static void
qls_set_multi(qla_host_t * ha,uint32_t add_multi)832711bcba0SDavid C Somayajulu qls_set_multi(qla_host_t *ha, uint32_t add_multi)
833711bcba0SDavid C Somayajulu {
834711bcba0SDavid C Somayajulu 	uint8_t mta[Q8_MAX_NUM_MULTICAST_ADDRS * Q8_MAC_ADDR_LEN];
83564c618edSJustin Hibbits 	if_t ifp = ha->ifp;
8366dfd0870SGleb Smirnoff 	int mcnt;
837711bcba0SDavid C Somayajulu 
8386dfd0870SGleb Smirnoff 	mcnt = if_foreach_llmaddr(ifp, qls_copy_maddr, mta);
839711bcba0SDavid C Somayajulu 
840711bcba0SDavid C Somayajulu 	if (QLA_LOCK(ha, __func__, 1) == 0) {
841711bcba0SDavid C Somayajulu 		qls_hw_set_multi(ha, mta, mcnt, add_multi);
842711bcba0SDavid C Somayajulu 		QLA_UNLOCK(ha, __func__);
843711bcba0SDavid C Somayajulu 	}
844711bcba0SDavid C Somayajulu 
845711bcba0SDavid C Somayajulu 	return;
846711bcba0SDavid C Somayajulu }
847711bcba0SDavid C Somayajulu 
848711bcba0SDavid C Somayajulu static int
qls_ioctl(if_t ifp,u_long cmd,caddr_t data)84964c618edSJustin Hibbits qls_ioctl(if_t ifp, u_long cmd, caddr_t data)
850711bcba0SDavid C Somayajulu {
851711bcba0SDavid C Somayajulu 	int ret = 0;
852711bcba0SDavid C Somayajulu 	struct ifreq *ifr = (struct ifreq *)data;
853618aa8cdSJohn Baldwin #ifdef INET
854711bcba0SDavid C Somayajulu 	struct ifaddr *ifa = (struct ifaddr *)data;
855618aa8cdSJohn Baldwin #endif
856711bcba0SDavid C Somayajulu 	qla_host_t *ha;
857711bcba0SDavid C Somayajulu 
85864c618edSJustin Hibbits 	ha = (qla_host_t *)if_getsoftc(ifp);
859711bcba0SDavid C Somayajulu 
860711bcba0SDavid C Somayajulu 	switch (cmd) {
861711bcba0SDavid C Somayajulu 	case SIOCSIFADDR:
862711bcba0SDavid C Somayajulu 		QL_DPRINT4((ha->pci_dev, "%s: SIOCSIFADDR (0x%lx)\n",
863711bcba0SDavid C Somayajulu 			__func__, cmd));
864711bcba0SDavid C Somayajulu 
865618aa8cdSJohn Baldwin #ifdef INET
866711bcba0SDavid C Somayajulu 		if (ifa->ifa_addr->sa_family == AF_INET) {
86764c618edSJustin Hibbits 			if_setflagbits(ifp, IFF_UP, 0);
86864c618edSJustin Hibbits 			if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING)) {
869711bcba0SDavid C Somayajulu 				(void)QLA_LOCK(ha, __func__, 0);
870711bcba0SDavid C Somayajulu 				qls_init_locked(ha);
871711bcba0SDavid C Somayajulu 				QLA_UNLOCK(ha, __func__);
872711bcba0SDavid C Somayajulu 			}
873711bcba0SDavid C Somayajulu 			QL_DPRINT4((ha->pci_dev,
874711bcba0SDavid C Somayajulu 				"%s: SIOCSIFADDR (0x%lx) ipv4 [0x%08x]\n",
875711bcba0SDavid C Somayajulu 				__func__, cmd,
876711bcba0SDavid C Somayajulu 				ntohl(IA_SIN(ifa)->sin_addr.s_addr)));
877711bcba0SDavid C Somayajulu 
878711bcba0SDavid C Somayajulu 			arp_ifinit(ifp, ifa);
879618aa8cdSJohn Baldwin 			break;
880711bcba0SDavid C Somayajulu 		}
881618aa8cdSJohn Baldwin #endif
882618aa8cdSJohn Baldwin 		ether_ioctl(ifp, cmd, data);
883711bcba0SDavid C Somayajulu 		break;
884711bcba0SDavid C Somayajulu 
885711bcba0SDavid C Somayajulu 	case SIOCSIFMTU:
886711bcba0SDavid C Somayajulu 		QL_DPRINT4((ha->pci_dev, "%s: SIOCSIFMTU (0x%lx)\n",
887711bcba0SDavid C Somayajulu 			__func__, cmd));
888711bcba0SDavid C Somayajulu 
889711bcba0SDavid C Somayajulu 		if (ifr->ifr_mtu > QLA_MAX_MTU) {
890711bcba0SDavid C Somayajulu 			ret = EINVAL;
891711bcba0SDavid C Somayajulu 		} else {
892711bcba0SDavid C Somayajulu 			(void) QLA_LOCK(ha, __func__, 0);
893711bcba0SDavid C Somayajulu 
89464c618edSJustin Hibbits 			if_setmtu(ifp, ifr->ifr_mtu);
895711bcba0SDavid C Somayajulu 			ha->max_frame_size =
89664c618edSJustin Hibbits 				if_getmtu(ifp) + ETHER_HDR_LEN + ETHER_CRC_LEN;
897711bcba0SDavid C Somayajulu 
898711bcba0SDavid C Somayajulu 			QLA_UNLOCK(ha, __func__);
899711bcba0SDavid C Somayajulu 
900711bcba0SDavid C Somayajulu 			if (ret)
901711bcba0SDavid C Somayajulu 				ret = EINVAL;
902711bcba0SDavid C Somayajulu 		}
903711bcba0SDavid C Somayajulu 
904711bcba0SDavid C Somayajulu 		break;
905711bcba0SDavid C Somayajulu 
906711bcba0SDavid C Somayajulu 	case SIOCSIFFLAGS:
907711bcba0SDavid C Somayajulu 		QL_DPRINT4((ha->pci_dev, "%s: SIOCSIFFLAGS (0x%lx)\n",
908711bcba0SDavid C Somayajulu 			__func__, cmd));
909711bcba0SDavid C Somayajulu 
910711bcba0SDavid C Somayajulu 		(void)QLA_LOCK(ha, __func__, 0);
911711bcba0SDavid C Somayajulu 
91264c618edSJustin Hibbits 		if (if_getflags(ifp) & IFF_UP) {
91364c618edSJustin Hibbits 			if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING)) {
91464c618edSJustin Hibbits 				if ((if_getflags(ifp) ^ ha->if_flags) &
915711bcba0SDavid C Somayajulu 					IFF_PROMISC) {
916711bcba0SDavid C Somayajulu 					ret = qls_set_promisc(ha);
91764c618edSJustin Hibbits 				} else if ((if_getflags(ifp) ^ ha->if_flags) &
918711bcba0SDavid C Somayajulu 					IFF_ALLMULTI) {
919711bcba0SDavid C Somayajulu 					ret = qls_set_allmulti(ha);
920711bcba0SDavid C Somayajulu 				}
921711bcba0SDavid C Somayajulu 			} else {
92264c618edSJustin Hibbits 				ha->max_frame_size = if_getmtu(ifp) +
923711bcba0SDavid C Somayajulu 					ETHER_HDR_LEN + ETHER_CRC_LEN;
924711bcba0SDavid C Somayajulu 				qls_init_locked(ha);
925711bcba0SDavid C Somayajulu 			}
926711bcba0SDavid C Somayajulu 		} else {
92764c618edSJustin Hibbits 			if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
928711bcba0SDavid C Somayajulu 				qls_stop(ha);
92964c618edSJustin Hibbits 			ha->if_flags = if_getflags(ifp);
930711bcba0SDavid C Somayajulu 		}
931711bcba0SDavid C Somayajulu 
932711bcba0SDavid C Somayajulu 		QLA_UNLOCK(ha, __func__);
933711bcba0SDavid C Somayajulu 		break;
934711bcba0SDavid C Somayajulu 
935711bcba0SDavid C Somayajulu 	case SIOCADDMULTI:
936711bcba0SDavid C Somayajulu 		QL_DPRINT4((ha->pci_dev,
937711bcba0SDavid C Somayajulu 			"%s: %s (0x%lx)\n", __func__, "SIOCADDMULTI", cmd));
938711bcba0SDavid C Somayajulu 
93964c618edSJustin Hibbits 		if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
940711bcba0SDavid C Somayajulu 			qls_set_multi(ha, 1);
941711bcba0SDavid C Somayajulu 		}
942711bcba0SDavid C Somayajulu 		break;
943711bcba0SDavid C Somayajulu 
944711bcba0SDavid C Somayajulu 	case SIOCDELMULTI:
945711bcba0SDavid C Somayajulu 		QL_DPRINT4((ha->pci_dev,
946711bcba0SDavid C Somayajulu 			"%s: %s (0x%lx)\n", __func__, "SIOCDELMULTI", cmd));
947711bcba0SDavid C Somayajulu 
94864c618edSJustin Hibbits 		if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
949711bcba0SDavid C Somayajulu 			qls_set_multi(ha, 0);
950711bcba0SDavid C Somayajulu 		}
951711bcba0SDavid C Somayajulu 		break;
952711bcba0SDavid C Somayajulu 
953711bcba0SDavid C Somayajulu 	case SIOCSIFMEDIA:
954711bcba0SDavid C Somayajulu 	case SIOCGIFMEDIA:
955711bcba0SDavid C Somayajulu 		QL_DPRINT4((ha->pci_dev,
956711bcba0SDavid C Somayajulu 			"%s: SIOCSIFMEDIA/SIOCGIFMEDIA (0x%lx)\n",
957711bcba0SDavid C Somayajulu 			__func__, cmd));
958711bcba0SDavid C Somayajulu 		ret = ifmedia_ioctl(ifp, ifr, &ha->media, cmd);
959711bcba0SDavid C Somayajulu 		break;
960711bcba0SDavid C Somayajulu 
961711bcba0SDavid C Somayajulu 	case SIOCSIFCAP:
962711bcba0SDavid C Somayajulu 	{
96364c618edSJustin Hibbits 		int mask = ifr->ifr_reqcap ^ if_getcapenable(ifp);
964711bcba0SDavid C Somayajulu 
965711bcba0SDavid C Somayajulu 		QL_DPRINT4((ha->pci_dev, "%s: SIOCSIFCAP (0x%lx)\n",
966711bcba0SDavid C Somayajulu 			__func__, cmd));
967711bcba0SDavid C Somayajulu 
968711bcba0SDavid C Somayajulu 		if (mask & IFCAP_HWCSUM)
96964c618edSJustin Hibbits 			if_togglecapenable(ifp, IFCAP_HWCSUM);
970711bcba0SDavid C Somayajulu 		if (mask & IFCAP_TSO4)
97164c618edSJustin Hibbits 			if_togglecapenable(ifp, IFCAP_TSO4);
972711bcba0SDavid C Somayajulu 		if (mask & IFCAP_VLAN_HWTAGGING)
97364c618edSJustin Hibbits 			if_togglecapenable(ifp, IFCAP_VLAN_HWTAGGING);
974711bcba0SDavid C Somayajulu 		if (mask & IFCAP_VLAN_HWTSO)
97564c618edSJustin Hibbits 			if_togglecapenable(ifp, IFCAP_VLAN_HWTSO);
976711bcba0SDavid C Somayajulu 
97764c618edSJustin Hibbits 		if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING))
978711bcba0SDavid C Somayajulu 			qls_init(ha);
979711bcba0SDavid C Somayajulu 
980711bcba0SDavid C Somayajulu 		VLAN_CAPABILITIES(ifp);
981711bcba0SDavid C Somayajulu 		break;
982711bcba0SDavid C Somayajulu 	}
983711bcba0SDavid C Somayajulu 
984711bcba0SDavid C Somayajulu 	default:
985711bcba0SDavid C Somayajulu 		QL_DPRINT4((ha->pci_dev, "%s: default (0x%lx)\n",
986711bcba0SDavid C Somayajulu 			__func__, cmd));
987711bcba0SDavid C Somayajulu 		ret = ether_ioctl(ifp, cmd, data);
988711bcba0SDavid C Somayajulu 		break;
989711bcba0SDavid C Somayajulu 	}
990711bcba0SDavid C Somayajulu 
991711bcba0SDavid C Somayajulu 	return (ret);
992711bcba0SDavid C Somayajulu }
993711bcba0SDavid C Somayajulu 
994711bcba0SDavid C Somayajulu static int
qls_media_change(if_t ifp)99564c618edSJustin Hibbits qls_media_change(if_t ifp)
996711bcba0SDavid C Somayajulu {
997711bcba0SDavid C Somayajulu 	qla_host_t *ha;
998711bcba0SDavid C Somayajulu 	struct ifmedia *ifm;
999711bcba0SDavid C Somayajulu 	int ret = 0;
1000711bcba0SDavid C Somayajulu 
100164c618edSJustin Hibbits 	ha = (qla_host_t *)if_getsoftc(ifp);
1002711bcba0SDavid C Somayajulu 
1003711bcba0SDavid C Somayajulu 	QL_DPRINT2((ha->pci_dev, "%s: enter\n", __func__));
1004711bcba0SDavid C Somayajulu 
1005711bcba0SDavid C Somayajulu 	ifm = &ha->media;
1006711bcba0SDavid C Somayajulu 
1007711bcba0SDavid C Somayajulu 	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
1008711bcba0SDavid C Somayajulu 		ret = EINVAL;
1009711bcba0SDavid C Somayajulu 
1010711bcba0SDavid C Somayajulu 	QL_DPRINT2((ha->pci_dev, "%s: exit\n", __func__));
1011711bcba0SDavid C Somayajulu 
1012711bcba0SDavid C Somayajulu 	return (ret);
1013711bcba0SDavid C Somayajulu }
1014711bcba0SDavid C Somayajulu 
1015711bcba0SDavid C Somayajulu static void
qls_media_status(if_t ifp,struct ifmediareq * ifmr)101664c618edSJustin Hibbits qls_media_status(if_t ifp, struct ifmediareq *ifmr)
1017711bcba0SDavid C Somayajulu {
1018711bcba0SDavid C Somayajulu 	qla_host_t *ha;
1019711bcba0SDavid C Somayajulu 
102064c618edSJustin Hibbits 	ha = (qla_host_t *)if_getsoftc(ifp);
1021711bcba0SDavid C Somayajulu 
1022711bcba0SDavid C Somayajulu 	QL_DPRINT2((ha->pci_dev, "%s: enter\n", __func__));
1023711bcba0SDavid C Somayajulu 
1024711bcba0SDavid C Somayajulu 	ifmr->ifm_status = IFM_AVALID;
1025711bcba0SDavid C Somayajulu 	ifmr->ifm_active = IFM_ETHER;
1026711bcba0SDavid C Somayajulu 
1027711bcba0SDavid C Somayajulu 	qls_update_link_state(ha);
1028711bcba0SDavid C Somayajulu 	if (ha->link_up) {
1029711bcba0SDavid C Somayajulu 		ifmr->ifm_status |= IFM_ACTIVE;
1030711bcba0SDavid C Somayajulu 		ifmr->ifm_active |= (IFM_FDX | qls_get_optics(ha));
1031711bcba0SDavid C Somayajulu 	}
1032711bcba0SDavid C Somayajulu 
1033711bcba0SDavid C Somayajulu 	QL_DPRINT2((ha->pci_dev, "%s: exit (%s)\n", __func__,\
1034711bcba0SDavid C Somayajulu 		(ha->link_up ? "link_up" : "link_down")));
1035711bcba0SDavid C Somayajulu 
1036711bcba0SDavid C Somayajulu 	return;
1037711bcba0SDavid C Somayajulu }
1038711bcba0SDavid C Somayajulu 
1039711bcba0SDavid C Somayajulu static void
qls_start(if_t ifp)104064c618edSJustin Hibbits qls_start(if_t ifp)
1041711bcba0SDavid C Somayajulu {
1042711bcba0SDavid C Somayajulu 	int		i, ret = 0;
1043711bcba0SDavid C Somayajulu 	struct mbuf	*m_head;
104464c618edSJustin Hibbits 	qla_host_t	*ha = (qla_host_t *)if_getsoftc(ifp);
1045711bcba0SDavid C Somayajulu 
1046711bcba0SDavid C Somayajulu 	QL_DPRINT8((ha->pci_dev, "%s: enter\n", __func__));
1047711bcba0SDavid C Somayajulu 
1048711bcba0SDavid C Somayajulu 	if (!mtx_trylock(&ha->tx_lock)) {
1049711bcba0SDavid C Somayajulu 		QL_DPRINT8((ha->pci_dev,
1050711bcba0SDavid C Somayajulu 			"%s: mtx_trylock(&ha->tx_lock) failed\n", __func__));
1051711bcba0SDavid C Somayajulu 		return;
1052711bcba0SDavid C Somayajulu 	}
1053711bcba0SDavid C Somayajulu 
105464c618edSJustin Hibbits 	if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) ==
1055711bcba0SDavid C Somayajulu 		IFF_DRV_RUNNING) {
1056711bcba0SDavid C Somayajulu 		for (i = 0; i < ha->num_tx_rings; i++) {
1057711bcba0SDavid C Somayajulu 			ret |= qls_hw_tx_done(ha, i);
1058711bcba0SDavid C Somayajulu 		}
1059711bcba0SDavid C Somayajulu 
1060711bcba0SDavid C Somayajulu 		if (ret == 0)
106164c618edSJustin Hibbits 			if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
1062711bcba0SDavid C Somayajulu 	}
1063711bcba0SDavid C Somayajulu 
106464c618edSJustin Hibbits 	if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
1065711bcba0SDavid C Somayajulu 		IFF_DRV_RUNNING) {
1066711bcba0SDavid C Somayajulu 		QL_DPRINT8((ha->pci_dev, "%s: !IFF_DRV_RUNNING\n", __func__));
1067711bcba0SDavid C Somayajulu 		QLA_TX_UNLOCK(ha);
1068711bcba0SDavid C Somayajulu 		return;
1069711bcba0SDavid C Somayajulu 	}
1070711bcba0SDavid C Somayajulu 
1071711bcba0SDavid C Somayajulu 	if (!ha->link_up) {
1072711bcba0SDavid C Somayajulu 		qls_update_link_state(ha);
1073711bcba0SDavid C Somayajulu 		if (!ha->link_up) {
1074711bcba0SDavid C Somayajulu 			QL_DPRINT8((ha->pci_dev, "%s: link down\n", __func__));
1075711bcba0SDavid C Somayajulu 			QLA_TX_UNLOCK(ha);
1076711bcba0SDavid C Somayajulu 			return;
1077711bcba0SDavid C Somayajulu 		}
1078711bcba0SDavid C Somayajulu 	}
1079711bcba0SDavid C Somayajulu 
108064c618edSJustin Hibbits 	while (!if_sendq_empty(ifp)) {
108164c618edSJustin Hibbits 		m_head = if_dequeue(ifp);
1082711bcba0SDavid C Somayajulu 
1083711bcba0SDavid C Somayajulu 		if (m_head == NULL) {
1084711bcba0SDavid C Somayajulu 			QL_DPRINT8((ha->pci_dev, "%s: m_head == NULL\n",
1085711bcba0SDavid C Somayajulu 				__func__));
1086711bcba0SDavid C Somayajulu 			break;
1087711bcba0SDavid C Somayajulu 		}
1088711bcba0SDavid C Somayajulu 
1089711bcba0SDavid C Somayajulu 		if (qls_send(ha, &m_head)) {
1090711bcba0SDavid C Somayajulu 			if (m_head == NULL)
1091711bcba0SDavid C Somayajulu 				break;
1092711bcba0SDavid C Somayajulu 			QL_DPRINT8((ha->pci_dev, "%s: PREPEND\n", __func__));
109364c618edSJustin Hibbits 			if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0);
109464c618edSJustin Hibbits 			if_sendq_prepend(ifp, m_head);
1095711bcba0SDavid C Somayajulu 			break;
1096711bcba0SDavid C Somayajulu 		}
1097711bcba0SDavid C Somayajulu 		/* Send a copy of the frame to the BPF listener */
1098711bcba0SDavid C Somayajulu 		ETHER_BPF_MTAP(ifp, m_head);
1099711bcba0SDavid C Somayajulu 	}
1100711bcba0SDavid C Somayajulu 
1101711bcba0SDavid C Somayajulu 	QLA_TX_UNLOCK(ha);
1102711bcba0SDavid C Somayajulu 	QL_DPRINT8((ha->pci_dev, "%s: exit\n", __func__));
1103711bcba0SDavid C Somayajulu 	return;
1104711bcba0SDavid C Somayajulu }
1105711bcba0SDavid C Somayajulu 
1106711bcba0SDavid C Somayajulu static int
qls_send(qla_host_t * ha,struct mbuf ** m_headp)1107711bcba0SDavid C Somayajulu qls_send(qla_host_t *ha, struct mbuf **m_headp)
1108711bcba0SDavid C Somayajulu {
1109711bcba0SDavid C Somayajulu 	bus_dma_segment_t	segs[QLA_MAX_SEGMENTS];
1110711bcba0SDavid C Somayajulu 	bus_dmamap_t		map;
1111711bcba0SDavid C Somayajulu 	int			nsegs;
1112711bcba0SDavid C Somayajulu 	int			ret = -1;
1113711bcba0SDavid C Somayajulu 	uint32_t		tx_idx;
1114711bcba0SDavid C Somayajulu 	struct mbuf		*m_head = *m_headp;
1115711bcba0SDavid C Somayajulu 	uint32_t		txr_idx = 0;
1116711bcba0SDavid C Somayajulu 
1117711bcba0SDavid C Somayajulu 	QL_DPRINT8((ha->pci_dev, "%s: enter\n", __func__));
1118711bcba0SDavid C Somayajulu 
1119c2529042SHans Petter Selasky 	/* check if flowid is set */
1120c2529042SHans Petter Selasky 	if (M_HASHTYPE_GET(m_head) != M_HASHTYPE_NONE)
1121711bcba0SDavid C Somayajulu 		txr_idx = m_head->m_pkthdr.flowid & (ha->num_tx_rings - 1);
1122711bcba0SDavid C Somayajulu 
1123711bcba0SDavid C Somayajulu 	tx_idx = ha->tx_ring[txr_idx].txr_next;
1124711bcba0SDavid C Somayajulu 
1125711bcba0SDavid C Somayajulu 	map = ha->tx_ring[txr_idx].tx_buf[tx_idx].map;
1126711bcba0SDavid C Somayajulu 
1127711bcba0SDavid C Somayajulu 	ret = bus_dmamap_load_mbuf_sg(ha->tx_tag, map, m_head, segs, &nsegs,
1128711bcba0SDavid C Somayajulu 			BUS_DMA_NOWAIT);
1129711bcba0SDavid C Somayajulu 
1130711bcba0SDavid C Somayajulu 	if (ret == EFBIG) {
1131711bcba0SDavid C Somayajulu 		struct mbuf *m;
1132711bcba0SDavid C Somayajulu 
1133711bcba0SDavid C Somayajulu 		QL_DPRINT8((ha->pci_dev, "%s: EFBIG [%d]\n", __func__,
1134711bcba0SDavid C Somayajulu 			m_head->m_pkthdr.len));
1135711bcba0SDavid C Somayajulu 
1136b8c83a19SGleb Smirnoff 		m = m_defrag(m_head, M_NOWAIT);
1137711bcba0SDavid C Somayajulu 		if (m == NULL) {
1138711bcba0SDavid C Somayajulu 			ha->err_tx_defrag++;
1139711bcba0SDavid C Somayajulu 			m_freem(m_head);
1140711bcba0SDavid C Somayajulu 			*m_headp = NULL;
1141711bcba0SDavid C Somayajulu 			device_printf(ha->pci_dev,
1142711bcba0SDavid C Somayajulu 				"%s: m_defrag() = NULL [%d]\n",
1143711bcba0SDavid C Somayajulu 				__func__, ret);
1144711bcba0SDavid C Somayajulu 			return (ENOBUFS);
1145711bcba0SDavid C Somayajulu 		}
1146711bcba0SDavid C Somayajulu 		m_head = m;
1147711bcba0SDavid C Somayajulu 		*m_headp = m_head;
1148711bcba0SDavid C Somayajulu 
1149711bcba0SDavid C Somayajulu 		if ((ret = bus_dmamap_load_mbuf_sg(ha->tx_tag, map, m_head,
1150711bcba0SDavid C Somayajulu 					segs, &nsegs, BUS_DMA_NOWAIT))) {
1151711bcba0SDavid C Somayajulu 			ha->err_tx_dmamap_load++;
1152711bcba0SDavid C Somayajulu 
1153711bcba0SDavid C Somayajulu 			device_printf(ha->pci_dev,
1154711bcba0SDavid C Somayajulu 				"%s: bus_dmamap_load_mbuf_sg failed0[%d, %d]\n",
1155711bcba0SDavid C Somayajulu 				__func__, ret, m_head->m_pkthdr.len);
1156711bcba0SDavid C Somayajulu 
1157711bcba0SDavid C Somayajulu 			if (ret != ENOMEM) {
1158711bcba0SDavid C Somayajulu 				m_freem(m_head);
1159711bcba0SDavid C Somayajulu 				*m_headp = NULL;
1160711bcba0SDavid C Somayajulu 			}
1161711bcba0SDavid C Somayajulu 			return (ret);
1162711bcba0SDavid C Somayajulu 		}
1163711bcba0SDavid C Somayajulu 
1164711bcba0SDavid C Somayajulu 	} else if (ret) {
1165711bcba0SDavid C Somayajulu 		ha->err_tx_dmamap_load++;
1166711bcba0SDavid C Somayajulu 
1167711bcba0SDavid C Somayajulu 		device_printf(ha->pci_dev,
1168711bcba0SDavid C Somayajulu 			"%s: bus_dmamap_load_mbuf_sg failed1[%d, %d]\n",
1169711bcba0SDavid C Somayajulu 			__func__, ret, m_head->m_pkthdr.len);
1170711bcba0SDavid C Somayajulu 
1171711bcba0SDavid C Somayajulu 		if (ret != ENOMEM) {
1172711bcba0SDavid C Somayajulu 			m_freem(m_head);
1173711bcba0SDavid C Somayajulu 			*m_headp = NULL;
1174711bcba0SDavid C Somayajulu 		}
1175711bcba0SDavid C Somayajulu 		return (ret);
1176711bcba0SDavid C Somayajulu 	}
1177711bcba0SDavid C Somayajulu 
1178711bcba0SDavid C Somayajulu 	QL_ASSERT(ha, (nsegs != 0), ("qls_send: empty packet"));
1179711bcba0SDavid C Somayajulu 
1180711bcba0SDavid C Somayajulu 	bus_dmamap_sync(ha->tx_tag, map, BUS_DMASYNC_PREWRITE);
1181711bcba0SDavid C Somayajulu 
1182711bcba0SDavid C Somayajulu         if (!(ret = qls_hw_send(ha, segs, nsegs, tx_idx, m_head, txr_idx))) {
1183711bcba0SDavid C Somayajulu 		ha->tx_ring[txr_idx].count++;
1184711bcba0SDavid C Somayajulu 		ha->tx_ring[txr_idx].tx_buf[tx_idx].m_head = m_head;
1185711bcba0SDavid C Somayajulu 		ha->tx_ring[txr_idx].tx_buf[tx_idx].map = map;
1186711bcba0SDavid C Somayajulu 	} else {
1187711bcba0SDavid C Somayajulu 		if (ret == EINVAL) {
1188711bcba0SDavid C Somayajulu 			if (m_head)
1189711bcba0SDavid C Somayajulu 				m_freem(m_head);
1190711bcba0SDavid C Somayajulu 			*m_headp = NULL;
1191711bcba0SDavid C Somayajulu 		}
1192711bcba0SDavid C Somayajulu 	}
1193711bcba0SDavid C Somayajulu 
1194711bcba0SDavid C Somayajulu 	QL_DPRINT8((ha->pci_dev, "%s: exit\n", __func__));
1195711bcba0SDavid C Somayajulu 	return (ret);
1196711bcba0SDavid C Somayajulu }
1197711bcba0SDavid C Somayajulu 
1198711bcba0SDavid C Somayajulu static void
qls_stop(qla_host_t * ha)1199711bcba0SDavid C Somayajulu qls_stop(qla_host_t *ha)
1200711bcba0SDavid C Somayajulu {
120164c618edSJustin Hibbits 	if_t ifp = ha->ifp;
1202711bcba0SDavid C Somayajulu 
120364c618edSJustin Hibbits 	if_setdrvflagbits(ifp, 0, (IFF_DRV_OACTIVE | IFF_DRV_RUNNING));
1204711bcba0SDavid C Somayajulu 
1205711bcba0SDavid C Somayajulu 	ha->flags.qla_watchdog_pause = 1;
1206711bcba0SDavid C Somayajulu 
1207711bcba0SDavid C Somayajulu 	while (!ha->qla_watchdog_paused)
1208711bcba0SDavid C Somayajulu 		qls_mdelay(__func__, 1);
1209711bcba0SDavid C Somayajulu 
1210711bcba0SDavid C Somayajulu 	qls_del_hw_if(ha);
1211711bcba0SDavid C Somayajulu 
1212711bcba0SDavid C Somayajulu 	qls_free_lro(ha);
1213711bcba0SDavid C Somayajulu 
1214711bcba0SDavid C Somayajulu 	qls_flush_xmt_bufs(ha);
1215711bcba0SDavid C Somayajulu 	qls_free_rcv_bufs(ha);
1216711bcba0SDavid C Somayajulu 
1217711bcba0SDavid C Somayajulu 	return;
1218711bcba0SDavid C Somayajulu }
1219711bcba0SDavid C Somayajulu 
1220711bcba0SDavid C Somayajulu /*
1221711bcba0SDavid C Somayajulu  * Buffer Management Functions for Transmit and Receive Rings
1222711bcba0SDavid C Somayajulu  */
1223711bcba0SDavid C Somayajulu /*
1224711bcba0SDavid C Somayajulu  * Release mbuf after it sent on the wire
1225711bcba0SDavid C Somayajulu  */
1226711bcba0SDavid C Somayajulu static void
qls_flush_tx_buf(qla_host_t * ha,qla_tx_buf_t * txb)1227711bcba0SDavid C Somayajulu qls_flush_tx_buf(qla_host_t *ha, qla_tx_buf_t *txb)
1228711bcba0SDavid C Somayajulu {
1229711bcba0SDavid C Somayajulu 	QL_DPRINT2((ha->pci_dev, "%s: enter\n", __func__));
1230711bcba0SDavid C Somayajulu 
1231711bcba0SDavid C Somayajulu 	if (txb->m_head) {
1232711bcba0SDavid C Somayajulu 		bus_dmamap_unload(ha->tx_tag, txb->map);
1233711bcba0SDavid C Somayajulu 
1234711bcba0SDavid C Somayajulu 		m_freem(txb->m_head);
1235711bcba0SDavid C Somayajulu 		txb->m_head = NULL;
1236711bcba0SDavid C Somayajulu 	}
1237711bcba0SDavid C Somayajulu 
1238711bcba0SDavid C Somayajulu 	QL_DPRINT2((ha->pci_dev, "%s: exit\n", __func__));
1239711bcba0SDavid C Somayajulu }
1240711bcba0SDavid C Somayajulu 
1241711bcba0SDavid C Somayajulu static void
qls_flush_xmt_bufs(qla_host_t * ha)1242711bcba0SDavid C Somayajulu qls_flush_xmt_bufs(qla_host_t *ha)
1243711bcba0SDavid C Somayajulu {
1244711bcba0SDavid C Somayajulu 	int		i, j;
1245711bcba0SDavid C Somayajulu 
1246711bcba0SDavid C Somayajulu 	for (j = 0; j < ha->num_tx_rings; j++) {
1247711bcba0SDavid C Somayajulu 		for (i = 0; i < NUM_TX_DESCRIPTORS; i++)
1248711bcba0SDavid C Somayajulu 			qls_flush_tx_buf(ha, &ha->tx_ring[j].tx_buf[i]);
1249711bcba0SDavid C Somayajulu 	}
1250711bcba0SDavid C Somayajulu 
1251711bcba0SDavid C Somayajulu 	return;
1252711bcba0SDavid C Somayajulu }
1253711bcba0SDavid C Somayajulu 
1254711bcba0SDavid C Somayajulu static int
qls_alloc_rcv_mbufs(qla_host_t * ha,int r)1255711bcba0SDavid C Somayajulu qls_alloc_rcv_mbufs(qla_host_t *ha, int r)
1256711bcba0SDavid C Somayajulu {
1257711bcba0SDavid C Somayajulu 	int			i, j, ret = 0;
1258711bcba0SDavid C Somayajulu 	qla_rx_buf_t		*rxb;
1259711bcba0SDavid C Somayajulu 	qla_rx_ring_t		*rx_ring;
1260711bcba0SDavid C Somayajulu 	volatile q81_bq_addr_e_t *sbq_e;
1261711bcba0SDavid C Somayajulu 
1262711bcba0SDavid C Somayajulu 	rx_ring = &ha->rx_ring[r];
1263711bcba0SDavid C Somayajulu 
1264711bcba0SDavid C Somayajulu 	for (i = 0; i < NUM_RX_DESCRIPTORS; i++) {
1265711bcba0SDavid C Somayajulu 		rxb = &rx_ring->rx_buf[i];
1266711bcba0SDavid C Somayajulu 
1267711bcba0SDavid C Somayajulu 		ret = bus_dmamap_create(ha->rx_tag, BUS_DMA_NOWAIT, &rxb->map);
1268711bcba0SDavid C Somayajulu 
1269711bcba0SDavid C Somayajulu 		if (ret) {
1270711bcba0SDavid C Somayajulu 			device_printf(ha->pci_dev,
1271711bcba0SDavid C Somayajulu 				"%s: dmamap[%d, %d] failed\n", __func__, r, i);
1272711bcba0SDavid C Somayajulu 
1273711bcba0SDavid C Somayajulu 			for (j = 0; j < i; j++) {
1274711bcba0SDavid C Somayajulu 				rxb = &rx_ring->rx_buf[j];
1275711bcba0SDavid C Somayajulu 				bus_dmamap_destroy(ha->rx_tag, rxb->map);
1276711bcba0SDavid C Somayajulu 			}
1277711bcba0SDavid C Somayajulu 			goto qls_alloc_rcv_mbufs_err;
1278711bcba0SDavid C Somayajulu 		}
1279711bcba0SDavid C Somayajulu 	}
1280711bcba0SDavid C Somayajulu 
1281711bcba0SDavid C Somayajulu 	rx_ring = &ha->rx_ring[r];
1282711bcba0SDavid C Somayajulu 
1283711bcba0SDavid C Somayajulu 	sbq_e = rx_ring->sbq_vaddr;
1284711bcba0SDavid C Somayajulu 
1285711bcba0SDavid C Somayajulu 	rxb = &rx_ring->rx_buf[0];
1286711bcba0SDavid C Somayajulu 
1287711bcba0SDavid C Somayajulu 	for (i = 0; i < NUM_RX_DESCRIPTORS; i++) {
1288711bcba0SDavid C Somayajulu 		if (!(ret = qls_get_mbuf(ha, rxb, NULL))) {
1289711bcba0SDavid C Somayajulu 			/*
1290711bcba0SDavid C Somayajulu 		 	 * set the physical address in the
1291711bcba0SDavid C Somayajulu 			 * corresponding descriptor entry in the
1292711bcba0SDavid C Somayajulu 			 * receive ring/queue for the hba
1293711bcba0SDavid C Somayajulu 			 */
1294711bcba0SDavid C Somayajulu 
1295711bcba0SDavid C Somayajulu 			sbq_e->addr_lo = rxb->paddr & 0xFFFFFFFF;
1296711bcba0SDavid C Somayajulu 			sbq_e->addr_hi = (rxb->paddr >> 32) & 0xFFFFFFFF;
1297711bcba0SDavid C Somayajulu 
1298711bcba0SDavid C Somayajulu 		} else {
1299711bcba0SDavid C Somayajulu 			device_printf(ha->pci_dev,
1300711bcba0SDavid C Somayajulu 				"%s: qls_get_mbuf [%d, %d] failed\n",
1301711bcba0SDavid C Somayajulu 					__func__, r, i);
1302711bcba0SDavid C Somayajulu 			bus_dmamap_destroy(ha->rx_tag, rxb->map);
1303711bcba0SDavid C Somayajulu 			goto qls_alloc_rcv_mbufs_err;
1304711bcba0SDavid C Somayajulu 		}
1305711bcba0SDavid C Somayajulu 
1306711bcba0SDavid C Somayajulu 		rxb++;
1307711bcba0SDavid C Somayajulu 		sbq_e++;
1308711bcba0SDavid C Somayajulu 	}
1309711bcba0SDavid C Somayajulu 	return 0;
1310711bcba0SDavid C Somayajulu 
1311711bcba0SDavid C Somayajulu qls_alloc_rcv_mbufs_err:
1312711bcba0SDavid C Somayajulu 	return (-1);
1313711bcba0SDavid C Somayajulu }
1314711bcba0SDavid C Somayajulu 
1315711bcba0SDavid C Somayajulu static void
qls_free_rcv_bufs(qla_host_t * ha)1316711bcba0SDavid C Somayajulu qls_free_rcv_bufs(qla_host_t *ha)
1317711bcba0SDavid C Somayajulu {
1318711bcba0SDavid C Somayajulu 	int		i, r;
1319711bcba0SDavid C Somayajulu 	qla_rx_buf_t	*rxb;
1320711bcba0SDavid C Somayajulu 	qla_rx_ring_t	*rxr;
1321711bcba0SDavid C Somayajulu 
1322711bcba0SDavid C Somayajulu 	for (r = 0; r < ha->num_rx_rings; r++) {
1323711bcba0SDavid C Somayajulu 		rxr = &ha->rx_ring[r];
1324711bcba0SDavid C Somayajulu 
1325711bcba0SDavid C Somayajulu 		for (i = 0; i < NUM_RX_DESCRIPTORS; i++) {
1326711bcba0SDavid C Somayajulu 			rxb = &rxr->rx_buf[i];
1327711bcba0SDavid C Somayajulu 
1328711bcba0SDavid C Somayajulu 			if (rxb->m_head != NULL) {
1329711bcba0SDavid C Somayajulu 				bus_dmamap_unload(ha->rx_tag, rxb->map);
1330711bcba0SDavid C Somayajulu 				bus_dmamap_destroy(ha->rx_tag, rxb->map);
1331711bcba0SDavid C Somayajulu 				m_freem(rxb->m_head);
1332711bcba0SDavid C Somayajulu 			}
1333711bcba0SDavid C Somayajulu 		}
1334711bcba0SDavid C Somayajulu 		bzero(rxr->rx_buf, (sizeof(qla_rx_buf_t) * NUM_RX_DESCRIPTORS));
1335711bcba0SDavid C Somayajulu 	}
1336711bcba0SDavid C Somayajulu 	return;
1337711bcba0SDavid C Somayajulu }
1338711bcba0SDavid C Somayajulu 
1339711bcba0SDavid C Somayajulu static int
qls_alloc_rcv_bufs(qla_host_t * ha)1340711bcba0SDavid C Somayajulu qls_alloc_rcv_bufs(qla_host_t *ha)
1341711bcba0SDavid C Somayajulu {
1342711bcba0SDavid C Somayajulu 	int		r, ret = 0;
1343711bcba0SDavid C Somayajulu 	qla_rx_ring_t	*rxr;
1344711bcba0SDavid C Somayajulu 
1345711bcba0SDavid C Somayajulu 	for (r = 0; r < ha->num_rx_rings; r++) {
1346711bcba0SDavid C Somayajulu 		rxr = &ha->rx_ring[r];
1347711bcba0SDavid C Somayajulu 		bzero(rxr->rx_buf, (sizeof(qla_rx_buf_t) * NUM_RX_DESCRIPTORS));
1348711bcba0SDavid C Somayajulu 	}
1349711bcba0SDavid C Somayajulu 
1350711bcba0SDavid C Somayajulu 	for (r = 0; r < ha->num_rx_rings; r++) {
1351711bcba0SDavid C Somayajulu 		ret = qls_alloc_rcv_mbufs(ha, r);
1352711bcba0SDavid C Somayajulu 
1353711bcba0SDavid C Somayajulu 		if (ret)
1354711bcba0SDavid C Somayajulu 			qls_free_rcv_bufs(ha);
1355711bcba0SDavid C Somayajulu 	}
1356711bcba0SDavid C Somayajulu 
1357711bcba0SDavid C Somayajulu 	return (ret);
1358711bcba0SDavid C Somayajulu }
1359711bcba0SDavid C Somayajulu 
1360711bcba0SDavid C Somayajulu int
qls_get_mbuf(qla_host_t * ha,qla_rx_buf_t * rxb,struct mbuf * nmp)1361711bcba0SDavid C Somayajulu qls_get_mbuf(qla_host_t *ha, qla_rx_buf_t *rxb, struct mbuf *nmp)
1362711bcba0SDavid C Somayajulu {
13633e85b721SEd Maste 	struct mbuf *mp = nmp;
1364711bcba0SDavid C Somayajulu 	int            		ret = 0;
1365711bcba0SDavid C Somayajulu 	uint32_t		offset;
1366711bcba0SDavid C Somayajulu 	bus_dma_segment_t	segs[1];
1367711bcba0SDavid C Somayajulu 	int			nsegs;
1368711bcba0SDavid C Somayajulu 
1369711bcba0SDavid C Somayajulu 	QL_DPRINT2((ha->pci_dev, "%s: enter\n", __func__));
1370711bcba0SDavid C Somayajulu 
1371711bcba0SDavid C Somayajulu 	if (mp == NULL) {
1372b8c83a19SGleb Smirnoff 		mp = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, ha->msize);
1373711bcba0SDavid C Somayajulu 
1374711bcba0SDavid C Somayajulu 		if (mp == NULL) {
1375711bcba0SDavid C Somayajulu 			if (ha->msize == MCLBYTES)
1376711bcba0SDavid C Somayajulu 				ha->err_m_getcl++;
1377711bcba0SDavid C Somayajulu 			else
1378711bcba0SDavid C Somayajulu 				ha->err_m_getjcl++;
1379711bcba0SDavid C Somayajulu 
1380711bcba0SDavid C Somayajulu 			ret = ENOBUFS;
1381711bcba0SDavid C Somayajulu 			device_printf(ha->pci_dev,
1382711bcba0SDavid C Somayajulu 					"%s: m_getcl failed\n", __func__);
1383711bcba0SDavid C Somayajulu 			goto exit_qls_get_mbuf;
1384711bcba0SDavid C Somayajulu 		}
1385711bcba0SDavid C Somayajulu 		mp->m_len = mp->m_pkthdr.len = ha->msize;
1386711bcba0SDavid C Somayajulu 	} else {
1387711bcba0SDavid C Somayajulu 		mp->m_len = mp->m_pkthdr.len = ha->msize;
1388711bcba0SDavid C Somayajulu 		mp->m_data = mp->m_ext.ext_buf;
1389711bcba0SDavid C Somayajulu 		mp->m_next = NULL;
1390711bcba0SDavid C Somayajulu 	}
1391711bcba0SDavid C Somayajulu 
1392711bcba0SDavid C Somayajulu 	/* align the receive buffers to 8 byte boundary */
1393711bcba0SDavid C Somayajulu 	offset = (uint32_t)((unsigned long long)mp->m_data & 0x7ULL);
1394711bcba0SDavid C Somayajulu 	if (offset) {
1395711bcba0SDavid C Somayajulu 		offset = 8 - offset;
1396711bcba0SDavid C Somayajulu 		m_adj(mp, offset);
1397711bcba0SDavid C Somayajulu 	}
1398711bcba0SDavid C Somayajulu 
1399711bcba0SDavid C Somayajulu 	/*
1400711bcba0SDavid C Somayajulu 	 * Using memory from the mbuf cluster pool, invoke the bus_dma
1401711bcba0SDavid C Somayajulu 	 * machinery to arrange the memory mapping.
1402711bcba0SDavid C Somayajulu 	 */
1403711bcba0SDavid C Somayajulu 	ret = bus_dmamap_load_mbuf_sg(ha->rx_tag, rxb->map,
1404711bcba0SDavid C Somayajulu 			mp, segs, &nsegs, BUS_DMA_NOWAIT);
1405711bcba0SDavid C Somayajulu 	rxb->paddr = segs[0].ds_addr;
1406711bcba0SDavid C Somayajulu 
1407711bcba0SDavid C Somayajulu 	if (ret || !rxb->paddr || (nsegs != 1)) {
1408711bcba0SDavid C Somayajulu 		m_freem(mp);
1409711bcba0SDavid C Somayajulu 		rxb->m_head = NULL;
1410711bcba0SDavid C Somayajulu 		device_printf(ha->pci_dev,
1411711bcba0SDavid C Somayajulu 			"%s: bus_dmamap_load failed[%d, 0x%016llx, %d]\n",
1412711bcba0SDavid C Somayajulu 			__func__, ret, (long long unsigned int)rxb->paddr,
1413711bcba0SDavid C Somayajulu 			nsegs);
1414711bcba0SDavid C Somayajulu                 ret = -1;
1415711bcba0SDavid C Somayajulu 		goto exit_qls_get_mbuf;
1416711bcba0SDavid C Somayajulu 	}
1417711bcba0SDavid C Somayajulu 	rxb->m_head = mp;
1418711bcba0SDavid C Somayajulu 	bus_dmamap_sync(ha->rx_tag, rxb->map, BUS_DMASYNC_PREREAD);
1419711bcba0SDavid C Somayajulu 
1420711bcba0SDavid C Somayajulu exit_qls_get_mbuf:
1421711bcba0SDavid C Somayajulu 	QL_DPRINT2((ha->pci_dev, "%s: exit ret = 0x%08x\n", __func__, ret));
1422711bcba0SDavid C Somayajulu 	return (ret);
1423711bcba0SDavid C Somayajulu }
1424711bcba0SDavid C Somayajulu 
1425711bcba0SDavid C Somayajulu static void
qls_tx_done(void * context,int pending)1426711bcba0SDavid C Somayajulu qls_tx_done(void *context, int pending)
1427711bcba0SDavid C Somayajulu {
1428711bcba0SDavid C Somayajulu 	qla_host_t *ha = context;
142964c618edSJustin Hibbits 	if_t ifp;
1430711bcba0SDavid C Somayajulu 
1431711bcba0SDavid C Somayajulu 	ifp = ha->ifp;
1432711bcba0SDavid C Somayajulu 
1433711bcba0SDavid C Somayajulu 	if (!ifp)
1434711bcba0SDavid C Somayajulu 		return;
1435711bcba0SDavid C Somayajulu 
143664c618edSJustin Hibbits 	if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING)) {
1437711bcba0SDavid C Somayajulu 		QL_DPRINT8((ha->pci_dev, "%s: !IFF_DRV_RUNNING\n", __func__));
1438711bcba0SDavid C Somayajulu 		return;
1439711bcba0SDavid C Somayajulu 	}
1440711bcba0SDavid C Somayajulu 
1441711bcba0SDavid C Somayajulu 	qls_start(ha->ifp);
1442711bcba0SDavid C Somayajulu 	return;
1443711bcba0SDavid C Somayajulu }
1444711bcba0SDavid C Somayajulu 
1445711bcba0SDavid C Somayajulu static int
qls_config_lro(qla_host_t * ha)1446711bcba0SDavid C Somayajulu qls_config_lro(qla_host_t *ha)
1447711bcba0SDavid C Somayajulu {
1448618aa8cdSJohn Baldwin #if defined(INET) || defined(INET6)
1449711bcba0SDavid C Somayajulu         int i;
1450711bcba0SDavid C Somayajulu         struct lro_ctrl *lro;
1451711bcba0SDavid C Somayajulu 
1452711bcba0SDavid C Somayajulu         for (i = 0; i < ha->num_rx_rings; i++) {
1453711bcba0SDavid C Somayajulu                 lro = &ha->rx_ring[i].lro;
1454711bcba0SDavid C Somayajulu                 if (tcp_lro_init(lro)) {
1455711bcba0SDavid C Somayajulu                         device_printf(ha->pci_dev, "%s: tcp_lro_init failed\n",
1456711bcba0SDavid C Somayajulu                                 __func__);
1457711bcba0SDavid C Somayajulu                         return (-1);
1458711bcba0SDavid C Somayajulu                 }
1459711bcba0SDavid C Somayajulu                 lro->ifp = ha->ifp;
1460711bcba0SDavid C Somayajulu         }
1461711bcba0SDavid C Somayajulu         ha->flags.lro_init = 1;
1462711bcba0SDavid C Somayajulu 
1463711bcba0SDavid C Somayajulu         QL_DPRINT2((ha->pci_dev, "%s: LRO initialized\n", __func__));
1464618aa8cdSJohn Baldwin #endif
1465711bcba0SDavid C Somayajulu         return (0);
1466711bcba0SDavid C Somayajulu }
1467711bcba0SDavid C Somayajulu 
1468711bcba0SDavid C Somayajulu static void
qls_free_lro(qla_host_t * ha)1469711bcba0SDavid C Somayajulu qls_free_lro(qla_host_t *ha)
1470711bcba0SDavid C Somayajulu {
1471618aa8cdSJohn Baldwin #if defined(INET) || defined(INET6)
1472711bcba0SDavid C Somayajulu         int i;
1473711bcba0SDavid C Somayajulu         struct lro_ctrl *lro;
1474711bcba0SDavid C Somayajulu 
1475711bcba0SDavid C Somayajulu         if (!ha->flags.lro_init)
1476711bcba0SDavid C Somayajulu                 return;
1477711bcba0SDavid C Somayajulu 
1478711bcba0SDavid C Somayajulu         for (i = 0; i < ha->num_rx_rings; i++) {
1479711bcba0SDavid C Somayajulu                 lro = &ha->rx_ring[i].lro;
1480711bcba0SDavid C Somayajulu                 tcp_lro_free(lro);
1481711bcba0SDavid C Somayajulu         }
1482711bcba0SDavid C Somayajulu         ha->flags.lro_init = 0;
1483618aa8cdSJohn Baldwin #endif
1484711bcba0SDavid C Somayajulu }
1485711bcba0SDavid C Somayajulu 
1486711bcba0SDavid C Somayajulu static void
qls_error_recovery(void * context,int pending)1487711bcba0SDavid C Somayajulu qls_error_recovery(void *context, int pending)
1488711bcba0SDavid C Somayajulu {
1489711bcba0SDavid C Somayajulu         qla_host_t *ha = context;
1490711bcba0SDavid C Somayajulu 
1491711bcba0SDavid C Somayajulu 	qls_init(ha);
1492711bcba0SDavid C Somayajulu 
1493711bcba0SDavid C Somayajulu 	return;
1494711bcba0SDavid C Somayajulu }
1495