ql_os.c revision 281955
1249259Sdim/*
2249259Sdim * Copyright (c) 2013-2014 Qlogic Corporation
3249259Sdim * All rights reserved.
4249259Sdim *
5249259Sdim *  Redistribution and use in source and binary forms, with or without
6249259Sdim *  modification, are permitted provided that the following conditions
7249259Sdim *  are met:
8249259Sdim *
9249259Sdim *  1. Redistributions of source code must retain the above copyright
10249259Sdim *     notice, this list of conditions and the following disclaimer.
11249259Sdim *  2. Redistributions in binary form must reproduce the above copyright
12249259Sdim *     notice, this list of conditions and the following disclaimer in the
13249259Sdim *     documentation and/or other materials provided with the distribution.
14249259Sdim *
15249259Sdim *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16251662Sdim *  and ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17251662Sdim *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18321369Sdim *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19321369Sdim *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20321369Sdim *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21321369Sdim *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22321369Sdim *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23249259Sdim *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24321369Sdim *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25249259Sdim *  POSSIBILITY OF SUCH DAMAGE.
26276479Sdim */
27249259Sdim
28249259Sdim/*
29249259Sdim * File: ql_os.c
30249259Sdim * Author : David C Somayajulu, Qlogic Corporation, Aliso Viejo, CA 92656.
31249259Sdim */
32321369Sdim
33321369Sdim#include <sys/cdefs.h>
34249259Sdim__FBSDID("$FreeBSD: stable/10/sys/dev/qlxgbe/ql_os.c 281955 2015-04-24 23:26:44Z hiren $");
35261991Sdim
36251662Sdim
37249259Sdim#include "ql_os.h"
38249259Sdim#include "ql_hw.h"
39249259Sdim#include "ql_def.h"
40321369Sdim#include "ql_inline.h"
41321369Sdim#include "ql_ver.h"
42288943Sdim#include "ql_glbl.h"
43321369Sdim#include "ql_dbg.h"
44276479Sdim#include <sys/smp.h>
45276479Sdim
46321369Sdim/*
47321369Sdim * Some PCI Configuration Space Related Defines
48261991Sdim */
49276479Sdim
50321369Sdim#ifndef PCI_VENDOR_QLOGIC
51249259Sdim#define PCI_VENDOR_QLOGIC	0x1077
52261991Sdim#endif
53321369Sdim
54321369Sdim#ifndef PCI_PRODUCT_QLOGIC_ISP8030
55321369Sdim#define PCI_PRODUCT_QLOGIC_ISP8030	0x8030
56321369Sdim#endif
57321369Sdim
58249259Sdim#define PCI_QLOGIC_ISP8030 \
59249259Sdim	((PCI_PRODUCT_QLOGIC_ISP8030 << 16) | PCI_VENDOR_QLOGIC)
60249259Sdim
61251662Sdim/*
62276479Sdim * static functions
63276479Sdim */
64251662Sdimstatic int qla_alloc_parent_dma_tag(qla_host_t *ha);
65251662Sdimstatic void qla_free_parent_dma_tag(qla_host_t *ha);
66251662Sdimstatic int qla_alloc_xmt_bufs(qla_host_t *ha);
67249259Sdimstatic void qla_free_xmt_bufs(qla_host_t *ha);
68249259Sdimstatic int qla_alloc_rcv_bufs(qla_host_t *ha);
69261991Sdimstatic void qla_free_rcv_bufs(qla_host_t *ha);
70261991Sdimstatic void qla_clear_tx_buf(qla_host_t *ha, qla_tx_buf_t *txb);
71261991Sdim
72261991Sdimstatic void qla_init_ifnet(device_t dev, qla_host_t *ha);
73261991Sdimstatic int qla_sysctl_get_stats(SYSCTL_HANDLER_ARGS);
74276479Sdimstatic int qla_sysctl_get_link_status(SYSCTL_HANDLER_ARGS);
75261991Sdimstatic void qla_release(qla_host_t *ha);
76276479Sdimstatic void qla_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nsegs,
77276479Sdim		int error);
78276479Sdimstatic void qla_stop(qla_host_t *ha);
79276479Sdimstatic int qla_send(qla_host_t *ha, struct mbuf **m_headp);
80276479Sdimstatic void qla_tx_done(void *context, int pending);
81276479Sdimstatic void qla_get_peer(qla_host_t *ha);
82276479Sdimstatic void qla_error_recovery(void *context, int pending);
83276479Sdim
84276479Sdim/*
85276479Sdim * Hooks to the Operating Systems
86276479Sdim */
87276479Sdimstatic int qla_pci_probe (device_t);
88276479Sdimstatic int qla_pci_attach (device_t);
89261991Sdimstatic int qla_pci_detach (device_t);
90276479Sdim
91276479Sdimstatic void qla_init(void *arg);
92276479Sdimstatic int qla_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
93276479Sdimstatic int qla_media_change(struct ifnet *ifp);
94296417Sdimstatic void qla_media_status(struct ifnet *ifp, struct ifmediareq *ifmr);
95276479Sdimstatic void qla_start(struct ifnet *ifp);
96288943Sdim
97276479Sdimstatic device_method_t qla_pci_methods[] = {
98276479Sdim	/* Device interface */
99276479Sdim	DEVMETHOD(device_probe, qla_pci_probe),
100276479Sdim	DEVMETHOD(device_attach, qla_pci_attach),
101261991Sdim	DEVMETHOD(device_detach, qla_pci_detach),
102276479Sdim	{ 0, 0 }
103276479Sdim};
104276479Sdim
105261991Sdimstatic driver_t qla_pci_driver = {
106276479Sdim	"ql", qla_pci_methods, sizeof (qla_host_t),
107276479Sdim};
108261991Sdim
109261991Sdimstatic devclass_t qla83xx_devclass;
110276479Sdim
111276479SdimDRIVER_MODULE(qla83xx, pci, qla_pci_driver, qla83xx_devclass, 0, 0);
112276479Sdim
113276479SdimMODULE_DEPEND(qla83xx, pci, 1, 1, 1);
114276479SdimMODULE_DEPEND(qla83xx, ether, 1, 1, 1);
115276479Sdim
116321369SdimMALLOC_DEFINE(M_QLA83XXBUF, "qla83xxbuf", "Buffers for qla83xx driver");
117261991Sdim
118261991Sdim#define QL_STD_REPLENISH_THRES		0
119261991Sdim#define QL_JUMBO_REPLENISH_THRES	32
120321369Sdim
121261991Sdim
122261991Sdimstatic char dev_str[64];
123261991Sdim
124321369Sdim/*
125276479Sdim * Name:	qla_pci_probe
126276479Sdim * Function:	Validate the PCI device to be a QLA80XX device
127276479Sdim */
128321369Sdimstatic int
129261991Sdimqla_pci_probe(device_t dev)
130321369Sdim{
131261991Sdim        switch ((pci_get_device(dev) << 16) | (pci_get_vendor(dev))) {
132261991Sdim        case PCI_QLOGIC_ISP8030:
133261991Sdim		snprintf(dev_str, sizeof(dev_str), "%s v%d.%d.%d",
134261991Sdim			"Qlogic ISP 83xx PCI CNA Adapter-Ethernet Function",
135261991Sdim			QLA_VERSION_MAJOR, QLA_VERSION_MINOR,
136261991Sdim			QLA_VERSION_BUILD);
137261991Sdim                device_set_desc(dev, dev_str);
138261991Sdim                break;
139261991Sdim        default:
140261991Sdim                return (ENXIO);
141321369Sdim        }
142276479Sdim
143276479Sdim        if (bootverbose)
144276479Sdim                printf("%s: %s\n ", __func__, dev_str);
145276479Sdim
146276479Sdim        return (BUS_PROBE_DEFAULT);
147276479Sdim}
148276479Sdim
149276479Sdimstatic void
150276479Sdimqla_add_sysctls(qla_host_t *ha)
151276479Sdim{
152321369Sdim        device_t dev = ha->pci_dev;
153261991Sdim
154261991Sdim        SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
155261991Sdim                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
156321369Sdim                OID_AUTO, "stats", CTLTYPE_INT | CTLFLAG_RW,
157261991Sdim                (void *)ha, 0,
158261991Sdim                qla_sysctl_get_stats, "I", "Statistics");
159261991Sdim
160261991Sdim        SYSCTL_ADD_STRING(device_get_sysctl_ctx(dev),
161261991Sdim                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
162261991Sdim                OID_AUTO, "fw_version", CTLFLAG_RD,
163261991Sdim                ha->fw_ver_str, 0, "firmware version");
164261991Sdim
165261991Sdim        SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
166261991Sdim                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
167261991Sdim                OID_AUTO, "link_status", CTLTYPE_INT | CTLFLAG_RW,
168261991Sdim                (void *)ha, 0,
169261991Sdim                qla_sysctl_get_link_status, "I", "Link Status");
170261991Sdim
171261991Sdim	ha->dbg_level = 0;
172261991Sdim        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
173261991Sdim                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
174321369Sdim                OID_AUTO, "debug", CTLFLAG_RW,
175321369Sdim                &ha->dbg_level, ha->dbg_level, "Debug Level");
176321369Sdim
177261991Sdim	ha->std_replenish = QL_STD_REPLENISH_THRES;
178276479Sdim        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
179276479Sdim                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
180276479Sdim                OID_AUTO, "std_replenish", CTLFLAG_RW,
181276479Sdim                &ha->std_replenish, ha->std_replenish,
182276479Sdim                "Threshold for Replenishing Standard Frames");
183276479Sdim
184276479Sdim        SYSCTL_ADD_QUAD(device_get_sysctl_ctx(dev),
185261991Sdim                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
186321369Sdim                OID_AUTO, "ipv4_lro",
187261991Sdim                CTLFLAG_RD, &ha->ipv4_lro,
188261991Sdim                "number of ipv4 lro completions");
189261991Sdim
190261991Sdim        SYSCTL_ADD_QUAD(device_get_sysctl_ctx(dev),
191276479Sdim                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
192261991Sdim                OID_AUTO, "ipv6_lro",
193276479Sdim                CTLFLAG_RD, &ha->ipv6_lro,
194276479Sdim                "number of ipv6 lro completions");
195276479Sdim
196276479Sdim	SYSCTL_ADD_QUAD(device_get_sysctl_ctx(dev),
197276479Sdim		SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
198276479Sdim		OID_AUTO, "tx_tso_frames",
199276479Sdim		CTLFLAG_RD, &ha->tx_tso_frames,
200276479Sdim		"number of Tx TSO Frames");
201261991Sdim
202276479Sdim	SYSCTL_ADD_QUAD(device_get_sysctl_ctx(dev),
203261991Sdim                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
204321369Sdim		OID_AUTO, "hw_vlan_tx_frames",
205276479Sdim		CTLFLAG_RD, &ha->hw_vlan_tx_frames,
206276479Sdim		"number of Tx VLAN Frames");
207276479Sdim
208276479Sdim        return;
209276479Sdim}
210276479Sdim
211276479Sdimstatic void
212276479Sdimqla_watchdog(void *arg)
213276479Sdim{
214276479Sdim	qla_host_t *ha = arg;
215276479Sdim	qla_hw_t *hw;
216276479Sdim	struct ifnet *ifp;
217276479Sdim	uint32_t i;
218276479Sdim	qla_hw_tx_cntxt_t *hw_tx_cntxt;
219276479Sdim
220321369Sdim	hw = &ha->hw;
221276479Sdim	ifp = ha->ifp;
222296417Sdim
223276479Sdim        if (ha->flags.qla_watchdog_exit) {
224321369Sdim		ha->qla_watchdog_exited = 1;
225288943Sdim		return;
226296417Sdim	}
227288943Sdim	ha->qla_watchdog_exited = 0;
228321369Sdim
229276479Sdim	if (!ha->flags.qla_watchdog_pause) {
230296417Sdim		if (ql_hw_check_health(ha) || ha->qla_initiate_recovery ||
231276479Sdim			(ha->msg_from_peer == QL_PEER_MSG_RESET)) {
232321369Sdim			ha->qla_watchdog_paused = 1;
233261991Sdim			ha->flags.qla_watchdog_pause = 1;
234296417Sdim			ha->qla_initiate_recovery = 0;
235261991Sdim			ha->err_inject = 0;
236321369Sdim			taskqueue_enqueue(ha->err_tq, &ha->err_task);
237321369Sdim		} else {
238321369Sdim			for (i = 0; i < ha->hw.num_tx_rings; i++) {
239276479Sdim				hw_tx_cntxt = &hw->tx_cntxt[i];
240276479Sdim				if (qla_le32_to_host(*(hw_tx_cntxt->tx_cons)) !=
241276479Sdim					hw_tx_cntxt->txr_comp) {
242276479Sdim					taskqueue_enqueue(ha->tx_tq,
243261991Sdim						&ha->tx_task);
244276479Sdim					break;
245288943Sdim				}
246288943Sdim			}
247288943Sdim
248288943Sdim			if ((ifp->if_snd.ifq_head != NULL) && QL_RUNNING(ifp)) {
249288943Sdim				taskqueue_enqueue(ha->tx_tq, &ha->tx_task);
250288943Sdim			}
251288943Sdim			ha->qla_watchdog_paused = 0;
252276479Sdim		}
253276479Sdim
254276479Sdim	} else {
255276479Sdim		ha->qla_watchdog_paused = 1;
256276479Sdim	}
257276479Sdim
258288943Sdim	ha->watchdog_ticks = ha->watchdog_ticks++ % 1000;
259276479Sdim	callout_reset(&ha->tx_callout, QLA_WATCHDOG_CALLOUT_TICKS,
260276479Sdim		qla_watchdog, ha);
261276479Sdim}
262276479Sdim
263276479Sdim/*
264276479Sdim * Name:	qla_pci_attach
265276479Sdim * Function:	attaches the device to the operating system
266276479Sdim */
267288943Sdimstatic int
268276479Sdimqla_pci_attach(device_t dev)
269276479Sdim{
270276479Sdim	qla_host_t *ha = NULL;
271261991Sdim	uint32_t rsrc_len;
272261991Sdim	int i;
273261991Sdim
274296417Sdim	QL_DPRINT2(ha, (dev, "%s: enter\n", __func__));
275261991Sdim
276261991Sdim        if ((ha = device_get_softc(dev)) == NULL) {
277261991Sdim                device_printf(dev, "cannot get softc\n");
278261991Sdim                return (ENOMEM);
279261991Sdim        }
280276479Sdim
281276479Sdim        memset(ha, 0, sizeof (qla_host_t));
282261991Sdim
283261991Sdim        if (pci_get_device(dev) != PCI_PRODUCT_QLOGIC_ISP8030) {
284261991Sdim                device_printf(dev, "device is not ISP8030\n");
285296417Sdim                return (ENXIO);
286261991Sdim	}
287261991Sdim
288280031Sdim        ha->pci_func = pci_get_function(dev);
289280031Sdim
290280031Sdim        ha->pci_dev = dev;
291280031Sdim
292280031Sdim	pci_enable_busmaster(dev);
293280031Sdim
294280031Sdim	ha->reg_rid = PCIR_BAR(0);
295280031Sdim	ha->pci_reg = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &ha->reg_rid,
296280031Sdim				RF_ACTIVE);
297280031Sdim
298280031Sdim        if (ha->pci_reg == NULL) {
299280031Sdim                device_printf(dev, "unable to map any ports\n");
300280031Sdim                goto qla_pci_attach_err;
301261991Sdim        }
302261991Sdim
303261991Sdim	rsrc_len = (uint32_t) bus_get_resource_count(dev, SYS_RES_MEMORY,
304261991Sdim					ha->reg_rid);
305321369Sdim
306321369Sdim	mtx_init(&ha->hw_lock, "qla83xx_hw_lock", MTX_NETWORK_LOCK, MTX_DEF);
307321369Sdim
308261991Sdim	mtx_init(&ha->tx_lock, "qla83xx_tx_lock", MTX_NETWORK_LOCK, MTX_DEF);
309261991Sdim
310321369Sdim	qla_add_sysctls(ha);
311261991Sdim	ql_hw_add_sysctls(ha);
312261991Sdim
313261991Sdim	ha->flags.lock_init = 1;
314261991Sdim
315261991Sdim	ha->reg_rid1 = PCIR_BAR(2);
316276479Sdim	ha->pci_reg1 = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
317261991Sdim			&ha->reg_rid1, RF_ACTIVE);
318261991Sdim
319261991Sdim	ha->msix_count = pci_msix_count(dev);
320261991Sdim
321261991Sdim	if (ha->msix_count < (ha->hw.num_sds_rings + 1)) {
322261991Sdim		device_printf(dev, "%s: msix_count[%d] not enough\n", __func__,
323261991Sdim			ha->msix_count);
324261991Sdim		goto qla_pci_attach_err;
325276479Sdim	}
326261991Sdim
327261991Sdim	QL_DPRINT2(ha, (dev, "%s: ha %p pci_func 0x%x rsrc_count 0x%08x"
328261991Sdim		" msix_count 0x%x pci_reg %p\n", __func__, ha,
329261991Sdim		ha->pci_func, rsrc_len, ha->msix_count, ha->pci_reg));
330261991Sdim
331261991Sdim	ha->msix_count = ha->hw.num_sds_rings + 1;
332261991Sdim
333261991Sdim	if (pci_alloc_msix(dev, &ha->msix_count)) {
334261991Sdim		device_printf(dev, "%s: pci_alloc_msi[%d] failed\n", __func__,
335261991Sdim			ha->msix_count);
336261991Sdim		ha->msix_count = 0;
337261991Sdim		goto qla_pci_attach_err;
338261991Sdim	}
339261991Sdim
340261991Sdim	ha->mbx_irq_rid = 1;
341261991Sdim	ha->mbx_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
342261991Sdim				&ha->mbx_irq_rid,
343261991Sdim				(RF_ACTIVE | RF_SHAREABLE));
344261991Sdim	if (ha->mbx_irq == NULL) {
345261991Sdim		device_printf(dev, "could not allocate mbx interrupt\n");
346276479Sdim		goto qla_pci_attach_err;
347261991Sdim	}
348261991Sdim	if (bus_setup_intr(dev, ha->mbx_irq, (INTR_TYPE_NET | INTR_MPSAFE),
349261991Sdim		NULL, ql_mbx_isr, ha, &ha->mbx_handle)) {
350261991Sdim		device_printf(dev, "could not setup mbx interrupt\n");
351261991Sdim		goto qla_pci_attach_err;
352261991Sdim	}
353261991Sdim
354261991Sdim
355261991Sdim	for (i = 0; i < ha->hw.num_sds_rings; i++) {
356261991Sdim		ha->irq_vec[i].sds_idx = i;
357261991Sdim                ha->irq_vec[i].ha = ha;
358261991Sdim                ha->irq_vec[i].irq_rid = 2 + i;
359261991Sdim
360261991Sdim		ha->irq_vec[i].irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
361276479Sdim				&ha->irq_vec[i].irq_rid,
362276479Sdim				(RF_ACTIVE | RF_SHAREABLE));
363276479Sdim
364276479Sdim		if (ha->irq_vec[i].irq == NULL) {
365276479Sdim			device_printf(dev, "could not allocate interrupt\n");
366276479Sdim			goto qla_pci_attach_err;
367276479Sdim		}
368276479Sdim		if (bus_setup_intr(dev, ha->irq_vec[i].irq,
369276479Sdim			(INTR_TYPE_NET | INTR_MPSAFE),
370276479Sdim			NULL, ql_isr, &ha->irq_vec[i],
371276479Sdim			&ha->irq_vec[i].handle)) {
372276479Sdim			device_printf(dev, "could not setup interrupt\n");
373276479Sdim			goto qla_pci_attach_err;
374276479Sdim		}
375276479Sdim	}
376276479Sdim
377276479Sdim	printf("%s: mp__ncpus %d sds %d rds %d msi-x %d\n", __func__, mp_ncpus,
378276479Sdim		ha->hw.num_sds_rings, ha->hw.num_rds_rings, ha->msix_count);
379276479Sdim
380276479Sdim	/* initialize hardware */
381276479Sdim	if (ql_init_hw(ha)) {
382276479Sdim		device_printf(dev, "%s: ql_init_hw failed\n", __func__);
383276479Sdim		goto qla_pci_attach_err;
384261991Sdim	}
385261991Sdim
386261991Sdim	device_printf(dev, "%s: firmware[%d.%d.%d.%d]\n", __func__,
387261991Sdim		ha->fw_ver_major, ha->fw_ver_minor, ha->fw_ver_sub,
388276479Sdim		ha->fw_ver_build);
389276479Sdim        snprintf(ha->fw_ver_str, sizeof(ha->fw_ver_str), "%d.%d.%d.%d",
390276479Sdim                        ha->fw_ver_major, ha->fw_ver_minor, ha->fw_ver_sub,
391276479Sdim                        ha->fw_ver_build);
392276479Sdim
393276479Sdim	ql_read_mac_addr(ha);
394276479Sdim
395276479Sdim	/* allocate parent dma tag */
396276479Sdim	if (qla_alloc_parent_dma_tag(ha)) {
397276479Sdim		device_printf(dev, "%s: qla_alloc_parent_dma_tag failed\n",
398276479Sdim			__func__);
399276479Sdim		goto qla_pci_attach_err;
400276479Sdim	}
401261991Sdim
402276479Sdim	/* alloc all dma buffers */
403276479Sdim	if (ql_alloc_dma(ha)) {
404276479Sdim		device_printf(dev, "%s: ql_alloc_dma failed\n", __func__);
405276479Sdim		goto qla_pci_attach_err;
406276479Sdim	}
407276479Sdim	qla_get_peer(ha);
408276479Sdim
409276479Sdim	/* create the o.s ethernet interface */
410276479Sdim	qla_init_ifnet(dev, ha);
411276479Sdim
412276479Sdim	ha->flags.qla_watchdog_active = 1;
413261991Sdim	ha->flags.qla_watchdog_pause = 1;
414276479Sdim
415276479Sdim
416276479Sdim	TASK_INIT(&ha->tx_task, 0, qla_tx_done, ha);
417261991Sdim	ha->tx_tq = taskqueue_create_fast("qla_txq", M_NOWAIT,
418261991Sdim			taskqueue_thread_enqueue, &ha->tx_tq);
419296417Sdim	taskqueue_start_threads(&ha->tx_tq, 1, PI_NET, "%s txq",
420296417Sdim		device_get_nameunit(ha->pci_dev));
421296417Sdim
422261991Sdim	callout_init(&ha->tx_callout, TRUE);
423276479Sdim	ha->flags.qla_callout_init = 1;
424321369Sdim
425261991Sdim	/* create ioctl device interface */
426261991Sdim	if (ql_make_cdev(ha)) {
427249259Sdim		device_printf(dev, "%s: ql_make_cdev failed\n", __func__);
428249259Sdim		goto qla_pci_attach_err;
429249259Sdim	}
430249259Sdim
431249259Sdim	callout_reset(&ha->tx_callout, QLA_WATCHDOG_CALLOUT_TICKS,
432249259Sdim		qla_watchdog, ha);
433249259Sdim
434249259Sdim	TASK_INIT(&ha->err_task, 0, qla_error_recovery, ha);
435249259Sdim	ha->err_tq = taskqueue_create_fast("qla_errq", M_NOWAIT,
436249259Sdim			taskqueue_thread_enqueue, &ha->err_tq);
437249259Sdim	taskqueue_start_threads(&ha->err_tq, 1, PI_NET, "%s errq",
438249259Sdim		device_get_nameunit(ha->pci_dev));
439249259Sdim
440249259Sdim	QL_DPRINT2(ha, (dev, "%s: exit 0\n", __func__));
441261991Sdim        return (0);
442261991Sdim
443288943Sdimqla_pci_attach_err:
444276479Sdim
445321369Sdim	qla_release(ha);
446296417Sdim
447251662Sdim	QL_DPRINT2(ha, (dev, "%s: exit ENXIO\n", __func__));
448249259Sdim        return (ENXIO);
449321369Sdim}
450249259Sdim
451276479Sdim/*
452261991Sdim * Name:	qla_pci_detach
453249259Sdim * Function:	Unhooks the device from the operating system
454261991Sdim */
455261991Sdimstatic int
456261991Sdimqla_pci_detach(device_t dev)
457261991Sdim{
458276479Sdim	qla_host_t *ha = NULL;
459261991Sdim	struct ifnet *ifp;
460261991Sdim
461276479Sdim	QL_DPRINT2(ha, (dev, "%s: enter\n", __func__));
462261991Sdim
463261991Sdim        if ((ha = device_get_softc(dev)) == NULL) {
464276479Sdim                device_printf(dev, "cannot get softc\n");
465249259Sdim                return (ENOMEM);
466288943Sdim        }
467321369Sdim
468251662Sdim	ifp = ha->ifp;
469321369Sdim
470321369Sdim	(void)QLA_LOCK(ha, __func__, 0);
471321369Sdim	qla_stop(ha);
472321369Sdim	QLA_UNLOCK(ha, __func__);
473321369Sdim
474321369Sdim	qla_release(ha);
475249259Sdim
476249259Sdim	QL_DPRINT2(ha, (dev, "%s: exit\n", __func__));
477249259Sdim
478249259Sdim        return (0);
479249259Sdim}
480321369Sdim
481321369Sdim/*
482249259Sdim * SYSCTL Related Callbacks
483249259Sdim */
484249259Sdimstatic int
485249259Sdimqla_sysctl_get_stats(SYSCTL_HANDLER_ARGS)
486249259Sdim{
487276479Sdim	int err, ret = 0;
488249259Sdim	qla_host_t *ha;
489249259Sdim
490276479Sdim	err = sysctl_handle_int(oidp, &ret, 0, req);
491276479Sdim
492276479Sdim	if (err || !req->newptr)
493276479Sdim		return (err);
494276479Sdim
495276479Sdim	if (ret == 1) {
496276479Sdim		ha = (qla_host_t *)arg1;
497276479Sdim		ql_get_stats(ha);
498276479Sdim	}
499276479Sdim	return (err);
500276479Sdim}
501276479Sdimstatic int
502276479Sdimqla_sysctl_get_link_status(SYSCTL_HANDLER_ARGS)
503276479Sdim{
504276479Sdim	int err, ret = 0;
505276479Sdim	qla_host_t *ha;
506276479Sdim
507276479Sdim	err = sysctl_handle_int(oidp, &ret, 0, req);
508276479Sdim
509276479Sdim	if (err || !req->newptr)
510276479Sdim		return (err);
511276479Sdim
512276479Sdim	if (ret == 1) {
513276479Sdim		ha = (qla_host_t *)arg1;
514276479Sdim		ql_hw_link_status(ha);
515276479Sdim	}
516276479Sdim	return (err);
517276479Sdim}
518276479Sdim
519276479Sdim/*
520276479Sdim * Name:	qla_release
521276479Sdim * Function:	Releases the resources allocated for the device
522276479Sdim */
523276479Sdimstatic void
524276479Sdimqla_release(qla_host_t *ha)
525276479Sdim{
526276479Sdim	device_t dev;
527276479Sdim	int i;
528249259Sdim
529249259Sdim	dev = ha->pci_dev;
530249259Sdim
531276479Sdim	if (ha->err_tq) {
532249259Sdim		taskqueue_drain(ha->err_tq, &ha->err_task);
533261991Sdim		taskqueue_free(ha->err_tq);
534249259Sdim	}
535249259Sdim
536321369Sdim	if (ha->tx_tq) {
537321369Sdim		taskqueue_drain(ha->tx_tq, &ha->tx_task);
538321369Sdim		taskqueue_free(ha->tx_tq);
539321369Sdim	}
540321369Sdim
541321369Sdim	ql_del_cdev(ha);
542321369Sdim
543321369Sdim	if (ha->flags.qla_watchdog_active) {
544249259Sdim		ha->flags.qla_watchdog_exit = 1;
545249259Sdim
546249259Sdim		while (ha->qla_watchdog_exited == 0)
547296417Sdim			qla_mdelay(__func__, 1);
548321369Sdim	}
549296417Sdim
550296417Sdim	if (ha->flags.qla_callout_init)
551296417Sdim		callout_stop(&ha->tx_callout);
552296417Sdim
553321369Sdim	if (ha->ifp != NULL)
554321369Sdim		ether_ifdetach(ha->ifp);
555280031Sdim
556249259Sdim	ql_free_dma(ha);
557296417Sdim	qla_free_parent_dma_tag(ha);
558249259Sdim
559249259Sdim	if (ha->mbx_handle)
560276479Sdim		(void)bus_teardown_intr(dev, ha->mbx_irq, ha->mbx_handle);
561249259Sdim
562249259Sdim	if (ha->mbx_irq)
563249259Sdim		(void) bus_release_resource(dev, SYS_RES_IRQ, ha->mbx_irq_rid,
564249259Sdim				ha->mbx_irq);
565249259Sdim
566249259Sdim	for (i = 0; i < ha->hw.num_sds_rings; i++) {
567249259Sdim
568249259Sdim		if (ha->irq_vec[i].handle) {
569249259Sdim			(void)bus_teardown_intr(dev, ha->irq_vec[i].irq,
570249259Sdim					ha->irq_vec[i].handle);
571249259Sdim		}
572249259Sdim
573249259Sdim		if (ha->irq_vec[i].irq) {
574249259Sdim			(void)bus_release_resource(dev, SYS_RES_IRQ,
575249259Sdim				ha->irq_vec[i].irq_rid,
576249259Sdim				ha->irq_vec[i].irq);
577249259Sdim		}
578249259Sdim	}
579249259Sdim
580249259Sdim	if (ha->msix_count)
581249259Sdim		pci_release_msi(dev);
582249259Sdim
583249259Sdim	if (ha->flags.lock_init) {
584249259Sdim		mtx_destroy(&ha->tx_lock);
585249259Sdim		mtx_destroy(&ha->hw_lock);
586249259Sdim	}
587321369Sdim
588321369Sdim        if (ha->pci_reg)
589321369Sdim                (void) bus_release_resource(dev, SYS_RES_MEMORY, ha->reg_rid,
590321369Sdim				ha->pci_reg);
591321369Sdim
592321369Sdim        if (ha->pci_reg1)
593321369Sdim                (void) bus_release_resource(dev, SYS_RES_MEMORY, ha->reg_rid1,
594321369Sdim				ha->pci_reg1);
595321369Sdim}
596321369Sdim
597321369Sdim/*
598321369Sdim * DMA Related Functions
599321369Sdim */
600321369Sdim
601249259Sdimstatic void
602321369Sdimqla_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
603321369Sdim{
604321369Sdim        *((bus_addr_t *)arg) = 0;
605321369Sdim
606321369Sdim        if (error) {
607321369Sdim                printf("%s: bus_dmamap_load failed (%d)\n", __func__, error);
608321369Sdim                return;
609321369Sdim	}
610321369Sdim
611321369Sdim        *((bus_addr_t *)arg) = segs[0].ds_addr;
612321369Sdim
613321369Sdim	return;
614321369Sdim}
615321369Sdim
616321369Sdimint
617249259Sdimql_alloc_dmabuf(qla_host_t *ha, qla_dma_t *dma_buf)
618321369Sdim{
619249259Sdim        int             ret = 0;
620249259Sdim        device_t        dev;
621249259Sdim        bus_addr_t      b_addr;
622321369Sdim
623321369Sdim        dev = ha->pci_dev;
624321369Sdim
625249259Sdim        QL_DPRINT2(ha, (dev, "%s: enter\n", __func__));
626321369Sdim
627249259Sdim        ret = bus_dma_tag_create(
628249259Sdim                        ha->parent_tag,/* parent */
629249259Sdim                        dma_buf->alignment,
630321369Sdim                        ((bus_size_t)(1ULL << 32)),/* boundary */
631321369Sdim                        BUS_SPACE_MAXADDR,      /* lowaddr */
632321369Sdim                        BUS_SPACE_MAXADDR,      /* highaddr */
633249259Sdim                        NULL, NULL,             /* filter, filterarg */
634321369Sdim                        dma_buf->size,          /* maxsize */
635249259Sdim                        1,                      /* nsegments */
636249259Sdim                        dma_buf->size,          /* maxsegsize */
637249259Sdim                        0,                      /* flags */
638288943Sdim                        NULL, NULL,             /* lockfunc, lockarg */
639288943Sdim                        &dma_buf->dma_tag);
640288943Sdim
641249259Sdim        if (ret) {
642288943Sdim                device_printf(dev, "%s: could not create dma tag\n", __func__);
643288943Sdim                goto ql_alloc_dmabuf_exit;
644288943Sdim        }
645249259Sdim        ret = bus_dmamem_alloc(dma_buf->dma_tag,
646249259Sdim                        (void **)&dma_buf->dma_b,
647321369Sdim                        (BUS_DMA_ZERO | BUS_DMA_COHERENT | BUS_DMA_NOWAIT),
648321369Sdim                        &dma_buf->dma_map);
649321369Sdim        if (ret) {
650321369Sdim                bus_dma_tag_destroy(dma_buf->dma_tag);
651321369Sdim                device_printf(dev, "%s: bus_dmamem_alloc failed\n", __func__);
652321369Sdim                goto ql_alloc_dmabuf_exit;
653321369Sdim        }
654321369Sdim
655321369Sdim        ret = bus_dmamap_load(dma_buf->dma_tag,
656321369Sdim                        dma_buf->dma_map,
657321369Sdim                        dma_buf->dma_b,
658276479Sdim                        dma_buf->size,
659249259Sdim                        qla_dmamap_callback,
660276479Sdim                        &b_addr, BUS_DMA_NOWAIT);
661249259Sdim
662249259Sdim        if (ret || !b_addr) {
663249259Sdim                bus_dma_tag_destroy(dma_buf->dma_tag);
664296417Sdim                bus_dmamem_free(dma_buf->dma_tag, dma_buf->dma_b,
665249259Sdim                        dma_buf->dma_map);
666296417Sdim                ret = -1;
667296417Sdim                goto ql_alloc_dmabuf_exit;
668296417Sdim        }
669249259Sdim
670261991Sdim        dma_buf->dma_addr = b_addr;
671261991Sdim
672249259Sdimql_alloc_dmabuf_exit:
673314564Sdim        QL_DPRINT2(ha, (dev, "%s: exit ret 0x%08x tag %p map %p b %p sz 0x%x\n",
674249259Sdim                __func__, ret, (void *)dma_buf->dma_tag,
675249259Sdim                (void *)dma_buf->dma_map, (void *)dma_buf->dma_b,
676249259Sdim		dma_buf->size));
677249259Sdim
678276479Sdim        return ret;
679276479Sdim}
680249259Sdim
681321369Sdimvoid
682249259Sdimql_free_dmabuf(qla_host_t *ha, qla_dma_t *dma_buf)
683321369Sdim{
684321369Sdim        bus_dmamem_free(dma_buf->dma_tag, dma_buf->dma_b, dma_buf->dma_map);
685249259Sdim        bus_dma_tag_destroy(dma_buf->dma_tag);
686321369Sdim}
687321369Sdim
688249259Sdimstatic int
689249259Sdimqla_alloc_parent_dma_tag(qla_host_t *ha)
690249259Sdim{
691249259Sdim	int		ret;
692261991Sdim	device_t	dev;
693261991Sdim
694261991Sdim	dev = ha->pci_dev;
695261991Sdim
696261991Sdim        /*
697251662Sdim         * Allocate parent DMA Tag
698249259Sdim         */
699261991Sdim        ret = bus_dma_tag_create(
700251662Sdim                        bus_get_dma_tag(dev),   /* parent */
701249259Sdim                        1,((bus_size_t)(1ULL << 32)),/* alignment, boundary */
702321369Sdim                        BUS_SPACE_MAXADDR,      /* lowaddr */
703251662Sdim                        BUS_SPACE_MAXADDR,      /* highaddr */
704249259Sdim                        NULL, NULL,             /* filter, filterarg */
705261991Sdim                        BUS_SPACE_MAXSIZE_32BIT,/* maxsize */
706276479Sdim                        0,                      /* nsegments */
707261991Sdim                        BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
708261991Sdim                        0,                      /* flags */
709261991Sdim                        NULL, NULL,             /* lockfunc, lockarg */
710261991Sdim                        &ha->parent_tag);
711261991Sdim
712321369Sdim        if (ret) {
713261991Sdim                device_printf(dev, "%s: could not create parent dma tag\n",
714261991Sdim                        __func__);
715261991Sdim		return (-1);
716321369Sdim        }
717276479Sdim
718276479Sdim        ha->flags.parent_tag = 1;
719276479Sdim
720321369Sdim	return (0);
721261991Sdim}
722261991Sdim
723261991Sdimstatic void
724321369Sdimqla_free_parent_dma_tag(qla_host_t *ha)
725261991Sdim{
726261991Sdim        if (ha->flags.parent_tag) {
727261991Sdim                bus_dma_tag_destroy(ha->parent_tag);
728261991Sdim                ha->flags.parent_tag = 0;
729321369Sdim        }
730276479Sdim}
731276479Sdim
732276479Sdim/*
733321369Sdim * Name: qla_init_ifnet
734261991Sdim * Function: Creates the Network Device Interface and Registers it with the O.S
735261991Sdim */
736261991Sdim
737321369Sdimstatic void
738261991Sdimqla_init_ifnet(device_t dev, qla_host_t *ha)
739261991Sdim{
740261991Sdim	struct ifnet *ifp;
741261991Sdim
742321369Sdim	QL_DPRINT2(ha, (dev, "%s: enter\n", __func__));
743276479Sdim
744276479Sdim	ifp = ha->ifp = if_alloc(IFT_ETHER);
745276479Sdim
746276479Sdim	if (ifp == NULL)
747321369Sdim		panic("%s: cannot if_alloc()\n", device_get_nameunit(dev));
748261991Sdim
749261991Sdim	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
750261991Sdim
751261991Sdim#if __FreeBSD_version >= 1000000
752261991Sdim	if_initbaudrate(ifp, IF_Gbps(10));
753261991Sdim	ifp->if_capabilities = IFCAP_LINKSTATE;
754261991Sdim#else
755261991Sdim	ifp->if_mtu = ETHERMTU;
756261991Sdim	ifp->if_baudrate = (1 * 1000 * 1000 *1000);
757261991Sdim
758261991Sdim#endif /* #if __FreeBSD_version >= 1000000 */
759261991Sdim
760261991Sdim	ifp->if_init = qla_init;
761261991Sdim	ifp->if_softc = ha;
762321369Sdim	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
763261991Sdim	ifp->if_ioctl = qla_ioctl;
764261991Sdim	ifp->if_start = qla_start;
765261991Sdim
766321369Sdim	IFQ_SET_MAXLEN(&ifp->if_snd, qla_get_ifq_snd_maxlen(ha));
767261991Sdim	ifp->if_snd.ifq_drv_maxlen = qla_get_ifq_snd_maxlen(ha);
768261991Sdim	IFQ_SET_READY(&ifp->if_snd);
769261991Sdim
770261991Sdim	ha->max_frame_size = ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN;
771321369Sdim
772276479Sdim	ether_ifattach(ifp, qla_get_mac_addr(ha));
773276479Sdim
774276479Sdim	ifp->if_capabilities = IFCAP_HWCSUM |
775276479Sdim				IFCAP_TSO4 |
776276479Sdim				IFCAP_JUMBO_MTU;
777276479Sdim
778321369Sdim	ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
779276479Sdim	ifp->if_capabilities |= IFCAP_VLAN_HWTSO;
780276479Sdim
781276479Sdim	ifp->if_capenable = ifp->if_capabilities;
782321369Sdim
783276479Sdim	ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
784276479Sdim
785276479Sdim	ifmedia_init(&ha->media, IFM_IMASK, qla_media_change, qla_media_status);
786321369Sdim
787276479Sdim	ifmedia_add(&ha->media, (IFM_ETHER | qla_get_optics(ha) | IFM_FDX), 0,
788276479Sdim		NULL);
789276479Sdim	ifmedia_add(&ha->media, (IFM_ETHER | IFM_AUTO), 0, NULL);
790288943Sdim
791296417Sdim	ifmedia_set(&ha->media, (IFM_ETHER | IFM_AUTO));
792288943Sdim
793288943Sdim	QL_DPRINT2(ha, (dev, "%s: exit\n", __func__));
794288943Sdim
795288943Sdim	return;
796296417Sdim}
797288943Sdim
798276479Sdimstatic void
799288943Sdimqla_init_locked(qla_host_t *ha)
800296417Sdim{
801288943Sdim	struct ifnet *ifp = ha->ifp;
802276479Sdim
803276479Sdim	qla_stop(ha);
804288943Sdim
805288943Sdim	if (qla_alloc_xmt_bufs(ha) != 0)
806288943Sdim		return;
807288943Sdim
808288943Sdim	if (qla_alloc_rcv_bufs(ha) != 0)
809276479Sdim		return;
810276479Sdim
811276479Sdim	bcopy(IF_LLADDR(ha->ifp), ha->hw.mac_addr, ETHER_ADDR_LEN);
812288943Sdim
813288943Sdim	ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_TSO;
814288943Sdim
815288943Sdim	ha->flags.stop_rcv = 0;
816276479Sdim 	if (ql_init_hw_if(ha) == 0) {
817276479Sdim		ifp = ha->ifp;
818276479Sdim		ifp->if_drv_flags |= IFF_DRV_RUNNING;
819276479Sdim		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
820288943Sdim		ha->flags.qla_watchdog_pause = 0;
821276479Sdim		ha->hw_vlan_tx_frames = 0;
822276479Sdim		ha->tx_tso_frames = 0;
823276479Sdim	}
824276479Sdim
825288943Sdim	return;
826296417Sdim}
827276479Sdim
828276479Sdimstatic void
829276479Sdimqla_init(void *arg)
830276479Sdim{
831276479Sdim	qla_host_t *ha;
832288943Sdim
833276479Sdim	ha = (qla_host_t *)arg;
834276479Sdim
835276479Sdim	QL_DPRINT2(ha, (ha->pci_dev, "%s: enter\n", __func__));
836288943Sdim
837276479Sdim	(void)QLA_LOCK(ha, __func__, 0);
838276479Sdim	qla_init_locked(ha);
839276479Sdim	QLA_UNLOCK(ha, __func__);
840276479Sdim
841276479Sdim	QL_DPRINT2(ha, (ha->pci_dev, "%s: exit\n", __func__));
842288943Sdim}
843276479Sdim
844276479Sdimstatic int
845276479Sdimqla_set_multi(qla_host_t *ha, uint32_t add_multi)
846276479Sdim{
847276479Sdim	uint8_t mta[Q8_MAX_NUM_MULTICAST_ADDRS * Q8_MAC_ADDR_LEN];
848288943Sdim	struct ifmultiaddr *ifma;
849276479Sdim	int mcnt = 0;
850276479Sdim	struct ifnet *ifp = ha->ifp;
851276479Sdim	int ret = 0;
852276479Sdim
853288943Sdim	if_maddr_rlock(ifp);
854288943Sdim
855296417Sdim	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
856276479Sdim
857276479Sdim		if (ifma->ifma_addr->sa_family != AF_LINK)
858276479Sdim			continue;
859276479Sdim
860276479Sdim		if (mcnt == Q8_MAX_NUM_MULTICAST_ADDRS)
861276479Sdim			break;
862276479Sdim
863309124Sdim		bcopy(LLADDR((struct sockaddr_dl *) ifma->ifma_addr),
864309124Sdim			&mta[mcnt * Q8_MAC_ADDR_LEN], Q8_MAC_ADDR_LEN);
865309124Sdim
866309124Sdim		mcnt++;
867309124Sdim	}
868309124Sdim
869288943Sdim	if_maddr_runlock(ifp);
870276479Sdim
871276479Sdim	if (QLA_LOCK(ha, __func__, 1) == 0) {
872276479Sdim		ret = ql_hw_set_multi(ha, mta, mcnt, add_multi);
873276479Sdim		QLA_UNLOCK(ha, __func__);
874276479Sdim	}
875288943Sdim
876276479Sdim	return (ret);
877276479Sdim}
878276479Sdim
879276479Sdimstatic int
880276479Sdimqla_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
881276479Sdim{
882276479Sdim	int ret = 0;
883276479Sdim	struct ifreq *ifr = (struct ifreq *)data;
884276479Sdim	struct ifaddr *ifa = (struct ifaddr *)data;
885276479Sdim	qla_host_t *ha;
886321369Sdim
887261991Sdim	ha = (qla_host_t *)ifp->if_softc;
888261991Sdim
889261991Sdim	switch (cmd) {
890321369Sdim	case SIOCSIFADDR:
891261991Sdim		QL_DPRINT4(ha, (ha->pci_dev, "%s: SIOCSIFADDR (0x%lx)\n",
892261991Sdim			__func__, cmd));
893288943Sdim
894288943Sdim		if (ifa->ifa_addr->sa_family == AF_INET) {
895276479Sdim			ifp->if_flags |= IFF_UP;
896261991Sdim			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
897261991Sdim				(void)QLA_LOCK(ha, __func__, 0);
898261991Sdim				qla_init_locked(ha);
899261991Sdim				QLA_UNLOCK(ha, __func__);
900288943Sdim			}
901276479Sdim			QL_DPRINT4(ha, (ha->pci_dev,
902261991Sdim				"%s: SIOCSIFADDR (0x%lx) ipv4 [0x%08x]\n",
903261991Sdim				__func__, cmd,
904261991Sdim				ntohl(IA_SIN(ifa)->sin_addr.s_addr)));
905261991Sdim
906288943Sdim			arp_ifinit(ifp, ifa);
907276479Sdim		} else {
908288943Sdim			ether_ioctl(ifp, cmd, data);
909288943Sdim		}
910288943Sdim		break;
911288943Sdim
912288943Sdim	case SIOCSIFMTU:
913288943Sdim		QL_DPRINT4(ha, (ha->pci_dev, "%s: SIOCSIFMTU (0x%lx)\n",
914288943Sdim			__func__, cmd));
915288943Sdim
916288943Sdim		if (ifr->ifr_mtu > QLA_MAX_MTU) {
917261991Sdim			ret = EINVAL;
918261991Sdim		} else {
919261991Sdim			(void) QLA_LOCK(ha, __func__, 0);
920261991Sdim			ifp->if_mtu = ifr->ifr_mtu;
921288943Sdim			ha->max_frame_size =
922276479Sdim				ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN;
923288943Sdim			if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) {
924288943Sdim				ret = ql_set_max_mtu(ha, ha->max_frame_size,
925288943Sdim					ha->hw.rcv_cntxt_id);
926288943Sdim			}
927288943Sdim
928288943Sdim			if (ifp->if_mtu > ETHERMTU)
929288943Sdim				ha->std_replenish = QL_JUMBO_REPLENISH_THRES;
930288943Sdim			else
931288943Sdim				ha->std_replenish = QL_STD_REPLENISH_THRES;
932288943Sdim
933288943Sdim
934288943Sdim			QLA_UNLOCK(ha, __func__);
935288943Sdim
936288943Sdim			if (ret)
937288943Sdim				ret = EINVAL;
938288943Sdim		}
939288943Sdim
940288943Sdim		break;
941288943Sdim
942288943Sdim	case SIOCSIFFLAGS:
943288943Sdim		QL_DPRINT4(ha, (ha->pci_dev, "%s: SIOCSIFFLAGS (0x%lx)\n",
944288943Sdim			__func__, cmd));
945288943Sdim
946261991Sdim		(void)QLA_LOCK(ha, __func__, 0);
947261991Sdim
948261991Sdim		if (ifp->if_flags & IFF_UP) {
949261991Sdim			if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) {
950288943Sdim				if ((ifp->if_flags ^ ha->if_flags) &
951288943Sdim					IFF_PROMISC) {
952288943Sdim					ret = ql_set_promisc(ha);
953288943Sdim				} else if ((ifp->if_flags ^ ha->if_flags) &
954276479Sdim					IFF_ALLMULTI) {
955261991Sdim					ret = ql_set_allmulti(ha);
956261991Sdim				}
957261991Sdim			} else {
958261991Sdim				qla_init_locked(ha);
959288943Sdim				ha->max_frame_size = ifp->if_mtu +
960276479Sdim					ETHER_HDR_LEN + ETHER_CRC_LEN;
961261991Sdim				ret = ql_set_max_mtu(ha, ha->max_frame_size,
962261991Sdim					ha->hw.rcv_cntxt_id);
963261991Sdim			}
964261991Sdim		} else {
965280031Sdim			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
966280031Sdim				qla_stop(ha);
967288943Sdim			ha->if_flags = ifp->if_flags;
968288943Sdim		}
969280031Sdim
970280031Sdim		QLA_UNLOCK(ha, __func__);
971280031Sdim		break;
972280031Sdim
973280031Sdim	case SIOCADDMULTI:
974288943Sdim		QL_DPRINT4(ha, (ha->pci_dev,
975276479Sdim			"%s: %s (0x%lx)\n", __func__, "SIOCADDMULTI", cmd));
976261991Sdim
977261991Sdim		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
978261991Sdim			if (qla_set_multi(ha, 1))
979261991Sdim				ret = EINVAL;
980261991Sdim		}
981261991Sdim		break;
982261991Sdim
983288943Sdim	case SIOCDELMULTI:
984276479Sdim		QL_DPRINT4(ha, (ha->pci_dev,
985288943Sdim			"%s: %s (0x%lx)\n", __func__, "SIOCDELMULTI", cmd));
986288943Sdim
987288943Sdim		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
988288943Sdim			if (qla_set_multi(ha, 0))
989288943Sdim				ret = EINVAL;
990288943Sdim		}
991288943Sdim		break;
992288943Sdim
993288943Sdim	case SIOCSIFMEDIA:
994288943Sdim	case SIOCGIFMEDIA:
995288943Sdim		QL_DPRINT4(ha, (ha->pci_dev,
996288943Sdim			"%s: SIOCSIFMEDIA/SIOCGIFMEDIA (0x%lx)\n",
997261991Sdim			__func__, cmd));
998261991Sdim		ret = ifmedia_ioctl(ifp, ifr, &ha->media, cmd);
999261991Sdim		break;
1000261991Sdim
1001261991Sdim	case SIOCSIFCAP:
1002261991Sdim	{
1003261991Sdim		int mask = ifr->ifr_reqcap ^ ifp->if_capenable;
1004288943Sdim
1005288943Sdim		QL_DPRINT4(ha, (ha->pci_dev, "%s: SIOCSIFCAP (0x%lx)\n",
1006276479Sdim			__func__, cmd));
1007261991Sdim
1008261991Sdim		if (mask & IFCAP_HWCSUM)
1009288943Sdim			ifp->if_capenable ^= IFCAP_HWCSUM;
1010288943Sdim		if (mask & IFCAP_TSO4)
1011261991Sdim			ifp->if_capenable ^= IFCAP_TSO4;
1012261991Sdim		if (mask & IFCAP_VLAN_HWTAGGING)
1013288943Sdim			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
1014288943Sdim		if (mask & IFCAP_VLAN_HWTSO)
1015276479Sdim			ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
1016276479Sdim
1017261991Sdim		if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
1018261991Sdim			qla_init(ha);
1019261991Sdim
1020261991Sdim		VLAN_CAPABILITIES(ifp);
1021261991Sdim		break;
1022321369Sdim	}
1023261991Sdim
1024261991Sdim	default:
1025261991Sdim		QL_DPRINT4(ha, (ha->pci_dev, "%s: default (0x%lx)\n",
1026261991Sdim			__func__, cmd));
1027261991Sdim		ret = ether_ioctl(ifp, cmd, data);
1028261991Sdim		break;
1029261991Sdim	}
1030261991Sdim
1031276479Sdim	return (ret);
1032276479Sdim}
1033261991Sdim
1034261991Sdimstatic int
1035276479Sdimqla_media_change(struct ifnet *ifp)
1036261991Sdim{
1037261991Sdim	qla_host_t *ha;
1038276479Sdim	struct ifmedia *ifm;
1039276479Sdim	int ret = 0;
1040276479Sdim
1041276479Sdim	ha = (qla_host_t *)ifp->if_softc;
1042276479Sdim
1043261991Sdim	QL_DPRINT2(ha, (ha->pci_dev, "%s: enter\n", __func__));
1044261991Sdim
1045261991Sdim	ifm = &ha->media;
1046261991Sdim
1047321369Sdim	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
1048261991Sdim		ret = EINVAL;
1049261991Sdim
1050261991Sdim	QL_DPRINT2(ha, (ha->pci_dev, "%s: exit\n", __func__));
1051261991Sdim
1052261991Sdim	return (ret);
1053261991Sdim}
1054261991Sdim
1055261991Sdimstatic void
1056261991Sdimqla_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
1057288943Sdim{
1058261991Sdim	qla_host_t *ha;
1059261991Sdim
1060288943Sdim	ha = (qla_host_t *)ifp->if_softc;
1061276479Sdim
1062276479Sdim	QL_DPRINT2(ha, (ha->pci_dev, "%s: enter\n", __func__));
1063261991Sdim
1064261991Sdim	ifmr->ifm_status = IFM_AVALID;
1065261991Sdim	ifmr->ifm_active = IFM_ETHER;
1066261991Sdim
1067261991Sdim	ql_update_link_state(ha);
1068261991Sdim	if (ha->hw.link_up) {
1069261991Sdim		ifmr->ifm_status |= IFM_ACTIVE;
1070261991Sdim		ifmr->ifm_active |= (IFM_FDX | qla_get_optics(ha));
1071261991Sdim	}
1072261991Sdim
1073261991Sdim	QL_DPRINT2(ha, (ha->pci_dev, "%s: exit (%s)\n", __func__,\
1074288943Sdim		(ha->hw.link_up ? "link_up" : "link_down")));
1075288943Sdim
1076261991Sdim	return;
1077261991Sdim}
1078261991Sdim
1079261991Sdimstatic void
1080261991Sdimqla_start(struct ifnet *ifp)
1081261991Sdim{
1082261991Sdim	struct mbuf    *m_head;
1083261991Sdim	qla_host_t *ha = (qla_host_t *)ifp->if_softc;
1084261991Sdim
1085261991Sdim	QL_DPRINT8(ha, (ha->pci_dev, "%s: enter\n", __func__));
1086261991Sdim
1087261991Sdim	if (!mtx_trylock(&ha->tx_lock)) {
1088261991Sdim		QL_DPRINT8(ha, (ha->pci_dev,
1089261991Sdim			"%s: mtx_trylock(&ha->tx_lock) failed\n", __func__));
1090261991Sdim		return;
1091261991Sdim	}
1092261991Sdim
1093261991Sdim	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
1094261991Sdim		IFF_DRV_RUNNING) {
1095261991Sdim		QL_DPRINT8(ha,
1096261991Sdim			(ha->pci_dev, "%s: !IFF_DRV_RUNNING\n", __func__));
1097261991Sdim		QLA_TX_UNLOCK(ha);
1098261991Sdim		return;
1099261991Sdim	}
1100261991Sdim
1101261991Sdim	if (!ha->watchdog_ticks)
1102261991Sdim		ql_update_link_state(ha);
1103261991Sdim
1104261991Sdim	if (!ha->hw.link_up) {
1105261991Sdim		QL_DPRINT8(ha, (ha->pci_dev, "%s: link down\n", __func__));
1106261991Sdim		QLA_TX_UNLOCK(ha);
1107261991Sdim		return;
1108280031Sdim	}
1109261991Sdim
1110261991Sdim	while (ifp->if_snd.ifq_head != NULL) {
1111276479Sdim		IF_DEQUEUE(&ifp->if_snd, m_head);
1112276479Sdim
1113280031Sdim		if (m_head == NULL) {
1114276479Sdim			QL_DPRINT8(ha, (ha->pci_dev, "%s: m_head == NULL\n",
1115276479Sdim				__func__));
1116261991Sdim			break;
1117261991Sdim		}
1118261991Sdim
1119261991Sdim		if (qla_send(ha, &m_head)) {
1120288943Sdim			if (m_head == NULL)
1121261991Sdim				break;
1122261991Sdim			QL_DPRINT8(ha, (ha->pci_dev, "%s: PREPEND\n", __func__));
1123276479Sdim			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1124276479Sdim			IF_PREPEND(&ifp->if_snd, m_head);
1125276479Sdim			break;
1126276479Sdim		}
1127276479Sdim		/* Send a copy of the frame to the BPF listener */
1128288943Sdim		ETHER_BPF_MTAP(ifp, m_head);
1129288943Sdim	}
1130288943Sdim	QLA_TX_UNLOCK(ha);
1131276479Sdim	QL_DPRINT8(ha, (ha->pci_dev, "%s: exit\n", __func__));
1132276479Sdim	return;
1133276479Sdim}
1134276479Sdim
1135276479Sdimstatic int
1136276479Sdimqla_send(qla_host_t *ha, struct mbuf **m_headp)
1137276479Sdim{
1138276479Sdim	bus_dma_segment_t	segs[QLA_MAX_SEGMENTS];
1139276479Sdim	bus_dmamap_t		map;
1140276479Sdim	int			nsegs;
1141276479Sdim	int			ret = -1;
1142276479Sdim	uint32_t		tx_idx;
1143276479Sdim	struct mbuf		*m_head = *m_headp;
1144276479Sdim	uint32_t		txr_idx = ha->txr_idx;
1145276479Sdim
1146276479Sdim	QL_DPRINT8(ha, (ha->pci_dev, "%s: enter\n", __func__));
1147276479Sdim
1148276479Sdim	/* check if flowid is set */
1149276479Sdim	if (M_HASHTYPE_GET(m_head) != M_HASHTYPE_NONE)
1150276479Sdim		txr_idx = m_head->m_pkthdr.flowid & (ha->hw.num_tx_rings - 1);
1151276479Sdim
1152276479Sdim	tx_idx = ha->hw.tx_cntxt[txr_idx].txr_next;
1153276479Sdim	map = ha->tx_ring[txr_idx].tx_buf[tx_idx].map;
1154276479Sdim
1155276479Sdim	ret = bus_dmamap_load_mbuf_sg(ha->tx_tag, map, m_head, segs, &nsegs,
1156296417Sdim			BUS_DMA_NOWAIT);
1157296417Sdim
1158261991Sdim	if (ret == EFBIG) {
1159276479Sdim
1160261991Sdim		struct mbuf *m;
1161261991Sdim
1162261991Sdim		QL_DPRINT8(ha, (ha->pci_dev, "%s: EFBIG [%d]\n", __func__,
1163261991Sdim			m_head->m_pkthdr.len));
1164261991Sdim
1165261991Sdim		m = m_defrag(m_head, M_NOWAIT);
1166296417Sdim		if (m == NULL) {
1167296417Sdim			ha->err_tx_defrag++;
1168296417Sdim			m_freem(m_head);
1169296417Sdim			*m_headp = NULL;
1170296417Sdim			device_printf(ha->pci_dev,
1171296417Sdim				"%s: m_defrag() = NULL [%d]\n",
1172296417Sdim				__func__, ret);
1173296417Sdim			return (ENOBUFS);
1174296417Sdim		}
1175296417Sdim		m_head = m;
1176296417Sdim		*m_headp = m_head;
1177296417Sdim
1178314564Sdim		if ((ret = bus_dmamap_load_mbuf_sg(ha->tx_tag, map, m_head,
1179249259Sdim					segs, &nsegs, BUS_DMA_NOWAIT))) {
1180249259Sdim
1181249259Sdim			ha->err_tx_dmamap_load++;
1182249259Sdim
1183249259Sdim			device_printf(ha->pci_dev,
1184249259Sdim				"%s: bus_dmamap_load_mbuf_sg failed0[%d, %d]\n",
1185249259Sdim				__func__, ret, m_head->m_pkthdr.len);
1186249259Sdim
1187249259Sdim			if (ret != ENOMEM) {
1188249259Sdim				m_freem(m_head);
1189249259Sdim				*m_headp = NULL;
1190249259Sdim			}
1191249259Sdim			return (ret);
1192249259Sdim		}
1193249259Sdim
1194288943Sdim	} else if (ret) {
1195288943Sdim
1196288943Sdim		ha->err_tx_dmamap_load++;
1197321369Sdim
1198321369Sdim		device_printf(ha->pci_dev,
1199321369Sdim			"%s: bus_dmamap_load_mbuf_sg failed1[%d, %d]\n",
1200288943Sdim			__func__, ret, m_head->m_pkthdr.len);
1201251662Sdim
1202249259Sdim		if (ret != ENOMEM) {
1203249259Sdim			m_freem(m_head);
1204249259Sdim			*m_headp = NULL;
1205276479Sdim		}
1206249259Sdim		return (ret);
1207249259Sdim	}
1208249259Sdim
1209296417Sdim	QL_ASSERT(ha, (nsegs != 0), ("qla_send: empty packet"));
1210296417Sdim
1211249259Sdim	bus_dmamap_sync(ha->tx_tag, map, BUS_DMASYNC_PREWRITE);
1212249259Sdim
1213249259Sdim        if (!(ret = ql_hw_send(ha, segs, nsegs, tx_idx, m_head, txr_idx))) {
1214296417Sdim
1215249259Sdim		ha->tx_ring[txr_idx].count++;
1216296417Sdim		ha->tx_ring[txr_idx].tx_buf[tx_idx].m_head = m_head;
1217249259Sdim	} else {
1218321369Sdim		if (ret == EINVAL) {
1219276479Sdim			if (m_head)
1220276479Sdim				m_freem(m_head);
1221288943Sdim			*m_headp = NULL;
1222276479Sdim		}
1223276479Sdim	}
1224249259Sdim
1225296417Sdim	QL_DPRINT8(ha, (ha->pci_dev, "%s: exit\n", __func__));
1226276479Sdim	return (ret);
1227276479Sdim}
1228276479Sdim
1229276479Sdimstatic void
1230261991Sdimqla_stop(qla_host_t *ha)
1231251662Sdim{
1232251662Sdim	struct ifnet *ifp = ha->ifp;
1233261991Sdim	device_t	dev;
1234251662Sdim
1235249259Sdim	dev = ha->pci_dev;
1236251662Sdim
1237261991Sdim	ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE | IFF_DRV_RUNNING);
1238251662Sdim
1239249259Sdim	ha->flags.qla_watchdog_pause = 1;
1240249259Sdim
1241261991Sdim	while (!ha->qla_watchdog_paused)
1242276479Sdim		qla_mdelay(__func__, 1);
1243288943Sdim
1244249259Sdim	ha->flags.stop_rcv = 1;
1245249259Sdim	ql_hw_stop_rcv(ha);
1246249259Sdim
1247261991Sdim	ql_del_hw_if(ha);
1248276479Sdim
1249249259Sdim	qla_free_xmt_bufs(ha);
1250249259Sdim	qla_free_rcv_bufs(ha);
1251261991Sdim
1252261991Sdim	return;
1253249259Sdim}
1254249259Sdim
1255249259Sdim/*
1256249259Sdim * Buffer Management Functions for Transmit and Receive Rings
1257276479Sdim */
1258251662Sdimstatic int
1259249259Sdimqla_alloc_xmt_bufs(qla_host_t *ha)
1260249259Sdim{
1261288943Sdim	int ret = 0;
1262249259Sdim	uint32_t i, j;
1263249259Sdim	qla_tx_buf_t *txb;
1264249259Sdim
1265261991Sdim	if (bus_dma_tag_create(NULL,    /* parent */
1266249259Sdim		1, 0,    /* alignment, bounds */
1267249259Sdim		BUS_SPACE_MAXADDR,       /* lowaddr */
1268276479Sdim		BUS_SPACE_MAXADDR,       /* highaddr */
1269251662Sdim		NULL, NULL,      /* filter, filterarg */
1270251662Sdim		QLA_MAX_TSO_FRAME_SIZE,     /* maxsize */
1271249259Sdim		QLA_MAX_SEGMENTS,        /* nsegments */
1272288943Sdim		PAGE_SIZE,        /* maxsegsize */
1273249259Sdim		BUS_DMA_ALLOCNOW,        /* flags */
1274249259Sdim		NULL,    /* lockfunc */
1275261991Sdim		NULL,    /* lockfuncarg */
1276251662Sdim		&ha->tx_tag)) {
1277251662Sdim		device_printf(ha->pci_dev, "%s: tx_tag alloc failed\n",
1278251662Sdim			__func__);
1279251662Sdim		return (ENOMEM);
1280276479Sdim	}
1281276479Sdim
1282261991Sdim	for (i = 0; i < ha->hw.num_tx_rings; i++) {
1283276479Sdim		bzero((void *)ha->tx_ring[i].tx_buf,
1284276479Sdim			(sizeof(qla_tx_buf_t) * NUM_TX_DESCRIPTORS));
1285276479Sdim	}
1286276479Sdim
1287276479Sdim	for (j = 0; j < ha->hw.num_tx_rings; j++) {
1288276479Sdim		for (i = 0; i < NUM_TX_DESCRIPTORS; i++) {
1289249259Sdim
1290249259Sdim			txb = &ha->tx_ring[j].tx_buf[i];
1291261991Sdim
1292261991Sdim			if ((ret = bus_dmamap_create(ha->tx_tag,
1293261991Sdim					BUS_DMA_NOWAIT, &txb->map))) {
1294249259Sdim
1295296417Sdim				ha->err_tx_dmamap_create++;
1296249259Sdim				device_printf(ha->pci_dev,
1297249259Sdim					"%s: bus_dmamap_create failed[%d]\n",
1298261991Sdim					__func__, ret);
1299261991Sdim
1300261991Sdim				qla_free_xmt_bufs(ha);
1301261991Sdim
1302288943Sdim				return (ret);
1303261991Sdim			}
1304288943Sdim		}
1305261991Sdim	}
1306261991Sdim
1307276479Sdim	return 0;
1308261991Sdim}
1309288943Sdim
1310261991Sdim/*
1311261991Sdim * Release mbuf after it sent on the wire
1312249259Sdim */
1313249259Sdimstatic void
1314261991Sdimqla_clear_tx_buf(qla_host_t *ha, qla_tx_buf_t *txb)
1315261991Sdim{
1316261991Sdim	QL_DPRINT2(ha, (ha->pci_dev, "%s: enter\n", __func__));
1317261991Sdim
1318261991Sdim	if (txb->m_head && txb->map) {
1319261991Sdim
1320261991Sdim		bus_dmamap_unload(ha->tx_tag, txb->map);
1321261991Sdim
1322261991Sdim		m_freem(txb->m_head);
1323261991Sdim		txb->m_head = NULL;
1324261991Sdim	}
1325261991Sdim
1326261991Sdim	if (txb->map)
1327261991Sdim		bus_dmamap_destroy(ha->tx_tag, txb->map);
1328261991Sdim
1329261991Sdim	QL_DPRINT2(ha, (ha->pci_dev, "%s: exit\n", __func__));
1330261991Sdim}
1331261991Sdim
1332261991Sdimstatic void
1333261991Sdimqla_free_xmt_bufs(qla_host_t *ha)
1334261991Sdim{
1335261991Sdim	int		i, j;
1336261991Sdim
1337261991Sdim	for (j = 0; j < ha->hw.num_tx_rings; j++) {
1338276479Sdim		for (i = 0; i < NUM_TX_DESCRIPTORS; i++)
1339261991Sdim			qla_clear_tx_buf(ha, &ha->tx_ring[j].tx_buf[i]);
1340261991Sdim	}
1341261991Sdim
1342249259Sdim	if (ha->tx_tag != NULL) {
1343249259Sdim		bus_dma_tag_destroy(ha->tx_tag);
1344249259Sdim		ha->tx_tag = NULL;
1345249259Sdim	}
1346288943Sdim
1347249259Sdim	for (i = 0; i < ha->hw.num_tx_rings; i++) {
1348249259Sdim		bzero((void *)ha->tx_ring[i].tx_buf,
1349261991Sdim			(sizeof(qla_tx_buf_t) * NUM_TX_DESCRIPTORS));
1350261991Sdim	}
1351261991Sdim	return;
1352288943Sdim}
1353261991Sdim
1354261991Sdim
1355249259Sdimstatic int
1356261991Sdimqla_alloc_rcv_std(qla_host_t *ha)
1357261991Sdim{
1358249259Sdim	int		i, j, k, r, ret = 0;
1359261991Sdim	qla_rx_buf_t	*rxb;
1360276479Sdim	qla_rx_ring_t	*rx_ring;
1361276479Sdim
1362276479Sdim	for (r = 0; r < ha->hw.num_rds_rings; r++) {
1363276479Sdim
1364276479Sdim		rx_ring = &ha->rx_ring[r];
1365276479Sdim
1366276479Sdim		for (i = 0; i < NUM_RX_DESCRIPTORS; i++) {
1367276479Sdim
1368276479Sdim			rxb = &rx_ring->rx_buf[i];
1369249259Sdim
1370261991Sdim			ret = bus_dmamap_create(ha->rx_tag, BUS_DMA_NOWAIT,
1371261991Sdim					&rxb->map);
1372261991Sdim
1373261991Sdim			if (ret) {
1374261991Sdim				device_printf(ha->pci_dev,
1375261991Sdim					"%s: dmamap[%d, %d] failed\n",
1376261991Sdim					__func__, r, i);
1377261991Sdim
1378261991Sdim				for (k = 0; k < r; k++) {
1379249259Sdim					for (j = 0; j < NUM_RX_DESCRIPTORS;
1380249259Sdim						j++) {
1381261991Sdim						rxb = &ha->rx_ring[k].rx_buf[j];
1382261991Sdim						bus_dmamap_destroy(ha->rx_tag,
1383261991Sdim							rxb->map);
1384249259Sdim					}
1385251662Sdim				}
1386249259Sdim
1387249259Sdim				for (j = 0; j < i; j++) {
1388276479Sdim					bus_dmamap_destroy(ha->rx_tag,
1389276479Sdim						rx_ring->rx_buf[j].map);
1390276479Sdim				}
1391276479Sdim				goto qla_alloc_rcv_std_err;
1392276479Sdim			}
1393261991Sdim		}
1394249259Sdim	}
1395261991Sdim
1396251662Sdim	qla_init_hw_rcv_descriptors(ha);
1397251662Sdim
1398251662Sdim
1399261991Sdim	for (r = 0; r < ha->hw.num_rds_rings; r++) {
1400261991Sdim
1401261991Sdim		rx_ring = &ha->rx_ring[r];
1402261991Sdim
1403261991Sdim		for (i = 0; i < NUM_RX_DESCRIPTORS; i++) {
1404261991Sdim			rxb = &rx_ring->rx_buf[i];
1405249259Sdim			rxb->handle = i;
1406249259Sdim			if (!(ret = ql_get_mbuf(ha, rxb, NULL))) {
1407276479Sdim				/*
1408276479Sdim			 	 * set the physical address in the
1409276479Sdim				 * corresponding descriptor entry in the
1410276479Sdim				 * receive ring/queue for the hba
1411276479Sdim				 */
1412276479Sdim				qla_set_hw_rcv_desc(ha, r, i, rxb->handle,
1413276479Sdim					rxb->paddr,
1414276479Sdim					(rxb->m_head)->m_pkthdr.len);
1415276479Sdim			} else {
1416276479Sdim				device_printf(ha->pci_dev,
1417276479Sdim					"%s: ql_get_mbuf [%d, %d] failed\n",
1418276479Sdim					__func__, r, i);
1419276479Sdim				bus_dmamap_destroy(ha->rx_tag, rxb->map);
1420276479Sdim				goto qla_alloc_rcv_std_err;
1421261991Sdim			}
1422261991Sdim		}
1423261991Sdim	}
1424261991Sdim	return 0;
1425261991Sdim
1426261991Sdimqla_alloc_rcv_std_err:
1427261991Sdim	return (-1);
1428249259Sdim}
1429249259Sdim
1430261991Sdimstatic void
1431249259Sdimqla_free_rcv_std(qla_host_t *ha)
1432261991Sdim{
1433261991Sdim	int		i, r;
1434261991Sdim	qla_rx_buf_t	*rxb;
1435261991Sdim
1436261991Sdim	for (r = 0; r < ha->hw.num_rds_rings; r++) {
1437261991Sdim		for (i = 0; i < NUM_RX_DESCRIPTORS; i++) {
1438261991Sdim			rxb = &ha->rx_ring[r].rx_buf[i];
1439261991Sdim			if (rxb->m_head != NULL) {
1440261991Sdim				bus_dmamap_unload(ha->rx_tag, rxb->map);
1441261991Sdim				bus_dmamap_destroy(ha->rx_tag, rxb->map);
1442261991Sdim				m_freem(rxb->m_head);
1443261991Sdim				rxb->m_head = NULL;
1444261991Sdim			}
1445251662Sdim		}
1446261991Sdim	}
1447261991Sdim	return;
1448261991Sdim}
1449261991Sdim
1450261991Sdimstatic int
1451251662Sdimqla_alloc_rcv_bufs(qla_host_t *ha)
1452261991Sdim{
1453261991Sdim	int		i, ret = 0;
1454261991Sdim
1455261991Sdim	if (bus_dma_tag_create(NULL,    /* parent */
1456261991Sdim			1, 0,    /* alignment, bounds */
1457261991Sdim			BUS_SPACE_MAXADDR,       /* lowaddr */
1458249259Sdim			BUS_SPACE_MAXADDR,       /* highaddr */
1459249259Sdim			NULL, NULL,      /* filter, filterarg */
1460276479Sdim			MJUM9BYTES,     /* maxsize */
1461276479Sdim			1,        /* nsegments */
1462276479Sdim			MJUM9BYTES,        /* maxsegsize */
1463276479Sdim			BUS_DMA_ALLOCNOW,        /* flags */
1464276479Sdim			NULL,    /* lockfunc */
1465276479Sdim			NULL,    /* lockfuncarg */
1466276479Sdim			&ha->rx_tag)) {
1467249259Sdim
1468261991Sdim		device_printf(ha->pci_dev, "%s: rx_tag alloc failed\n",
1469288943Sdim			__func__);
1470288943Sdim
1471288943Sdim		return (ENOMEM);
1472288943Sdim	}
1473288943Sdim
1474276479Sdim	bzero((void *)ha->rx_ring, (sizeof(qla_rx_ring_t) * MAX_RDS_RINGS));
1475261991Sdim
1476288943Sdim	for (i = 0; i < ha->hw.num_sds_rings; i++) {
1477288943Sdim		ha->hw.sds[i].sdsr_next = 0;
1478261991Sdim		ha->hw.sds[i].rxb_free = NULL;
1479261991Sdim		ha->hw.sds[i].rx_free = 0;
1480288943Sdim	}
1481288943Sdim
1482288943Sdim	ret = qla_alloc_rcv_std(ha);
1483288943Sdim
1484288943Sdim	return (ret);
1485288943Sdim}
1486288943Sdim
1487288943Sdimstatic void
1488280031Sdimqla_free_rcv_bufs(qla_host_t *ha)
1489288943Sdim{
1490288943Sdim	int		i;
1491288943Sdim
1492276479Sdim	qla_free_rcv_std(ha);
1493261991Sdim
1494261991Sdim	if (ha->rx_tag != NULL) {
1495261991Sdim		bus_dma_tag_destroy(ha->rx_tag);
1496261991Sdim		ha->rx_tag = NULL;
1497261991Sdim	}
1498249259Sdim
1499249259Sdim	bzero((void *)ha->rx_ring, (sizeof(qla_rx_ring_t) * MAX_RDS_RINGS));
1500249259Sdim
1501249259Sdim	for (i = 0; i < ha->hw.num_sds_rings; i++) {
1502249259Sdim		ha->hw.sds[i].sdsr_next = 0;
1503321369Sdim		ha->hw.sds[i].rxb_free = NULL;
1504		ha->hw.sds[i].rx_free = 0;
1505	}
1506
1507	return;
1508}
1509
1510int
1511ql_get_mbuf(qla_host_t *ha, qla_rx_buf_t *rxb, struct mbuf *nmp)
1512{
1513	register struct mbuf *mp = nmp;
1514	struct ifnet   		*ifp;
1515	int            		ret = 0;
1516	uint32_t		offset;
1517	bus_dma_segment_t	segs[1];
1518	int			nsegs;
1519
1520	QL_DPRINT2(ha, (ha->pci_dev, "%s: enter\n", __func__));
1521
1522	ifp = ha->ifp;
1523
1524	if (mp == NULL) {
1525
1526		mp = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
1527
1528		if (mp == NULL) {
1529			ha->err_m_getcl++;
1530			ret = ENOBUFS;
1531			device_printf(ha->pci_dev,
1532					"%s: m_getcl failed\n", __func__);
1533			goto exit_ql_get_mbuf;
1534		}
1535		mp->m_len = mp->m_pkthdr.len = MCLBYTES;
1536	} else {
1537		mp->m_len = mp->m_pkthdr.len = MCLBYTES;
1538		mp->m_data = mp->m_ext.ext_buf;
1539		mp->m_next = NULL;
1540	}
1541
1542	offset = (uint32_t)((unsigned long long)mp->m_data & 0x7ULL);
1543	if (offset) {
1544		offset = 8 - offset;
1545		m_adj(mp, offset);
1546	}
1547
1548	/*
1549	 * Using memory from the mbuf cluster pool, invoke the bus_dma
1550	 * machinery to arrange the memory mapping.
1551	 */
1552	ret = bus_dmamap_load_mbuf_sg(ha->rx_tag, rxb->map,
1553			mp, segs, &nsegs, BUS_DMA_NOWAIT);
1554	rxb->paddr = segs[0].ds_addr;
1555
1556	if (ret || !rxb->paddr || (nsegs != 1)) {
1557		m_free(mp);
1558		rxb->m_head = NULL;
1559		device_printf(ha->pci_dev,
1560			"%s: bus_dmamap_load failed[%d, 0x%016llx, %d]\n",
1561			__func__, ret, (long long unsigned int)rxb->paddr,
1562			nsegs);
1563                ret = -1;
1564		goto exit_ql_get_mbuf;
1565	}
1566	rxb->m_head = mp;
1567	bus_dmamap_sync(ha->rx_tag, rxb->map, BUS_DMASYNC_PREREAD);
1568
1569exit_ql_get_mbuf:
1570	QL_DPRINT2(ha, (ha->pci_dev, "%s: exit ret = 0x%08x\n", __func__, ret));
1571	return (ret);
1572}
1573
1574static void
1575qla_tx_done(void *context, int pending)
1576{
1577	qla_host_t *ha = context;
1578	struct ifnet   *ifp;
1579
1580	ifp = ha->ifp;
1581
1582	if (!ifp)
1583		return;
1584
1585	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
1586		QL_DPRINT8(ha, (ha->pci_dev, "%s: !IFF_DRV_RUNNING\n", __func__));
1587		return;
1588	}
1589	ql_hw_tx_done(ha);
1590
1591	qla_start(ha->ifp);
1592}
1593
1594static void
1595qla_get_peer(qla_host_t *ha)
1596{
1597	device_t *peers;
1598	int count, i, slot;
1599	int my_slot = pci_get_slot(ha->pci_dev);
1600
1601	if (device_get_children(device_get_parent(ha->pci_dev), &peers, &count))
1602		return;
1603
1604	for (i = 0; i < count; i++) {
1605		slot = pci_get_slot(peers[i]);
1606
1607		if ((slot >= 0) && (slot == my_slot) &&
1608			(pci_get_device(peers[i]) ==
1609				pci_get_device(ha->pci_dev))) {
1610			if (ha->pci_dev != peers[i])
1611				ha->peer_dev = peers[i];
1612		}
1613	}
1614}
1615
1616static void
1617qla_send_msg_to_peer(qla_host_t *ha, uint32_t msg_to_peer)
1618{
1619	qla_host_t *ha_peer;
1620
1621	if (ha->peer_dev) {
1622        	if ((ha_peer = device_get_softc(ha->peer_dev)) != NULL) {
1623
1624			ha_peer->msg_from_peer = msg_to_peer;
1625		}
1626	}
1627}
1628
1629static void
1630qla_error_recovery(void *context, int pending)
1631{
1632	qla_host_t *ha = context;
1633	uint32_t msecs_100 = 100;
1634	struct ifnet *ifp = ha->ifp;
1635
1636        (void)QLA_LOCK(ha, __func__, 0);
1637
1638        ha->flags.stop_rcv = 1;
1639
1640        ql_hw_stop_rcv(ha);
1641
1642        ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE | IFF_DRV_RUNNING);
1643
1644        QLA_UNLOCK(ha, __func__);
1645
1646	if ((ha->pci_func & 0x1) == 0) {
1647
1648		if (!ha->msg_from_peer) {
1649			qla_send_msg_to_peer(ha, QL_PEER_MSG_RESET);
1650
1651			while ((ha->msg_from_peer != QL_PEER_MSG_ACK) &&
1652				msecs_100--)
1653				qla_mdelay(__func__, 100);
1654		}
1655
1656		ha->msg_from_peer = 0;
1657
1658		ql_minidump(ha);
1659
1660		(void) ql_init_hw(ha);
1661        	qla_free_xmt_bufs(ha);
1662	        qla_free_rcv_bufs(ha);
1663
1664		qla_send_msg_to_peer(ha, QL_PEER_MSG_ACK);
1665
1666	} else {
1667		if (ha->msg_from_peer == QL_PEER_MSG_RESET) {
1668
1669			ha->msg_from_peer = 0;
1670
1671			qla_send_msg_to_peer(ha, QL_PEER_MSG_ACK);
1672		} else {
1673			qla_send_msg_to_peer(ha, QL_PEER_MSG_RESET);
1674		}
1675
1676		while ((ha->msg_from_peer != QL_PEER_MSG_ACK)  && msecs_100--)
1677			qla_mdelay(__func__, 100);
1678		ha->msg_from_peer = 0;
1679
1680		(void) ql_init_hw(ha);
1681        	qla_free_xmt_bufs(ha);
1682	        qla_free_rcv_bufs(ha);
1683	}
1684        (void)QLA_LOCK(ha, __func__, 0);
1685
1686	if (qla_alloc_xmt_bufs(ha) != 0) {
1687        	QLA_UNLOCK(ha, __func__);
1688                return;
1689	}
1690
1691        if (qla_alloc_rcv_bufs(ha) != 0) {
1692        	QLA_UNLOCK(ha, __func__);
1693                return;
1694	}
1695
1696        ha->flags.stop_rcv = 0;
1697        if (ql_init_hw_if(ha) == 0) {
1698                ifp = ha->ifp;
1699                ifp->if_drv_flags |= IFF_DRV_RUNNING;
1700                ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1701                ha->flags.qla_watchdog_pause = 0;
1702        }
1703
1704        QLA_UNLOCK(ha, __func__);
1705}
1706
1707