ql_hw.c revision 305488
1250661Sdavidcs/*
2284741Sdavidcs * Copyright (c) 2013-2016 Qlogic Corporation
3250661Sdavidcs * All rights reserved.
4250661Sdavidcs *
5250661Sdavidcs *  Redistribution and use in source and binary forms, with or without
6250661Sdavidcs *  modification, are permitted provided that the following conditions
7250661Sdavidcs *  are met:
8250661Sdavidcs *
9250661Sdavidcs *  1. Redistributions of source code must retain the above copyright
10250661Sdavidcs *     notice, this list of conditions and the following disclaimer.
11250661Sdavidcs *  2. Redistributions in binary form must reproduce the above copyright
12250661Sdavidcs *     notice, this list of conditions and the following disclaimer in the
13250661Sdavidcs *     documentation and/or other materials provided with the distribution.
14250661Sdavidcs *
15250661Sdavidcs *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16250661Sdavidcs *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17250661Sdavidcs *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18250661Sdavidcs *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19250661Sdavidcs *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20250661Sdavidcs *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21250661Sdavidcs *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22250661Sdavidcs *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23250661Sdavidcs *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24250661Sdavidcs *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25250661Sdavidcs *  POSSIBILITY OF SUCH DAMAGE.
26250661Sdavidcs */
27250661Sdavidcs
28250661Sdavidcs/*
29250661Sdavidcs * File: ql_hw.c
30250661Sdavidcs * Author : David C Somayajulu, Qlogic Corporation, Aliso Viejo, CA 92656.
31298955Spfg * Content: Contains Hardware dependent functions
32250661Sdavidcs */
33250661Sdavidcs
34250661Sdavidcs#include <sys/cdefs.h>
35250661Sdavidcs__FBSDID("$FreeBSD: stable/11/sys/dev/qlxgbe/ql_hw.c 305488 2016-09-06 19:18:50Z davidcs $");
36250661Sdavidcs
37250661Sdavidcs#include "ql_os.h"
38250661Sdavidcs#include "ql_hw.h"
39250661Sdavidcs#include "ql_def.h"
40250661Sdavidcs#include "ql_inline.h"
41250661Sdavidcs#include "ql_ver.h"
42250661Sdavidcs#include "ql_glbl.h"
43250661Sdavidcs#include "ql_dbg.h"
44305487Sdavidcs#include "ql_minidump.h"
45250661Sdavidcs
46250661Sdavidcs/*
47250661Sdavidcs * Static Functions
48250661Sdavidcs */
49250661Sdavidcs
50250661Sdavidcsstatic void qla_del_rcv_cntxt(qla_host_t *ha);
51250661Sdavidcsstatic int qla_init_rcv_cntxt(qla_host_t *ha);
52250661Sdavidcsstatic void qla_del_xmt_cntxt(qla_host_t *ha);
53250661Sdavidcsstatic int qla_init_xmt_cntxt(qla_host_t *ha);
54250661Sdavidcsstatic void qla_hw_tx_done_locked(qla_host_t *ha, uint32_t txr_idx);
55250661Sdavidcsstatic int qla_mbx_cmd(qla_host_t *ha, uint32_t *h_mbox, uint32_t n_hmbox,
56250661Sdavidcs	uint32_t *fw_mbox, uint32_t n_fwmbox, uint32_t no_pause);
57284741Sdavidcsstatic int qla_config_intr_cntxt(qla_host_t *ha, uint32_t start_idx,
58284741Sdavidcs	uint32_t num_intrs, uint32_t create);
59250661Sdavidcsstatic int qla_config_rss(qla_host_t *ha, uint16_t cntxt_id);
60250661Sdavidcsstatic int qla_config_intr_coalesce(qla_host_t *ha, uint16_t cntxt_id,
61284741Sdavidcs	int tenable, int rcv);
62250661Sdavidcsstatic int qla_set_mac_rcv_mode(qla_host_t *ha, uint32_t mode);
63250661Sdavidcsstatic int qla_link_event_req(qla_host_t *ha, uint16_t cntxt_id);
64250661Sdavidcs
65250661Sdavidcsstatic int qla_tx_tso(qla_host_t *ha, struct mbuf *mp, q80_tx_cmd_t *tx_cmd,
66250661Sdavidcs		uint8_t *hdr);
67250661Sdavidcsstatic int qla_hw_add_all_mcast(qla_host_t *ha);
68250661Sdavidcsstatic int qla_hw_del_all_mcast(qla_host_t *ha);
69284741Sdavidcsstatic int qla_add_rcv_rings(qla_host_t *ha, uint32_t sds_idx, uint32_t nsds);
70250661Sdavidcs
71284741Sdavidcsstatic int qla_init_nic_func(qla_host_t *ha);
72284741Sdavidcsstatic int qla_stop_nic_func(qla_host_t *ha);
73284741Sdavidcsstatic int qla_query_fw_dcbx_caps(qla_host_t *ha);
74284741Sdavidcsstatic int qla_set_port_config(qla_host_t *ha, uint32_t cfg_bits);
75284741Sdavidcsstatic int qla_get_port_config(qla_host_t *ha, uint32_t *cfg_bits);
76284741Sdavidcsstatic void qla_get_quick_stats(qla_host_t *ha);
77305488Sdavidcsstatic int qla_set_cam_search_mode(qla_host_t *ha, uint32_t search_mode);
78305488Sdavidcsstatic int qla_get_cam_search_mode(qla_host_t *ha);
79284741Sdavidcs
80305487Sdavidcsstatic void ql_minidump_free(qla_host_t *ha);
81250661Sdavidcs
82250661Sdavidcs
83250661Sdavidcsstatic int
84250661Sdavidcsqla_sysctl_get_drvr_stats(SYSCTL_HANDLER_ARGS)
85250661Sdavidcs{
86250661Sdavidcs        int err = 0, ret;
87250661Sdavidcs        qla_host_t *ha;
88250661Sdavidcs	uint32_t i;
89250661Sdavidcs
90250661Sdavidcs        err = sysctl_handle_int(oidp, &ret, 0, req);
91250661Sdavidcs
92250661Sdavidcs        if (err || !req->newptr)
93250661Sdavidcs                return (err);
94250661Sdavidcs
95250661Sdavidcs        if (ret == 1) {
96250661Sdavidcs
97250661Sdavidcs                ha = (qla_host_t *)arg1;
98250661Sdavidcs
99305488Sdavidcs		for (i = 0; i < ha->hw.num_sds_rings; i++) {
100305488Sdavidcs
101250661Sdavidcs			device_printf(ha->pci_dev,
102250661Sdavidcs				"%s: sds_ring[%d] = %p\n", __func__,i,
103250661Sdavidcs				(void *)ha->hw.sds[i].intr_count);
104250661Sdavidcs
105305488Sdavidcs			device_printf(ha->pci_dev,
106305488Sdavidcs				"%s: sds_ring[%d].spurious_intr_count = %p\n",
107305488Sdavidcs				__func__,
108305488Sdavidcs				i, (void *)ha->hw.sds[i].spurious_intr_count);
109305488Sdavidcs
110305488Sdavidcs			device_printf(ha->pci_dev,
111305488Sdavidcs				"%s: sds_ring[%d].rx_free = %d\n", __func__,i,
112305488Sdavidcs				ha->hw.sds[i].rx_free);
113305488Sdavidcs		}
114305488Sdavidcs
115250661Sdavidcs		for (i = 0; i < ha->hw.num_tx_rings; i++)
116250661Sdavidcs			device_printf(ha->pci_dev,
117250661Sdavidcs				"%s: tx[%d] = %p\n", __func__,i,
118250661Sdavidcs				(void *)ha->tx_ring[i].count);
119250661Sdavidcs
120250661Sdavidcs		for (i = 0; i < ha->hw.num_rds_rings; i++)
121250661Sdavidcs			device_printf(ha->pci_dev,
122250661Sdavidcs				"%s: rds_ring[%d] = %p\n", __func__,i,
123250661Sdavidcs				(void *)ha->hw.rds[i].count);
124250661Sdavidcs
125250661Sdavidcs		device_printf(ha->pci_dev, "%s: lro_pkt_count = %p\n", __func__,
126250661Sdavidcs			(void *)ha->lro_pkt_count);
127250661Sdavidcs
128250661Sdavidcs		device_printf(ha->pci_dev, "%s: lro_bytes = %p\n", __func__,
129250661Sdavidcs			(void *)ha->lro_bytes);
130284741Sdavidcs
131284741Sdavidcs#ifdef QL_ENABLE_ISCSI_TLV
132284741Sdavidcs		device_printf(ha->pci_dev, "%s: iscsi_pkts = %p\n", __func__,
133284741Sdavidcs			(void *)ha->hw.iscsi_pkt_count);
134284741Sdavidcs#endif /* #ifdef QL_ENABLE_ISCSI_TLV */
135284741Sdavidcs
136250661Sdavidcs	}
137250661Sdavidcs	return (err);
138250661Sdavidcs}
139250661Sdavidcs
140284741Sdavidcsstatic int
141284741Sdavidcsqla_sysctl_get_quick_stats(SYSCTL_HANDLER_ARGS)
142284741Sdavidcs{
143284741Sdavidcs	int err, ret = 0;
144284741Sdavidcs	qla_host_t *ha;
145284741Sdavidcs
146284741Sdavidcs	err = sysctl_handle_int(oidp, &ret, 0, req);
147284741Sdavidcs
148284741Sdavidcs	if (err || !req->newptr)
149284741Sdavidcs		return (err);
150284741Sdavidcs
151284741Sdavidcs	if (ret == 1) {
152284741Sdavidcs		ha = (qla_host_t *)arg1;
153284741Sdavidcs		qla_get_quick_stats(ha);
154284741Sdavidcs	}
155284741Sdavidcs	return (err);
156284741Sdavidcs}
157284741Sdavidcs
158250661Sdavidcs#ifdef QL_DBG
159250661Sdavidcs
160250661Sdavidcsstatic void
161250661Sdavidcsqla_stop_pegs(qla_host_t *ha)
162250661Sdavidcs{
163250661Sdavidcs        uint32_t val = 1;
164250661Sdavidcs
165250661Sdavidcs        ql_rdwr_indreg32(ha, Q8_CRB_PEG_0, &val, 0);
166250661Sdavidcs        ql_rdwr_indreg32(ha, Q8_CRB_PEG_1, &val, 0);
167250661Sdavidcs        ql_rdwr_indreg32(ha, Q8_CRB_PEG_2, &val, 0);
168250661Sdavidcs        ql_rdwr_indreg32(ha, Q8_CRB_PEG_3, &val, 0);
169250661Sdavidcs        ql_rdwr_indreg32(ha, Q8_CRB_PEG_4, &val, 0);
170250661Sdavidcs        device_printf(ha->pci_dev, "%s PEGS HALTED!!!!!\n", __func__);
171250661Sdavidcs}
172250661Sdavidcs
173250661Sdavidcsstatic int
174250661Sdavidcsqla_sysctl_stop_pegs(SYSCTL_HANDLER_ARGS)
175250661Sdavidcs{
176250661Sdavidcs	int err, ret = 0;
177250661Sdavidcs	qla_host_t *ha;
178250661Sdavidcs
179250661Sdavidcs	err = sysctl_handle_int(oidp, &ret, 0, req);
180250661Sdavidcs
181250661Sdavidcs
182250661Sdavidcs	if (err || !req->newptr)
183250661Sdavidcs		return (err);
184250661Sdavidcs
185250661Sdavidcs	if (ret == 1) {
186250661Sdavidcs		ha = (qla_host_t *)arg1;
187250661Sdavidcs		(void)QLA_LOCK(ha, __func__, 0);
188250661Sdavidcs		qla_stop_pegs(ha);
189250661Sdavidcs		QLA_UNLOCK(ha, __func__);
190250661Sdavidcs	}
191250661Sdavidcs
192250661Sdavidcs	return err;
193250661Sdavidcs}
194250661Sdavidcs#endif /* #ifdef QL_DBG */
195250661Sdavidcs
196284741Sdavidcsstatic int
197284741Sdavidcsqla_validate_set_port_cfg_bit(uint32_t bits)
198284741Sdavidcs{
199284741Sdavidcs        if ((bits & 0xF) > 1)
200284741Sdavidcs                return (-1);
201284741Sdavidcs
202284741Sdavidcs        if (((bits >> 4) & 0xF) > 2)
203284741Sdavidcs                return (-1);
204284741Sdavidcs
205284741Sdavidcs        if (((bits >> 8) & 0xF) > 2)
206284741Sdavidcs                return (-1);
207284741Sdavidcs
208284741Sdavidcs        return (0);
209284741Sdavidcs}
210284741Sdavidcs
211284741Sdavidcsstatic int
212284741Sdavidcsqla_sysctl_port_cfg(SYSCTL_HANDLER_ARGS)
213284741Sdavidcs{
214284741Sdavidcs        int err, ret = 0;
215284741Sdavidcs        qla_host_t *ha;
216284741Sdavidcs        uint32_t cfg_bits;
217284741Sdavidcs
218284741Sdavidcs        err = sysctl_handle_int(oidp, &ret, 0, req);
219284741Sdavidcs
220284741Sdavidcs        if (err || !req->newptr)
221284741Sdavidcs                return (err);
222284741Sdavidcs
223284741Sdavidcs        if ((qla_validate_set_port_cfg_bit((uint32_t)ret) == 0)) {
224284741Sdavidcs
225284741Sdavidcs                ha = (qla_host_t *)arg1;
226284741Sdavidcs
227284741Sdavidcs                err = qla_get_port_config(ha, &cfg_bits);
228284741Sdavidcs
229284741Sdavidcs                if (err)
230284741Sdavidcs                        goto qla_sysctl_set_port_cfg_exit;
231284741Sdavidcs
232284741Sdavidcs                if (ret & 0x1) {
233284741Sdavidcs                        cfg_bits |= Q8_PORT_CFG_BITS_DCBX_ENABLE;
234284741Sdavidcs                } else {
235284741Sdavidcs                        cfg_bits &= ~Q8_PORT_CFG_BITS_DCBX_ENABLE;
236284741Sdavidcs                }
237284741Sdavidcs
238284741Sdavidcs                ret = ret >> 4;
239284741Sdavidcs                cfg_bits &= ~Q8_PORT_CFG_BITS_PAUSE_CFG_MASK;
240284741Sdavidcs
241284741Sdavidcs                if ((ret & 0xF) == 0) {
242284741Sdavidcs                        cfg_bits |= Q8_PORT_CFG_BITS_PAUSE_DISABLED;
243284741Sdavidcs                } else if ((ret & 0xF) == 1){
244284741Sdavidcs                        cfg_bits |= Q8_PORT_CFG_BITS_PAUSE_STD;
245284741Sdavidcs                } else {
246284741Sdavidcs                        cfg_bits |= Q8_PORT_CFG_BITS_PAUSE_PPM;
247284741Sdavidcs                }
248284741Sdavidcs
249284741Sdavidcs                ret = ret >> 4;
250284741Sdavidcs                cfg_bits &= ~Q8_PORT_CFG_BITS_STDPAUSE_DIR_MASK;
251284741Sdavidcs
252284741Sdavidcs                if (ret == 0) {
253284741Sdavidcs                        cfg_bits |= Q8_PORT_CFG_BITS_STDPAUSE_XMT_RCV;
254284741Sdavidcs                } else if (ret == 1){
255284741Sdavidcs                        cfg_bits |= Q8_PORT_CFG_BITS_STDPAUSE_XMT;
256284741Sdavidcs                } else {
257284741Sdavidcs                        cfg_bits |= Q8_PORT_CFG_BITS_STDPAUSE_RCV;
258284741Sdavidcs                }
259284741Sdavidcs
260284741Sdavidcs                err = qla_set_port_config(ha, cfg_bits);
261284741Sdavidcs        } else {
262284741Sdavidcs                ha = (qla_host_t *)arg1;
263284741Sdavidcs
264284741Sdavidcs                err = qla_get_port_config(ha, &cfg_bits);
265284741Sdavidcs        }
266284741Sdavidcs
267284741Sdavidcsqla_sysctl_set_port_cfg_exit:
268284741Sdavidcs        return err;
269284741Sdavidcs}
270284741Sdavidcs
271305488Sdavidcsstatic int
272305488Sdavidcsqla_sysctl_set_cam_search_mode(SYSCTL_HANDLER_ARGS)
273305488Sdavidcs{
274305488Sdavidcs	int err, ret = 0;
275305488Sdavidcs	qla_host_t *ha;
276305488Sdavidcs
277305488Sdavidcs	err = sysctl_handle_int(oidp, &ret, 0, req);
278305488Sdavidcs
279305488Sdavidcs	if (err || !req->newptr)
280305488Sdavidcs		return (err);
281305488Sdavidcs
282305488Sdavidcs	ha = (qla_host_t *)arg1;
283305488Sdavidcs
284305488Sdavidcs	if ((ret == Q8_HW_CONFIG_CAM_SEARCH_MODE_INTERNAL) ||
285305488Sdavidcs		(ret == Q8_HW_CONFIG_CAM_SEARCH_MODE_AUTO)) {
286305488Sdavidcs		err = qla_set_cam_search_mode(ha, (uint32_t)ret);
287305488Sdavidcs	} else {
288305488Sdavidcs		device_printf(ha->pci_dev, "%s: ret = %d\n", __func__, ret);
289305488Sdavidcs	}
290305488Sdavidcs
291305488Sdavidcs	return (err);
292305488Sdavidcs}
293305488Sdavidcs
294305488Sdavidcsstatic int
295305488Sdavidcsqla_sysctl_get_cam_search_mode(SYSCTL_HANDLER_ARGS)
296305488Sdavidcs{
297305488Sdavidcs	int err, ret = 0;
298305488Sdavidcs	qla_host_t *ha;
299305488Sdavidcs
300305488Sdavidcs	err = sysctl_handle_int(oidp, &ret, 0, req);
301305488Sdavidcs
302305488Sdavidcs	if (err || !req->newptr)
303305488Sdavidcs		return (err);
304305488Sdavidcs
305305488Sdavidcs	ha = (qla_host_t *)arg1;
306305488Sdavidcs	err = qla_get_cam_search_mode(ha);
307305488Sdavidcs
308305488Sdavidcs	return (err);
309305488Sdavidcs}
310305488Sdavidcs
311305488Sdavidcs
312250661Sdavidcs/*
313250661Sdavidcs * Name: ql_hw_add_sysctls
314250661Sdavidcs * Function: Add P3Plus specific sysctls
315250661Sdavidcs */
316250661Sdavidcsvoid
317250661Sdavidcsql_hw_add_sysctls(qla_host_t *ha)
318250661Sdavidcs{
319250661Sdavidcs        device_t	dev;
320250661Sdavidcs
321250661Sdavidcs        dev = ha->pci_dev;
322250661Sdavidcs
323250661Sdavidcs	ha->hw.num_sds_rings = MAX_SDS_RINGS;
324250661Sdavidcs	ha->hw.num_rds_rings = MAX_RDS_RINGS;
325250661Sdavidcs	ha->hw.num_tx_rings = NUM_TX_RINGS;
326250661Sdavidcs
327250661Sdavidcs	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
328250661Sdavidcs		SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
329250661Sdavidcs		OID_AUTO, "num_rds_rings", CTLFLAG_RD, &ha->hw.num_rds_rings,
330250661Sdavidcs		ha->hw.num_rds_rings, "Number of Rcv Descriptor Rings");
331250661Sdavidcs
332250661Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
333250661Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
334250661Sdavidcs                OID_AUTO, "num_sds_rings", CTLFLAG_RD, &ha->hw.num_sds_rings,
335250661Sdavidcs		ha->hw.num_sds_rings, "Number of Status Descriptor Rings");
336250661Sdavidcs
337250661Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
338250661Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
339250661Sdavidcs                OID_AUTO, "num_tx_rings", CTLFLAG_RD, &ha->hw.num_tx_rings,
340250661Sdavidcs		ha->hw.num_tx_rings, "Number of Transmit Rings");
341250661Sdavidcs
342250661Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
343250661Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
344250661Sdavidcs                OID_AUTO, "tx_ring_index", CTLFLAG_RW, &ha->txr_idx,
345250661Sdavidcs		ha->txr_idx, "Tx Ring Used");
346250661Sdavidcs
347250661Sdavidcs	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
348250661Sdavidcs		SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
349250661Sdavidcs		OID_AUTO, "drvr_stats", CTLTYPE_INT | CTLFLAG_RW,
350250661Sdavidcs		(void *)ha, 0,
351250661Sdavidcs		qla_sysctl_get_drvr_stats, "I", "Driver Maintained Statistics");
352250661Sdavidcs
353284741Sdavidcs        SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
354284741Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
355284741Sdavidcs                OID_AUTO, "quick_stats", CTLTYPE_INT | CTLFLAG_RW,
356284741Sdavidcs                (void *)ha, 0,
357284741Sdavidcs                qla_sysctl_get_quick_stats, "I", "Quick Statistics");
358284741Sdavidcs
359250661Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
360250661Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
361250661Sdavidcs                OID_AUTO, "max_tx_segs", CTLFLAG_RD, &ha->hw.max_tx_segs,
362250661Sdavidcs		ha->hw.max_tx_segs, "Max # of Segments in a non-TSO pkt");
363250661Sdavidcs
364250661Sdavidcs	ha->hw.sds_cidx_thres = 32;
365250661Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
366250661Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
367250661Sdavidcs                OID_AUTO, "sds_cidx_thres", CTLFLAG_RW, &ha->hw.sds_cidx_thres,
368250661Sdavidcs		ha->hw.sds_cidx_thres,
369250661Sdavidcs		"Number of SDS entries to process before updating"
370250661Sdavidcs		" SDS Ring Consumer Index");
371250661Sdavidcs
372250661Sdavidcs	ha->hw.rds_pidx_thres = 32;
373250661Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
374250661Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
375250661Sdavidcs                OID_AUTO, "rds_pidx_thres", CTLFLAG_RW, &ha->hw.rds_pidx_thres,
376250661Sdavidcs		ha->hw.rds_pidx_thres,
377250661Sdavidcs		"Number of Rcv Rings Entries to post before updating"
378250661Sdavidcs		" RDS Ring Producer Index");
379250661Sdavidcs
380284741Sdavidcs        ha->hw.rcv_intr_coalesce = (3 << 16) | 256;
381284741Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
382284741Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
383284741Sdavidcs                OID_AUTO, "rcv_intr_coalesce", CTLFLAG_RW,
384284741Sdavidcs                &ha->hw.rcv_intr_coalesce,
385284741Sdavidcs                ha->hw.rcv_intr_coalesce,
386284741Sdavidcs                "Rcv Intr Coalescing Parameters\n"
387284741Sdavidcs                "\tbits 15:0 max packets\n"
388284741Sdavidcs                "\tbits 31:16 max micro-seconds to wait\n"
389284741Sdavidcs                "\tplease run\n"
390284741Sdavidcs                "\tifconfig <if> down && ifconfig <if> up\n"
391284741Sdavidcs                "\tto take effect \n");
392258155Sdavidcs
393284741Sdavidcs        ha->hw.xmt_intr_coalesce = (64 << 16) | 64;
394284741Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
395284741Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
396284741Sdavidcs                OID_AUTO, "xmt_intr_coalesce", CTLFLAG_RW,
397284741Sdavidcs                &ha->hw.xmt_intr_coalesce,
398284741Sdavidcs                ha->hw.xmt_intr_coalesce,
399284741Sdavidcs                "Xmt Intr Coalescing Parameters\n"
400284741Sdavidcs                "\tbits 15:0 max packets\n"
401284741Sdavidcs                "\tbits 31:16 max micro-seconds to wait\n"
402284741Sdavidcs                "\tplease run\n"
403284741Sdavidcs                "\tifconfig <if> down && ifconfig <if> up\n"
404284741Sdavidcs                "\tto take effect \n");
405284741Sdavidcs
406284741Sdavidcs        SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
407284741Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
408284741Sdavidcs                OID_AUTO, "port_cfg", CTLTYPE_INT | CTLFLAG_RW,
409284741Sdavidcs                (void *)ha, 0,
410284741Sdavidcs                qla_sysctl_port_cfg, "I",
411284741Sdavidcs                        "Set Port Configuration if values below "
412284741Sdavidcs                        "otherwise Get Port Configuration\n"
413284741Sdavidcs                        "\tBits 0-3 ; 1 = DCBX Enable; 0 = DCBX Disable\n"
414284741Sdavidcs                        "\tBits 4-7 : 0 = no pause; 1 = std ; 2 = ppm \n"
415284741Sdavidcs                        "\tBits 8-11: std pause cfg; 0 = xmt and rcv;"
416284741Sdavidcs                        " 1 = xmt only; 2 = rcv only;\n"
417284741Sdavidcs                );
418284741Sdavidcs
419305488Sdavidcs	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
420305488Sdavidcs		SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
421305488Sdavidcs		OID_AUTO, "set_cam_search_mode", CTLTYPE_INT | CTLFLAG_RW,
422305488Sdavidcs		(void *)ha, 0,
423305488Sdavidcs		qla_sysctl_set_cam_search_mode, "I",
424305488Sdavidcs			"Set CAM Search Mode"
425305488Sdavidcs			"\t 1 = search mode internal\n"
426305488Sdavidcs			"\t 2 = search mode auto\n");
427305488Sdavidcs
428305488Sdavidcs	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
429305488Sdavidcs		SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
430305488Sdavidcs		OID_AUTO, "get_cam_search_mode", CTLTYPE_INT | CTLFLAG_RW,
431305488Sdavidcs		(void *)ha, 0,
432305488Sdavidcs		qla_sysctl_get_cam_search_mode, "I",
433305488Sdavidcs			"Get CAM Search Mode"
434305488Sdavidcs			"\t 1 = search mode internal\n"
435305488Sdavidcs			"\t 2 = search mode auto\n");
436305488Sdavidcs
437284741Sdavidcs        ha->hw.enable_9kb = 1;
438284741Sdavidcs
439284741Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
440284741Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
441284741Sdavidcs                OID_AUTO, "enable_9kb", CTLFLAG_RW, &ha->hw.enable_9kb,
442284741Sdavidcs                ha->hw.enable_9kb, "Enable 9Kbyte Buffers when MTU = 9000");
443284741Sdavidcs
444250661Sdavidcs	ha->hw.mdump_active = 0;
445250661Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
446250661Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
447250661Sdavidcs                OID_AUTO, "minidump_active", CTLFLAG_RW, &ha->hw.mdump_active,
448250661Sdavidcs		ha->hw.mdump_active,
449305487Sdavidcs		"Minidump retrieval is Active");
450250661Sdavidcs
451305487Sdavidcs	ha->hw.mdump_done = 0;
452250661Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
453250661Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
454305487Sdavidcs                OID_AUTO, "mdump_done", CTLFLAG_RW,
455305487Sdavidcs		&ha->hw.mdump_done, ha->hw.mdump_done,
456305487Sdavidcs		"Minidump has been done and available for retrieval");
457305487Sdavidcs
458305487Sdavidcs	ha->hw.mdump_capture_mask = 0xF;
459305487Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
460305487Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
461305487Sdavidcs                OID_AUTO, "minidump_capture_mask", CTLFLAG_RW,
462305487Sdavidcs		&ha->hw.mdump_capture_mask, ha->hw.mdump_capture_mask,
463305487Sdavidcs		"Minidump capture mask");
464250661Sdavidcs#ifdef QL_DBG
465250661Sdavidcs
466289635Sdavidcs	ha->err_inject = 0;
467250661Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
468250661Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
469250661Sdavidcs                OID_AUTO, "err_inject",
470250661Sdavidcs                CTLFLAG_RW, &ha->err_inject, ha->err_inject,
471250661Sdavidcs                "Error to be injected\n"
472250661Sdavidcs                "\t\t\t 0: No Errors\n"
473250661Sdavidcs                "\t\t\t 1: rcv: rxb struct invalid\n"
474250661Sdavidcs                "\t\t\t 2: rcv: mp == NULL\n"
475250661Sdavidcs                "\t\t\t 3: lro: rxb struct invalid\n"
476250661Sdavidcs                "\t\t\t 4: lro: mp == NULL\n"
477250661Sdavidcs                "\t\t\t 5: rcv: num handles invalid\n"
478250661Sdavidcs                "\t\t\t 6: reg: indirect reg rd_wr failure\n"
479250661Sdavidcs                "\t\t\t 7: ocm: offchip memory rd_wr failure\n"
480250661Sdavidcs                "\t\t\t 8: mbx: mailbox command failure\n"
481250661Sdavidcs                "\t\t\t 9: heartbeat failure\n"
482305488Sdavidcs                "\t\t\t A: temperature failure\n"
483305488Sdavidcs		"\t\t\t 11: m_getcl or m_getjcl failure\n" );
484250661Sdavidcs
485250661Sdavidcs	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
486250661Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
487250661Sdavidcs                OID_AUTO, "peg_stop", CTLTYPE_INT | CTLFLAG_RW,
488250661Sdavidcs                (void *)ha, 0,
489250661Sdavidcs                qla_sysctl_stop_pegs, "I", "Peg Stop");
490250661Sdavidcs
491250661Sdavidcs#endif /* #ifdef QL_DBG */
492250661Sdavidcs
493284741Sdavidcs        ha->hw.user_pri_nic = 0;
494284741Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
495284741Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
496284741Sdavidcs                OID_AUTO, "user_pri_nic", CTLFLAG_RW, &ha->hw.user_pri_nic,
497284741Sdavidcs                ha->hw.user_pri_nic,
498284741Sdavidcs                "VLAN Tag User Priority for Normal Ethernet Packets");
499284741Sdavidcs
500284741Sdavidcs        ha->hw.user_pri_iscsi = 4;
501284741Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
502284741Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
503284741Sdavidcs                OID_AUTO, "user_pri_iscsi", CTLFLAG_RW, &ha->hw.user_pri_iscsi,
504284741Sdavidcs                ha->hw.user_pri_iscsi,
505284741Sdavidcs                "VLAN Tag User Priority for iSCSI Packets");
506284741Sdavidcs
507250661Sdavidcs}
508250661Sdavidcs
509250661Sdavidcsvoid
510250661Sdavidcsql_hw_link_status(qla_host_t *ha)
511250661Sdavidcs{
512250661Sdavidcs	device_printf(ha->pci_dev, "cable_oui\t\t 0x%08x\n", ha->hw.cable_oui);
513250661Sdavidcs
514250661Sdavidcs	if (ha->hw.link_up) {
515250661Sdavidcs		device_printf(ha->pci_dev, "link Up\n");
516250661Sdavidcs	} else {
517250661Sdavidcs		device_printf(ha->pci_dev, "link Down\n");
518250661Sdavidcs	}
519250661Sdavidcs
520250661Sdavidcs	if (ha->hw.flags.fduplex) {
521250661Sdavidcs		device_printf(ha->pci_dev, "Full Duplex\n");
522250661Sdavidcs	} else {
523250661Sdavidcs		device_printf(ha->pci_dev, "Half Duplex\n");
524250661Sdavidcs	}
525250661Sdavidcs
526250661Sdavidcs	if (ha->hw.flags.autoneg) {
527250661Sdavidcs		device_printf(ha->pci_dev, "Auto Negotiation Enabled\n");
528250661Sdavidcs	} else {
529250661Sdavidcs		device_printf(ha->pci_dev, "Auto Negotiation Disabled\n");
530250661Sdavidcs	}
531250661Sdavidcs
532250661Sdavidcs	switch (ha->hw.link_speed) {
533250661Sdavidcs	case 0x710:
534250661Sdavidcs		device_printf(ha->pci_dev, "link speed\t\t 10Gps\n");
535250661Sdavidcs		break;
536250661Sdavidcs
537250661Sdavidcs	case 0x3E8:
538250661Sdavidcs		device_printf(ha->pci_dev, "link speed\t\t 1Gps\n");
539250661Sdavidcs		break;
540250661Sdavidcs
541250661Sdavidcs	case 0x64:
542250661Sdavidcs		device_printf(ha->pci_dev, "link speed\t\t 100Mbps\n");
543250661Sdavidcs		break;
544250661Sdavidcs
545250661Sdavidcs	default:
546250661Sdavidcs		device_printf(ha->pci_dev, "link speed\t\t Unknown\n");
547250661Sdavidcs		break;
548250661Sdavidcs	}
549250661Sdavidcs
550250661Sdavidcs	switch (ha->hw.module_type) {
551250661Sdavidcs
552250661Sdavidcs	case 0x01:
553250661Sdavidcs		device_printf(ha->pci_dev, "Module Type 10GBase-LRM\n");
554250661Sdavidcs		break;
555250661Sdavidcs
556250661Sdavidcs	case 0x02:
557250661Sdavidcs		device_printf(ha->pci_dev, "Module Type 10GBase-LR\n");
558250661Sdavidcs		break;
559250661Sdavidcs
560250661Sdavidcs	case 0x03:
561250661Sdavidcs		device_printf(ha->pci_dev, "Module Type 10GBase-SR\n");
562250661Sdavidcs		break;
563250661Sdavidcs
564250661Sdavidcs	case 0x04:
565250661Sdavidcs		device_printf(ha->pci_dev,
566250661Sdavidcs			"Module Type 10GE Passive Copper(Compliant)[%d m]\n",
567250661Sdavidcs			ha->hw.cable_length);
568250661Sdavidcs		break;
569250661Sdavidcs
570250661Sdavidcs	case 0x05:
571250661Sdavidcs		device_printf(ha->pci_dev, "Module Type 10GE Active"
572250661Sdavidcs			" Limiting Copper(Compliant)[%d m]\n",
573250661Sdavidcs			ha->hw.cable_length);
574250661Sdavidcs		break;
575250661Sdavidcs
576250661Sdavidcs	case 0x06:
577250661Sdavidcs		device_printf(ha->pci_dev,
578250661Sdavidcs			"Module Type 10GE Passive Copper"
579250661Sdavidcs			" (Legacy, Best Effort)[%d m]\n",
580250661Sdavidcs			ha->hw.cable_length);
581250661Sdavidcs		break;
582250661Sdavidcs
583250661Sdavidcs	case 0x07:
584250661Sdavidcs		device_printf(ha->pci_dev, "Module Type 1000Base-SX\n");
585250661Sdavidcs		break;
586250661Sdavidcs
587250661Sdavidcs	case 0x08:
588250661Sdavidcs		device_printf(ha->pci_dev, "Module Type 1000Base-LX\n");
589250661Sdavidcs		break;
590250661Sdavidcs
591250661Sdavidcs	case 0x09:
592250661Sdavidcs		device_printf(ha->pci_dev, "Module Type 1000Base-CX\n");
593250661Sdavidcs		break;
594250661Sdavidcs
595250661Sdavidcs	case 0x0A:
596250661Sdavidcs		device_printf(ha->pci_dev, "Module Type 1000Base-T\n");
597250661Sdavidcs		break;
598250661Sdavidcs
599250661Sdavidcs	case 0x0B:
600250661Sdavidcs		device_printf(ha->pci_dev, "Module Type 1GE Passive Copper"
601250661Sdavidcs			"(Legacy, Best Effort)\n");
602250661Sdavidcs		break;
603250661Sdavidcs
604250661Sdavidcs	default:
605250661Sdavidcs		device_printf(ha->pci_dev, "Unknown Module Type 0x%x\n",
606250661Sdavidcs			ha->hw.module_type);
607250661Sdavidcs		break;
608250661Sdavidcs	}
609250661Sdavidcs
610250661Sdavidcs	if (ha->hw.link_faults == 1)
611250661Sdavidcs		device_printf(ha->pci_dev, "SFP Power Fault\n");
612250661Sdavidcs}
613250661Sdavidcs
614250661Sdavidcs/*
615250661Sdavidcs * Name: ql_free_dma
616250661Sdavidcs * Function: Frees the DMA'able memory allocated in ql_alloc_dma()
617250661Sdavidcs */
618250661Sdavidcsvoid
619250661Sdavidcsql_free_dma(qla_host_t *ha)
620250661Sdavidcs{
621250661Sdavidcs	uint32_t i;
622250661Sdavidcs
623250661Sdavidcs        if (ha->hw.dma_buf.flags.sds_ring) {
624250661Sdavidcs		for (i = 0; i < ha->hw.num_sds_rings; i++) {
625250661Sdavidcs			ql_free_dmabuf(ha, &ha->hw.dma_buf.sds_ring[i]);
626250661Sdavidcs		}
627250661Sdavidcs        	ha->hw.dma_buf.flags.sds_ring = 0;
628250661Sdavidcs	}
629250661Sdavidcs
630250661Sdavidcs        if (ha->hw.dma_buf.flags.rds_ring) {
631250661Sdavidcs		for (i = 0; i < ha->hw.num_rds_rings; i++) {
632250661Sdavidcs			ql_free_dmabuf(ha, &ha->hw.dma_buf.rds_ring[i]);
633250661Sdavidcs		}
634250661Sdavidcs        	ha->hw.dma_buf.flags.rds_ring = 0;
635250661Sdavidcs	}
636250661Sdavidcs
637250661Sdavidcs        if (ha->hw.dma_buf.flags.tx_ring) {
638250661Sdavidcs		ql_free_dmabuf(ha, &ha->hw.dma_buf.tx_ring);
639250661Sdavidcs        	ha->hw.dma_buf.flags.tx_ring = 0;
640250661Sdavidcs	}
641305487Sdavidcs	ql_minidump_free(ha);
642250661Sdavidcs}
643250661Sdavidcs
644250661Sdavidcs/*
645250661Sdavidcs * Name: ql_alloc_dma
646250661Sdavidcs * Function: Allocates DMA'able memory for Tx/Rx Rings, Tx/Rx Contexts.
647250661Sdavidcs */
648250661Sdavidcsint
649250661Sdavidcsql_alloc_dma(qla_host_t *ha)
650250661Sdavidcs{
651250661Sdavidcs        device_t                dev;
652250661Sdavidcs	uint32_t		i, j, size, tx_ring_size;
653250661Sdavidcs	qla_hw_t		*hw;
654250661Sdavidcs	qla_hw_tx_cntxt_t	*tx_cntxt;
655250661Sdavidcs	uint8_t			*vaddr;
656250661Sdavidcs	bus_addr_t		paddr;
657250661Sdavidcs
658250661Sdavidcs        dev = ha->pci_dev;
659250661Sdavidcs
660250661Sdavidcs        QL_DPRINT2(ha, (dev, "%s: enter\n", __func__));
661250661Sdavidcs
662250661Sdavidcs	hw = &ha->hw;
663250661Sdavidcs	/*
664250661Sdavidcs	 * Allocate Transmit Ring
665250661Sdavidcs	 */
666250661Sdavidcs	tx_ring_size = (sizeof(q80_tx_cmd_t) * NUM_TX_DESCRIPTORS);
667250661Sdavidcs	size = (tx_ring_size * ha->hw.num_tx_rings);
668250661Sdavidcs
669250661Sdavidcs	hw->dma_buf.tx_ring.alignment = 8;
670250661Sdavidcs	hw->dma_buf.tx_ring.size = size + PAGE_SIZE;
671250661Sdavidcs
672250661Sdavidcs        if (ql_alloc_dmabuf(ha, &hw->dma_buf.tx_ring)) {
673250661Sdavidcs                device_printf(dev, "%s: tx ring alloc failed\n", __func__);
674250661Sdavidcs                goto ql_alloc_dma_exit;
675250661Sdavidcs        }
676250661Sdavidcs
677250661Sdavidcs	vaddr = (uint8_t *)hw->dma_buf.tx_ring.dma_b;
678250661Sdavidcs	paddr = hw->dma_buf.tx_ring.dma_addr;
679250661Sdavidcs
680250661Sdavidcs	for (i = 0; i < ha->hw.num_tx_rings; i++) {
681250661Sdavidcs		tx_cntxt = (qla_hw_tx_cntxt_t *)&hw->tx_cntxt[i];
682250661Sdavidcs
683250661Sdavidcs		tx_cntxt->tx_ring_base = (q80_tx_cmd_t *)vaddr;
684250661Sdavidcs		tx_cntxt->tx_ring_paddr = paddr;
685250661Sdavidcs
686250661Sdavidcs		vaddr += tx_ring_size;
687250661Sdavidcs		paddr += tx_ring_size;
688250661Sdavidcs	}
689250661Sdavidcs
690250661Sdavidcs	for (i = 0; i < ha->hw.num_tx_rings; i++) {
691250661Sdavidcs		tx_cntxt = (qla_hw_tx_cntxt_t *)&hw->tx_cntxt[i];
692250661Sdavidcs
693250661Sdavidcs		tx_cntxt->tx_cons = (uint32_t *)vaddr;
694250661Sdavidcs		tx_cntxt->tx_cons_paddr = paddr;
695250661Sdavidcs
696250661Sdavidcs		vaddr += sizeof (uint32_t);
697250661Sdavidcs		paddr += sizeof (uint32_t);
698250661Sdavidcs	}
699250661Sdavidcs
700250661Sdavidcs        ha->hw.dma_buf.flags.tx_ring = 1;
701250661Sdavidcs
702250661Sdavidcs	QL_DPRINT2(ha, (dev, "%s: tx_ring phys %p virt %p\n",
703250661Sdavidcs		__func__, (void *)(hw->dma_buf.tx_ring.dma_addr),
704250661Sdavidcs		hw->dma_buf.tx_ring.dma_b));
705250661Sdavidcs	/*
706250661Sdavidcs	 * Allocate Receive Descriptor Rings
707250661Sdavidcs	 */
708250661Sdavidcs
709250661Sdavidcs	for (i = 0; i < hw->num_rds_rings; i++) {
710250661Sdavidcs
711250661Sdavidcs		hw->dma_buf.rds_ring[i].alignment = 8;
712250661Sdavidcs		hw->dma_buf.rds_ring[i].size =
713250661Sdavidcs			(sizeof(q80_recv_desc_t)) * NUM_RX_DESCRIPTORS;
714250661Sdavidcs
715250661Sdavidcs		if (ql_alloc_dmabuf(ha, &hw->dma_buf.rds_ring[i])) {
716250661Sdavidcs			device_printf(dev, "%s: rds ring[%d] alloc failed\n",
717250661Sdavidcs				__func__, i);
718250661Sdavidcs
719250661Sdavidcs			for (j = 0; j < i; j++)
720250661Sdavidcs				ql_free_dmabuf(ha, &hw->dma_buf.rds_ring[j]);
721250661Sdavidcs
722250661Sdavidcs			goto ql_alloc_dma_exit;
723250661Sdavidcs		}
724250661Sdavidcs		QL_DPRINT4(ha, (dev, "%s: rx_ring[%d] phys %p virt %p\n",
725250661Sdavidcs			__func__, i, (void *)(hw->dma_buf.rds_ring[i].dma_addr),
726250661Sdavidcs			hw->dma_buf.rds_ring[i].dma_b));
727250661Sdavidcs	}
728250661Sdavidcs
729250661Sdavidcs	hw->dma_buf.flags.rds_ring = 1;
730250661Sdavidcs
731250661Sdavidcs	/*
732250661Sdavidcs	 * Allocate Status Descriptor Rings
733250661Sdavidcs	 */
734250661Sdavidcs
735250661Sdavidcs	for (i = 0; i < hw->num_sds_rings; i++) {
736250661Sdavidcs		hw->dma_buf.sds_ring[i].alignment = 8;
737250661Sdavidcs		hw->dma_buf.sds_ring[i].size =
738250661Sdavidcs			(sizeof(q80_stat_desc_t)) * NUM_STATUS_DESCRIPTORS;
739250661Sdavidcs
740250661Sdavidcs		if (ql_alloc_dmabuf(ha, &hw->dma_buf.sds_ring[i])) {
741250661Sdavidcs			device_printf(dev, "%s: sds ring alloc failed\n",
742250661Sdavidcs				__func__);
743250661Sdavidcs
744250661Sdavidcs			for (j = 0; j < i; j++)
745250661Sdavidcs				ql_free_dmabuf(ha, &hw->dma_buf.sds_ring[j]);
746250661Sdavidcs
747250661Sdavidcs			goto ql_alloc_dma_exit;
748250661Sdavidcs		}
749250661Sdavidcs		QL_DPRINT4(ha, (dev, "%s: sds_ring[%d] phys %p virt %p\n",
750250661Sdavidcs			__func__, i,
751250661Sdavidcs			(void *)(hw->dma_buf.sds_ring[i].dma_addr),
752250661Sdavidcs			hw->dma_buf.sds_ring[i].dma_b));
753250661Sdavidcs	}
754250661Sdavidcs	for (i = 0; i < hw->num_sds_rings; i++) {
755250661Sdavidcs		hw->sds[i].sds_ring_base =
756250661Sdavidcs			(q80_stat_desc_t *)hw->dma_buf.sds_ring[i].dma_b;
757250661Sdavidcs	}
758250661Sdavidcs
759250661Sdavidcs	hw->dma_buf.flags.sds_ring = 1;
760250661Sdavidcs
761250661Sdavidcs	return 0;
762250661Sdavidcs
763250661Sdavidcsql_alloc_dma_exit:
764250661Sdavidcs	ql_free_dma(ha);
765250661Sdavidcs	return -1;
766250661Sdavidcs}
767250661Sdavidcs
768250661Sdavidcs#define Q8_MBX_MSEC_DELAY	5000
769250661Sdavidcs
770250661Sdavidcsstatic int
771250661Sdavidcsqla_mbx_cmd(qla_host_t *ha, uint32_t *h_mbox, uint32_t n_hmbox,
772250661Sdavidcs	uint32_t *fw_mbox, uint32_t n_fwmbox, uint32_t no_pause)
773250661Sdavidcs{
774250661Sdavidcs	uint32_t i;
775250661Sdavidcs	uint32_t data;
776250661Sdavidcs	int ret = 0;
777250661Sdavidcs
778250661Sdavidcs	if (QL_ERR_INJECT(ha, INJCT_MBX_CMD_FAILURE)) {
779250661Sdavidcs		ret = -3;
780250661Sdavidcs		ha->qla_initiate_recovery = 1;
781250661Sdavidcs		goto exit_qla_mbx_cmd;
782250661Sdavidcs	}
783250661Sdavidcs
784250661Sdavidcs	if (no_pause)
785250661Sdavidcs		i = 1000;
786250661Sdavidcs	else
787250661Sdavidcs		i = Q8_MBX_MSEC_DELAY;
788250661Sdavidcs
789250661Sdavidcs	while (i) {
790250661Sdavidcs		data = READ_REG32(ha, Q8_HOST_MBOX_CNTRL);
791250661Sdavidcs		if (data == 0)
792250661Sdavidcs			break;
793250661Sdavidcs		if (no_pause) {
794250661Sdavidcs			DELAY(1000);
795250661Sdavidcs		} else {
796250661Sdavidcs			qla_mdelay(__func__, 1);
797250661Sdavidcs		}
798250661Sdavidcs		i--;
799250661Sdavidcs	}
800250661Sdavidcs
801250661Sdavidcs	if (i == 0) {
802250661Sdavidcs		device_printf(ha->pci_dev, "%s: host_mbx_cntrl 0x%08x\n",
803250661Sdavidcs			__func__, data);
804250661Sdavidcs		ret = -1;
805250661Sdavidcs		ha->qla_initiate_recovery = 1;
806250661Sdavidcs		goto exit_qla_mbx_cmd;
807250661Sdavidcs	}
808250661Sdavidcs
809250661Sdavidcs	for (i = 0; i < n_hmbox; i++) {
810250661Sdavidcs		WRITE_REG32(ha, (Q8_HOST_MBOX0 + (i << 2)), *h_mbox);
811250661Sdavidcs		h_mbox++;
812250661Sdavidcs	}
813250661Sdavidcs
814250661Sdavidcs	WRITE_REG32(ha, Q8_HOST_MBOX_CNTRL, 0x1);
815250661Sdavidcs
816250661Sdavidcs
817250661Sdavidcs	i = Q8_MBX_MSEC_DELAY;
818250661Sdavidcs	while (i) {
819250661Sdavidcs		data = READ_REG32(ha, Q8_FW_MBOX_CNTRL);
820250661Sdavidcs
821250661Sdavidcs		if ((data & 0x3) == 1) {
822250661Sdavidcs			data = READ_REG32(ha, Q8_FW_MBOX0);
823250661Sdavidcs			if ((data & 0xF000) != 0x8000)
824250661Sdavidcs				break;
825250661Sdavidcs		}
826250661Sdavidcs		if (no_pause) {
827250661Sdavidcs			DELAY(1000);
828250661Sdavidcs		} else {
829250661Sdavidcs			qla_mdelay(__func__, 1);
830250661Sdavidcs		}
831250661Sdavidcs		i--;
832250661Sdavidcs	}
833250661Sdavidcs	if (i == 0) {
834250661Sdavidcs		device_printf(ha->pci_dev, "%s: fw_mbx_cntrl 0x%08x\n",
835250661Sdavidcs			__func__, data);
836250661Sdavidcs		ret = -2;
837250661Sdavidcs		ha->qla_initiate_recovery = 1;
838250661Sdavidcs		goto exit_qla_mbx_cmd;
839250661Sdavidcs	}
840250661Sdavidcs
841250661Sdavidcs	for (i = 0; i < n_fwmbox; i++) {
842250661Sdavidcs		*fw_mbox++ = READ_REG32(ha, (Q8_FW_MBOX0 + (i << 2)));
843250661Sdavidcs	}
844250661Sdavidcs
845250661Sdavidcs	WRITE_REG32(ha, Q8_FW_MBOX_CNTRL, 0x0);
846250661Sdavidcs	WRITE_REG32(ha, ha->hw.mbx_intr_mask_offset, 0x0);
847250661Sdavidcs
848250661Sdavidcsexit_qla_mbx_cmd:
849250661Sdavidcs	return (ret);
850250661Sdavidcs}
851250661Sdavidcs
852284741Sdavidcsint
853284741Sdavidcsqla_get_nic_partition(qla_host_t *ha, uint32_t *supports_9kb,
854284741Sdavidcs	uint32_t *num_rcvq)
855250661Sdavidcs{
856250661Sdavidcs	uint32_t *mbox, err;
857250661Sdavidcs	device_t dev = ha->pci_dev;
858250661Sdavidcs
859250661Sdavidcs	bzero(ha->hw.mbox, (sizeof (uint32_t) * Q8_NUM_MBOX));
860250661Sdavidcs
861250661Sdavidcs	mbox = ha->hw.mbox;
862250661Sdavidcs
863250661Sdavidcs	mbox[0] = Q8_MBX_GET_NIC_PARTITION | (0x2 << 16) | (0x2 << 29);
864250661Sdavidcs
865250661Sdavidcs	if (qla_mbx_cmd(ha, mbox, 2, mbox, 19, 0)) {
866250661Sdavidcs		device_printf(dev, "%s: failed0\n", __func__);
867250661Sdavidcs		return (-1);
868250661Sdavidcs	}
869250661Sdavidcs	err = mbox[0] >> 25;
870250661Sdavidcs
871284741Sdavidcs	if (supports_9kb != NULL) {
872284741Sdavidcs		if (mbox[16] & 0x80) /* bit 7 of mbox 16 */
873284741Sdavidcs			*supports_9kb = 1;
874284741Sdavidcs		else
875284741Sdavidcs			*supports_9kb = 0;
876284741Sdavidcs	}
877284741Sdavidcs
878284741Sdavidcs	if (num_rcvq != NULL)
879284741Sdavidcs		*num_rcvq =  ((mbox[6] >> 16) & 0xFFFF);
880284741Sdavidcs
881250661Sdavidcs	if ((err != 1) && (err != 0)) {
882250661Sdavidcs		device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err);
883250661Sdavidcs		return (-1);
884250661Sdavidcs	}
885250661Sdavidcs	return 0;
886250661Sdavidcs}
887250661Sdavidcs
888250661Sdavidcsstatic int
889284741Sdavidcsqla_config_intr_cntxt(qla_host_t *ha, uint32_t start_idx, uint32_t num_intrs,
890284741Sdavidcs	uint32_t create)
891250661Sdavidcs{
892250661Sdavidcs	uint32_t i, err;
893250661Sdavidcs	device_t dev = ha->pci_dev;
894250661Sdavidcs	q80_config_intr_t *c_intr;
895250661Sdavidcs	q80_config_intr_rsp_t *c_intr_rsp;
896250661Sdavidcs
897250661Sdavidcs	c_intr = (q80_config_intr_t *)ha->hw.mbox;
898250661Sdavidcs	bzero(c_intr, (sizeof (q80_config_intr_t)));
899250661Sdavidcs
900250661Sdavidcs	c_intr->opcode = Q8_MBX_CONFIG_INTR;
901250661Sdavidcs
902250661Sdavidcs	c_intr->count_version = (sizeof (q80_config_intr_t) >> 2);
903250661Sdavidcs	c_intr->count_version |= Q8_MBX_CMD_VERSION;
904250661Sdavidcs
905250661Sdavidcs	c_intr->nentries = num_intrs;
906250661Sdavidcs
907250661Sdavidcs	for (i = 0; i < num_intrs; i++) {
908250661Sdavidcs		if (create) {
909250661Sdavidcs			c_intr->intr[i].cmd_type = Q8_MBX_CONFIG_INTR_CREATE;
910284741Sdavidcs			c_intr->intr[i].msix_index = start_idx + 1 + i;
911250661Sdavidcs		} else {
912250661Sdavidcs			c_intr->intr[i].cmd_type = Q8_MBX_CONFIG_INTR_DELETE;
913284741Sdavidcs			c_intr->intr[i].msix_index =
914284741Sdavidcs				ha->hw.intr_id[(start_idx + i)];
915250661Sdavidcs		}
916250661Sdavidcs
917250661Sdavidcs		c_intr->intr[i].cmd_type |= Q8_MBX_CONFIG_INTR_TYPE_MSI_X;
918250661Sdavidcs	}
919250661Sdavidcs
920250661Sdavidcs	if (qla_mbx_cmd(ha, (uint32_t *)c_intr,
921250661Sdavidcs		(sizeof (q80_config_intr_t) >> 2),
922250661Sdavidcs		ha->hw.mbox, (sizeof (q80_config_intr_rsp_t) >> 2), 0)) {
923250661Sdavidcs		device_printf(dev, "%s: failed0\n", __func__);
924250661Sdavidcs		return (-1);
925250661Sdavidcs	}
926250661Sdavidcs
927250661Sdavidcs	c_intr_rsp = (q80_config_intr_rsp_t *)ha->hw.mbox;
928250661Sdavidcs
929250661Sdavidcs	err = Q8_MBX_RSP_STATUS(c_intr_rsp->regcnt_status);
930250661Sdavidcs
931250661Sdavidcs	if (err) {
932250661Sdavidcs		device_printf(dev, "%s: failed1 [0x%08x, %d]\n", __func__, err,
933250661Sdavidcs			c_intr_rsp->nentries);
934250661Sdavidcs
935250661Sdavidcs		for (i = 0; i < c_intr_rsp->nentries; i++) {
936250661Sdavidcs			device_printf(dev, "%s: [%d]:[0x%x 0x%x 0x%x]\n",
937250661Sdavidcs				__func__, i,
938250661Sdavidcs				c_intr_rsp->intr[i].status,
939250661Sdavidcs				c_intr_rsp->intr[i].intr_id,
940250661Sdavidcs				c_intr_rsp->intr[i].intr_src);
941250661Sdavidcs		}
942250661Sdavidcs
943250661Sdavidcs		return (-1);
944250661Sdavidcs	}
945250661Sdavidcs
946250661Sdavidcs	for (i = 0; ((i < num_intrs) && create); i++) {
947250661Sdavidcs		if (!c_intr_rsp->intr[i].status) {
948284741Sdavidcs			ha->hw.intr_id[(start_idx + i)] =
949284741Sdavidcs				c_intr_rsp->intr[i].intr_id;
950284741Sdavidcs			ha->hw.intr_src[(start_idx + i)] =
951284741Sdavidcs				c_intr_rsp->intr[i].intr_src;
952250661Sdavidcs		}
953250661Sdavidcs	}
954250661Sdavidcs
955250661Sdavidcs	return (0);
956250661Sdavidcs}
957250661Sdavidcs
958250661Sdavidcs/*
959250661Sdavidcs * Name: qla_config_rss
960250661Sdavidcs * Function: Configure RSS for the context/interface.
961250661Sdavidcs */
962250661Sdavidcsstatic const uint64_t rss_key[] = { 0xbeac01fa6a42b73bULL,
963250661Sdavidcs			0x8030f20c77cb2da3ULL,
964250661Sdavidcs			0xae7b30b4d0ca2bcbULL, 0x43a38fb04167253dULL,
965250661Sdavidcs			0x255b0ec26d5a56daULL };
966250661Sdavidcs
967250661Sdavidcsstatic int
968250661Sdavidcsqla_config_rss(qla_host_t *ha, uint16_t cntxt_id)
969250661Sdavidcs{
970250661Sdavidcs	q80_config_rss_t	*c_rss;
971250661Sdavidcs	q80_config_rss_rsp_t	*c_rss_rsp;
972250661Sdavidcs	uint32_t		err, i;
973250661Sdavidcs	device_t		dev = ha->pci_dev;
974250661Sdavidcs
975250661Sdavidcs	c_rss = (q80_config_rss_t *)ha->hw.mbox;
976250661Sdavidcs	bzero(c_rss, (sizeof (q80_config_rss_t)));
977250661Sdavidcs
978250661Sdavidcs	c_rss->opcode = Q8_MBX_CONFIG_RSS;
979250661Sdavidcs
980250661Sdavidcs	c_rss->count_version = (sizeof (q80_config_rss_t) >> 2);
981250661Sdavidcs	c_rss->count_version |= Q8_MBX_CMD_VERSION;
982250661Sdavidcs
983250661Sdavidcs	c_rss->hash_type = (Q8_MBX_RSS_HASH_TYPE_IPV4_TCP_IP |
984250661Sdavidcs				Q8_MBX_RSS_HASH_TYPE_IPV6_TCP_IP);
985284741Sdavidcs	//c_rss->hash_type = (Q8_MBX_RSS_HASH_TYPE_IPV4_TCP |
986284741Sdavidcs	//			Q8_MBX_RSS_HASH_TYPE_IPV6_TCP);
987250661Sdavidcs
988250661Sdavidcs	c_rss->flags = Q8_MBX_RSS_FLAGS_ENABLE_RSS;
989250661Sdavidcs	c_rss->flags |= Q8_MBX_RSS_FLAGS_USE_IND_TABLE;
990250661Sdavidcs
991250661Sdavidcs	c_rss->indtbl_mask = Q8_MBX_RSS_INDTBL_MASK;
992250661Sdavidcs
993250661Sdavidcs	c_rss->indtbl_mask |= Q8_MBX_RSS_FLAGS_MULTI_RSS_VALID;
994250661Sdavidcs	c_rss->flags |= Q8_MBX_RSS_FLAGS_TYPE_CRSS;
995250661Sdavidcs
996250661Sdavidcs	c_rss->cntxt_id = cntxt_id;
997250661Sdavidcs
998250661Sdavidcs	for (i = 0; i < 5; i++) {
999250661Sdavidcs		c_rss->rss_key[i] = rss_key[i];
1000250661Sdavidcs	}
1001250661Sdavidcs
1002250661Sdavidcs	if (qla_mbx_cmd(ha, (uint32_t *)c_rss,
1003250661Sdavidcs		(sizeof (q80_config_rss_t) >> 2),
1004250661Sdavidcs		ha->hw.mbox, (sizeof(q80_config_rss_rsp_t) >> 2), 0)) {
1005250661Sdavidcs		device_printf(dev, "%s: failed0\n", __func__);
1006250661Sdavidcs		return (-1);
1007250661Sdavidcs	}
1008250661Sdavidcs	c_rss_rsp = (q80_config_rss_rsp_t *)ha->hw.mbox;
1009250661Sdavidcs
1010250661Sdavidcs	err = Q8_MBX_RSP_STATUS(c_rss_rsp->regcnt_status);
1011250661Sdavidcs
1012250661Sdavidcs	if (err) {
1013250661Sdavidcs		device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err);
1014250661Sdavidcs		return (-1);
1015250661Sdavidcs	}
1016250661Sdavidcs	return 0;
1017250661Sdavidcs}
1018250661Sdavidcs
1019250661Sdavidcsstatic int
1020250661Sdavidcsqla_set_rss_ind_table(qla_host_t *ha, uint32_t start_idx, uint32_t count,
1021250661Sdavidcs        uint16_t cntxt_id, uint8_t *ind_table)
1022250661Sdavidcs{
1023250661Sdavidcs        q80_config_rss_ind_table_t      *c_rss_ind;
1024250661Sdavidcs        q80_config_rss_ind_table_rsp_t  *c_rss_ind_rsp;
1025250661Sdavidcs        uint32_t                        err;
1026250661Sdavidcs        device_t                        dev = ha->pci_dev;
1027250661Sdavidcs
1028250661Sdavidcs	if ((count > Q8_RSS_IND_TBL_SIZE) ||
1029250661Sdavidcs		((start_idx + count - 1) > Q8_RSS_IND_TBL_MAX_IDX)) {
1030250661Sdavidcs		device_printf(dev, "%s: illegal count [%d, %d]\n", __func__,
1031250661Sdavidcs			start_idx, count);
1032250661Sdavidcs		return (-1);
1033250661Sdavidcs	}
1034250661Sdavidcs
1035250661Sdavidcs        c_rss_ind = (q80_config_rss_ind_table_t *)ha->hw.mbox;
1036250661Sdavidcs        bzero(c_rss_ind, sizeof (q80_config_rss_ind_table_t));
1037250661Sdavidcs
1038250661Sdavidcs        c_rss_ind->opcode = Q8_MBX_CONFIG_RSS_TABLE;
1039250661Sdavidcs        c_rss_ind->count_version = (sizeof (q80_config_rss_ind_table_t) >> 2);
1040250661Sdavidcs        c_rss_ind->count_version |= Q8_MBX_CMD_VERSION;
1041250661Sdavidcs
1042250661Sdavidcs	c_rss_ind->start_idx = start_idx;
1043250661Sdavidcs	c_rss_ind->end_idx = start_idx + count - 1;
1044250661Sdavidcs	c_rss_ind->cntxt_id = cntxt_id;
1045250661Sdavidcs	bcopy(ind_table, c_rss_ind->ind_table, count);
1046250661Sdavidcs
1047250661Sdavidcs	if (qla_mbx_cmd(ha, (uint32_t *)c_rss_ind,
1048250661Sdavidcs		(sizeof (q80_config_rss_ind_table_t) >> 2), ha->hw.mbox,
1049250661Sdavidcs		(sizeof(q80_config_rss_ind_table_rsp_t) >> 2), 0)) {
1050250661Sdavidcs		device_printf(dev, "%s: failed0\n", __func__);
1051250661Sdavidcs		return (-1);
1052250661Sdavidcs	}
1053250661Sdavidcs
1054250661Sdavidcs	c_rss_ind_rsp = (q80_config_rss_ind_table_rsp_t *)ha->hw.mbox;
1055250661Sdavidcs	err = Q8_MBX_RSP_STATUS(c_rss_ind_rsp->regcnt_status);
1056250661Sdavidcs
1057250661Sdavidcs	if (err) {
1058250661Sdavidcs		device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err);
1059250661Sdavidcs		return (-1);
1060250661Sdavidcs	}
1061250661Sdavidcs	return 0;
1062250661Sdavidcs}
1063250661Sdavidcs
1064250661Sdavidcs/*
1065250661Sdavidcs * Name: qla_config_intr_coalesce
1066250661Sdavidcs * Function: Configure Interrupt Coalescing.
1067250661Sdavidcs */
1068250661Sdavidcsstatic int
1069284741Sdavidcsqla_config_intr_coalesce(qla_host_t *ha, uint16_t cntxt_id, int tenable,
1070284741Sdavidcs	int rcv)
1071250661Sdavidcs{
1072250661Sdavidcs	q80_config_intr_coalesc_t	*intrc;
1073250661Sdavidcs	q80_config_intr_coalesc_rsp_t	*intrc_rsp;
1074250661Sdavidcs	uint32_t			err, i;
1075250661Sdavidcs	device_t			dev = ha->pci_dev;
1076250661Sdavidcs
1077250661Sdavidcs	intrc = (q80_config_intr_coalesc_t *)ha->hw.mbox;
1078250661Sdavidcs	bzero(intrc, (sizeof (q80_config_intr_coalesc_t)));
1079250661Sdavidcs
1080250661Sdavidcs	intrc->opcode = Q8_MBX_CONFIG_INTR_COALESCE;
1081250661Sdavidcs	intrc->count_version = (sizeof (q80_config_intr_coalesc_t) >> 2);
1082250661Sdavidcs	intrc->count_version |= Q8_MBX_CMD_VERSION;
1083250661Sdavidcs
1084284741Sdavidcs	if (rcv) {
1085284741Sdavidcs		intrc->flags = Q8_MBX_INTRC_FLAGS_RCV;
1086284741Sdavidcs		intrc->max_pkts = ha->hw.rcv_intr_coalesce & 0xFFFF;
1087284741Sdavidcs		intrc->max_mswait = (ha->hw.rcv_intr_coalesce >> 16) & 0xFFFF;
1088284741Sdavidcs	} else {
1089284741Sdavidcs		intrc->flags = Q8_MBX_INTRC_FLAGS_XMT;
1090284741Sdavidcs		intrc->max_pkts = ha->hw.xmt_intr_coalesce & 0xFFFF;
1091284741Sdavidcs		intrc->max_mswait = (ha->hw.xmt_intr_coalesce >> 16) & 0xFFFF;
1092284741Sdavidcs	}
1093284741Sdavidcs
1094250661Sdavidcs	intrc->cntxt_id = cntxt_id;
1095250661Sdavidcs
1096250661Sdavidcs	if (tenable) {
1097250661Sdavidcs		intrc->flags |= Q8_MBX_INTRC_FLAGS_PERIODIC;
1098250661Sdavidcs		intrc->timer_type = Q8_MBX_INTRC_TIMER_PERIODIC;
1099250661Sdavidcs
1100250661Sdavidcs		for (i = 0; i < ha->hw.num_sds_rings; i++) {
1101250661Sdavidcs			intrc->sds_ring_mask |= (1 << i);
1102250661Sdavidcs		}
1103250661Sdavidcs		intrc->ms_timeout = 1000;
1104250661Sdavidcs	}
1105250661Sdavidcs
1106250661Sdavidcs	if (qla_mbx_cmd(ha, (uint32_t *)intrc,
1107250661Sdavidcs		(sizeof (q80_config_intr_coalesc_t) >> 2),
1108250661Sdavidcs		ha->hw.mbox, (sizeof(q80_config_intr_coalesc_rsp_t) >> 2), 0)) {
1109250661Sdavidcs		device_printf(dev, "%s: failed0\n", __func__);
1110250661Sdavidcs		return (-1);
1111250661Sdavidcs	}
1112250661Sdavidcs	intrc_rsp = (q80_config_intr_coalesc_rsp_t *)ha->hw.mbox;
1113250661Sdavidcs
1114250661Sdavidcs	err = Q8_MBX_RSP_STATUS(intrc_rsp->regcnt_status);
1115250661Sdavidcs
1116250661Sdavidcs	if (err) {
1117250661Sdavidcs		device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err);
1118250661Sdavidcs		return (-1);
1119250661Sdavidcs	}
1120250661Sdavidcs
1121250661Sdavidcs	return 0;
1122250661Sdavidcs}
1123250661Sdavidcs
1124250661Sdavidcs
1125250661Sdavidcs/*
1126250661Sdavidcs * Name: qla_config_mac_addr
1127250661Sdavidcs * Function: binds a MAC address to the context/interface.
1128250661Sdavidcs *	Can be unicast, multicast or broadcast.
1129250661Sdavidcs */
1130250661Sdavidcsstatic int
1131250661Sdavidcsqla_config_mac_addr(qla_host_t *ha, uint8_t *mac_addr, uint32_t add_mac)
1132250661Sdavidcs{
1133250661Sdavidcs	q80_config_mac_addr_t		*cmac;
1134250661Sdavidcs	q80_config_mac_addr_rsp_t	*cmac_rsp;
1135250661Sdavidcs	uint32_t			err;
1136250661Sdavidcs	device_t			dev = ha->pci_dev;
1137250661Sdavidcs
1138250661Sdavidcs	cmac = (q80_config_mac_addr_t *)ha->hw.mbox;
1139250661Sdavidcs	bzero(cmac, (sizeof (q80_config_mac_addr_t)));
1140250661Sdavidcs
1141250661Sdavidcs	cmac->opcode = Q8_MBX_CONFIG_MAC_ADDR;
1142250661Sdavidcs	cmac->count_version = sizeof (q80_config_mac_addr_t) >> 2;
1143250661Sdavidcs	cmac->count_version |= Q8_MBX_CMD_VERSION;
1144250661Sdavidcs
1145250661Sdavidcs	if (add_mac)
1146250661Sdavidcs		cmac->cmd = Q8_MBX_CMAC_CMD_ADD_MAC_ADDR;
1147250661Sdavidcs	else
1148250661Sdavidcs		cmac->cmd = Q8_MBX_CMAC_CMD_DEL_MAC_ADDR;
1149250661Sdavidcs
1150250661Sdavidcs	cmac->cmd |= Q8_MBX_CMAC_CMD_CAM_INGRESS;
1151250661Sdavidcs
1152250661Sdavidcs	cmac->nmac_entries = 1;
1153250661Sdavidcs	cmac->cntxt_id = ha->hw.rcv_cntxt_id;
1154250661Sdavidcs	bcopy(mac_addr, cmac->mac_addr[0].addr, 6);
1155250661Sdavidcs
1156250661Sdavidcs	if (qla_mbx_cmd(ha, (uint32_t *)cmac,
1157250661Sdavidcs		(sizeof (q80_config_mac_addr_t) >> 2),
1158250661Sdavidcs		ha->hw.mbox, (sizeof(q80_config_mac_addr_rsp_t) >> 2), 1)) {
1159250661Sdavidcs		device_printf(dev, "%s: %s failed0\n", __func__,
1160250661Sdavidcs			(add_mac ? "Add" : "Del"));
1161250661Sdavidcs		return (-1);
1162250661Sdavidcs	}
1163250661Sdavidcs	cmac_rsp = (q80_config_mac_addr_rsp_t *)ha->hw.mbox;
1164250661Sdavidcs
1165250661Sdavidcs	err = Q8_MBX_RSP_STATUS(cmac_rsp->regcnt_status);
1166250661Sdavidcs
1167250661Sdavidcs	if (err) {
1168250661Sdavidcs		device_printf(dev, "%s: %s "
1169250661Sdavidcs			"%02x:%02x:%02x:%02x:%02x:%02x failed1 [0x%08x]\n",
1170250661Sdavidcs			__func__, (add_mac ? "Add" : "Del"),
1171250661Sdavidcs			mac_addr[0], mac_addr[1], mac_addr[2],
1172250661Sdavidcs			mac_addr[3], mac_addr[4], mac_addr[5], err);
1173250661Sdavidcs		return (-1);
1174250661Sdavidcs	}
1175250661Sdavidcs
1176250661Sdavidcs	return 0;
1177250661Sdavidcs}
1178250661Sdavidcs
1179250661Sdavidcs
1180250661Sdavidcs/*
1181250661Sdavidcs * Name: qla_set_mac_rcv_mode
1182305487Sdavidcs * Function: Enable/Disable AllMulticast and Promiscous Modes.
1183250661Sdavidcs */
1184250661Sdavidcsstatic int
1185250661Sdavidcsqla_set_mac_rcv_mode(qla_host_t *ha, uint32_t mode)
1186250661Sdavidcs{
1187250661Sdavidcs	q80_config_mac_rcv_mode_t	*rcv_mode;
1188250661Sdavidcs	uint32_t			err;
1189250661Sdavidcs	q80_config_mac_rcv_mode_rsp_t	*rcv_mode_rsp;
1190250661Sdavidcs	device_t			dev = ha->pci_dev;
1191250661Sdavidcs
1192250661Sdavidcs	rcv_mode = (q80_config_mac_rcv_mode_t *)ha->hw.mbox;
1193250661Sdavidcs	bzero(rcv_mode, (sizeof (q80_config_mac_rcv_mode_t)));
1194250661Sdavidcs
1195250661Sdavidcs	rcv_mode->opcode = Q8_MBX_CONFIG_MAC_RX_MODE;
1196250661Sdavidcs	rcv_mode->count_version = sizeof (q80_config_mac_rcv_mode_t) >> 2;
1197250661Sdavidcs	rcv_mode->count_version |= Q8_MBX_CMD_VERSION;
1198250661Sdavidcs
1199250661Sdavidcs	rcv_mode->mode = mode;
1200250661Sdavidcs
1201250661Sdavidcs	rcv_mode->cntxt_id = ha->hw.rcv_cntxt_id;
1202250661Sdavidcs
1203250661Sdavidcs	if (qla_mbx_cmd(ha, (uint32_t *)rcv_mode,
1204250661Sdavidcs		(sizeof (q80_config_mac_rcv_mode_t) >> 2),
1205250661Sdavidcs		ha->hw.mbox, (sizeof(q80_config_mac_rcv_mode_rsp_t) >> 2), 1)) {
1206250661Sdavidcs		device_printf(dev, "%s: failed0\n", __func__);
1207250661Sdavidcs		return (-1);
1208250661Sdavidcs	}
1209250661Sdavidcs	rcv_mode_rsp = (q80_config_mac_rcv_mode_rsp_t *)ha->hw.mbox;
1210250661Sdavidcs
1211250661Sdavidcs	err = Q8_MBX_RSP_STATUS(rcv_mode_rsp->regcnt_status);
1212250661Sdavidcs
1213250661Sdavidcs	if (err) {
1214250661Sdavidcs		device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err);
1215250661Sdavidcs		return (-1);
1216250661Sdavidcs	}
1217250661Sdavidcs
1218250661Sdavidcs	return 0;
1219250661Sdavidcs}
1220250661Sdavidcs
1221250661Sdavidcsint
1222250661Sdavidcsql_set_promisc(qla_host_t *ha)
1223250661Sdavidcs{
1224250661Sdavidcs	int ret;
1225250661Sdavidcs
1226250661Sdavidcs	ha->hw.mac_rcv_mode |= Q8_MBX_MAC_RCV_PROMISC_ENABLE;
1227250661Sdavidcs	ret = qla_set_mac_rcv_mode(ha, ha->hw.mac_rcv_mode);
1228250661Sdavidcs	return (ret);
1229250661Sdavidcs}
1230250661Sdavidcs
1231284741Sdavidcsvoid
1232284741Sdavidcsqla_reset_promisc(qla_host_t *ha)
1233284741Sdavidcs{
1234284741Sdavidcs	ha->hw.mac_rcv_mode &= ~Q8_MBX_MAC_RCV_PROMISC_ENABLE;
1235284741Sdavidcs	(void)qla_set_mac_rcv_mode(ha, ha->hw.mac_rcv_mode);
1236284741Sdavidcs}
1237284741Sdavidcs
1238250661Sdavidcsint
1239250661Sdavidcsql_set_allmulti(qla_host_t *ha)
1240250661Sdavidcs{
1241250661Sdavidcs	int ret;
1242250661Sdavidcs
1243250661Sdavidcs	ha->hw.mac_rcv_mode |= Q8_MBX_MAC_ALL_MULTI_ENABLE;
1244250661Sdavidcs	ret = qla_set_mac_rcv_mode(ha, ha->hw.mac_rcv_mode);
1245250661Sdavidcs	return (ret);
1246250661Sdavidcs}
1247250661Sdavidcs
1248284741Sdavidcsvoid
1249284741Sdavidcsqla_reset_allmulti(qla_host_t *ha)
1250284741Sdavidcs{
1251284741Sdavidcs	ha->hw.mac_rcv_mode &= ~Q8_MBX_MAC_ALL_MULTI_ENABLE;
1252284741Sdavidcs	(void)qla_set_mac_rcv_mode(ha, ha->hw.mac_rcv_mode);
1253284741Sdavidcs}
1254250661Sdavidcs
1255250661Sdavidcs/*
1256250661Sdavidcs * Name: ql_set_max_mtu
1257250661Sdavidcs * Function:
1258250661Sdavidcs *	Sets the maximum transfer unit size for the specified rcv context.
1259250661Sdavidcs */
1260250661Sdavidcsint
1261250661Sdavidcsql_set_max_mtu(qla_host_t *ha, uint32_t mtu, uint16_t cntxt_id)
1262250661Sdavidcs{
1263250661Sdavidcs	device_t		dev;
1264250661Sdavidcs	q80_set_max_mtu_t	*max_mtu;
1265250661Sdavidcs	q80_set_max_mtu_rsp_t	*max_mtu_rsp;
1266250661Sdavidcs	uint32_t		err;
1267250661Sdavidcs
1268250661Sdavidcs	dev = ha->pci_dev;
1269250661Sdavidcs
1270250661Sdavidcs	max_mtu = (q80_set_max_mtu_t *)ha->hw.mbox;
1271250661Sdavidcs	bzero(max_mtu, (sizeof (q80_set_max_mtu_t)));
1272250661Sdavidcs
1273250661Sdavidcs	max_mtu->opcode = Q8_MBX_SET_MAX_MTU;
1274250661Sdavidcs	max_mtu->count_version = (sizeof (q80_set_max_mtu_t) >> 2);
1275250661Sdavidcs	max_mtu->count_version |= Q8_MBX_CMD_VERSION;
1276250661Sdavidcs
1277250661Sdavidcs	max_mtu->cntxt_id = cntxt_id;
1278250661Sdavidcs	max_mtu->mtu = mtu;
1279250661Sdavidcs
1280250661Sdavidcs        if (qla_mbx_cmd(ha, (uint32_t *)max_mtu,
1281250661Sdavidcs		(sizeof (q80_set_max_mtu_t) >> 2),
1282250661Sdavidcs                ha->hw.mbox, (sizeof (q80_set_max_mtu_rsp_t) >> 2), 1)) {
1283250661Sdavidcs                device_printf(dev, "%s: failed\n", __func__);
1284250661Sdavidcs                return -1;
1285250661Sdavidcs        }
1286250661Sdavidcs
1287250661Sdavidcs	max_mtu_rsp = (q80_set_max_mtu_rsp_t *)ha->hw.mbox;
1288250661Sdavidcs
1289250661Sdavidcs        err = Q8_MBX_RSP_STATUS(max_mtu_rsp->regcnt_status);
1290250661Sdavidcs
1291250661Sdavidcs        if (err) {
1292250661Sdavidcs                device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
1293250661Sdavidcs        }
1294250661Sdavidcs
1295250661Sdavidcs	return 0;
1296250661Sdavidcs}
1297250661Sdavidcs
1298250661Sdavidcsstatic int
1299250661Sdavidcsqla_link_event_req(qla_host_t *ha, uint16_t cntxt_id)
1300250661Sdavidcs{
1301250661Sdavidcs	device_t		dev;
1302250661Sdavidcs	q80_link_event_t	*lnk;
1303250661Sdavidcs	q80_link_event_rsp_t	*lnk_rsp;
1304250661Sdavidcs	uint32_t		err;
1305250661Sdavidcs
1306250661Sdavidcs	dev = ha->pci_dev;
1307250661Sdavidcs
1308250661Sdavidcs	lnk = (q80_link_event_t *)ha->hw.mbox;
1309250661Sdavidcs	bzero(lnk, (sizeof (q80_link_event_t)));
1310250661Sdavidcs
1311250661Sdavidcs	lnk->opcode = Q8_MBX_LINK_EVENT_REQ;
1312250661Sdavidcs	lnk->count_version = (sizeof (q80_link_event_t) >> 2);
1313250661Sdavidcs	lnk->count_version |= Q8_MBX_CMD_VERSION;
1314250661Sdavidcs
1315250661Sdavidcs	lnk->cntxt_id = cntxt_id;
1316250661Sdavidcs	lnk->cmd = Q8_LINK_EVENT_CMD_ENABLE_ASYNC;
1317250661Sdavidcs
1318250661Sdavidcs        if (qla_mbx_cmd(ha, (uint32_t *)lnk, (sizeof (q80_link_event_t) >> 2),
1319250661Sdavidcs                ha->hw.mbox, (sizeof (q80_link_event_rsp_t) >> 2), 0)) {
1320250661Sdavidcs                device_printf(dev, "%s: failed\n", __func__);
1321250661Sdavidcs                return -1;
1322250661Sdavidcs        }
1323250661Sdavidcs
1324250661Sdavidcs	lnk_rsp = (q80_link_event_rsp_t *)ha->hw.mbox;
1325250661Sdavidcs
1326250661Sdavidcs        err = Q8_MBX_RSP_STATUS(lnk_rsp->regcnt_status);
1327250661Sdavidcs
1328250661Sdavidcs        if (err) {
1329250661Sdavidcs                device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
1330250661Sdavidcs        }
1331250661Sdavidcs
1332250661Sdavidcs	return 0;
1333250661Sdavidcs}
1334250661Sdavidcs
1335250661Sdavidcsstatic int
1336250661Sdavidcsqla_config_fw_lro(qla_host_t *ha, uint16_t cntxt_id)
1337250661Sdavidcs{
1338250661Sdavidcs	device_t		dev;
1339250661Sdavidcs	q80_config_fw_lro_t	*fw_lro;
1340250661Sdavidcs	q80_config_fw_lro_rsp_t	*fw_lro_rsp;
1341250661Sdavidcs	uint32_t		err;
1342250661Sdavidcs
1343250661Sdavidcs	dev = ha->pci_dev;
1344250661Sdavidcs
1345250661Sdavidcs	fw_lro = (q80_config_fw_lro_t *)ha->hw.mbox;
1346250661Sdavidcs	bzero(fw_lro, sizeof(q80_config_fw_lro_t));
1347250661Sdavidcs
1348250661Sdavidcs	fw_lro->opcode = Q8_MBX_CONFIG_FW_LRO;
1349250661Sdavidcs	fw_lro->count_version = (sizeof (q80_config_fw_lro_t) >> 2);
1350250661Sdavidcs	fw_lro->count_version |= Q8_MBX_CMD_VERSION;
1351250661Sdavidcs
1352250661Sdavidcs	fw_lro->flags |= Q8_MBX_FW_LRO_IPV4 | Q8_MBX_FW_LRO_IPV4_WO_DST_IP_CHK;
1353284741Sdavidcs	fw_lro->flags |= Q8_MBX_FW_LRO_IPV6 | Q8_MBX_FW_LRO_IPV6_WO_DST_IP_CHK;
1354250661Sdavidcs
1355250661Sdavidcs	fw_lro->cntxt_id = cntxt_id;
1356250661Sdavidcs
1357250661Sdavidcs	if (qla_mbx_cmd(ha, (uint32_t *)fw_lro,
1358250661Sdavidcs		(sizeof (q80_config_fw_lro_t) >> 2),
1359250661Sdavidcs		ha->hw.mbox, (sizeof (q80_config_fw_lro_rsp_t) >> 2), 0)) {
1360250661Sdavidcs		device_printf(dev, "%s: failed\n", __func__);
1361250661Sdavidcs		return -1;
1362250661Sdavidcs	}
1363250661Sdavidcs
1364250661Sdavidcs	fw_lro_rsp = (q80_config_fw_lro_rsp_t *)ha->hw.mbox;
1365250661Sdavidcs
1366250661Sdavidcs	err = Q8_MBX_RSP_STATUS(fw_lro_rsp->regcnt_status);
1367250661Sdavidcs
1368250661Sdavidcs	if (err) {
1369250661Sdavidcs		device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
1370250661Sdavidcs	}
1371250661Sdavidcs
1372250661Sdavidcs	return 0;
1373250661Sdavidcs}
1374250661Sdavidcs
1375305488Sdavidcsstatic int
1376305488Sdavidcsqla_set_cam_search_mode(qla_host_t *ha, uint32_t search_mode)
1377305488Sdavidcs{
1378305488Sdavidcs	device_t                dev;
1379305488Sdavidcs	q80_hw_config_t         *hw_config;
1380305488Sdavidcs	q80_hw_config_rsp_t     *hw_config_rsp;
1381305488Sdavidcs	uint32_t                err;
1382305488Sdavidcs
1383305488Sdavidcs	dev = ha->pci_dev;
1384305488Sdavidcs
1385305488Sdavidcs	hw_config = (q80_hw_config_t *)ha->hw.mbox;
1386305488Sdavidcs	bzero(hw_config, sizeof (q80_hw_config_t));
1387305488Sdavidcs
1388305488Sdavidcs	hw_config->opcode = Q8_MBX_HW_CONFIG;
1389305488Sdavidcs	hw_config->count_version = Q8_HW_CONFIG_SET_CAM_SEARCH_MODE_COUNT;
1390305488Sdavidcs	hw_config->count_version |= Q8_MBX_CMD_VERSION;
1391305488Sdavidcs
1392305488Sdavidcs	hw_config->cmd = Q8_HW_CONFIG_SET_CAM_SEARCH_MODE;
1393305488Sdavidcs
1394305488Sdavidcs	hw_config->u.set_cam_search_mode.mode = search_mode;
1395305488Sdavidcs
1396305488Sdavidcs	if (qla_mbx_cmd(ha, (uint32_t *)hw_config,
1397305488Sdavidcs		(sizeof (q80_hw_config_t) >> 2),
1398305488Sdavidcs		ha->hw.mbox, (sizeof (q80_hw_config_rsp_t) >> 2), 0)) {
1399305488Sdavidcs		device_printf(dev, "%s: failed\n", __func__);
1400305488Sdavidcs		return -1;
1401305488Sdavidcs	}
1402305488Sdavidcs	hw_config_rsp = (q80_hw_config_rsp_t *)ha->hw.mbox;
1403305488Sdavidcs
1404305488Sdavidcs	err = Q8_MBX_RSP_STATUS(hw_config_rsp->regcnt_status);
1405305488Sdavidcs
1406305488Sdavidcs	if (err) {
1407305488Sdavidcs		device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
1408305488Sdavidcs	}
1409305488Sdavidcs
1410305488Sdavidcs	return 0;
1411305488Sdavidcs}
1412305488Sdavidcs
1413305488Sdavidcsstatic int
1414305488Sdavidcsqla_get_cam_search_mode(qla_host_t *ha)
1415305488Sdavidcs{
1416305488Sdavidcs	device_t                dev;
1417305488Sdavidcs	q80_hw_config_t         *hw_config;
1418305488Sdavidcs	q80_hw_config_rsp_t     *hw_config_rsp;
1419305488Sdavidcs	uint32_t                err;
1420305488Sdavidcs
1421305488Sdavidcs	dev = ha->pci_dev;
1422305488Sdavidcs
1423305488Sdavidcs	hw_config = (q80_hw_config_t *)ha->hw.mbox;
1424305488Sdavidcs	bzero(hw_config, sizeof (q80_hw_config_t));
1425305488Sdavidcs
1426305488Sdavidcs	hw_config->opcode = Q8_MBX_HW_CONFIG;
1427305488Sdavidcs	hw_config->count_version = Q8_HW_CONFIG_GET_CAM_SEARCH_MODE_COUNT;
1428305488Sdavidcs	hw_config->count_version |= Q8_MBX_CMD_VERSION;
1429305488Sdavidcs
1430305488Sdavidcs	hw_config->cmd = Q8_HW_CONFIG_GET_CAM_SEARCH_MODE;
1431305488Sdavidcs
1432305488Sdavidcs	if (qla_mbx_cmd(ha, (uint32_t *)hw_config,
1433305488Sdavidcs		(sizeof (q80_hw_config_t) >> 2),
1434305488Sdavidcs		ha->hw.mbox, (sizeof (q80_hw_config_rsp_t) >> 2), 0)) {
1435305488Sdavidcs		device_printf(dev, "%s: failed\n", __func__);
1436305488Sdavidcs		return -1;
1437305488Sdavidcs	}
1438305488Sdavidcs	hw_config_rsp = (q80_hw_config_rsp_t *)ha->hw.mbox;
1439305488Sdavidcs
1440305488Sdavidcs	err = Q8_MBX_RSP_STATUS(hw_config_rsp->regcnt_status);
1441305488Sdavidcs
1442305488Sdavidcs	if (err) {
1443305488Sdavidcs		device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
1444305488Sdavidcs	} else {
1445305488Sdavidcs		device_printf(dev, "%s: cam search mode [0x%08x]\n", __func__,
1446305488Sdavidcs			hw_config_rsp->u.get_cam_search_mode.mode);
1447305488Sdavidcs	}
1448305488Sdavidcs
1449305488Sdavidcs	return 0;
1450305488Sdavidcs}
1451305488Sdavidcs
1452305488Sdavidcs
1453305488Sdavidcs
1454250661Sdavidcsstatic void
1455284741Sdavidcsqla_xmt_stats(qla_host_t *ha, q80_xmt_stats_t *xstat, int i)
1456250661Sdavidcs{
1457250661Sdavidcs	device_t dev = ha->pci_dev;
1458250661Sdavidcs
1459284741Sdavidcs	if (i < ha->hw.num_tx_rings) {
1460284741Sdavidcs		device_printf(dev, "%s[%d]: total_bytes\t\t%" PRIu64 "\n",
1461284741Sdavidcs			__func__, i, xstat->total_bytes);
1462284741Sdavidcs		device_printf(dev, "%s[%d]: total_pkts\t\t%" PRIu64 "\n",
1463284741Sdavidcs			__func__, i, xstat->total_pkts);
1464284741Sdavidcs		device_printf(dev, "%s[%d]: errors\t\t%" PRIu64 "\n",
1465284741Sdavidcs			__func__, i, xstat->errors);
1466284741Sdavidcs		device_printf(dev, "%s[%d]: pkts_dropped\t%" PRIu64 "\n",
1467284741Sdavidcs			__func__, i, xstat->pkts_dropped);
1468284741Sdavidcs		device_printf(dev, "%s[%d]: switch_pkts\t\t%" PRIu64 "\n",
1469284741Sdavidcs			__func__, i, xstat->switch_pkts);
1470284741Sdavidcs		device_printf(dev, "%s[%d]: num_buffers\t\t%" PRIu64 "\n",
1471284741Sdavidcs			__func__, i, xstat->num_buffers);
1472284741Sdavidcs	} else {
1473284741Sdavidcs		device_printf(dev, "%s: total_bytes\t\t\t%" PRIu64 "\n",
1474284741Sdavidcs			__func__, xstat->total_bytes);
1475284741Sdavidcs		device_printf(dev, "%s: total_pkts\t\t\t%" PRIu64 "\n",
1476284741Sdavidcs			__func__, xstat->total_pkts);
1477284741Sdavidcs		device_printf(dev, "%s: errors\t\t\t%" PRIu64 "\n",
1478284741Sdavidcs			__func__, xstat->errors);
1479284741Sdavidcs		device_printf(dev, "%s: pkts_dropped\t\t\t%" PRIu64 "\n",
1480284741Sdavidcs			__func__, xstat->pkts_dropped);
1481284741Sdavidcs		device_printf(dev, "%s: switch_pkts\t\t\t%" PRIu64 "\n",
1482284741Sdavidcs			__func__, xstat->switch_pkts);
1483284741Sdavidcs		device_printf(dev, "%s: num_buffers\t\t\t%" PRIu64 "\n",
1484284741Sdavidcs			__func__, xstat->num_buffers);
1485284741Sdavidcs	}
1486250661Sdavidcs}
1487250661Sdavidcs
1488250661Sdavidcsstatic void
1489250661Sdavidcsqla_rcv_stats(qla_host_t *ha, q80_rcv_stats_t *rstat)
1490250661Sdavidcs{
1491250661Sdavidcs	device_t dev = ha->pci_dev;
1492250661Sdavidcs
1493250661Sdavidcs	device_printf(dev, "%s: total_bytes\t\t\t%" PRIu64 "\n", __func__,
1494250661Sdavidcs		rstat->total_bytes);
1495250661Sdavidcs	device_printf(dev, "%s: total_pkts\t\t\t%" PRIu64 "\n", __func__,
1496250661Sdavidcs		rstat->total_pkts);
1497250661Sdavidcs	device_printf(dev, "%s: lro_pkt_count\t\t%" PRIu64 "\n", __func__,
1498250661Sdavidcs		rstat->lro_pkt_count);
1499284741Sdavidcs	device_printf(dev, "%s: sw_pkt_count\t\t\t%" PRIu64 "\n", __func__,
1500250661Sdavidcs		rstat->sw_pkt_count);
1501250661Sdavidcs	device_printf(dev, "%s: ip_chksum_err\t\t%" PRIu64 "\n", __func__,
1502250661Sdavidcs		rstat->ip_chksum_err);
1503250661Sdavidcs	device_printf(dev, "%s: pkts_wo_acntxts\t\t%" PRIu64 "\n", __func__,
1504250661Sdavidcs		rstat->pkts_wo_acntxts);
1505250661Sdavidcs	device_printf(dev, "%s: pkts_dropped_no_sds_card\t%" PRIu64 "\n",
1506250661Sdavidcs		__func__, rstat->pkts_dropped_no_sds_card);
1507250661Sdavidcs	device_printf(dev, "%s: pkts_dropped_no_sds_host\t%" PRIu64 "\n",
1508250661Sdavidcs		__func__, rstat->pkts_dropped_no_sds_host);
1509250661Sdavidcs	device_printf(dev, "%s: oversized_pkts\t\t%" PRIu64 "\n", __func__,
1510250661Sdavidcs		rstat->oversized_pkts);
1511250661Sdavidcs	device_printf(dev, "%s: pkts_dropped_no_rds\t\t%" PRIu64 "\n",
1512250661Sdavidcs		__func__, rstat->pkts_dropped_no_rds);
1513250661Sdavidcs	device_printf(dev, "%s: unxpctd_mcast_pkts\t\t%" PRIu64 "\n",
1514250661Sdavidcs		__func__, rstat->unxpctd_mcast_pkts);
1515250661Sdavidcs	device_printf(dev, "%s: re1_fbq_error\t\t%" PRIu64 "\n", __func__,
1516250661Sdavidcs		rstat->re1_fbq_error);
1517250661Sdavidcs	device_printf(dev, "%s: invalid_mac_addr\t\t%" PRIu64 "\n", __func__,
1518250661Sdavidcs		rstat->invalid_mac_addr);
1519250661Sdavidcs	device_printf(dev, "%s: rds_prime_trys\t\t%" PRIu64 "\n", __func__,
1520250661Sdavidcs		rstat->rds_prime_trys);
1521250661Sdavidcs	device_printf(dev, "%s: rds_prime_success\t\t%" PRIu64 "\n", __func__,
1522250661Sdavidcs		rstat->rds_prime_success);
1523250661Sdavidcs	device_printf(dev, "%s: lro_flows_added\t\t%" PRIu64 "\n", __func__,
1524250661Sdavidcs		rstat->lro_flows_added);
1525250661Sdavidcs	device_printf(dev, "%s: lro_flows_deleted\t\t%" PRIu64 "\n", __func__,
1526250661Sdavidcs		rstat->lro_flows_deleted);
1527250661Sdavidcs	device_printf(dev, "%s: lro_flows_active\t\t%" PRIu64 "\n", __func__,
1528250661Sdavidcs		rstat->lro_flows_active);
1529250661Sdavidcs	device_printf(dev, "%s: pkts_droped_unknown\t\t%" PRIu64 "\n",
1530250661Sdavidcs		__func__, rstat->pkts_droped_unknown);
1531250661Sdavidcs}
1532250661Sdavidcs
1533250661Sdavidcsstatic void
1534250661Sdavidcsqla_mac_stats(qla_host_t *ha, q80_mac_stats_t *mstat)
1535250661Sdavidcs{
1536250661Sdavidcs	device_t dev = ha->pci_dev;
1537250661Sdavidcs
1538250661Sdavidcs	device_printf(dev, "%s: xmt_frames\t\t\t%" PRIu64 "\n", __func__,
1539250661Sdavidcs		mstat->xmt_frames);
1540250661Sdavidcs	device_printf(dev, "%s: xmt_bytes\t\t\t%" PRIu64 "\n", __func__,
1541250661Sdavidcs		mstat->xmt_bytes);
1542250661Sdavidcs	device_printf(dev, "%s: xmt_mcast_pkts\t\t%" PRIu64 "\n", __func__,
1543250661Sdavidcs		mstat->xmt_mcast_pkts);
1544250661Sdavidcs	device_printf(dev, "%s: xmt_bcast_pkts\t\t%" PRIu64 "\n", __func__,
1545250661Sdavidcs		mstat->xmt_bcast_pkts);
1546250661Sdavidcs	device_printf(dev, "%s: xmt_pause_frames\t\t%" PRIu64 "\n", __func__,
1547250661Sdavidcs		mstat->xmt_pause_frames);
1548250661Sdavidcs	device_printf(dev, "%s: xmt_cntrl_pkts\t\t%" PRIu64 "\n", __func__,
1549250661Sdavidcs		mstat->xmt_cntrl_pkts);
1550250661Sdavidcs	device_printf(dev, "%s: xmt_pkt_lt_64bytes\t\t%" PRIu64 "\n",
1551250661Sdavidcs		__func__, mstat->xmt_pkt_lt_64bytes);
1552250661Sdavidcs	device_printf(dev, "%s: xmt_pkt_lt_127bytes\t\t%" PRIu64 "\n",
1553250661Sdavidcs		__func__, mstat->xmt_pkt_lt_127bytes);
1554250661Sdavidcs	device_printf(dev, "%s: xmt_pkt_lt_255bytes\t\t%" PRIu64 "\n",
1555250661Sdavidcs		__func__, mstat->xmt_pkt_lt_255bytes);
1556250661Sdavidcs	device_printf(dev, "%s: xmt_pkt_lt_511bytes\t\t%" PRIu64 "\n",
1557250661Sdavidcs		__func__, mstat->xmt_pkt_lt_511bytes);
1558284741Sdavidcs	device_printf(dev, "%s: xmt_pkt_lt_1023bytes\t\t%" PRIu64 "\n",
1559250661Sdavidcs		__func__, mstat->xmt_pkt_lt_1023bytes);
1560284741Sdavidcs	device_printf(dev, "%s: xmt_pkt_lt_1518bytes\t\t%" PRIu64 "\n",
1561250661Sdavidcs		__func__, mstat->xmt_pkt_lt_1518bytes);
1562284741Sdavidcs	device_printf(dev, "%s: xmt_pkt_gt_1518bytes\t\t%" PRIu64 "\n",
1563250661Sdavidcs		__func__, mstat->xmt_pkt_gt_1518bytes);
1564250661Sdavidcs
1565250661Sdavidcs	device_printf(dev, "%s: rcv_frames\t\t\t%" PRIu64 "\n", __func__,
1566250661Sdavidcs		mstat->rcv_frames);
1567250661Sdavidcs	device_printf(dev, "%s: rcv_bytes\t\t\t%" PRIu64 "\n", __func__,
1568250661Sdavidcs		mstat->rcv_bytes);
1569250661Sdavidcs	device_printf(dev, "%s: rcv_mcast_pkts\t\t%" PRIu64 "\n", __func__,
1570250661Sdavidcs		mstat->rcv_mcast_pkts);
1571250661Sdavidcs	device_printf(dev, "%s: rcv_bcast_pkts\t\t%" PRIu64 "\n", __func__,
1572250661Sdavidcs		mstat->rcv_bcast_pkts);
1573250661Sdavidcs	device_printf(dev, "%s: rcv_pause_frames\t\t%" PRIu64 "\n", __func__,
1574250661Sdavidcs		mstat->rcv_pause_frames);
1575250661Sdavidcs	device_printf(dev, "%s: rcv_cntrl_pkts\t\t%" PRIu64 "\n", __func__,
1576250661Sdavidcs		mstat->rcv_cntrl_pkts);
1577250661Sdavidcs	device_printf(dev, "%s: rcv_pkt_lt_64bytes\t\t%" PRIu64 "\n",
1578250661Sdavidcs		__func__, mstat->rcv_pkt_lt_64bytes);
1579250661Sdavidcs	device_printf(dev, "%s: rcv_pkt_lt_127bytes\t\t%" PRIu64 "\n",
1580250661Sdavidcs		__func__, mstat->rcv_pkt_lt_127bytes);
1581250661Sdavidcs	device_printf(dev, "%s: rcv_pkt_lt_255bytes\t\t%" PRIu64 "\n",
1582250661Sdavidcs		__func__, mstat->rcv_pkt_lt_255bytes);
1583250661Sdavidcs	device_printf(dev, "%s: rcv_pkt_lt_511bytes\t\t%" PRIu64 "\n",
1584250661Sdavidcs		__func__, mstat->rcv_pkt_lt_511bytes);
1585284741Sdavidcs	device_printf(dev, "%s: rcv_pkt_lt_1023bytes\t\t%" PRIu64 "\n",
1586250661Sdavidcs		__func__, mstat->rcv_pkt_lt_1023bytes);
1587284741Sdavidcs	device_printf(dev, "%s: rcv_pkt_lt_1518bytes\t\t%" PRIu64 "\n",
1588250661Sdavidcs		__func__, mstat->rcv_pkt_lt_1518bytes);
1589284741Sdavidcs	device_printf(dev, "%s: rcv_pkt_gt_1518bytes\t\t%" PRIu64 "\n",
1590250661Sdavidcs		__func__, mstat->rcv_pkt_gt_1518bytes);
1591250661Sdavidcs
1592250661Sdavidcs	device_printf(dev, "%s: rcv_len_error\t\t%" PRIu64 "\n", __func__,
1593250661Sdavidcs		mstat->rcv_len_error);
1594250661Sdavidcs	device_printf(dev, "%s: rcv_len_small\t\t%" PRIu64 "\n", __func__,
1595250661Sdavidcs		mstat->rcv_len_small);
1596250661Sdavidcs	device_printf(dev, "%s: rcv_len_large\t\t%" PRIu64 "\n", __func__,
1597250661Sdavidcs		mstat->rcv_len_large);
1598250661Sdavidcs	device_printf(dev, "%s: rcv_jabber\t\t\t%" PRIu64 "\n", __func__,
1599250661Sdavidcs		mstat->rcv_jabber);
1600250661Sdavidcs	device_printf(dev, "%s: rcv_dropped\t\t\t%" PRIu64 "\n", __func__,
1601250661Sdavidcs		mstat->rcv_dropped);
1602250661Sdavidcs	device_printf(dev, "%s: fcs_error\t\t\t%" PRIu64 "\n", __func__,
1603250661Sdavidcs		mstat->fcs_error);
1604250661Sdavidcs	device_printf(dev, "%s: align_error\t\t\t%" PRIu64 "\n", __func__,
1605250661Sdavidcs		mstat->align_error);
1606250661Sdavidcs}
1607250661Sdavidcs
1608250661Sdavidcs
1609250661Sdavidcsstatic int
1610284741Sdavidcsqla_get_hw_stats(qla_host_t *ha, uint32_t cmd, uint32_t rsp_size)
1611250661Sdavidcs{
1612250661Sdavidcs	device_t		dev;
1613250661Sdavidcs	q80_get_stats_t		*stat;
1614250661Sdavidcs	q80_get_stats_rsp_t	*stat_rsp;
1615250661Sdavidcs	uint32_t		err;
1616250661Sdavidcs
1617250661Sdavidcs	dev = ha->pci_dev;
1618250661Sdavidcs
1619250661Sdavidcs	stat = (q80_get_stats_t *)ha->hw.mbox;
1620250661Sdavidcs	bzero(stat, (sizeof (q80_get_stats_t)));
1621250661Sdavidcs
1622250661Sdavidcs	stat->opcode = Q8_MBX_GET_STATS;
1623250661Sdavidcs	stat->count_version = 2;
1624250661Sdavidcs	stat->count_version |= Q8_MBX_CMD_VERSION;
1625250661Sdavidcs
1626250661Sdavidcs	stat->cmd = cmd;
1627250661Sdavidcs
1628250661Sdavidcs        if (qla_mbx_cmd(ha, (uint32_t *)stat, 2,
1629284741Sdavidcs                ha->hw.mbox, (rsp_size >> 2), 0)) {
1630250661Sdavidcs                device_printf(dev, "%s: failed\n", __func__);
1631250661Sdavidcs                return -1;
1632250661Sdavidcs        }
1633250661Sdavidcs
1634250661Sdavidcs	stat_rsp = (q80_get_stats_rsp_t *)ha->hw.mbox;
1635250661Sdavidcs
1636250661Sdavidcs        err = Q8_MBX_RSP_STATUS(stat_rsp->regcnt_status);
1637250661Sdavidcs
1638250661Sdavidcs        if (err) {
1639250661Sdavidcs                return -1;
1640250661Sdavidcs        }
1641250661Sdavidcs
1642250661Sdavidcs	return 0;
1643250661Sdavidcs}
1644250661Sdavidcs
1645250661Sdavidcsvoid
1646250661Sdavidcsql_get_stats(qla_host_t *ha)
1647250661Sdavidcs{
1648250661Sdavidcs	q80_get_stats_rsp_t	*stat_rsp;
1649250661Sdavidcs	q80_mac_stats_t		*mstat;
1650250661Sdavidcs	q80_xmt_stats_t		*xstat;
1651250661Sdavidcs	q80_rcv_stats_t		*rstat;
1652250661Sdavidcs	uint32_t		cmd;
1653284741Sdavidcs	int			i;
1654250661Sdavidcs
1655250661Sdavidcs	stat_rsp = (q80_get_stats_rsp_t *)ha->hw.mbox;
1656250661Sdavidcs	/*
1657250661Sdavidcs	 * Get MAC Statistics
1658250661Sdavidcs	 */
1659250661Sdavidcs	cmd = Q8_GET_STATS_CMD_TYPE_MAC;
1660284741Sdavidcs//	cmd |= Q8_GET_STATS_CMD_CLEAR;
1661250661Sdavidcs
1662250661Sdavidcs	cmd |= ((ha->pci_func & 0x1) << 16);
1663250661Sdavidcs
1664284741Sdavidcs	if (qla_get_hw_stats(ha, cmd, sizeof (q80_get_stats_rsp_t)) == 0) {
1665250661Sdavidcs		mstat = (q80_mac_stats_t *)&stat_rsp->u.mac;
1666250661Sdavidcs		qla_mac_stats(ha, mstat);
1667250661Sdavidcs	} else {
1668250661Sdavidcs                device_printf(ha->pci_dev, "%s: mac failed [0x%08x]\n",
1669250661Sdavidcs			__func__, ha->hw.mbox[0]);
1670250661Sdavidcs	}
1671250661Sdavidcs	/*
1672250661Sdavidcs	 * Get RCV Statistics
1673250661Sdavidcs	 */
1674250661Sdavidcs	cmd = Q8_GET_STATS_CMD_RCV | Q8_GET_STATS_CMD_TYPE_CNTXT;
1675284741Sdavidcs//	cmd |= Q8_GET_STATS_CMD_CLEAR;
1676250661Sdavidcs	cmd |= (ha->hw.rcv_cntxt_id << 16);
1677250661Sdavidcs
1678284741Sdavidcs	if (qla_get_hw_stats(ha, cmd, sizeof (q80_get_stats_rsp_t)) == 0) {
1679250661Sdavidcs		rstat = (q80_rcv_stats_t *)&stat_rsp->u.rcv;
1680250661Sdavidcs		qla_rcv_stats(ha, rstat);
1681250661Sdavidcs	} else {
1682250661Sdavidcs                device_printf(ha->pci_dev, "%s: rcv failed [0x%08x]\n",
1683250661Sdavidcs			__func__, ha->hw.mbox[0]);
1684250661Sdavidcs	}
1685250661Sdavidcs	/*
1686250661Sdavidcs	 * Get XMT Statistics
1687250661Sdavidcs	 */
1688284741Sdavidcs	for (i = 0 ; i < ha->hw.num_tx_rings; i++) {
1689284741Sdavidcs		cmd = Q8_GET_STATS_CMD_XMT | Q8_GET_STATS_CMD_TYPE_CNTXT;
1690284741Sdavidcs//		cmd |= Q8_GET_STATS_CMD_CLEAR;
1691284741Sdavidcs		cmd |= (ha->hw.tx_cntxt[i].tx_cntxt_id << 16);
1692250661Sdavidcs
1693284741Sdavidcs		if (qla_get_hw_stats(ha, cmd, sizeof(q80_get_stats_rsp_t))
1694284741Sdavidcs			== 0) {
1695284741Sdavidcs			xstat = (q80_xmt_stats_t *)&stat_rsp->u.xmt;
1696284741Sdavidcs			qla_xmt_stats(ha, xstat, i);
1697284741Sdavidcs		} else {
1698284741Sdavidcs			device_printf(ha->pci_dev, "%s: xmt failed [0x%08x]\n",
1699284741Sdavidcs				__func__, ha->hw.mbox[0]);
1700284741Sdavidcs		}
1701284741Sdavidcs	}
1702284741Sdavidcs	return;
1703284741Sdavidcs}
1704250661Sdavidcs
1705284741Sdavidcsstatic void
1706284741Sdavidcsqla_get_quick_stats(qla_host_t *ha)
1707284741Sdavidcs{
1708284741Sdavidcs	q80_get_mac_rcv_xmt_stats_rsp_t *stat_rsp;
1709284741Sdavidcs	q80_mac_stats_t         *mstat;
1710284741Sdavidcs	q80_xmt_stats_t         *xstat;
1711284741Sdavidcs	q80_rcv_stats_t         *rstat;
1712284741Sdavidcs	uint32_t                cmd;
1713284741Sdavidcs
1714284741Sdavidcs	stat_rsp = (q80_get_mac_rcv_xmt_stats_rsp_t *)ha->hw.mbox;
1715284741Sdavidcs
1716284741Sdavidcs	cmd = Q8_GET_STATS_CMD_TYPE_ALL;
1717284741Sdavidcs//      cmd |= Q8_GET_STATS_CMD_CLEAR;
1718284741Sdavidcs
1719284741Sdavidcs//      cmd |= ((ha->pci_func & 0x3) << 16);
1720284741Sdavidcs	cmd |= (0xFFFF << 16);
1721284741Sdavidcs
1722284741Sdavidcs	if (qla_get_hw_stats(ha, cmd,
1723284741Sdavidcs			sizeof (q80_get_mac_rcv_xmt_stats_rsp_t)) == 0) {
1724284741Sdavidcs
1725284741Sdavidcs		mstat = (q80_mac_stats_t *)&stat_rsp->mac;
1726284741Sdavidcs		rstat = (q80_rcv_stats_t *)&stat_rsp->rcv;
1727284741Sdavidcs		xstat = (q80_xmt_stats_t *)&stat_rsp->xmt;
1728284741Sdavidcs		qla_mac_stats(ha, mstat);
1729284741Sdavidcs		qla_rcv_stats(ha, rstat);
1730284741Sdavidcs		qla_xmt_stats(ha, xstat, ha->hw.num_tx_rings);
1731250661Sdavidcs	} else {
1732284741Sdavidcs		device_printf(ha->pci_dev, "%s: failed [0x%08x]\n",
1733250661Sdavidcs			__func__, ha->hw.mbox[0]);
1734250661Sdavidcs	}
1735284741Sdavidcs	return;
1736250661Sdavidcs}
1737250661Sdavidcs
1738250661Sdavidcs/*
1739250661Sdavidcs * Name: qla_tx_tso
1740250661Sdavidcs * Function: Checks if the packet to be transmitted is a candidate for
1741250661Sdavidcs *	Large TCP Segment Offload. If yes, the appropriate fields in the Tx
1742250661Sdavidcs *	Ring Structure are plugged in.
1743250661Sdavidcs */
1744250661Sdavidcsstatic int
1745250661Sdavidcsqla_tx_tso(qla_host_t *ha, struct mbuf *mp, q80_tx_cmd_t *tx_cmd, uint8_t *hdr)
1746250661Sdavidcs{
1747250661Sdavidcs	struct ether_vlan_header *eh;
1748250661Sdavidcs	struct ip *ip = NULL;
1749250661Sdavidcs	struct ip6_hdr *ip6 = NULL;
1750250661Sdavidcs	struct tcphdr *th = NULL;
1751250661Sdavidcs	uint32_t ehdrlen,  hdrlen, ip_hlen, tcp_hlen, tcp_opt_off;
1752250661Sdavidcs	uint16_t etype, opcode, offload = 1;
1753250661Sdavidcs	device_t dev;
1754250661Sdavidcs
1755250661Sdavidcs	dev = ha->pci_dev;
1756250661Sdavidcs
1757250661Sdavidcs
1758250661Sdavidcs	eh = mtod(mp, struct ether_vlan_header *);
1759250661Sdavidcs
1760250661Sdavidcs	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
1761250661Sdavidcs		ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
1762250661Sdavidcs		etype = ntohs(eh->evl_proto);
1763250661Sdavidcs	} else {
1764250661Sdavidcs		ehdrlen = ETHER_HDR_LEN;
1765250661Sdavidcs		etype = ntohs(eh->evl_encap_proto);
1766250661Sdavidcs	}
1767250661Sdavidcs
1768250661Sdavidcs	hdrlen = 0;
1769250661Sdavidcs
1770250661Sdavidcs	switch (etype) {
1771250661Sdavidcs		case ETHERTYPE_IP:
1772250661Sdavidcs
1773250661Sdavidcs			tcp_opt_off = ehdrlen + sizeof(struct ip) +
1774250661Sdavidcs					sizeof(struct tcphdr);
1775250661Sdavidcs
1776250661Sdavidcs			if (mp->m_len < tcp_opt_off) {
1777250661Sdavidcs				m_copydata(mp, 0, tcp_opt_off, hdr);
1778250661Sdavidcs				ip = (struct ip *)(hdr + ehdrlen);
1779250661Sdavidcs			} else {
1780250661Sdavidcs				ip = (struct ip *)(mp->m_data + ehdrlen);
1781250661Sdavidcs			}
1782250661Sdavidcs
1783250661Sdavidcs			ip_hlen = ip->ip_hl << 2;
1784250661Sdavidcs			opcode = Q8_TX_CMD_OP_XMT_TCP_LSO;
1785250661Sdavidcs
1786250661Sdavidcs
1787250661Sdavidcs			if ((ip->ip_p != IPPROTO_TCP) ||
1788250661Sdavidcs				(ip_hlen != sizeof (struct ip))){
1789250661Sdavidcs				/* IP Options are not supported */
1790250661Sdavidcs
1791250661Sdavidcs				offload = 0;
1792250661Sdavidcs			} else
1793250661Sdavidcs				th = (struct tcphdr *)((caddr_t)ip + ip_hlen);
1794250661Sdavidcs
1795250661Sdavidcs		break;
1796250661Sdavidcs
1797250661Sdavidcs		case ETHERTYPE_IPV6:
1798250661Sdavidcs
1799250661Sdavidcs			tcp_opt_off = ehdrlen + sizeof(struct ip6_hdr) +
1800250661Sdavidcs					sizeof (struct tcphdr);
1801250661Sdavidcs
1802250661Sdavidcs			if (mp->m_len < tcp_opt_off) {
1803250661Sdavidcs				m_copydata(mp, 0, tcp_opt_off, hdr);
1804250661Sdavidcs				ip6 = (struct ip6_hdr *)(hdr + ehdrlen);
1805250661Sdavidcs			} else {
1806250661Sdavidcs				ip6 = (struct ip6_hdr *)(mp->m_data + ehdrlen);
1807250661Sdavidcs			}
1808250661Sdavidcs
1809250661Sdavidcs			ip_hlen = sizeof(struct ip6_hdr);
1810250661Sdavidcs			opcode = Q8_TX_CMD_OP_XMT_TCP_LSO_IPV6;
1811250661Sdavidcs
1812250661Sdavidcs			if (ip6->ip6_nxt != IPPROTO_TCP) {
1813250661Sdavidcs				//device_printf(dev, "%s: ipv6\n", __func__);
1814250661Sdavidcs				offload = 0;
1815250661Sdavidcs			} else
1816250661Sdavidcs				th = (struct tcphdr *)((caddr_t)ip6 + ip_hlen);
1817250661Sdavidcs		break;
1818250661Sdavidcs
1819250661Sdavidcs		default:
1820250661Sdavidcs			QL_DPRINT8(ha, (dev, "%s: type!=ip\n", __func__));
1821250661Sdavidcs			offload = 0;
1822250661Sdavidcs		break;
1823250661Sdavidcs	}
1824250661Sdavidcs
1825250661Sdavidcs	if (!offload)
1826250661Sdavidcs		return (-1);
1827250661Sdavidcs
1828250661Sdavidcs	tcp_hlen = th->th_off << 2;
1829250661Sdavidcs	hdrlen = ehdrlen + ip_hlen + tcp_hlen;
1830250661Sdavidcs
1831250661Sdavidcs        if (mp->m_len < hdrlen) {
1832250661Sdavidcs                if (mp->m_len < tcp_opt_off) {
1833250661Sdavidcs                        if (tcp_hlen > sizeof(struct tcphdr)) {
1834250661Sdavidcs                                m_copydata(mp, tcp_opt_off,
1835250661Sdavidcs                                        (tcp_hlen - sizeof(struct tcphdr)),
1836250661Sdavidcs                                        &hdr[tcp_opt_off]);
1837250661Sdavidcs                        }
1838250661Sdavidcs                } else {
1839250661Sdavidcs                        m_copydata(mp, 0, hdrlen, hdr);
1840250661Sdavidcs                }
1841250661Sdavidcs        }
1842250661Sdavidcs
1843250661Sdavidcs	tx_cmd->mss = mp->m_pkthdr.tso_segsz;
1844250661Sdavidcs
1845250661Sdavidcs	tx_cmd->flags_opcode = opcode ;
1846250661Sdavidcs	tx_cmd->tcp_hdr_off = ip_hlen + ehdrlen;
1847250661Sdavidcs	tx_cmd->total_hdr_len = hdrlen;
1848250661Sdavidcs
1849250661Sdavidcs	/* Check for Multicast least significant bit of MSB == 1 */
1850250661Sdavidcs	if (eh->evl_dhost[0] & 0x01) {
1851250661Sdavidcs		tx_cmd->flags_opcode |= Q8_TX_CMD_FLAGS_MULTICAST;
1852250661Sdavidcs	}
1853250661Sdavidcs
1854250661Sdavidcs	if (mp->m_len < hdrlen) {
1855250661Sdavidcs		printf("%d\n", hdrlen);
1856250661Sdavidcs		return (1);
1857250661Sdavidcs	}
1858250661Sdavidcs
1859250661Sdavidcs	return (0);
1860250661Sdavidcs}
1861250661Sdavidcs
1862250661Sdavidcs/*
1863250661Sdavidcs * Name: qla_tx_chksum
1864250661Sdavidcs * Function: Checks if the packet to be transmitted is a candidate for
1865250661Sdavidcs *	TCP/UDP Checksum offload. If yes, the appropriate fields in the Tx
1866250661Sdavidcs *	Ring Structure are plugged in.
1867250661Sdavidcs */
1868250661Sdavidcsstatic int
1869250661Sdavidcsqla_tx_chksum(qla_host_t *ha, struct mbuf *mp, uint32_t *op_code,
1870250661Sdavidcs	uint32_t *tcp_hdr_off)
1871250661Sdavidcs{
1872250661Sdavidcs	struct ether_vlan_header *eh;
1873250661Sdavidcs	struct ip *ip;
1874250661Sdavidcs	struct ip6_hdr *ip6;
1875250661Sdavidcs	uint32_t ehdrlen, ip_hlen;
1876250661Sdavidcs	uint16_t etype, opcode, offload = 1;
1877250661Sdavidcs	device_t dev;
1878250661Sdavidcs	uint8_t buf[sizeof(struct ip6_hdr)];
1879250661Sdavidcs
1880250661Sdavidcs	dev = ha->pci_dev;
1881250661Sdavidcs
1882250661Sdavidcs	*op_code = 0;
1883250661Sdavidcs
1884250661Sdavidcs	if ((mp->m_pkthdr.csum_flags & (CSUM_TCP|CSUM_UDP)) == 0)
1885250661Sdavidcs		return (-1);
1886250661Sdavidcs
1887250661Sdavidcs	eh = mtod(mp, struct ether_vlan_header *);
1888250661Sdavidcs
1889250661Sdavidcs	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
1890250661Sdavidcs		ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
1891250661Sdavidcs		etype = ntohs(eh->evl_proto);
1892250661Sdavidcs	} else {
1893250661Sdavidcs		ehdrlen = ETHER_HDR_LEN;
1894250661Sdavidcs		etype = ntohs(eh->evl_encap_proto);
1895250661Sdavidcs	}
1896250661Sdavidcs
1897250661Sdavidcs
1898250661Sdavidcs	switch (etype) {
1899250661Sdavidcs		case ETHERTYPE_IP:
1900250661Sdavidcs			ip = (struct ip *)(mp->m_data + ehdrlen);
1901250661Sdavidcs
1902250661Sdavidcs			ip_hlen = sizeof (struct ip);
1903250661Sdavidcs
1904250661Sdavidcs			if (mp->m_len < (ehdrlen + ip_hlen)) {
1905250661Sdavidcs				m_copydata(mp, ehdrlen, sizeof(struct ip), buf);
1906250661Sdavidcs				ip = (struct ip *)buf;
1907250661Sdavidcs			}
1908250661Sdavidcs
1909250661Sdavidcs			if (ip->ip_p == IPPROTO_TCP)
1910250661Sdavidcs				opcode = Q8_TX_CMD_OP_XMT_TCP_CHKSUM;
1911250661Sdavidcs			else if (ip->ip_p == IPPROTO_UDP)
1912250661Sdavidcs				opcode = Q8_TX_CMD_OP_XMT_UDP_CHKSUM;
1913250661Sdavidcs			else {
1914250661Sdavidcs				//device_printf(dev, "%s: ipv4\n", __func__);
1915250661Sdavidcs				offload = 0;
1916250661Sdavidcs			}
1917250661Sdavidcs		break;
1918250661Sdavidcs
1919250661Sdavidcs		case ETHERTYPE_IPV6:
1920250661Sdavidcs			ip6 = (struct ip6_hdr *)(mp->m_data + ehdrlen);
1921250661Sdavidcs
1922250661Sdavidcs			ip_hlen = sizeof(struct ip6_hdr);
1923250661Sdavidcs
1924250661Sdavidcs			if (mp->m_len < (ehdrlen + ip_hlen)) {
1925250661Sdavidcs				m_copydata(mp, ehdrlen, sizeof (struct ip6_hdr),
1926250661Sdavidcs					buf);
1927250661Sdavidcs				ip6 = (struct ip6_hdr *)buf;
1928250661Sdavidcs			}
1929250661Sdavidcs
1930250661Sdavidcs			if (ip6->ip6_nxt == IPPROTO_TCP)
1931250661Sdavidcs				opcode = Q8_TX_CMD_OP_XMT_TCP_CHKSUM_IPV6;
1932250661Sdavidcs			else if (ip6->ip6_nxt == IPPROTO_UDP)
1933250661Sdavidcs				opcode = Q8_TX_CMD_OP_XMT_UDP_CHKSUM_IPV6;
1934250661Sdavidcs			else {
1935250661Sdavidcs				//device_printf(dev, "%s: ipv6\n", __func__);
1936250661Sdavidcs				offload = 0;
1937250661Sdavidcs			}
1938250661Sdavidcs		break;
1939250661Sdavidcs
1940250661Sdavidcs		default:
1941250661Sdavidcs			offload = 0;
1942250661Sdavidcs		break;
1943250661Sdavidcs	}
1944250661Sdavidcs	if (!offload)
1945250661Sdavidcs		return (-1);
1946250661Sdavidcs
1947250661Sdavidcs	*op_code = opcode;
1948250661Sdavidcs	*tcp_hdr_off = (ip_hlen + ehdrlen);
1949250661Sdavidcs
1950250661Sdavidcs	return (0);
1951250661Sdavidcs}
1952250661Sdavidcs
1953250661Sdavidcs#define QLA_TX_MIN_FREE 2
1954250661Sdavidcs/*
1955250661Sdavidcs * Name: ql_hw_send
1956250661Sdavidcs * Function: Transmits a packet. It first checks if the packet is a
1957250661Sdavidcs *	candidate for Large TCP Segment Offload and then for UDP/TCP checksum
1958250661Sdavidcs *	offload. If either of these creteria are not met, it is transmitted
1959250661Sdavidcs *	as a regular ethernet frame.
1960250661Sdavidcs */
1961250661Sdavidcsint
1962250661Sdavidcsql_hw_send(qla_host_t *ha, bus_dma_segment_t *segs, int nsegs,
1963284741Sdavidcs	uint32_t tx_idx, struct mbuf *mp, uint32_t txr_idx, uint32_t iscsi_pdu)
1964250661Sdavidcs{
1965250661Sdavidcs	struct ether_vlan_header *eh;
1966250661Sdavidcs	qla_hw_t *hw = &ha->hw;
1967250661Sdavidcs	q80_tx_cmd_t *tx_cmd, tso_cmd;
1968250661Sdavidcs	bus_dma_segment_t *c_seg;
1969250661Sdavidcs	uint32_t num_tx_cmds, hdr_len = 0;
1970250661Sdavidcs	uint32_t total_length = 0, bytes, tx_cmd_count = 0, txr_next;
1971250661Sdavidcs	device_t dev;
1972250661Sdavidcs	int i, ret;
1973250661Sdavidcs	uint8_t *src = NULL, *dst = NULL;
1974250661Sdavidcs	uint8_t frame_hdr[QL_FRAME_HDR_SIZE];
1975250661Sdavidcs	uint32_t op_code = 0;
1976250661Sdavidcs	uint32_t tcp_hdr_off = 0;
1977250661Sdavidcs
1978250661Sdavidcs	dev = ha->pci_dev;
1979250661Sdavidcs
1980250661Sdavidcs	/*
1981250661Sdavidcs	 * Always make sure there is atleast one empty slot in the tx_ring
1982250661Sdavidcs	 * tx_ring is considered full when there only one entry available
1983250661Sdavidcs	 */
1984250661Sdavidcs        num_tx_cmds = (nsegs + (Q8_TX_CMD_MAX_SEGMENTS - 1)) >> 2;
1985250661Sdavidcs
1986250661Sdavidcs	total_length = mp->m_pkthdr.len;
1987250661Sdavidcs	if (total_length > QLA_MAX_TSO_FRAME_SIZE) {
1988250661Sdavidcs		device_printf(dev, "%s: total length exceeds maxlen(%d)\n",
1989250661Sdavidcs			__func__, total_length);
1990250661Sdavidcs		return (-1);
1991250661Sdavidcs	}
1992250661Sdavidcs	eh = mtod(mp, struct ether_vlan_header *);
1993250661Sdavidcs
1994250661Sdavidcs	if (mp->m_pkthdr.csum_flags & CSUM_TSO) {
1995250661Sdavidcs
1996250661Sdavidcs		bzero((void *)&tso_cmd, sizeof(q80_tx_cmd_t));
1997250661Sdavidcs
1998250661Sdavidcs		src = frame_hdr;
1999250661Sdavidcs		ret = qla_tx_tso(ha, mp, &tso_cmd, src);
2000250661Sdavidcs
2001250661Sdavidcs		if (!(ret & ~1)) {
2002250661Sdavidcs			/* find the additional tx_cmd descriptors required */
2003250661Sdavidcs
2004250661Sdavidcs			if (mp->m_flags & M_VLANTAG)
2005250661Sdavidcs				tso_cmd.total_hdr_len += ETHER_VLAN_ENCAP_LEN;
2006250661Sdavidcs
2007250661Sdavidcs			hdr_len = tso_cmd.total_hdr_len;
2008250661Sdavidcs
2009250661Sdavidcs			bytes = sizeof(q80_tx_cmd_t) - Q8_TX_CMD_TSO_ALIGN;
2010250661Sdavidcs			bytes = QL_MIN(bytes, hdr_len);
2011250661Sdavidcs
2012250661Sdavidcs			num_tx_cmds++;
2013250661Sdavidcs			hdr_len -= bytes;
2014250661Sdavidcs
2015250661Sdavidcs			while (hdr_len) {
2016250661Sdavidcs				bytes = QL_MIN((sizeof(q80_tx_cmd_t)), hdr_len);
2017250661Sdavidcs				hdr_len -= bytes;
2018250661Sdavidcs				num_tx_cmds++;
2019250661Sdavidcs			}
2020250661Sdavidcs			hdr_len = tso_cmd.total_hdr_len;
2021250661Sdavidcs
2022250661Sdavidcs			if (ret == 0)
2023250661Sdavidcs				src = (uint8_t *)eh;
2024250661Sdavidcs		} else
2025250661Sdavidcs			return (EINVAL);
2026250661Sdavidcs	} else {
2027250661Sdavidcs		(void)qla_tx_chksum(ha, mp, &op_code, &tcp_hdr_off);
2028250661Sdavidcs	}
2029250661Sdavidcs
2030284741Sdavidcs	if (iscsi_pdu)
2031284741Sdavidcs		ha->hw.iscsi_pkt_count++;
2032284741Sdavidcs
2033250661Sdavidcs	if (hw->tx_cntxt[txr_idx].txr_free <= (num_tx_cmds + QLA_TX_MIN_FREE)) {
2034250661Sdavidcs		qla_hw_tx_done_locked(ha, txr_idx);
2035250661Sdavidcs		if (hw->tx_cntxt[txr_idx].txr_free <=
2036250661Sdavidcs				(num_tx_cmds + QLA_TX_MIN_FREE)) {
2037250661Sdavidcs        		QL_DPRINT8(ha, (dev, "%s: (hw->txr_free <= "
2038250661Sdavidcs				"(num_tx_cmds + QLA_TX_MIN_FREE))\n",
2039250661Sdavidcs				__func__));
2040250661Sdavidcs			return (-1);
2041250661Sdavidcs		}
2042250661Sdavidcs	}
2043250661Sdavidcs
2044250661Sdavidcs	tx_cmd = &hw->tx_cntxt[txr_idx].tx_ring_base[tx_idx];
2045250661Sdavidcs
2046250661Sdavidcs        if (!(mp->m_pkthdr.csum_flags & CSUM_TSO)) {
2047250661Sdavidcs
2048250661Sdavidcs                if (nsegs > ha->hw.max_tx_segs)
2049250661Sdavidcs                        ha->hw.max_tx_segs = nsegs;
2050250661Sdavidcs
2051250661Sdavidcs                bzero((void *)tx_cmd, sizeof(q80_tx_cmd_t));
2052250661Sdavidcs
2053250661Sdavidcs                if (op_code) {
2054250661Sdavidcs                        tx_cmd->flags_opcode = op_code;
2055250661Sdavidcs                        tx_cmd->tcp_hdr_off = tcp_hdr_off;
2056250661Sdavidcs
2057250661Sdavidcs                } else {
2058250661Sdavidcs                        tx_cmd->flags_opcode = Q8_TX_CMD_OP_XMT_ETHER;
2059250661Sdavidcs                }
2060250661Sdavidcs	} else {
2061250661Sdavidcs		bcopy(&tso_cmd, tx_cmd, sizeof(q80_tx_cmd_t));
2062250661Sdavidcs		ha->tx_tso_frames++;
2063250661Sdavidcs	}
2064250661Sdavidcs
2065250661Sdavidcs	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
2066250661Sdavidcs        	tx_cmd->flags_opcode |= Q8_TX_CMD_FLAGS_VLAN_TAGGED;
2067284741Sdavidcs
2068284741Sdavidcs		if (iscsi_pdu)
2069284741Sdavidcs			eh->evl_tag |= ha->hw.user_pri_iscsi << 13;
2070284741Sdavidcs
2071250661Sdavidcs	} else if (mp->m_flags & M_VLANTAG) {
2072250661Sdavidcs
2073250661Sdavidcs		if (hdr_len) { /* TSO */
2074250661Sdavidcs			tx_cmd->flags_opcode |= (Q8_TX_CMD_FLAGS_VLAN_TAGGED |
2075250661Sdavidcs						Q8_TX_CMD_FLAGS_HW_VLAN_ID);
2076250661Sdavidcs			tx_cmd->tcp_hdr_off += ETHER_VLAN_ENCAP_LEN;
2077250661Sdavidcs		} else
2078250661Sdavidcs			tx_cmd->flags_opcode |= Q8_TX_CMD_FLAGS_HW_VLAN_ID;
2079250661Sdavidcs
2080250661Sdavidcs		ha->hw_vlan_tx_frames++;
2081250661Sdavidcs		tx_cmd->vlan_tci = mp->m_pkthdr.ether_vtag;
2082284741Sdavidcs
2083284741Sdavidcs		if (iscsi_pdu) {
2084284741Sdavidcs			tx_cmd->vlan_tci |= ha->hw.user_pri_iscsi << 13;
2085284741Sdavidcs			mp->m_pkthdr.ether_vtag = tx_cmd->vlan_tci;
2086284741Sdavidcs		}
2087250661Sdavidcs	}
2088250661Sdavidcs
2089250661Sdavidcs
2090250661Sdavidcs        tx_cmd->n_bufs = (uint8_t)nsegs;
2091250661Sdavidcs        tx_cmd->data_len_lo = (uint8_t)(total_length & 0xFF);
2092250661Sdavidcs        tx_cmd->data_len_hi = qla_host_to_le16(((uint16_t)(total_length >> 8)));
2093250661Sdavidcs	tx_cmd->cntxtid = Q8_TX_CMD_PORT_CNXTID(ha->pci_func);
2094250661Sdavidcs
2095250661Sdavidcs	c_seg = segs;
2096250661Sdavidcs
2097250661Sdavidcs	while (1) {
2098250661Sdavidcs		for (i = 0; ((i < Q8_TX_CMD_MAX_SEGMENTS) && nsegs); i++) {
2099250661Sdavidcs
2100250661Sdavidcs			switch (i) {
2101250661Sdavidcs			case 0:
2102250661Sdavidcs				tx_cmd->buf1_addr = c_seg->ds_addr;
2103250661Sdavidcs				tx_cmd->buf1_len = c_seg->ds_len;
2104250661Sdavidcs				break;
2105250661Sdavidcs
2106250661Sdavidcs			case 1:
2107250661Sdavidcs				tx_cmd->buf2_addr = c_seg->ds_addr;
2108250661Sdavidcs				tx_cmd->buf2_len = c_seg->ds_len;
2109250661Sdavidcs				break;
2110250661Sdavidcs
2111250661Sdavidcs			case 2:
2112250661Sdavidcs				tx_cmd->buf3_addr = c_seg->ds_addr;
2113250661Sdavidcs				tx_cmd->buf3_len = c_seg->ds_len;
2114250661Sdavidcs				break;
2115250661Sdavidcs
2116250661Sdavidcs			case 3:
2117250661Sdavidcs				tx_cmd->buf4_addr = c_seg->ds_addr;
2118250661Sdavidcs				tx_cmd->buf4_len = c_seg->ds_len;
2119250661Sdavidcs				break;
2120250661Sdavidcs			}
2121250661Sdavidcs
2122250661Sdavidcs			c_seg++;
2123250661Sdavidcs			nsegs--;
2124250661Sdavidcs		}
2125250661Sdavidcs
2126250661Sdavidcs		txr_next = hw->tx_cntxt[txr_idx].txr_next =
2127250661Sdavidcs			(hw->tx_cntxt[txr_idx].txr_next + 1) &
2128250661Sdavidcs				(NUM_TX_DESCRIPTORS - 1);
2129250661Sdavidcs		tx_cmd_count++;
2130250661Sdavidcs
2131250661Sdavidcs		if (!nsegs)
2132250661Sdavidcs			break;
2133250661Sdavidcs
2134250661Sdavidcs		tx_cmd = &hw->tx_cntxt[txr_idx].tx_ring_base[txr_next];
2135250661Sdavidcs		bzero((void *)tx_cmd, sizeof(q80_tx_cmd_t));
2136250661Sdavidcs	}
2137250661Sdavidcs
2138250661Sdavidcs	if (mp->m_pkthdr.csum_flags & CSUM_TSO) {
2139250661Sdavidcs
2140250661Sdavidcs		/* TSO : Copy the header in the following tx cmd descriptors */
2141250661Sdavidcs
2142250661Sdavidcs		txr_next = hw->tx_cntxt[txr_idx].txr_next;
2143250661Sdavidcs
2144250661Sdavidcs		tx_cmd = &hw->tx_cntxt[txr_idx].tx_ring_base[txr_next];
2145250661Sdavidcs		bzero((void *)tx_cmd, sizeof(q80_tx_cmd_t));
2146250661Sdavidcs
2147250661Sdavidcs		bytes = sizeof(q80_tx_cmd_t) - Q8_TX_CMD_TSO_ALIGN;
2148250661Sdavidcs		bytes = QL_MIN(bytes, hdr_len);
2149250661Sdavidcs
2150250661Sdavidcs		dst = (uint8_t *)tx_cmd + Q8_TX_CMD_TSO_ALIGN;
2151250661Sdavidcs
2152250661Sdavidcs		if (mp->m_flags & M_VLANTAG) {
2153250661Sdavidcs			/* first copy the src/dst MAC addresses */
2154250661Sdavidcs			bcopy(src, dst, (ETHER_ADDR_LEN * 2));
2155250661Sdavidcs			dst += (ETHER_ADDR_LEN * 2);
2156250661Sdavidcs			src += (ETHER_ADDR_LEN * 2);
2157250661Sdavidcs
2158250661Sdavidcs			*((uint16_t *)dst) = htons(ETHERTYPE_VLAN);
2159250661Sdavidcs			dst += 2;
2160250661Sdavidcs			*((uint16_t *)dst) = htons(mp->m_pkthdr.ether_vtag);
2161250661Sdavidcs			dst += 2;
2162250661Sdavidcs
2163250661Sdavidcs			/* bytes left in src header */
2164250661Sdavidcs			hdr_len -= ((ETHER_ADDR_LEN * 2) +
2165250661Sdavidcs					ETHER_VLAN_ENCAP_LEN);
2166250661Sdavidcs
2167250661Sdavidcs			/* bytes left in TxCmd Entry */
2168250661Sdavidcs			bytes -= ((ETHER_ADDR_LEN * 2) + ETHER_VLAN_ENCAP_LEN);
2169250661Sdavidcs
2170250661Sdavidcs
2171250661Sdavidcs			bcopy(src, dst, bytes);
2172250661Sdavidcs			src += bytes;
2173250661Sdavidcs			hdr_len -= bytes;
2174250661Sdavidcs		} else {
2175250661Sdavidcs			bcopy(src, dst, bytes);
2176250661Sdavidcs			src += bytes;
2177250661Sdavidcs			hdr_len -= bytes;
2178250661Sdavidcs		}
2179250661Sdavidcs
2180250661Sdavidcs		txr_next = hw->tx_cntxt[txr_idx].txr_next =
2181250661Sdavidcs				(hw->tx_cntxt[txr_idx].txr_next + 1) &
2182250661Sdavidcs					(NUM_TX_DESCRIPTORS - 1);
2183250661Sdavidcs		tx_cmd_count++;
2184250661Sdavidcs
2185250661Sdavidcs		while (hdr_len) {
2186250661Sdavidcs			tx_cmd = &hw->tx_cntxt[txr_idx].tx_ring_base[txr_next];
2187250661Sdavidcs			bzero((void *)tx_cmd, sizeof(q80_tx_cmd_t));
2188250661Sdavidcs
2189250661Sdavidcs			bytes = QL_MIN((sizeof(q80_tx_cmd_t)), hdr_len);
2190250661Sdavidcs
2191250661Sdavidcs			bcopy(src, tx_cmd, bytes);
2192250661Sdavidcs			src += bytes;
2193250661Sdavidcs			hdr_len -= bytes;
2194250661Sdavidcs
2195250661Sdavidcs			txr_next = hw->tx_cntxt[txr_idx].txr_next =
2196250661Sdavidcs				(hw->tx_cntxt[txr_idx].txr_next + 1) &
2197250661Sdavidcs					(NUM_TX_DESCRIPTORS - 1);
2198250661Sdavidcs			tx_cmd_count++;
2199250661Sdavidcs		}
2200250661Sdavidcs	}
2201250661Sdavidcs
2202250661Sdavidcs	hw->tx_cntxt[txr_idx].txr_free =
2203250661Sdavidcs		hw->tx_cntxt[txr_idx].txr_free - tx_cmd_count;
2204250661Sdavidcs
2205250661Sdavidcs	QL_UPDATE_TX_PRODUCER_INDEX(ha, hw->tx_cntxt[txr_idx].txr_next,\
2206250661Sdavidcs		txr_idx);
2207250661Sdavidcs       	QL_DPRINT8(ha, (dev, "%s: return\n", __func__));
2208250661Sdavidcs
2209250661Sdavidcs	return (0);
2210250661Sdavidcs}
2211250661Sdavidcs
2212250661Sdavidcs
2213284741Sdavidcs
2214284741Sdavidcs#define Q8_CONFIG_IND_TBL_SIZE	32 /* < Q8_RSS_IND_TBL_SIZE and power of 2 */
2215250661Sdavidcsstatic int
2216250661Sdavidcsqla_config_rss_ind_table(qla_host_t *ha)
2217250661Sdavidcs{
2218250661Sdavidcs	uint32_t i, count;
2219284741Sdavidcs	uint8_t rss_ind_tbl[Q8_CONFIG_IND_TBL_SIZE];
2220250661Sdavidcs
2221250661Sdavidcs
2222284741Sdavidcs	for (i = 0; i < Q8_CONFIG_IND_TBL_SIZE; i++) {
2223250661Sdavidcs		rss_ind_tbl[i] = i % ha->hw.num_sds_rings;
2224250661Sdavidcs	}
2225250661Sdavidcs
2226284741Sdavidcs	for (i = 0; i <= Q8_RSS_IND_TBL_MAX_IDX ;
2227284741Sdavidcs		i = i + Q8_CONFIG_IND_TBL_SIZE) {
2228250661Sdavidcs
2229284741Sdavidcs		if ((i + Q8_CONFIG_IND_TBL_SIZE) > Q8_RSS_IND_TBL_MAX_IDX) {
2230250661Sdavidcs			count = Q8_RSS_IND_TBL_MAX_IDX - i + 1;
2231250661Sdavidcs		} else {
2232284741Sdavidcs			count = Q8_CONFIG_IND_TBL_SIZE;
2233250661Sdavidcs		}
2234250661Sdavidcs
2235250661Sdavidcs		if (qla_set_rss_ind_table(ha, i, count, ha->hw.rcv_cntxt_id,
2236250661Sdavidcs			rss_ind_tbl))
2237250661Sdavidcs			return (-1);
2238250661Sdavidcs	}
2239250661Sdavidcs
2240250661Sdavidcs	return (0);
2241250661Sdavidcs}
2242250661Sdavidcs
2243250661Sdavidcs/*
2244250661Sdavidcs * Name: ql_del_hw_if
2245250661Sdavidcs * Function: Destroys the hardware specific entities corresponding to an
2246250661Sdavidcs *	Ethernet Interface
2247250661Sdavidcs */
2248250661Sdavidcsvoid
2249250661Sdavidcsql_del_hw_if(qla_host_t *ha)
2250250661Sdavidcs{
2251284741Sdavidcs	uint32_t i;
2252284741Sdavidcs	uint32_t num_msix;
2253250661Sdavidcs
2254284741Sdavidcs	(void)qla_stop_nic_func(ha);
2255284741Sdavidcs
2256250661Sdavidcs	qla_del_rcv_cntxt(ha);
2257250661Sdavidcs	qla_del_xmt_cntxt(ha);
2258250661Sdavidcs
2259250661Sdavidcs	if (ha->hw.flags.init_intr_cnxt) {
2260284741Sdavidcs		for (i = 0; i < ha->hw.num_sds_rings; ) {
2261284741Sdavidcs
2262284741Sdavidcs			if ((i + Q8_MAX_INTR_VECTORS) < ha->hw.num_sds_rings)
2263284741Sdavidcs				num_msix = Q8_MAX_INTR_VECTORS;
2264284741Sdavidcs			else
2265284741Sdavidcs				num_msix = ha->hw.num_sds_rings - i;
2266284741Sdavidcs			qla_config_intr_cntxt(ha, i, num_msix, 0);
2267284741Sdavidcs
2268284741Sdavidcs			i += num_msix;
2269284741Sdavidcs		}
2270284741Sdavidcs
2271250661Sdavidcs		ha->hw.flags.init_intr_cnxt = 0;
2272250661Sdavidcs	}
2273284741Sdavidcs	return;
2274250661Sdavidcs}
2275250661Sdavidcs
2276284741Sdavidcsvoid
2277284741Sdavidcsqla_confirm_9kb_enable(qla_host_t *ha)
2278284741Sdavidcs{
2279284741Sdavidcs	uint32_t supports_9kb = 0;
2280284741Sdavidcs
2281284741Sdavidcs	ha->hw.mbx_intr_mask_offset = READ_REG32(ha, Q8_MBOX_INT_MASK_MSIX);
2282284741Sdavidcs
2283284741Sdavidcs	/* Use MSI-X vector 0; Enable Firmware Mailbox Interrupt */
2284284741Sdavidcs	WRITE_REG32(ha, Q8_MBOX_INT_ENABLE, BIT_2);
2285284741Sdavidcs	WRITE_REG32(ha, ha->hw.mbx_intr_mask_offset, 0x0);
2286284741Sdavidcs
2287284741Sdavidcs	qla_get_nic_partition(ha, &supports_9kb, NULL);
2288284741Sdavidcs
2289284741Sdavidcs	if (!supports_9kb)
2290284741Sdavidcs		ha->hw.enable_9kb = 0;
2291284741Sdavidcs
2292284741Sdavidcs	return;
2293284741Sdavidcs}
2294284741Sdavidcs
2295284741Sdavidcs
2296250661Sdavidcs/*
2297250661Sdavidcs * Name: ql_init_hw_if
2298250661Sdavidcs * Function: Creates the hardware specific entities corresponding to an
2299250661Sdavidcs *	Ethernet Interface - Transmit and Receive Contexts. Sets the MAC Address
2300250661Sdavidcs *	corresponding to the interface. Enables LRO if allowed.
2301250661Sdavidcs */
2302250661Sdavidcsint
2303250661Sdavidcsql_init_hw_if(qla_host_t *ha)
2304250661Sdavidcs{
2305250661Sdavidcs	device_t	dev;
2306250661Sdavidcs	uint32_t	i;
2307250661Sdavidcs	uint8_t		bcast_mac[6];
2308250661Sdavidcs	qla_rdesc_t	*rdesc;
2309284741Sdavidcs	uint32_t	num_msix;
2310250661Sdavidcs
2311250661Sdavidcs	dev = ha->pci_dev;
2312250661Sdavidcs
2313250661Sdavidcs	for (i = 0; i < ha->hw.num_sds_rings; i++) {
2314250661Sdavidcs		bzero(ha->hw.dma_buf.sds_ring[i].dma_b,
2315250661Sdavidcs			ha->hw.dma_buf.sds_ring[i].size);
2316250661Sdavidcs	}
2317250661Sdavidcs
2318284741Sdavidcs	for (i = 0; i < ha->hw.num_sds_rings; ) {
2319250661Sdavidcs
2320284741Sdavidcs		if ((i + Q8_MAX_INTR_VECTORS) < ha->hw.num_sds_rings)
2321284741Sdavidcs			num_msix = Q8_MAX_INTR_VECTORS;
2322284741Sdavidcs		else
2323284741Sdavidcs			num_msix = ha->hw.num_sds_rings - i;
2324250661Sdavidcs
2325284741Sdavidcs		if (qla_config_intr_cntxt(ha, i, num_msix, 1)) {
2326250661Sdavidcs
2327284741Sdavidcs			if (i > 0) {
2328284741Sdavidcs
2329284741Sdavidcs				num_msix = i;
2330284741Sdavidcs
2331284741Sdavidcs				for (i = 0; i < num_msix; ) {
2332284741Sdavidcs					qla_config_intr_cntxt(ha, i,
2333284741Sdavidcs						Q8_MAX_INTR_VECTORS, 0);
2334284741Sdavidcs					i += Q8_MAX_INTR_VECTORS;
2335284741Sdavidcs				}
2336284741Sdavidcs			}
2337284741Sdavidcs			return (-1);
2338284741Sdavidcs		}
2339284741Sdavidcs
2340284741Sdavidcs		i = i + num_msix;
2341284741Sdavidcs	}
2342284741Sdavidcs
2343284741Sdavidcs        ha->hw.flags.init_intr_cnxt = 1;
2344284741Sdavidcs
2345250661Sdavidcs	/*
2346250661Sdavidcs	 * Create Receive Context
2347250661Sdavidcs	 */
2348250661Sdavidcs	if (qla_init_rcv_cntxt(ha)) {
2349250661Sdavidcs		return (-1);
2350250661Sdavidcs	}
2351250661Sdavidcs
2352250661Sdavidcs	for (i = 0; i < ha->hw.num_rds_rings; i++) {
2353250661Sdavidcs		rdesc = &ha->hw.rds[i];
2354250661Sdavidcs		rdesc->rx_next = NUM_RX_DESCRIPTORS - 2;
2355250661Sdavidcs		rdesc->rx_in = 0;
2356250661Sdavidcs		/* Update the RDS Producer Indices */
2357250661Sdavidcs		QL_UPDATE_RDS_PRODUCER_INDEX(ha, rdesc->prod_std,\
2358250661Sdavidcs			rdesc->rx_next);
2359250661Sdavidcs	}
2360250661Sdavidcs
2361250661Sdavidcs
2362250661Sdavidcs	/*
2363250661Sdavidcs	 * Create Transmit Context
2364250661Sdavidcs	 */
2365250661Sdavidcs	if (qla_init_xmt_cntxt(ha)) {
2366250661Sdavidcs		qla_del_rcv_cntxt(ha);
2367250661Sdavidcs		return (-1);
2368250661Sdavidcs	}
2369250661Sdavidcs	ha->hw.max_tx_segs = 0;
2370250661Sdavidcs
2371250661Sdavidcs	if (qla_config_mac_addr(ha, ha->hw.mac_addr, 1))
2372250661Sdavidcs		return(-1);
2373250661Sdavidcs
2374250661Sdavidcs	ha->hw.flags.unicast_mac = 1;
2375250661Sdavidcs
2376250661Sdavidcs	bcast_mac[0] = 0xFF; bcast_mac[1] = 0xFF; bcast_mac[2] = 0xFF;
2377250661Sdavidcs	bcast_mac[3] = 0xFF; bcast_mac[4] = 0xFF; bcast_mac[5] = 0xFF;
2378250661Sdavidcs
2379250661Sdavidcs	if (qla_config_mac_addr(ha, bcast_mac, 1))
2380250661Sdavidcs		return (-1);
2381250661Sdavidcs
2382250661Sdavidcs	ha->hw.flags.bcast_mac = 1;
2383250661Sdavidcs
2384250661Sdavidcs	/*
2385250661Sdavidcs	 * program any cached multicast addresses
2386250661Sdavidcs	 */
2387250661Sdavidcs	if (qla_hw_add_all_mcast(ha))
2388250661Sdavidcs		return (-1);
2389250661Sdavidcs
2390250661Sdavidcs	if (qla_config_rss(ha, ha->hw.rcv_cntxt_id))
2391250661Sdavidcs		return (-1);
2392250661Sdavidcs
2393250661Sdavidcs	if (qla_config_rss_ind_table(ha))
2394250661Sdavidcs		return (-1);
2395250661Sdavidcs
2396284741Sdavidcs	if (qla_config_intr_coalesce(ha, ha->hw.rcv_cntxt_id, 0, 1))
2397250661Sdavidcs		return (-1);
2398250661Sdavidcs
2399250661Sdavidcs	if (qla_link_event_req(ha, ha->hw.rcv_cntxt_id))
2400250661Sdavidcs		return (-1);
2401250661Sdavidcs
2402250661Sdavidcs	if (qla_config_fw_lro(ha, ha->hw.rcv_cntxt_id))
2403250661Sdavidcs		return (-1);
2404250661Sdavidcs
2405284741Sdavidcs        if (qla_init_nic_func(ha))
2406284741Sdavidcs                return (-1);
2407284741Sdavidcs
2408284741Sdavidcs        if (qla_query_fw_dcbx_caps(ha))
2409284741Sdavidcs                return (-1);
2410284741Sdavidcs
2411250661Sdavidcs	for (i = 0; i < ha->hw.num_sds_rings; i++)
2412250661Sdavidcs		QL_ENABLE_INTERRUPTS(ha, i);
2413250661Sdavidcs
2414250661Sdavidcs	return (0);
2415250661Sdavidcs}
2416250661Sdavidcs
2417250661Sdavidcsstatic int
2418284741Sdavidcsqla_map_sds_to_rds(qla_host_t *ha, uint32_t start_idx, uint32_t num_idx)
2419250661Sdavidcs{
2420250661Sdavidcs        device_t                dev = ha->pci_dev;
2421250661Sdavidcs        q80_rq_map_sds_to_rds_t *map_rings;
2422284741Sdavidcs	q80_rsp_map_sds_to_rds_t *map_rings_rsp;
2423250661Sdavidcs        uint32_t                i, err;
2424250661Sdavidcs        qla_hw_t                *hw = &ha->hw;
2425250661Sdavidcs
2426250661Sdavidcs        map_rings = (q80_rq_map_sds_to_rds_t *)ha->hw.mbox;
2427250661Sdavidcs        bzero(map_rings, sizeof(q80_rq_map_sds_to_rds_t));
2428250661Sdavidcs
2429250661Sdavidcs        map_rings->opcode = Q8_MBX_MAP_SDS_TO_RDS;
2430250661Sdavidcs        map_rings->count_version = (sizeof (q80_rq_map_sds_to_rds_t) >> 2);
2431250661Sdavidcs        map_rings->count_version |= Q8_MBX_CMD_VERSION;
2432250661Sdavidcs
2433250661Sdavidcs        map_rings->cntxt_id = hw->rcv_cntxt_id;
2434284741Sdavidcs        map_rings->num_rings = num_idx;
2435250661Sdavidcs
2436284741Sdavidcs	for (i = 0; i < num_idx; i++) {
2437284741Sdavidcs		map_rings->sds_rds[i].sds_ring = i + start_idx;
2438284741Sdavidcs		map_rings->sds_rds[i].rds_ring = i + start_idx;
2439284741Sdavidcs	}
2440250661Sdavidcs
2441250661Sdavidcs        if (qla_mbx_cmd(ha, (uint32_t *)map_rings,
2442250661Sdavidcs                (sizeof (q80_rq_map_sds_to_rds_t) >> 2),
2443250661Sdavidcs                ha->hw.mbox, (sizeof(q80_rsp_add_rcv_rings_t) >> 2), 0)) {
2444250661Sdavidcs                device_printf(dev, "%s: failed0\n", __func__);
2445250661Sdavidcs                return (-1);
2446250661Sdavidcs        }
2447250661Sdavidcs
2448284741Sdavidcs        map_rings_rsp = (q80_rsp_map_sds_to_rds_t *)ha->hw.mbox;
2449250661Sdavidcs
2450250661Sdavidcs        err = Q8_MBX_RSP_STATUS(map_rings_rsp->regcnt_status);
2451250661Sdavidcs
2452250661Sdavidcs        if (err) {
2453250661Sdavidcs                device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err);
2454250661Sdavidcs                return (-1);
2455250661Sdavidcs        }
2456250661Sdavidcs
2457250661Sdavidcs        return (0);
2458250661Sdavidcs}
2459250661Sdavidcs
2460250661Sdavidcs/*
2461250661Sdavidcs * Name: qla_init_rcv_cntxt
2462250661Sdavidcs * Function: Creates the Receive Context.
2463250661Sdavidcs */
2464250661Sdavidcsstatic int
2465250661Sdavidcsqla_init_rcv_cntxt(qla_host_t *ha)
2466250661Sdavidcs{
2467250661Sdavidcs	q80_rq_rcv_cntxt_t	*rcntxt;
2468250661Sdavidcs	q80_rsp_rcv_cntxt_t	*rcntxt_rsp;
2469250661Sdavidcs	q80_stat_desc_t		*sdesc;
2470250661Sdavidcs	int			i, j;
2471250661Sdavidcs        qla_hw_t		*hw = &ha->hw;
2472250661Sdavidcs	device_t		dev;
2473250661Sdavidcs	uint32_t		err;
2474250661Sdavidcs	uint32_t		rcntxt_sds_rings;
2475250661Sdavidcs	uint32_t		rcntxt_rds_rings;
2476284741Sdavidcs	uint32_t		max_idx;
2477250661Sdavidcs
2478250661Sdavidcs	dev = ha->pci_dev;
2479250661Sdavidcs
2480250661Sdavidcs	/*
2481250661Sdavidcs	 * Create Receive Context
2482250661Sdavidcs	 */
2483250661Sdavidcs
2484250661Sdavidcs	for (i = 0; i < hw->num_sds_rings; i++) {
2485250661Sdavidcs		sdesc = (q80_stat_desc_t *)&hw->sds[i].sds_ring_base[0];
2486250661Sdavidcs
2487250661Sdavidcs		for (j = 0; j < NUM_STATUS_DESCRIPTORS; j++) {
2488250661Sdavidcs			sdesc->data[0] = 1ULL;
2489250661Sdavidcs			sdesc->data[1] = 1ULL;
2490250661Sdavidcs		}
2491250661Sdavidcs	}
2492250661Sdavidcs
2493250661Sdavidcs	rcntxt_sds_rings = hw->num_sds_rings;
2494250661Sdavidcs	if (hw->num_sds_rings > MAX_RCNTXT_SDS_RINGS)
2495250661Sdavidcs		rcntxt_sds_rings = MAX_RCNTXT_SDS_RINGS;
2496250661Sdavidcs
2497250661Sdavidcs	rcntxt_rds_rings = hw->num_rds_rings;
2498250661Sdavidcs
2499250661Sdavidcs	if (hw->num_rds_rings > MAX_RDS_RING_SETS)
2500250661Sdavidcs		rcntxt_rds_rings = MAX_RDS_RING_SETS;
2501250661Sdavidcs
2502250661Sdavidcs	rcntxt = (q80_rq_rcv_cntxt_t *)ha->hw.mbox;
2503250661Sdavidcs	bzero(rcntxt, (sizeof (q80_rq_rcv_cntxt_t)));
2504250661Sdavidcs
2505250661Sdavidcs	rcntxt->opcode = Q8_MBX_CREATE_RX_CNTXT;
2506250661Sdavidcs	rcntxt->count_version = (sizeof (q80_rq_rcv_cntxt_t) >> 2);
2507250661Sdavidcs	rcntxt->count_version |= Q8_MBX_CMD_VERSION;
2508250661Sdavidcs
2509250661Sdavidcs	rcntxt->cap0 = Q8_RCV_CNTXT_CAP0_BASEFW |
2510250661Sdavidcs			Q8_RCV_CNTXT_CAP0_LRO |
2511250661Sdavidcs			Q8_RCV_CNTXT_CAP0_HW_LRO |
2512250661Sdavidcs			Q8_RCV_CNTXT_CAP0_RSS |
2513250661Sdavidcs			Q8_RCV_CNTXT_CAP0_SGL_LRO;
2514250661Sdavidcs
2515284741Sdavidcs	if (ha->hw.enable_9kb)
2516284741Sdavidcs		rcntxt->cap0 |= Q8_RCV_CNTXT_CAP0_SINGLE_JUMBO;
2517284741Sdavidcs	else
2518284741Sdavidcs		rcntxt->cap0 |= Q8_RCV_CNTXT_CAP0_SGL_JUMBO;
2519284741Sdavidcs
2520250661Sdavidcs	if (ha->hw.num_rds_rings > 1) {
2521250661Sdavidcs		rcntxt->nrds_sets_rings = rcntxt_rds_rings | (1 << 5);
2522250661Sdavidcs		rcntxt->cap0 |= Q8_RCV_CNTXT_CAP0_MULTI_RDS;
2523250661Sdavidcs	} else
2524250661Sdavidcs		rcntxt->nrds_sets_rings = 0x1 | (1 << 5);
2525250661Sdavidcs
2526250661Sdavidcs	rcntxt->nsds_rings = rcntxt_sds_rings;
2527250661Sdavidcs
2528250661Sdavidcs	rcntxt->rds_producer_mode = Q8_RCV_CNTXT_RDS_PROD_MODE_UNIQUE;
2529250661Sdavidcs
2530250661Sdavidcs	rcntxt->rcv_vpid = 0;
2531250661Sdavidcs
2532250661Sdavidcs	for (i = 0; i <  rcntxt_sds_rings; i++) {
2533250661Sdavidcs		rcntxt->sds[i].paddr =
2534250661Sdavidcs			qla_host_to_le64(hw->dma_buf.sds_ring[i].dma_addr);
2535250661Sdavidcs		rcntxt->sds[i].size =
2536250661Sdavidcs			qla_host_to_le32(NUM_STATUS_DESCRIPTORS);
2537250661Sdavidcs		if (ha->msix_count == 2) {
2538250661Sdavidcs			rcntxt->sds[i].intr_id =
2539250661Sdavidcs				qla_host_to_le16(hw->intr_id[0]);
2540250661Sdavidcs			rcntxt->sds[i].intr_src_bit = qla_host_to_le16((i));
2541250661Sdavidcs		} else {
2542250661Sdavidcs			rcntxt->sds[i].intr_id =
2543250661Sdavidcs				qla_host_to_le16(hw->intr_id[i]);
2544250661Sdavidcs			rcntxt->sds[i].intr_src_bit = qla_host_to_le16(0);
2545250661Sdavidcs		}
2546250661Sdavidcs	}
2547250661Sdavidcs
2548250661Sdavidcs	for (i = 0; i <  rcntxt_rds_rings; i++) {
2549250661Sdavidcs		rcntxt->rds[i].paddr_std =
2550250661Sdavidcs			qla_host_to_le64(hw->dma_buf.rds_ring[i].dma_addr);
2551284741Sdavidcs
2552284741Sdavidcs		if (ha->hw.enable_9kb)
2553284741Sdavidcs			rcntxt->rds[i].std_bsize =
2554284741Sdavidcs				qla_host_to_le64(MJUM9BYTES);
2555284741Sdavidcs		else
2556284741Sdavidcs			rcntxt->rds[i].std_bsize = qla_host_to_le64(MCLBYTES);
2557284741Sdavidcs
2558250661Sdavidcs		rcntxt->rds[i].std_nentries =
2559250661Sdavidcs			qla_host_to_le32(NUM_RX_DESCRIPTORS);
2560250661Sdavidcs	}
2561250661Sdavidcs
2562250661Sdavidcs        if (qla_mbx_cmd(ha, (uint32_t *)rcntxt,
2563250661Sdavidcs		(sizeof (q80_rq_rcv_cntxt_t) >> 2),
2564250661Sdavidcs                ha->hw.mbox, (sizeof(q80_rsp_rcv_cntxt_t) >> 2), 0)) {
2565250661Sdavidcs                device_printf(dev, "%s: failed0\n", __func__);
2566250661Sdavidcs                return (-1);
2567250661Sdavidcs        }
2568250661Sdavidcs
2569250661Sdavidcs        rcntxt_rsp = (q80_rsp_rcv_cntxt_t *)ha->hw.mbox;
2570250661Sdavidcs
2571250661Sdavidcs        err = Q8_MBX_RSP_STATUS(rcntxt_rsp->regcnt_status);
2572250661Sdavidcs
2573250661Sdavidcs        if (err) {
2574250661Sdavidcs                device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err);
2575250661Sdavidcs                return (-1);
2576250661Sdavidcs        }
2577250661Sdavidcs
2578250661Sdavidcs	for (i = 0; i <  rcntxt_sds_rings; i++) {
2579250661Sdavidcs		hw->sds[i].sds_consumer = rcntxt_rsp->sds_cons[i];
2580250661Sdavidcs	}
2581250661Sdavidcs
2582250661Sdavidcs	for (i = 0; i <  rcntxt_rds_rings; i++) {
2583250661Sdavidcs		hw->rds[i].prod_std = rcntxt_rsp->rds[i].prod_std;
2584250661Sdavidcs	}
2585250661Sdavidcs
2586250661Sdavidcs	hw->rcv_cntxt_id = rcntxt_rsp->cntxt_id;
2587250661Sdavidcs
2588250661Sdavidcs	ha->hw.flags.init_rx_cnxt = 1;
2589250661Sdavidcs
2590250661Sdavidcs	if (hw->num_sds_rings > MAX_RCNTXT_SDS_RINGS) {
2591284741Sdavidcs
2592284741Sdavidcs		for (i = MAX_RCNTXT_SDS_RINGS; i < hw->num_sds_rings;) {
2593284741Sdavidcs
2594284741Sdavidcs			if ((i + MAX_RCNTXT_SDS_RINGS) < hw->num_sds_rings)
2595284741Sdavidcs				max_idx = MAX_RCNTXT_SDS_RINGS;
2596284741Sdavidcs			else
2597284741Sdavidcs				max_idx = hw->num_sds_rings - i;
2598284741Sdavidcs
2599284741Sdavidcs			err = qla_add_rcv_rings(ha, i, max_idx);
2600284741Sdavidcs			if (err)
2601284741Sdavidcs				return -1;
2602284741Sdavidcs
2603284741Sdavidcs			i += max_idx;
2604284741Sdavidcs		}
2605250661Sdavidcs	}
2606250661Sdavidcs
2607284741Sdavidcs	if (hw->num_rds_rings > 1) {
2608284741Sdavidcs
2609284741Sdavidcs		for (i = 0; i < hw->num_rds_rings; ) {
2610284741Sdavidcs
2611284741Sdavidcs			if ((i + MAX_SDS_TO_RDS_MAP) < hw->num_rds_rings)
2612284741Sdavidcs				max_idx = MAX_SDS_TO_RDS_MAP;
2613284741Sdavidcs			else
2614284741Sdavidcs				max_idx = hw->num_rds_rings - i;
2615284741Sdavidcs
2616284741Sdavidcs			err = qla_map_sds_to_rds(ha, i, max_idx);
2617284741Sdavidcs			if (err)
2618284741Sdavidcs				return -1;
2619284741Sdavidcs
2620284741Sdavidcs			i += max_idx;
2621284741Sdavidcs		}
2622250661Sdavidcs	}
2623250661Sdavidcs
2624250661Sdavidcs	return (0);
2625250661Sdavidcs}
2626250661Sdavidcs
2627250661Sdavidcsstatic int
2628284741Sdavidcsqla_add_rcv_rings(qla_host_t *ha, uint32_t sds_idx, uint32_t nsds)
2629250661Sdavidcs{
2630250661Sdavidcs	device_t		dev = ha->pci_dev;
2631250661Sdavidcs	q80_rq_add_rcv_rings_t	*add_rcv;
2632250661Sdavidcs	q80_rsp_add_rcv_rings_t	*add_rcv_rsp;
2633250661Sdavidcs	uint32_t		i,j, err;
2634250661Sdavidcs        qla_hw_t		*hw = &ha->hw;
2635250661Sdavidcs
2636250661Sdavidcs	add_rcv = (q80_rq_add_rcv_rings_t *)ha->hw.mbox;
2637250661Sdavidcs	bzero(add_rcv, sizeof (q80_rq_add_rcv_rings_t));
2638250661Sdavidcs
2639250661Sdavidcs	add_rcv->opcode = Q8_MBX_ADD_RX_RINGS;
2640250661Sdavidcs	add_rcv->count_version = (sizeof (q80_rq_add_rcv_rings_t) >> 2);
2641250661Sdavidcs	add_rcv->count_version |= Q8_MBX_CMD_VERSION;
2642250661Sdavidcs
2643284741Sdavidcs	add_rcv->nrds_sets_rings = nsds | (1 << 5);
2644250661Sdavidcs	add_rcv->nsds_rings = nsds;
2645250661Sdavidcs	add_rcv->cntxt_id = hw->rcv_cntxt_id;
2646250661Sdavidcs
2647250661Sdavidcs        for (i = 0; i <  nsds; i++) {
2648250661Sdavidcs
2649250661Sdavidcs		j = i + sds_idx;
2650250661Sdavidcs
2651250661Sdavidcs                add_rcv->sds[i].paddr =
2652250661Sdavidcs                        qla_host_to_le64(hw->dma_buf.sds_ring[j].dma_addr);
2653250661Sdavidcs
2654250661Sdavidcs                add_rcv->sds[i].size =
2655250661Sdavidcs                        qla_host_to_le32(NUM_STATUS_DESCRIPTORS);
2656250661Sdavidcs
2657250661Sdavidcs                if (ha->msix_count == 2) {
2658250661Sdavidcs                        add_rcv->sds[i].intr_id =
2659250661Sdavidcs                                qla_host_to_le16(hw->intr_id[0]);
2660250661Sdavidcs                        add_rcv->sds[i].intr_src_bit = qla_host_to_le16(j);
2661250661Sdavidcs                } else {
2662250661Sdavidcs                        add_rcv->sds[i].intr_id =
2663250661Sdavidcs                                qla_host_to_le16(hw->intr_id[j]);
2664250661Sdavidcs                        add_rcv->sds[i].intr_src_bit = qla_host_to_le16(0);
2665250661Sdavidcs                }
2666250661Sdavidcs
2667250661Sdavidcs        }
2668284741Sdavidcs        for (i = 0; (i <  nsds); i++) {
2669250661Sdavidcs                j = i + sds_idx;
2670284741Sdavidcs
2671250661Sdavidcs                add_rcv->rds[i].paddr_std =
2672250661Sdavidcs                        qla_host_to_le64(hw->dma_buf.rds_ring[j].dma_addr);
2673284741Sdavidcs
2674284741Sdavidcs		if (ha->hw.enable_9kb)
2675284741Sdavidcs			add_rcv->rds[i].std_bsize =
2676284741Sdavidcs				qla_host_to_le64(MJUM9BYTES);
2677284741Sdavidcs		else
2678284741Sdavidcs                	add_rcv->rds[i].std_bsize = qla_host_to_le64(MCLBYTES);
2679284741Sdavidcs
2680250661Sdavidcs                add_rcv->rds[i].std_nentries =
2681250661Sdavidcs                        qla_host_to_le32(NUM_RX_DESCRIPTORS);
2682250661Sdavidcs        }
2683250661Sdavidcs
2684250661Sdavidcs
2685250661Sdavidcs        if (qla_mbx_cmd(ha, (uint32_t *)add_rcv,
2686250661Sdavidcs		(sizeof (q80_rq_add_rcv_rings_t) >> 2),
2687250661Sdavidcs                ha->hw.mbox, (sizeof(q80_rsp_add_rcv_rings_t) >> 2), 0)) {
2688250661Sdavidcs                device_printf(dev, "%s: failed0\n", __func__);
2689250661Sdavidcs                return (-1);
2690250661Sdavidcs        }
2691250661Sdavidcs
2692250661Sdavidcs        add_rcv_rsp = (q80_rsp_add_rcv_rings_t *)ha->hw.mbox;
2693250661Sdavidcs
2694250661Sdavidcs        err = Q8_MBX_RSP_STATUS(add_rcv_rsp->regcnt_status);
2695250661Sdavidcs
2696250661Sdavidcs        if (err) {
2697250661Sdavidcs                device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err);
2698250661Sdavidcs                return (-1);
2699250661Sdavidcs        }
2700250661Sdavidcs
2701284741Sdavidcs	for (i = 0; i < nsds; i++) {
2702284741Sdavidcs		hw->sds[(i + sds_idx)].sds_consumer = add_rcv_rsp->sds_cons[i];
2703250661Sdavidcs	}
2704284741Sdavidcs
2705284741Sdavidcs	for (i = 0; i < nsds; i++) {
2706284741Sdavidcs		hw->rds[(i + sds_idx)].prod_std = add_rcv_rsp->rds[i].prod_std;
2707250661Sdavidcs	}
2708284741Sdavidcs
2709250661Sdavidcs	return (0);
2710250661Sdavidcs}
2711250661Sdavidcs
2712250661Sdavidcs/*
2713250661Sdavidcs * Name: qla_del_rcv_cntxt
2714250661Sdavidcs * Function: Destroys the Receive Context.
2715250661Sdavidcs */
2716250661Sdavidcsstatic void
2717250661Sdavidcsqla_del_rcv_cntxt(qla_host_t *ha)
2718250661Sdavidcs{
2719250661Sdavidcs	device_t			dev = ha->pci_dev;
2720250661Sdavidcs	q80_rcv_cntxt_destroy_t		*rcntxt;
2721250661Sdavidcs	q80_rcv_cntxt_destroy_rsp_t	*rcntxt_rsp;
2722250661Sdavidcs	uint32_t			err;
2723250661Sdavidcs	uint8_t				bcast_mac[6];
2724250661Sdavidcs
2725250661Sdavidcs	if (!ha->hw.flags.init_rx_cnxt)
2726250661Sdavidcs		return;
2727250661Sdavidcs
2728250661Sdavidcs	if (qla_hw_del_all_mcast(ha))
2729250661Sdavidcs		return;
2730250661Sdavidcs
2731250661Sdavidcs	if (ha->hw.flags.bcast_mac) {
2732250661Sdavidcs
2733250661Sdavidcs		bcast_mac[0] = 0xFF; bcast_mac[1] = 0xFF; bcast_mac[2] = 0xFF;
2734250661Sdavidcs		bcast_mac[3] = 0xFF; bcast_mac[4] = 0xFF; bcast_mac[5] = 0xFF;
2735250661Sdavidcs
2736250661Sdavidcs		if (qla_config_mac_addr(ha, bcast_mac, 0))
2737250661Sdavidcs			return;
2738250661Sdavidcs		ha->hw.flags.bcast_mac = 0;
2739250661Sdavidcs
2740250661Sdavidcs	}
2741250661Sdavidcs
2742250661Sdavidcs	if (ha->hw.flags.unicast_mac) {
2743250661Sdavidcs		if (qla_config_mac_addr(ha, ha->hw.mac_addr, 0))
2744250661Sdavidcs			return;
2745250661Sdavidcs		ha->hw.flags.unicast_mac = 0;
2746250661Sdavidcs	}
2747250661Sdavidcs
2748250661Sdavidcs	rcntxt = (q80_rcv_cntxt_destroy_t *)ha->hw.mbox;
2749250661Sdavidcs	bzero(rcntxt, (sizeof (q80_rcv_cntxt_destroy_t)));
2750250661Sdavidcs
2751250661Sdavidcs	rcntxt->opcode = Q8_MBX_DESTROY_RX_CNTXT;
2752250661Sdavidcs	rcntxt->count_version = (sizeof (q80_rcv_cntxt_destroy_t) >> 2);
2753250661Sdavidcs	rcntxt->count_version |= Q8_MBX_CMD_VERSION;
2754250661Sdavidcs
2755250661Sdavidcs	rcntxt->cntxt_id = ha->hw.rcv_cntxt_id;
2756250661Sdavidcs
2757250661Sdavidcs        if (qla_mbx_cmd(ha, (uint32_t *)rcntxt,
2758250661Sdavidcs		(sizeof (q80_rcv_cntxt_destroy_t) >> 2),
2759250661Sdavidcs                ha->hw.mbox, (sizeof(q80_rcv_cntxt_destroy_rsp_t) >> 2), 0)) {
2760250661Sdavidcs                device_printf(dev, "%s: failed0\n", __func__);
2761250661Sdavidcs                return;
2762250661Sdavidcs        }
2763250661Sdavidcs        rcntxt_rsp = (q80_rcv_cntxt_destroy_rsp_t *)ha->hw.mbox;
2764250661Sdavidcs
2765250661Sdavidcs        err = Q8_MBX_RSP_STATUS(rcntxt_rsp->regcnt_status);
2766250661Sdavidcs
2767250661Sdavidcs        if (err) {
2768250661Sdavidcs                device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err);
2769250661Sdavidcs        }
2770250661Sdavidcs
2771250661Sdavidcs	ha->hw.flags.init_rx_cnxt = 0;
2772250661Sdavidcs	return;
2773250661Sdavidcs}
2774250661Sdavidcs
2775250661Sdavidcs/*
2776250661Sdavidcs * Name: qla_init_xmt_cntxt
2777250661Sdavidcs * Function: Creates the Transmit Context.
2778250661Sdavidcs */
2779250661Sdavidcsstatic int
2780250661Sdavidcsqla_init_xmt_cntxt_i(qla_host_t *ha, uint32_t txr_idx)
2781250661Sdavidcs{
2782250661Sdavidcs	device_t		dev;
2783250661Sdavidcs        qla_hw_t		*hw = &ha->hw;
2784250661Sdavidcs	q80_rq_tx_cntxt_t	*tcntxt;
2785250661Sdavidcs	q80_rsp_tx_cntxt_t	*tcntxt_rsp;
2786250661Sdavidcs	uint32_t		err;
2787250661Sdavidcs	qla_hw_tx_cntxt_t       *hw_tx_cntxt;
2788250661Sdavidcs
2789250661Sdavidcs	hw_tx_cntxt = &hw->tx_cntxt[txr_idx];
2790250661Sdavidcs
2791250661Sdavidcs	dev = ha->pci_dev;
2792250661Sdavidcs
2793250661Sdavidcs	/*
2794250661Sdavidcs	 * Create Transmit Context
2795250661Sdavidcs	 */
2796250661Sdavidcs	tcntxt = (q80_rq_tx_cntxt_t *)ha->hw.mbox;
2797250661Sdavidcs	bzero(tcntxt, (sizeof (q80_rq_tx_cntxt_t)));
2798250661Sdavidcs
2799250661Sdavidcs	tcntxt->opcode = Q8_MBX_CREATE_TX_CNTXT;
2800250661Sdavidcs	tcntxt->count_version = (sizeof (q80_rq_tx_cntxt_t) >> 2);
2801250661Sdavidcs	tcntxt->count_version |= Q8_MBX_CMD_VERSION;
2802250661Sdavidcs
2803284741Sdavidcs#ifdef QL_ENABLE_ISCSI_TLV
2804284741Sdavidcs
2805284741Sdavidcs	tcntxt->cap0 = Q8_TX_CNTXT_CAP0_BASEFW | Q8_TX_CNTXT_CAP0_LSO |
2806284741Sdavidcs				Q8_TX_CNTXT_CAP0_TC;
2807284741Sdavidcs
2808284741Sdavidcs	if (txr_idx >= (ha->hw.num_tx_rings >> 1)) {
2809284741Sdavidcs		tcntxt->traffic_class = 1;
2810284741Sdavidcs	}
2811284741Sdavidcs
2812284741Sdavidcs#else
2813284741Sdavidcs
2814250661Sdavidcs	tcntxt->cap0 = Q8_TX_CNTXT_CAP0_BASEFW | Q8_TX_CNTXT_CAP0_LSO;
2815250661Sdavidcs
2816284741Sdavidcs#endif /* #ifdef QL_ENABLE_ISCSI_TLV */
2817284741Sdavidcs
2818250661Sdavidcs	tcntxt->ntx_rings = 1;
2819250661Sdavidcs
2820250661Sdavidcs	tcntxt->tx_ring[0].paddr =
2821250661Sdavidcs		qla_host_to_le64(hw_tx_cntxt->tx_ring_paddr);
2822250661Sdavidcs	tcntxt->tx_ring[0].tx_consumer =
2823250661Sdavidcs		qla_host_to_le64(hw_tx_cntxt->tx_cons_paddr);
2824250661Sdavidcs	tcntxt->tx_ring[0].nentries = qla_host_to_le16(NUM_TX_DESCRIPTORS);
2825250661Sdavidcs
2826250661Sdavidcs	tcntxt->tx_ring[0].intr_id = qla_host_to_le16(hw->intr_id[0]);
2827250661Sdavidcs	tcntxt->tx_ring[0].intr_src_bit = qla_host_to_le16(0);
2828250661Sdavidcs
2829250661Sdavidcs
2830250661Sdavidcs	hw_tx_cntxt->txr_free = NUM_TX_DESCRIPTORS;
2831250661Sdavidcs	hw_tx_cntxt->txr_next = hw_tx_cntxt->txr_comp = 0;
2832250661Sdavidcs
2833250661Sdavidcs        if (qla_mbx_cmd(ha, (uint32_t *)tcntxt,
2834250661Sdavidcs		(sizeof (q80_rq_tx_cntxt_t) >> 2),
2835250661Sdavidcs                ha->hw.mbox,
2836250661Sdavidcs		(sizeof(q80_rsp_tx_cntxt_t) >> 2), 0)) {
2837250661Sdavidcs                device_printf(dev, "%s: failed0\n", __func__);
2838250661Sdavidcs                return (-1);
2839250661Sdavidcs        }
2840250661Sdavidcs        tcntxt_rsp = (q80_rsp_tx_cntxt_t *)ha->hw.mbox;
2841250661Sdavidcs
2842250661Sdavidcs        err = Q8_MBX_RSP_STATUS(tcntxt_rsp->regcnt_status);
2843250661Sdavidcs
2844250661Sdavidcs        if (err) {
2845250661Sdavidcs                device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err);
2846250661Sdavidcs		return -1;
2847250661Sdavidcs        }
2848250661Sdavidcs
2849250661Sdavidcs	hw_tx_cntxt->tx_prod_reg = tcntxt_rsp->tx_ring[0].prod_index;
2850250661Sdavidcs	hw_tx_cntxt->tx_cntxt_id = tcntxt_rsp->tx_ring[0].cntxt_id;
2851250661Sdavidcs
2852284741Sdavidcs	if (qla_config_intr_coalesce(ha, hw_tx_cntxt->tx_cntxt_id, 0, 0))
2853284741Sdavidcs		return (-1);
2854284741Sdavidcs
2855250661Sdavidcs	return (0);
2856250661Sdavidcs}
2857250661Sdavidcs
2858250661Sdavidcs
2859250661Sdavidcs/*
2860250661Sdavidcs * Name: qla_del_xmt_cntxt
2861250661Sdavidcs * Function: Destroys the Transmit Context.
2862250661Sdavidcs */
2863250661Sdavidcsstatic int
2864250661Sdavidcsqla_del_xmt_cntxt_i(qla_host_t *ha, uint32_t txr_idx)
2865250661Sdavidcs{
2866250661Sdavidcs	device_t			dev = ha->pci_dev;
2867250661Sdavidcs	q80_tx_cntxt_destroy_t		*tcntxt;
2868250661Sdavidcs	q80_tx_cntxt_destroy_rsp_t	*tcntxt_rsp;
2869250661Sdavidcs	uint32_t			err;
2870250661Sdavidcs
2871250661Sdavidcs	tcntxt = (q80_tx_cntxt_destroy_t *)ha->hw.mbox;
2872250661Sdavidcs	bzero(tcntxt, (sizeof (q80_tx_cntxt_destroy_t)));
2873250661Sdavidcs
2874250661Sdavidcs	tcntxt->opcode = Q8_MBX_DESTROY_TX_CNTXT;
2875250661Sdavidcs	tcntxt->count_version = (sizeof (q80_tx_cntxt_destroy_t) >> 2);
2876250661Sdavidcs	tcntxt->count_version |= Q8_MBX_CMD_VERSION;
2877250661Sdavidcs
2878250661Sdavidcs	tcntxt->cntxt_id = ha->hw.tx_cntxt[txr_idx].tx_cntxt_id;
2879250661Sdavidcs
2880250661Sdavidcs        if (qla_mbx_cmd(ha, (uint32_t *)tcntxt,
2881250661Sdavidcs		(sizeof (q80_tx_cntxt_destroy_t) >> 2),
2882250661Sdavidcs                ha->hw.mbox, (sizeof (q80_tx_cntxt_destroy_rsp_t) >> 2), 0)) {
2883250661Sdavidcs                device_printf(dev, "%s: failed0\n", __func__);
2884250661Sdavidcs                return (-1);
2885250661Sdavidcs        }
2886250661Sdavidcs        tcntxt_rsp = (q80_tx_cntxt_destroy_rsp_t *)ha->hw.mbox;
2887250661Sdavidcs
2888250661Sdavidcs        err = Q8_MBX_RSP_STATUS(tcntxt_rsp->regcnt_status);
2889250661Sdavidcs
2890250661Sdavidcs        if (err) {
2891250661Sdavidcs                device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err);
2892250661Sdavidcs		return (-1);
2893250661Sdavidcs        }
2894250661Sdavidcs
2895250661Sdavidcs	return (0);
2896250661Sdavidcs}
2897250661Sdavidcsstatic void
2898250661Sdavidcsqla_del_xmt_cntxt(qla_host_t *ha)
2899250661Sdavidcs{
2900250661Sdavidcs	uint32_t i;
2901250661Sdavidcs
2902250661Sdavidcs	if (!ha->hw.flags.init_tx_cnxt)
2903250661Sdavidcs		return;
2904250661Sdavidcs
2905250661Sdavidcs	for (i = 0; i < ha->hw.num_tx_rings; i++) {
2906250661Sdavidcs		if (qla_del_xmt_cntxt_i(ha, i))
2907250661Sdavidcs			break;
2908250661Sdavidcs	}
2909250661Sdavidcs	ha->hw.flags.init_tx_cnxt = 0;
2910250661Sdavidcs}
2911250661Sdavidcs
2912250661Sdavidcsstatic int
2913250661Sdavidcsqla_init_xmt_cntxt(qla_host_t *ha)
2914250661Sdavidcs{
2915250661Sdavidcs	uint32_t i, j;
2916250661Sdavidcs
2917250661Sdavidcs	for (i = 0; i < ha->hw.num_tx_rings; i++) {
2918250661Sdavidcs		if (qla_init_xmt_cntxt_i(ha, i) != 0) {
2919250661Sdavidcs			for (j = 0; j < i; j++)
2920250661Sdavidcs				qla_del_xmt_cntxt_i(ha, j);
2921250661Sdavidcs			return (-1);
2922250661Sdavidcs		}
2923250661Sdavidcs	}
2924250661Sdavidcs	ha->hw.flags.init_tx_cnxt = 1;
2925250661Sdavidcs	return (0);
2926250661Sdavidcs}
2927250661Sdavidcs
2928250661Sdavidcsstatic int
2929250661Sdavidcsqla_hw_add_all_mcast(qla_host_t *ha)
2930250661Sdavidcs{
2931250661Sdavidcs	int i, nmcast;
2932250661Sdavidcs
2933250661Sdavidcs	nmcast = ha->hw.nmcast;
2934250661Sdavidcs
2935250661Sdavidcs	for (i = 0 ; ((i < Q8_MAX_NUM_MULTICAST_ADDRS) && nmcast); i++) {
2936250661Sdavidcs		if ((ha->hw.mcast[i].addr[0] != 0) ||
2937250661Sdavidcs			(ha->hw.mcast[i].addr[1] != 0) ||
2938250661Sdavidcs			(ha->hw.mcast[i].addr[2] != 0) ||
2939250661Sdavidcs			(ha->hw.mcast[i].addr[3] != 0) ||
2940250661Sdavidcs			(ha->hw.mcast[i].addr[4] != 0) ||
2941250661Sdavidcs			(ha->hw.mcast[i].addr[5] != 0)) {
2942250661Sdavidcs
2943250661Sdavidcs			if (qla_config_mac_addr(ha, ha->hw.mcast[i].addr, 1)) {
2944250661Sdavidcs                		device_printf(ha->pci_dev, "%s: failed\n",
2945250661Sdavidcs					__func__);
2946250661Sdavidcs				return (-1);
2947250661Sdavidcs			}
2948250661Sdavidcs
2949250661Sdavidcs			nmcast--;
2950250661Sdavidcs		}
2951250661Sdavidcs	}
2952250661Sdavidcs	return 0;
2953250661Sdavidcs}
2954250661Sdavidcs
2955250661Sdavidcsstatic int
2956250661Sdavidcsqla_hw_del_all_mcast(qla_host_t *ha)
2957250661Sdavidcs{
2958250661Sdavidcs	int i, nmcast;
2959250661Sdavidcs
2960250661Sdavidcs	nmcast = ha->hw.nmcast;
2961250661Sdavidcs
2962250661Sdavidcs	for (i = 0 ; ((i < Q8_MAX_NUM_MULTICAST_ADDRS) && nmcast); i++) {
2963250661Sdavidcs		if ((ha->hw.mcast[i].addr[0] != 0) ||
2964250661Sdavidcs			(ha->hw.mcast[i].addr[1] != 0) ||
2965250661Sdavidcs			(ha->hw.mcast[i].addr[2] != 0) ||
2966250661Sdavidcs			(ha->hw.mcast[i].addr[3] != 0) ||
2967250661Sdavidcs			(ha->hw.mcast[i].addr[4] != 0) ||
2968250661Sdavidcs			(ha->hw.mcast[i].addr[5] != 0)) {
2969250661Sdavidcs
2970250661Sdavidcs			if (qla_config_mac_addr(ha, ha->hw.mcast[i].addr, 0))
2971250661Sdavidcs				return (-1);
2972250661Sdavidcs
2973250661Sdavidcs			nmcast--;
2974250661Sdavidcs		}
2975250661Sdavidcs	}
2976250661Sdavidcs	return 0;
2977250661Sdavidcs}
2978250661Sdavidcs
2979250661Sdavidcsstatic int
2980250661Sdavidcsqla_hw_add_mcast(qla_host_t *ha, uint8_t *mta)
2981250661Sdavidcs{
2982250661Sdavidcs	int i;
2983250661Sdavidcs
2984250661Sdavidcs	for (i = 0; i < Q8_MAX_NUM_MULTICAST_ADDRS; i++) {
2985250661Sdavidcs
2986250661Sdavidcs		if (QL_MAC_CMP(ha->hw.mcast[i].addr, mta) == 0)
2987250661Sdavidcs			return 0; /* its been already added */
2988250661Sdavidcs	}
2989250661Sdavidcs
2990250661Sdavidcs	for (i = 0; i < Q8_MAX_NUM_MULTICAST_ADDRS; i++) {
2991250661Sdavidcs
2992250661Sdavidcs		if ((ha->hw.mcast[i].addr[0] == 0) &&
2993250661Sdavidcs			(ha->hw.mcast[i].addr[1] == 0) &&
2994250661Sdavidcs			(ha->hw.mcast[i].addr[2] == 0) &&
2995250661Sdavidcs			(ha->hw.mcast[i].addr[3] == 0) &&
2996250661Sdavidcs			(ha->hw.mcast[i].addr[4] == 0) &&
2997250661Sdavidcs			(ha->hw.mcast[i].addr[5] == 0)) {
2998250661Sdavidcs
2999250661Sdavidcs			if (qla_config_mac_addr(ha, mta, 1))
3000250661Sdavidcs				return (-1);
3001250661Sdavidcs
3002250661Sdavidcs			bcopy(mta, ha->hw.mcast[i].addr, Q8_MAC_ADDR_LEN);
3003250661Sdavidcs			ha->hw.nmcast++;
3004250661Sdavidcs
3005250661Sdavidcs			return 0;
3006250661Sdavidcs		}
3007250661Sdavidcs	}
3008250661Sdavidcs	return 0;
3009250661Sdavidcs}
3010250661Sdavidcs
3011250661Sdavidcsstatic int
3012250661Sdavidcsqla_hw_del_mcast(qla_host_t *ha, uint8_t *mta)
3013250661Sdavidcs{
3014250661Sdavidcs	int i;
3015250661Sdavidcs
3016250661Sdavidcs	for (i = 0; i < Q8_MAX_NUM_MULTICAST_ADDRS; i++) {
3017250661Sdavidcs		if (QL_MAC_CMP(ha->hw.mcast[i].addr, mta) == 0) {
3018250661Sdavidcs
3019250661Sdavidcs			if (qla_config_mac_addr(ha, mta, 0))
3020250661Sdavidcs				return (-1);
3021250661Sdavidcs
3022250661Sdavidcs			ha->hw.mcast[i].addr[0] = 0;
3023250661Sdavidcs			ha->hw.mcast[i].addr[1] = 0;
3024250661Sdavidcs			ha->hw.mcast[i].addr[2] = 0;
3025250661Sdavidcs			ha->hw.mcast[i].addr[3] = 0;
3026250661Sdavidcs			ha->hw.mcast[i].addr[4] = 0;
3027250661Sdavidcs			ha->hw.mcast[i].addr[5] = 0;
3028250661Sdavidcs
3029250661Sdavidcs			ha->hw.nmcast--;
3030250661Sdavidcs
3031250661Sdavidcs			return 0;
3032250661Sdavidcs		}
3033250661Sdavidcs	}
3034250661Sdavidcs	return 0;
3035250661Sdavidcs}
3036250661Sdavidcs
3037250661Sdavidcs/*
3038250661Sdavidcs * Name: ql_hw_set_multi
3039250661Sdavidcs * Function: Sets the Multicast Addresses provided the host O.S into the
3040250661Sdavidcs *	hardware (for the given interface)
3041250661Sdavidcs */
3042250661Sdavidcsint
3043250661Sdavidcsql_hw_set_multi(qla_host_t *ha, uint8_t *mcast, uint32_t mcnt,
3044250661Sdavidcs	uint32_t add_mac)
3045250661Sdavidcs{
3046250661Sdavidcs	int i;
3047250661Sdavidcs	uint8_t *mta = mcast;
3048250661Sdavidcs	int ret = 0;
3049250661Sdavidcs
3050250661Sdavidcs	for (i = 0; i < mcnt; i++) {
3051250661Sdavidcs		if (add_mac) {
3052250661Sdavidcs			ret = qla_hw_add_mcast(ha, mta);
3053250661Sdavidcs			if (ret)
3054250661Sdavidcs				break;
3055250661Sdavidcs		} else {
3056250661Sdavidcs			ret = qla_hw_del_mcast(ha, mta);
3057250661Sdavidcs			if (ret)
3058250661Sdavidcs				break;
3059250661Sdavidcs		}
3060250661Sdavidcs
3061250661Sdavidcs		mta += Q8_MAC_ADDR_LEN;
3062250661Sdavidcs	}
3063250661Sdavidcs	return (ret);
3064250661Sdavidcs}
3065250661Sdavidcs
3066250661Sdavidcs/*
3067250661Sdavidcs * Name: qla_hw_tx_done_locked
3068250661Sdavidcs * Function: Handle Transmit Completions
3069250661Sdavidcs */
3070250661Sdavidcsstatic void
3071250661Sdavidcsqla_hw_tx_done_locked(qla_host_t *ha, uint32_t txr_idx)
3072250661Sdavidcs{
3073250661Sdavidcs	qla_tx_buf_t *txb;
3074250661Sdavidcs        qla_hw_t *hw = &ha->hw;
3075250661Sdavidcs	uint32_t comp_idx, comp_count = 0;
3076250661Sdavidcs	qla_hw_tx_cntxt_t *hw_tx_cntxt;
3077250661Sdavidcs
3078250661Sdavidcs	hw_tx_cntxt = &hw->tx_cntxt[txr_idx];
3079250661Sdavidcs
3080250661Sdavidcs	/* retrieve index of last entry in tx ring completed */
3081250661Sdavidcs	comp_idx = qla_le32_to_host(*(hw_tx_cntxt->tx_cons));
3082250661Sdavidcs
3083250661Sdavidcs	while (comp_idx != hw_tx_cntxt->txr_comp) {
3084250661Sdavidcs
3085250661Sdavidcs		txb = &ha->tx_ring[txr_idx].tx_buf[hw_tx_cntxt->txr_comp];
3086250661Sdavidcs
3087250661Sdavidcs		hw_tx_cntxt->txr_comp++;
3088250661Sdavidcs		if (hw_tx_cntxt->txr_comp == NUM_TX_DESCRIPTORS)
3089250661Sdavidcs			hw_tx_cntxt->txr_comp = 0;
3090250661Sdavidcs
3091250661Sdavidcs		comp_count++;
3092250661Sdavidcs
3093250661Sdavidcs		if (txb->m_head) {
3094271849Sglebius			if_inc_counter(ha->ifp, IFCOUNTER_OPACKETS, 1);
3095250661Sdavidcs
3096250661Sdavidcs			bus_dmamap_sync(ha->tx_tag, txb->map,
3097250661Sdavidcs				BUS_DMASYNC_POSTWRITE);
3098250661Sdavidcs			bus_dmamap_unload(ha->tx_tag, txb->map);
3099250661Sdavidcs			m_freem(txb->m_head);
3100250661Sdavidcs
3101250661Sdavidcs			txb->m_head = NULL;
3102250661Sdavidcs		}
3103250661Sdavidcs	}
3104250661Sdavidcs
3105250661Sdavidcs	hw_tx_cntxt->txr_free += comp_count;
3106250661Sdavidcs	return;
3107250661Sdavidcs}
3108250661Sdavidcs
3109250661Sdavidcs/*
3110250661Sdavidcs * Name: ql_hw_tx_done
3111250661Sdavidcs * Function: Handle Transmit Completions
3112250661Sdavidcs */
3113250661Sdavidcsvoid
3114250661Sdavidcsql_hw_tx_done(qla_host_t *ha)
3115250661Sdavidcs{
3116250661Sdavidcs	int i;
3117250661Sdavidcs	uint32_t flag = 0;
3118250661Sdavidcs
3119250661Sdavidcs	if (!mtx_trylock(&ha->tx_lock)) {
3120250661Sdavidcs       		QL_DPRINT8(ha, (ha->pci_dev,
3121250661Sdavidcs			"%s: !mtx_trylock(&ha->tx_lock)\n", __func__));
3122250661Sdavidcs		return;
3123250661Sdavidcs	}
3124250661Sdavidcs	for (i = 0; i < ha->hw.num_tx_rings; i++) {
3125250661Sdavidcs		qla_hw_tx_done_locked(ha, i);
3126250661Sdavidcs		if (ha->hw.tx_cntxt[i].txr_free <= (NUM_TX_DESCRIPTORS >> 1))
3127250661Sdavidcs			flag = 1;
3128250661Sdavidcs	}
3129250661Sdavidcs
3130250661Sdavidcs	if (!flag)
3131250661Sdavidcs		ha->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
3132250661Sdavidcs
3133250661Sdavidcs	QLA_TX_UNLOCK(ha);
3134250661Sdavidcs	return;
3135250661Sdavidcs}
3136250661Sdavidcs
3137250661Sdavidcsvoid
3138250661Sdavidcsql_update_link_state(qla_host_t *ha)
3139250661Sdavidcs{
3140250661Sdavidcs	uint32_t link_state;
3141250661Sdavidcs	uint32_t prev_link_state;
3142250661Sdavidcs
3143250661Sdavidcs	if (!(ha->ifp->if_drv_flags & IFF_DRV_RUNNING)) {
3144250661Sdavidcs		ha->hw.link_up = 0;
3145250661Sdavidcs		return;
3146250661Sdavidcs	}
3147250661Sdavidcs	link_state = READ_REG32(ha, Q8_LINK_STATE);
3148250661Sdavidcs
3149250661Sdavidcs	prev_link_state =  ha->hw.link_up;
3150250661Sdavidcs
3151250661Sdavidcs	if (ha->pci_func == 0)
3152250661Sdavidcs		ha->hw.link_up = (((link_state & 0xF) == 1)? 1 : 0);
3153250661Sdavidcs	else
3154250661Sdavidcs		ha->hw.link_up = ((((link_state >> 4)& 0xF) == 1)? 1 : 0);
3155250661Sdavidcs
3156250661Sdavidcs	if (prev_link_state !=  ha->hw.link_up) {
3157250661Sdavidcs		if (ha->hw.link_up) {
3158250661Sdavidcs			if_link_state_change(ha->ifp, LINK_STATE_UP);
3159250661Sdavidcs		} else {
3160250661Sdavidcs			if_link_state_change(ha->ifp, LINK_STATE_DOWN);
3161250661Sdavidcs		}
3162250661Sdavidcs	}
3163250661Sdavidcs	return;
3164250661Sdavidcs}
3165250661Sdavidcs
3166250661Sdavidcsvoid
3167250661Sdavidcsql_hw_stop_rcv(qla_host_t *ha)
3168250661Sdavidcs{
3169250661Sdavidcs	int i, done, count = 100;
3170250661Sdavidcs
3171305487Sdavidcs	ha->flags.stop_rcv = 1;
3172305487Sdavidcs
3173284741Sdavidcs	while (count) {
3174250661Sdavidcs		done = 1;
3175250661Sdavidcs		for (i = 0; i < ha->hw.num_sds_rings; i++) {
3176250661Sdavidcs			if (ha->hw.sds[i].rcv_active)
3177250661Sdavidcs				done = 0;
3178250661Sdavidcs		}
3179250661Sdavidcs		if (done)
3180250661Sdavidcs			break;
3181250661Sdavidcs		else
3182250661Sdavidcs			qla_mdelay(__func__, 10);
3183284741Sdavidcs		count--;
3184250661Sdavidcs	}
3185250661Sdavidcs	if (!count)
3186250661Sdavidcs		device_printf(ha->pci_dev, "%s: Counter expired.\n", __func__);
3187250661Sdavidcs
3188250661Sdavidcs	return;
3189250661Sdavidcs}
3190250661Sdavidcs
3191250661Sdavidcsint
3192250661Sdavidcsql_hw_check_health(qla_host_t *ha)
3193250661Sdavidcs{
3194250661Sdavidcs	uint32_t val;
3195250661Sdavidcs
3196250661Sdavidcs	ha->hw.health_count++;
3197250661Sdavidcs
3198250661Sdavidcs	if (ha->hw.health_count < 1000)
3199250661Sdavidcs		return 0;
3200250661Sdavidcs
3201250661Sdavidcs	ha->hw.health_count = 0;
3202250661Sdavidcs
3203250661Sdavidcs	val = READ_REG32(ha, Q8_ASIC_TEMPERATURE);
3204250661Sdavidcs
3205250661Sdavidcs	if (((val & 0xFFFF) == 2) || ((val & 0xFFFF) == 3) ||
3206250661Sdavidcs		(QL_ERR_INJECT(ha, INJCT_TEMPERATURE_FAILURE))) {
3207250661Sdavidcs		device_printf(ha->pci_dev, "%s: Temperature Alert [0x%08x]\n",
3208250661Sdavidcs			__func__, val);
3209250661Sdavidcs		return -1;
3210250661Sdavidcs	}
3211250661Sdavidcs
3212250661Sdavidcs	val = READ_REG32(ha, Q8_FIRMWARE_HEARTBEAT);
3213250661Sdavidcs
3214250661Sdavidcs	if ((val != ha->hw.hbeat_value) &&
3215289635Sdavidcs		(!(QL_ERR_INJECT(ha, INJCT_HEARTBEAT_FAILURE)))) {
3216250661Sdavidcs		ha->hw.hbeat_value = val;
3217250661Sdavidcs		return 0;
3218250661Sdavidcs	}
3219250661Sdavidcs	device_printf(ha->pci_dev, "%s: Heartbeat Failue [0x%08x]\n",
3220250661Sdavidcs		__func__, val);
3221250661Sdavidcs
3222250661Sdavidcs	return -1;
3223250661Sdavidcs}
3224250661Sdavidcs
3225250661Sdavidcsstatic int
3226284741Sdavidcsqla_init_nic_func(qla_host_t *ha)
3227284741Sdavidcs{
3228284741Sdavidcs        device_t                dev;
3229284741Sdavidcs        q80_init_nic_func_t     *init_nic;
3230284741Sdavidcs        q80_init_nic_func_rsp_t *init_nic_rsp;
3231284741Sdavidcs        uint32_t                err;
3232284741Sdavidcs
3233284741Sdavidcs        dev = ha->pci_dev;
3234284741Sdavidcs
3235284741Sdavidcs        init_nic = (q80_init_nic_func_t *)ha->hw.mbox;
3236284741Sdavidcs        bzero(init_nic, sizeof(q80_init_nic_func_t));
3237284741Sdavidcs
3238284741Sdavidcs        init_nic->opcode = Q8_MBX_INIT_NIC_FUNC;
3239284741Sdavidcs        init_nic->count_version = (sizeof (q80_init_nic_func_t) >> 2);
3240284741Sdavidcs        init_nic->count_version |= Q8_MBX_CMD_VERSION;
3241284741Sdavidcs
3242284741Sdavidcs        init_nic->options = Q8_INIT_NIC_REG_DCBX_CHNG_AEN;
3243284741Sdavidcs        init_nic->options |= Q8_INIT_NIC_REG_SFP_CHNG_AEN;
3244284741Sdavidcs        init_nic->options |= Q8_INIT_NIC_REG_IDC_AEN;
3245284741Sdavidcs
3246284741Sdavidcs//qla_dump_buf8(ha, __func__, init_nic, sizeof (q80_init_nic_func_t));
3247284741Sdavidcs        if (qla_mbx_cmd(ha, (uint32_t *)init_nic,
3248284741Sdavidcs                (sizeof (q80_init_nic_func_t) >> 2),
3249284741Sdavidcs                ha->hw.mbox, (sizeof (q80_init_nic_func_rsp_t) >> 2), 0)) {
3250284741Sdavidcs                device_printf(dev, "%s: failed\n", __func__);
3251284741Sdavidcs                return -1;
3252284741Sdavidcs        }
3253284741Sdavidcs
3254284741Sdavidcs        init_nic_rsp = (q80_init_nic_func_rsp_t *)ha->hw.mbox;
3255284741Sdavidcs// qla_dump_buf8(ha, __func__, init_nic_rsp, sizeof (q80_init_nic_func_rsp_t));
3256284741Sdavidcs
3257284741Sdavidcs        err = Q8_MBX_RSP_STATUS(init_nic_rsp->regcnt_status);
3258284741Sdavidcs
3259284741Sdavidcs        if (err) {
3260284741Sdavidcs                device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
3261284741Sdavidcs        }
3262284741Sdavidcs
3263284741Sdavidcs        return 0;
3264284741Sdavidcs}
3265284741Sdavidcs
3266284741Sdavidcsstatic int
3267284741Sdavidcsqla_stop_nic_func(qla_host_t *ha)
3268284741Sdavidcs{
3269284741Sdavidcs        device_t                dev;
3270284741Sdavidcs        q80_stop_nic_func_t     *stop_nic;
3271284741Sdavidcs        q80_stop_nic_func_rsp_t *stop_nic_rsp;
3272284741Sdavidcs        uint32_t                err;
3273284741Sdavidcs
3274284741Sdavidcs        dev = ha->pci_dev;
3275284741Sdavidcs
3276284741Sdavidcs        stop_nic = (q80_stop_nic_func_t *)ha->hw.mbox;
3277284741Sdavidcs        bzero(stop_nic, sizeof(q80_stop_nic_func_t));
3278284741Sdavidcs
3279284741Sdavidcs        stop_nic->opcode = Q8_MBX_STOP_NIC_FUNC;
3280284741Sdavidcs        stop_nic->count_version = (sizeof (q80_stop_nic_func_t) >> 2);
3281284741Sdavidcs        stop_nic->count_version |= Q8_MBX_CMD_VERSION;
3282284741Sdavidcs
3283284741Sdavidcs        stop_nic->options = Q8_STOP_NIC_DEREG_DCBX_CHNG_AEN;
3284284741Sdavidcs        stop_nic->options |= Q8_STOP_NIC_DEREG_SFP_CHNG_AEN;
3285284741Sdavidcs
3286284741Sdavidcs//qla_dump_buf8(ha, __func__, stop_nic, sizeof (q80_stop_nic_func_t));
3287284741Sdavidcs        if (qla_mbx_cmd(ha, (uint32_t *)stop_nic,
3288284741Sdavidcs                (sizeof (q80_stop_nic_func_t) >> 2),
3289284741Sdavidcs                ha->hw.mbox, (sizeof (q80_stop_nic_func_rsp_t) >> 2), 0)) {
3290284741Sdavidcs                device_printf(dev, "%s: failed\n", __func__);
3291284741Sdavidcs                return -1;
3292284741Sdavidcs        }
3293284741Sdavidcs
3294284741Sdavidcs        stop_nic_rsp = (q80_stop_nic_func_rsp_t *)ha->hw.mbox;
3295284741Sdavidcs//qla_dump_buf8(ha, __func__, stop_nic_rsp, sizeof (q80_stop_nic_func_rsp_ t));
3296284741Sdavidcs
3297284741Sdavidcs        err = Q8_MBX_RSP_STATUS(stop_nic_rsp->regcnt_status);
3298284741Sdavidcs
3299284741Sdavidcs        if (err) {
3300284741Sdavidcs                device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
3301284741Sdavidcs        }
3302284741Sdavidcs
3303284741Sdavidcs        return 0;
3304284741Sdavidcs}
3305284741Sdavidcs
3306284741Sdavidcsstatic int
3307284741Sdavidcsqla_query_fw_dcbx_caps(qla_host_t *ha)
3308284741Sdavidcs{
3309284741Sdavidcs        device_t                        dev;
3310284741Sdavidcs        q80_query_fw_dcbx_caps_t        *fw_dcbx;
3311284741Sdavidcs        q80_query_fw_dcbx_caps_rsp_t    *fw_dcbx_rsp;
3312284741Sdavidcs        uint32_t                        err;
3313284741Sdavidcs
3314284741Sdavidcs        dev = ha->pci_dev;
3315284741Sdavidcs
3316284741Sdavidcs        fw_dcbx = (q80_query_fw_dcbx_caps_t *)ha->hw.mbox;
3317284741Sdavidcs        bzero(fw_dcbx, sizeof(q80_query_fw_dcbx_caps_t));
3318284741Sdavidcs
3319284741Sdavidcs        fw_dcbx->opcode = Q8_MBX_GET_FW_DCBX_CAPS;
3320284741Sdavidcs        fw_dcbx->count_version = (sizeof (q80_query_fw_dcbx_caps_t) >> 2);
3321284741Sdavidcs        fw_dcbx->count_version |= Q8_MBX_CMD_VERSION;
3322284741Sdavidcs
3323284741Sdavidcs        ql_dump_buf8(ha, __func__, fw_dcbx, sizeof (q80_query_fw_dcbx_caps_t));
3324284741Sdavidcs        if (qla_mbx_cmd(ha, (uint32_t *)fw_dcbx,
3325284741Sdavidcs                (sizeof (q80_query_fw_dcbx_caps_t) >> 2),
3326284741Sdavidcs                ha->hw.mbox, (sizeof (q80_query_fw_dcbx_caps_rsp_t) >> 2), 0)) {
3327284741Sdavidcs                device_printf(dev, "%s: failed\n", __func__);
3328284741Sdavidcs                return -1;
3329284741Sdavidcs        }
3330284741Sdavidcs
3331284741Sdavidcs        fw_dcbx_rsp = (q80_query_fw_dcbx_caps_rsp_t *)ha->hw.mbox;
3332284741Sdavidcs        ql_dump_buf8(ha, __func__, fw_dcbx_rsp,
3333284741Sdavidcs                sizeof (q80_query_fw_dcbx_caps_rsp_t));
3334284741Sdavidcs
3335284741Sdavidcs        err = Q8_MBX_RSP_STATUS(fw_dcbx_rsp->regcnt_status);
3336284741Sdavidcs
3337284741Sdavidcs        if (err) {
3338284741Sdavidcs                device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
3339284741Sdavidcs        }
3340284741Sdavidcs
3341284741Sdavidcs        return 0;
3342284741Sdavidcs}
3343284741Sdavidcs
3344284741Sdavidcsstatic int
3345284741Sdavidcsqla_idc_ack(qla_host_t *ha, uint32_t aen_mb1, uint32_t aen_mb2,
3346284741Sdavidcs        uint32_t aen_mb3, uint32_t aen_mb4)
3347284741Sdavidcs{
3348284741Sdavidcs        device_t                dev;
3349284741Sdavidcs        q80_idc_ack_t           *idc_ack;
3350284741Sdavidcs        q80_idc_ack_rsp_t       *idc_ack_rsp;
3351284741Sdavidcs        uint32_t                err;
3352284741Sdavidcs        int                     count = 300;
3353284741Sdavidcs
3354284741Sdavidcs        dev = ha->pci_dev;
3355284741Sdavidcs
3356284741Sdavidcs        idc_ack = (q80_idc_ack_t *)ha->hw.mbox;
3357284741Sdavidcs        bzero(idc_ack, sizeof(q80_idc_ack_t));
3358284741Sdavidcs
3359284741Sdavidcs        idc_ack->opcode = Q8_MBX_IDC_ACK;
3360284741Sdavidcs        idc_ack->count_version = (sizeof (q80_idc_ack_t) >> 2);
3361284741Sdavidcs        idc_ack->count_version |= Q8_MBX_CMD_VERSION;
3362284741Sdavidcs
3363284741Sdavidcs        idc_ack->aen_mb1 = aen_mb1;
3364284741Sdavidcs        idc_ack->aen_mb2 = aen_mb2;
3365284741Sdavidcs        idc_ack->aen_mb3 = aen_mb3;
3366284741Sdavidcs        idc_ack->aen_mb4 = aen_mb4;
3367284741Sdavidcs
3368284741Sdavidcs        ha->hw.imd_compl= 0;
3369284741Sdavidcs
3370284741Sdavidcs        if (qla_mbx_cmd(ha, (uint32_t *)idc_ack,
3371284741Sdavidcs                (sizeof (q80_idc_ack_t) >> 2),
3372284741Sdavidcs                ha->hw.mbox, (sizeof (q80_idc_ack_rsp_t) >> 2), 0)) {
3373284741Sdavidcs                device_printf(dev, "%s: failed\n", __func__);
3374284741Sdavidcs                return -1;
3375284741Sdavidcs        }
3376284741Sdavidcs
3377284741Sdavidcs        idc_ack_rsp = (q80_idc_ack_rsp_t *)ha->hw.mbox;
3378284741Sdavidcs
3379284741Sdavidcs        err = Q8_MBX_RSP_STATUS(idc_ack_rsp->regcnt_status);
3380284741Sdavidcs
3381284741Sdavidcs        if (err) {
3382284741Sdavidcs                device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
3383284741Sdavidcs                return(-1);
3384284741Sdavidcs        }
3385284741Sdavidcs
3386284741Sdavidcs        while (count && !ha->hw.imd_compl) {
3387284741Sdavidcs                qla_mdelay(__func__, 100);
3388284741Sdavidcs                count--;
3389284741Sdavidcs        }
3390284741Sdavidcs
3391284741Sdavidcs        if (!count)
3392284741Sdavidcs                return -1;
3393284741Sdavidcs        else
3394284741Sdavidcs                device_printf(dev, "%s: count %d\n", __func__, count);
3395284741Sdavidcs
3396284741Sdavidcs        return (0);
3397284741Sdavidcs}
3398284741Sdavidcs
3399284741Sdavidcsstatic int
3400284741Sdavidcsqla_set_port_config(qla_host_t *ha, uint32_t cfg_bits)
3401284741Sdavidcs{
3402284741Sdavidcs        device_t                dev;
3403284741Sdavidcs        q80_set_port_cfg_t      *pcfg;
3404284741Sdavidcs        q80_set_port_cfg_rsp_t  *pfg_rsp;
3405284741Sdavidcs        uint32_t                err;
3406284741Sdavidcs        int                     count = 300;
3407284741Sdavidcs
3408284741Sdavidcs        dev = ha->pci_dev;
3409284741Sdavidcs
3410284741Sdavidcs        pcfg = (q80_set_port_cfg_t *)ha->hw.mbox;
3411284741Sdavidcs        bzero(pcfg, sizeof(q80_set_port_cfg_t));
3412284741Sdavidcs
3413284741Sdavidcs        pcfg->opcode = Q8_MBX_SET_PORT_CONFIG;
3414284741Sdavidcs        pcfg->count_version = (sizeof (q80_set_port_cfg_t) >> 2);
3415284741Sdavidcs        pcfg->count_version |= Q8_MBX_CMD_VERSION;
3416284741Sdavidcs
3417284741Sdavidcs        pcfg->cfg_bits = cfg_bits;
3418284741Sdavidcs
3419284741Sdavidcs        device_printf(dev, "%s: cfg_bits"
3420284741Sdavidcs                " [STD_PAUSE_DIR, PAUSE_TYPE, DCBX]"
3421284741Sdavidcs                " [0x%x, 0x%x, 0x%x]\n", __func__,
3422284741Sdavidcs                ((cfg_bits & Q8_PORT_CFG_BITS_STDPAUSE_DIR_MASK)>>20),
3423284741Sdavidcs                ((cfg_bits & Q8_PORT_CFG_BITS_PAUSE_CFG_MASK) >> 5),
3424284741Sdavidcs                ((cfg_bits & Q8_PORT_CFG_BITS_DCBX_ENABLE) ? 1: 0));
3425284741Sdavidcs
3426284741Sdavidcs        ha->hw.imd_compl= 0;
3427284741Sdavidcs
3428284741Sdavidcs        if (qla_mbx_cmd(ha, (uint32_t *)pcfg,
3429284741Sdavidcs                (sizeof (q80_set_port_cfg_t) >> 2),
3430284741Sdavidcs                ha->hw.mbox, (sizeof (q80_set_port_cfg_rsp_t) >> 2), 0)) {
3431284741Sdavidcs                device_printf(dev, "%s: failed\n", __func__);
3432284741Sdavidcs                return -1;
3433284741Sdavidcs        }
3434284741Sdavidcs
3435284741Sdavidcs        pfg_rsp = (q80_set_port_cfg_rsp_t *)ha->hw.mbox;
3436284741Sdavidcs
3437284741Sdavidcs        err = Q8_MBX_RSP_STATUS(pfg_rsp->regcnt_status);
3438284741Sdavidcs
3439284741Sdavidcs        if (err == Q8_MBX_RSP_IDC_INTRMD_RSP) {
3440284741Sdavidcs                while (count && !ha->hw.imd_compl) {
3441284741Sdavidcs                        qla_mdelay(__func__, 100);
3442284741Sdavidcs                        count--;
3443284741Sdavidcs                }
3444284741Sdavidcs                if (count) {
3445284741Sdavidcs                        device_printf(dev, "%s: count %d\n", __func__, count);
3446284741Sdavidcs
3447284741Sdavidcs                        err = 0;
3448284741Sdavidcs                }
3449284741Sdavidcs        }
3450284741Sdavidcs
3451284741Sdavidcs        if (err) {
3452284741Sdavidcs                device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
3453284741Sdavidcs                return(-1);
3454284741Sdavidcs        }
3455284741Sdavidcs
3456284741Sdavidcs        return (0);
3457284741Sdavidcs}
3458284741Sdavidcs
3459284741Sdavidcs
3460284741Sdavidcsstatic int
3461250661Sdavidcsqla_get_minidump_tmplt_size(qla_host_t *ha, uint32_t *size)
3462250661Sdavidcs{
3463250661Sdavidcs	uint32_t			err;
3464250661Sdavidcs	device_t			dev = ha->pci_dev;
3465250661Sdavidcs	q80_config_md_templ_size_t	*md_size;
3466250661Sdavidcs	q80_config_md_templ_size_rsp_t	*md_size_rsp;
3467250661Sdavidcs
3468305487Sdavidcs#ifndef QL_LDFLASH_FW
3469284741Sdavidcs
3470305487Sdavidcs	ql_minidump_template_hdr_t *hdr;
3471305487Sdavidcs
3472305487Sdavidcs	hdr = (ql_minidump_template_hdr_t *)ql83xx_minidump;
3473305487Sdavidcs	*size = hdr->size_of_template;
3474284741Sdavidcs	return (0);
3475284741Sdavidcs
3476284741Sdavidcs#endif /* #ifdef QL_LDFLASH_FW */
3477284741Sdavidcs
3478250661Sdavidcs	md_size = (q80_config_md_templ_size_t *) ha->hw.mbox;
3479250661Sdavidcs	bzero(md_size, sizeof(q80_config_md_templ_size_t));
3480250661Sdavidcs
3481250661Sdavidcs	md_size->opcode = Q8_MBX_GET_MINIDUMP_TMPLT_SIZE;
3482250661Sdavidcs	md_size->count_version = (sizeof (q80_config_md_templ_size_t) >> 2);
3483250661Sdavidcs	md_size->count_version |= Q8_MBX_CMD_VERSION;
3484250661Sdavidcs
3485250661Sdavidcs	if (qla_mbx_cmd(ha, (uint32_t *) md_size,
3486250661Sdavidcs		(sizeof(q80_config_md_templ_size_t) >> 2), ha->hw.mbox,
3487250661Sdavidcs		(sizeof(q80_config_md_templ_size_rsp_t) >> 2), 0)) {
3488250661Sdavidcs
3489250661Sdavidcs		device_printf(dev, "%s: failed\n", __func__);
3490250661Sdavidcs
3491250661Sdavidcs		return (-1);
3492250661Sdavidcs	}
3493250661Sdavidcs
3494250661Sdavidcs	md_size_rsp = (q80_config_md_templ_size_rsp_t *) ha->hw.mbox;
3495250661Sdavidcs
3496250661Sdavidcs	err = Q8_MBX_RSP_STATUS(md_size_rsp->regcnt_status);
3497250661Sdavidcs
3498250661Sdavidcs        if (err) {
3499250661Sdavidcs		device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
3500250661Sdavidcs		return(-1);
3501250661Sdavidcs        }
3502250661Sdavidcs
3503250661Sdavidcs	*size = md_size_rsp->templ_size;
3504250661Sdavidcs
3505250661Sdavidcs	return (0);
3506250661Sdavidcs}
3507250661Sdavidcs
3508250661Sdavidcsstatic int
3509284741Sdavidcsqla_get_port_config(qla_host_t *ha, uint32_t *cfg_bits)
3510284741Sdavidcs{
3511284741Sdavidcs        device_t                dev;
3512284741Sdavidcs        q80_get_port_cfg_t      *pcfg;
3513284741Sdavidcs        q80_get_port_cfg_rsp_t  *pcfg_rsp;
3514284741Sdavidcs        uint32_t                err;
3515284741Sdavidcs
3516284741Sdavidcs        dev = ha->pci_dev;
3517284741Sdavidcs
3518284741Sdavidcs        pcfg = (q80_get_port_cfg_t *)ha->hw.mbox;
3519284741Sdavidcs        bzero(pcfg, sizeof(q80_get_port_cfg_t));
3520284741Sdavidcs
3521284741Sdavidcs        pcfg->opcode = Q8_MBX_GET_PORT_CONFIG;
3522284741Sdavidcs        pcfg->count_version = (sizeof (q80_get_port_cfg_t) >> 2);
3523284741Sdavidcs        pcfg->count_version |= Q8_MBX_CMD_VERSION;
3524284741Sdavidcs
3525284741Sdavidcs        if (qla_mbx_cmd(ha, (uint32_t *)pcfg,
3526284741Sdavidcs                (sizeof (q80_get_port_cfg_t) >> 2),
3527284741Sdavidcs                ha->hw.mbox, (sizeof (q80_get_port_cfg_rsp_t) >> 2), 0)) {
3528284741Sdavidcs                device_printf(dev, "%s: failed\n", __func__);
3529284741Sdavidcs                return -1;
3530284741Sdavidcs        }
3531284741Sdavidcs
3532284741Sdavidcs        pcfg_rsp = (q80_get_port_cfg_rsp_t *)ha->hw.mbox;
3533284741Sdavidcs
3534284741Sdavidcs        err = Q8_MBX_RSP_STATUS(pcfg_rsp->regcnt_status);
3535284741Sdavidcs
3536284741Sdavidcs        if (err) {
3537284741Sdavidcs                device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
3538284741Sdavidcs                return(-1);
3539284741Sdavidcs        }
3540284741Sdavidcs
3541284741Sdavidcs        device_printf(dev, "%s: [cfg_bits, port type]"
3542284741Sdavidcs                " [0x%08x, 0x%02x] [STD_PAUSE_DIR, PAUSE_TYPE, DCBX]"
3543284741Sdavidcs                " [0x%x, 0x%x, 0x%x]\n", __func__,
3544284741Sdavidcs                pcfg_rsp->cfg_bits, pcfg_rsp->phys_port_type,
3545284741Sdavidcs                ((pcfg_rsp->cfg_bits & Q8_PORT_CFG_BITS_STDPAUSE_DIR_MASK)>>20),
3546284741Sdavidcs                ((pcfg_rsp->cfg_bits & Q8_PORT_CFG_BITS_PAUSE_CFG_MASK) >> 5),
3547284741Sdavidcs                ((pcfg_rsp->cfg_bits & Q8_PORT_CFG_BITS_DCBX_ENABLE) ? 1: 0)
3548284741Sdavidcs                );
3549284741Sdavidcs
3550284741Sdavidcs        *cfg_bits = pcfg_rsp->cfg_bits;
3551284741Sdavidcs
3552284741Sdavidcs        return (0);
3553284741Sdavidcs}
3554284741Sdavidcs
3555284741Sdavidcsint
3556284741Sdavidcsqla_iscsi_pdu(qla_host_t *ha, struct mbuf *mp)
3557284741Sdavidcs{
3558284741Sdavidcs        struct ether_vlan_header        *eh;
3559284741Sdavidcs        uint16_t                        etype;
3560284741Sdavidcs        struct ip                       *ip = NULL;
3561284741Sdavidcs        struct ip6_hdr                  *ip6 = NULL;
3562284741Sdavidcs        struct tcphdr                   *th = NULL;
3563284741Sdavidcs        uint32_t                        hdrlen;
3564284741Sdavidcs        uint32_t                        offset;
3565284741Sdavidcs        uint8_t                         buf[sizeof(struct ip6_hdr)];
3566284741Sdavidcs
3567284741Sdavidcs        eh = mtod(mp, struct ether_vlan_header *);
3568284741Sdavidcs
3569284741Sdavidcs        if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
3570284741Sdavidcs                hdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
3571284741Sdavidcs                etype = ntohs(eh->evl_proto);
3572284741Sdavidcs        } else {
3573284741Sdavidcs                hdrlen = ETHER_HDR_LEN;
3574284741Sdavidcs                etype = ntohs(eh->evl_encap_proto);
3575284741Sdavidcs        }
3576284741Sdavidcs
3577284741Sdavidcs	if (etype == ETHERTYPE_IP) {
3578284741Sdavidcs
3579284741Sdavidcs		offset = (hdrlen + sizeof (struct ip));
3580284741Sdavidcs
3581284741Sdavidcs		if (mp->m_len >= offset) {
3582284741Sdavidcs                        ip = (struct ip *)(mp->m_data + hdrlen);
3583284741Sdavidcs		} else {
3584284741Sdavidcs			m_copydata(mp, hdrlen, sizeof (struct ip), buf);
3585284741Sdavidcs                        ip = (struct ip *)buf;
3586284741Sdavidcs		}
3587284741Sdavidcs
3588284741Sdavidcs                if (ip->ip_p == IPPROTO_TCP) {
3589284741Sdavidcs
3590284741Sdavidcs			hdrlen += ip->ip_hl << 2;
3591284741Sdavidcs			offset = hdrlen + 4;
3592284741Sdavidcs
3593284741Sdavidcs			if (mp->m_len >= offset) {
3594305487Sdavidcs				th = (struct tcphdr *)(mp->m_data + hdrlen);;
3595284741Sdavidcs			} else {
3596284741Sdavidcs                                m_copydata(mp, hdrlen, 4, buf);
3597284741Sdavidcs				th = (struct tcphdr *)buf;
3598284741Sdavidcs			}
3599284741Sdavidcs                }
3600284741Sdavidcs
3601284741Sdavidcs	} else if (etype == ETHERTYPE_IPV6) {
3602284741Sdavidcs
3603284741Sdavidcs		offset = (hdrlen + sizeof (struct ip6_hdr));
3604284741Sdavidcs
3605284741Sdavidcs		if (mp->m_len >= offset) {
3606284741Sdavidcs                        ip6 = (struct ip6_hdr *)(mp->m_data + hdrlen);
3607284741Sdavidcs		} else {
3608284741Sdavidcs                        m_copydata(mp, hdrlen, sizeof (struct ip6_hdr), buf);
3609284741Sdavidcs                        ip6 = (struct ip6_hdr *)buf;
3610284741Sdavidcs		}
3611284741Sdavidcs
3612284741Sdavidcs                if (ip6->ip6_nxt == IPPROTO_TCP) {
3613284741Sdavidcs
3614284741Sdavidcs			hdrlen += sizeof(struct ip6_hdr);
3615284741Sdavidcs			offset = hdrlen + 4;
3616284741Sdavidcs
3617284741Sdavidcs			if (mp->m_len >= offset) {
3618305487Sdavidcs				th = (struct tcphdr *)(mp->m_data + hdrlen);;
3619284741Sdavidcs			} else {
3620284741Sdavidcs				m_copydata(mp, hdrlen, 4, buf);
3621284741Sdavidcs				th = (struct tcphdr *)buf;
3622284741Sdavidcs			}
3623284741Sdavidcs                }
3624284741Sdavidcs	}
3625284741Sdavidcs
3626284741Sdavidcs        if (th != NULL) {
3627284741Sdavidcs                if ((th->th_sport == htons(3260)) ||
3628284741Sdavidcs                        (th->th_dport == htons(3260)))
3629284741Sdavidcs                        return 0;
3630284741Sdavidcs        }
3631284741Sdavidcs        return (-1);
3632284741Sdavidcs}
3633284741Sdavidcs
3634284741Sdavidcsvoid
3635284741Sdavidcsqla_hw_async_event(qla_host_t *ha)
3636284741Sdavidcs{
3637284741Sdavidcs        switch (ha->hw.aen_mb0) {
3638284741Sdavidcs        case 0x8101:
3639284741Sdavidcs                (void)qla_idc_ack(ha, ha->hw.aen_mb1, ha->hw.aen_mb2,
3640284741Sdavidcs                        ha->hw.aen_mb3, ha->hw.aen_mb4);
3641284741Sdavidcs
3642284741Sdavidcs                break;
3643284741Sdavidcs
3644284741Sdavidcs        default:
3645284741Sdavidcs                break;
3646284741Sdavidcs        }
3647284741Sdavidcs
3648284741Sdavidcs        return;
3649284741Sdavidcs}
3650284741Sdavidcs
3651284741Sdavidcs#ifdef QL_LDFLASH_FW
3652284741Sdavidcsstatic int
3653305487Sdavidcsql_get_minidump_template(qla_host_t *ha)
3654250661Sdavidcs{
3655250661Sdavidcs	uint32_t			err;
3656250661Sdavidcs	device_t			dev = ha->pci_dev;
3657250661Sdavidcs	q80_config_md_templ_cmd_t	*md_templ;
3658250661Sdavidcs	q80_config_md_templ_cmd_rsp_t	*md_templ_rsp;
3659250661Sdavidcs
3660250661Sdavidcs	md_templ = (q80_config_md_templ_cmd_t *) ha->hw.mbox;
3661250661Sdavidcs	bzero(md_templ, (sizeof (q80_config_md_templ_cmd_t)));
3662250661Sdavidcs
3663250661Sdavidcs	md_templ->opcode = Q8_MBX_GET_MINIDUMP_TMPLT;
3664250661Sdavidcs	md_templ->count_version = ( sizeof(q80_config_md_templ_cmd_t) >> 2);
3665250661Sdavidcs	md_templ->count_version |= Q8_MBX_CMD_VERSION;
3666250661Sdavidcs
3667250661Sdavidcs	md_templ->buf_addr = ha->hw.dma_buf.minidump.dma_addr;
3668250661Sdavidcs	md_templ->buff_size = ha->hw.dma_buf.minidump.size;
3669250661Sdavidcs
3670250661Sdavidcs	if (qla_mbx_cmd(ha, (uint32_t *) md_templ,
3671250661Sdavidcs		(sizeof(q80_config_md_templ_cmd_t) >> 2),
3672250661Sdavidcs		 ha->hw.mbox,
3673250661Sdavidcs		(sizeof(q80_config_md_templ_cmd_rsp_t) >> 2), 0)) {
3674250661Sdavidcs
3675250661Sdavidcs		device_printf(dev, "%s: failed\n", __func__);
3676250661Sdavidcs
3677250661Sdavidcs		return (-1);
3678250661Sdavidcs	}
3679250661Sdavidcs
3680250661Sdavidcs	md_templ_rsp = (q80_config_md_templ_cmd_rsp_t *) ha->hw.mbox;
3681250661Sdavidcs
3682250661Sdavidcs	err = Q8_MBX_RSP_STATUS(md_templ_rsp->regcnt_status);
3683250661Sdavidcs
3684250661Sdavidcs	if (err) {
3685250661Sdavidcs		device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
3686250661Sdavidcs		return (-1);
3687250661Sdavidcs	}
3688250661Sdavidcs
3689250661Sdavidcs	return (0);
3690250661Sdavidcs
3691250661Sdavidcs}
3692284741Sdavidcs#endif /* #ifdef QL_LDFLASH_FW */
3693250661Sdavidcs
3694305487Sdavidcs/*
3695305487Sdavidcs * Minidump related functionality
3696305487Sdavidcs */
3697305487Sdavidcs
3698305487Sdavidcsstatic int ql_parse_template(qla_host_t *ha);
3699305487Sdavidcs
3700305487Sdavidcsstatic uint32_t ql_rdcrb(qla_host_t *ha,
3701305487Sdavidcs			ql_minidump_entry_rdcrb_t *crb_entry,
3702305487Sdavidcs			uint32_t * data_buff);
3703305487Sdavidcs
3704305487Sdavidcsstatic uint32_t ql_pollrd(qla_host_t *ha,
3705305487Sdavidcs			ql_minidump_entry_pollrd_t *entry,
3706305487Sdavidcs			uint32_t * data_buff);
3707305487Sdavidcs
3708305487Sdavidcsstatic uint32_t ql_pollrd_modify_write(qla_host_t *ha,
3709305487Sdavidcs			ql_minidump_entry_rd_modify_wr_with_poll_t *entry,
3710305487Sdavidcs			uint32_t *data_buff);
3711305487Sdavidcs
3712305487Sdavidcsstatic uint32_t ql_L2Cache(qla_host_t *ha,
3713305487Sdavidcs			ql_minidump_entry_cache_t *cacheEntry,
3714305487Sdavidcs			uint32_t * data_buff);
3715305487Sdavidcs
3716305487Sdavidcsstatic uint32_t ql_L1Cache(qla_host_t *ha,
3717305487Sdavidcs			ql_minidump_entry_cache_t *cacheEntry,
3718305487Sdavidcs			uint32_t *data_buff);
3719305487Sdavidcs
3720305487Sdavidcsstatic uint32_t ql_rdocm(qla_host_t *ha,
3721305487Sdavidcs			ql_minidump_entry_rdocm_t *ocmEntry,
3722305487Sdavidcs			uint32_t *data_buff);
3723305487Sdavidcs
3724305487Sdavidcsstatic uint32_t ql_rdmem(qla_host_t *ha,
3725305487Sdavidcs			ql_minidump_entry_rdmem_t *mem_entry,
3726305487Sdavidcs			uint32_t *data_buff);
3727305487Sdavidcs
3728305487Sdavidcsstatic uint32_t ql_rdrom(qla_host_t *ha,
3729305487Sdavidcs			ql_minidump_entry_rdrom_t *romEntry,
3730305487Sdavidcs			uint32_t *data_buff);
3731305487Sdavidcs
3732305487Sdavidcsstatic uint32_t ql_rdmux(qla_host_t *ha,
3733305487Sdavidcs			ql_minidump_entry_mux_t *muxEntry,
3734305487Sdavidcs			uint32_t *data_buff);
3735305487Sdavidcs
3736305487Sdavidcsstatic uint32_t ql_rdmux2(qla_host_t *ha,
3737305487Sdavidcs			ql_minidump_entry_mux2_t *muxEntry,
3738305487Sdavidcs			uint32_t *data_buff);
3739305487Sdavidcs
3740305487Sdavidcsstatic uint32_t ql_rdqueue(qla_host_t *ha,
3741305487Sdavidcs			ql_minidump_entry_queue_t *queueEntry,
3742305487Sdavidcs			uint32_t *data_buff);
3743305487Sdavidcs
3744305487Sdavidcsstatic uint32_t ql_cntrl(qla_host_t *ha,
3745305487Sdavidcs			ql_minidump_template_hdr_t *template_hdr,
3746305487Sdavidcs			ql_minidump_entry_cntrl_t *crbEntry);
3747305487Sdavidcs
3748305487Sdavidcs
3749305487Sdavidcsstatic uint32_t
3750305487Sdavidcsql_minidump_size(qla_host_t *ha)
3751305487Sdavidcs{
3752305487Sdavidcs	uint32_t i, k;
3753305487Sdavidcs	uint32_t size = 0;
3754305487Sdavidcs	ql_minidump_template_hdr_t *hdr;
3755305487Sdavidcs
3756305487Sdavidcs	hdr = (ql_minidump_template_hdr_t *)ha->hw.dma_buf.minidump.dma_b;
3757305487Sdavidcs
3758305487Sdavidcs	i = 0x2;
3759305487Sdavidcs
3760305487Sdavidcs	for (k = 1; k < QL_DBG_CAP_SIZE_ARRAY_LEN; k++) {
3761305487Sdavidcs		if (i & ha->hw.mdump_capture_mask)
3762305487Sdavidcs			size += hdr->capture_size_array[k];
3763305487Sdavidcs		i = i << 1;
3764305487Sdavidcs	}
3765305487Sdavidcs	return (size);
3766305487Sdavidcs}
3767305487Sdavidcs
3768305487Sdavidcsstatic void
3769305487Sdavidcsql_free_minidump_buffer(qla_host_t *ha)
3770305487Sdavidcs{
3771305487Sdavidcs	if (ha->hw.mdump_buffer != NULL) {
3772305487Sdavidcs		free(ha->hw.mdump_buffer, M_QLA83XXBUF);
3773305487Sdavidcs		ha->hw.mdump_buffer = NULL;
3774305487Sdavidcs		ha->hw.mdump_buffer_size = 0;
3775305487Sdavidcs	}
3776305487Sdavidcs	return;
3777305487Sdavidcs}
3778305487Sdavidcs
3779250661Sdavidcsstatic int
3780305487Sdavidcsql_alloc_minidump_buffer(qla_host_t *ha)
3781250661Sdavidcs{
3782305487Sdavidcs	ha->hw.mdump_buffer_size = ql_minidump_size(ha);
3783305487Sdavidcs
3784305487Sdavidcs	if (!ha->hw.mdump_buffer_size)
3785305487Sdavidcs		return (-1);
3786305487Sdavidcs
3787305487Sdavidcs	ha->hw.mdump_buffer = malloc(ha->hw.mdump_buffer_size, M_QLA83XXBUF,
3788305487Sdavidcs					M_NOWAIT);
3789305487Sdavidcs
3790305487Sdavidcs	if (ha->hw.mdump_buffer == NULL)
3791305487Sdavidcs		return (-1);
3792305487Sdavidcs
3793305487Sdavidcs	return (0);
3794305487Sdavidcs}
3795305487Sdavidcs
3796305487Sdavidcsstatic void
3797305487Sdavidcsql_free_minidump_template_buffer(qla_host_t *ha)
3798305487Sdavidcs{
3799305487Sdavidcs	if (ha->hw.mdump_template != NULL) {
3800305487Sdavidcs		free(ha->hw.mdump_template, M_QLA83XXBUF);
3801305487Sdavidcs		ha->hw.mdump_template = NULL;
3802305487Sdavidcs		ha->hw.mdump_template_size = 0;
3803305487Sdavidcs	}
3804305487Sdavidcs	return;
3805305487Sdavidcs}
3806305487Sdavidcs
3807305487Sdavidcsstatic int
3808305487Sdavidcsql_alloc_minidump_template_buffer(qla_host_t *ha)
3809305487Sdavidcs{
3810305487Sdavidcs	ha->hw.mdump_template_size = ha->hw.dma_buf.minidump.size;
3811305487Sdavidcs
3812305487Sdavidcs	ha->hw.mdump_template = malloc(ha->hw.mdump_template_size,
3813305487Sdavidcs					M_QLA83XXBUF, M_NOWAIT);
3814305487Sdavidcs
3815305487Sdavidcs	if (ha->hw.mdump_template == NULL)
3816305487Sdavidcs		return (-1);
3817305487Sdavidcs
3818305487Sdavidcs	return (0);
3819305487Sdavidcs}
3820305487Sdavidcs
3821305487Sdavidcsstatic int
3822305487Sdavidcsql_alloc_minidump_buffers(qla_host_t *ha)
3823305487Sdavidcs{
3824305487Sdavidcs	int ret;
3825305487Sdavidcs
3826305487Sdavidcs	ret = ql_alloc_minidump_template_buffer(ha);
3827305487Sdavidcs
3828305487Sdavidcs	if (ret)
3829305487Sdavidcs		return (ret);
3830305487Sdavidcs
3831305487Sdavidcs	ret = ql_alloc_minidump_buffer(ha);
3832305487Sdavidcs
3833305487Sdavidcs	if (ret)
3834305487Sdavidcs		ql_free_minidump_template_buffer(ha);
3835305487Sdavidcs
3836305487Sdavidcs	return (ret);
3837305487Sdavidcs}
3838305487Sdavidcs
3839305487Sdavidcs
3840305487Sdavidcsstatic uint32_t
3841305487Sdavidcsql_validate_minidump_checksum(qla_host_t *ha)
3842305487Sdavidcs{
3843305487Sdavidcs        uint64_t sum = 0;
3844305487Sdavidcs	int count;
3845305487Sdavidcs	uint32_t *template_buff;
3846305487Sdavidcs
3847305487Sdavidcs	count = ha->hw.dma_buf.minidump.size / sizeof (uint32_t);
3848305487Sdavidcs	template_buff = ha->hw.dma_buf.minidump.dma_b;
3849305487Sdavidcs
3850305487Sdavidcs	while (count-- > 0) {
3851305487Sdavidcs		sum += *template_buff++;
3852305487Sdavidcs	}
3853305487Sdavidcs
3854305487Sdavidcs	while (sum >> 32) {
3855305487Sdavidcs		sum = (sum & 0xFFFFFFFF) + (sum >> 32);
3856305487Sdavidcs	}
3857305487Sdavidcs
3858305487Sdavidcs	return (~sum);
3859305487Sdavidcs}
3860305487Sdavidcs
3861305487Sdavidcsint
3862305487Sdavidcsql_minidump_init(qla_host_t *ha)
3863305487Sdavidcs{
3864284741Sdavidcs	int		ret = 0;
3865250661Sdavidcs	uint32_t	template_size = 0;
3866250661Sdavidcs	device_t	dev = ha->pci_dev;
3867250661Sdavidcs
3868250661Sdavidcs	/*
3869250661Sdavidcs	 * Get Minidump Template Size
3870250661Sdavidcs 	 */
3871250661Sdavidcs	ret = qla_get_minidump_tmplt_size(ha, &template_size);
3872250661Sdavidcs
3873250661Sdavidcs	if (ret || (template_size == 0)) {
3874250661Sdavidcs		device_printf(dev, "%s: failed [%d, %d]\n", __func__, ret,
3875250661Sdavidcs			template_size);
3876250661Sdavidcs		return (-1);
3877250661Sdavidcs	}
3878250661Sdavidcs
3879250661Sdavidcs	/*
3880250661Sdavidcs	 * Allocate Memory for Minidump Template
3881250661Sdavidcs	 */
3882250661Sdavidcs
3883250661Sdavidcs	ha->hw.dma_buf.minidump.alignment = 8;
3884250661Sdavidcs	ha->hw.dma_buf.minidump.size = template_size;
3885250661Sdavidcs
3886284741Sdavidcs#ifdef QL_LDFLASH_FW
3887250661Sdavidcs	if (ql_alloc_dmabuf(ha, &ha->hw.dma_buf.minidump)) {
3888250661Sdavidcs
3889250661Sdavidcs		device_printf(dev, "%s: minidump dma alloc failed\n", __func__);
3890250661Sdavidcs
3891250661Sdavidcs		return (-1);
3892250661Sdavidcs	}
3893250661Sdavidcs	ha->hw.dma_buf.flags.minidump = 1;
3894250661Sdavidcs
3895250661Sdavidcs	/*
3896250661Sdavidcs	 * Retrieve Minidump Template
3897250661Sdavidcs	 */
3898305487Sdavidcs	ret = ql_get_minidump_template(ha);
3899284741Sdavidcs#else
3900284741Sdavidcs	ha->hw.dma_buf.minidump.dma_b = ql83xx_minidump;
3901305487Sdavidcs
3902284741Sdavidcs#endif /* #ifdef QL_LDFLASH_FW */
3903250661Sdavidcs
3904305487Sdavidcs	if (ret == 0) {
3905305487Sdavidcs
3906305487Sdavidcs		ret = ql_validate_minidump_checksum(ha);
3907305487Sdavidcs
3908305487Sdavidcs		if (ret == 0) {
3909305487Sdavidcs
3910305487Sdavidcs			ret = ql_alloc_minidump_buffers(ha);
3911305487Sdavidcs
3912305487Sdavidcs			if (ret == 0)
3913305487Sdavidcs		ha->hw.mdump_init = 1;
3914305487Sdavidcs			else
3915305487Sdavidcs				device_printf(dev,
3916305487Sdavidcs					"%s: ql_alloc_minidump_buffers"
3917305487Sdavidcs					" failed\n", __func__);
3918305487Sdavidcs		} else {
3919305487Sdavidcs			device_printf(dev, "%s: ql_validate_minidump_checksum"
3920305487Sdavidcs				" failed\n", __func__);
3921305487Sdavidcs		}
3922250661Sdavidcs	} else {
3923305487Sdavidcs		device_printf(dev, "%s: ql_get_minidump_template failed\n",
3924305487Sdavidcs			 __func__);
3925250661Sdavidcs	}
3926250661Sdavidcs
3927305487Sdavidcs	if (ret)
3928305487Sdavidcs		ql_minidump_free(ha);
3929305487Sdavidcs
3930250661Sdavidcs	return (ret);
3931250661Sdavidcs}
3932250661Sdavidcs
3933250661Sdavidcsstatic void
3934305487Sdavidcsql_minidump_free(qla_host_t *ha)
3935250661Sdavidcs{
3936250661Sdavidcs	ha->hw.mdump_init = 0;
3937250661Sdavidcs	if (ha->hw.dma_buf.flags.minidump) {
3938250661Sdavidcs		ha->hw.dma_buf.flags.minidump = 0;
3939250661Sdavidcs		ql_free_dmabuf(ha, &ha->hw.dma_buf.minidump);
3940250661Sdavidcs	}
3941305487Sdavidcs
3942305487Sdavidcs	ql_free_minidump_template_buffer(ha);
3943305487Sdavidcs	ql_free_minidump_buffer(ha);
3944305487Sdavidcs
3945250661Sdavidcs	return;
3946250661Sdavidcs}
3947250661Sdavidcs
3948250661Sdavidcsvoid
3949250661Sdavidcsql_minidump(qla_host_t *ha)
3950250661Sdavidcs{
3951250661Sdavidcs	if (!ha->hw.mdump_init)
3952250661Sdavidcs		return;
3953250661Sdavidcs
3954305487Sdavidcs	if (ha->hw.mdump_done)
3955250661Sdavidcs		return;
3956250661Sdavidcs
3957250661Sdavidcs		ha->hw.mdump_start_seq_index = ql_stop_sequence(ha);
3958250661Sdavidcs
3959305487Sdavidcs	bzero(ha->hw.mdump_buffer, ha->hw.mdump_buffer_size);
3960305487Sdavidcs	bzero(ha->hw.mdump_template, ha->hw.mdump_template_size);
3961305487Sdavidcs
3962305487Sdavidcs	bcopy(ha->hw.dma_buf.minidump.dma_b, ha->hw.mdump_template,
3963305487Sdavidcs		ha->hw.mdump_template_size);
3964305487Sdavidcs
3965305487Sdavidcs	ql_parse_template(ha);
3966305487Sdavidcs
3967250661Sdavidcs	ql_start_sequence(ha, ha->hw.mdump_start_seq_index);
3968250661Sdavidcs
3969305487Sdavidcs	ha->hw.mdump_done = 1;
3970305487Sdavidcs
3971250661Sdavidcs	return;
3972250661Sdavidcs}
3973305487Sdavidcs
3974305487Sdavidcs
3975305487Sdavidcs/*
3976305487Sdavidcs * helper routines
3977305487Sdavidcs */
3978305487Sdavidcsstatic void
3979305487Sdavidcsql_entry_err_chk(ql_minidump_entry_t *entry, uint32_t esize)
3980305487Sdavidcs{
3981305487Sdavidcs	if (esize != entry->hdr.entry_capture_size) {
3982305487Sdavidcs		entry->hdr.entry_capture_size = esize;
3983305487Sdavidcs		entry->hdr.driver_flags |= QL_DBG_SIZE_ERR_FLAG;
3984305487Sdavidcs	}
3985305487Sdavidcs	return;
3986305487Sdavidcs}
3987305487Sdavidcs
3988305487Sdavidcs
3989305487Sdavidcsstatic int
3990305487Sdavidcsql_parse_template(qla_host_t *ha)
3991305487Sdavidcs{
3992305487Sdavidcs	uint32_t num_of_entries, buff_level, e_cnt, esize;
3993305487Sdavidcs	uint32_t end_cnt, rv = 0;
3994305487Sdavidcs	char *dump_buff, *dbuff;
3995305487Sdavidcs	int sane_start = 0, sane_end = 0;
3996305487Sdavidcs	ql_minidump_template_hdr_t *template_hdr;
3997305487Sdavidcs	ql_minidump_entry_t *entry;
3998305487Sdavidcs	uint32_t capture_mask;
3999305487Sdavidcs	uint32_t dump_size;
4000305487Sdavidcs
4001305487Sdavidcs	/* Setup parameters */
4002305487Sdavidcs	template_hdr = (ql_minidump_template_hdr_t *)ha->hw.mdump_template;
4003305487Sdavidcs
4004305487Sdavidcs	if (template_hdr->entry_type == TLHDR)
4005305487Sdavidcs		sane_start = 1;
4006305487Sdavidcs
4007305487Sdavidcs	dump_buff = (char *) ha->hw.mdump_buffer;
4008305487Sdavidcs
4009305487Sdavidcs	num_of_entries = template_hdr->num_of_entries;
4010305487Sdavidcs
4011305487Sdavidcs	entry = (ql_minidump_entry_t *) ((char *)template_hdr
4012305487Sdavidcs			+ template_hdr->first_entry_offset );
4013305487Sdavidcs
4014305487Sdavidcs	template_hdr->saved_state_array[QL_OCM0_ADDR_INDX] =
4015305487Sdavidcs		template_hdr->ocm_window_array[ha->pci_func];
4016305487Sdavidcs	template_hdr->saved_state_array[QL_PCIE_FUNC_INDX] = ha->pci_func;
4017305487Sdavidcs
4018305487Sdavidcs	capture_mask = ha->hw.mdump_capture_mask;
4019305487Sdavidcs	dump_size = ha->hw.mdump_buffer_size;
4020305487Sdavidcs
4021305487Sdavidcs	template_hdr->driver_capture_mask = capture_mask;
4022305487Sdavidcs
4023305487Sdavidcs	QL_DPRINT80(ha, (ha->pci_dev,
4024305487Sdavidcs		"%s: sane_start = %d num_of_entries = %d "
4025305487Sdavidcs		"capture_mask = 0x%x dump_size = %d \n",
4026305487Sdavidcs		__func__, sane_start, num_of_entries, capture_mask, dump_size));
4027305487Sdavidcs
4028305487Sdavidcs	for (buff_level = 0, e_cnt = 0; e_cnt < num_of_entries; e_cnt++) {
4029305487Sdavidcs
4030305487Sdavidcs		/*
4031305487Sdavidcs		 * If the capture_mask of the entry does not match capture mask
4032305487Sdavidcs		 * skip the entry after marking the driver_flags indicator.
4033305487Sdavidcs		 */
4034305487Sdavidcs
4035305487Sdavidcs		if (!(entry->hdr.entry_capture_mask & capture_mask)) {
4036305487Sdavidcs
4037305487Sdavidcs			entry->hdr.driver_flags |= QL_DBG_SKIPPED_FLAG;
4038305487Sdavidcs			entry = (ql_minidump_entry_t *) ((char *) entry
4039305487Sdavidcs					+ entry->hdr.entry_size);
4040305487Sdavidcs			continue;
4041305487Sdavidcs		}
4042305487Sdavidcs
4043305487Sdavidcs		/*
4044305487Sdavidcs		 * This is ONLY needed in implementations where
4045305487Sdavidcs		 * the capture buffer allocated is too small to capture
4046305487Sdavidcs		 * all of the required entries for a given capture mask.
4047305487Sdavidcs		 * We need to empty the buffer contents to a file
4048305487Sdavidcs		 * if possible, before processing the next entry
4049305487Sdavidcs		 * If the buff_full_flag is set, no further capture will happen
4050305487Sdavidcs		 * and all remaining non-control entries will be skipped.
4051305487Sdavidcs		 */
4052305487Sdavidcs		if (entry->hdr.entry_capture_size != 0) {
4053305487Sdavidcs			if ((buff_level + entry->hdr.entry_capture_size) >
4054305487Sdavidcs				dump_size) {
4055305487Sdavidcs				/*  Try to recover by emptying buffer to file */
4056305487Sdavidcs				entry->hdr.driver_flags |= QL_DBG_SKIPPED_FLAG;
4057305487Sdavidcs				entry = (ql_minidump_entry_t *) ((char *) entry
4058305487Sdavidcs						+ entry->hdr.entry_size);
4059305487Sdavidcs				continue;
4060305487Sdavidcs			}
4061305487Sdavidcs		}
4062305487Sdavidcs
4063305487Sdavidcs		/*
4064305487Sdavidcs		 * Decode the entry type and process it accordingly
4065305487Sdavidcs		 */
4066305487Sdavidcs
4067305487Sdavidcs		switch (entry->hdr.entry_type) {
4068305487Sdavidcs		case RDNOP:
4069305487Sdavidcs			break;
4070305487Sdavidcs
4071305487Sdavidcs		case RDEND:
4072305487Sdavidcs			if (sane_end == 0) {
4073305487Sdavidcs				end_cnt = e_cnt;
4074305487Sdavidcs			}
4075305487Sdavidcs			sane_end++;
4076305487Sdavidcs			break;
4077305487Sdavidcs
4078305487Sdavidcs		case RDCRB:
4079305487Sdavidcs			dbuff = dump_buff + buff_level;
4080305487Sdavidcs			esize = ql_rdcrb(ha, (void *)entry, (void *)dbuff);
4081305487Sdavidcs			ql_entry_err_chk(entry, esize);
4082305487Sdavidcs			buff_level += esize;
4083305487Sdavidcs			break;
4084305487Sdavidcs
4085305487Sdavidcs                case POLLRD:
4086305487Sdavidcs                        dbuff = dump_buff + buff_level;
4087305487Sdavidcs                        esize = ql_pollrd(ha, (void *)entry, (void *)dbuff);
4088305487Sdavidcs                        ql_entry_err_chk(entry, esize);
4089305487Sdavidcs                        buff_level += esize;
4090305487Sdavidcs                        break;
4091305487Sdavidcs
4092305487Sdavidcs                case POLLRDMWR:
4093305487Sdavidcs                        dbuff = dump_buff + buff_level;
4094305487Sdavidcs                        esize = ql_pollrd_modify_write(ha, (void *)entry,
4095305487Sdavidcs					(void *)dbuff);
4096305487Sdavidcs                        ql_entry_err_chk(entry, esize);
4097305487Sdavidcs                        buff_level += esize;
4098305487Sdavidcs                        break;
4099305487Sdavidcs
4100305487Sdavidcs		case L2ITG:
4101305487Sdavidcs		case L2DTG:
4102305487Sdavidcs		case L2DAT:
4103305487Sdavidcs		case L2INS:
4104305487Sdavidcs			dbuff = dump_buff + buff_level;
4105305487Sdavidcs			esize = ql_L2Cache(ha, (void *)entry, (void *)dbuff);
4106305487Sdavidcs			if (esize == -1) {
4107305487Sdavidcs				entry->hdr.driver_flags |= QL_DBG_SKIPPED_FLAG;
4108305487Sdavidcs			} else {
4109305487Sdavidcs				ql_entry_err_chk(entry, esize);
4110305487Sdavidcs				buff_level += esize;
4111305487Sdavidcs			}
4112305487Sdavidcs			break;
4113305487Sdavidcs
4114305487Sdavidcs		case L1DAT:
4115305487Sdavidcs		case L1INS:
4116305487Sdavidcs			dbuff = dump_buff + buff_level;
4117305487Sdavidcs			esize = ql_L1Cache(ha, (void *)entry, (void *)dbuff);
4118305487Sdavidcs			ql_entry_err_chk(entry, esize);
4119305487Sdavidcs			buff_level += esize;
4120305487Sdavidcs			break;
4121305487Sdavidcs
4122305487Sdavidcs		case RDOCM:
4123305487Sdavidcs			dbuff = dump_buff + buff_level;
4124305487Sdavidcs			esize = ql_rdocm(ha, (void *)entry, (void *)dbuff);
4125305487Sdavidcs			ql_entry_err_chk(entry, esize);
4126305487Sdavidcs			buff_level += esize;
4127305487Sdavidcs			break;
4128305487Sdavidcs
4129305487Sdavidcs		case RDMEM:
4130305487Sdavidcs			dbuff = dump_buff + buff_level;
4131305487Sdavidcs			esize = ql_rdmem(ha, (void *)entry, (void *)dbuff);
4132305487Sdavidcs			ql_entry_err_chk(entry, esize);
4133305487Sdavidcs			buff_level += esize;
4134305487Sdavidcs			break;
4135305487Sdavidcs
4136305487Sdavidcs		case BOARD:
4137305487Sdavidcs		case RDROM:
4138305487Sdavidcs			dbuff = dump_buff + buff_level;
4139305487Sdavidcs			esize = ql_rdrom(ha, (void *)entry, (void *)dbuff);
4140305487Sdavidcs			ql_entry_err_chk(entry, esize);
4141305487Sdavidcs			buff_level += esize;
4142305487Sdavidcs			break;
4143305487Sdavidcs
4144305487Sdavidcs		case RDMUX:
4145305487Sdavidcs			dbuff = dump_buff + buff_level;
4146305487Sdavidcs			esize = ql_rdmux(ha, (void *)entry, (void *)dbuff);
4147305487Sdavidcs			ql_entry_err_chk(entry, esize);
4148305487Sdavidcs			buff_level += esize;
4149305487Sdavidcs			break;
4150305487Sdavidcs
4151305487Sdavidcs                case RDMUX2:
4152305487Sdavidcs                        dbuff = dump_buff + buff_level;
4153305487Sdavidcs                        esize = ql_rdmux2(ha, (void *)entry, (void *)dbuff);
4154305487Sdavidcs                        ql_entry_err_chk(entry, esize);
4155305487Sdavidcs                        buff_level += esize;
4156305487Sdavidcs                        break;
4157305487Sdavidcs
4158305487Sdavidcs		case QUEUE:
4159305487Sdavidcs			dbuff = dump_buff + buff_level;
4160305487Sdavidcs			esize = ql_rdqueue(ha, (void *)entry, (void *)dbuff);
4161305487Sdavidcs			ql_entry_err_chk(entry, esize);
4162305487Sdavidcs			buff_level += esize;
4163305487Sdavidcs			break;
4164305487Sdavidcs
4165305487Sdavidcs		case CNTRL:
4166305487Sdavidcs			if ((rv = ql_cntrl(ha, template_hdr, (void *)entry))) {
4167305487Sdavidcs				entry->hdr.driver_flags |= QL_DBG_SKIPPED_FLAG;
4168305487Sdavidcs			}
4169305487Sdavidcs			break;
4170305487Sdavidcs		default:
4171305487Sdavidcs			entry->hdr.driver_flags |= QL_DBG_SKIPPED_FLAG;
4172305487Sdavidcs			break;
4173305487Sdavidcs		}
4174305487Sdavidcs		/*  next entry in the template */
4175305487Sdavidcs		entry = (ql_minidump_entry_t *) ((char *) entry
4176305487Sdavidcs						+ entry->hdr.entry_size);
4177305487Sdavidcs	}
4178305487Sdavidcs
4179305487Sdavidcs	if (!sane_start || (sane_end > 1)) {
4180305487Sdavidcs		device_printf(ha->pci_dev,
4181305487Sdavidcs			"\n%s: Template configuration error. Check Template\n",
4182305487Sdavidcs			__func__);
4183305487Sdavidcs	}
4184305487Sdavidcs
4185305487Sdavidcs	QL_DPRINT80(ha, (ha->pci_dev, "%s: Minidump num of entries = %d\n",
4186305487Sdavidcs		__func__, template_hdr->num_of_entries));
4187305487Sdavidcs
4188305487Sdavidcs	return 0;
4189305487Sdavidcs}
4190305487Sdavidcs
4191305487Sdavidcs/*
4192305487Sdavidcs * Read CRB operation.
4193305487Sdavidcs */
4194305487Sdavidcsstatic uint32_t
4195305487Sdavidcsql_rdcrb(qla_host_t *ha, ql_minidump_entry_rdcrb_t * crb_entry,
4196305487Sdavidcs	uint32_t * data_buff)
4197305487Sdavidcs{
4198305487Sdavidcs	int loop_cnt;
4199305487Sdavidcs	int ret;
4200305487Sdavidcs	uint32_t op_count, addr, stride, value = 0;
4201305487Sdavidcs
4202305487Sdavidcs	addr = crb_entry->addr;
4203305487Sdavidcs	op_count = crb_entry->op_count;
4204305487Sdavidcs	stride = crb_entry->addr_stride;
4205305487Sdavidcs
4206305487Sdavidcs	for (loop_cnt = 0; loop_cnt < op_count; loop_cnt++) {
4207305487Sdavidcs
4208305487Sdavidcs		ret = ql_rdwr_indreg32(ha, addr, &value, 1);
4209305487Sdavidcs
4210305487Sdavidcs		if (ret)
4211305487Sdavidcs			return (0);
4212305487Sdavidcs
4213305487Sdavidcs		*data_buff++ = addr;
4214305487Sdavidcs		*data_buff++ = value;
4215305487Sdavidcs		addr = addr + stride;
4216305487Sdavidcs	}
4217305487Sdavidcs
4218305487Sdavidcs	/*
4219305487Sdavidcs	 * for testing purpose we return amount of data written
4220305487Sdavidcs	 */
4221305487Sdavidcs	return (op_count * (2 * sizeof(uint32_t)));
4222305487Sdavidcs}
4223305487Sdavidcs
4224305487Sdavidcs/*
4225305487Sdavidcs * Handle L2 Cache.
4226305487Sdavidcs */
4227305487Sdavidcs
4228305487Sdavidcsstatic uint32_t
4229305487Sdavidcsql_L2Cache(qla_host_t *ha, ql_minidump_entry_cache_t *cacheEntry,
4230305487Sdavidcs	uint32_t * data_buff)
4231305487Sdavidcs{
4232305487Sdavidcs	int i, k;
4233305487Sdavidcs	int loop_cnt;
4234305487Sdavidcs	int ret;
4235305487Sdavidcs
4236305487Sdavidcs	uint32_t read_value;
4237305487Sdavidcs	uint32_t addr, read_addr, cntrl_addr, tag_reg_addr, cntl_value_w;
4238305487Sdavidcs	uint32_t tag_value, read_cnt;
4239305487Sdavidcs	volatile uint8_t cntl_value_r;
4240305487Sdavidcs	long timeout;
4241305487Sdavidcs	uint32_t data;
4242305487Sdavidcs
4243305487Sdavidcs	loop_cnt = cacheEntry->op_count;
4244305487Sdavidcs
4245305487Sdavidcs	read_addr = cacheEntry->read_addr;
4246305487Sdavidcs	cntrl_addr = cacheEntry->control_addr;
4247305487Sdavidcs	cntl_value_w = (uint32_t) cacheEntry->write_value;
4248305487Sdavidcs
4249305487Sdavidcs	tag_reg_addr = cacheEntry->tag_reg_addr;
4250305487Sdavidcs
4251305487Sdavidcs	tag_value = cacheEntry->init_tag_value;
4252305487Sdavidcs	read_cnt = cacheEntry->read_addr_cnt;
4253305487Sdavidcs
4254305487Sdavidcs	for (i = 0; i < loop_cnt; i++) {
4255305487Sdavidcs
4256305487Sdavidcs		ret = ql_rdwr_indreg32(ha, tag_reg_addr, &tag_value, 0);
4257305487Sdavidcs		if (ret)
4258305487Sdavidcs			return (0);
4259305487Sdavidcs
4260305487Sdavidcs		if (cacheEntry->write_value != 0) {
4261305487Sdavidcs
4262305487Sdavidcs			ret = ql_rdwr_indreg32(ha, cntrl_addr,
4263305487Sdavidcs					&cntl_value_w, 0);
4264305487Sdavidcs			if (ret)
4265305487Sdavidcs				return (0);
4266305487Sdavidcs		}
4267305487Sdavidcs
4268305487Sdavidcs		if (cacheEntry->poll_mask != 0) {
4269305487Sdavidcs
4270305487Sdavidcs			timeout = cacheEntry->poll_wait;
4271305487Sdavidcs
4272305487Sdavidcs			ret = ql_rdwr_indreg32(ha, cntrl_addr, &data, 1);
4273305487Sdavidcs			if (ret)
4274305487Sdavidcs				return (0);
4275305487Sdavidcs
4276305487Sdavidcs			cntl_value_r = (uint8_t)data;
4277305487Sdavidcs
4278305487Sdavidcs			while ((cntl_value_r & cacheEntry->poll_mask) != 0) {
4279305487Sdavidcs
4280305487Sdavidcs				if (timeout) {
4281305487Sdavidcs					qla_mdelay(__func__, 1);
4282305487Sdavidcs					timeout--;
4283305487Sdavidcs				} else
4284305487Sdavidcs					break;
4285305487Sdavidcs
4286305487Sdavidcs				ret = ql_rdwr_indreg32(ha, cntrl_addr,
4287305487Sdavidcs						&data, 1);
4288305487Sdavidcs				if (ret)
4289305487Sdavidcs					return (0);
4290305487Sdavidcs
4291305487Sdavidcs				cntl_value_r = (uint8_t)data;
4292305487Sdavidcs			}
4293305487Sdavidcs			if (!timeout) {
4294305487Sdavidcs				/* Report timeout error.
4295305487Sdavidcs				 * core dump capture failed
4296305487Sdavidcs				 * Skip remaining entries.
4297305487Sdavidcs				 * Write buffer out to file
4298305487Sdavidcs				 * Use driver specific fields in template header
4299305487Sdavidcs				 * to report this error.
4300305487Sdavidcs				 */
4301305487Sdavidcs				return (-1);
4302305487Sdavidcs			}
4303305487Sdavidcs		}
4304305487Sdavidcs
4305305487Sdavidcs		addr = read_addr;
4306305487Sdavidcs		for (k = 0; k < read_cnt; k++) {
4307305487Sdavidcs
4308305487Sdavidcs			ret = ql_rdwr_indreg32(ha, addr, &read_value, 1);
4309305487Sdavidcs			if (ret)
4310305487Sdavidcs				return (0);
4311305487Sdavidcs
4312305487Sdavidcs			*data_buff++ = read_value;
4313305487Sdavidcs			addr += cacheEntry->read_addr_stride;
4314305487Sdavidcs		}
4315305487Sdavidcs
4316305487Sdavidcs		tag_value += cacheEntry->tag_value_stride;
4317305487Sdavidcs	}
4318305487Sdavidcs
4319305487Sdavidcs	return (read_cnt * loop_cnt * sizeof(uint32_t));
4320305487Sdavidcs}
4321305487Sdavidcs
4322305487Sdavidcs/*
4323305487Sdavidcs * Handle L1 Cache.
4324305487Sdavidcs */
4325305487Sdavidcs
4326305487Sdavidcsstatic uint32_t
4327305487Sdavidcsql_L1Cache(qla_host_t *ha,
4328305487Sdavidcs	ql_minidump_entry_cache_t *cacheEntry,
4329305487Sdavidcs	uint32_t *data_buff)
4330305487Sdavidcs{
4331305487Sdavidcs	int ret;
4332305487Sdavidcs	int i, k;
4333305487Sdavidcs	int loop_cnt;
4334305487Sdavidcs
4335305487Sdavidcs	uint32_t read_value;
4336305487Sdavidcs	uint32_t addr, read_addr, cntrl_addr, tag_reg_addr;
4337305487Sdavidcs	uint32_t tag_value, read_cnt;
4338305487Sdavidcs	uint32_t cntl_value_w;
4339305487Sdavidcs
4340305487Sdavidcs	loop_cnt = cacheEntry->op_count;
4341305487Sdavidcs
4342305487Sdavidcs	read_addr = cacheEntry->read_addr;
4343305487Sdavidcs	cntrl_addr = cacheEntry->control_addr;
4344305487Sdavidcs	cntl_value_w = (uint32_t) cacheEntry->write_value;
4345305487Sdavidcs
4346305487Sdavidcs	tag_reg_addr = cacheEntry->tag_reg_addr;
4347305487Sdavidcs
4348305487Sdavidcs	tag_value = cacheEntry->init_tag_value;
4349305487Sdavidcs	read_cnt = cacheEntry->read_addr_cnt;
4350305487Sdavidcs
4351305487Sdavidcs	for (i = 0; i < loop_cnt; i++) {
4352305487Sdavidcs
4353305487Sdavidcs		ret = ql_rdwr_indreg32(ha, tag_reg_addr, &tag_value, 0);
4354305487Sdavidcs		if (ret)
4355305487Sdavidcs			return (0);
4356305487Sdavidcs
4357305487Sdavidcs		ret = ql_rdwr_indreg32(ha, cntrl_addr, &cntl_value_w, 0);
4358305487Sdavidcs		if (ret)
4359305487Sdavidcs			return (0);
4360305487Sdavidcs
4361305487Sdavidcs		addr = read_addr;
4362305487Sdavidcs		for (k = 0; k < read_cnt; k++) {
4363305487Sdavidcs
4364305487Sdavidcs			ret = ql_rdwr_indreg32(ha, addr, &read_value, 1);
4365305487Sdavidcs			if (ret)
4366305487Sdavidcs				return (0);
4367305487Sdavidcs
4368305487Sdavidcs			*data_buff++ = read_value;
4369305487Sdavidcs			addr += cacheEntry->read_addr_stride;
4370305487Sdavidcs		}
4371305487Sdavidcs
4372305487Sdavidcs		tag_value += cacheEntry->tag_value_stride;
4373305487Sdavidcs	}
4374305487Sdavidcs
4375305487Sdavidcs	return (read_cnt * loop_cnt * sizeof(uint32_t));
4376305487Sdavidcs}
4377305487Sdavidcs
4378305487Sdavidcs/*
4379305487Sdavidcs * Reading OCM memory
4380305487Sdavidcs */
4381305487Sdavidcs
4382305487Sdavidcsstatic uint32_t
4383305487Sdavidcsql_rdocm(qla_host_t *ha,
4384305487Sdavidcs	ql_minidump_entry_rdocm_t *ocmEntry,
4385305487Sdavidcs	uint32_t *data_buff)
4386305487Sdavidcs{
4387305487Sdavidcs	int i, loop_cnt;
4388305487Sdavidcs	volatile uint32_t addr;
4389305487Sdavidcs	volatile uint32_t value;
4390305487Sdavidcs
4391305487Sdavidcs	addr = ocmEntry->read_addr;
4392305487Sdavidcs	loop_cnt = ocmEntry->op_count;
4393305487Sdavidcs
4394305487Sdavidcs	for (i = 0; i < loop_cnt; i++) {
4395305487Sdavidcs		value = READ_REG32(ha, addr);
4396305487Sdavidcs		*data_buff++ = value;
4397305487Sdavidcs		addr += ocmEntry->read_addr_stride;
4398305487Sdavidcs	}
4399305487Sdavidcs	return (loop_cnt * sizeof(value));
4400305487Sdavidcs}
4401305487Sdavidcs
4402305487Sdavidcs/*
4403305487Sdavidcs * Read memory
4404305487Sdavidcs */
4405305487Sdavidcs
4406305487Sdavidcsstatic uint32_t
4407305487Sdavidcsql_rdmem(qla_host_t *ha,
4408305487Sdavidcs	ql_minidump_entry_rdmem_t *mem_entry,
4409305487Sdavidcs	uint32_t *data_buff)
4410305487Sdavidcs{
4411305487Sdavidcs	int ret;
4412305487Sdavidcs        int i, loop_cnt;
4413305487Sdavidcs        volatile uint32_t addr;
4414305487Sdavidcs	q80_offchip_mem_val_t val;
4415305487Sdavidcs
4416305487Sdavidcs        addr = mem_entry->read_addr;
4417305487Sdavidcs
4418305487Sdavidcs	/* size in bytes / 16 */
4419305487Sdavidcs        loop_cnt = mem_entry->read_data_size / (sizeof(uint32_t) * 4);
4420305487Sdavidcs
4421305487Sdavidcs        for (i = 0; i < loop_cnt; i++) {
4422305487Sdavidcs
4423305487Sdavidcs		ret = ql_rdwr_offchip_mem(ha, (addr & 0x0ffffffff), &val, 1);
4424305487Sdavidcs		if (ret)
4425305487Sdavidcs			return (0);
4426305487Sdavidcs
4427305487Sdavidcs                *data_buff++ = val.data_lo;
4428305487Sdavidcs                *data_buff++ = val.data_hi;
4429305487Sdavidcs                *data_buff++ = val.data_ulo;
4430305487Sdavidcs                *data_buff++ = val.data_uhi;
4431305487Sdavidcs
4432305487Sdavidcs                addr += (sizeof(uint32_t) * 4);
4433305487Sdavidcs        }
4434305487Sdavidcs
4435305487Sdavidcs        return (loop_cnt * (sizeof(uint32_t) * 4));
4436305487Sdavidcs}
4437305487Sdavidcs
4438305487Sdavidcs/*
4439305487Sdavidcs * Read Rom
4440305487Sdavidcs */
4441305487Sdavidcs
4442305487Sdavidcsstatic uint32_t
4443305487Sdavidcsql_rdrom(qla_host_t *ha,
4444305487Sdavidcs	ql_minidump_entry_rdrom_t *romEntry,
4445305487Sdavidcs	uint32_t *data_buff)
4446305487Sdavidcs{
4447305487Sdavidcs	int ret;
4448305487Sdavidcs	int i, loop_cnt;
4449305487Sdavidcs	uint32_t addr;
4450305487Sdavidcs	uint32_t value;
4451305487Sdavidcs
4452305487Sdavidcs	addr = romEntry->read_addr;
4453305487Sdavidcs	loop_cnt = romEntry->read_data_size; /* This is size in bytes */
4454305487Sdavidcs	loop_cnt /= sizeof(value);
4455305487Sdavidcs
4456305487Sdavidcs	for (i = 0; i < loop_cnt; i++) {
4457305487Sdavidcs
4458305487Sdavidcs		ret = ql_rd_flash32(ha, addr, &value);
4459305487Sdavidcs		if (ret)
4460305487Sdavidcs			return (0);
4461305487Sdavidcs
4462305487Sdavidcs		*data_buff++ = value;
4463305487Sdavidcs		addr += sizeof(value);
4464305487Sdavidcs	}
4465305487Sdavidcs
4466305487Sdavidcs	return (loop_cnt * sizeof(value));
4467305487Sdavidcs}
4468305487Sdavidcs
4469305487Sdavidcs/*
4470305487Sdavidcs * Read MUX data
4471305487Sdavidcs */
4472305487Sdavidcs
4473305487Sdavidcsstatic uint32_t
4474305487Sdavidcsql_rdmux(qla_host_t *ha,
4475305487Sdavidcs	ql_minidump_entry_mux_t *muxEntry,
4476305487Sdavidcs	uint32_t *data_buff)
4477305487Sdavidcs{
4478305487Sdavidcs	int ret;
4479305487Sdavidcs	int loop_cnt;
4480305487Sdavidcs	uint32_t read_value, sel_value;
4481305487Sdavidcs	uint32_t read_addr, select_addr;
4482305487Sdavidcs
4483305487Sdavidcs	select_addr = muxEntry->select_addr;
4484305487Sdavidcs	sel_value = muxEntry->select_value;
4485305487Sdavidcs	read_addr = muxEntry->read_addr;
4486305487Sdavidcs
4487305487Sdavidcs	for (loop_cnt = 0; loop_cnt < muxEntry->op_count; loop_cnt++) {
4488305487Sdavidcs
4489305487Sdavidcs		ret = ql_rdwr_indreg32(ha, select_addr, &sel_value, 0);
4490305487Sdavidcs		if (ret)
4491305487Sdavidcs			return (0);
4492305487Sdavidcs
4493305487Sdavidcs		ret = ql_rdwr_indreg32(ha, read_addr, &read_value, 1);
4494305487Sdavidcs		if (ret)
4495305487Sdavidcs			return (0);
4496305487Sdavidcs
4497305487Sdavidcs		*data_buff++ = sel_value;
4498305487Sdavidcs		*data_buff++ = read_value;
4499305487Sdavidcs
4500305487Sdavidcs		sel_value += muxEntry->select_value_stride;
4501305487Sdavidcs	}
4502305487Sdavidcs
4503305487Sdavidcs	return (loop_cnt * (2 * sizeof(uint32_t)));
4504305487Sdavidcs}
4505305487Sdavidcs
4506305487Sdavidcsstatic uint32_t
4507305487Sdavidcsql_rdmux2(qla_host_t *ha,
4508305487Sdavidcs	ql_minidump_entry_mux2_t *muxEntry,
4509305487Sdavidcs	uint32_t *data_buff)
4510305487Sdavidcs{
4511305487Sdavidcs	int ret;
4512305487Sdavidcs        int loop_cnt;
4513305487Sdavidcs
4514305487Sdavidcs        uint32_t select_addr_1, select_addr_2;
4515305487Sdavidcs        uint32_t select_value_1, select_value_2;
4516305487Sdavidcs        uint32_t select_value_count, select_value_mask;
4517305487Sdavidcs        uint32_t read_addr, read_value;
4518305487Sdavidcs
4519305487Sdavidcs        select_addr_1 = muxEntry->select_addr_1;
4520305487Sdavidcs        select_addr_2 = muxEntry->select_addr_2;
4521305487Sdavidcs        select_value_1 = muxEntry->select_value_1;
4522305487Sdavidcs        select_value_2 = muxEntry->select_value_2;
4523305487Sdavidcs        select_value_count = muxEntry->select_value_count;
4524305487Sdavidcs        select_value_mask  = muxEntry->select_value_mask;
4525305487Sdavidcs
4526305487Sdavidcs        read_addr = muxEntry->read_addr;
4527305487Sdavidcs
4528305487Sdavidcs        for (loop_cnt = 0; loop_cnt < muxEntry->select_value_count;
4529305487Sdavidcs		loop_cnt++) {
4530305487Sdavidcs
4531305487Sdavidcs                uint32_t temp_sel_val;
4532305487Sdavidcs
4533305487Sdavidcs		ret = ql_rdwr_indreg32(ha, select_addr_1, &select_value_1, 0);
4534305487Sdavidcs		if (ret)
4535305487Sdavidcs			return (0);
4536305487Sdavidcs
4537305487Sdavidcs                temp_sel_val = select_value_1 & select_value_mask;
4538305487Sdavidcs
4539305487Sdavidcs		ret = ql_rdwr_indreg32(ha, select_addr_2, &temp_sel_val, 0);
4540305487Sdavidcs		if (ret)
4541305487Sdavidcs			return (0);
4542305487Sdavidcs
4543305487Sdavidcs		ret = ql_rdwr_indreg32(ha, read_addr, &read_value, 1);
4544305487Sdavidcs		if (ret)
4545305487Sdavidcs			return (0);
4546305487Sdavidcs
4547305487Sdavidcs                *data_buff++ = temp_sel_val;
4548305487Sdavidcs                *data_buff++ = read_value;
4549305487Sdavidcs
4550305487Sdavidcs		ret = ql_rdwr_indreg32(ha, select_addr_1, &select_value_2, 0);
4551305487Sdavidcs		if (ret)
4552305487Sdavidcs			return (0);
4553305487Sdavidcs
4554305487Sdavidcs                temp_sel_val = select_value_2 & select_value_mask;
4555305487Sdavidcs
4556305487Sdavidcs		ret = ql_rdwr_indreg32(ha, select_addr_2, &temp_sel_val, 0);
4557305487Sdavidcs		if (ret)
4558305487Sdavidcs			return (0);
4559305487Sdavidcs
4560305487Sdavidcs		ret = ql_rdwr_indreg32(ha, read_addr, &read_value, 1);
4561305487Sdavidcs		if (ret)
4562305487Sdavidcs			return (0);
4563305487Sdavidcs
4564305487Sdavidcs                *data_buff++ = temp_sel_val;
4565305487Sdavidcs                *data_buff++ = read_value;
4566305487Sdavidcs
4567305487Sdavidcs                select_value_1 += muxEntry->select_value_stride;
4568305487Sdavidcs                select_value_2 += muxEntry->select_value_stride;
4569305487Sdavidcs        }
4570305487Sdavidcs
4571305487Sdavidcs        return (loop_cnt * (4 * sizeof(uint32_t)));
4572305487Sdavidcs}
4573305487Sdavidcs
4574305487Sdavidcs/*
4575305487Sdavidcs * Handling Queue State Reads.
4576305487Sdavidcs */
4577305487Sdavidcs
4578305487Sdavidcsstatic uint32_t
4579305487Sdavidcsql_rdqueue(qla_host_t *ha,
4580305487Sdavidcs	ql_minidump_entry_queue_t *queueEntry,
4581305487Sdavidcs	uint32_t *data_buff)
4582305487Sdavidcs{
4583305487Sdavidcs	int ret;
4584305487Sdavidcs	int loop_cnt, k;
4585305487Sdavidcs	uint32_t read_value;
4586305487Sdavidcs	uint32_t read_addr, read_stride, select_addr;
4587305487Sdavidcs	uint32_t queue_id, read_cnt;
4588305487Sdavidcs
4589305487Sdavidcs	read_cnt = queueEntry->read_addr_cnt;
4590305487Sdavidcs	read_stride = queueEntry->read_addr_stride;
4591305487Sdavidcs	select_addr = queueEntry->select_addr;
4592305487Sdavidcs
4593305487Sdavidcs	for (loop_cnt = 0, queue_id = 0; loop_cnt < queueEntry->op_count;
4594305487Sdavidcs		loop_cnt++) {
4595305487Sdavidcs
4596305487Sdavidcs		ret = ql_rdwr_indreg32(ha, select_addr, &queue_id, 0);
4597305487Sdavidcs		if (ret)
4598305487Sdavidcs			return (0);
4599305487Sdavidcs
4600305487Sdavidcs		read_addr = queueEntry->read_addr;
4601305487Sdavidcs
4602305487Sdavidcs		for (k = 0; k < read_cnt; k++) {
4603305487Sdavidcs
4604305487Sdavidcs			ret = ql_rdwr_indreg32(ha, read_addr, &read_value, 1);
4605305487Sdavidcs			if (ret)
4606305487Sdavidcs				return (0);
4607305487Sdavidcs
4608305487Sdavidcs			*data_buff++ = read_value;
4609305487Sdavidcs			read_addr += read_stride;
4610305487Sdavidcs		}
4611305487Sdavidcs
4612305487Sdavidcs		queue_id += queueEntry->queue_id_stride;
4613305487Sdavidcs	}
4614305487Sdavidcs
4615305487Sdavidcs	return (loop_cnt * (read_cnt * sizeof(uint32_t)));
4616305487Sdavidcs}
4617305487Sdavidcs
4618305487Sdavidcs/*
4619305487Sdavidcs * Handling control entries.
4620305487Sdavidcs */
4621305487Sdavidcs
4622305487Sdavidcsstatic uint32_t
4623305487Sdavidcsql_cntrl(qla_host_t *ha,
4624305487Sdavidcs	ql_minidump_template_hdr_t *template_hdr,
4625305487Sdavidcs	ql_minidump_entry_cntrl_t *crbEntry)
4626305487Sdavidcs{
4627305487Sdavidcs	int ret;
4628305487Sdavidcs	int count;
4629305487Sdavidcs	uint32_t opcode, read_value, addr, entry_addr;
4630305487Sdavidcs	long timeout;
4631305487Sdavidcs
4632305487Sdavidcs	entry_addr = crbEntry->addr;
4633305487Sdavidcs
4634305487Sdavidcs	for (count = 0; count < crbEntry->op_count; count++) {
4635305487Sdavidcs		opcode = crbEntry->opcode;
4636305487Sdavidcs
4637305487Sdavidcs		if (opcode & QL_DBG_OPCODE_WR) {
4638305487Sdavidcs
4639305487Sdavidcs                	ret = ql_rdwr_indreg32(ha, entry_addr,
4640305487Sdavidcs					&crbEntry->value_1, 0);
4641305487Sdavidcs			if (ret)
4642305487Sdavidcs				return (0);
4643305487Sdavidcs
4644305487Sdavidcs			opcode &= ~QL_DBG_OPCODE_WR;
4645305487Sdavidcs		}
4646305487Sdavidcs
4647305487Sdavidcs		if (opcode & QL_DBG_OPCODE_RW) {
4648305487Sdavidcs
4649305487Sdavidcs                	ret = ql_rdwr_indreg32(ha, entry_addr, &read_value, 1);
4650305487Sdavidcs			if (ret)
4651305487Sdavidcs				return (0);
4652305487Sdavidcs
4653305487Sdavidcs                	ret = ql_rdwr_indreg32(ha, entry_addr, &read_value, 0);
4654305487Sdavidcs			if (ret)
4655305487Sdavidcs				return (0);
4656305487Sdavidcs
4657305487Sdavidcs			opcode &= ~QL_DBG_OPCODE_RW;
4658305487Sdavidcs		}
4659305487Sdavidcs
4660305487Sdavidcs		if (opcode & QL_DBG_OPCODE_AND) {
4661305487Sdavidcs
4662305487Sdavidcs                	ret = ql_rdwr_indreg32(ha, entry_addr, &read_value, 1);
4663305487Sdavidcs			if (ret)
4664305487Sdavidcs				return (0);
4665305487Sdavidcs
4666305487Sdavidcs			read_value &= crbEntry->value_2;
4667305487Sdavidcs			opcode &= ~QL_DBG_OPCODE_AND;
4668305487Sdavidcs
4669305487Sdavidcs			if (opcode & QL_DBG_OPCODE_OR) {
4670305487Sdavidcs				read_value |= crbEntry->value_3;
4671305487Sdavidcs				opcode &= ~QL_DBG_OPCODE_OR;
4672305487Sdavidcs			}
4673305487Sdavidcs
4674305487Sdavidcs                	ret = ql_rdwr_indreg32(ha, entry_addr, &read_value, 0);
4675305487Sdavidcs			if (ret)
4676305487Sdavidcs				return (0);
4677305487Sdavidcs		}
4678305487Sdavidcs
4679305487Sdavidcs		if (opcode & QL_DBG_OPCODE_OR) {
4680305487Sdavidcs
4681305487Sdavidcs                	ret = ql_rdwr_indreg32(ha, entry_addr, &read_value, 1);
4682305487Sdavidcs			if (ret)
4683305487Sdavidcs				return (0);
4684305487Sdavidcs
4685305487Sdavidcs			read_value |= crbEntry->value_3;
4686305487Sdavidcs
4687305487Sdavidcs                	ret = ql_rdwr_indreg32(ha, entry_addr, &read_value, 0);
4688305487Sdavidcs			if (ret)
4689305487Sdavidcs				return (0);
4690305487Sdavidcs
4691305487Sdavidcs			opcode &= ~QL_DBG_OPCODE_OR;
4692305487Sdavidcs		}
4693305487Sdavidcs
4694305487Sdavidcs		if (opcode & QL_DBG_OPCODE_POLL) {
4695305487Sdavidcs
4696305487Sdavidcs			opcode &= ~QL_DBG_OPCODE_POLL;
4697305487Sdavidcs			timeout = crbEntry->poll_timeout;
4698305487Sdavidcs			addr = entry_addr;
4699305487Sdavidcs
4700305487Sdavidcs                	ret = ql_rdwr_indreg32(ha, addr, &read_value, 1);
4701305487Sdavidcs			if (ret)
4702305487Sdavidcs				return (0);
4703305487Sdavidcs
4704305487Sdavidcs			while ((read_value & crbEntry->value_2)
4705305487Sdavidcs				!= crbEntry->value_1) {
4706305487Sdavidcs
4707305487Sdavidcs				if (timeout) {
4708305487Sdavidcs					qla_mdelay(__func__, 1);
4709305487Sdavidcs					timeout--;
4710305487Sdavidcs				} else
4711305487Sdavidcs					break;
4712305487Sdavidcs
4713305487Sdavidcs                		ret = ql_rdwr_indreg32(ha, addr,
4714305487Sdavidcs						&read_value, 1);
4715305487Sdavidcs				if (ret)
4716305487Sdavidcs					return (0);
4717305487Sdavidcs			}
4718305487Sdavidcs
4719305487Sdavidcs			if (!timeout) {
4720305487Sdavidcs				/*
4721305487Sdavidcs				 * Report timeout error.
4722305487Sdavidcs				 * core dump capture failed
4723305487Sdavidcs				 * Skip remaining entries.
4724305487Sdavidcs				 * Write buffer out to file
4725305487Sdavidcs				 * Use driver specific fields in template header
4726305487Sdavidcs				 * to report this error.
4727305487Sdavidcs				 */
4728305487Sdavidcs				return (-1);
4729305487Sdavidcs			}
4730305487Sdavidcs		}
4731305487Sdavidcs
4732305487Sdavidcs		if (opcode & QL_DBG_OPCODE_RDSTATE) {
4733305487Sdavidcs			/*
4734305487Sdavidcs			 * decide which address to use.
4735305487Sdavidcs			 */
4736305487Sdavidcs			if (crbEntry->state_index_a) {
4737305487Sdavidcs				addr = template_hdr->saved_state_array[
4738305487Sdavidcs						crbEntry-> state_index_a];
4739305487Sdavidcs			} else {
4740305487Sdavidcs				addr = entry_addr;
4741305487Sdavidcs			}
4742305487Sdavidcs
4743305487Sdavidcs                	ret = ql_rdwr_indreg32(ha, addr, &read_value, 1);
4744305487Sdavidcs			if (ret)
4745305487Sdavidcs				return (0);
4746305487Sdavidcs
4747305487Sdavidcs			template_hdr->saved_state_array[crbEntry->state_index_v]
4748305487Sdavidcs					= read_value;
4749305487Sdavidcs			opcode &= ~QL_DBG_OPCODE_RDSTATE;
4750305487Sdavidcs		}
4751305487Sdavidcs
4752305487Sdavidcs		if (opcode & QL_DBG_OPCODE_WRSTATE) {
4753305487Sdavidcs			/*
4754305487Sdavidcs			 * decide which value to use.
4755305487Sdavidcs			 */
4756305487Sdavidcs			if (crbEntry->state_index_v) {
4757305487Sdavidcs				read_value = template_hdr->saved_state_array[
4758305487Sdavidcs						crbEntry->state_index_v];
4759305487Sdavidcs			} else {
4760305487Sdavidcs				read_value = crbEntry->value_1;
4761305487Sdavidcs			}
4762305487Sdavidcs			/*
4763305487Sdavidcs			 * decide which address to use.
4764305487Sdavidcs			 */
4765305487Sdavidcs			if (crbEntry->state_index_a) {
4766305487Sdavidcs				addr = template_hdr->saved_state_array[
4767305487Sdavidcs						crbEntry-> state_index_a];
4768305487Sdavidcs			} else {
4769305487Sdavidcs				addr = entry_addr;
4770305487Sdavidcs			}
4771305487Sdavidcs
4772305487Sdavidcs                	ret = ql_rdwr_indreg32(ha, addr, &read_value, 0);
4773305487Sdavidcs			if (ret)
4774305487Sdavidcs				return (0);
4775305487Sdavidcs
4776305487Sdavidcs			opcode &= ~QL_DBG_OPCODE_WRSTATE;
4777305487Sdavidcs		}
4778305487Sdavidcs
4779305487Sdavidcs		if (opcode & QL_DBG_OPCODE_MDSTATE) {
4780305487Sdavidcs			/*  Read value from saved state using index */
4781305487Sdavidcs			read_value = template_hdr->saved_state_array[
4782305487Sdavidcs						crbEntry->state_index_v];
4783305487Sdavidcs
4784305487Sdavidcs			read_value <<= crbEntry->shl; /*Shift left operation */
4785305487Sdavidcs			read_value >>= crbEntry->shr; /*Shift right operation */
4786305487Sdavidcs
4787305487Sdavidcs			if (crbEntry->value_2) {
4788305487Sdavidcs				/* check if AND mask is provided */
4789305487Sdavidcs				read_value &= crbEntry->value_2;
4790305487Sdavidcs			}
4791305487Sdavidcs
4792305487Sdavidcs			read_value |= crbEntry->value_3; /* OR operation */
4793305487Sdavidcs			read_value += crbEntry->value_1; /* increment op */
4794305487Sdavidcs
4795305487Sdavidcs			/* Write value back to state area. */
4796305487Sdavidcs
4797305487Sdavidcs			template_hdr->saved_state_array[crbEntry->state_index_v]
4798305487Sdavidcs					= read_value;
4799305487Sdavidcs			opcode &= ~QL_DBG_OPCODE_MDSTATE;
4800305487Sdavidcs		}
4801305487Sdavidcs
4802305487Sdavidcs		entry_addr += crbEntry->addr_stride;
4803305487Sdavidcs	}
4804305487Sdavidcs
4805305487Sdavidcs	return (0);
4806305487Sdavidcs}
4807305487Sdavidcs
4808305487Sdavidcs/*
4809305487Sdavidcs * Handling rd poll entry.
4810305487Sdavidcs */
4811305487Sdavidcs
4812305487Sdavidcsstatic uint32_t
4813305487Sdavidcsql_pollrd(qla_host_t *ha, ql_minidump_entry_pollrd_t *entry,
4814305487Sdavidcs	uint32_t *data_buff)
4815305487Sdavidcs{
4816305487Sdavidcs        int ret;
4817305487Sdavidcs        int loop_cnt;
4818305487Sdavidcs        uint32_t op_count, select_addr, select_value_stride, select_value;
4819305487Sdavidcs        uint32_t read_addr, poll, mask, data_size, data;
4820305487Sdavidcs        uint32_t wait_count = 0;
4821305487Sdavidcs
4822305487Sdavidcs        select_addr            = entry->select_addr;
4823305487Sdavidcs        read_addr              = entry->read_addr;
4824305487Sdavidcs        select_value           = entry->select_value;
4825305487Sdavidcs        select_value_stride    = entry->select_value_stride;
4826305487Sdavidcs        op_count               = entry->op_count;
4827305487Sdavidcs        poll                   = entry->poll;
4828305487Sdavidcs        mask                   = entry->mask;
4829305487Sdavidcs        data_size              = entry->data_size;
4830305487Sdavidcs
4831305487Sdavidcs        for (loop_cnt = 0; loop_cnt < op_count; loop_cnt++) {
4832305487Sdavidcs
4833305487Sdavidcs                ret = ql_rdwr_indreg32(ha, select_addr, &select_value, 0);
4834305487Sdavidcs		if (ret)
4835305487Sdavidcs			return (0);
4836305487Sdavidcs
4837305487Sdavidcs                wait_count = 0;
4838305487Sdavidcs
4839305487Sdavidcs                while (wait_count < poll) {
4840305487Sdavidcs
4841305487Sdavidcs                        uint32_t temp;
4842305487Sdavidcs
4843305487Sdavidcs			ret = ql_rdwr_indreg32(ha, select_addr, &temp, 1);
4844305487Sdavidcs			if (ret)
4845305487Sdavidcs				return (0);
4846305487Sdavidcs
4847305487Sdavidcs                        if ( (temp & mask) != 0 ) {
4848305487Sdavidcs                                break;
4849305487Sdavidcs                        }
4850305487Sdavidcs                        wait_count++;
4851305487Sdavidcs                }
4852305487Sdavidcs
4853305487Sdavidcs                if (wait_count == poll) {
4854305487Sdavidcs                        device_printf(ha->pci_dev,
4855305487Sdavidcs				"%s: Error in processing entry\n", __func__);
4856305487Sdavidcs                        device_printf(ha->pci_dev,
4857305487Sdavidcs				"%s: wait_count <0x%x> poll <0x%x>\n",
4858305487Sdavidcs				__func__, wait_count, poll);
4859305487Sdavidcs                        return 0;
4860305487Sdavidcs                }
4861305487Sdavidcs
4862305487Sdavidcs		ret = ql_rdwr_indreg32(ha, read_addr, &data, 1);
4863305487Sdavidcs		if (ret)
4864305487Sdavidcs			return (0);
4865305487Sdavidcs
4866305487Sdavidcs                *data_buff++ = select_value;
4867305487Sdavidcs                *data_buff++ = data;
4868305487Sdavidcs                select_value = select_value + select_value_stride;
4869305487Sdavidcs        }
4870305487Sdavidcs
4871305487Sdavidcs        /*
4872305487Sdavidcs         * for testing purpose we return amount of data written
4873305487Sdavidcs         */
4874305487Sdavidcs        return (loop_cnt * (2 * sizeof(uint32_t)));
4875305487Sdavidcs}
4876305487Sdavidcs
4877305487Sdavidcs
4878305487Sdavidcs/*
4879305487Sdavidcs * Handling rd modify write poll entry.
4880305487Sdavidcs */
4881305487Sdavidcs
4882305487Sdavidcsstatic uint32_t
4883305487Sdavidcsql_pollrd_modify_write(qla_host_t *ha,
4884305487Sdavidcs	ql_minidump_entry_rd_modify_wr_with_poll_t *entry,
4885305487Sdavidcs	uint32_t *data_buff)
4886305487Sdavidcs{
4887305487Sdavidcs	int ret;
4888305487Sdavidcs        uint32_t addr_1, addr_2, value_1, value_2, data;
4889305487Sdavidcs        uint32_t poll, mask, data_size, modify_mask;
4890305487Sdavidcs        uint32_t wait_count = 0;
4891305487Sdavidcs
4892305487Sdavidcs        addr_1		= entry->addr_1;
4893305487Sdavidcs        addr_2		= entry->addr_2;
4894305487Sdavidcs        value_1		= entry->value_1;
4895305487Sdavidcs        value_2		= entry->value_2;
4896305487Sdavidcs
4897305487Sdavidcs        poll		= entry->poll;
4898305487Sdavidcs        mask		= entry->mask;
4899305487Sdavidcs        modify_mask	= entry->modify_mask;
4900305487Sdavidcs        data_size	= entry->data_size;
4901305487Sdavidcs
4902305487Sdavidcs
4903305487Sdavidcs	ret = ql_rdwr_indreg32(ha, addr_1, &value_1, 0);
4904305487Sdavidcs	if (ret)
4905305487Sdavidcs		return (0);
4906305487Sdavidcs
4907305487Sdavidcs        wait_count = 0;
4908305487Sdavidcs        while (wait_count < poll) {
4909305487Sdavidcs
4910305487Sdavidcs		uint32_t temp;
4911305487Sdavidcs
4912305487Sdavidcs		ret = ql_rdwr_indreg32(ha, addr_1, &temp, 1);
4913305487Sdavidcs		if (ret)
4914305487Sdavidcs			return (0);
4915305487Sdavidcs
4916305487Sdavidcs                if ( (temp & mask) != 0 ) {
4917305487Sdavidcs                        break;
4918305487Sdavidcs                }
4919305487Sdavidcs                wait_count++;
4920305487Sdavidcs        }
4921305487Sdavidcs
4922305487Sdavidcs        if (wait_count == poll) {
4923305487Sdavidcs                device_printf(ha->pci_dev, "%s Error in processing entry\n",
4924305487Sdavidcs			__func__);
4925305487Sdavidcs        } else {
4926305487Sdavidcs
4927305487Sdavidcs		ret = ql_rdwr_indreg32(ha, addr_2, &data, 1);
4928305487Sdavidcs		if (ret)
4929305487Sdavidcs			return (0);
4930305487Sdavidcs
4931305487Sdavidcs                data = (data & modify_mask);
4932305487Sdavidcs
4933305487Sdavidcs		ret = ql_rdwr_indreg32(ha, addr_2, &data, 0);
4934305487Sdavidcs		if (ret)
4935305487Sdavidcs			return (0);
4936305487Sdavidcs
4937305487Sdavidcs		ret = ql_rdwr_indreg32(ha, addr_1, &value_2, 0);
4938305487Sdavidcs		if (ret)
4939305487Sdavidcs			return (0);
4940305487Sdavidcs
4941305487Sdavidcs                /* Poll again */
4942305487Sdavidcs                wait_count = 0;
4943305487Sdavidcs                while (wait_count < poll) {
4944305487Sdavidcs
4945305487Sdavidcs                        uint32_t temp;
4946305487Sdavidcs
4947305487Sdavidcs			ret = ql_rdwr_indreg32(ha, addr_1, &temp, 1);
4948305487Sdavidcs			if (ret)
4949305487Sdavidcs				return (0);
4950305487Sdavidcs
4951305487Sdavidcs                        if ( (temp & mask) != 0 ) {
4952305487Sdavidcs                                break;
4953305487Sdavidcs                        }
4954305487Sdavidcs                        wait_count++;
4955305487Sdavidcs                }
4956305487Sdavidcs                *data_buff++ = addr_2;
4957305487Sdavidcs                *data_buff++ = data;
4958305487Sdavidcs        }
4959305487Sdavidcs
4960305487Sdavidcs        /*
4961305487Sdavidcs         * for testing purpose we return amount of data written
4962305487Sdavidcs         */
4963305487Sdavidcs        return (2 * sizeof(uint32_t));
4964305487Sdavidcs}
4965305487Sdavidcs
4966305487Sdavidcs
4967