xref: /freebsd/sys/dev/qlxge/qls_os.c (revision 618aa8cd0ae0edca7d9a4e37ff242a6bb77bbccc)
1718cf2ccSPedro F. Giffuni /*-
2718cf2ccSPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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 __FBSDID("$FreeBSD$");
37711bcba0SDavid C Somayajulu 
38711bcba0SDavid C Somayajulu #include "qls_os.h"
39711bcba0SDavid C Somayajulu #include "qls_hw.h"
40711bcba0SDavid C Somayajulu #include "qls_def.h"
41711bcba0SDavid C Somayajulu #include "qls_inline.h"
42711bcba0SDavid C Somayajulu #include "qls_ver.h"
43711bcba0SDavid C Somayajulu #include "qls_glbl.h"
44711bcba0SDavid C Somayajulu #include "qls_dbg.h"
45711bcba0SDavid C Somayajulu #include <sys/smp.h>
46711bcba0SDavid C Somayajulu 
47711bcba0SDavid C Somayajulu /*
48711bcba0SDavid C Somayajulu  * Some PCI Configuration Space Related Defines
49711bcba0SDavid C Somayajulu  */
50711bcba0SDavid C Somayajulu 
51711bcba0SDavid C Somayajulu #ifndef PCI_VENDOR_QLOGIC
52711bcba0SDavid C Somayajulu #define PCI_VENDOR_QLOGIC	0x1077
53711bcba0SDavid C Somayajulu #endif
54711bcba0SDavid C Somayajulu 
55711bcba0SDavid C Somayajulu #ifndef PCI_DEVICE_QLOGIC_8000
56711bcba0SDavid C Somayajulu #define PCI_DEVICE_QLOGIC_8000	0x8000
57711bcba0SDavid C Somayajulu #endif
58711bcba0SDavid C Somayajulu 
59711bcba0SDavid C Somayajulu #define PCI_QLOGIC_DEV8000 \
60711bcba0SDavid C Somayajulu 	((PCI_DEVICE_QLOGIC_8000 << 16) | PCI_VENDOR_QLOGIC)
61711bcba0SDavid C Somayajulu 
62711bcba0SDavid C Somayajulu /*
63711bcba0SDavid C Somayajulu  * static functions
64711bcba0SDavid C Somayajulu  */
65711bcba0SDavid C Somayajulu static int qls_alloc_parent_dma_tag(qla_host_t *ha);
66711bcba0SDavid C Somayajulu static void qls_free_parent_dma_tag(qla_host_t *ha);
67711bcba0SDavid C Somayajulu 
68711bcba0SDavid C Somayajulu static void qls_flush_xmt_bufs(qla_host_t *ha);
69711bcba0SDavid C Somayajulu 
70711bcba0SDavid C Somayajulu static int qls_alloc_rcv_bufs(qla_host_t *ha);
71711bcba0SDavid C Somayajulu static void qls_free_rcv_bufs(qla_host_t *ha);
72711bcba0SDavid C Somayajulu 
73711bcba0SDavid C Somayajulu static void qls_init_ifnet(device_t dev, qla_host_t *ha);
74711bcba0SDavid C Somayajulu static void qls_release(qla_host_t *ha);
75711bcba0SDavid C Somayajulu static void qls_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nsegs,
76711bcba0SDavid C Somayajulu 		int error);
77711bcba0SDavid C Somayajulu static void qls_stop(qla_host_t *ha);
78711bcba0SDavid C Somayajulu static int qls_send(qla_host_t *ha, struct mbuf **m_headp);
79711bcba0SDavid C Somayajulu static void qls_tx_done(void *context, int pending);
80711bcba0SDavid C Somayajulu 
81711bcba0SDavid C Somayajulu static int qls_config_lro(qla_host_t *ha);
82711bcba0SDavid C Somayajulu static void qls_free_lro(qla_host_t *ha);
83711bcba0SDavid C Somayajulu 
84711bcba0SDavid C Somayajulu static void qls_error_recovery(void *context, int pending);
85711bcba0SDavid C Somayajulu 
86711bcba0SDavid C Somayajulu /*
87711bcba0SDavid C Somayajulu  * Hooks to the Operating Systems
88711bcba0SDavid C Somayajulu  */
89711bcba0SDavid C Somayajulu static int qls_pci_probe (device_t);
90711bcba0SDavid C Somayajulu static int qls_pci_attach (device_t);
91711bcba0SDavid C Somayajulu static int qls_pci_detach (device_t);
92711bcba0SDavid C Somayajulu 
93711bcba0SDavid C Somayajulu static void qls_start(struct ifnet *ifp);
94711bcba0SDavid C Somayajulu static void qls_init(void *arg);
95711bcba0SDavid C Somayajulu static int qls_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
96711bcba0SDavid C Somayajulu static int qls_media_change(struct ifnet *ifp);
97711bcba0SDavid C Somayajulu static void qls_media_status(struct ifnet *ifp, struct ifmediareq *ifmr);
98711bcba0SDavid C Somayajulu 
99711bcba0SDavid C Somayajulu static device_method_t qla_pci_methods[] = {
100711bcba0SDavid C Somayajulu 	/* Device interface */
101711bcba0SDavid C Somayajulu 	DEVMETHOD(device_probe, qls_pci_probe),
102711bcba0SDavid C Somayajulu 	DEVMETHOD(device_attach, qls_pci_attach),
103711bcba0SDavid C Somayajulu 	DEVMETHOD(device_detach, qls_pci_detach),
104711bcba0SDavid C Somayajulu 	{ 0, 0 }
105711bcba0SDavid C Somayajulu };
106711bcba0SDavid C Somayajulu 
107711bcba0SDavid C Somayajulu static driver_t qla_pci_driver = {
108711bcba0SDavid C Somayajulu 	"ql", qla_pci_methods, sizeof (qla_host_t),
109711bcba0SDavid C Somayajulu };
110711bcba0SDavid C Somayajulu 
111711bcba0SDavid C Somayajulu static devclass_t qla8000_devclass;
112711bcba0SDavid C Somayajulu 
113711bcba0SDavid C Somayajulu DRIVER_MODULE(qla8000, pci, qla_pci_driver, qla8000_devclass, 0, 0);
114711bcba0SDavid C Somayajulu 
115711bcba0SDavid C Somayajulu MODULE_DEPEND(qla8000, pci, 1, 1, 1);
116711bcba0SDavid C Somayajulu MODULE_DEPEND(qla8000, ether, 1, 1, 1);
117711bcba0SDavid C Somayajulu 
118711bcba0SDavid C Somayajulu MALLOC_DEFINE(M_QLA8000BUF, "qla8000buf", "Buffers for qla8000 driver");
119711bcba0SDavid C Somayajulu 
120711bcba0SDavid C Somayajulu static char dev_str[64];
121711bcba0SDavid C Somayajulu static char ver_str[64];
122711bcba0SDavid C Somayajulu 
123711bcba0SDavid C Somayajulu /*
124711bcba0SDavid C Somayajulu  * Name:	qls_pci_probe
125711bcba0SDavid C Somayajulu  * Function:	Validate the PCI device to be a QLA80XX device
126711bcba0SDavid C Somayajulu  */
127711bcba0SDavid C Somayajulu static int
128711bcba0SDavid C Somayajulu qls_pci_probe(device_t dev)
129711bcba0SDavid C Somayajulu {
130711bcba0SDavid C Somayajulu         switch ((pci_get_device(dev) << 16) | (pci_get_vendor(dev))) {
131711bcba0SDavid C Somayajulu         case PCI_QLOGIC_DEV8000:
132711bcba0SDavid C Somayajulu 		snprintf(dev_str, sizeof(dev_str), "%s v%d.%d.%d",
133711bcba0SDavid C Somayajulu 			"Qlogic ISP 8000 PCI CNA Adapter-Ethernet Function",
134711bcba0SDavid C Somayajulu 			QLA_VERSION_MAJOR, QLA_VERSION_MINOR,
135711bcba0SDavid C Somayajulu 			QLA_VERSION_BUILD);
136711bcba0SDavid C Somayajulu 		snprintf(ver_str, sizeof(ver_str), "v%d.%d.%d",
137711bcba0SDavid C Somayajulu 			QLA_VERSION_MAJOR, QLA_VERSION_MINOR,
138711bcba0SDavid C Somayajulu 			QLA_VERSION_BUILD);
139711bcba0SDavid C Somayajulu                 device_set_desc(dev, dev_str);
140711bcba0SDavid C Somayajulu                 break;
141711bcba0SDavid C Somayajulu         default:
142711bcba0SDavid C Somayajulu                 return (ENXIO);
143711bcba0SDavid C Somayajulu         }
144711bcba0SDavid C Somayajulu 
145711bcba0SDavid C Somayajulu         if (bootverbose)
146711bcba0SDavid C Somayajulu                 printf("%s: %s\n ", __func__, dev_str);
147711bcba0SDavid C Somayajulu 
148711bcba0SDavid C Somayajulu         return (BUS_PROBE_DEFAULT);
149711bcba0SDavid C Somayajulu }
150711bcba0SDavid C Somayajulu 
151711bcba0SDavid C Somayajulu static int
152711bcba0SDavid C Somayajulu qls_sysctl_get_drvr_stats(SYSCTL_HANDLER_ARGS)
153711bcba0SDavid C Somayajulu {
154711bcba0SDavid C Somayajulu         int err = 0, ret;
155711bcba0SDavid C Somayajulu         qla_host_t *ha;
156711bcba0SDavid C Somayajulu         uint32_t i;
157711bcba0SDavid C Somayajulu 
158711bcba0SDavid C Somayajulu         err = sysctl_handle_int(oidp, &ret, 0, req);
159711bcba0SDavid C Somayajulu 
160711bcba0SDavid C Somayajulu         if (err || !req->newptr)
161711bcba0SDavid C Somayajulu                 return (err);
162711bcba0SDavid C Somayajulu 
163711bcba0SDavid C Somayajulu         if (ret == 1) {
164711bcba0SDavid C Somayajulu                 ha = (qla_host_t *)arg1;
165711bcba0SDavid C Somayajulu 
166711bcba0SDavid C Somayajulu                 for (i = 0; i < ha->num_tx_rings; i++) {
167711bcba0SDavid C Somayajulu                         device_printf(ha->pci_dev,
168711bcba0SDavid C Somayajulu                                 "%s: tx_ring[%d].tx_frames= %p\n",
169711bcba0SDavid C Somayajulu 				__func__, i,
170711bcba0SDavid C Somayajulu                                 (void *)ha->tx_ring[i].tx_frames);
171711bcba0SDavid C Somayajulu 
172711bcba0SDavid C Somayajulu                         device_printf(ha->pci_dev,
173711bcba0SDavid C Somayajulu                                 "%s: tx_ring[%d].tx_tso_frames= %p\n",
174711bcba0SDavid C Somayajulu 				__func__, i,
175711bcba0SDavid C Somayajulu                                 (void *)ha->tx_ring[i].tx_tso_frames);
176711bcba0SDavid C Somayajulu 
177711bcba0SDavid C Somayajulu                         device_printf(ha->pci_dev,
178711bcba0SDavid C Somayajulu                                 "%s: tx_ring[%d].tx_vlan_frames= %p\n",
179711bcba0SDavid C Somayajulu 				__func__, i,
180711bcba0SDavid C Somayajulu                                 (void *)ha->tx_ring[i].tx_vlan_frames);
181711bcba0SDavid C Somayajulu 
182711bcba0SDavid C Somayajulu                         device_printf(ha->pci_dev,
183711bcba0SDavid C Somayajulu                                 "%s: tx_ring[%d].txr_free= 0x%08x\n",
184711bcba0SDavid C Somayajulu 				__func__, i,
185711bcba0SDavid C Somayajulu                                 ha->tx_ring[i].txr_free);
186711bcba0SDavid C Somayajulu 
187711bcba0SDavid C Somayajulu                         device_printf(ha->pci_dev,
188711bcba0SDavid C Somayajulu                                 "%s: tx_ring[%d].txr_next= 0x%08x\n",
189711bcba0SDavid C Somayajulu 				__func__, i,
190711bcba0SDavid C Somayajulu                                 ha->tx_ring[i].txr_next);
191711bcba0SDavid C Somayajulu 
192711bcba0SDavid C Somayajulu                         device_printf(ha->pci_dev,
193711bcba0SDavid C Somayajulu                                 "%s: tx_ring[%d].txr_done= 0x%08x\n",
194711bcba0SDavid C Somayajulu 				__func__, i,
195711bcba0SDavid C Somayajulu                                 ha->tx_ring[i].txr_done);
196711bcba0SDavid C Somayajulu 
197711bcba0SDavid C Somayajulu                         device_printf(ha->pci_dev,
198711bcba0SDavid C Somayajulu                                 "%s: tx_ring[%d].txr_cons_idx= 0x%08x\n",
199711bcba0SDavid C Somayajulu 				__func__, i,
200711bcba0SDavid C Somayajulu                                 *(ha->tx_ring[i].txr_cons_vaddr));
201711bcba0SDavid C Somayajulu 		}
202711bcba0SDavid C Somayajulu 
203711bcba0SDavid C Somayajulu                 for (i = 0; i < ha->num_rx_rings; i++) {
204711bcba0SDavid C Somayajulu                         device_printf(ha->pci_dev,
205711bcba0SDavid C Somayajulu                                 "%s: rx_ring[%d].rx_int= %p\n",
206711bcba0SDavid C Somayajulu 				__func__, i,
207711bcba0SDavid C Somayajulu                                 (void *)ha->rx_ring[i].rx_int);
208711bcba0SDavid C Somayajulu 
209711bcba0SDavid C Somayajulu                         device_printf(ha->pci_dev,
210711bcba0SDavid C Somayajulu                                 "%s: rx_ring[%d].rss_int= %p\n",
211711bcba0SDavid C Somayajulu 				__func__, i,
212711bcba0SDavid C Somayajulu                                 (void *)ha->rx_ring[i].rss_int);
213711bcba0SDavid C Somayajulu 
214711bcba0SDavid C Somayajulu                         device_printf(ha->pci_dev,
215711bcba0SDavid C Somayajulu                                 "%s: rx_ring[%d].lbq_next= 0x%08x\n",
216711bcba0SDavid C Somayajulu 				__func__, i,
217711bcba0SDavid C Somayajulu                                 ha->rx_ring[i].lbq_next);
218711bcba0SDavid C Somayajulu 
219711bcba0SDavid C Somayajulu                         device_printf(ha->pci_dev,
220711bcba0SDavid C Somayajulu                                 "%s: rx_ring[%d].lbq_free= 0x%08x\n",
221711bcba0SDavid C Somayajulu 				__func__, i,
222711bcba0SDavid C Somayajulu                                 ha->rx_ring[i].lbq_free);
223711bcba0SDavid C Somayajulu 
224711bcba0SDavid C Somayajulu                         device_printf(ha->pci_dev,
225711bcba0SDavid C Somayajulu                                 "%s: rx_ring[%d].lbq_in= 0x%08x\n",
226711bcba0SDavid C Somayajulu 				__func__, i,
227711bcba0SDavid C Somayajulu                                 ha->rx_ring[i].lbq_in);
228711bcba0SDavid C Somayajulu 
229711bcba0SDavid C Somayajulu                         device_printf(ha->pci_dev,
230711bcba0SDavid C Somayajulu                                 "%s: rx_ring[%d].sbq_next= 0x%08x\n",
231711bcba0SDavid C Somayajulu 				__func__, i,
232711bcba0SDavid C Somayajulu                                 ha->rx_ring[i].sbq_next);
233711bcba0SDavid C Somayajulu 
234711bcba0SDavid C Somayajulu                         device_printf(ha->pci_dev,
235711bcba0SDavid C Somayajulu                                 "%s: rx_ring[%d].sbq_free= 0x%08x\n",
236711bcba0SDavid C Somayajulu 				__func__, i,
237711bcba0SDavid C Somayajulu                                 ha->rx_ring[i].sbq_free);
238711bcba0SDavid C Somayajulu 
239711bcba0SDavid C Somayajulu                         device_printf(ha->pci_dev,
240711bcba0SDavid C Somayajulu                                 "%s: rx_ring[%d].sbq_in= 0x%08x\n",
241711bcba0SDavid C Somayajulu 				__func__, i,
242711bcba0SDavid C Somayajulu                                 ha->rx_ring[i].sbq_in);
243711bcba0SDavid C Somayajulu 		}
244711bcba0SDavid C Somayajulu 
245711bcba0SDavid C Somayajulu 		device_printf(ha->pci_dev, "%s: err_m_getcl = 0x%08x\n",
246711bcba0SDavid C Somayajulu 				__func__, ha->err_m_getcl);
247711bcba0SDavid C Somayajulu 		device_printf(ha->pci_dev, "%s: err_m_getjcl = 0x%08x\n",
248711bcba0SDavid C Somayajulu 				__func__, ha->err_m_getjcl);
249711bcba0SDavid C Somayajulu 		device_printf(ha->pci_dev,
250711bcba0SDavid C Somayajulu 				"%s: err_tx_dmamap_create = 0x%08x\n",
251711bcba0SDavid C Somayajulu 				__func__, ha->err_tx_dmamap_create);
252711bcba0SDavid C Somayajulu 		device_printf(ha->pci_dev,
253711bcba0SDavid C Somayajulu 				"%s: err_tx_dmamap_load = 0x%08x\n",
254711bcba0SDavid C Somayajulu 				__func__, ha->err_tx_dmamap_load);
255711bcba0SDavid C Somayajulu 		device_printf(ha->pci_dev,
256711bcba0SDavid C Somayajulu 				"%s: err_tx_defrag = 0x%08x\n",
257711bcba0SDavid C Somayajulu 				__func__, ha->err_tx_defrag);
258711bcba0SDavid C Somayajulu         }
259711bcba0SDavid C Somayajulu         return (err);
260711bcba0SDavid C Somayajulu }
261711bcba0SDavid C Somayajulu 
262711bcba0SDavid C Somayajulu static void
263711bcba0SDavid C Somayajulu qls_add_sysctls(qla_host_t *ha)
264711bcba0SDavid C Somayajulu {
265711bcba0SDavid C Somayajulu         device_t dev = ha->pci_dev;
266711bcba0SDavid C Somayajulu 
267711bcba0SDavid C Somayajulu 	SYSCTL_ADD_STRING(device_get_sysctl_ctx(dev),
268711bcba0SDavid C Somayajulu 		SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
269711bcba0SDavid C Somayajulu 		OID_AUTO, "version", CTLFLAG_RD,
270711bcba0SDavid C Somayajulu 		ver_str, 0, "Driver Version");
271711bcba0SDavid C Somayajulu 
272711bcba0SDavid C Somayajulu 	qls_dbg_level = 0;
273711bcba0SDavid C Somayajulu         SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
274711bcba0SDavid C Somayajulu                 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
275711bcba0SDavid C Somayajulu                 OID_AUTO, "debug", CTLFLAG_RW,
276711bcba0SDavid C Somayajulu                 &qls_dbg_level, qls_dbg_level, "Debug Level");
277711bcba0SDavid C Somayajulu 
278711bcba0SDavid C Somayajulu         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
279711bcba0SDavid C Somayajulu             SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
2807029da5cSPawel Biernacki             OID_AUTO, "drvr_stats",
2817029da5cSPawel Biernacki 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, (void *)ha, 0,
282711bcba0SDavid C Somayajulu 	    qls_sysctl_get_drvr_stats, "I", "Driver Maintained Statistics");
283711bcba0SDavid C Somayajulu 
284711bcba0SDavid C Somayajulu         return;
285711bcba0SDavid C Somayajulu }
286711bcba0SDavid C Somayajulu 
287711bcba0SDavid C Somayajulu static void
288711bcba0SDavid C Somayajulu qls_watchdog(void *arg)
289711bcba0SDavid C Somayajulu {
290711bcba0SDavid C Somayajulu 	qla_host_t *ha = arg;
291711bcba0SDavid C Somayajulu 	struct ifnet *ifp;
292711bcba0SDavid C Somayajulu 
293711bcba0SDavid C Somayajulu 	ifp = ha->ifp;
294711bcba0SDavid C Somayajulu 
295711bcba0SDavid C Somayajulu         if (ha->flags.qla_watchdog_exit) {
296711bcba0SDavid C Somayajulu 		ha->qla_watchdog_exited = 1;
297711bcba0SDavid C Somayajulu 		return;
298711bcba0SDavid C Somayajulu 	}
299711bcba0SDavid C Somayajulu 	ha->qla_watchdog_exited = 0;
300711bcba0SDavid C Somayajulu 
301711bcba0SDavid C Somayajulu 	if (!ha->flags.qla_watchdog_pause) {
302711bcba0SDavid C Somayajulu 		if (ha->qla_initiate_recovery) {
303711bcba0SDavid C Somayajulu 			ha->qla_watchdog_paused = 1;
304711bcba0SDavid C Somayajulu 			ha->qla_initiate_recovery = 0;
305711bcba0SDavid C Somayajulu 			ha->err_inject = 0;
306711bcba0SDavid C Somayajulu 			taskqueue_enqueue(ha->err_tq, &ha->err_task);
307711bcba0SDavid C Somayajulu 
308711bcba0SDavid C Somayajulu 		} else if ((ifp->if_snd.ifq_head != NULL) && QL_RUNNING(ifp)) {
309711bcba0SDavid C Somayajulu 			taskqueue_enqueue(ha->tx_tq, &ha->tx_task);
310711bcba0SDavid C Somayajulu 		}
311711bcba0SDavid C Somayajulu 
312711bcba0SDavid C Somayajulu 		ha->qla_watchdog_paused = 0;
313711bcba0SDavid C Somayajulu 	} else {
314711bcba0SDavid C Somayajulu 		ha->qla_watchdog_paused = 1;
315711bcba0SDavid C Somayajulu 	}
316711bcba0SDavid C Somayajulu 
31782b5e644SConrad Meyer 	ha->watchdog_ticks = (ha->watchdog_ticks + 1) % 1000;
318711bcba0SDavid C Somayajulu 	callout_reset(&ha->tx_callout, QLA_WATCHDOG_CALLOUT_TICKS,
319711bcba0SDavid C Somayajulu 		qls_watchdog, ha);
320711bcba0SDavid C Somayajulu 
321711bcba0SDavid C Somayajulu 	return;
322711bcba0SDavid C Somayajulu }
323711bcba0SDavid C Somayajulu 
324711bcba0SDavid C Somayajulu /*
325711bcba0SDavid C Somayajulu  * Name:	qls_pci_attach
326711bcba0SDavid C Somayajulu  * Function:	attaches the device to the operating system
327711bcba0SDavid C Somayajulu  */
328711bcba0SDavid C Somayajulu static int
329711bcba0SDavid C Somayajulu qls_pci_attach(device_t dev)
330711bcba0SDavid C Somayajulu {
331711bcba0SDavid C Somayajulu 	qla_host_t *ha = NULL;
332711bcba0SDavid C Somayajulu 	int i;
333711bcba0SDavid C Somayajulu 
334711bcba0SDavid C Somayajulu 	QL_DPRINT2((dev, "%s: enter\n", __func__));
335711bcba0SDavid C Somayajulu 
336711bcba0SDavid C Somayajulu         if ((ha = device_get_softc(dev)) == NULL) {
337711bcba0SDavid C Somayajulu                 device_printf(dev, "cannot get softc\n");
338711bcba0SDavid C Somayajulu                 return (ENOMEM);
339711bcba0SDavid C Somayajulu         }
340711bcba0SDavid C Somayajulu 
341711bcba0SDavid C Somayajulu         memset(ha, 0, sizeof (qla_host_t));
342711bcba0SDavid C Somayajulu 
343711bcba0SDavid C Somayajulu         if (pci_get_device(dev) != PCI_DEVICE_QLOGIC_8000) {
344711bcba0SDavid C Somayajulu                 device_printf(dev, "device is not QLE8000\n");
345711bcba0SDavid C Somayajulu                 return (ENXIO);
346711bcba0SDavid C Somayajulu 	}
347711bcba0SDavid C Somayajulu 
348711bcba0SDavid C Somayajulu         ha->pci_func = pci_get_function(dev);
349711bcba0SDavid C Somayajulu 
350711bcba0SDavid C Somayajulu         ha->pci_dev = dev;
351711bcba0SDavid C Somayajulu 
352711bcba0SDavid C Somayajulu 	pci_enable_busmaster(dev);
353711bcba0SDavid C Somayajulu 
354711bcba0SDavid C Somayajulu 	ha->reg_rid = PCIR_BAR(1);
355711bcba0SDavid C Somayajulu 	ha->pci_reg = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &ha->reg_rid,
356711bcba0SDavid C Somayajulu 				RF_ACTIVE);
357711bcba0SDavid C Somayajulu 
358711bcba0SDavid C Somayajulu         if (ha->pci_reg == NULL) {
359711bcba0SDavid C Somayajulu                 device_printf(dev, "unable to map any ports\n");
360711bcba0SDavid C Somayajulu                 goto qls_pci_attach_err;
361711bcba0SDavid C Somayajulu         }
362711bcba0SDavid C Somayajulu 
363711bcba0SDavid C Somayajulu 	ha->reg_rid1 = PCIR_BAR(3);
364711bcba0SDavid C Somayajulu 	ha->pci_reg1 = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
365711bcba0SDavid C Somayajulu 			&ha->reg_rid1, RF_ACTIVE);
366711bcba0SDavid C Somayajulu 
367711bcba0SDavid C Somayajulu         if (ha->pci_reg1 == NULL) {
368711bcba0SDavid C Somayajulu                 device_printf(dev, "unable to map any ports\n");
369711bcba0SDavid C Somayajulu                 goto qls_pci_attach_err;
370711bcba0SDavid C Somayajulu         }
371711bcba0SDavid C Somayajulu 
372711bcba0SDavid C Somayajulu 	mtx_init(&ha->hw_lock, "qla80xx_hw_lock", MTX_NETWORK_LOCK, MTX_DEF);
373711bcba0SDavid C Somayajulu 	mtx_init(&ha->tx_lock, "qla80xx_tx_lock", MTX_NETWORK_LOCK, MTX_DEF);
374711bcba0SDavid C Somayajulu 
375711bcba0SDavid C Somayajulu 	qls_add_sysctls(ha);
376711bcba0SDavid C Somayajulu 	qls_hw_add_sysctls(ha);
377711bcba0SDavid C Somayajulu 
378711bcba0SDavid C Somayajulu 	ha->flags.lock_init = 1;
379711bcba0SDavid C Somayajulu 
380711bcba0SDavid C Somayajulu 	ha->msix_count = pci_msix_count(dev);
381711bcba0SDavid C Somayajulu 
382711bcba0SDavid C Somayajulu 	if (ha->msix_count < qls_get_msix_count(ha)) {
383711bcba0SDavid C Somayajulu 		device_printf(dev, "%s: msix_count[%d] not enough\n", __func__,
384711bcba0SDavid C Somayajulu 			ha->msix_count);
385711bcba0SDavid C Somayajulu 		goto qls_pci_attach_err;
386711bcba0SDavid C Somayajulu 	}
387711bcba0SDavid C Somayajulu 
388711bcba0SDavid C Somayajulu 	ha->msix_count = qls_get_msix_count(ha);
389711bcba0SDavid C Somayajulu 
390711bcba0SDavid C Somayajulu 	device_printf(dev, "\n%s: ha %p pci_func 0x%x  msix_count 0x%x"
391711bcba0SDavid C Somayajulu 		" pci_reg %p pci_reg1 %p\n", __func__, ha,
392711bcba0SDavid C Somayajulu 		ha->pci_func, ha->msix_count, ha->pci_reg, ha->pci_reg1);
393711bcba0SDavid C Somayajulu 
394711bcba0SDavid C Somayajulu 	if (pci_alloc_msix(dev, &ha->msix_count)) {
395711bcba0SDavid C Somayajulu 		device_printf(dev, "%s: pci_alloc_msi[%d] failed\n", __func__,
396711bcba0SDavid C Somayajulu 			ha->msix_count);
397711bcba0SDavid C Somayajulu 		ha->msix_count = 0;
398711bcba0SDavid C Somayajulu 		goto qls_pci_attach_err;
399711bcba0SDavid C Somayajulu 	}
400711bcba0SDavid C Somayajulu 
401711bcba0SDavid C Somayajulu         for (i = 0; i < ha->num_rx_rings; i++) {
402711bcba0SDavid C Somayajulu                 ha->irq_vec[i].cq_idx = i;
403711bcba0SDavid C Somayajulu                 ha->irq_vec[i].ha = ha;
404711bcba0SDavid C Somayajulu                 ha->irq_vec[i].irq_rid = 1 + i;
405711bcba0SDavid C Somayajulu 
406711bcba0SDavid C Somayajulu                 ha->irq_vec[i].irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
407711bcba0SDavid C Somayajulu                                 &ha->irq_vec[i].irq_rid,
408711bcba0SDavid C Somayajulu                                 (RF_ACTIVE | RF_SHAREABLE));
409711bcba0SDavid C Somayajulu 
410711bcba0SDavid C Somayajulu                 if (ha->irq_vec[i].irq == NULL) {
411711bcba0SDavid C Somayajulu                         device_printf(dev, "could not allocate interrupt\n");
412711bcba0SDavid C Somayajulu                         goto qls_pci_attach_err;
413711bcba0SDavid C Somayajulu                 }
414711bcba0SDavid C Somayajulu 
415711bcba0SDavid C Somayajulu 		if (bus_setup_intr(dev, ha->irq_vec[i].irq,
416711bcba0SDavid C Somayajulu 			(INTR_TYPE_NET | INTR_MPSAFE), NULL, qls_isr,
417711bcba0SDavid C Somayajulu 			&ha->irq_vec[i], &ha->irq_vec[i].handle)) {
418711bcba0SDavid C Somayajulu 				device_printf(dev,
419711bcba0SDavid C Somayajulu 					"could not setup interrupt\n");
420711bcba0SDavid C Somayajulu 			goto qls_pci_attach_err;
421711bcba0SDavid C Somayajulu 		}
422711bcba0SDavid C Somayajulu         }
423711bcba0SDavid C Somayajulu 
424711bcba0SDavid C Somayajulu 	qls_rd_nic_params(ha);
425711bcba0SDavid C Somayajulu 
426711bcba0SDavid C Somayajulu 	/* allocate parent dma tag */
427711bcba0SDavid C Somayajulu 	if (qls_alloc_parent_dma_tag(ha)) {
428711bcba0SDavid C Somayajulu 		device_printf(dev, "%s: qls_alloc_parent_dma_tag failed\n",
429711bcba0SDavid C Somayajulu 			__func__);
430711bcba0SDavid C Somayajulu 		goto qls_pci_attach_err;
431711bcba0SDavid C Somayajulu 	}
432711bcba0SDavid C Somayajulu 
433711bcba0SDavid C Somayajulu 	/* alloc all dma buffers */
434711bcba0SDavid C Somayajulu 	if (qls_alloc_dma(ha)) {
435711bcba0SDavid C Somayajulu 		device_printf(dev, "%s: qls_alloc_dma failed\n", __func__);
436711bcba0SDavid C Somayajulu 		goto qls_pci_attach_err;
437711bcba0SDavid C Somayajulu 	}
438711bcba0SDavid C Somayajulu 
439711bcba0SDavid C Somayajulu 	/* create the o.s ethernet interface */
440711bcba0SDavid C Somayajulu 	qls_init_ifnet(dev, ha);
441711bcba0SDavid C Somayajulu 
442711bcba0SDavid C Somayajulu 	ha->flags.qla_watchdog_active = 1;
443711bcba0SDavid C Somayajulu 	ha->flags.qla_watchdog_pause = 1;
444711bcba0SDavid C Somayajulu 
445711bcba0SDavid C Somayajulu 	TASK_INIT(&ha->tx_task, 0, qls_tx_done, ha);
446711bcba0SDavid C Somayajulu 	ha->tx_tq = taskqueue_create_fast("qla_txq", M_NOWAIT,
447711bcba0SDavid C Somayajulu 			taskqueue_thread_enqueue, &ha->tx_tq);
448711bcba0SDavid C Somayajulu 	taskqueue_start_threads(&ha->tx_tq, 1, PI_NET, "%s txq",
449711bcba0SDavid C Somayajulu 		device_get_nameunit(ha->pci_dev));
450711bcba0SDavid C Somayajulu 
451fd90e2edSJung-uk Kim 	callout_init(&ha->tx_callout, 1);
452711bcba0SDavid C Somayajulu 	ha->flags.qla_callout_init = 1;
453711bcba0SDavid C Somayajulu 
454711bcba0SDavid C Somayajulu         /* create ioctl device interface */
455711bcba0SDavid C Somayajulu         if (qls_make_cdev(ha)) {
456711bcba0SDavid C Somayajulu                 device_printf(dev, "%s: qls_make_cdev failed\n", __func__);
457711bcba0SDavid C Somayajulu                 goto qls_pci_attach_err;
458711bcba0SDavid C Somayajulu         }
459711bcba0SDavid C Somayajulu 
460711bcba0SDavid C Somayajulu 	callout_reset(&ha->tx_callout, QLA_WATCHDOG_CALLOUT_TICKS,
461711bcba0SDavid C Somayajulu 		qls_watchdog, ha);
462711bcba0SDavid C Somayajulu 
463711bcba0SDavid C Somayajulu         TASK_INIT(&ha->err_task, 0, qls_error_recovery, ha);
464711bcba0SDavid C Somayajulu         ha->err_tq = taskqueue_create_fast("qla_errq", M_NOWAIT,
465711bcba0SDavid C Somayajulu                         taskqueue_thread_enqueue, &ha->err_tq);
466711bcba0SDavid C Somayajulu         taskqueue_start_threads(&ha->err_tq, 1, PI_NET, "%s errq",
467711bcba0SDavid C Somayajulu                 device_get_nameunit(ha->pci_dev));
468711bcba0SDavid C Somayajulu 
469711bcba0SDavid C Somayajulu 	QL_DPRINT2((dev, "%s: exit 0\n", __func__));
470711bcba0SDavid C Somayajulu         return (0);
471711bcba0SDavid C Somayajulu 
472711bcba0SDavid C Somayajulu qls_pci_attach_err:
473711bcba0SDavid C Somayajulu 
474711bcba0SDavid C Somayajulu 	qls_release(ha);
475711bcba0SDavid C Somayajulu 
476711bcba0SDavid C Somayajulu 	QL_DPRINT2((dev, "%s: exit ENXIO\n", __func__));
477711bcba0SDavid C Somayajulu         return (ENXIO);
478711bcba0SDavid C Somayajulu }
479711bcba0SDavid C Somayajulu 
480711bcba0SDavid C Somayajulu /*
481711bcba0SDavid C Somayajulu  * Name:	qls_pci_detach
482711bcba0SDavid C Somayajulu  * Function:	Unhooks the device from the operating system
483711bcba0SDavid C Somayajulu  */
484711bcba0SDavid C Somayajulu static int
485711bcba0SDavid C Somayajulu qls_pci_detach(device_t dev)
486711bcba0SDavid C Somayajulu {
487711bcba0SDavid C Somayajulu 	qla_host_t *ha = NULL;
488711bcba0SDavid C Somayajulu 
489711bcba0SDavid C Somayajulu 	QL_DPRINT2((dev, "%s: enter\n", __func__));
490711bcba0SDavid C Somayajulu 
491711bcba0SDavid C Somayajulu         if ((ha = device_get_softc(dev)) == NULL) {
492711bcba0SDavid C Somayajulu                 device_printf(dev, "cannot get softc\n");
493711bcba0SDavid C Somayajulu                 return (ENOMEM);
494711bcba0SDavid C Somayajulu         }
495711bcba0SDavid C Somayajulu 
496711bcba0SDavid C Somayajulu 	(void)QLA_LOCK(ha, __func__, 0);
497711bcba0SDavid C Somayajulu 	qls_stop(ha);
498711bcba0SDavid C Somayajulu 	QLA_UNLOCK(ha, __func__);
499711bcba0SDavid C Somayajulu 
500711bcba0SDavid C Somayajulu 	qls_release(ha);
501711bcba0SDavid C Somayajulu 
502711bcba0SDavid C Somayajulu 	QL_DPRINT2((dev, "%s: exit\n", __func__));
503711bcba0SDavid C Somayajulu 
504711bcba0SDavid C Somayajulu         return (0);
505711bcba0SDavid C Somayajulu }
506711bcba0SDavid C Somayajulu 
507711bcba0SDavid C Somayajulu /*
508711bcba0SDavid C Somayajulu  * Name:	qls_release
509711bcba0SDavid C Somayajulu  * Function:	Releases the resources allocated for the device
510711bcba0SDavid C Somayajulu  */
511711bcba0SDavid C Somayajulu static void
512711bcba0SDavid C Somayajulu qls_release(qla_host_t *ha)
513711bcba0SDavid C Somayajulu {
514711bcba0SDavid C Somayajulu 	device_t dev;
515711bcba0SDavid C Somayajulu 	int i;
516711bcba0SDavid C Somayajulu 
517711bcba0SDavid C Somayajulu 	dev = ha->pci_dev;
518711bcba0SDavid C Somayajulu 
519711bcba0SDavid C Somayajulu 	if (ha->err_tq) {
520711bcba0SDavid C Somayajulu 		taskqueue_drain(ha->err_tq, &ha->err_task);
521711bcba0SDavid C Somayajulu 		taskqueue_free(ha->err_tq);
522711bcba0SDavid C Somayajulu 	}
523711bcba0SDavid C Somayajulu 
524711bcba0SDavid C Somayajulu 	if (ha->tx_tq) {
525711bcba0SDavid C Somayajulu 		taskqueue_drain(ha->tx_tq, &ha->tx_task);
526711bcba0SDavid C Somayajulu 		taskqueue_free(ha->tx_tq);
527711bcba0SDavid C Somayajulu 	}
528711bcba0SDavid C Somayajulu 
529711bcba0SDavid C Somayajulu 	qls_del_cdev(ha);
530711bcba0SDavid C Somayajulu 
531711bcba0SDavid C Somayajulu 	if (ha->flags.qla_watchdog_active) {
532711bcba0SDavid C Somayajulu 		ha->flags.qla_watchdog_exit = 1;
533711bcba0SDavid C Somayajulu 
534711bcba0SDavid C Somayajulu 		while (ha->qla_watchdog_exited == 0)
535711bcba0SDavid C Somayajulu 			qls_mdelay(__func__, 1);
536711bcba0SDavid C Somayajulu 	}
537711bcba0SDavid C Somayajulu 
538711bcba0SDavid C Somayajulu 	if (ha->flags.qla_callout_init)
539711bcba0SDavid C Somayajulu 		callout_stop(&ha->tx_callout);
540711bcba0SDavid C Somayajulu 
541711bcba0SDavid C Somayajulu 	if (ha->ifp != NULL)
542711bcba0SDavid C Somayajulu 		ether_ifdetach(ha->ifp);
543711bcba0SDavid C Somayajulu 
544711bcba0SDavid C Somayajulu 	qls_free_dma(ha);
545711bcba0SDavid C Somayajulu 	qls_free_parent_dma_tag(ha);
546711bcba0SDavid C Somayajulu 
547711bcba0SDavid C Somayajulu         for (i = 0; i < ha->num_rx_rings; i++) {
548711bcba0SDavid C Somayajulu                 if (ha->irq_vec[i].handle) {
549711bcba0SDavid C Somayajulu                         (void)bus_teardown_intr(dev, ha->irq_vec[i].irq,
550711bcba0SDavid C Somayajulu                                         ha->irq_vec[i].handle);
551711bcba0SDavid C Somayajulu                 }
552711bcba0SDavid C Somayajulu 
553711bcba0SDavid C Somayajulu                 if (ha->irq_vec[i].irq) {
554711bcba0SDavid C Somayajulu                         (void)bus_release_resource(dev, SYS_RES_IRQ,
555711bcba0SDavid C Somayajulu                                 ha->irq_vec[i].irq_rid,
556711bcba0SDavid C Somayajulu                                 ha->irq_vec[i].irq);
557711bcba0SDavid C Somayajulu                 }
558711bcba0SDavid C Somayajulu         }
559711bcba0SDavid C Somayajulu 
560711bcba0SDavid C Somayajulu 	if (ha->msix_count)
561711bcba0SDavid C Somayajulu 		pci_release_msi(dev);
562711bcba0SDavid C Somayajulu 
563711bcba0SDavid C Somayajulu 	if (ha->flags.lock_init) {
564711bcba0SDavid C Somayajulu 		mtx_destroy(&ha->tx_lock);
565711bcba0SDavid C Somayajulu 		mtx_destroy(&ha->hw_lock);
566711bcba0SDavid C Somayajulu 	}
567711bcba0SDavid C Somayajulu 
568711bcba0SDavid C Somayajulu         if (ha->pci_reg)
569711bcba0SDavid C Somayajulu                 (void) bus_release_resource(dev, SYS_RES_MEMORY, ha->reg_rid,
570711bcba0SDavid C Somayajulu 				ha->pci_reg);
571711bcba0SDavid C Somayajulu 
572711bcba0SDavid C Somayajulu         if (ha->pci_reg1)
573711bcba0SDavid C Somayajulu                 (void) bus_release_resource(dev, SYS_RES_MEMORY, ha->reg_rid1,
574711bcba0SDavid C Somayajulu 				ha->pci_reg1);
575711bcba0SDavid C Somayajulu }
576711bcba0SDavid C Somayajulu 
577711bcba0SDavid C Somayajulu /*
578711bcba0SDavid C Somayajulu  * DMA Related Functions
579711bcba0SDavid C Somayajulu  */
580711bcba0SDavid C Somayajulu 
581711bcba0SDavid C Somayajulu static void
582711bcba0SDavid C Somayajulu qls_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
583711bcba0SDavid C Somayajulu {
584711bcba0SDavid C Somayajulu         *((bus_addr_t *)arg) = 0;
585711bcba0SDavid C Somayajulu 
586711bcba0SDavid C Somayajulu         if (error) {
587711bcba0SDavid C Somayajulu                 printf("%s: bus_dmamap_load failed (%d)\n", __func__, error);
588711bcba0SDavid C Somayajulu                 return;
589711bcba0SDavid C Somayajulu 	}
590711bcba0SDavid C Somayajulu 
591711bcba0SDavid C Somayajulu         *((bus_addr_t *)arg) = segs[0].ds_addr;
592711bcba0SDavid C Somayajulu 
593711bcba0SDavid C Somayajulu 	return;
594711bcba0SDavid C Somayajulu }
595711bcba0SDavid C Somayajulu 
596711bcba0SDavid C Somayajulu int
597711bcba0SDavid C Somayajulu qls_alloc_dmabuf(qla_host_t *ha, qla_dma_t *dma_buf)
598711bcba0SDavid C Somayajulu {
599711bcba0SDavid C Somayajulu         int             ret = 0;
600711bcba0SDavid C Somayajulu         device_t        dev;
601711bcba0SDavid C Somayajulu         bus_addr_t      b_addr;
602711bcba0SDavid C Somayajulu 
603711bcba0SDavid C Somayajulu         dev = ha->pci_dev;
604711bcba0SDavid C Somayajulu 
605711bcba0SDavid C Somayajulu         QL_DPRINT2((dev, "%s: enter\n", __func__));
606711bcba0SDavid C Somayajulu 
607711bcba0SDavid C Somayajulu         ret = bus_dma_tag_create(
608711bcba0SDavid C Somayajulu                         ha->parent_tag,/* parent */
609711bcba0SDavid C Somayajulu                         dma_buf->alignment,
610711bcba0SDavid C Somayajulu                         ((bus_size_t)(1ULL << 32)),/* boundary */
611711bcba0SDavid C Somayajulu                         BUS_SPACE_MAXADDR,      /* lowaddr */
612711bcba0SDavid C Somayajulu                         BUS_SPACE_MAXADDR,      /* highaddr */
613711bcba0SDavid C Somayajulu                         NULL, NULL,             /* filter, filterarg */
614711bcba0SDavid C Somayajulu                         dma_buf->size,          /* maxsize */
615711bcba0SDavid C Somayajulu                         1,                      /* nsegments */
616711bcba0SDavid C Somayajulu                         dma_buf->size,          /* maxsegsize */
617711bcba0SDavid C Somayajulu                         0,                      /* flags */
618711bcba0SDavid C Somayajulu                         NULL, NULL,             /* lockfunc, lockarg */
619711bcba0SDavid C Somayajulu                         &dma_buf->dma_tag);
620711bcba0SDavid C Somayajulu 
621711bcba0SDavid C Somayajulu         if (ret) {
622711bcba0SDavid C Somayajulu                 device_printf(dev, "%s: could not create dma tag\n", __func__);
623711bcba0SDavid C Somayajulu                 goto qls_alloc_dmabuf_exit;
624711bcba0SDavid C Somayajulu         }
625711bcba0SDavid C Somayajulu         ret = bus_dmamem_alloc(dma_buf->dma_tag,
626711bcba0SDavid C Somayajulu                         (void **)&dma_buf->dma_b,
627711bcba0SDavid C Somayajulu                         (BUS_DMA_ZERO | BUS_DMA_COHERENT | BUS_DMA_NOWAIT),
628711bcba0SDavid C Somayajulu                         &dma_buf->dma_map);
629711bcba0SDavid C Somayajulu         if (ret) {
630711bcba0SDavid C Somayajulu                 bus_dma_tag_destroy(dma_buf->dma_tag);
631711bcba0SDavid C Somayajulu                 device_printf(dev, "%s: bus_dmamem_alloc failed\n", __func__);
632711bcba0SDavid C Somayajulu                 goto qls_alloc_dmabuf_exit;
633711bcba0SDavid C Somayajulu         }
634711bcba0SDavid C Somayajulu 
635711bcba0SDavid C Somayajulu         ret = bus_dmamap_load(dma_buf->dma_tag,
636711bcba0SDavid C Somayajulu                         dma_buf->dma_map,
637711bcba0SDavid C Somayajulu                         dma_buf->dma_b,
638711bcba0SDavid C Somayajulu                         dma_buf->size,
639711bcba0SDavid C Somayajulu                         qls_dmamap_callback,
640711bcba0SDavid C Somayajulu                         &b_addr, BUS_DMA_NOWAIT);
641711bcba0SDavid C Somayajulu 
642711bcba0SDavid C Somayajulu         if (ret || !b_addr) {
643711bcba0SDavid C Somayajulu                 bus_dma_tag_destroy(dma_buf->dma_tag);
644711bcba0SDavid C Somayajulu                 bus_dmamem_free(dma_buf->dma_tag, dma_buf->dma_b,
645711bcba0SDavid C Somayajulu                         dma_buf->dma_map);
646711bcba0SDavid C Somayajulu                 ret = -1;
647711bcba0SDavid C Somayajulu                 goto qls_alloc_dmabuf_exit;
648711bcba0SDavid C Somayajulu         }
649711bcba0SDavid C Somayajulu 
650711bcba0SDavid C Somayajulu         dma_buf->dma_addr = b_addr;
651711bcba0SDavid C Somayajulu 
652711bcba0SDavid C Somayajulu qls_alloc_dmabuf_exit:
653711bcba0SDavid C Somayajulu         QL_DPRINT2((dev, "%s: exit ret 0x%08x tag %p map %p b %p sz 0x%x\n",
654711bcba0SDavid C Somayajulu                 __func__, ret, (void *)dma_buf->dma_tag,
655711bcba0SDavid C Somayajulu                 (void *)dma_buf->dma_map, (void *)dma_buf->dma_b,
656711bcba0SDavid C Somayajulu 		dma_buf->size));
657711bcba0SDavid C Somayajulu 
658711bcba0SDavid C Somayajulu         return ret;
659711bcba0SDavid C Somayajulu }
660711bcba0SDavid C Somayajulu 
661711bcba0SDavid C Somayajulu void
662711bcba0SDavid C Somayajulu qls_free_dmabuf(qla_host_t *ha, qla_dma_t *dma_buf)
663711bcba0SDavid C Somayajulu {
664aeeb653cSJohn Baldwin         bus_dmamap_unload(dma_buf->dma_tag, dma_buf->dma_map);
665711bcba0SDavid C Somayajulu         bus_dmamem_free(dma_buf->dma_tag, dma_buf->dma_b, dma_buf->dma_map);
666711bcba0SDavid C Somayajulu         bus_dma_tag_destroy(dma_buf->dma_tag);
667711bcba0SDavid C Somayajulu }
668711bcba0SDavid C Somayajulu 
669711bcba0SDavid C Somayajulu static int
670711bcba0SDavid C Somayajulu qls_alloc_parent_dma_tag(qla_host_t *ha)
671711bcba0SDavid C Somayajulu {
672711bcba0SDavid C Somayajulu 	int		ret;
673711bcba0SDavid C Somayajulu 	device_t	dev;
674711bcba0SDavid C Somayajulu 
675711bcba0SDavid C Somayajulu 	dev = ha->pci_dev;
676711bcba0SDavid C Somayajulu 
677711bcba0SDavid C Somayajulu         /*
678711bcba0SDavid C Somayajulu          * Allocate parent DMA Tag
679711bcba0SDavid C Somayajulu          */
680711bcba0SDavid C Somayajulu         ret = bus_dma_tag_create(
681711bcba0SDavid C Somayajulu                         bus_get_dma_tag(dev),   /* parent */
682711bcba0SDavid C Somayajulu                         1,((bus_size_t)(1ULL << 32)),/* alignment, boundary */
683711bcba0SDavid C Somayajulu                         BUS_SPACE_MAXADDR,      /* lowaddr */
684711bcba0SDavid C Somayajulu                         BUS_SPACE_MAXADDR,      /* highaddr */
685711bcba0SDavid C Somayajulu                         NULL, NULL,             /* filter, filterarg */
686711bcba0SDavid C Somayajulu                         BUS_SPACE_MAXSIZE_32BIT,/* maxsize */
687711bcba0SDavid C Somayajulu                         0,                      /* nsegments */
688711bcba0SDavid C Somayajulu                         BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
689711bcba0SDavid C Somayajulu                         0,                      /* flags */
690711bcba0SDavid C Somayajulu                         NULL, NULL,             /* lockfunc, lockarg */
691711bcba0SDavid C Somayajulu                         &ha->parent_tag);
692711bcba0SDavid C Somayajulu 
693711bcba0SDavid C Somayajulu         if (ret) {
694711bcba0SDavid C Somayajulu                 device_printf(dev, "%s: could not create parent dma tag\n",
695711bcba0SDavid C Somayajulu                         __func__);
696711bcba0SDavid C Somayajulu 		return (-1);
697711bcba0SDavid C Somayajulu         }
698711bcba0SDavid C Somayajulu 
699711bcba0SDavid C Somayajulu         ha->flags.parent_tag = 1;
700711bcba0SDavid C Somayajulu 
701711bcba0SDavid C Somayajulu 	return (0);
702711bcba0SDavid C Somayajulu }
703711bcba0SDavid C Somayajulu 
704711bcba0SDavid C Somayajulu static void
705711bcba0SDavid C Somayajulu qls_free_parent_dma_tag(qla_host_t *ha)
706711bcba0SDavid C Somayajulu {
707711bcba0SDavid C Somayajulu         if (ha->flags.parent_tag) {
708711bcba0SDavid C Somayajulu                 bus_dma_tag_destroy(ha->parent_tag);
709711bcba0SDavid C Somayajulu                 ha->flags.parent_tag = 0;
710711bcba0SDavid C Somayajulu         }
711711bcba0SDavid C Somayajulu }
712711bcba0SDavid C Somayajulu 
713711bcba0SDavid C Somayajulu /*
714711bcba0SDavid C Somayajulu  * Name: qls_init_ifnet
715711bcba0SDavid C Somayajulu  * Function: Creates the Network Device Interface and Registers it with the O.S
716711bcba0SDavid C Somayajulu  */
717711bcba0SDavid C Somayajulu 
718711bcba0SDavid C Somayajulu static void
719711bcba0SDavid C Somayajulu qls_init_ifnet(device_t dev, qla_host_t *ha)
720711bcba0SDavid C Somayajulu {
721711bcba0SDavid C Somayajulu 	struct ifnet *ifp;
722711bcba0SDavid C Somayajulu 
723711bcba0SDavid C Somayajulu 	QL_DPRINT2((dev, "%s: enter\n", __func__));
724711bcba0SDavid C Somayajulu 
725711bcba0SDavid C Somayajulu 	ifp = ha->ifp = if_alloc(IFT_ETHER);
726711bcba0SDavid C Somayajulu 
727711bcba0SDavid C Somayajulu 	if (ifp == NULL)
728711bcba0SDavid C Somayajulu 		panic("%s: cannot if_alloc()\n", device_get_nameunit(dev));
729711bcba0SDavid C Somayajulu 
730711bcba0SDavid C Somayajulu 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
731b245f96cSGleb Smirnoff 	ifp->if_baudrate = IF_Gbps(10);
732711bcba0SDavid C Somayajulu 	ifp->if_init = qls_init;
733711bcba0SDavid C Somayajulu 	ifp->if_softc = ha;
734711bcba0SDavid C Somayajulu 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
735711bcba0SDavid C Somayajulu 	ifp->if_ioctl = qls_ioctl;
736711bcba0SDavid C Somayajulu 	ifp->if_start = qls_start;
737711bcba0SDavid C Somayajulu 
738711bcba0SDavid C Somayajulu 	IFQ_SET_MAXLEN(&ifp->if_snd, qls_get_ifq_snd_maxlen(ha));
739711bcba0SDavid C Somayajulu 	ifp->if_snd.ifq_drv_maxlen = qls_get_ifq_snd_maxlen(ha);
740711bcba0SDavid C Somayajulu 	IFQ_SET_READY(&ifp->if_snd);
741711bcba0SDavid C Somayajulu 
742711bcba0SDavid C Somayajulu 	ha->max_frame_size = ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN;
743711bcba0SDavid C Somayajulu 	if (ha->max_frame_size <= MCLBYTES) {
744711bcba0SDavid C Somayajulu 		ha->msize = MCLBYTES;
745711bcba0SDavid C Somayajulu 	} else if (ha->max_frame_size <= MJUMPAGESIZE) {
746711bcba0SDavid C Somayajulu 		ha->msize = MJUMPAGESIZE;
747711bcba0SDavid C Somayajulu 	} else
748711bcba0SDavid C Somayajulu 		ha->msize = MJUM9BYTES;
749711bcba0SDavid C Somayajulu 
750711bcba0SDavid C Somayajulu 	ether_ifattach(ifp, qls_get_mac_addr(ha));
751711bcba0SDavid C Somayajulu 
752711bcba0SDavid C Somayajulu 	ifp->if_capabilities = IFCAP_JUMBO_MTU;
753711bcba0SDavid C Somayajulu 
754711bcba0SDavid C Somayajulu 	ifp->if_capabilities |= IFCAP_HWCSUM;
755711bcba0SDavid C Somayajulu 	ifp->if_capabilities |= IFCAP_VLAN_MTU;
756711bcba0SDavid C Somayajulu 
757711bcba0SDavid C Somayajulu 	ifp->if_capabilities |= IFCAP_TSO4;
758711bcba0SDavid C Somayajulu 	ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
759711bcba0SDavid C Somayajulu 	ifp->if_capabilities |= IFCAP_VLAN_HWTSO;
760711bcba0SDavid C Somayajulu 	ifp->if_capabilities |= IFCAP_LINKSTATE;
761711bcba0SDavid C Somayajulu 
762711bcba0SDavid C Somayajulu 	ifp->if_capenable = ifp->if_capabilities;
763711bcba0SDavid C Somayajulu 
7641bffa951SGleb Smirnoff 	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
765711bcba0SDavid C Somayajulu 
766711bcba0SDavid C Somayajulu 	ifmedia_init(&ha->media, IFM_IMASK, qls_media_change, qls_media_status);
767711bcba0SDavid C Somayajulu 
768711bcba0SDavid C Somayajulu 	ifmedia_add(&ha->media, (IFM_ETHER | qls_get_optics(ha) | IFM_FDX), 0,
769711bcba0SDavid C Somayajulu 		NULL);
770711bcba0SDavid C Somayajulu 	ifmedia_add(&ha->media, (IFM_ETHER | IFM_AUTO), 0, NULL);
771711bcba0SDavid C Somayajulu 
772711bcba0SDavid C Somayajulu 	ifmedia_set(&ha->media, (IFM_ETHER | IFM_AUTO));
773711bcba0SDavid C Somayajulu 
774711bcba0SDavid C Somayajulu 	QL_DPRINT2((dev, "%s: exit\n", __func__));
775711bcba0SDavid C Somayajulu 
776711bcba0SDavid C Somayajulu 	return;
777711bcba0SDavid C Somayajulu }
778711bcba0SDavid C Somayajulu 
779711bcba0SDavid C Somayajulu static void
780711bcba0SDavid C Somayajulu qls_init_locked(qla_host_t *ha)
781711bcba0SDavid C Somayajulu {
782711bcba0SDavid C Somayajulu 	struct ifnet *ifp = ha->ifp;
783711bcba0SDavid C Somayajulu 
784711bcba0SDavid C Somayajulu 	qls_stop(ha);
785711bcba0SDavid C Somayajulu 
786711bcba0SDavid C Somayajulu 	qls_flush_xmt_bufs(ha);
787711bcba0SDavid C Somayajulu 
788711bcba0SDavid C Somayajulu 	if (qls_alloc_rcv_bufs(ha) != 0)
789711bcba0SDavid C Somayajulu 		return;
790711bcba0SDavid C Somayajulu 
791711bcba0SDavid C Somayajulu 	if (qls_config_lro(ha))
792711bcba0SDavid C Somayajulu 		return;
793711bcba0SDavid C Somayajulu 
794711bcba0SDavid C Somayajulu 	bcopy(IF_LLADDR(ha->ifp), ha->mac_addr, ETHER_ADDR_LEN);
795711bcba0SDavid C Somayajulu 
796711bcba0SDavid C Somayajulu 	ifp->if_hwassist = CSUM_IP;
797711bcba0SDavid C Somayajulu 	ifp->if_hwassist |= CSUM_TCP;
798711bcba0SDavid C Somayajulu 	ifp->if_hwassist |= CSUM_UDP;
799711bcba0SDavid C Somayajulu 	ifp->if_hwassist |= CSUM_TSO;
800711bcba0SDavid C Somayajulu 
801711bcba0SDavid C Somayajulu  	if (qls_init_hw_if(ha) == 0) {
802711bcba0SDavid C Somayajulu 		ifp = ha->ifp;
803711bcba0SDavid C Somayajulu 		ifp->if_drv_flags |= IFF_DRV_RUNNING;
804711bcba0SDavid C Somayajulu 		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
805711bcba0SDavid C Somayajulu 		ha->flags.qla_watchdog_pause = 0;
806711bcba0SDavid C Somayajulu 	}
807711bcba0SDavid C Somayajulu 
808711bcba0SDavid C Somayajulu 	return;
809711bcba0SDavid C Somayajulu }
810711bcba0SDavid C Somayajulu 
811711bcba0SDavid C Somayajulu static void
812711bcba0SDavid C Somayajulu qls_init(void *arg)
813711bcba0SDavid C Somayajulu {
814711bcba0SDavid C Somayajulu 	qla_host_t *ha;
815711bcba0SDavid C Somayajulu 
816711bcba0SDavid C Somayajulu 	ha = (qla_host_t *)arg;
817711bcba0SDavid C Somayajulu 
818711bcba0SDavid C Somayajulu 	QL_DPRINT2((ha->pci_dev, "%s: enter\n", __func__));
819711bcba0SDavid C Somayajulu 
820711bcba0SDavid C Somayajulu 	(void)QLA_LOCK(ha, __func__, 0);
821711bcba0SDavid C Somayajulu 	qls_init_locked(ha);
822711bcba0SDavid C Somayajulu 	QLA_UNLOCK(ha, __func__);
823711bcba0SDavid C Somayajulu 
824711bcba0SDavid C Somayajulu 	QL_DPRINT2((ha->pci_dev, "%s: exit\n", __func__));
825711bcba0SDavid C Somayajulu }
826711bcba0SDavid C Somayajulu 
8276dfd0870SGleb Smirnoff static u_int
8286dfd0870SGleb Smirnoff qls_copy_maddr(void *arg, struct sockaddr_dl *sdl, u_int mcnt)
8296dfd0870SGleb Smirnoff {
8306dfd0870SGleb Smirnoff 	uint8_t *mta = arg;
8316dfd0870SGleb Smirnoff 
8326dfd0870SGleb Smirnoff 	if (mcnt == Q8_MAX_NUM_MULTICAST_ADDRS)
8336dfd0870SGleb Smirnoff 		return (0);
8346dfd0870SGleb Smirnoff 
8356dfd0870SGleb Smirnoff 	bcopy(LLADDR(sdl), &mta[mcnt * Q8_MAC_ADDR_LEN], Q8_MAC_ADDR_LEN);
8366dfd0870SGleb Smirnoff 
8376dfd0870SGleb Smirnoff 	return (1);
8386dfd0870SGleb Smirnoff }
8396dfd0870SGleb Smirnoff 
840711bcba0SDavid C Somayajulu static void
841711bcba0SDavid C Somayajulu qls_set_multi(qla_host_t *ha, uint32_t add_multi)
842711bcba0SDavid C Somayajulu {
843711bcba0SDavid C Somayajulu 	uint8_t mta[Q8_MAX_NUM_MULTICAST_ADDRS * Q8_MAC_ADDR_LEN];
844711bcba0SDavid C Somayajulu 	struct ifnet *ifp = ha->ifp;
8456dfd0870SGleb Smirnoff 	int mcnt;
846711bcba0SDavid C Somayajulu 
8476dfd0870SGleb Smirnoff 	mcnt = if_foreach_llmaddr(ifp, qls_copy_maddr, mta);
848711bcba0SDavid C Somayajulu 
849711bcba0SDavid C Somayajulu 	if (QLA_LOCK(ha, __func__, 1) == 0) {
850711bcba0SDavid C Somayajulu 		qls_hw_set_multi(ha, mta, mcnt, add_multi);
851711bcba0SDavid C Somayajulu 		QLA_UNLOCK(ha, __func__);
852711bcba0SDavid C Somayajulu 	}
853711bcba0SDavid C Somayajulu 
854711bcba0SDavid C Somayajulu 	return;
855711bcba0SDavid C Somayajulu }
856711bcba0SDavid C Somayajulu 
857711bcba0SDavid C Somayajulu static int
858711bcba0SDavid C Somayajulu qls_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
859711bcba0SDavid C Somayajulu {
860711bcba0SDavid C Somayajulu 	int ret = 0;
861711bcba0SDavid C Somayajulu 	struct ifreq *ifr = (struct ifreq *)data;
862*618aa8cdSJohn Baldwin #ifdef INET
863711bcba0SDavid C Somayajulu 	struct ifaddr *ifa = (struct ifaddr *)data;
864*618aa8cdSJohn Baldwin #endif
865711bcba0SDavid C Somayajulu 	qla_host_t *ha;
866711bcba0SDavid C Somayajulu 
867711bcba0SDavid C Somayajulu 	ha = (qla_host_t *)ifp->if_softc;
868711bcba0SDavid C Somayajulu 
869711bcba0SDavid C Somayajulu 	switch (cmd) {
870711bcba0SDavid C Somayajulu 	case SIOCSIFADDR:
871711bcba0SDavid C Somayajulu 		QL_DPRINT4((ha->pci_dev, "%s: SIOCSIFADDR (0x%lx)\n",
872711bcba0SDavid C Somayajulu 			__func__, cmd));
873711bcba0SDavid C Somayajulu 
874*618aa8cdSJohn Baldwin #ifdef INET
875711bcba0SDavid C Somayajulu 		if (ifa->ifa_addr->sa_family == AF_INET) {
876711bcba0SDavid C Somayajulu 			ifp->if_flags |= IFF_UP;
877711bcba0SDavid C Somayajulu 			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
878711bcba0SDavid C Somayajulu 				(void)QLA_LOCK(ha, __func__, 0);
879711bcba0SDavid C Somayajulu 				qls_init_locked(ha);
880711bcba0SDavid C Somayajulu 				QLA_UNLOCK(ha, __func__);
881711bcba0SDavid C Somayajulu 			}
882711bcba0SDavid C Somayajulu 			QL_DPRINT4((ha->pci_dev,
883711bcba0SDavid C Somayajulu 				"%s: SIOCSIFADDR (0x%lx) ipv4 [0x%08x]\n",
884711bcba0SDavid C Somayajulu 				__func__, cmd,
885711bcba0SDavid C Somayajulu 				ntohl(IA_SIN(ifa)->sin_addr.s_addr)));
886711bcba0SDavid C Somayajulu 
887711bcba0SDavid C Somayajulu 			arp_ifinit(ifp, ifa);
888*618aa8cdSJohn Baldwin 			break;
889711bcba0SDavid C Somayajulu 		}
890*618aa8cdSJohn Baldwin #endif
891*618aa8cdSJohn Baldwin 		ether_ioctl(ifp, cmd, data);
892711bcba0SDavid C Somayajulu 		break;
893711bcba0SDavid C Somayajulu 
894711bcba0SDavid C Somayajulu 	case SIOCSIFMTU:
895711bcba0SDavid C Somayajulu 		QL_DPRINT4((ha->pci_dev, "%s: SIOCSIFMTU (0x%lx)\n",
896711bcba0SDavid C Somayajulu 			__func__, cmd));
897711bcba0SDavid C Somayajulu 
898711bcba0SDavid C Somayajulu 		if (ifr->ifr_mtu > QLA_MAX_MTU) {
899711bcba0SDavid C Somayajulu 			ret = EINVAL;
900711bcba0SDavid C Somayajulu 		} else {
901711bcba0SDavid C Somayajulu 			(void) QLA_LOCK(ha, __func__, 0);
902711bcba0SDavid C Somayajulu 
903711bcba0SDavid C Somayajulu 			ifp->if_mtu = ifr->ifr_mtu;
904711bcba0SDavid C Somayajulu 			ha->max_frame_size =
905711bcba0SDavid C Somayajulu 				ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN;
906711bcba0SDavid C Somayajulu 
907711bcba0SDavid C Somayajulu 			QLA_UNLOCK(ha, __func__);
908711bcba0SDavid C Somayajulu 
909711bcba0SDavid C Somayajulu 			if (ret)
910711bcba0SDavid C Somayajulu 				ret = EINVAL;
911711bcba0SDavid C Somayajulu 		}
912711bcba0SDavid C Somayajulu 
913711bcba0SDavid C Somayajulu 		break;
914711bcba0SDavid C Somayajulu 
915711bcba0SDavid C Somayajulu 	case SIOCSIFFLAGS:
916711bcba0SDavid C Somayajulu 		QL_DPRINT4((ha->pci_dev, "%s: SIOCSIFFLAGS (0x%lx)\n",
917711bcba0SDavid C Somayajulu 			__func__, cmd));
918711bcba0SDavid C Somayajulu 
919711bcba0SDavid C Somayajulu 		(void)QLA_LOCK(ha, __func__, 0);
920711bcba0SDavid C Somayajulu 
921711bcba0SDavid C Somayajulu 		if (ifp->if_flags & IFF_UP) {
922711bcba0SDavid C Somayajulu 			if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) {
923711bcba0SDavid C Somayajulu 				if ((ifp->if_flags ^ ha->if_flags) &
924711bcba0SDavid C Somayajulu 					IFF_PROMISC) {
925711bcba0SDavid C Somayajulu 					ret = qls_set_promisc(ha);
926711bcba0SDavid C Somayajulu 				} else if ((ifp->if_flags ^ ha->if_flags) &
927711bcba0SDavid C Somayajulu 					IFF_ALLMULTI) {
928711bcba0SDavid C Somayajulu 					ret = qls_set_allmulti(ha);
929711bcba0SDavid C Somayajulu 				}
930711bcba0SDavid C Somayajulu 			} else {
931711bcba0SDavid C Somayajulu 				ha->max_frame_size = ifp->if_mtu +
932711bcba0SDavid C Somayajulu 					ETHER_HDR_LEN + ETHER_CRC_LEN;
933711bcba0SDavid C Somayajulu 				qls_init_locked(ha);
934711bcba0SDavid C Somayajulu 			}
935711bcba0SDavid C Somayajulu 		} else {
936711bcba0SDavid C Somayajulu 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
937711bcba0SDavid C Somayajulu 				qls_stop(ha);
938711bcba0SDavid C Somayajulu 			ha->if_flags = ifp->if_flags;
939711bcba0SDavid C Somayajulu 		}
940711bcba0SDavid C Somayajulu 
941711bcba0SDavid C Somayajulu 		QLA_UNLOCK(ha, __func__);
942711bcba0SDavid C Somayajulu 		break;
943711bcba0SDavid C Somayajulu 
944711bcba0SDavid C Somayajulu 	case SIOCADDMULTI:
945711bcba0SDavid C Somayajulu 		QL_DPRINT4((ha->pci_dev,
946711bcba0SDavid C Somayajulu 			"%s: %s (0x%lx)\n", __func__, "SIOCADDMULTI", cmd));
947711bcba0SDavid C Somayajulu 
948711bcba0SDavid C Somayajulu 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
949711bcba0SDavid C Somayajulu 			qls_set_multi(ha, 1);
950711bcba0SDavid C Somayajulu 		}
951711bcba0SDavid C Somayajulu 		break;
952711bcba0SDavid C Somayajulu 
953711bcba0SDavid C Somayajulu 	case SIOCDELMULTI:
954711bcba0SDavid C Somayajulu 		QL_DPRINT4((ha->pci_dev,
955711bcba0SDavid C Somayajulu 			"%s: %s (0x%lx)\n", __func__, "SIOCDELMULTI", cmd));
956711bcba0SDavid C Somayajulu 
957711bcba0SDavid C Somayajulu 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
958711bcba0SDavid C Somayajulu 			qls_set_multi(ha, 0);
959711bcba0SDavid C Somayajulu 		}
960711bcba0SDavid C Somayajulu 		break;
961711bcba0SDavid C Somayajulu 
962711bcba0SDavid C Somayajulu 	case SIOCSIFMEDIA:
963711bcba0SDavid C Somayajulu 	case SIOCGIFMEDIA:
964711bcba0SDavid C Somayajulu 		QL_DPRINT4((ha->pci_dev,
965711bcba0SDavid C Somayajulu 			"%s: SIOCSIFMEDIA/SIOCGIFMEDIA (0x%lx)\n",
966711bcba0SDavid C Somayajulu 			__func__, cmd));
967711bcba0SDavid C Somayajulu 		ret = ifmedia_ioctl(ifp, ifr, &ha->media, cmd);
968711bcba0SDavid C Somayajulu 		break;
969711bcba0SDavid C Somayajulu 
970711bcba0SDavid C Somayajulu 	case SIOCSIFCAP:
971711bcba0SDavid C Somayajulu 	{
972711bcba0SDavid C Somayajulu 		int mask = ifr->ifr_reqcap ^ ifp->if_capenable;
973711bcba0SDavid C Somayajulu 
974711bcba0SDavid C Somayajulu 		QL_DPRINT4((ha->pci_dev, "%s: SIOCSIFCAP (0x%lx)\n",
975711bcba0SDavid C Somayajulu 			__func__, cmd));
976711bcba0SDavid C Somayajulu 
977711bcba0SDavid C Somayajulu 		if (mask & IFCAP_HWCSUM)
978711bcba0SDavid C Somayajulu 			ifp->if_capenable ^= IFCAP_HWCSUM;
979711bcba0SDavid C Somayajulu 		if (mask & IFCAP_TSO4)
980711bcba0SDavid C Somayajulu 			ifp->if_capenable ^= IFCAP_TSO4;
981711bcba0SDavid C Somayajulu 		if (mask & IFCAP_VLAN_HWTAGGING)
982711bcba0SDavid C Somayajulu 			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
983711bcba0SDavid C Somayajulu 		if (mask & IFCAP_VLAN_HWTSO)
984711bcba0SDavid C Somayajulu 			ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
985711bcba0SDavid C Somayajulu 
986711bcba0SDavid C Somayajulu 		if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
987711bcba0SDavid C Somayajulu 			qls_init(ha);
988711bcba0SDavid C Somayajulu 
989711bcba0SDavid C Somayajulu 		VLAN_CAPABILITIES(ifp);
990711bcba0SDavid C Somayajulu 		break;
991711bcba0SDavid C Somayajulu 	}
992711bcba0SDavid C Somayajulu 
993711bcba0SDavid C Somayajulu 	default:
994711bcba0SDavid C Somayajulu 		QL_DPRINT4((ha->pci_dev, "%s: default (0x%lx)\n",
995711bcba0SDavid C Somayajulu 			__func__, cmd));
996711bcba0SDavid C Somayajulu 		ret = ether_ioctl(ifp, cmd, data);
997711bcba0SDavid C Somayajulu 		break;
998711bcba0SDavid C Somayajulu 	}
999711bcba0SDavid C Somayajulu 
1000711bcba0SDavid C Somayajulu 	return (ret);
1001711bcba0SDavid C Somayajulu }
1002711bcba0SDavid C Somayajulu 
1003711bcba0SDavid C Somayajulu static int
1004711bcba0SDavid C Somayajulu qls_media_change(struct ifnet *ifp)
1005711bcba0SDavid C Somayajulu {
1006711bcba0SDavid C Somayajulu 	qla_host_t *ha;
1007711bcba0SDavid C Somayajulu 	struct ifmedia *ifm;
1008711bcba0SDavid C Somayajulu 	int ret = 0;
1009711bcba0SDavid C Somayajulu 
1010711bcba0SDavid C Somayajulu 	ha = (qla_host_t *)ifp->if_softc;
1011711bcba0SDavid C Somayajulu 
1012711bcba0SDavid C Somayajulu 	QL_DPRINT2((ha->pci_dev, "%s: enter\n", __func__));
1013711bcba0SDavid C Somayajulu 
1014711bcba0SDavid C Somayajulu 	ifm = &ha->media;
1015711bcba0SDavid C Somayajulu 
1016711bcba0SDavid C Somayajulu 	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
1017711bcba0SDavid C Somayajulu 		ret = EINVAL;
1018711bcba0SDavid C Somayajulu 
1019711bcba0SDavid C Somayajulu 	QL_DPRINT2((ha->pci_dev, "%s: exit\n", __func__));
1020711bcba0SDavid C Somayajulu 
1021711bcba0SDavid C Somayajulu 	return (ret);
1022711bcba0SDavid C Somayajulu }
1023711bcba0SDavid C Somayajulu 
1024711bcba0SDavid C Somayajulu static void
1025711bcba0SDavid C Somayajulu qls_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
1026711bcba0SDavid C Somayajulu {
1027711bcba0SDavid C Somayajulu 	qla_host_t *ha;
1028711bcba0SDavid C Somayajulu 
1029711bcba0SDavid C Somayajulu 	ha = (qla_host_t *)ifp->if_softc;
1030711bcba0SDavid C Somayajulu 
1031711bcba0SDavid C Somayajulu 	QL_DPRINT2((ha->pci_dev, "%s: enter\n", __func__));
1032711bcba0SDavid C Somayajulu 
1033711bcba0SDavid C Somayajulu 	ifmr->ifm_status = IFM_AVALID;
1034711bcba0SDavid C Somayajulu 	ifmr->ifm_active = IFM_ETHER;
1035711bcba0SDavid C Somayajulu 
1036711bcba0SDavid C Somayajulu 	qls_update_link_state(ha);
1037711bcba0SDavid C Somayajulu 	if (ha->link_up) {
1038711bcba0SDavid C Somayajulu 		ifmr->ifm_status |= IFM_ACTIVE;
1039711bcba0SDavid C Somayajulu 		ifmr->ifm_active |= (IFM_FDX | qls_get_optics(ha));
1040711bcba0SDavid C Somayajulu 	}
1041711bcba0SDavid C Somayajulu 
1042711bcba0SDavid C Somayajulu 	QL_DPRINT2((ha->pci_dev, "%s: exit (%s)\n", __func__,\
1043711bcba0SDavid C Somayajulu 		(ha->link_up ? "link_up" : "link_down")));
1044711bcba0SDavid C Somayajulu 
1045711bcba0SDavid C Somayajulu 	return;
1046711bcba0SDavid C Somayajulu }
1047711bcba0SDavid C Somayajulu 
1048711bcba0SDavid C Somayajulu static void
1049711bcba0SDavid C Somayajulu qls_start(struct ifnet *ifp)
1050711bcba0SDavid C Somayajulu {
1051711bcba0SDavid C Somayajulu 	int		i, ret = 0;
1052711bcba0SDavid C Somayajulu 	struct mbuf	*m_head;
1053711bcba0SDavid C Somayajulu 	qla_host_t	*ha = (qla_host_t *)ifp->if_softc;
1054711bcba0SDavid C Somayajulu 
1055711bcba0SDavid C Somayajulu 	QL_DPRINT8((ha->pci_dev, "%s: enter\n", __func__));
1056711bcba0SDavid C Somayajulu 
1057711bcba0SDavid C Somayajulu 	if (!mtx_trylock(&ha->tx_lock)) {
1058711bcba0SDavid C Somayajulu 		QL_DPRINT8((ha->pci_dev,
1059711bcba0SDavid C Somayajulu 			"%s: mtx_trylock(&ha->tx_lock) failed\n", __func__));
1060711bcba0SDavid C Somayajulu 		return;
1061711bcba0SDavid C Somayajulu 	}
1062711bcba0SDavid C Somayajulu 
1063711bcba0SDavid C Somayajulu 	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) ==
1064711bcba0SDavid C Somayajulu 		IFF_DRV_RUNNING) {
1065711bcba0SDavid C Somayajulu 		for (i = 0; i < ha->num_tx_rings; i++) {
1066711bcba0SDavid C Somayajulu 			ret |= qls_hw_tx_done(ha, i);
1067711bcba0SDavid C Somayajulu 		}
1068711bcba0SDavid C Somayajulu 
1069711bcba0SDavid C Somayajulu 		if (ret == 0)
1070711bcba0SDavid C Somayajulu 			ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1071711bcba0SDavid C Somayajulu 	}
1072711bcba0SDavid C Somayajulu 
1073711bcba0SDavid C Somayajulu 	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
1074711bcba0SDavid C Somayajulu 		IFF_DRV_RUNNING) {
1075711bcba0SDavid C Somayajulu 		QL_DPRINT8((ha->pci_dev, "%s: !IFF_DRV_RUNNING\n", __func__));
1076711bcba0SDavid C Somayajulu 		QLA_TX_UNLOCK(ha);
1077711bcba0SDavid C Somayajulu 		return;
1078711bcba0SDavid C Somayajulu 	}
1079711bcba0SDavid C Somayajulu 
1080711bcba0SDavid C Somayajulu 	if (!ha->link_up) {
1081711bcba0SDavid C Somayajulu 		qls_update_link_state(ha);
1082711bcba0SDavid C Somayajulu 		if (!ha->link_up) {
1083711bcba0SDavid C Somayajulu 			QL_DPRINT8((ha->pci_dev, "%s: link down\n", __func__));
1084711bcba0SDavid C Somayajulu 			QLA_TX_UNLOCK(ha);
1085711bcba0SDavid C Somayajulu 			return;
1086711bcba0SDavid C Somayajulu 		}
1087711bcba0SDavid C Somayajulu 	}
1088711bcba0SDavid C Somayajulu 
1089711bcba0SDavid C Somayajulu 	while (ifp->if_snd.ifq_head != NULL) {
1090711bcba0SDavid C Somayajulu 		IF_DEQUEUE(&ifp->if_snd, m_head);
1091711bcba0SDavid C Somayajulu 
1092711bcba0SDavid C Somayajulu 		if (m_head == NULL) {
1093711bcba0SDavid C Somayajulu 			QL_DPRINT8((ha->pci_dev, "%s: m_head == NULL\n",
1094711bcba0SDavid C Somayajulu 				__func__));
1095711bcba0SDavid C Somayajulu 			break;
1096711bcba0SDavid C Somayajulu 		}
1097711bcba0SDavid C Somayajulu 
1098711bcba0SDavid C Somayajulu 		if (qls_send(ha, &m_head)) {
1099711bcba0SDavid C Somayajulu 			if (m_head == NULL)
1100711bcba0SDavid C Somayajulu 				break;
1101711bcba0SDavid C Somayajulu 			QL_DPRINT8((ha->pci_dev, "%s: PREPEND\n", __func__));
1102711bcba0SDavid C Somayajulu 			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1103711bcba0SDavid C Somayajulu 			IF_PREPEND(&ifp->if_snd, m_head);
1104711bcba0SDavid C Somayajulu 			break;
1105711bcba0SDavid C Somayajulu 		}
1106711bcba0SDavid C Somayajulu 		/* Send a copy of the frame to the BPF listener */
1107711bcba0SDavid C Somayajulu 		ETHER_BPF_MTAP(ifp, m_head);
1108711bcba0SDavid C Somayajulu 	}
1109711bcba0SDavid C Somayajulu 
1110711bcba0SDavid C Somayajulu 	QLA_TX_UNLOCK(ha);
1111711bcba0SDavid C Somayajulu 	QL_DPRINT8((ha->pci_dev, "%s: exit\n", __func__));
1112711bcba0SDavid C Somayajulu 	return;
1113711bcba0SDavid C Somayajulu }
1114711bcba0SDavid C Somayajulu 
1115711bcba0SDavid C Somayajulu static int
1116711bcba0SDavid C Somayajulu qls_send(qla_host_t *ha, struct mbuf **m_headp)
1117711bcba0SDavid C Somayajulu {
1118711bcba0SDavid C Somayajulu 	bus_dma_segment_t	segs[QLA_MAX_SEGMENTS];
1119711bcba0SDavid C Somayajulu 	bus_dmamap_t		map;
1120711bcba0SDavid C Somayajulu 	int			nsegs;
1121711bcba0SDavid C Somayajulu 	int			ret = -1;
1122711bcba0SDavid C Somayajulu 	uint32_t		tx_idx;
1123711bcba0SDavid C Somayajulu 	struct mbuf		*m_head = *m_headp;
1124711bcba0SDavid C Somayajulu 	uint32_t		txr_idx = 0;
1125711bcba0SDavid C Somayajulu 
1126711bcba0SDavid C Somayajulu 	QL_DPRINT8((ha->pci_dev, "%s: enter\n", __func__));
1127711bcba0SDavid C Somayajulu 
1128c2529042SHans Petter Selasky 	/* check if flowid is set */
1129c2529042SHans Petter Selasky 	if (M_HASHTYPE_GET(m_head) != M_HASHTYPE_NONE)
1130711bcba0SDavid C Somayajulu 		txr_idx = m_head->m_pkthdr.flowid & (ha->num_tx_rings - 1);
1131711bcba0SDavid C Somayajulu 
1132711bcba0SDavid C Somayajulu 	tx_idx = ha->tx_ring[txr_idx].txr_next;
1133711bcba0SDavid C Somayajulu 
1134711bcba0SDavid C Somayajulu 	map = ha->tx_ring[txr_idx].tx_buf[tx_idx].map;
1135711bcba0SDavid C Somayajulu 
1136711bcba0SDavid C Somayajulu 	ret = bus_dmamap_load_mbuf_sg(ha->tx_tag, map, m_head, segs, &nsegs,
1137711bcba0SDavid C Somayajulu 			BUS_DMA_NOWAIT);
1138711bcba0SDavid C Somayajulu 
1139711bcba0SDavid C Somayajulu 	if (ret == EFBIG) {
1140711bcba0SDavid C Somayajulu 		struct mbuf *m;
1141711bcba0SDavid C Somayajulu 
1142711bcba0SDavid C Somayajulu 		QL_DPRINT8((ha->pci_dev, "%s: EFBIG [%d]\n", __func__,
1143711bcba0SDavid C Somayajulu 			m_head->m_pkthdr.len));
1144711bcba0SDavid C Somayajulu 
1145b8c83a19SGleb Smirnoff 		m = m_defrag(m_head, M_NOWAIT);
1146711bcba0SDavid C Somayajulu 		if (m == NULL) {
1147711bcba0SDavid C Somayajulu 			ha->err_tx_defrag++;
1148711bcba0SDavid C Somayajulu 			m_freem(m_head);
1149711bcba0SDavid C Somayajulu 			*m_headp = NULL;
1150711bcba0SDavid C Somayajulu 			device_printf(ha->pci_dev,
1151711bcba0SDavid C Somayajulu 				"%s: m_defrag() = NULL [%d]\n",
1152711bcba0SDavid C Somayajulu 				__func__, ret);
1153711bcba0SDavid C Somayajulu 			return (ENOBUFS);
1154711bcba0SDavid C Somayajulu 		}
1155711bcba0SDavid C Somayajulu 		m_head = m;
1156711bcba0SDavid C Somayajulu 		*m_headp = m_head;
1157711bcba0SDavid C Somayajulu 
1158711bcba0SDavid C Somayajulu 		if ((ret = bus_dmamap_load_mbuf_sg(ha->tx_tag, map, m_head,
1159711bcba0SDavid C Somayajulu 					segs, &nsegs, BUS_DMA_NOWAIT))) {
1160711bcba0SDavid C Somayajulu 			ha->err_tx_dmamap_load++;
1161711bcba0SDavid C Somayajulu 
1162711bcba0SDavid C Somayajulu 			device_printf(ha->pci_dev,
1163711bcba0SDavid C Somayajulu 				"%s: bus_dmamap_load_mbuf_sg failed0[%d, %d]\n",
1164711bcba0SDavid C Somayajulu 				__func__, ret, m_head->m_pkthdr.len);
1165711bcba0SDavid C Somayajulu 
1166711bcba0SDavid C Somayajulu 			if (ret != ENOMEM) {
1167711bcba0SDavid C Somayajulu 				m_freem(m_head);
1168711bcba0SDavid C Somayajulu 				*m_headp = NULL;
1169711bcba0SDavid C Somayajulu 			}
1170711bcba0SDavid C Somayajulu 			return (ret);
1171711bcba0SDavid C Somayajulu 		}
1172711bcba0SDavid C Somayajulu 
1173711bcba0SDavid C Somayajulu 	} else if (ret) {
1174711bcba0SDavid C Somayajulu 		ha->err_tx_dmamap_load++;
1175711bcba0SDavid C Somayajulu 
1176711bcba0SDavid C Somayajulu 		device_printf(ha->pci_dev,
1177711bcba0SDavid C Somayajulu 			"%s: bus_dmamap_load_mbuf_sg failed1[%d, %d]\n",
1178711bcba0SDavid C Somayajulu 			__func__, ret, m_head->m_pkthdr.len);
1179711bcba0SDavid C Somayajulu 
1180711bcba0SDavid C Somayajulu 		if (ret != ENOMEM) {
1181711bcba0SDavid C Somayajulu 			m_freem(m_head);
1182711bcba0SDavid C Somayajulu 			*m_headp = NULL;
1183711bcba0SDavid C Somayajulu 		}
1184711bcba0SDavid C Somayajulu 		return (ret);
1185711bcba0SDavid C Somayajulu 	}
1186711bcba0SDavid C Somayajulu 
1187711bcba0SDavid C Somayajulu 	QL_ASSERT(ha, (nsegs != 0), ("qls_send: empty packet"));
1188711bcba0SDavid C Somayajulu 
1189711bcba0SDavid C Somayajulu 	bus_dmamap_sync(ha->tx_tag, map, BUS_DMASYNC_PREWRITE);
1190711bcba0SDavid C Somayajulu 
1191711bcba0SDavid C Somayajulu         if (!(ret = qls_hw_send(ha, segs, nsegs, tx_idx, m_head, txr_idx))) {
1192711bcba0SDavid C Somayajulu 		ha->tx_ring[txr_idx].count++;
1193711bcba0SDavid C Somayajulu 		ha->tx_ring[txr_idx].tx_buf[tx_idx].m_head = m_head;
1194711bcba0SDavid C Somayajulu 		ha->tx_ring[txr_idx].tx_buf[tx_idx].map = map;
1195711bcba0SDavid C Somayajulu 	} else {
1196711bcba0SDavid C Somayajulu 		if (ret == EINVAL) {
1197711bcba0SDavid C Somayajulu 			if (m_head)
1198711bcba0SDavid C Somayajulu 				m_freem(m_head);
1199711bcba0SDavid C Somayajulu 			*m_headp = NULL;
1200711bcba0SDavid C Somayajulu 		}
1201711bcba0SDavid C Somayajulu 	}
1202711bcba0SDavid C Somayajulu 
1203711bcba0SDavid C Somayajulu 	QL_DPRINT8((ha->pci_dev, "%s: exit\n", __func__));
1204711bcba0SDavid C Somayajulu 	return (ret);
1205711bcba0SDavid C Somayajulu }
1206711bcba0SDavid C Somayajulu 
1207711bcba0SDavid C Somayajulu static void
1208711bcba0SDavid C Somayajulu qls_stop(qla_host_t *ha)
1209711bcba0SDavid C Somayajulu {
1210711bcba0SDavid C Somayajulu 	struct ifnet *ifp = ha->ifp;
1211711bcba0SDavid C Somayajulu 
1212711bcba0SDavid C Somayajulu 	ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE | IFF_DRV_RUNNING);
1213711bcba0SDavid C Somayajulu 
1214711bcba0SDavid C Somayajulu 	ha->flags.qla_watchdog_pause = 1;
1215711bcba0SDavid C Somayajulu 
1216711bcba0SDavid C Somayajulu 	while (!ha->qla_watchdog_paused)
1217711bcba0SDavid C Somayajulu 		qls_mdelay(__func__, 1);
1218711bcba0SDavid C Somayajulu 
1219711bcba0SDavid C Somayajulu 	qls_del_hw_if(ha);
1220711bcba0SDavid C Somayajulu 
1221711bcba0SDavid C Somayajulu 	qls_free_lro(ha);
1222711bcba0SDavid C Somayajulu 
1223711bcba0SDavid C Somayajulu 	qls_flush_xmt_bufs(ha);
1224711bcba0SDavid C Somayajulu 	qls_free_rcv_bufs(ha);
1225711bcba0SDavid C Somayajulu 
1226711bcba0SDavid C Somayajulu 	return;
1227711bcba0SDavid C Somayajulu }
1228711bcba0SDavid C Somayajulu 
1229711bcba0SDavid C Somayajulu /*
1230711bcba0SDavid C Somayajulu  * Buffer Management Functions for Transmit and Receive Rings
1231711bcba0SDavid C Somayajulu  */
1232711bcba0SDavid C Somayajulu /*
1233711bcba0SDavid C Somayajulu  * Release mbuf after it sent on the wire
1234711bcba0SDavid C Somayajulu  */
1235711bcba0SDavid C Somayajulu static void
1236711bcba0SDavid C Somayajulu qls_flush_tx_buf(qla_host_t *ha, qla_tx_buf_t *txb)
1237711bcba0SDavid C Somayajulu {
1238711bcba0SDavid C Somayajulu 	QL_DPRINT2((ha->pci_dev, "%s: enter\n", __func__));
1239711bcba0SDavid C Somayajulu 
1240711bcba0SDavid C Somayajulu 	if (txb->m_head) {
1241711bcba0SDavid C Somayajulu 		bus_dmamap_unload(ha->tx_tag, txb->map);
1242711bcba0SDavid C Somayajulu 
1243711bcba0SDavid C Somayajulu 		m_freem(txb->m_head);
1244711bcba0SDavid C Somayajulu 		txb->m_head = NULL;
1245711bcba0SDavid C Somayajulu 	}
1246711bcba0SDavid C Somayajulu 
1247711bcba0SDavid C Somayajulu 	QL_DPRINT2((ha->pci_dev, "%s: exit\n", __func__));
1248711bcba0SDavid C Somayajulu }
1249711bcba0SDavid C Somayajulu 
1250711bcba0SDavid C Somayajulu static void
1251711bcba0SDavid C Somayajulu qls_flush_xmt_bufs(qla_host_t *ha)
1252711bcba0SDavid C Somayajulu {
1253711bcba0SDavid C Somayajulu 	int		i, j;
1254711bcba0SDavid C Somayajulu 
1255711bcba0SDavid C Somayajulu 	for (j = 0; j < ha->num_tx_rings; j++) {
1256711bcba0SDavid C Somayajulu 		for (i = 0; i < NUM_TX_DESCRIPTORS; i++)
1257711bcba0SDavid C Somayajulu 			qls_flush_tx_buf(ha, &ha->tx_ring[j].tx_buf[i]);
1258711bcba0SDavid C Somayajulu 	}
1259711bcba0SDavid C Somayajulu 
1260711bcba0SDavid C Somayajulu 	return;
1261711bcba0SDavid C Somayajulu }
1262711bcba0SDavid C Somayajulu 
1263711bcba0SDavid C Somayajulu static int
1264711bcba0SDavid C Somayajulu qls_alloc_rcv_mbufs(qla_host_t *ha, int r)
1265711bcba0SDavid C Somayajulu {
1266711bcba0SDavid C Somayajulu 	int			i, j, ret = 0;
1267711bcba0SDavid C Somayajulu 	qla_rx_buf_t		*rxb;
1268711bcba0SDavid C Somayajulu 	qla_rx_ring_t		*rx_ring;
1269711bcba0SDavid C Somayajulu 	volatile q81_bq_addr_e_t *sbq_e;
1270711bcba0SDavid C Somayajulu 
1271711bcba0SDavid C Somayajulu 	rx_ring = &ha->rx_ring[r];
1272711bcba0SDavid C Somayajulu 
1273711bcba0SDavid C Somayajulu 	for (i = 0; i < NUM_RX_DESCRIPTORS; i++) {
1274711bcba0SDavid C Somayajulu 		rxb = &rx_ring->rx_buf[i];
1275711bcba0SDavid C Somayajulu 
1276711bcba0SDavid C Somayajulu 		ret = bus_dmamap_create(ha->rx_tag, BUS_DMA_NOWAIT, &rxb->map);
1277711bcba0SDavid C Somayajulu 
1278711bcba0SDavid C Somayajulu 		if (ret) {
1279711bcba0SDavid C Somayajulu 			device_printf(ha->pci_dev,
1280711bcba0SDavid C Somayajulu 				"%s: dmamap[%d, %d] failed\n", __func__, r, i);
1281711bcba0SDavid C Somayajulu 
1282711bcba0SDavid C Somayajulu 			for (j = 0; j < i; j++) {
1283711bcba0SDavid C Somayajulu 				rxb = &rx_ring->rx_buf[j];
1284711bcba0SDavid C Somayajulu 				bus_dmamap_destroy(ha->rx_tag, rxb->map);
1285711bcba0SDavid C Somayajulu 			}
1286711bcba0SDavid C Somayajulu 			goto qls_alloc_rcv_mbufs_err;
1287711bcba0SDavid C Somayajulu 		}
1288711bcba0SDavid C Somayajulu 	}
1289711bcba0SDavid C Somayajulu 
1290711bcba0SDavid C Somayajulu 	rx_ring = &ha->rx_ring[r];
1291711bcba0SDavid C Somayajulu 
1292711bcba0SDavid C Somayajulu 	sbq_e = rx_ring->sbq_vaddr;
1293711bcba0SDavid C Somayajulu 
1294711bcba0SDavid C Somayajulu 	rxb = &rx_ring->rx_buf[0];
1295711bcba0SDavid C Somayajulu 
1296711bcba0SDavid C Somayajulu 	for (i = 0; i < NUM_RX_DESCRIPTORS; i++) {
1297711bcba0SDavid C Somayajulu 		if (!(ret = qls_get_mbuf(ha, rxb, NULL))) {
1298711bcba0SDavid C Somayajulu 			/*
1299711bcba0SDavid C Somayajulu 		 	 * set the physical address in the
1300711bcba0SDavid C Somayajulu 			 * corresponding descriptor entry in the
1301711bcba0SDavid C Somayajulu 			 * receive ring/queue for the hba
1302711bcba0SDavid C Somayajulu 			 */
1303711bcba0SDavid C Somayajulu 
1304711bcba0SDavid C Somayajulu 			sbq_e->addr_lo = rxb->paddr & 0xFFFFFFFF;
1305711bcba0SDavid C Somayajulu 			sbq_e->addr_hi = (rxb->paddr >> 32) & 0xFFFFFFFF;
1306711bcba0SDavid C Somayajulu 
1307711bcba0SDavid C Somayajulu 		} else {
1308711bcba0SDavid C Somayajulu 			device_printf(ha->pci_dev,
1309711bcba0SDavid C Somayajulu 				"%s: qls_get_mbuf [%d, %d] failed\n",
1310711bcba0SDavid C Somayajulu 					__func__, r, i);
1311711bcba0SDavid C Somayajulu 			bus_dmamap_destroy(ha->rx_tag, rxb->map);
1312711bcba0SDavid C Somayajulu 			goto qls_alloc_rcv_mbufs_err;
1313711bcba0SDavid C Somayajulu 		}
1314711bcba0SDavid C Somayajulu 
1315711bcba0SDavid C Somayajulu 		rxb++;
1316711bcba0SDavid C Somayajulu 		sbq_e++;
1317711bcba0SDavid C Somayajulu 	}
1318711bcba0SDavid C Somayajulu 	return 0;
1319711bcba0SDavid C Somayajulu 
1320711bcba0SDavid C Somayajulu qls_alloc_rcv_mbufs_err:
1321711bcba0SDavid C Somayajulu 	return (-1);
1322711bcba0SDavid C Somayajulu }
1323711bcba0SDavid C Somayajulu 
1324711bcba0SDavid C Somayajulu static void
1325711bcba0SDavid C Somayajulu qls_free_rcv_bufs(qla_host_t *ha)
1326711bcba0SDavid C Somayajulu {
1327711bcba0SDavid C Somayajulu 	int		i, r;
1328711bcba0SDavid C Somayajulu 	qla_rx_buf_t	*rxb;
1329711bcba0SDavid C Somayajulu 	qla_rx_ring_t	*rxr;
1330711bcba0SDavid C Somayajulu 
1331711bcba0SDavid C Somayajulu 	for (r = 0; r < ha->num_rx_rings; r++) {
1332711bcba0SDavid C Somayajulu 		rxr = &ha->rx_ring[r];
1333711bcba0SDavid C Somayajulu 
1334711bcba0SDavid C Somayajulu 		for (i = 0; i < NUM_RX_DESCRIPTORS; i++) {
1335711bcba0SDavid C Somayajulu 			rxb = &rxr->rx_buf[i];
1336711bcba0SDavid C Somayajulu 
1337711bcba0SDavid C Somayajulu 			if (rxb->m_head != NULL) {
1338711bcba0SDavid C Somayajulu 				bus_dmamap_unload(ha->rx_tag, rxb->map);
1339711bcba0SDavid C Somayajulu 				bus_dmamap_destroy(ha->rx_tag, rxb->map);
1340711bcba0SDavid C Somayajulu 				m_freem(rxb->m_head);
1341711bcba0SDavid C Somayajulu 			}
1342711bcba0SDavid C Somayajulu 		}
1343711bcba0SDavid C Somayajulu 		bzero(rxr->rx_buf, (sizeof(qla_rx_buf_t) * NUM_RX_DESCRIPTORS));
1344711bcba0SDavid C Somayajulu 	}
1345711bcba0SDavid C Somayajulu 	return;
1346711bcba0SDavid C Somayajulu }
1347711bcba0SDavid C Somayajulu 
1348711bcba0SDavid C Somayajulu static int
1349711bcba0SDavid C Somayajulu qls_alloc_rcv_bufs(qla_host_t *ha)
1350711bcba0SDavid C Somayajulu {
1351711bcba0SDavid C Somayajulu 	int		r, ret = 0;
1352711bcba0SDavid C Somayajulu 	qla_rx_ring_t	*rxr;
1353711bcba0SDavid C Somayajulu 
1354711bcba0SDavid C Somayajulu 	for (r = 0; r < ha->num_rx_rings; r++) {
1355711bcba0SDavid C Somayajulu 		rxr = &ha->rx_ring[r];
1356711bcba0SDavid C Somayajulu 		bzero(rxr->rx_buf, (sizeof(qla_rx_buf_t) * NUM_RX_DESCRIPTORS));
1357711bcba0SDavid C Somayajulu 	}
1358711bcba0SDavid C Somayajulu 
1359711bcba0SDavid C Somayajulu 	for (r = 0; r < ha->num_rx_rings; r++) {
1360711bcba0SDavid C Somayajulu 		ret = qls_alloc_rcv_mbufs(ha, r);
1361711bcba0SDavid C Somayajulu 
1362711bcba0SDavid C Somayajulu 		if (ret)
1363711bcba0SDavid C Somayajulu 			qls_free_rcv_bufs(ha);
1364711bcba0SDavid C Somayajulu 	}
1365711bcba0SDavid C Somayajulu 
1366711bcba0SDavid C Somayajulu 	return (ret);
1367711bcba0SDavid C Somayajulu }
1368711bcba0SDavid C Somayajulu 
1369711bcba0SDavid C Somayajulu int
1370711bcba0SDavid C Somayajulu qls_get_mbuf(qla_host_t *ha, qla_rx_buf_t *rxb, struct mbuf *nmp)
1371711bcba0SDavid C Somayajulu {
13723e85b721SEd Maste 	struct mbuf *mp = nmp;
1373711bcba0SDavid C Somayajulu 	int            		ret = 0;
1374711bcba0SDavid C Somayajulu 	uint32_t		offset;
1375711bcba0SDavid C Somayajulu 	bus_dma_segment_t	segs[1];
1376711bcba0SDavid C Somayajulu 	int			nsegs;
1377711bcba0SDavid C Somayajulu 
1378711bcba0SDavid C Somayajulu 	QL_DPRINT2((ha->pci_dev, "%s: enter\n", __func__));
1379711bcba0SDavid C Somayajulu 
1380711bcba0SDavid C Somayajulu 	if (mp == NULL) {
1381b8c83a19SGleb Smirnoff 		mp = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, ha->msize);
1382711bcba0SDavid C Somayajulu 
1383711bcba0SDavid C Somayajulu 		if (mp == NULL) {
1384711bcba0SDavid C Somayajulu 			if (ha->msize == MCLBYTES)
1385711bcba0SDavid C Somayajulu 				ha->err_m_getcl++;
1386711bcba0SDavid C Somayajulu 			else
1387711bcba0SDavid C Somayajulu 				ha->err_m_getjcl++;
1388711bcba0SDavid C Somayajulu 
1389711bcba0SDavid C Somayajulu 			ret = ENOBUFS;
1390711bcba0SDavid C Somayajulu 			device_printf(ha->pci_dev,
1391711bcba0SDavid C Somayajulu 					"%s: m_getcl failed\n", __func__);
1392711bcba0SDavid C Somayajulu 			goto exit_qls_get_mbuf;
1393711bcba0SDavid C Somayajulu 		}
1394711bcba0SDavid C Somayajulu 		mp->m_len = mp->m_pkthdr.len = ha->msize;
1395711bcba0SDavid C Somayajulu 	} else {
1396711bcba0SDavid C Somayajulu 		mp->m_len = mp->m_pkthdr.len = ha->msize;
1397711bcba0SDavid C Somayajulu 		mp->m_data = mp->m_ext.ext_buf;
1398711bcba0SDavid C Somayajulu 		mp->m_next = NULL;
1399711bcba0SDavid C Somayajulu 	}
1400711bcba0SDavid C Somayajulu 
1401711bcba0SDavid C Somayajulu 	/* align the receive buffers to 8 byte boundary */
1402711bcba0SDavid C Somayajulu 	offset = (uint32_t)((unsigned long long)mp->m_data & 0x7ULL);
1403711bcba0SDavid C Somayajulu 	if (offset) {
1404711bcba0SDavid C Somayajulu 		offset = 8 - offset;
1405711bcba0SDavid C Somayajulu 		m_adj(mp, offset);
1406711bcba0SDavid C Somayajulu 	}
1407711bcba0SDavid C Somayajulu 
1408711bcba0SDavid C Somayajulu 	/*
1409711bcba0SDavid C Somayajulu 	 * Using memory from the mbuf cluster pool, invoke the bus_dma
1410711bcba0SDavid C Somayajulu 	 * machinery to arrange the memory mapping.
1411711bcba0SDavid C Somayajulu 	 */
1412711bcba0SDavid C Somayajulu 	ret = bus_dmamap_load_mbuf_sg(ha->rx_tag, rxb->map,
1413711bcba0SDavid C Somayajulu 			mp, segs, &nsegs, BUS_DMA_NOWAIT);
1414711bcba0SDavid C Somayajulu 	rxb->paddr = segs[0].ds_addr;
1415711bcba0SDavid C Somayajulu 
1416711bcba0SDavid C Somayajulu 	if (ret || !rxb->paddr || (nsegs != 1)) {
1417711bcba0SDavid C Somayajulu 		m_freem(mp);
1418711bcba0SDavid C Somayajulu 		rxb->m_head = NULL;
1419711bcba0SDavid C Somayajulu 		device_printf(ha->pci_dev,
1420711bcba0SDavid C Somayajulu 			"%s: bus_dmamap_load failed[%d, 0x%016llx, %d]\n",
1421711bcba0SDavid C Somayajulu 			__func__, ret, (long long unsigned int)rxb->paddr,
1422711bcba0SDavid C Somayajulu 			nsegs);
1423711bcba0SDavid C Somayajulu                 ret = -1;
1424711bcba0SDavid C Somayajulu 		goto exit_qls_get_mbuf;
1425711bcba0SDavid C Somayajulu 	}
1426711bcba0SDavid C Somayajulu 	rxb->m_head = mp;
1427711bcba0SDavid C Somayajulu 	bus_dmamap_sync(ha->rx_tag, rxb->map, BUS_DMASYNC_PREREAD);
1428711bcba0SDavid C Somayajulu 
1429711bcba0SDavid C Somayajulu exit_qls_get_mbuf:
1430711bcba0SDavid C Somayajulu 	QL_DPRINT2((ha->pci_dev, "%s: exit ret = 0x%08x\n", __func__, ret));
1431711bcba0SDavid C Somayajulu 	return (ret);
1432711bcba0SDavid C Somayajulu }
1433711bcba0SDavid C Somayajulu 
1434711bcba0SDavid C Somayajulu static void
1435711bcba0SDavid C Somayajulu qls_tx_done(void *context, int pending)
1436711bcba0SDavid C Somayajulu {
1437711bcba0SDavid C Somayajulu 	qla_host_t *ha = context;
1438711bcba0SDavid C Somayajulu 	struct ifnet   *ifp;
1439711bcba0SDavid C Somayajulu 
1440711bcba0SDavid C Somayajulu 	ifp = ha->ifp;
1441711bcba0SDavid C Somayajulu 
1442711bcba0SDavid C Somayajulu 	if (!ifp)
1443711bcba0SDavid C Somayajulu 		return;
1444711bcba0SDavid C Somayajulu 
1445711bcba0SDavid C Somayajulu 	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
1446711bcba0SDavid C Somayajulu 		QL_DPRINT8((ha->pci_dev, "%s: !IFF_DRV_RUNNING\n", __func__));
1447711bcba0SDavid C Somayajulu 		return;
1448711bcba0SDavid C Somayajulu 	}
1449711bcba0SDavid C Somayajulu 
1450711bcba0SDavid C Somayajulu 	qls_start(ha->ifp);
1451711bcba0SDavid C Somayajulu 	return;
1452711bcba0SDavid C Somayajulu }
1453711bcba0SDavid C Somayajulu 
1454711bcba0SDavid C Somayajulu static int
1455711bcba0SDavid C Somayajulu qls_config_lro(qla_host_t *ha)
1456711bcba0SDavid C Somayajulu {
1457*618aa8cdSJohn Baldwin #if defined(INET) || defined(INET6)
1458711bcba0SDavid C Somayajulu         int i;
1459711bcba0SDavid C Somayajulu         struct lro_ctrl *lro;
1460711bcba0SDavid C Somayajulu 
1461711bcba0SDavid C Somayajulu         for (i = 0; i < ha->num_rx_rings; i++) {
1462711bcba0SDavid C Somayajulu                 lro = &ha->rx_ring[i].lro;
1463711bcba0SDavid C Somayajulu                 if (tcp_lro_init(lro)) {
1464711bcba0SDavid C Somayajulu                         device_printf(ha->pci_dev, "%s: tcp_lro_init failed\n",
1465711bcba0SDavid C Somayajulu                                 __func__);
1466711bcba0SDavid C Somayajulu                         return (-1);
1467711bcba0SDavid C Somayajulu                 }
1468711bcba0SDavid C Somayajulu                 lro->ifp = ha->ifp;
1469711bcba0SDavid C Somayajulu         }
1470711bcba0SDavid C Somayajulu         ha->flags.lro_init = 1;
1471711bcba0SDavid C Somayajulu 
1472711bcba0SDavid C Somayajulu         QL_DPRINT2((ha->pci_dev, "%s: LRO initialized\n", __func__));
1473*618aa8cdSJohn Baldwin #endif
1474711bcba0SDavid C Somayajulu         return (0);
1475711bcba0SDavid C Somayajulu }
1476711bcba0SDavid C Somayajulu 
1477711bcba0SDavid C Somayajulu static void
1478711bcba0SDavid C Somayajulu qls_free_lro(qla_host_t *ha)
1479711bcba0SDavid C Somayajulu {
1480*618aa8cdSJohn Baldwin #if defined(INET) || defined(INET6)
1481711bcba0SDavid C Somayajulu         int i;
1482711bcba0SDavid C Somayajulu         struct lro_ctrl *lro;
1483711bcba0SDavid C Somayajulu 
1484711bcba0SDavid C Somayajulu         if (!ha->flags.lro_init)
1485711bcba0SDavid C Somayajulu                 return;
1486711bcba0SDavid C Somayajulu 
1487711bcba0SDavid C Somayajulu         for (i = 0; i < ha->num_rx_rings; i++) {
1488711bcba0SDavid C Somayajulu                 lro = &ha->rx_ring[i].lro;
1489711bcba0SDavid C Somayajulu                 tcp_lro_free(lro);
1490711bcba0SDavid C Somayajulu         }
1491711bcba0SDavid C Somayajulu         ha->flags.lro_init = 0;
1492*618aa8cdSJohn Baldwin #endif
1493711bcba0SDavid C Somayajulu }
1494711bcba0SDavid C Somayajulu 
1495711bcba0SDavid C Somayajulu static void
1496711bcba0SDavid C Somayajulu qls_error_recovery(void *context, int pending)
1497711bcba0SDavid C Somayajulu {
1498711bcba0SDavid C Somayajulu         qla_host_t *ha = context;
1499711bcba0SDavid C Somayajulu 
1500711bcba0SDavid C Somayajulu 	qls_init(ha);
1501711bcba0SDavid C Somayajulu 
1502711bcba0SDavid C Somayajulu 	return;
1503711bcba0SDavid C Somayajulu }
1504