1331722Seadler/*
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 332052 2018-04-04 23:53:29Z 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);
52330555Sdavidcsstatic int qla_del_xmt_cntxt(qla_host_t *ha);
53250661Sdavidcsstatic int qla_init_xmt_cntxt(qla_host_t *ha);
54250661Sdavidcsstatic int qla_mbx_cmd(qla_host_t *ha, uint32_t *h_mbox, uint32_t n_hmbox,
55250661Sdavidcs	uint32_t *fw_mbox, uint32_t n_fwmbox, uint32_t no_pause);
56284741Sdavidcsstatic int qla_config_intr_cntxt(qla_host_t *ha, uint32_t start_idx,
57284741Sdavidcs	uint32_t num_intrs, uint32_t create);
58250661Sdavidcsstatic int qla_config_rss(qla_host_t *ha, uint16_t cntxt_id);
59250661Sdavidcsstatic int qla_config_intr_coalesce(qla_host_t *ha, uint16_t cntxt_id,
60284741Sdavidcs	int tenable, int rcv);
61250661Sdavidcsstatic int qla_set_mac_rcv_mode(qla_host_t *ha, uint32_t mode);
62250661Sdavidcsstatic int qla_link_event_req(qla_host_t *ha, uint16_t cntxt_id);
63250661Sdavidcs
64250661Sdavidcsstatic int qla_tx_tso(qla_host_t *ha, struct mbuf *mp, q80_tx_cmd_t *tx_cmd,
65250661Sdavidcs		uint8_t *hdr);
66250661Sdavidcsstatic int qla_hw_add_all_mcast(qla_host_t *ha);
67284741Sdavidcsstatic int qla_add_rcv_rings(qla_host_t *ha, uint32_t sds_idx, uint32_t nsds);
68250661Sdavidcs
69284741Sdavidcsstatic int qla_init_nic_func(qla_host_t *ha);
70284741Sdavidcsstatic int qla_stop_nic_func(qla_host_t *ha);
71284741Sdavidcsstatic int qla_query_fw_dcbx_caps(qla_host_t *ha);
72284741Sdavidcsstatic int qla_set_port_config(qla_host_t *ha, uint32_t cfg_bits);
73284741Sdavidcsstatic int qla_get_port_config(qla_host_t *ha, uint32_t *cfg_bits);
74305488Sdavidcsstatic int qla_set_cam_search_mode(qla_host_t *ha, uint32_t search_mode);
75305488Sdavidcsstatic int qla_get_cam_search_mode(qla_host_t *ha);
76284741Sdavidcs
77305487Sdavidcsstatic void ql_minidump_free(qla_host_t *ha);
78250661Sdavidcs
79250661Sdavidcs#ifdef QL_DBG
80250661Sdavidcs
81250661Sdavidcsstatic void
82250661Sdavidcsqla_stop_pegs(qla_host_t *ha)
83250661Sdavidcs{
84250661Sdavidcs        uint32_t val = 1;
85250661Sdavidcs
86250661Sdavidcs        ql_rdwr_indreg32(ha, Q8_CRB_PEG_0, &val, 0);
87250661Sdavidcs        ql_rdwr_indreg32(ha, Q8_CRB_PEG_1, &val, 0);
88250661Sdavidcs        ql_rdwr_indreg32(ha, Q8_CRB_PEG_2, &val, 0);
89250661Sdavidcs        ql_rdwr_indreg32(ha, Q8_CRB_PEG_3, &val, 0);
90250661Sdavidcs        ql_rdwr_indreg32(ha, Q8_CRB_PEG_4, &val, 0);
91250661Sdavidcs        device_printf(ha->pci_dev, "%s PEGS HALTED!!!!!\n", __func__);
92250661Sdavidcs}
93250661Sdavidcs
94250661Sdavidcsstatic int
95250661Sdavidcsqla_sysctl_stop_pegs(SYSCTL_HANDLER_ARGS)
96250661Sdavidcs{
97250661Sdavidcs	int err, ret = 0;
98250661Sdavidcs	qla_host_t *ha;
99250661Sdavidcs
100250661Sdavidcs	err = sysctl_handle_int(oidp, &ret, 0, req);
101250661Sdavidcs
102250661Sdavidcs
103250661Sdavidcs	if (err || !req->newptr)
104250661Sdavidcs		return (err);
105250661Sdavidcs
106250661Sdavidcs	if (ret == 1) {
107250661Sdavidcs		ha = (qla_host_t *)arg1;
108322972Sdavidcs		if (QLA_LOCK(ha, __func__, QLA_LOCK_DEFAULT_MS_TIMEOUT, 0) == 0) {
109322972Sdavidcs			qla_stop_pegs(ha);
110322972Sdavidcs			QLA_UNLOCK(ha, __func__);
111322972Sdavidcs		}
112250661Sdavidcs	}
113250661Sdavidcs
114250661Sdavidcs	return err;
115250661Sdavidcs}
116250661Sdavidcs#endif /* #ifdef QL_DBG */
117250661Sdavidcs
118284741Sdavidcsstatic int
119284741Sdavidcsqla_validate_set_port_cfg_bit(uint32_t bits)
120284741Sdavidcs{
121284741Sdavidcs        if ((bits & 0xF) > 1)
122284741Sdavidcs                return (-1);
123284741Sdavidcs
124284741Sdavidcs        if (((bits >> 4) & 0xF) > 2)
125284741Sdavidcs                return (-1);
126284741Sdavidcs
127284741Sdavidcs        if (((bits >> 8) & 0xF) > 2)
128284741Sdavidcs                return (-1);
129284741Sdavidcs
130284741Sdavidcs        return (0);
131284741Sdavidcs}
132284741Sdavidcs
133284741Sdavidcsstatic int
134284741Sdavidcsqla_sysctl_port_cfg(SYSCTL_HANDLER_ARGS)
135284741Sdavidcs{
136284741Sdavidcs        int err, ret = 0;
137284741Sdavidcs        qla_host_t *ha;
138284741Sdavidcs        uint32_t cfg_bits;
139284741Sdavidcs
140284741Sdavidcs        err = sysctl_handle_int(oidp, &ret, 0, req);
141284741Sdavidcs
142284741Sdavidcs        if (err || !req->newptr)
143284741Sdavidcs                return (err);
144284741Sdavidcs
145322972Sdavidcs	ha = (qla_host_t *)arg1;
146322972Sdavidcs
147284741Sdavidcs        if ((qla_validate_set_port_cfg_bit((uint32_t)ret) == 0)) {
148284741Sdavidcs
149284741Sdavidcs                err = qla_get_port_config(ha, &cfg_bits);
150284741Sdavidcs
151284741Sdavidcs                if (err)
152284741Sdavidcs                        goto qla_sysctl_set_port_cfg_exit;
153284741Sdavidcs
154284741Sdavidcs                if (ret & 0x1) {
155284741Sdavidcs                        cfg_bits |= Q8_PORT_CFG_BITS_DCBX_ENABLE;
156284741Sdavidcs                } else {
157284741Sdavidcs                        cfg_bits &= ~Q8_PORT_CFG_BITS_DCBX_ENABLE;
158284741Sdavidcs                }
159284741Sdavidcs
160284741Sdavidcs                ret = ret >> 4;
161284741Sdavidcs                cfg_bits &= ~Q8_PORT_CFG_BITS_PAUSE_CFG_MASK;
162284741Sdavidcs
163284741Sdavidcs                if ((ret & 0xF) == 0) {
164284741Sdavidcs                        cfg_bits |= Q8_PORT_CFG_BITS_PAUSE_DISABLED;
165284741Sdavidcs                } else if ((ret & 0xF) == 1){
166284741Sdavidcs                        cfg_bits |= Q8_PORT_CFG_BITS_PAUSE_STD;
167284741Sdavidcs                } else {
168284741Sdavidcs                        cfg_bits |= Q8_PORT_CFG_BITS_PAUSE_PPM;
169284741Sdavidcs                }
170284741Sdavidcs
171284741Sdavidcs                ret = ret >> 4;
172284741Sdavidcs                cfg_bits &= ~Q8_PORT_CFG_BITS_STDPAUSE_DIR_MASK;
173284741Sdavidcs
174284741Sdavidcs                if (ret == 0) {
175284741Sdavidcs                        cfg_bits |= Q8_PORT_CFG_BITS_STDPAUSE_XMT_RCV;
176284741Sdavidcs                } else if (ret == 1){
177284741Sdavidcs                        cfg_bits |= Q8_PORT_CFG_BITS_STDPAUSE_XMT;
178284741Sdavidcs                } else {
179284741Sdavidcs                        cfg_bits |= Q8_PORT_CFG_BITS_STDPAUSE_RCV;
180284741Sdavidcs                }
181284741Sdavidcs
182322972Sdavidcs		if (QLA_LOCK(ha, __func__, QLA_LOCK_DEFAULT_MS_TIMEOUT, 0) == 0) {
183322972Sdavidcs                	err = qla_set_port_config(ha, cfg_bits);
184322972Sdavidcs			QLA_UNLOCK(ha, __func__);
185322972Sdavidcs		} else {
186322972Sdavidcs			device_printf(ha->pci_dev, "%s: failed\n", __func__);
187322972Sdavidcs		}
188284741Sdavidcs        } else {
189322972Sdavidcs		if (QLA_LOCK(ha, __func__, QLA_LOCK_DEFAULT_MS_TIMEOUT, 0) == 0) {
190322972Sdavidcs                	err = qla_get_port_config(ha, &cfg_bits);
191322972Sdavidcs			QLA_UNLOCK(ha, __func__);
192322972Sdavidcs		} else {
193322972Sdavidcs			device_printf(ha->pci_dev, "%s: failed\n", __func__);
194322972Sdavidcs		}
195284741Sdavidcs        }
196284741Sdavidcs
197284741Sdavidcsqla_sysctl_set_port_cfg_exit:
198284741Sdavidcs        return err;
199284741Sdavidcs}
200284741Sdavidcs
201305488Sdavidcsstatic int
202305488Sdavidcsqla_sysctl_set_cam_search_mode(SYSCTL_HANDLER_ARGS)
203305488Sdavidcs{
204305488Sdavidcs	int err, ret = 0;
205305488Sdavidcs	qla_host_t *ha;
206305488Sdavidcs
207305488Sdavidcs	err = sysctl_handle_int(oidp, &ret, 0, req);
208305488Sdavidcs
209305488Sdavidcs	if (err || !req->newptr)
210305488Sdavidcs		return (err);
211305488Sdavidcs
212305488Sdavidcs	ha = (qla_host_t *)arg1;
213305488Sdavidcs
214305488Sdavidcs	if ((ret == Q8_HW_CONFIG_CAM_SEARCH_MODE_INTERNAL) ||
215305488Sdavidcs		(ret == Q8_HW_CONFIG_CAM_SEARCH_MODE_AUTO)) {
216322972Sdavidcs
217322972Sdavidcs		if (QLA_LOCK(ha, __func__, QLA_LOCK_DEFAULT_MS_TIMEOUT, 0) == 0) {
218322972Sdavidcs			err = qla_set_cam_search_mode(ha, (uint32_t)ret);
219322972Sdavidcs			QLA_UNLOCK(ha, __func__);
220322972Sdavidcs		} else {
221322972Sdavidcs			device_printf(ha->pci_dev, "%s: failed\n", __func__);
222322972Sdavidcs		}
223322972Sdavidcs
224305488Sdavidcs	} else {
225305488Sdavidcs		device_printf(ha->pci_dev, "%s: ret = %d\n", __func__, ret);
226305488Sdavidcs	}
227305488Sdavidcs
228305488Sdavidcs	return (err);
229305488Sdavidcs}
230305488Sdavidcs
231305488Sdavidcsstatic int
232305488Sdavidcsqla_sysctl_get_cam_search_mode(SYSCTL_HANDLER_ARGS)
233305488Sdavidcs{
234305488Sdavidcs	int err, ret = 0;
235305488Sdavidcs	qla_host_t *ha;
236305488Sdavidcs
237305488Sdavidcs	err = sysctl_handle_int(oidp, &ret, 0, req);
238305488Sdavidcs
239305488Sdavidcs	if (err || !req->newptr)
240305488Sdavidcs		return (err);
241305488Sdavidcs
242305488Sdavidcs	ha = (qla_host_t *)arg1;
243322972Sdavidcs	if (QLA_LOCK(ha, __func__, QLA_LOCK_DEFAULT_MS_TIMEOUT, 0) == 0) {
244322972Sdavidcs		err = qla_get_cam_search_mode(ha);
245322972Sdavidcs		QLA_UNLOCK(ha, __func__);
246322972Sdavidcs	} else {
247322972Sdavidcs		device_printf(ha->pci_dev, "%s: failed\n", __func__);
248322972Sdavidcs	}
249305488Sdavidcs
250305488Sdavidcs	return (err);
251305488Sdavidcs}
252305488Sdavidcs
253322972Sdavidcsstatic void
254322972Sdavidcsqlnx_add_hw_mac_stats_sysctls(qla_host_t *ha)
255322972Sdavidcs{
256322972Sdavidcs        struct sysctl_ctx_list  *ctx;
257322972Sdavidcs        struct sysctl_oid_list  *children;
258322972Sdavidcs        struct sysctl_oid       *ctx_oid;
259305488Sdavidcs
260322972Sdavidcs        ctx = device_get_sysctl_ctx(ha->pci_dev);
261322972Sdavidcs        children = SYSCTL_CHILDREN(device_get_sysctl_tree(ha->pci_dev));
262322972Sdavidcs
263322972Sdavidcs        ctx_oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats_hw_mac",
264322972Sdavidcs                        CTLFLAG_RD, NULL, "stats_hw_mac");
265322972Sdavidcs        children = SYSCTL_CHILDREN(ctx_oid);
266322972Sdavidcs
267322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
268322972Sdavidcs                OID_AUTO, "xmt_frames",
269322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.xmt_frames,
270322972Sdavidcs                "xmt_frames");
271322972Sdavidcs
272322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
273322972Sdavidcs                OID_AUTO, "xmt_bytes",
274322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.xmt_bytes,
275322972Sdavidcs                "xmt_frames");
276322972Sdavidcs
277322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
278322972Sdavidcs                OID_AUTO, "xmt_mcast_pkts",
279322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.xmt_mcast_pkts,
280322972Sdavidcs                "xmt_mcast_pkts");
281322972Sdavidcs
282322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
283322972Sdavidcs                OID_AUTO, "xmt_bcast_pkts",
284322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.xmt_bcast_pkts,
285322972Sdavidcs                "xmt_bcast_pkts");
286322972Sdavidcs
287322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
288322972Sdavidcs                OID_AUTO, "xmt_pause_frames",
289322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.xmt_pause_frames,
290322972Sdavidcs                "xmt_pause_frames");
291322972Sdavidcs
292322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
293322972Sdavidcs                OID_AUTO, "xmt_cntrl_pkts",
294322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.xmt_cntrl_pkts,
295322972Sdavidcs                "xmt_cntrl_pkts");
296322972Sdavidcs
297322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
298322972Sdavidcs                OID_AUTO, "xmt_pkt_lt_64bytes",
299322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.xmt_pkt_lt_64bytes,
300322972Sdavidcs                "xmt_pkt_lt_64bytes");
301322972Sdavidcs
302322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
303322972Sdavidcs                OID_AUTO, "xmt_pkt_lt_127bytes",
304322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.xmt_pkt_lt_127bytes,
305322972Sdavidcs                "xmt_pkt_lt_127bytes");
306322972Sdavidcs
307322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
308322972Sdavidcs                OID_AUTO, "xmt_pkt_lt_255bytes",
309322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.xmt_pkt_lt_255bytes,
310322972Sdavidcs                "xmt_pkt_lt_255bytes");
311322972Sdavidcs
312322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
313322972Sdavidcs                OID_AUTO, "xmt_pkt_lt_511bytes",
314322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.xmt_pkt_lt_511bytes,
315322972Sdavidcs                "xmt_pkt_lt_511bytes");
316322972Sdavidcs
317322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
318322972Sdavidcs                OID_AUTO, "xmt_pkt_lt_1023bytes",
319322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.xmt_pkt_lt_1023bytes,
320322972Sdavidcs                "xmt_pkt_lt_1023bytes");
321322972Sdavidcs
322322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
323322972Sdavidcs                OID_AUTO, "xmt_pkt_lt_1518bytes",
324322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.xmt_pkt_lt_1518bytes,
325322972Sdavidcs                "xmt_pkt_lt_1518bytes");
326322972Sdavidcs
327322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
328322972Sdavidcs                OID_AUTO, "xmt_pkt_gt_1518bytes",
329322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.xmt_pkt_gt_1518bytes,
330322972Sdavidcs                "xmt_pkt_gt_1518bytes");
331322972Sdavidcs
332322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
333322972Sdavidcs                OID_AUTO, "rcv_frames",
334322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.rcv_frames,
335322972Sdavidcs                "rcv_frames");
336322972Sdavidcs
337322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
338322972Sdavidcs                OID_AUTO, "rcv_bytes",
339322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.rcv_bytes,
340322972Sdavidcs                "rcv_bytes");
341322972Sdavidcs
342322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
343322972Sdavidcs                OID_AUTO, "rcv_mcast_pkts",
344322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.rcv_mcast_pkts,
345322972Sdavidcs                "rcv_mcast_pkts");
346322972Sdavidcs
347322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
348322972Sdavidcs                OID_AUTO, "rcv_bcast_pkts",
349322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.rcv_bcast_pkts,
350322972Sdavidcs                "rcv_bcast_pkts");
351322972Sdavidcs
352322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
353322972Sdavidcs                OID_AUTO, "rcv_pause_frames",
354322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.rcv_pause_frames,
355322972Sdavidcs                "rcv_pause_frames");
356322972Sdavidcs
357322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
358322972Sdavidcs                OID_AUTO, "rcv_cntrl_pkts",
359322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.rcv_cntrl_pkts,
360322972Sdavidcs                "rcv_cntrl_pkts");
361322972Sdavidcs
362322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
363322972Sdavidcs                OID_AUTO, "rcv_pkt_lt_64bytes",
364322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.rcv_pkt_lt_64bytes,
365322972Sdavidcs                "rcv_pkt_lt_64bytes");
366322972Sdavidcs
367322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
368322972Sdavidcs                OID_AUTO, "rcv_pkt_lt_127bytes",
369322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.rcv_pkt_lt_127bytes,
370322972Sdavidcs                "rcv_pkt_lt_127bytes");
371322972Sdavidcs
372322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
373322972Sdavidcs                OID_AUTO, "rcv_pkt_lt_255bytes",
374322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.rcv_pkt_lt_255bytes,
375322972Sdavidcs                "rcv_pkt_lt_255bytes");
376322972Sdavidcs
377322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
378322972Sdavidcs                OID_AUTO, "rcv_pkt_lt_511bytes",
379322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.rcv_pkt_lt_511bytes,
380322972Sdavidcs                "rcv_pkt_lt_511bytes");
381322972Sdavidcs
382322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
383322972Sdavidcs                OID_AUTO, "rcv_pkt_lt_1023bytes",
384322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.rcv_pkt_lt_1023bytes,
385322972Sdavidcs                "rcv_pkt_lt_1023bytes");
386322972Sdavidcs
387322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
388322972Sdavidcs                OID_AUTO, "rcv_pkt_lt_1518bytes",
389322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.rcv_pkt_lt_1518bytes,
390322972Sdavidcs                "rcv_pkt_lt_1518bytes");
391322972Sdavidcs
392322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
393322972Sdavidcs                OID_AUTO, "rcv_pkt_gt_1518bytes",
394322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.rcv_pkt_gt_1518bytes,
395322972Sdavidcs                "rcv_pkt_gt_1518bytes");
396322972Sdavidcs
397322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
398322972Sdavidcs                OID_AUTO, "rcv_len_error",
399322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.rcv_len_error,
400322972Sdavidcs                "rcv_len_error");
401322972Sdavidcs
402322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
403322972Sdavidcs                OID_AUTO, "rcv_len_small",
404322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.rcv_len_small,
405322972Sdavidcs                "rcv_len_small");
406322972Sdavidcs
407322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
408322972Sdavidcs                OID_AUTO, "rcv_len_large",
409322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.rcv_len_large,
410322972Sdavidcs                "rcv_len_large");
411322972Sdavidcs
412322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
413322972Sdavidcs                OID_AUTO, "rcv_jabber",
414322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.rcv_jabber,
415322972Sdavidcs                "rcv_jabber");
416322972Sdavidcs
417322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
418322972Sdavidcs                OID_AUTO, "rcv_dropped",
419322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.rcv_dropped,
420322972Sdavidcs                "rcv_dropped");
421322972Sdavidcs
422322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
423322972Sdavidcs                OID_AUTO, "fcs_error",
424322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.fcs_error,
425322972Sdavidcs                "fcs_error");
426322972Sdavidcs
427322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
428322972Sdavidcs                OID_AUTO, "align_error",
429322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.align_error,
430322972Sdavidcs                "align_error");
431322972Sdavidcs
432322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
433322972Sdavidcs                OID_AUTO, "eswitched_frames",
434322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.eswitched_frames,
435322972Sdavidcs                "eswitched_frames");
436322972Sdavidcs
437322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
438322972Sdavidcs                OID_AUTO, "eswitched_bytes",
439322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.eswitched_bytes,
440322972Sdavidcs                "eswitched_bytes");
441322972Sdavidcs
442322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
443322972Sdavidcs                OID_AUTO, "eswitched_mcast_frames",
444322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.eswitched_mcast_frames,
445322972Sdavidcs                "eswitched_mcast_frames");
446322972Sdavidcs
447322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
448322972Sdavidcs                OID_AUTO, "eswitched_bcast_frames",
449322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.eswitched_bcast_frames,
450322972Sdavidcs                "eswitched_bcast_frames");
451322972Sdavidcs
452322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
453322972Sdavidcs                OID_AUTO, "eswitched_ucast_frames",
454322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.eswitched_ucast_frames,
455322972Sdavidcs                "eswitched_ucast_frames");
456322972Sdavidcs
457322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
458322972Sdavidcs                OID_AUTO, "eswitched_err_free_frames",
459322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.eswitched_err_free_frames,
460322972Sdavidcs                "eswitched_err_free_frames");
461322972Sdavidcs
462322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
463322972Sdavidcs                OID_AUTO, "eswitched_err_free_bytes",
464322972Sdavidcs                CTLFLAG_RD, &ha->hw.mac.eswitched_err_free_bytes,
465322972Sdavidcs                "eswitched_err_free_bytes");
466322972Sdavidcs
467322972Sdavidcs	return;
468322972Sdavidcs}
469322972Sdavidcs
470322972Sdavidcsstatic void
471322972Sdavidcsqlnx_add_hw_rcv_stats_sysctls(qla_host_t *ha)
472322972Sdavidcs{
473322972Sdavidcs        struct sysctl_ctx_list  *ctx;
474322972Sdavidcs        struct sysctl_oid_list  *children;
475322972Sdavidcs        struct sysctl_oid       *ctx_oid;
476322972Sdavidcs
477322972Sdavidcs        ctx = device_get_sysctl_ctx(ha->pci_dev);
478322972Sdavidcs        children = SYSCTL_CHILDREN(device_get_sysctl_tree(ha->pci_dev));
479322972Sdavidcs
480322972Sdavidcs        ctx_oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats_hw_rcv",
481322972Sdavidcs                        CTLFLAG_RD, NULL, "stats_hw_rcv");
482322972Sdavidcs        children = SYSCTL_CHILDREN(ctx_oid);
483322972Sdavidcs
484322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
485322972Sdavidcs                OID_AUTO, "total_bytes",
486322972Sdavidcs                CTLFLAG_RD, &ha->hw.rcv.total_bytes,
487322972Sdavidcs                "total_bytes");
488322972Sdavidcs
489322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
490322972Sdavidcs                OID_AUTO, "total_pkts",
491322972Sdavidcs                CTLFLAG_RD, &ha->hw.rcv.total_pkts,
492322972Sdavidcs                "total_pkts");
493322972Sdavidcs
494322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
495322972Sdavidcs                OID_AUTO, "lro_pkt_count",
496322972Sdavidcs                CTLFLAG_RD, &ha->hw.rcv.lro_pkt_count,
497322972Sdavidcs                "lro_pkt_count");
498322972Sdavidcs
499322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
500322972Sdavidcs                OID_AUTO, "sw_pkt_count",
501322972Sdavidcs                CTLFLAG_RD, &ha->hw.rcv.sw_pkt_count,
502322972Sdavidcs                "sw_pkt_count");
503322972Sdavidcs
504322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
505322972Sdavidcs                OID_AUTO, "ip_chksum_err",
506322972Sdavidcs                CTLFLAG_RD, &ha->hw.rcv.ip_chksum_err,
507322972Sdavidcs                "ip_chksum_err");
508322972Sdavidcs
509322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
510322972Sdavidcs                OID_AUTO, "pkts_wo_acntxts",
511322972Sdavidcs                CTLFLAG_RD, &ha->hw.rcv.pkts_wo_acntxts,
512322972Sdavidcs                "pkts_wo_acntxts");
513322972Sdavidcs
514322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
515322972Sdavidcs                OID_AUTO, "pkts_dropped_no_sds_card",
516322972Sdavidcs                CTLFLAG_RD, &ha->hw.rcv.pkts_dropped_no_sds_card,
517322972Sdavidcs                "pkts_dropped_no_sds_card");
518322972Sdavidcs
519322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
520322972Sdavidcs                OID_AUTO, "pkts_dropped_no_sds_host",
521322972Sdavidcs                CTLFLAG_RD, &ha->hw.rcv.pkts_dropped_no_sds_host,
522322972Sdavidcs                "pkts_dropped_no_sds_host");
523322972Sdavidcs
524322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
525322972Sdavidcs                OID_AUTO, "oversized_pkts",
526322972Sdavidcs                CTLFLAG_RD, &ha->hw.rcv.oversized_pkts,
527322972Sdavidcs                "oversized_pkts");
528322972Sdavidcs
529322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
530322972Sdavidcs                OID_AUTO, "pkts_dropped_no_rds",
531322972Sdavidcs                CTLFLAG_RD, &ha->hw.rcv.pkts_dropped_no_rds,
532322972Sdavidcs                "pkts_dropped_no_rds");
533322972Sdavidcs
534322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
535322972Sdavidcs                OID_AUTO, "unxpctd_mcast_pkts",
536322972Sdavidcs                CTLFLAG_RD, &ha->hw.rcv.unxpctd_mcast_pkts,
537322972Sdavidcs                "unxpctd_mcast_pkts");
538322972Sdavidcs
539322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
540322972Sdavidcs                OID_AUTO, "re1_fbq_error",
541322972Sdavidcs                CTLFLAG_RD, &ha->hw.rcv.re1_fbq_error,
542322972Sdavidcs                "re1_fbq_error");
543322972Sdavidcs
544322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
545322972Sdavidcs                OID_AUTO, "invalid_mac_addr",
546322972Sdavidcs                CTLFLAG_RD, &ha->hw.rcv.invalid_mac_addr,
547322972Sdavidcs                "invalid_mac_addr");
548322972Sdavidcs
549322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
550322972Sdavidcs                OID_AUTO, "rds_prime_trys",
551322972Sdavidcs                CTLFLAG_RD, &ha->hw.rcv.rds_prime_trys,
552322972Sdavidcs                "rds_prime_trys");
553322972Sdavidcs
554322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
555322972Sdavidcs                OID_AUTO, "rds_prime_success",
556322972Sdavidcs                CTLFLAG_RD, &ha->hw.rcv.rds_prime_success,
557322972Sdavidcs                "rds_prime_success");
558322972Sdavidcs
559322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
560322972Sdavidcs                OID_AUTO, "lro_flows_added",
561322972Sdavidcs                CTLFLAG_RD, &ha->hw.rcv.lro_flows_added,
562322972Sdavidcs                "lro_flows_added");
563322972Sdavidcs
564322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
565322972Sdavidcs                OID_AUTO, "lro_flows_deleted",
566322972Sdavidcs                CTLFLAG_RD, &ha->hw.rcv.lro_flows_deleted,
567322972Sdavidcs                "lro_flows_deleted");
568322972Sdavidcs
569322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
570322972Sdavidcs                OID_AUTO, "lro_flows_active",
571322972Sdavidcs                CTLFLAG_RD, &ha->hw.rcv.lro_flows_active,
572322972Sdavidcs                "lro_flows_active");
573322972Sdavidcs
574322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
575322972Sdavidcs                OID_AUTO, "pkts_droped_unknown",
576322972Sdavidcs                CTLFLAG_RD, &ha->hw.rcv.pkts_droped_unknown,
577322972Sdavidcs                "pkts_droped_unknown");
578322972Sdavidcs
579322972Sdavidcs        SYSCTL_ADD_QUAD(ctx, children,
580322972Sdavidcs                OID_AUTO, "pkts_cnt_oversized",
581322972Sdavidcs                CTLFLAG_RD, &ha->hw.rcv.pkts_cnt_oversized,
582322972Sdavidcs                "pkts_cnt_oversized");
583322972Sdavidcs
584322972Sdavidcs	return;
585322972Sdavidcs}
586322972Sdavidcs
587322972Sdavidcsstatic void
588322972Sdavidcsqlnx_add_hw_xmt_stats_sysctls(qla_host_t *ha)
589322972Sdavidcs{
590322972Sdavidcs        struct sysctl_ctx_list  *ctx;
591322972Sdavidcs        struct sysctl_oid_list  *children;
592322972Sdavidcs        struct sysctl_oid_list  *node_children;
593322972Sdavidcs        struct sysctl_oid       *ctx_oid;
594322972Sdavidcs        int                     i;
595322972Sdavidcs        uint8_t                 name_str[16];
596322972Sdavidcs
597322972Sdavidcs        ctx = device_get_sysctl_ctx(ha->pci_dev);
598322972Sdavidcs        children = SYSCTL_CHILDREN(device_get_sysctl_tree(ha->pci_dev));
599322972Sdavidcs
600322972Sdavidcs        ctx_oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats_hw_xmt",
601322972Sdavidcs                        CTLFLAG_RD, NULL, "stats_hw_xmt");
602322972Sdavidcs        children = SYSCTL_CHILDREN(ctx_oid);
603322972Sdavidcs
604322972Sdavidcs        for (i = 0; i < ha->hw.num_tx_rings; i++) {
605322972Sdavidcs
606322972Sdavidcs                bzero(name_str, (sizeof(uint8_t) * sizeof(name_str)));
607322972Sdavidcs                snprintf(name_str, sizeof(name_str), "%d", i);
608322972Sdavidcs
609322972Sdavidcs                ctx_oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, name_str,
610322972Sdavidcs                        CTLFLAG_RD, NULL, name_str);
611322972Sdavidcs                node_children = SYSCTL_CHILDREN(ctx_oid);
612322972Sdavidcs
613322972Sdavidcs                /* Tx Related */
614322972Sdavidcs
615322972Sdavidcs                SYSCTL_ADD_QUAD(ctx, node_children,
616322972Sdavidcs			OID_AUTO, "total_bytes",
617322972Sdavidcs                        CTLFLAG_RD, &ha->hw.xmt[i].total_bytes,
618322972Sdavidcs                        "total_bytes");
619322972Sdavidcs
620322972Sdavidcs                SYSCTL_ADD_QUAD(ctx, node_children,
621322972Sdavidcs			OID_AUTO, "total_pkts",
622322972Sdavidcs                        CTLFLAG_RD, &ha->hw.xmt[i].total_pkts,
623322972Sdavidcs                        "total_pkts");
624322972Sdavidcs
625322972Sdavidcs                SYSCTL_ADD_QUAD(ctx, node_children,
626322972Sdavidcs			OID_AUTO, "errors",
627322972Sdavidcs                        CTLFLAG_RD, &ha->hw.xmt[i].errors,
628322972Sdavidcs                        "errors");
629322972Sdavidcs
630322972Sdavidcs                SYSCTL_ADD_QUAD(ctx, node_children,
631322972Sdavidcs			OID_AUTO, "pkts_dropped",
632322972Sdavidcs                        CTLFLAG_RD, &ha->hw.xmt[i].pkts_dropped,
633322972Sdavidcs                        "pkts_dropped");
634322972Sdavidcs
635322972Sdavidcs                SYSCTL_ADD_QUAD(ctx, node_children,
636322972Sdavidcs			OID_AUTO, "switch_pkts",
637322972Sdavidcs                        CTLFLAG_RD, &ha->hw.xmt[i].switch_pkts,
638322972Sdavidcs                        "switch_pkts");
639322972Sdavidcs
640322972Sdavidcs                SYSCTL_ADD_QUAD(ctx, node_children,
641322972Sdavidcs			OID_AUTO, "num_buffers",
642322972Sdavidcs                        CTLFLAG_RD, &ha->hw.xmt[i].num_buffers,
643322972Sdavidcs                        "num_buffers");
644322972Sdavidcs	}
645322972Sdavidcs
646322972Sdavidcs	return;
647322972Sdavidcs}
648322972Sdavidcs
649322972Sdavidcsstatic void
650330555Sdavidcsqlnx_add_hw_mbx_cmpl_stats_sysctls(qla_host_t *ha)
651330555Sdavidcs{
652330555Sdavidcs        struct sysctl_ctx_list  *ctx;
653330555Sdavidcs        struct sysctl_oid_list  *node_children;
654330555Sdavidcs
655330555Sdavidcs        ctx = device_get_sysctl_ctx(ha->pci_dev);
656330555Sdavidcs        node_children = SYSCTL_CHILDREN(device_get_sysctl_tree(ha->pci_dev));
657330555Sdavidcs
658330555Sdavidcs	SYSCTL_ADD_QUAD(ctx, node_children,
659330555Sdavidcs		OID_AUTO, "mbx_completion_time_lt_200ms",
660330555Sdavidcs		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[0],
661330555Sdavidcs		"mbx_completion_time_lt_200ms");
662330555Sdavidcs
663330555Sdavidcs	SYSCTL_ADD_QUAD(ctx, node_children,
664330555Sdavidcs		OID_AUTO, "mbx_completion_time_200ms_400ms",
665330555Sdavidcs		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[1],
666330555Sdavidcs		"mbx_completion_time_200ms_400ms");
667330555Sdavidcs
668330555Sdavidcs	SYSCTL_ADD_QUAD(ctx, node_children,
669330555Sdavidcs		OID_AUTO, "mbx_completion_time_400ms_600ms",
670330555Sdavidcs		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[2],
671330555Sdavidcs		"mbx_completion_time_400ms_600ms");
672330555Sdavidcs
673330555Sdavidcs	SYSCTL_ADD_QUAD(ctx, node_children,
674330555Sdavidcs		OID_AUTO, "mbx_completion_time_600ms_800ms",
675330555Sdavidcs		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[3],
676330555Sdavidcs		"mbx_completion_time_600ms_800ms");
677330555Sdavidcs
678330555Sdavidcs	SYSCTL_ADD_QUAD(ctx, node_children,
679330555Sdavidcs		OID_AUTO, "mbx_completion_time_800ms_1000ms",
680330555Sdavidcs		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[4],
681330555Sdavidcs		"mbx_completion_time_800ms_1000ms");
682330555Sdavidcs
683330555Sdavidcs	SYSCTL_ADD_QUAD(ctx, node_children,
684330555Sdavidcs		OID_AUTO, "mbx_completion_time_1000ms_1200ms",
685330555Sdavidcs		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[5],
686330555Sdavidcs		"mbx_completion_time_1000ms_1200ms");
687330555Sdavidcs
688330555Sdavidcs	SYSCTL_ADD_QUAD(ctx, node_children,
689330555Sdavidcs		OID_AUTO, "mbx_completion_time_1200ms_1400ms",
690330555Sdavidcs		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[6],
691330555Sdavidcs		"mbx_completion_time_1200ms_1400ms");
692330555Sdavidcs
693330555Sdavidcs	SYSCTL_ADD_QUAD(ctx, node_children,
694330555Sdavidcs		OID_AUTO, "mbx_completion_time_1400ms_1600ms",
695330555Sdavidcs		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[7],
696330555Sdavidcs		"mbx_completion_time_1400ms_1600ms");
697330555Sdavidcs
698330555Sdavidcs	SYSCTL_ADD_QUAD(ctx, node_children,
699330555Sdavidcs		OID_AUTO, "mbx_completion_time_1600ms_1800ms",
700330555Sdavidcs		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[8],
701330555Sdavidcs		"mbx_completion_time_1600ms_1800ms");
702330555Sdavidcs
703330555Sdavidcs	SYSCTL_ADD_QUAD(ctx, node_children,
704330555Sdavidcs		OID_AUTO, "mbx_completion_time_1800ms_2000ms",
705330555Sdavidcs		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[9],
706330555Sdavidcs		"mbx_completion_time_1800ms_2000ms");
707330555Sdavidcs
708330555Sdavidcs	SYSCTL_ADD_QUAD(ctx, node_children,
709330555Sdavidcs		OID_AUTO, "mbx_completion_time_2000ms_2200ms",
710330555Sdavidcs		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[10],
711330555Sdavidcs		"mbx_completion_time_2000ms_2200ms");
712330555Sdavidcs
713330555Sdavidcs	SYSCTL_ADD_QUAD(ctx, node_children,
714330555Sdavidcs		OID_AUTO, "mbx_completion_time_2200ms_2400ms",
715330555Sdavidcs		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[11],
716330555Sdavidcs		"mbx_completion_time_2200ms_2400ms");
717330555Sdavidcs
718330555Sdavidcs	SYSCTL_ADD_QUAD(ctx, node_children,
719330555Sdavidcs		OID_AUTO, "mbx_completion_time_2400ms_2600ms",
720330555Sdavidcs		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[12],
721330555Sdavidcs		"mbx_completion_time_2400ms_2600ms");
722330555Sdavidcs
723330555Sdavidcs	SYSCTL_ADD_QUAD(ctx, node_children,
724330555Sdavidcs		OID_AUTO, "mbx_completion_time_2600ms_2800ms",
725330555Sdavidcs		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[13],
726330555Sdavidcs		"mbx_completion_time_2600ms_2800ms");
727330555Sdavidcs
728330555Sdavidcs	SYSCTL_ADD_QUAD(ctx, node_children,
729330555Sdavidcs		OID_AUTO, "mbx_completion_time_2800ms_3000ms",
730330555Sdavidcs		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[14],
731330555Sdavidcs		"mbx_completion_time_2800ms_3000ms");
732330555Sdavidcs
733330555Sdavidcs	SYSCTL_ADD_QUAD(ctx, node_children,
734330555Sdavidcs		OID_AUTO, "mbx_completion_time_3000ms_4000ms",
735330555Sdavidcs		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[15],
736330555Sdavidcs		"mbx_completion_time_3000ms_4000ms");
737330555Sdavidcs
738330555Sdavidcs	SYSCTL_ADD_QUAD(ctx, node_children,
739330555Sdavidcs		OID_AUTO, "mbx_completion_time_4000ms_5000ms",
740330555Sdavidcs		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[16],
741330555Sdavidcs		"mbx_completion_time_4000ms_5000ms");
742330555Sdavidcs
743330555Sdavidcs	SYSCTL_ADD_QUAD(ctx, node_children,
744330555Sdavidcs		OID_AUTO, "mbx_completion_host_mbx_cntrl_timeout",
745330555Sdavidcs		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[17],
746330555Sdavidcs		"mbx_completion_host_mbx_cntrl_timeout");
747330555Sdavidcs
748330555Sdavidcs	SYSCTL_ADD_QUAD(ctx, node_children,
749330555Sdavidcs		OID_AUTO, "mbx_completion_fw_mbx_cntrl_timeout",
750330555Sdavidcs		CTLFLAG_RD, &ha->hw.mbx_comp_msecs[18],
751330555Sdavidcs		"mbx_completion_fw_mbx_cntrl_timeout");
752330555Sdavidcs	return;
753330555Sdavidcs}
754330555Sdavidcs
755330555Sdavidcsstatic void
756322972Sdavidcsqlnx_add_hw_stats_sysctls(qla_host_t *ha)
757322972Sdavidcs{
758322972Sdavidcs	qlnx_add_hw_mac_stats_sysctls(ha);
759322972Sdavidcs	qlnx_add_hw_rcv_stats_sysctls(ha);
760322972Sdavidcs	qlnx_add_hw_xmt_stats_sysctls(ha);
761330555Sdavidcs	qlnx_add_hw_mbx_cmpl_stats_sysctls(ha);
762322972Sdavidcs
763322972Sdavidcs	return;
764322972Sdavidcs}
765322972Sdavidcs
766322972Sdavidcsstatic void
767322972Sdavidcsqlnx_add_drvr_sds_stats(qla_host_t *ha)
768322972Sdavidcs{
769322972Sdavidcs        struct sysctl_ctx_list  *ctx;
770322972Sdavidcs        struct sysctl_oid_list  *children;
771322972Sdavidcs        struct sysctl_oid_list  *node_children;
772322972Sdavidcs        struct sysctl_oid       *ctx_oid;
773322972Sdavidcs        int                     i;
774322972Sdavidcs        uint8_t                 name_str[16];
775322972Sdavidcs
776322972Sdavidcs        ctx = device_get_sysctl_ctx(ha->pci_dev);
777322972Sdavidcs        children = SYSCTL_CHILDREN(device_get_sysctl_tree(ha->pci_dev));
778322972Sdavidcs
779322972Sdavidcs        ctx_oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats_drvr_sds",
780322972Sdavidcs                        CTLFLAG_RD, NULL, "stats_drvr_sds");
781322972Sdavidcs        children = SYSCTL_CHILDREN(ctx_oid);
782322972Sdavidcs
783322972Sdavidcs        for (i = 0; i < ha->hw.num_sds_rings; i++) {
784322972Sdavidcs
785322972Sdavidcs                bzero(name_str, (sizeof(uint8_t) * sizeof(name_str)));
786322972Sdavidcs                snprintf(name_str, sizeof(name_str), "%d", i);
787322972Sdavidcs
788322972Sdavidcs                ctx_oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, name_str,
789322972Sdavidcs                        CTLFLAG_RD, NULL, name_str);
790322972Sdavidcs                node_children = SYSCTL_CHILDREN(ctx_oid);
791322972Sdavidcs
792322972Sdavidcs                SYSCTL_ADD_QUAD(ctx, node_children,
793322972Sdavidcs			OID_AUTO, "intr_count",
794322972Sdavidcs                        CTLFLAG_RD, &ha->hw.sds[i].intr_count,
795322972Sdavidcs                        "intr_count");
796322972Sdavidcs
797322972Sdavidcs                SYSCTL_ADD_UINT(ctx, node_children,
798322972Sdavidcs			OID_AUTO, "rx_free",
799322972Sdavidcs                        CTLFLAG_RD, &ha->hw.sds[i].rx_free,
800322972Sdavidcs			ha->hw.sds[i].rx_free, "rx_free");
801322972Sdavidcs	}
802322972Sdavidcs
803322972Sdavidcs	return;
804322972Sdavidcs}
805322972Sdavidcsstatic void
806322972Sdavidcsqlnx_add_drvr_rds_stats(qla_host_t *ha)
807322972Sdavidcs{
808322972Sdavidcs        struct sysctl_ctx_list  *ctx;
809322972Sdavidcs        struct sysctl_oid_list  *children;
810322972Sdavidcs        struct sysctl_oid_list  *node_children;
811322972Sdavidcs        struct sysctl_oid       *ctx_oid;
812322972Sdavidcs        int                     i;
813322972Sdavidcs        uint8_t                 name_str[16];
814322972Sdavidcs
815322972Sdavidcs        ctx = device_get_sysctl_ctx(ha->pci_dev);
816322972Sdavidcs        children = SYSCTL_CHILDREN(device_get_sysctl_tree(ha->pci_dev));
817322972Sdavidcs
818322972Sdavidcs        ctx_oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats_drvr_rds",
819322972Sdavidcs                        CTLFLAG_RD, NULL, "stats_drvr_rds");
820322972Sdavidcs        children = SYSCTL_CHILDREN(ctx_oid);
821322972Sdavidcs
822322972Sdavidcs        for (i = 0; i < ha->hw.num_rds_rings; i++) {
823322972Sdavidcs
824322972Sdavidcs                bzero(name_str, (sizeof(uint8_t) * sizeof(name_str)));
825322972Sdavidcs                snprintf(name_str, sizeof(name_str), "%d", i);
826322972Sdavidcs
827322972Sdavidcs                ctx_oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, name_str,
828322972Sdavidcs                        CTLFLAG_RD, NULL, name_str);
829322972Sdavidcs                node_children = SYSCTL_CHILDREN(ctx_oid);
830322972Sdavidcs
831322972Sdavidcs                SYSCTL_ADD_QUAD(ctx, node_children,
832322972Sdavidcs			OID_AUTO, "count",
833322972Sdavidcs                        CTLFLAG_RD, &ha->hw.rds[i].count,
834322972Sdavidcs                        "count");
835322972Sdavidcs
836322972Sdavidcs                SYSCTL_ADD_QUAD(ctx, node_children,
837322972Sdavidcs			OID_AUTO, "lro_pkt_count",
838322972Sdavidcs                        CTLFLAG_RD, &ha->hw.rds[i].lro_pkt_count,
839322972Sdavidcs                        "lro_pkt_count");
840322972Sdavidcs
841322972Sdavidcs                SYSCTL_ADD_QUAD(ctx, node_children,
842322972Sdavidcs			OID_AUTO, "lro_bytes",
843322972Sdavidcs                        CTLFLAG_RD, &ha->hw.rds[i].lro_bytes,
844322972Sdavidcs                        "lro_bytes");
845322972Sdavidcs	}
846322972Sdavidcs
847322972Sdavidcs	return;
848322972Sdavidcs}
849322972Sdavidcs
850322972Sdavidcsstatic void
851322972Sdavidcsqlnx_add_drvr_tx_stats(qla_host_t *ha)
852322972Sdavidcs{
853322972Sdavidcs        struct sysctl_ctx_list  *ctx;
854322972Sdavidcs        struct sysctl_oid_list  *children;
855322972Sdavidcs        struct sysctl_oid_list  *node_children;
856322972Sdavidcs        struct sysctl_oid       *ctx_oid;
857322972Sdavidcs        int                     i;
858322972Sdavidcs        uint8_t                 name_str[16];
859322972Sdavidcs
860322972Sdavidcs        ctx = device_get_sysctl_ctx(ha->pci_dev);
861322972Sdavidcs        children = SYSCTL_CHILDREN(device_get_sysctl_tree(ha->pci_dev));
862322972Sdavidcs
863322972Sdavidcs        ctx_oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats_drvr_xmt",
864322972Sdavidcs                        CTLFLAG_RD, NULL, "stats_drvr_xmt");
865322972Sdavidcs        children = SYSCTL_CHILDREN(ctx_oid);
866322972Sdavidcs
867322972Sdavidcs        for (i = 0; i < ha->hw.num_tx_rings; i++) {
868322972Sdavidcs
869322972Sdavidcs                bzero(name_str, (sizeof(uint8_t) * sizeof(name_str)));
870322972Sdavidcs                snprintf(name_str, sizeof(name_str), "%d", i);
871322972Sdavidcs
872322972Sdavidcs                ctx_oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, name_str,
873322972Sdavidcs                        CTLFLAG_RD, NULL, name_str);
874322972Sdavidcs                node_children = SYSCTL_CHILDREN(ctx_oid);
875322972Sdavidcs
876322972Sdavidcs                SYSCTL_ADD_QUAD(ctx, node_children,
877322972Sdavidcs			OID_AUTO, "count",
878322972Sdavidcs                        CTLFLAG_RD, &ha->tx_ring[i].count,
879322972Sdavidcs                        "count");
880322972Sdavidcs
881322972Sdavidcs#ifdef QL_ENABLE_ISCSI_TLV
882322972Sdavidcs                SYSCTL_ADD_QUAD(ctx, node_children,
883322972Sdavidcs			OID_AUTO, "iscsi_pkt_count",
884322972Sdavidcs                        CTLFLAG_RD, &ha->tx_ring[i].iscsi_pkt_count,
885322972Sdavidcs                        "iscsi_pkt_count");
886322972Sdavidcs#endif /* #ifdef QL_ENABLE_ISCSI_TLV */
887322972Sdavidcs	}
888322972Sdavidcs
889322972Sdavidcs	return;
890322972Sdavidcs}
891322972Sdavidcs
892322972Sdavidcsstatic void
893322972Sdavidcsqlnx_add_drvr_stats_sysctls(qla_host_t *ha)
894322972Sdavidcs{
895322972Sdavidcs	qlnx_add_drvr_sds_stats(ha);
896322972Sdavidcs	qlnx_add_drvr_rds_stats(ha);
897322972Sdavidcs	qlnx_add_drvr_tx_stats(ha);
898322972Sdavidcs	return;
899322972Sdavidcs}
900322972Sdavidcs
901250661Sdavidcs/*
902250661Sdavidcs * Name: ql_hw_add_sysctls
903250661Sdavidcs * Function: Add P3Plus specific sysctls
904250661Sdavidcs */
905250661Sdavidcsvoid
906250661Sdavidcsql_hw_add_sysctls(qla_host_t *ha)
907250661Sdavidcs{
908250661Sdavidcs        device_t	dev;
909250661Sdavidcs
910250661Sdavidcs        dev = ha->pci_dev;
911250661Sdavidcs
912250661Sdavidcs	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
913250661Sdavidcs		SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
914250661Sdavidcs		OID_AUTO, "num_rds_rings", CTLFLAG_RD, &ha->hw.num_rds_rings,
915250661Sdavidcs		ha->hw.num_rds_rings, "Number of Rcv Descriptor Rings");
916250661Sdavidcs
917250661Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
918250661Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
919250661Sdavidcs                OID_AUTO, "num_sds_rings", CTLFLAG_RD, &ha->hw.num_sds_rings,
920250661Sdavidcs		ha->hw.num_sds_rings, "Number of Status Descriptor Rings");
921250661Sdavidcs
922250661Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
923250661Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
924250661Sdavidcs                OID_AUTO, "num_tx_rings", CTLFLAG_RD, &ha->hw.num_tx_rings,
925250661Sdavidcs		ha->hw.num_tx_rings, "Number of Transmit Rings");
926250661Sdavidcs
927250661Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
928250661Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
929250661Sdavidcs                OID_AUTO, "tx_ring_index", CTLFLAG_RW, &ha->txr_idx,
930250661Sdavidcs		ha->txr_idx, "Tx Ring Used");
931250661Sdavidcs
932250661Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
933250661Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
934250661Sdavidcs                OID_AUTO, "max_tx_segs", CTLFLAG_RD, &ha->hw.max_tx_segs,
935250661Sdavidcs		ha->hw.max_tx_segs, "Max # of Segments in a non-TSO pkt");
936250661Sdavidcs
937250661Sdavidcs	ha->hw.sds_cidx_thres = 32;
938250661Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
939250661Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
940250661Sdavidcs                OID_AUTO, "sds_cidx_thres", CTLFLAG_RW, &ha->hw.sds_cidx_thres,
941250661Sdavidcs		ha->hw.sds_cidx_thres,
942250661Sdavidcs		"Number of SDS entries to process before updating"
943250661Sdavidcs		" SDS Ring Consumer Index");
944250661Sdavidcs
945250661Sdavidcs	ha->hw.rds_pidx_thres = 32;
946250661Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
947250661Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
948250661Sdavidcs                OID_AUTO, "rds_pidx_thres", CTLFLAG_RW, &ha->hw.rds_pidx_thres,
949250661Sdavidcs		ha->hw.rds_pidx_thres,
950250661Sdavidcs		"Number of Rcv Rings Entries to post before updating"
951250661Sdavidcs		" RDS Ring Producer Index");
952250661Sdavidcs
953284741Sdavidcs        ha->hw.rcv_intr_coalesce = (3 << 16) | 256;
954284741Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
955284741Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
956284741Sdavidcs                OID_AUTO, "rcv_intr_coalesce", CTLFLAG_RW,
957284741Sdavidcs                &ha->hw.rcv_intr_coalesce,
958284741Sdavidcs                ha->hw.rcv_intr_coalesce,
959284741Sdavidcs                "Rcv Intr Coalescing Parameters\n"
960284741Sdavidcs                "\tbits 15:0 max packets\n"
961284741Sdavidcs                "\tbits 31:16 max micro-seconds to wait\n"
962284741Sdavidcs                "\tplease run\n"
963284741Sdavidcs                "\tifconfig <if> down && ifconfig <if> up\n"
964284741Sdavidcs                "\tto take effect \n");
965258155Sdavidcs
966284741Sdavidcs        ha->hw.xmt_intr_coalesce = (64 << 16) | 64;
967284741Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
968284741Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
969284741Sdavidcs                OID_AUTO, "xmt_intr_coalesce", CTLFLAG_RW,
970284741Sdavidcs                &ha->hw.xmt_intr_coalesce,
971284741Sdavidcs                ha->hw.xmt_intr_coalesce,
972284741Sdavidcs                "Xmt Intr Coalescing Parameters\n"
973284741Sdavidcs                "\tbits 15:0 max packets\n"
974284741Sdavidcs                "\tbits 31:16 max micro-seconds to wait\n"
975284741Sdavidcs                "\tplease run\n"
976284741Sdavidcs                "\tifconfig <if> down && ifconfig <if> up\n"
977284741Sdavidcs                "\tto take effect \n");
978284741Sdavidcs
979284741Sdavidcs        SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
980284741Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
981284741Sdavidcs                OID_AUTO, "port_cfg", CTLTYPE_INT | CTLFLAG_RW,
982284741Sdavidcs                (void *)ha, 0,
983284741Sdavidcs                qla_sysctl_port_cfg, "I",
984284741Sdavidcs                        "Set Port Configuration if values below "
985284741Sdavidcs                        "otherwise Get Port Configuration\n"
986284741Sdavidcs                        "\tBits 0-3 ; 1 = DCBX Enable; 0 = DCBX Disable\n"
987284741Sdavidcs                        "\tBits 4-7 : 0 = no pause; 1 = std ; 2 = ppm \n"
988284741Sdavidcs                        "\tBits 8-11: std pause cfg; 0 = xmt and rcv;"
989284741Sdavidcs                        " 1 = xmt only; 2 = rcv only;\n"
990284741Sdavidcs                );
991284741Sdavidcs
992305488Sdavidcs	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
993305488Sdavidcs		SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
994305488Sdavidcs		OID_AUTO, "set_cam_search_mode", CTLTYPE_INT | CTLFLAG_RW,
995305488Sdavidcs		(void *)ha, 0,
996305488Sdavidcs		qla_sysctl_set_cam_search_mode, "I",
997305488Sdavidcs			"Set CAM Search Mode"
998305488Sdavidcs			"\t 1 = search mode internal\n"
999305488Sdavidcs			"\t 2 = search mode auto\n");
1000305488Sdavidcs
1001305488Sdavidcs	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
1002305488Sdavidcs		SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1003305488Sdavidcs		OID_AUTO, "get_cam_search_mode", CTLTYPE_INT | CTLFLAG_RW,
1004305488Sdavidcs		(void *)ha, 0,
1005305488Sdavidcs		qla_sysctl_get_cam_search_mode, "I",
1006305488Sdavidcs			"Get CAM Search Mode"
1007305488Sdavidcs			"\t 1 = search mode internal\n"
1008305488Sdavidcs			"\t 2 = search mode auto\n");
1009305488Sdavidcs
1010284741Sdavidcs        ha->hw.enable_9kb = 1;
1011284741Sdavidcs
1012284741Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
1013284741Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1014284741Sdavidcs                OID_AUTO, "enable_9kb", CTLFLAG_RW, &ha->hw.enable_9kb,
1015284741Sdavidcs                ha->hw.enable_9kb, "Enable 9Kbyte Buffers when MTU = 9000");
1016284741Sdavidcs
1017317109Sdavidcs        ha->hw.enable_hw_lro = 1;
1018317109Sdavidcs
1019317109Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
1020317109Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1021317109Sdavidcs                OID_AUTO, "enable_hw_lro", CTLFLAG_RW, &ha->hw.enable_hw_lro,
1022317109Sdavidcs                ha->hw.enable_hw_lro, "Enable Hardware LRO; Default is true \n"
1023317109Sdavidcs		"\t 1 : Hardware LRO if LRO is enabled\n"
1024317109Sdavidcs		"\t 0 : Software LRO if LRO is enabled\n"
1025317109Sdavidcs		"\t Any change requires ifconfig down/up to take effect\n"
1026317109Sdavidcs		"\t Note that LRO may be turned off/on via ifconfig\n");
1027317109Sdavidcs
1028330555Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
1029330555Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1030330555Sdavidcs                OID_AUTO, "sp_log_index", CTLFLAG_RW, &ha->hw.sp_log_index,
1031330555Sdavidcs                ha->hw.sp_log_index, "sp_log_index");
1032330555Sdavidcs
1033330555Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
1034330555Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1035330555Sdavidcs                OID_AUTO, "sp_log_stop", CTLFLAG_RW, &ha->hw.sp_log_stop,
1036330555Sdavidcs                ha->hw.sp_log_stop, "sp_log_stop");
1037330555Sdavidcs
1038330555Sdavidcs        ha->hw.sp_log_stop_events = 0;
1039330555Sdavidcs
1040330555Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
1041330555Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1042330555Sdavidcs                OID_AUTO, "sp_log_stop_events", CTLFLAG_RW,
1043330555Sdavidcs		&ha->hw.sp_log_stop_events,
1044330555Sdavidcs                ha->hw.sp_log_stop_events, "Slow path event log is stopped"
1045330555Sdavidcs		" when OR of the following events occur \n"
1046330555Sdavidcs		"\t 0x01 : Heart beat Failure\n"
1047330555Sdavidcs		"\t 0x02 : Temperature Failure\n"
1048330555Sdavidcs		"\t 0x04 : HW Initialization Failure\n"
1049330555Sdavidcs		"\t 0x08 : Interface Initialization Failure\n"
1050330555Sdavidcs		"\t 0x10 : Error Recovery Failure\n");
1051330555Sdavidcs
1052250661Sdavidcs	ha->hw.mdump_active = 0;
1053250661Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
1054250661Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1055250661Sdavidcs                OID_AUTO, "minidump_active", CTLFLAG_RW, &ha->hw.mdump_active,
1056250661Sdavidcs		ha->hw.mdump_active,
1057305487Sdavidcs		"Minidump retrieval is Active");
1058250661Sdavidcs
1059305487Sdavidcs	ha->hw.mdump_done = 0;
1060250661Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
1061250661Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1062305487Sdavidcs                OID_AUTO, "mdump_done", CTLFLAG_RW,
1063305487Sdavidcs		&ha->hw.mdump_done, ha->hw.mdump_done,
1064305487Sdavidcs		"Minidump has been done and available for retrieval");
1065305487Sdavidcs
1066305487Sdavidcs	ha->hw.mdump_capture_mask = 0xF;
1067305487Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
1068305487Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1069305487Sdavidcs                OID_AUTO, "minidump_capture_mask", CTLFLAG_RW,
1070305487Sdavidcs		&ha->hw.mdump_capture_mask, ha->hw.mdump_capture_mask,
1071305487Sdavidcs		"Minidump capture mask");
1072250661Sdavidcs#ifdef QL_DBG
1073250661Sdavidcs
1074289635Sdavidcs	ha->err_inject = 0;
1075250661Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
1076250661Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1077250661Sdavidcs                OID_AUTO, "err_inject",
1078250661Sdavidcs                CTLFLAG_RW, &ha->err_inject, ha->err_inject,
1079250661Sdavidcs                "Error to be injected\n"
1080250661Sdavidcs                "\t\t\t 0: No Errors\n"
1081250661Sdavidcs                "\t\t\t 1: rcv: rxb struct invalid\n"
1082250661Sdavidcs                "\t\t\t 2: rcv: mp == NULL\n"
1083250661Sdavidcs                "\t\t\t 3: lro: rxb struct invalid\n"
1084250661Sdavidcs                "\t\t\t 4: lro: mp == NULL\n"
1085250661Sdavidcs                "\t\t\t 5: rcv: num handles invalid\n"
1086250661Sdavidcs                "\t\t\t 6: reg: indirect reg rd_wr failure\n"
1087250661Sdavidcs                "\t\t\t 7: ocm: offchip memory rd_wr failure\n"
1088250661Sdavidcs                "\t\t\t 8: mbx: mailbox command failure\n"
1089250661Sdavidcs                "\t\t\t 9: heartbeat failure\n"
1090305488Sdavidcs                "\t\t\t A: temperature failure\n"
1091332052Sdavidcs		"\t\t\t 11: m_getcl or m_getjcl failure\n"
1092332052Sdavidcs		"\t\t\t 13: Invalid Descriptor Count in SGL Receive\n"
1093332052Sdavidcs		"\t\t\t 14: Invalid Descriptor Count in LRO Receive\n"
1094332052Sdavidcs		"\t\t\t 15: peer port error recovery failure\n"
1095332052Sdavidcs		"\t\t\t 16: tx_buf[next_prod_index].mbuf != NULL\n" );
1096250661Sdavidcs
1097250661Sdavidcs	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
1098250661Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1099250661Sdavidcs                OID_AUTO, "peg_stop", CTLTYPE_INT | CTLFLAG_RW,
1100250661Sdavidcs                (void *)ha, 0,
1101250661Sdavidcs                qla_sysctl_stop_pegs, "I", "Peg Stop");
1102250661Sdavidcs
1103250661Sdavidcs#endif /* #ifdef QL_DBG */
1104250661Sdavidcs
1105284741Sdavidcs        ha->hw.user_pri_nic = 0;
1106284741Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
1107284741Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1108284741Sdavidcs                OID_AUTO, "user_pri_nic", CTLFLAG_RW, &ha->hw.user_pri_nic,
1109284741Sdavidcs                ha->hw.user_pri_nic,
1110284741Sdavidcs                "VLAN Tag User Priority for Normal Ethernet Packets");
1111284741Sdavidcs
1112284741Sdavidcs        ha->hw.user_pri_iscsi = 4;
1113284741Sdavidcs        SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
1114284741Sdavidcs                SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1115284741Sdavidcs                OID_AUTO, "user_pri_iscsi", CTLFLAG_RW, &ha->hw.user_pri_iscsi,
1116284741Sdavidcs                ha->hw.user_pri_iscsi,
1117284741Sdavidcs                "VLAN Tag User Priority for iSCSI Packets");
1118284741Sdavidcs
1119322972Sdavidcs	qlnx_add_hw_stats_sysctls(ha);
1120322972Sdavidcs	qlnx_add_drvr_stats_sysctls(ha);
1121322972Sdavidcs
1122322972Sdavidcs	return;
1123250661Sdavidcs}
1124250661Sdavidcs
1125250661Sdavidcsvoid
1126250661Sdavidcsql_hw_link_status(qla_host_t *ha)
1127250661Sdavidcs{
1128250661Sdavidcs	device_printf(ha->pci_dev, "cable_oui\t\t 0x%08x\n", ha->hw.cable_oui);
1129250661Sdavidcs
1130250661Sdavidcs	if (ha->hw.link_up) {
1131250661Sdavidcs		device_printf(ha->pci_dev, "link Up\n");
1132250661Sdavidcs	} else {
1133250661Sdavidcs		device_printf(ha->pci_dev, "link Down\n");
1134250661Sdavidcs	}
1135250661Sdavidcs
1136330555Sdavidcs	if (ha->hw.fduplex) {
1137250661Sdavidcs		device_printf(ha->pci_dev, "Full Duplex\n");
1138250661Sdavidcs	} else {
1139250661Sdavidcs		device_printf(ha->pci_dev, "Half Duplex\n");
1140250661Sdavidcs	}
1141250661Sdavidcs
1142330555Sdavidcs	if (ha->hw.autoneg) {
1143250661Sdavidcs		device_printf(ha->pci_dev, "Auto Negotiation Enabled\n");
1144250661Sdavidcs	} else {
1145250661Sdavidcs		device_printf(ha->pci_dev, "Auto Negotiation Disabled\n");
1146250661Sdavidcs	}
1147250661Sdavidcs
1148250661Sdavidcs	switch (ha->hw.link_speed) {
1149250661Sdavidcs	case 0x710:
1150250661Sdavidcs		device_printf(ha->pci_dev, "link speed\t\t 10Gps\n");
1151250661Sdavidcs		break;
1152250661Sdavidcs
1153250661Sdavidcs	case 0x3E8:
1154250661Sdavidcs		device_printf(ha->pci_dev, "link speed\t\t 1Gps\n");
1155250661Sdavidcs		break;
1156250661Sdavidcs
1157250661Sdavidcs	case 0x64:
1158250661Sdavidcs		device_printf(ha->pci_dev, "link speed\t\t 100Mbps\n");
1159250661Sdavidcs		break;
1160250661Sdavidcs
1161250661Sdavidcs	default:
1162250661Sdavidcs		device_printf(ha->pci_dev, "link speed\t\t Unknown\n");
1163250661Sdavidcs		break;
1164250661Sdavidcs	}
1165250661Sdavidcs
1166250661Sdavidcs	switch (ha->hw.module_type) {
1167250661Sdavidcs
1168250661Sdavidcs	case 0x01:
1169250661Sdavidcs		device_printf(ha->pci_dev, "Module Type 10GBase-LRM\n");
1170250661Sdavidcs		break;
1171250661Sdavidcs
1172250661Sdavidcs	case 0x02:
1173250661Sdavidcs		device_printf(ha->pci_dev, "Module Type 10GBase-LR\n");
1174250661Sdavidcs		break;
1175250661Sdavidcs
1176250661Sdavidcs	case 0x03:
1177250661Sdavidcs		device_printf(ha->pci_dev, "Module Type 10GBase-SR\n");
1178250661Sdavidcs		break;
1179250661Sdavidcs
1180250661Sdavidcs	case 0x04:
1181250661Sdavidcs		device_printf(ha->pci_dev,
1182250661Sdavidcs			"Module Type 10GE Passive Copper(Compliant)[%d m]\n",
1183250661Sdavidcs			ha->hw.cable_length);
1184250661Sdavidcs		break;
1185250661Sdavidcs
1186250661Sdavidcs	case 0x05:
1187250661Sdavidcs		device_printf(ha->pci_dev, "Module Type 10GE Active"
1188250661Sdavidcs			" Limiting Copper(Compliant)[%d m]\n",
1189250661Sdavidcs			ha->hw.cable_length);
1190250661Sdavidcs		break;
1191250661Sdavidcs
1192250661Sdavidcs	case 0x06:
1193250661Sdavidcs		device_printf(ha->pci_dev,
1194250661Sdavidcs			"Module Type 10GE Passive Copper"
1195250661Sdavidcs			" (Legacy, Best Effort)[%d m]\n",
1196250661Sdavidcs			ha->hw.cable_length);
1197250661Sdavidcs		break;
1198250661Sdavidcs
1199250661Sdavidcs	case 0x07:
1200250661Sdavidcs		device_printf(ha->pci_dev, "Module Type 1000Base-SX\n");
1201250661Sdavidcs		break;
1202250661Sdavidcs
1203250661Sdavidcs	case 0x08:
1204250661Sdavidcs		device_printf(ha->pci_dev, "Module Type 1000Base-LX\n");
1205250661Sdavidcs		break;
1206250661Sdavidcs
1207250661Sdavidcs	case 0x09:
1208250661Sdavidcs		device_printf(ha->pci_dev, "Module Type 1000Base-CX\n");
1209250661Sdavidcs		break;
1210250661Sdavidcs
1211250661Sdavidcs	case 0x0A:
1212250661Sdavidcs		device_printf(ha->pci_dev, "Module Type 1000Base-T\n");
1213250661Sdavidcs		break;
1214250661Sdavidcs
1215250661Sdavidcs	case 0x0B:
1216250661Sdavidcs		device_printf(ha->pci_dev, "Module Type 1GE Passive Copper"
1217250661Sdavidcs			"(Legacy, Best Effort)\n");
1218250661Sdavidcs		break;
1219250661Sdavidcs
1220250661Sdavidcs	default:
1221250661Sdavidcs		device_printf(ha->pci_dev, "Unknown Module Type 0x%x\n",
1222250661Sdavidcs			ha->hw.module_type);
1223250661Sdavidcs		break;
1224250661Sdavidcs	}
1225250661Sdavidcs
1226250661Sdavidcs	if (ha->hw.link_faults == 1)
1227250661Sdavidcs		device_printf(ha->pci_dev, "SFP Power Fault\n");
1228250661Sdavidcs}
1229250661Sdavidcs
1230250661Sdavidcs/*
1231250661Sdavidcs * Name: ql_free_dma
1232250661Sdavidcs * Function: Frees the DMA'able memory allocated in ql_alloc_dma()
1233250661Sdavidcs */
1234250661Sdavidcsvoid
1235250661Sdavidcsql_free_dma(qla_host_t *ha)
1236250661Sdavidcs{
1237250661Sdavidcs	uint32_t i;
1238250661Sdavidcs
1239250661Sdavidcs        if (ha->hw.dma_buf.flags.sds_ring) {
1240250661Sdavidcs		for (i = 0; i < ha->hw.num_sds_rings; i++) {
1241250661Sdavidcs			ql_free_dmabuf(ha, &ha->hw.dma_buf.sds_ring[i]);
1242250661Sdavidcs		}
1243250661Sdavidcs        	ha->hw.dma_buf.flags.sds_ring = 0;
1244250661Sdavidcs	}
1245250661Sdavidcs
1246250661Sdavidcs        if (ha->hw.dma_buf.flags.rds_ring) {
1247250661Sdavidcs		for (i = 0; i < ha->hw.num_rds_rings; i++) {
1248250661Sdavidcs			ql_free_dmabuf(ha, &ha->hw.dma_buf.rds_ring[i]);
1249250661Sdavidcs		}
1250250661Sdavidcs        	ha->hw.dma_buf.flags.rds_ring = 0;
1251250661Sdavidcs	}
1252250661Sdavidcs
1253250661Sdavidcs        if (ha->hw.dma_buf.flags.tx_ring) {
1254250661Sdavidcs		ql_free_dmabuf(ha, &ha->hw.dma_buf.tx_ring);
1255250661Sdavidcs        	ha->hw.dma_buf.flags.tx_ring = 0;
1256250661Sdavidcs	}
1257305487Sdavidcs	ql_minidump_free(ha);
1258250661Sdavidcs}
1259250661Sdavidcs
1260250661Sdavidcs/*
1261250661Sdavidcs * Name: ql_alloc_dma
1262250661Sdavidcs * Function: Allocates DMA'able memory for Tx/Rx Rings, Tx/Rx Contexts.
1263250661Sdavidcs */
1264250661Sdavidcsint
1265250661Sdavidcsql_alloc_dma(qla_host_t *ha)
1266250661Sdavidcs{
1267250661Sdavidcs        device_t                dev;
1268250661Sdavidcs	uint32_t		i, j, size, tx_ring_size;
1269250661Sdavidcs	qla_hw_t		*hw;
1270250661Sdavidcs	qla_hw_tx_cntxt_t	*tx_cntxt;
1271250661Sdavidcs	uint8_t			*vaddr;
1272250661Sdavidcs	bus_addr_t		paddr;
1273250661Sdavidcs
1274250661Sdavidcs        dev = ha->pci_dev;
1275250661Sdavidcs
1276250661Sdavidcs        QL_DPRINT2(ha, (dev, "%s: enter\n", __func__));
1277250661Sdavidcs
1278250661Sdavidcs	hw = &ha->hw;
1279250661Sdavidcs	/*
1280250661Sdavidcs	 * Allocate Transmit Ring
1281250661Sdavidcs	 */
1282250661Sdavidcs	tx_ring_size = (sizeof(q80_tx_cmd_t) * NUM_TX_DESCRIPTORS);
1283250661Sdavidcs	size = (tx_ring_size * ha->hw.num_tx_rings);
1284250661Sdavidcs
1285250661Sdavidcs	hw->dma_buf.tx_ring.alignment = 8;
1286250661Sdavidcs	hw->dma_buf.tx_ring.size = size + PAGE_SIZE;
1287250661Sdavidcs
1288250661Sdavidcs        if (ql_alloc_dmabuf(ha, &hw->dma_buf.tx_ring)) {
1289250661Sdavidcs                device_printf(dev, "%s: tx ring alloc failed\n", __func__);
1290250661Sdavidcs                goto ql_alloc_dma_exit;
1291250661Sdavidcs        }
1292250661Sdavidcs
1293250661Sdavidcs	vaddr = (uint8_t *)hw->dma_buf.tx_ring.dma_b;
1294250661Sdavidcs	paddr = hw->dma_buf.tx_ring.dma_addr;
1295250661Sdavidcs
1296250661Sdavidcs	for (i = 0; i < ha->hw.num_tx_rings; i++) {
1297250661Sdavidcs		tx_cntxt = (qla_hw_tx_cntxt_t *)&hw->tx_cntxt[i];
1298250661Sdavidcs
1299250661Sdavidcs		tx_cntxt->tx_ring_base = (q80_tx_cmd_t *)vaddr;
1300250661Sdavidcs		tx_cntxt->tx_ring_paddr = paddr;
1301250661Sdavidcs
1302250661Sdavidcs		vaddr += tx_ring_size;
1303250661Sdavidcs		paddr += tx_ring_size;
1304250661Sdavidcs	}
1305250661Sdavidcs
1306250661Sdavidcs	for (i = 0; i < ha->hw.num_tx_rings; i++) {
1307250661Sdavidcs		tx_cntxt = (qla_hw_tx_cntxt_t *)&hw->tx_cntxt[i];
1308250661Sdavidcs
1309250661Sdavidcs		tx_cntxt->tx_cons = (uint32_t *)vaddr;
1310250661Sdavidcs		tx_cntxt->tx_cons_paddr = paddr;
1311250661Sdavidcs
1312250661Sdavidcs		vaddr += sizeof (uint32_t);
1313250661Sdavidcs		paddr += sizeof (uint32_t);
1314250661Sdavidcs	}
1315250661Sdavidcs
1316250661Sdavidcs        ha->hw.dma_buf.flags.tx_ring = 1;
1317250661Sdavidcs
1318250661Sdavidcs	QL_DPRINT2(ha, (dev, "%s: tx_ring phys %p virt %p\n",
1319250661Sdavidcs		__func__, (void *)(hw->dma_buf.tx_ring.dma_addr),
1320250661Sdavidcs		hw->dma_buf.tx_ring.dma_b));
1321250661Sdavidcs	/*
1322250661Sdavidcs	 * Allocate Receive Descriptor Rings
1323250661Sdavidcs	 */
1324250661Sdavidcs
1325250661Sdavidcs	for (i = 0; i < hw->num_rds_rings; i++) {
1326250661Sdavidcs
1327250661Sdavidcs		hw->dma_buf.rds_ring[i].alignment = 8;
1328250661Sdavidcs		hw->dma_buf.rds_ring[i].size =
1329250661Sdavidcs			(sizeof(q80_recv_desc_t)) * NUM_RX_DESCRIPTORS;
1330250661Sdavidcs
1331250661Sdavidcs		if (ql_alloc_dmabuf(ha, &hw->dma_buf.rds_ring[i])) {
1332250661Sdavidcs			device_printf(dev, "%s: rds ring[%d] alloc failed\n",
1333250661Sdavidcs				__func__, i);
1334250661Sdavidcs
1335250661Sdavidcs			for (j = 0; j < i; j++)
1336250661Sdavidcs				ql_free_dmabuf(ha, &hw->dma_buf.rds_ring[j]);
1337250661Sdavidcs
1338250661Sdavidcs			goto ql_alloc_dma_exit;
1339250661Sdavidcs		}
1340250661Sdavidcs		QL_DPRINT4(ha, (dev, "%s: rx_ring[%d] phys %p virt %p\n",
1341250661Sdavidcs			__func__, i, (void *)(hw->dma_buf.rds_ring[i].dma_addr),
1342250661Sdavidcs			hw->dma_buf.rds_ring[i].dma_b));
1343250661Sdavidcs	}
1344250661Sdavidcs
1345250661Sdavidcs	hw->dma_buf.flags.rds_ring = 1;
1346250661Sdavidcs
1347250661Sdavidcs	/*
1348250661Sdavidcs	 * Allocate Status Descriptor Rings
1349250661Sdavidcs	 */
1350250661Sdavidcs
1351250661Sdavidcs	for (i = 0; i < hw->num_sds_rings; i++) {
1352250661Sdavidcs		hw->dma_buf.sds_ring[i].alignment = 8;
1353250661Sdavidcs		hw->dma_buf.sds_ring[i].size =
1354250661Sdavidcs			(sizeof(q80_stat_desc_t)) * NUM_STATUS_DESCRIPTORS;
1355250661Sdavidcs
1356250661Sdavidcs		if (ql_alloc_dmabuf(ha, &hw->dma_buf.sds_ring[i])) {
1357250661Sdavidcs			device_printf(dev, "%s: sds ring alloc failed\n",
1358250661Sdavidcs				__func__);
1359250661Sdavidcs
1360250661Sdavidcs			for (j = 0; j < i; j++)
1361250661Sdavidcs				ql_free_dmabuf(ha, &hw->dma_buf.sds_ring[j]);
1362250661Sdavidcs
1363250661Sdavidcs			goto ql_alloc_dma_exit;
1364250661Sdavidcs		}
1365250661Sdavidcs		QL_DPRINT4(ha, (dev, "%s: sds_ring[%d] phys %p virt %p\n",
1366250661Sdavidcs			__func__, i,
1367250661Sdavidcs			(void *)(hw->dma_buf.sds_ring[i].dma_addr),
1368250661Sdavidcs			hw->dma_buf.sds_ring[i].dma_b));
1369250661Sdavidcs	}
1370250661Sdavidcs	for (i = 0; i < hw->num_sds_rings; i++) {
1371250661Sdavidcs		hw->sds[i].sds_ring_base =
1372250661Sdavidcs			(q80_stat_desc_t *)hw->dma_buf.sds_ring[i].dma_b;
1373250661Sdavidcs	}
1374250661Sdavidcs
1375250661Sdavidcs	hw->dma_buf.flags.sds_ring = 1;
1376250661Sdavidcs
1377250661Sdavidcs	return 0;
1378250661Sdavidcs
1379250661Sdavidcsql_alloc_dma_exit:
1380250661Sdavidcs	ql_free_dma(ha);
1381250661Sdavidcs	return -1;
1382250661Sdavidcs}
1383250661Sdavidcs
1384250661Sdavidcs#define Q8_MBX_MSEC_DELAY	5000
1385250661Sdavidcs
1386250661Sdavidcsstatic int
1387250661Sdavidcsqla_mbx_cmd(qla_host_t *ha, uint32_t *h_mbox, uint32_t n_hmbox,
1388250661Sdavidcs	uint32_t *fw_mbox, uint32_t n_fwmbox, uint32_t no_pause)
1389250661Sdavidcs{
1390250661Sdavidcs	uint32_t i;
1391250661Sdavidcs	uint32_t data;
1392250661Sdavidcs	int ret = 0;
1393330555Sdavidcs	uint64_t start_usecs;
1394330555Sdavidcs	uint64_t end_usecs;
1395330555Sdavidcs	uint64_t msecs_200;
1396250661Sdavidcs
1397330555Sdavidcs	ql_sp_log(ha, 0, 5, no_pause, h_mbox[0], h_mbox[1], h_mbox[2], h_mbox[3]);
1398330555Sdavidcs
1399330555Sdavidcs	if (ha->offline || ha->qla_initiate_recovery) {
1400330555Sdavidcs		ql_sp_log(ha, 1, 2, ha->offline, ha->qla_initiate_recovery, 0, 0, 0);
1401330555Sdavidcs		goto exit_qla_mbx_cmd;
1402330555Sdavidcs	}
1403330555Sdavidcs
1404330555Sdavidcs	if (((ha->err_inject & 0xFFFF) == INJCT_MBX_CMD_FAILURE) &&
1405330555Sdavidcs		(((ha->err_inject & ~0xFFFF) == ((h_mbox[0] & 0xFFFF) << 16))||
1406330555Sdavidcs		!(ha->err_inject & ~0xFFFF))) {
1407250661Sdavidcs		ret = -3;
1408330555Sdavidcs		QL_INITIATE_RECOVERY(ha);
1409250661Sdavidcs		goto exit_qla_mbx_cmd;
1410250661Sdavidcs	}
1411250661Sdavidcs
1412330555Sdavidcs	start_usecs = qla_get_usec_timestamp();
1413330555Sdavidcs
1414250661Sdavidcs	if (no_pause)
1415250661Sdavidcs		i = 1000;
1416250661Sdavidcs	else
1417250661Sdavidcs		i = Q8_MBX_MSEC_DELAY;
1418250661Sdavidcs
1419250661Sdavidcs	while (i) {
1420330555Sdavidcs
1421330555Sdavidcs		if (ha->qla_initiate_recovery) {
1422330555Sdavidcs			ql_sp_log(ha, 2, 1, ha->qla_initiate_recovery, 0, 0, 0, 0);
1423330555Sdavidcs			return (-1);
1424330555Sdavidcs		}
1425330555Sdavidcs
1426250661Sdavidcs		data = READ_REG32(ha, Q8_HOST_MBOX_CNTRL);
1427250661Sdavidcs		if (data == 0)
1428250661Sdavidcs			break;
1429250661Sdavidcs		if (no_pause) {
1430250661Sdavidcs			DELAY(1000);
1431250661Sdavidcs		} else {
1432250661Sdavidcs			qla_mdelay(__func__, 1);
1433250661Sdavidcs		}
1434250661Sdavidcs		i--;
1435250661Sdavidcs	}
1436250661Sdavidcs
1437250661Sdavidcs	if (i == 0) {
1438250661Sdavidcs		device_printf(ha->pci_dev, "%s: host_mbx_cntrl 0x%08x\n",
1439250661Sdavidcs			__func__, data);
1440330555Sdavidcs		ql_sp_log(ha, 3, 1, data, 0, 0, 0, 0);
1441250661Sdavidcs		ret = -1;
1442330555Sdavidcs		ha->hw.mbx_comp_msecs[(Q8_MBX_COMP_MSECS - 2)]++;
1443330555Sdavidcs		QL_INITIATE_RECOVERY(ha);
1444250661Sdavidcs		goto exit_qla_mbx_cmd;
1445250661Sdavidcs	}
1446250661Sdavidcs
1447250661Sdavidcs	for (i = 0; i < n_hmbox; i++) {
1448250661Sdavidcs		WRITE_REG32(ha, (Q8_HOST_MBOX0 + (i << 2)), *h_mbox);
1449250661Sdavidcs		h_mbox++;
1450250661Sdavidcs	}
1451250661Sdavidcs
1452250661Sdavidcs	WRITE_REG32(ha, Q8_HOST_MBOX_CNTRL, 0x1);
1453250661Sdavidcs
1454250661Sdavidcs
1455250661Sdavidcs	i = Q8_MBX_MSEC_DELAY;
1456250661Sdavidcs	while (i) {
1457330555Sdavidcs
1458330555Sdavidcs		if (ha->qla_initiate_recovery) {
1459330555Sdavidcs			ql_sp_log(ha, 4, 1, ha->qla_initiate_recovery, 0, 0, 0, 0);
1460330555Sdavidcs			return (-1);
1461330555Sdavidcs		}
1462330555Sdavidcs
1463250661Sdavidcs		data = READ_REG32(ha, Q8_FW_MBOX_CNTRL);
1464250661Sdavidcs
1465250661Sdavidcs		if ((data & 0x3) == 1) {
1466250661Sdavidcs			data = READ_REG32(ha, Q8_FW_MBOX0);
1467250661Sdavidcs			if ((data & 0xF000) != 0x8000)
1468250661Sdavidcs				break;
1469250661Sdavidcs		}
1470250661Sdavidcs		if (no_pause) {
1471250661Sdavidcs			DELAY(1000);
1472250661Sdavidcs		} else {
1473250661Sdavidcs			qla_mdelay(__func__, 1);
1474250661Sdavidcs		}
1475250661Sdavidcs		i--;
1476250661Sdavidcs	}
1477250661Sdavidcs	if (i == 0) {
1478250661Sdavidcs		device_printf(ha->pci_dev, "%s: fw_mbx_cntrl 0x%08x\n",
1479250661Sdavidcs			__func__, data);
1480330555Sdavidcs		ql_sp_log(ha, 5, 1, data, 0, 0, 0, 0);
1481250661Sdavidcs		ret = -2;
1482330555Sdavidcs		ha->hw.mbx_comp_msecs[(Q8_MBX_COMP_MSECS - 1)]++;
1483330555Sdavidcs		QL_INITIATE_RECOVERY(ha);
1484250661Sdavidcs		goto exit_qla_mbx_cmd;
1485250661Sdavidcs	}
1486250661Sdavidcs
1487250661Sdavidcs	for (i = 0; i < n_fwmbox; i++) {
1488330555Sdavidcs
1489330555Sdavidcs		if (ha->qla_initiate_recovery) {
1490330555Sdavidcs			ql_sp_log(ha, 6, 1, ha->qla_initiate_recovery, 0, 0, 0, 0);
1491330555Sdavidcs			return (-1);
1492330555Sdavidcs		}
1493330555Sdavidcs
1494250661Sdavidcs		*fw_mbox++ = READ_REG32(ha, (Q8_FW_MBOX0 + (i << 2)));
1495250661Sdavidcs	}
1496250661Sdavidcs
1497250661Sdavidcs	WRITE_REG32(ha, Q8_FW_MBOX_CNTRL, 0x0);
1498250661Sdavidcs	WRITE_REG32(ha, ha->hw.mbx_intr_mask_offset, 0x0);
1499250661Sdavidcs
1500330555Sdavidcs	end_usecs = qla_get_usec_timestamp();
1501330555Sdavidcs
1502330555Sdavidcs	if (end_usecs > start_usecs) {
1503330555Sdavidcs		msecs_200 = (end_usecs - start_usecs)/(1000 * 200);
1504330555Sdavidcs
1505330555Sdavidcs		if (msecs_200 < 15)
1506330555Sdavidcs			ha->hw.mbx_comp_msecs[msecs_200]++;
1507330555Sdavidcs		else if (msecs_200 < 20)
1508330555Sdavidcs			ha->hw.mbx_comp_msecs[15]++;
1509330555Sdavidcs		else {
1510330555Sdavidcs			device_printf(ha->pci_dev, "%s: [%ld, %ld] %ld\n", __func__,
1511330555Sdavidcs				start_usecs, end_usecs, msecs_200);
1512330555Sdavidcs			ha->hw.mbx_comp_msecs[16]++;
1513330555Sdavidcs		}
1514330555Sdavidcs	}
1515330555Sdavidcs	ql_sp_log(ha, 7, 5, fw_mbox[0], fw_mbox[1], fw_mbox[2], fw_mbox[3], fw_mbox[4]);
1516330555Sdavidcs
1517330555Sdavidcs
1518250661Sdavidcsexit_qla_mbx_cmd:
1519250661Sdavidcs	return (ret);
1520250661Sdavidcs}
1521250661Sdavidcs
1522284741Sdavidcsint
1523284741Sdavidcsqla_get_nic_partition(qla_host_t *ha, uint32_t *supports_9kb,
1524284741Sdavidcs	uint32_t *num_rcvq)
1525250661Sdavidcs{
1526250661Sdavidcs	uint32_t *mbox, err;
1527250661Sdavidcs	device_t dev = ha->pci_dev;
1528250661Sdavidcs
1529250661Sdavidcs	bzero(ha->hw.mbox, (sizeof (uint32_t) * Q8_NUM_MBOX));
1530250661Sdavidcs
1531250661Sdavidcs	mbox = ha->hw.mbox;
1532250661Sdavidcs
1533250661Sdavidcs	mbox[0] = Q8_MBX_GET_NIC_PARTITION | (0x2 << 16) | (0x2 << 29);
1534250661Sdavidcs
1535250661Sdavidcs	if (qla_mbx_cmd(ha, mbox, 2, mbox, 19, 0)) {
1536250661Sdavidcs		device_printf(dev, "%s: failed0\n", __func__);
1537250661Sdavidcs		return (-1);
1538250661Sdavidcs	}
1539250661Sdavidcs	err = mbox[0] >> 25;
1540250661Sdavidcs
1541284741Sdavidcs	if (supports_9kb != NULL) {
1542284741Sdavidcs		if (mbox[16] & 0x80) /* bit 7 of mbox 16 */
1543284741Sdavidcs			*supports_9kb = 1;
1544284741Sdavidcs		else
1545284741Sdavidcs			*supports_9kb = 0;
1546284741Sdavidcs	}
1547284741Sdavidcs
1548284741Sdavidcs	if (num_rcvq != NULL)
1549284741Sdavidcs		*num_rcvq =  ((mbox[6] >> 16) & 0xFFFF);
1550284741Sdavidcs
1551250661Sdavidcs	if ((err != 1) && (err != 0)) {
1552250661Sdavidcs		device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err);
1553250661Sdavidcs		return (-1);
1554250661Sdavidcs	}
1555250661Sdavidcs	return 0;
1556250661Sdavidcs}
1557250661Sdavidcs
1558250661Sdavidcsstatic int
1559284741Sdavidcsqla_config_intr_cntxt(qla_host_t *ha, uint32_t start_idx, uint32_t num_intrs,
1560284741Sdavidcs	uint32_t create)
1561250661Sdavidcs{
1562250661Sdavidcs	uint32_t i, err;
1563250661Sdavidcs	device_t dev = ha->pci_dev;
1564250661Sdavidcs	q80_config_intr_t *c_intr;
1565250661Sdavidcs	q80_config_intr_rsp_t *c_intr_rsp;
1566250661Sdavidcs
1567250661Sdavidcs	c_intr = (q80_config_intr_t *)ha->hw.mbox;
1568250661Sdavidcs	bzero(c_intr, (sizeof (q80_config_intr_t)));
1569250661Sdavidcs
1570250661Sdavidcs	c_intr->opcode = Q8_MBX_CONFIG_INTR;
1571250661Sdavidcs
1572250661Sdavidcs	c_intr->count_version = (sizeof (q80_config_intr_t) >> 2);
1573250661Sdavidcs	c_intr->count_version |= Q8_MBX_CMD_VERSION;
1574250661Sdavidcs
1575250661Sdavidcs	c_intr->nentries = num_intrs;
1576250661Sdavidcs
1577250661Sdavidcs	for (i = 0; i < num_intrs; i++) {
1578250661Sdavidcs		if (create) {
1579250661Sdavidcs			c_intr->intr[i].cmd_type = Q8_MBX_CONFIG_INTR_CREATE;
1580284741Sdavidcs			c_intr->intr[i].msix_index = start_idx + 1 + i;
1581250661Sdavidcs		} else {
1582250661Sdavidcs			c_intr->intr[i].cmd_type = Q8_MBX_CONFIG_INTR_DELETE;
1583284741Sdavidcs			c_intr->intr[i].msix_index =
1584284741Sdavidcs				ha->hw.intr_id[(start_idx + i)];
1585250661Sdavidcs		}
1586250661Sdavidcs
1587250661Sdavidcs		c_intr->intr[i].cmd_type |= Q8_MBX_CONFIG_INTR_TYPE_MSI_X;
1588250661Sdavidcs	}
1589250661Sdavidcs
1590250661Sdavidcs	if (qla_mbx_cmd(ha, (uint32_t *)c_intr,
1591250661Sdavidcs		(sizeof (q80_config_intr_t) >> 2),
1592250661Sdavidcs		ha->hw.mbox, (sizeof (q80_config_intr_rsp_t) >> 2), 0)) {
1593330555Sdavidcs		device_printf(dev, "%s: %s failed0\n", __func__,
1594330555Sdavidcs			(create ? "create" : "delete"));
1595250661Sdavidcs		return (-1);
1596250661Sdavidcs	}
1597250661Sdavidcs
1598250661Sdavidcs	c_intr_rsp = (q80_config_intr_rsp_t *)ha->hw.mbox;
1599250661Sdavidcs
1600250661Sdavidcs	err = Q8_MBX_RSP_STATUS(c_intr_rsp->regcnt_status);
1601250661Sdavidcs
1602250661Sdavidcs	if (err) {
1603330555Sdavidcs		device_printf(dev, "%s: %s failed1 [0x%08x, %d]\n", __func__,
1604330555Sdavidcs			(create ? "create" : "delete"), err, c_intr_rsp->nentries);
1605250661Sdavidcs
1606250661Sdavidcs		for (i = 0; i < c_intr_rsp->nentries; i++) {
1607250661Sdavidcs			device_printf(dev, "%s: [%d]:[0x%x 0x%x 0x%x]\n",
1608250661Sdavidcs				__func__, i,
1609250661Sdavidcs				c_intr_rsp->intr[i].status,
1610250661Sdavidcs				c_intr_rsp->intr[i].intr_id,
1611250661Sdavidcs				c_intr_rsp->intr[i].intr_src);
1612250661Sdavidcs		}
1613250661Sdavidcs
1614250661Sdavidcs		return (-1);
1615250661Sdavidcs	}
1616250661Sdavidcs
1617250661Sdavidcs	for (i = 0; ((i < num_intrs) && create); i++) {
1618250661Sdavidcs		if (!c_intr_rsp->intr[i].status) {
1619284741Sdavidcs			ha->hw.intr_id[(start_idx + i)] =
1620284741Sdavidcs				c_intr_rsp->intr[i].intr_id;
1621284741Sdavidcs			ha->hw.intr_src[(start_idx + i)] =
1622284741Sdavidcs				c_intr_rsp->intr[i].intr_src;
1623250661Sdavidcs		}
1624250661Sdavidcs	}
1625250661Sdavidcs
1626250661Sdavidcs	return (0);
1627250661Sdavidcs}
1628250661Sdavidcs
1629250661Sdavidcs/*
1630250661Sdavidcs * Name: qla_config_rss
1631250661Sdavidcs * Function: Configure RSS for the context/interface.
1632250661Sdavidcs */
1633250661Sdavidcsstatic const uint64_t rss_key[] = { 0xbeac01fa6a42b73bULL,
1634250661Sdavidcs			0x8030f20c77cb2da3ULL,
1635250661Sdavidcs			0xae7b30b4d0ca2bcbULL, 0x43a38fb04167253dULL,
1636250661Sdavidcs			0x255b0ec26d5a56daULL };
1637250661Sdavidcs
1638250661Sdavidcsstatic int
1639250661Sdavidcsqla_config_rss(qla_host_t *ha, uint16_t cntxt_id)
1640250661Sdavidcs{
1641250661Sdavidcs	q80_config_rss_t	*c_rss;
1642250661Sdavidcs	q80_config_rss_rsp_t	*c_rss_rsp;
1643250661Sdavidcs	uint32_t		err, i;
1644250661Sdavidcs	device_t		dev = ha->pci_dev;
1645250661Sdavidcs
1646250661Sdavidcs	c_rss = (q80_config_rss_t *)ha->hw.mbox;
1647250661Sdavidcs	bzero(c_rss, (sizeof (q80_config_rss_t)));
1648250661Sdavidcs
1649250661Sdavidcs	c_rss->opcode = Q8_MBX_CONFIG_RSS;
1650250661Sdavidcs
1651250661Sdavidcs	c_rss->count_version = (sizeof (q80_config_rss_t) >> 2);
1652250661Sdavidcs	c_rss->count_version |= Q8_MBX_CMD_VERSION;
1653250661Sdavidcs
1654250661Sdavidcs	c_rss->hash_type = (Q8_MBX_RSS_HASH_TYPE_IPV4_TCP_IP |
1655250661Sdavidcs				Q8_MBX_RSS_HASH_TYPE_IPV6_TCP_IP);
1656284741Sdavidcs	//c_rss->hash_type = (Q8_MBX_RSS_HASH_TYPE_IPV4_TCP |
1657284741Sdavidcs	//			Q8_MBX_RSS_HASH_TYPE_IPV6_TCP);
1658250661Sdavidcs
1659250661Sdavidcs	c_rss->flags = Q8_MBX_RSS_FLAGS_ENABLE_RSS;
1660250661Sdavidcs	c_rss->flags |= Q8_MBX_RSS_FLAGS_USE_IND_TABLE;
1661250661Sdavidcs
1662250661Sdavidcs	c_rss->indtbl_mask = Q8_MBX_RSS_INDTBL_MASK;
1663250661Sdavidcs
1664250661Sdavidcs	c_rss->indtbl_mask |= Q8_MBX_RSS_FLAGS_MULTI_RSS_VALID;
1665250661Sdavidcs	c_rss->flags |= Q8_MBX_RSS_FLAGS_TYPE_CRSS;
1666250661Sdavidcs
1667250661Sdavidcs	c_rss->cntxt_id = cntxt_id;
1668250661Sdavidcs
1669250661Sdavidcs	for (i = 0; i < 5; i++) {
1670250661Sdavidcs		c_rss->rss_key[i] = rss_key[i];
1671250661Sdavidcs	}
1672250661Sdavidcs
1673250661Sdavidcs	if (qla_mbx_cmd(ha, (uint32_t *)c_rss,
1674250661Sdavidcs		(sizeof (q80_config_rss_t) >> 2),
1675250661Sdavidcs		ha->hw.mbox, (sizeof(q80_config_rss_rsp_t) >> 2), 0)) {
1676250661Sdavidcs		device_printf(dev, "%s: failed0\n", __func__);
1677250661Sdavidcs		return (-1);
1678250661Sdavidcs	}
1679250661Sdavidcs	c_rss_rsp = (q80_config_rss_rsp_t *)ha->hw.mbox;
1680250661Sdavidcs
1681250661Sdavidcs	err = Q8_MBX_RSP_STATUS(c_rss_rsp->regcnt_status);
1682250661Sdavidcs
1683250661Sdavidcs	if (err) {
1684250661Sdavidcs		device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err);
1685250661Sdavidcs		return (-1);
1686250661Sdavidcs	}
1687250661Sdavidcs	return 0;
1688250661Sdavidcs}
1689250661Sdavidcs
1690250661Sdavidcsstatic int
1691250661Sdavidcsqla_set_rss_ind_table(qla_host_t *ha, uint32_t start_idx, uint32_t count,
1692250661Sdavidcs        uint16_t cntxt_id, uint8_t *ind_table)
1693250661Sdavidcs{
1694250661Sdavidcs        q80_config_rss_ind_table_t      *c_rss_ind;
1695250661Sdavidcs        q80_config_rss_ind_table_rsp_t  *c_rss_ind_rsp;
1696250661Sdavidcs        uint32_t                        err;
1697250661Sdavidcs        device_t                        dev = ha->pci_dev;
1698250661Sdavidcs
1699250661Sdavidcs	if ((count > Q8_RSS_IND_TBL_SIZE) ||
1700250661Sdavidcs		((start_idx + count - 1) > Q8_RSS_IND_TBL_MAX_IDX)) {
1701250661Sdavidcs		device_printf(dev, "%s: illegal count [%d, %d]\n", __func__,
1702250661Sdavidcs			start_idx, count);
1703250661Sdavidcs		return (-1);
1704250661Sdavidcs	}
1705250661Sdavidcs
1706250661Sdavidcs        c_rss_ind = (q80_config_rss_ind_table_t *)ha->hw.mbox;
1707250661Sdavidcs        bzero(c_rss_ind, sizeof (q80_config_rss_ind_table_t));
1708250661Sdavidcs
1709250661Sdavidcs        c_rss_ind->opcode = Q8_MBX_CONFIG_RSS_TABLE;
1710250661Sdavidcs        c_rss_ind->count_version = (sizeof (q80_config_rss_ind_table_t) >> 2);
1711250661Sdavidcs        c_rss_ind->count_version |= Q8_MBX_CMD_VERSION;
1712250661Sdavidcs
1713250661Sdavidcs	c_rss_ind->start_idx = start_idx;
1714250661Sdavidcs	c_rss_ind->end_idx = start_idx + count - 1;
1715250661Sdavidcs	c_rss_ind->cntxt_id = cntxt_id;
1716250661Sdavidcs	bcopy(ind_table, c_rss_ind->ind_table, count);
1717250661Sdavidcs
1718250661Sdavidcs	if (qla_mbx_cmd(ha, (uint32_t *)c_rss_ind,
1719250661Sdavidcs		(sizeof (q80_config_rss_ind_table_t) >> 2), ha->hw.mbox,
1720250661Sdavidcs		(sizeof(q80_config_rss_ind_table_rsp_t) >> 2), 0)) {
1721250661Sdavidcs		device_printf(dev, "%s: failed0\n", __func__);
1722250661Sdavidcs		return (-1);
1723250661Sdavidcs	}
1724250661Sdavidcs
1725250661Sdavidcs	c_rss_ind_rsp = (q80_config_rss_ind_table_rsp_t *)ha->hw.mbox;
1726250661Sdavidcs	err = Q8_MBX_RSP_STATUS(c_rss_ind_rsp->regcnt_status);
1727250661Sdavidcs
1728250661Sdavidcs	if (err) {
1729250661Sdavidcs		device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err);
1730250661Sdavidcs		return (-1);
1731250661Sdavidcs	}
1732250661Sdavidcs	return 0;
1733250661Sdavidcs}
1734250661Sdavidcs
1735250661Sdavidcs/*
1736250661Sdavidcs * Name: qla_config_intr_coalesce
1737250661Sdavidcs * Function: Configure Interrupt Coalescing.
1738250661Sdavidcs */
1739250661Sdavidcsstatic int
1740284741Sdavidcsqla_config_intr_coalesce(qla_host_t *ha, uint16_t cntxt_id, int tenable,
1741284741Sdavidcs	int rcv)
1742250661Sdavidcs{
1743250661Sdavidcs	q80_config_intr_coalesc_t	*intrc;
1744250661Sdavidcs	q80_config_intr_coalesc_rsp_t	*intrc_rsp;
1745250661Sdavidcs	uint32_t			err, i;
1746250661Sdavidcs	device_t			dev = ha->pci_dev;
1747250661Sdavidcs
1748250661Sdavidcs	intrc = (q80_config_intr_coalesc_t *)ha->hw.mbox;
1749250661Sdavidcs	bzero(intrc, (sizeof (q80_config_intr_coalesc_t)));
1750250661Sdavidcs
1751250661Sdavidcs	intrc->opcode = Q8_MBX_CONFIG_INTR_COALESCE;
1752250661Sdavidcs	intrc->count_version = (sizeof (q80_config_intr_coalesc_t) >> 2);
1753250661Sdavidcs	intrc->count_version |= Q8_MBX_CMD_VERSION;
1754250661Sdavidcs
1755284741Sdavidcs	if (rcv) {
1756284741Sdavidcs		intrc->flags = Q8_MBX_INTRC_FLAGS_RCV;
1757284741Sdavidcs		intrc->max_pkts = ha->hw.rcv_intr_coalesce & 0xFFFF;
1758284741Sdavidcs		intrc->max_mswait = (ha->hw.rcv_intr_coalesce >> 16) & 0xFFFF;
1759284741Sdavidcs	} else {
1760284741Sdavidcs		intrc->flags = Q8_MBX_INTRC_FLAGS_XMT;
1761284741Sdavidcs		intrc->max_pkts = ha->hw.xmt_intr_coalesce & 0xFFFF;
1762284741Sdavidcs		intrc->max_mswait = (ha->hw.xmt_intr_coalesce >> 16) & 0xFFFF;
1763284741Sdavidcs	}
1764284741Sdavidcs
1765250661Sdavidcs	intrc->cntxt_id = cntxt_id;
1766250661Sdavidcs
1767250661Sdavidcs	if (tenable) {
1768250661Sdavidcs		intrc->flags |= Q8_MBX_INTRC_FLAGS_PERIODIC;
1769250661Sdavidcs		intrc->timer_type = Q8_MBX_INTRC_TIMER_PERIODIC;
1770250661Sdavidcs
1771250661Sdavidcs		for (i = 0; i < ha->hw.num_sds_rings; i++) {
1772250661Sdavidcs			intrc->sds_ring_mask |= (1 << i);
1773250661Sdavidcs		}
1774250661Sdavidcs		intrc->ms_timeout = 1000;
1775250661Sdavidcs	}
1776250661Sdavidcs
1777250661Sdavidcs	if (qla_mbx_cmd(ha, (uint32_t *)intrc,
1778250661Sdavidcs		(sizeof (q80_config_intr_coalesc_t) >> 2),
1779250661Sdavidcs		ha->hw.mbox, (sizeof(q80_config_intr_coalesc_rsp_t) >> 2), 0)) {
1780250661Sdavidcs		device_printf(dev, "%s: failed0\n", __func__);
1781250661Sdavidcs		return (-1);
1782250661Sdavidcs	}
1783250661Sdavidcs	intrc_rsp = (q80_config_intr_coalesc_rsp_t *)ha->hw.mbox;
1784250661Sdavidcs
1785250661Sdavidcs	err = Q8_MBX_RSP_STATUS(intrc_rsp->regcnt_status);
1786250661Sdavidcs
1787250661Sdavidcs	if (err) {
1788250661Sdavidcs		device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err);
1789250661Sdavidcs		return (-1);
1790250661Sdavidcs	}
1791250661Sdavidcs
1792250661Sdavidcs	return 0;
1793250661Sdavidcs}
1794250661Sdavidcs
1795250661Sdavidcs
1796250661Sdavidcs/*
1797250661Sdavidcs * Name: qla_config_mac_addr
1798250661Sdavidcs * Function: binds a MAC address to the context/interface.
1799250661Sdavidcs *	Can be unicast, multicast or broadcast.
1800250661Sdavidcs */
1801250661Sdavidcsstatic int
1802307524Sdavidcsqla_config_mac_addr(qla_host_t *ha, uint8_t *mac_addr, uint32_t add_mac,
1803307524Sdavidcs	uint32_t num_mac)
1804250661Sdavidcs{
1805250661Sdavidcs	q80_config_mac_addr_t		*cmac;
1806250661Sdavidcs	q80_config_mac_addr_rsp_t	*cmac_rsp;
1807250661Sdavidcs	uint32_t			err;
1808250661Sdavidcs	device_t			dev = ha->pci_dev;
1809307524Sdavidcs	int				i;
1810307524Sdavidcs	uint8_t				*mac_cpy = mac_addr;
1811250661Sdavidcs
1812307524Sdavidcs	if (num_mac > Q8_MAX_MAC_ADDRS) {
1813307524Sdavidcs		device_printf(dev, "%s: %s num_mac [0x%x] > Q8_MAX_MAC_ADDRS\n",
1814307524Sdavidcs			__func__, (add_mac ? "Add" : "Del"), num_mac);
1815307524Sdavidcs		return (-1);
1816307524Sdavidcs	}
1817307524Sdavidcs
1818250661Sdavidcs	cmac = (q80_config_mac_addr_t *)ha->hw.mbox;
1819250661Sdavidcs	bzero(cmac, (sizeof (q80_config_mac_addr_t)));
1820250661Sdavidcs
1821250661Sdavidcs	cmac->opcode = Q8_MBX_CONFIG_MAC_ADDR;
1822250661Sdavidcs	cmac->count_version = sizeof (q80_config_mac_addr_t) >> 2;
1823250661Sdavidcs	cmac->count_version |= Q8_MBX_CMD_VERSION;
1824250661Sdavidcs
1825250661Sdavidcs	if (add_mac)
1826250661Sdavidcs		cmac->cmd = Q8_MBX_CMAC_CMD_ADD_MAC_ADDR;
1827250661Sdavidcs	else
1828250661Sdavidcs		cmac->cmd = Q8_MBX_CMAC_CMD_DEL_MAC_ADDR;
1829250661Sdavidcs
1830250661Sdavidcs	cmac->cmd |= Q8_MBX_CMAC_CMD_CAM_INGRESS;
1831250661Sdavidcs
1832307524Sdavidcs	cmac->nmac_entries = num_mac;
1833250661Sdavidcs	cmac->cntxt_id = ha->hw.rcv_cntxt_id;
1834250661Sdavidcs
1835307524Sdavidcs	for (i = 0; i < num_mac; i++) {
1836307524Sdavidcs		bcopy(mac_addr, cmac->mac_addr[i].addr, Q8_ETHER_ADDR_LEN);
1837307524Sdavidcs		mac_addr = mac_addr + ETHER_ADDR_LEN;
1838307524Sdavidcs	}
1839307524Sdavidcs
1840250661Sdavidcs	if (qla_mbx_cmd(ha, (uint32_t *)cmac,
1841250661Sdavidcs		(sizeof (q80_config_mac_addr_t) >> 2),
1842250661Sdavidcs		ha->hw.mbox, (sizeof(q80_config_mac_addr_rsp_t) >> 2), 1)) {
1843250661Sdavidcs		device_printf(dev, "%s: %s failed0\n", __func__,
1844250661Sdavidcs			(add_mac ? "Add" : "Del"));
1845250661Sdavidcs		return (-1);
1846250661Sdavidcs	}
1847250661Sdavidcs	cmac_rsp = (q80_config_mac_addr_rsp_t *)ha->hw.mbox;
1848250661Sdavidcs
1849250661Sdavidcs	err = Q8_MBX_RSP_STATUS(cmac_rsp->regcnt_status);
1850250661Sdavidcs
1851250661Sdavidcs	if (err) {
1852307524Sdavidcs		device_printf(dev, "%s: %s failed1 [0x%08x]\n", __func__,
1853307524Sdavidcs			(add_mac ? "Add" : "Del"), err);
1854307524Sdavidcs		for (i = 0; i < num_mac; i++) {
1855307524Sdavidcs			device_printf(dev, "%s: %02x:%02x:%02x:%02x:%02x:%02x\n",
1856307524Sdavidcs				__func__, mac_cpy[0], mac_cpy[1], mac_cpy[2],
1857307524Sdavidcs				mac_cpy[3], mac_cpy[4], mac_cpy[5]);
1858307524Sdavidcs			mac_cpy += ETHER_ADDR_LEN;
1859307524Sdavidcs		}
1860250661Sdavidcs		return (-1);
1861250661Sdavidcs	}
1862250661Sdavidcs
1863250661Sdavidcs	return 0;
1864250661Sdavidcs}
1865250661Sdavidcs
1866250661Sdavidcs
1867250661Sdavidcs/*
1868250661Sdavidcs * Name: qla_set_mac_rcv_mode
1869305487Sdavidcs * Function: Enable/Disable AllMulticast and Promiscous Modes.
1870250661Sdavidcs */
1871250661Sdavidcsstatic int
1872250661Sdavidcsqla_set_mac_rcv_mode(qla_host_t *ha, uint32_t mode)
1873250661Sdavidcs{
1874250661Sdavidcs	q80_config_mac_rcv_mode_t	*rcv_mode;
1875250661Sdavidcs	uint32_t			err;
1876250661Sdavidcs	q80_config_mac_rcv_mode_rsp_t	*rcv_mode_rsp;
1877250661Sdavidcs	device_t			dev = ha->pci_dev;
1878250661Sdavidcs
1879250661Sdavidcs	rcv_mode = (q80_config_mac_rcv_mode_t *)ha->hw.mbox;
1880250661Sdavidcs	bzero(rcv_mode, (sizeof (q80_config_mac_rcv_mode_t)));
1881250661Sdavidcs
1882250661Sdavidcs	rcv_mode->opcode = Q8_MBX_CONFIG_MAC_RX_MODE;
1883250661Sdavidcs	rcv_mode->count_version = sizeof (q80_config_mac_rcv_mode_t) >> 2;
1884250661Sdavidcs	rcv_mode->count_version |= Q8_MBX_CMD_VERSION;
1885250661Sdavidcs
1886250661Sdavidcs	rcv_mode->mode = mode;
1887250661Sdavidcs
1888250661Sdavidcs	rcv_mode->cntxt_id = ha->hw.rcv_cntxt_id;
1889250661Sdavidcs
1890250661Sdavidcs	if (qla_mbx_cmd(ha, (uint32_t *)rcv_mode,
1891250661Sdavidcs		(sizeof (q80_config_mac_rcv_mode_t) >> 2),
1892250661Sdavidcs		ha->hw.mbox, (sizeof(q80_config_mac_rcv_mode_rsp_t) >> 2), 1)) {
1893250661Sdavidcs		device_printf(dev, "%s: failed0\n", __func__);
1894250661Sdavidcs		return (-1);
1895250661Sdavidcs	}
1896250661Sdavidcs	rcv_mode_rsp = (q80_config_mac_rcv_mode_rsp_t *)ha->hw.mbox;
1897250661Sdavidcs
1898250661Sdavidcs	err = Q8_MBX_RSP_STATUS(rcv_mode_rsp->regcnt_status);
1899250661Sdavidcs
1900250661Sdavidcs	if (err) {
1901250661Sdavidcs		device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err);
1902250661Sdavidcs		return (-1);
1903250661Sdavidcs	}
1904250661Sdavidcs
1905250661Sdavidcs	return 0;
1906250661Sdavidcs}
1907250661Sdavidcs
1908250661Sdavidcsint
1909250661Sdavidcsql_set_promisc(qla_host_t *ha)
1910250661Sdavidcs{
1911250661Sdavidcs	int ret;
1912250661Sdavidcs
1913250661Sdavidcs	ha->hw.mac_rcv_mode |= Q8_MBX_MAC_RCV_PROMISC_ENABLE;
1914250661Sdavidcs	ret = qla_set_mac_rcv_mode(ha, ha->hw.mac_rcv_mode);
1915250661Sdavidcs	return (ret);
1916250661Sdavidcs}
1917250661Sdavidcs
1918284741Sdavidcsvoid
1919284741Sdavidcsqla_reset_promisc(qla_host_t *ha)
1920284741Sdavidcs{
1921284741Sdavidcs	ha->hw.mac_rcv_mode &= ~Q8_MBX_MAC_RCV_PROMISC_ENABLE;
1922284741Sdavidcs	(void)qla_set_mac_rcv_mode(ha, ha->hw.mac_rcv_mode);
1923284741Sdavidcs}
1924284741Sdavidcs
1925250661Sdavidcsint
1926250661Sdavidcsql_set_allmulti(qla_host_t *ha)
1927250661Sdavidcs{
1928250661Sdavidcs	int ret;
1929250661Sdavidcs
1930250661Sdavidcs	ha->hw.mac_rcv_mode |= Q8_MBX_MAC_ALL_MULTI_ENABLE;
1931250661Sdavidcs	ret = qla_set_mac_rcv_mode(ha, ha->hw.mac_rcv_mode);
1932250661Sdavidcs	return (ret);
1933250661Sdavidcs}
1934250661Sdavidcs
1935284741Sdavidcsvoid
1936284741Sdavidcsqla_reset_allmulti(qla_host_t *ha)
1937284741Sdavidcs{
1938284741Sdavidcs	ha->hw.mac_rcv_mode &= ~Q8_MBX_MAC_ALL_MULTI_ENABLE;
1939284741Sdavidcs	(void)qla_set_mac_rcv_mode(ha, ha->hw.mac_rcv_mode);
1940284741Sdavidcs}
1941250661Sdavidcs
1942250661Sdavidcs/*
1943250661Sdavidcs * Name: ql_set_max_mtu
1944250661Sdavidcs * Function:
1945250661Sdavidcs *	Sets the maximum transfer unit size for the specified rcv context.
1946250661Sdavidcs */
1947250661Sdavidcsint
1948250661Sdavidcsql_set_max_mtu(qla_host_t *ha, uint32_t mtu, uint16_t cntxt_id)
1949250661Sdavidcs{
1950250661Sdavidcs	device_t		dev;
1951250661Sdavidcs	q80_set_max_mtu_t	*max_mtu;
1952250661Sdavidcs	q80_set_max_mtu_rsp_t	*max_mtu_rsp;
1953250661Sdavidcs	uint32_t		err;
1954250661Sdavidcs
1955250661Sdavidcs	dev = ha->pci_dev;
1956250661Sdavidcs
1957250661Sdavidcs	max_mtu = (q80_set_max_mtu_t *)ha->hw.mbox;
1958250661Sdavidcs	bzero(max_mtu, (sizeof (q80_set_max_mtu_t)));
1959250661Sdavidcs
1960250661Sdavidcs	max_mtu->opcode = Q8_MBX_SET_MAX_MTU;
1961250661Sdavidcs	max_mtu->count_version = (sizeof (q80_set_max_mtu_t) >> 2);
1962250661Sdavidcs	max_mtu->count_version |= Q8_MBX_CMD_VERSION;
1963250661Sdavidcs
1964250661Sdavidcs	max_mtu->cntxt_id = cntxt_id;
1965250661Sdavidcs	max_mtu->mtu = mtu;
1966250661Sdavidcs
1967250661Sdavidcs        if (qla_mbx_cmd(ha, (uint32_t *)max_mtu,
1968250661Sdavidcs		(sizeof (q80_set_max_mtu_t) >> 2),
1969250661Sdavidcs                ha->hw.mbox, (sizeof (q80_set_max_mtu_rsp_t) >> 2), 1)) {
1970250661Sdavidcs                device_printf(dev, "%s: failed\n", __func__);
1971250661Sdavidcs                return -1;
1972250661Sdavidcs        }
1973250661Sdavidcs
1974250661Sdavidcs	max_mtu_rsp = (q80_set_max_mtu_rsp_t *)ha->hw.mbox;
1975250661Sdavidcs
1976250661Sdavidcs        err = Q8_MBX_RSP_STATUS(max_mtu_rsp->regcnt_status);
1977250661Sdavidcs
1978250661Sdavidcs        if (err) {
1979250661Sdavidcs                device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
1980250661Sdavidcs        }
1981250661Sdavidcs
1982250661Sdavidcs	return 0;
1983250661Sdavidcs}
1984250661Sdavidcs
1985250661Sdavidcsstatic int
1986250661Sdavidcsqla_link_event_req(qla_host_t *ha, uint16_t cntxt_id)
1987250661Sdavidcs{
1988250661Sdavidcs	device_t		dev;
1989250661Sdavidcs	q80_link_event_t	*lnk;
1990250661Sdavidcs	q80_link_event_rsp_t	*lnk_rsp;
1991250661Sdavidcs	uint32_t		err;
1992250661Sdavidcs
1993250661Sdavidcs	dev = ha->pci_dev;
1994250661Sdavidcs
1995250661Sdavidcs	lnk = (q80_link_event_t *)ha->hw.mbox;
1996250661Sdavidcs	bzero(lnk, (sizeof (q80_link_event_t)));
1997250661Sdavidcs
1998250661Sdavidcs	lnk->opcode = Q8_MBX_LINK_EVENT_REQ;
1999250661Sdavidcs	lnk->count_version = (sizeof (q80_link_event_t) >> 2);
2000250661Sdavidcs	lnk->count_version |= Q8_MBX_CMD_VERSION;
2001250661Sdavidcs
2002250661Sdavidcs	lnk->cntxt_id = cntxt_id;
2003250661Sdavidcs	lnk->cmd = Q8_LINK_EVENT_CMD_ENABLE_ASYNC;
2004250661Sdavidcs
2005250661Sdavidcs        if (qla_mbx_cmd(ha, (uint32_t *)lnk, (sizeof (q80_link_event_t) >> 2),
2006250661Sdavidcs                ha->hw.mbox, (sizeof (q80_link_event_rsp_t) >> 2), 0)) {
2007250661Sdavidcs                device_printf(dev, "%s: failed\n", __func__);
2008250661Sdavidcs                return -1;
2009250661Sdavidcs        }
2010250661Sdavidcs
2011250661Sdavidcs	lnk_rsp = (q80_link_event_rsp_t *)ha->hw.mbox;
2012250661Sdavidcs
2013250661Sdavidcs        err = Q8_MBX_RSP_STATUS(lnk_rsp->regcnt_status);
2014250661Sdavidcs
2015250661Sdavidcs        if (err) {
2016250661Sdavidcs                device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
2017250661Sdavidcs        }
2018250661Sdavidcs
2019250661Sdavidcs	return 0;
2020250661Sdavidcs}
2021250661Sdavidcs
2022250661Sdavidcsstatic int
2023250661Sdavidcsqla_config_fw_lro(qla_host_t *ha, uint16_t cntxt_id)
2024250661Sdavidcs{
2025250661Sdavidcs	device_t		dev;
2026250661Sdavidcs	q80_config_fw_lro_t	*fw_lro;
2027250661Sdavidcs	q80_config_fw_lro_rsp_t	*fw_lro_rsp;
2028250661Sdavidcs	uint32_t		err;
2029250661Sdavidcs
2030250661Sdavidcs	dev = ha->pci_dev;
2031250661Sdavidcs
2032250661Sdavidcs	fw_lro = (q80_config_fw_lro_t *)ha->hw.mbox;
2033250661Sdavidcs	bzero(fw_lro, sizeof(q80_config_fw_lro_t));
2034250661Sdavidcs
2035250661Sdavidcs	fw_lro->opcode = Q8_MBX_CONFIG_FW_LRO;
2036250661Sdavidcs	fw_lro->count_version = (sizeof (q80_config_fw_lro_t) >> 2);
2037250661Sdavidcs	fw_lro->count_version |= Q8_MBX_CMD_VERSION;
2038250661Sdavidcs
2039250661Sdavidcs	fw_lro->flags |= Q8_MBX_FW_LRO_IPV4 | Q8_MBX_FW_LRO_IPV4_WO_DST_IP_CHK;
2040284741Sdavidcs	fw_lro->flags |= Q8_MBX_FW_LRO_IPV6 | Q8_MBX_FW_LRO_IPV6_WO_DST_IP_CHK;
2041250661Sdavidcs
2042250661Sdavidcs	fw_lro->cntxt_id = cntxt_id;
2043250661Sdavidcs
2044250661Sdavidcs	if (qla_mbx_cmd(ha, (uint32_t *)fw_lro,
2045250661Sdavidcs		(sizeof (q80_config_fw_lro_t) >> 2),
2046250661Sdavidcs		ha->hw.mbox, (sizeof (q80_config_fw_lro_rsp_t) >> 2), 0)) {
2047250661Sdavidcs		device_printf(dev, "%s: failed\n", __func__);
2048250661Sdavidcs		return -1;
2049250661Sdavidcs	}
2050250661Sdavidcs
2051250661Sdavidcs	fw_lro_rsp = (q80_config_fw_lro_rsp_t *)ha->hw.mbox;
2052250661Sdavidcs
2053250661Sdavidcs	err = Q8_MBX_RSP_STATUS(fw_lro_rsp->regcnt_status);
2054250661Sdavidcs
2055250661Sdavidcs	if (err) {
2056250661Sdavidcs		device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
2057250661Sdavidcs	}
2058250661Sdavidcs
2059250661Sdavidcs	return 0;
2060250661Sdavidcs}
2061250661Sdavidcs
2062305488Sdavidcsstatic int
2063305488Sdavidcsqla_set_cam_search_mode(qla_host_t *ha, uint32_t search_mode)
2064305488Sdavidcs{
2065305488Sdavidcs	device_t                dev;
2066305488Sdavidcs	q80_hw_config_t         *hw_config;
2067305488Sdavidcs	q80_hw_config_rsp_t     *hw_config_rsp;
2068305488Sdavidcs	uint32_t                err;
2069305488Sdavidcs
2070305488Sdavidcs	dev = ha->pci_dev;
2071305488Sdavidcs
2072305488Sdavidcs	hw_config = (q80_hw_config_t *)ha->hw.mbox;
2073305488Sdavidcs	bzero(hw_config, sizeof (q80_hw_config_t));
2074305488Sdavidcs
2075305488Sdavidcs	hw_config->opcode = Q8_MBX_HW_CONFIG;
2076305488Sdavidcs	hw_config->count_version = Q8_HW_CONFIG_SET_CAM_SEARCH_MODE_COUNT;
2077305488Sdavidcs	hw_config->count_version |= Q8_MBX_CMD_VERSION;
2078305488Sdavidcs
2079305488Sdavidcs	hw_config->cmd = Q8_HW_CONFIG_SET_CAM_SEARCH_MODE;
2080305488Sdavidcs
2081305488Sdavidcs	hw_config->u.set_cam_search_mode.mode = search_mode;
2082305488Sdavidcs
2083305488Sdavidcs	if (qla_mbx_cmd(ha, (uint32_t *)hw_config,
2084305488Sdavidcs		(sizeof (q80_hw_config_t) >> 2),
2085305488Sdavidcs		ha->hw.mbox, (sizeof (q80_hw_config_rsp_t) >> 2), 0)) {
2086305488Sdavidcs		device_printf(dev, "%s: failed\n", __func__);
2087305488Sdavidcs		return -1;
2088305488Sdavidcs	}
2089305488Sdavidcs	hw_config_rsp = (q80_hw_config_rsp_t *)ha->hw.mbox;
2090305488Sdavidcs
2091305488Sdavidcs	err = Q8_MBX_RSP_STATUS(hw_config_rsp->regcnt_status);
2092305488Sdavidcs
2093305488Sdavidcs	if (err) {
2094305488Sdavidcs		device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
2095305488Sdavidcs	}
2096305488Sdavidcs
2097305488Sdavidcs	return 0;
2098305488Sdavidcs}
2099305488Sdavidcs
2100305488Sdavidcsstatic int
2101305488Sdavidcsqla_get_cam_search_mode(qla_host_t *ha)
2102305488Sdavidcs{
2103305488Sdavidcs	device_t                dev;
2104305488Sdavidcs	q80_hw_config_t         *hw_config;
2105305488Sdavidcs	q80_hw_config_rsp_t     *hw_config_rsp;
2106305488Sdavidcs	uint32_t                err;
2107305488Sdavidcs
2108305488Sdavidcs	dev = ha->pci_dev;
2109305488Sdavidcs
2110305488Sdavidcs	hw_config = (q80_hw_config_t *)ha->hw.mbox;
2111305488Sdavidcs	bzero(hw_config, sizeof (q80_hw_config_t));
2112305488Sdavidcs
2113305488Sdavidcs	hw_config->opcode = Q8_MBX_HW_CONFIG;
2114305488Sdavidcs	hw_config->count_version = Q8_HW_CONFIG_GET_CAM_SEARCH_MODE_COUNT;
2115305488Sdavidcs	hw_config->count_version |= Q8_MBX_CMD_VERSION;
2116305488Sdavidcs
2117305488Sdavidcs	hw_config->cmd = Q8_HW_CONFIG_GET_CAM_SEARCH_MODE;
2118305488Sdavidcs
2119305488Sdavidcs	if (qla_mbx_cmd(ha, (uint32_t *)hw_config,
2120305488Sdavidcs		(sizeof (q80_hw_config_t) >> 2),
2121305488Sdavidcs		ha->hw.mbox, (sizeof (q80_hw_config_rsp_t) >> 2), 0)) {
2122305488Sdavidcs		device_printf(dev, "%s: failed\n", __func__);
2123305488Sdavidcs		return -1;
2124305488Sdavidcs	}
2125305488Sdavidcs	hw_config_rsp = (q80_hw_config_rsp_t *)ha->hw.mbox;
2126305488Sdavidcs
2127305488Sdavidcs	err = Q8_MBX_RSP_STATUS(hw_config_rsp->regcnt_status);
2128305488Sdavidcs
2129305488Sdavidcs	if (err) {
2130305488Sdavidcs		device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
2131305488Sdavidcs	} else {
2132305488Sdavidcs		device_printf(dev, "%s: cam search mode [0x%08x]\n", __func__,
2133305488Sdavidcs			hw_config_rsp->u.get_cam_search_mode.mode);
2134305488Sdavidcs	}
2135305488Sdavidcs
2136305488Sdavidcs	return 0;
2137305488Sdavidcs}
2138305488Sdavidcs
2139250661Sdavidcsstatic int
2140284741Sdavidcsqla_get_hw_stats(qla_host_t *ha, uint32_t cmd, uint32_t rsp_size)
2141250661Sdavidcs{
2142250661Sdavidcs	device_t		dev;
2143250661Sdavidcs	q80_get_stats_t		*stat;
2144250661Sdavidcs	q80_get_stats_rsp_t	*stat_rsp;
2145250661Sdavidcs	uint32_t		err;
2146250661Sdavidcs
2147250661Sdavidcs	dev = ha->pci_dev;
2148250661Sdavidcs
2149250661Sdavidcs	stat = (q80_get_stats_t *)ha->hw.mbox;
2150250661Sdavidcs	bzero(stat, (sizeof (q80_get_stats_t)));
2151250661Sdavidcs
2152250661Sdavidcs	stat->opcode = Q8_MBX_GET_STATS;
2153250661Sdavidcs	stat->count_version = 2;
2154250661Sdavidcs	stat->count_version |= Q8_MBX_CMD_VERSION;
2155250661Sdavidcs
2156250661Sdavidcs	stat->cmd = cmd;
2157250661Sdavidcs
2158250661Sdavidcs        if (qla_mbx_cmd(ha, (uint32_t *)stat, 2,
2159284741Sdavidcs                ha->hw.mbox, (rsp_size >> 2), 0)) {
2160250661Sdavidcs                device_printf(dev, "%s: failed\n", __func__);
2161250661Sdavidcs                return -1;
2162250661Sdavidcs        }
2163250661Sdavidcs
2164250661Sdavidcs	stat_rsp = (q80_get_stats_rsp_t *)ha->hw.mbox;
2165250661Sdavidcs
2166250661Sdavidcs        err = Q8_MBX_RSP_STATUS(stat_rsp->regcnt_status);
2167250661Sdavidcs
2168250661Sdavidcs        if (err) {
2169250661Sdavidcs                return -1;
2170250661Sdavidcs        }
2171250661Sdavidcs
2172250661Sdavidcs	return 0;
2173250661Sdavidcs}
2174250661Sdavidcs
2175250661Sdavidcsvoid
2176250661Sdavidcsql_get_stats(qla_host_t *ha)
2177250661Sdavidcs{
2178250661Sdavidcs	q80_get_stats_rsp_t	*stat_rsp;
2179250661Sdavidcs	q80_mac_stats_t		*mstat;
2180250661Sdavidcs	q80_xmt_stats_t		*xstat;
2181250661Sdavidcs	q80_rcv_stats_t		*rstat;
2182250661Sdavidcs	uint32_t		cmd;
2183284741Sdavidcs	int			i;
2184322972Sdavidcs	struct ifnet *ifp = ha->ifp;
2185250661Sdavidcs
2186322972Sdavidcs	if (ifp == NULL)
2187322972Sdavidcs		return;
2188322972Sdavidcs
2189322972Sdavidcs	if (QLA_LOCK(ha, __func__, QLA_LOCK_DEFAULT_MS_TIMEOUT, 0) != 0) {
2190322972Sdavidcs		device_printf(ha->pci_dev, "%s: failed\n", __func__);
2191322972Sdavidcs		return;
2192322972Sdavidcs	}
2193322972Sdavidcs
2194322972Sdavidcs	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
2195322972Sdavidcs		QLA_UNLOCK(ha, __func__);
2196322972Sdavidcs		return;
2197322972Sdavidcs	}
2198322972Sdavidcs
2199250661Sdavidcs	stat_rsp = (q80_get_stats_rsp_t *)ha->hw.mbox;
2200250661Sdavidcs	/*
2201250661Sdavidcs	 * Get MAC Statistics
2202250661Sdavidcs	 */
2203250661Sdavidcs	cmd = Q8_GET_STATS_CMD_TYPE_MAC;
2204284741Sdavidcs//	cmd |= Q8_GET_STATS_CMD_CLEAR;
2205250661Sdavidcs
2206250661Sdavidcs	cmd |= ((ha->pci_func & 0x1) << 16);
2207250661Sdavidcs
2208330555Sdavidcs	if (ha->qla_watchdog_pause || (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) ||
2209330555Sdavidcs		ha->offline)
2210322972Sdavidcs		goto ql_get_stats_exit;
2211322972Sdavidcs
2212284741Sdavidcs	if (qla_get_hw_stats(ha, cmd, sizeof (q80_get_stats_rsp_t)) == 0) {
2213250661Sdavidcs		mstat = (q80_mac_stats_t *)&stat_rsp->u.mac;
2214322972Sdavidcs		bcopy(mstat, &ha->hw.mac, sizeof(q80_mac_stats_t));
2215250661Sdavidcs	} else {
2216250661Sdavidcs                device_printf(ha->pci_dev, "%s: mac failed [0x%08x]\n",
2217250661Sdavidcs			__func__, ha->hw.mbox[0]);
2218250661Sdavidcs	}
2219250661Sdavidcs	/*
2220250661Sdavidcs	 * Get RCV Statistics
2221250661Sdavidcs	 */
2222250661Sdavidcs	cmd = Q8_GET_STATS_CMD_RCV | Q8_GET_STATS_CMD_TYPE_CNTXT;
2223284741Sdavidcs//	cmd |= Q8_GET_STATS_CMD_CLEAR;
2224250661Sdavidcs	cmd |= (ha->hw.rcv_cntxt_id << 16);
2225250661Sdavidcs
2226330555Sdavidcs	if (ha->qla_watchdog_pause || (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) ||
2227330555Sdavidcs		ha->offline)
2228322972Sdavidcs		goto ql_get_stats_exit;
2229322972Sdavidcs
2230284741Sdavidcs	if (qla_get_hw_stats(ha, cmd, sizeof (q80_get_stats_rsp_t)) == 0) {
2231250661Sdavidcs		rstat = (q80_rcv_stats_t *)&stat_rsp->u.rcv;
2232322972Sdavidcs		bcopy(rstat, &ha->hw.rcv, sizeof(q80_rcv_stats_t));
2233250661Sdavidcs	} else {
2234250661Sdavidcs                device_printf(ha->pci_dev, "%s: rcv failed [0x%08x]\n",
2235250661Sdavidcs			__func__, ha->hw.mbox[0]);
2236250661Sdavidcs	}
2237322972Sdavidcs
2238330555Sdavidcs	if (ha->qla_watchdog_pause || (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) ||
2239330555Sdavidcs		ha->offline)
2240322972Sdavidcs		goto ql_get_stats_exit;
2241250661Sdavidcs	/*
2242250661Sdavidcs	 * Get XMT Statistics
2243250661Sdavidcs	 */
2244330555Sdavidcs	for (i = 0 ; (i < ha->hw.num_tx_rings); i++) {
2245330555Sdavidcs		if (ha->qla_watchdog_pause ||
2246330555Sdavidcs			(!(ifp->if_drv_flags & IFF_DRV_RUNNING)) ||
2247330555Sdavidcs			ha->offline)
2248330555Sdavidcs			goto ql_get_stats_exit;
2249330555Sdavidcs
2250284741Sdavidcs		cmd = Q8_GET_STATS_CMD_XMT | Q8_GET_STATS_CMD_TYPE_CNTXT;
2251284741Sdavidcs//		cmd |= Q8_GET_STATS_CMD_CLEAR;
2252284741Sdavidcs		cmd |= (ha->hw.tx_cntxt[i].tx_cntxt_id << 16);
2253250661Sdavidcs
2254284741Sdavidcs		if (qla_get_hw_stats(ha, cmd, sizeof(q80_get_stats_rsp_t))
2255284741Sdavidcs			== 0) {
2256284741Sdavidcs			xstat = (q80_xmt_stats_t *)&stat_rsp->u.xmt;
2257322972Sdavidcs			bcopy(xstat, &ha->hw.xmt[i], sizeof(q80_xmt_stats_t));
2258284741Sdavidcs		} else {
2259284741Sdavidcs			device_printf(ha->pci_dev, "%s: xmt failed [0x%08x]\n",
2260284741Sdavidcs				__func__, ha->hw.mbox[0]);
2261284741Sdavidcs		}
2262284741Sdavidcs	}
2263250661Sdavidcs
2264322972Sdavidcsql_get_stats_exit:
2265322972Sdavidcs	QLA_UNLOCK(ha, __func__);
2266284741Sdavidcs
2267284741Sdavidcs	return;
2268250661Sdavidcs}
2269250661Sdavidcs
2270250661Sdavidcs/*
2271250661Sdavidcs * Name: qla_tx_tso
2272250661Sdavidcs * Function: Checks if the packet to be transmitted is a candidate for
2273250661Sdavidcs *	Large TCP Segment Offload. If yes, the appropriate fields in the Tx
2274250661Sdavidcs *	Ring Structure are plugged in.
2275250661Sdavidcs */
2276250661Sdavidcsstatic int
2277250661Sdavidcsqla_tx_tso(qla_host_t *ha, struct mbuf *mp, q80_tx_cmd_t *tx_cmd, uint8_t *hdr)
2278250661Sdavidcs{
2279250661Sdavidcs	struct ether_vlan_header *eh;
2280250661Sdavidcs	struct ip *ip = NULL;
2281250661Sdavidcs	struct ip6_hdr *ip6 = NULL;
2282250661Sdavidcs	struct tcphdr *th = NULL;
2283250661Sdavidcs	uint32_t ehdrlen,  hdrlen, ip_hlen, tcp_hlen, tcp_opt_off;
2284250661Sdavidcs	uint16_t etype, opcode, offload = 1;
2285250661Sdavidcs	device_t dev;
2286250661Sdavidcs
2287250661Sdavidcs	dev = ha->pci_dev;
2288250661Sdavidcs
2289250661Sdavidcs
2290250661Sdavidcs	eh = mtod(mp, struct ether_vlan_header *);
2291250661Sdavidcs
2292250661Sdavidcs	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
2293250661Sdavidcs		ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
2294250661Sdavidcs		etype = ntohs(eh->evl_proto);
2295250661Sdavidcs	} else {
2296250661Sdavidcs		ehdrlen = ETHER_HDR_LEN;
2297250661Sdavidcs		etype = ntohs(eh->evl_encap_proto);
2298250661Sdavidcs	}
2299250661Sdavidcs
2300250661Sdavidcs	hdrlen = 0;
2301250661Sdavidcs
2302250661Sdavidcs	switch (etype) {
2303250661Sdavidcs		case ETHERTYPE_IP:
2304250661Sdavidcs
2305250661Sdavidcs			tcp_opt_off = ehdrlen + sizeof(struct ip) +
2306250661Sdavidcs					sizeof(struct tcphdr);
2307250661Sdavidcs
2308250661Sdavidcs			if (mp->m_len < tcp_opt_off) {
2309250661Sdavidcs				m_copydata(mp, 0, tcp_opt_off, hdr);
2310250661Sdavidcs				ip = (struct ip *)(hdr + ehdrlen);
2311250661Sdavidcs			} else {
2312250661Sdavidcs				ip = (struct ip *)(mp->m_data + ehdrlen);
2313250661Sdavidcs			}
2314250661Sdavidcs
2315250661Sdavidcs			ip_hlen = ip->ip_hl << 2;
2316250661Sdavidcs			opcode = Q8_TX_CMD_OP_XMT_TCP_LSO;
2317250661Sdavidcs
2318250661Sdavidcs
2319250661Sdavidcs			if ((ip->ip_p != IPPROTO_TCP) ||
2320250661Sdavidcs				(ip_hlen != sizeof (struct ip))){
2321250661Sdavidcs				/* IP Options are not supported */
2322250661Sdavidcs
2323250661Sdavidcs				offload = 0;
2324250661Sdavidcs			} else
2325250661Sdavidcs				th = (struct tcphdr *)((caddr_t)ip + ip_hlen);
2326250661Sdavidcs
2327250661Sdavidcs		break;
2328250661Sdavidcs
2329250661Sdavidcs		case ETHERTYPE_IPV6:
2330250661Sdavidcs
2331250661Sdavidcs			tcp_opt_off = ehdrlen + sizeof(struct ip6_hdr) +
2332250661Sdavidcs					sizeof (struct tcphdr);
2333250661Sdavidcs
2334250661Sdavidcs			if (mp->m_len < tcp_opt_off) {
2335250661Sdavidcs				m_copydata(mp, 0, tcp_opt_off, hdr);
2336250661Sdavidcs				ip6 = (struct ip6_hdr *)(hdr + ehdrlen);
2337250661Sdavidcs			} else {
2338250661Sdavidcs				ip6 = (struct ip6_hdr *)(mp->m_data + ehdrlen);
2339250661Sdavidcs			}
2340250661Sdavidcs
2341250661Sdavidcs			ip_hlen = sizeof(struct ip6_hdr);
2342250661Sdavidcs			opcode = Q8_TX_CMD_OP_XMT_TCP_LSO_IPV6;
2343250661Sdavidcs
2344250661Sdavidcs			if (ip6->ip6_nxt != IPPROTO_TCP) {
2345250661Sdavidcs				//device_printf(dev, "%s: ipv6\n", __func__);
2346250661Sdavidcs				offload = 0;
2347250661Sdavidcs			} else
2348250661Sdavidcs				th = (struct tcphdr *)((caddr_t)ip6 + ip_hlen);
2349250661Sdavidcs		break;
2350250661Sdavidcs
2351250661Sdavidcs		default:
2352250661Sdavidcs			QL_DPRINT8(ha, (dev, "%s: type!=ip\n", __func__));
2353250661Sdavidcs			offload = 0;
2354250661Sdavidcs		break;
2355250661Sdavidcs	}
2356250661Sdavidcs
2357250661Sdavidcs	if (!offload)
2358250661Sdavidcs		return (-1);
2359250661Sdavidcs
2360250661Sdavidcs	tcp_hlen = th->th_off << 2;
2361250661Sdavidcs	hdrlen = ehdrlen + ip_hlen + tcp_hlen;
2362250661Sdavidcs
2363250661Sdavidcs        if (mp->m_len < hdrlen) {
2364250661Sdavidcs                if (mp->m_len < tcp_opt_off) {
2365250661Sdavidcs                        if (tcp_hlen > sizeof(struct tcphdr)) {
2366250661Sdavidcs                                m_copydata(mp, tcp_opt_off,
2367250661Sdavidcs                                        (tcp_hlen - sizeof(struct tcphdr)),
2368250661Sdavidcs                                        &hdr[tcp_opt_off]);
2369250661Sdavidcs                        }
2370250661Sdavidcs                } else {
2371250661Sdavidcs                        m_copydata(mp, 0, hdrlen, hdr);
2372250661Sdavidcs                }
2373250661Sdavidcs        }
2374250661Sdavidcs
2375250661Sdavidcs	tx_cmd->mss = mp->m_pkthdr.tso_segsz;
2376250661Sdavidcs
2377250661Sdavidcs	tx_cmd->flags_opcode = opcode ;
2378250661Sdavidcs	tx_cmd->tcp_hdr_off = ip_hlen + ehdrlen;
2379250661Sdavidcs	tx_cmd->total_hdr_len = hdrlen;
2380250661Sdavidcs
2381250661Sdavidcs	/* Check for Multicast least significant bit of MSB == 1 */
2382250661Sdavidcs	if (eh->evl_dhost[0] & 0x01) {
2383250661Sdavidcs		tx_cmd->flags_opcode |= Q8_TX_CMD_FLAGS_MULTICAST;
2384250661Sdavidcs	}
2385250661Sdavidcs
2386250661Sdavidcs	if (mp->m_len < hdrlen) {
2387250661Sdavidcs		printf("%d\n", hdrlen);
2388250661Sdavidcs		return (1);
2389250661Sdavidcs	}
2390250661Sdavidcs
2391250661Sdavidcs	return (0);
2392250661Sdavidcs}
2393250661Sdavidcs
2394250661Sdavidcs/*
2395250661Sdavidcs * Name: qla_tx_chksum
2396250661Sdavidcs * Function: Checks if the packet to be transmitted is a candidate for
2397250661Sdavidcs *	TCP/UDP Checksum offload. If yes, the appropriate fields in the Tx
2398250661Sdavidcs *	Ring Structure are plugged in.
2399250661Sdavidcs */
2400250661Sdavidcsstatic int
2401250661Sdavidcsqla_tx_chksum(qla_host_t *ha, struct mbuf *mp, uint32_t *op_code,
2402250661Sdavidcs	uint32_t *tcp_hdr_off)
2403250661Sdavidcs{
2404250661Sdavidcs	struct ether_vlan_header *eh;
2405250661Sdavidcs	struct ip *ip;
2406250661Sdavidcs	struct ip6_hdr *ip6;
2407250661Sdavidcs	uint32_t ehdrlen, ip_hlen;
2408250661Sdavidcs	uint16_t etype, opcode, offload = 1;
2409250661Sdavidcs	device_t dev;
2410250661Sdavidcs	uint8_t buf[sizeof(struct ip6_hdr)];
2411250661Sdavidcs
2412250661Sdavidcs	dev = ha->pci_dev;
2413250661Sdavidcs
2414250661Sdavidcs	*op_code = 0;
2415250661Sdavidcs
2416322972Sdavidcs	if ((mp->m_pkthdr.csum_flags &
2417322972Sdavidcs		(CSUM_TCP|CSUM_UDP|CSUM_TCP_IPV6 | CSUM_UDP_IPV6)) == 0)
2418250661Sdavidcs		return (-1);
2419250661Sdavidcs
2420250661Sdavidcs	eh = mtod(mp, struct ether_vlan_header *);
2421250661Sdavidcs
2422250661Sdavidcs	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
2423250661Sdavidcs		ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
2424250661Sdavidcs		etype = ntohs(eh->evl_proto);
2425250661Sdavidcs	} else {
2426250661Sdavidcs		ehdrlen = ETHER_HDR_LEN;
2427250661Sdavidcs		etype = ntohs(eh->evl_encap_proto);
2428250661Sdavidcs	}
2429250661Sdavidcs
2430250661Sdavidcs
2431250661Sdavidcs	switch (etype) {
2432250661Sdavidcs		case ETHERTYPE_IP:
2433250661Sdavidcs			ip = (struct ip *)(mp->m_data + ehdrlen);
2434250661Sdavidcs
2435250661Sdavidcs			ip_hlen = sizeof (struct ip);
2436250661Sdavidcs
2437250661Sdavidcs			if (mp->m_len < (ehdrlen + ip_hlen)) {
2438250661Sdavidcs				m_copydata(mp, ehdrlen, sizeof(struct ip), buf);
2439250661Sdavidcs				ip = (struct ip *)buf;
2440250661Sdavidcs			}
2441250661Sdavidcs
2442250661Sdavidcs			if (ip->ip_p == IPPROTO_TCP)
2443250661Sdavidcs				opcode = Q8_TX_CMD_OP_XMT_TCP_CHKSUM;
2444250661Sdavidcs			else if (ip->ip_p == IPPROTO_UDP)
2445250661Sdavidcs				opcode = Q8_TX_CMD_OP_XMT_UDP_CHKSUM;
2446250661Sdavidcs			else {
2447250661Sdavidcs				//device_printf(dev, "%s: ipv4\n", __func__);
2448250661Sdavidcs				offload = 0;
2449250661Sdavidcs			}
2450250661Sdavidcs		break;
2451250661Sdavidcs
2452250661Sdavidcs		case ETHERTYPE_IPV6:
2453250661Sdavidcs			ip6 = (struct ip6_hdr *)(mp->m_data + ehdrlen);
2454250661Sdavidcs
2455250661Sdavidcs			ip_hlen = sizeof(struct ip6_hdr);
2456250661Sdavidcs
2457250661Sdavidcs			if (mp->m_len < (ehdrlen + ip_hlen)) {
2458250661Sdavidcs				m_copydata(mp, ehdrlen, sizeof (struct ip6_hdr),
2459250661Sdavidcs					buf);
2460250661Sdavidcs				ip6 = (struct ip6_hdr *)buf;
2461250661Sdavidcs			}
2462250661Sdavidcs
2463250661Sdavidcs			if (ip6->ip6_nxt == IPPROTO_TCP)
2464250661Sdavidcs				opcode = Q8_TX_CMD_OP_XMT_TCP_CHKSUM_IPV6;
2465250661Sdavidcs			else if (ip6->ip6_nxt == IPPROTO_UDP)
2466250661Sdavidcs				opcode = Q8_TX_CMD_OP_XMT_UDP_CHKSUM_IPV6;
2467250661Sdavidcs			else {
2468250661Sdavidcs				//device_printf(dev, "%s: ipv6\n", __func__);
2469250661Sdavidcs				offload = 0;
2470250661Sdavidcs			}
2471250661Sdavidcs		break;
2472250661Sdavidcs
2473250661Sdavidcs		default:
2474250661Sdavidcs			offload = 0;
2475250661Sdavidcs		break;
2476250661Sdavidcs	}
2477250661Sdavidcs	if (!offload)
2478250661Sdavidcs		return (-1);
2479250661Sdavidcs
2480250661Sdavidcs	*op_code = opcode;
2481250661Sdavidcs	*tcp_hdr_off = (ip_hlen + ehdrlen);
2482250661Sdavidcs
2483250661Sdavidcs	return (0);
2484250661Sdavidcs}
2485250661Sdavidcs
2486250661Sdavidcs#define QLA_TX_MIN_FREE 2
2487250661Sdavidcs/*
2488250661Sdavidcs * Name: ql_hw_send
2489250661Sdavidcs * Function: Transmits a packet. It first checks if the packet is a
2490250661Sdavidcs *	candidate for Large TCP Segment Offload and then for UDP/TCP checksum
2491250661Sdavidcs *	offload. If either of these creteria are not met, it is transmitted
2492250661Sdavidcs *	as a regular ethernet frame.
2493250661Sdavidcs */
2494250661Sdavidcsint
2495250661Sdavidcsql_hw_send(qla_host_t *ha, bus_dma_segment_t *segs, int nsegs,
2496284741Sdavidcs	uint32_t tx_idx, struct mbuf *mp, uint32_t txr_idx, uint32_t iscsi_pdu)
2497250661Sdavidcs{
2498250661Sdavidcs	struct ether_vlan_header *eh;
2499250661Sdavidcs	qla_hw_t *hw = &ha->hw;
2500250661Sdavidcs	q80_tx_cmd_t *tx_cmd, tso_cmd;
2501250661Sdavidcs	bus_dma_segment_t *c_seg;
2502250661Sdavidcs	uint32_t num_tx_cmds, hdr_len = 0;
2503250661Sdavidcs	uint32_t total_length = 0, bytes, tx_cmd_count = 0, txr_next;
2504250661Sdavidcs	device_t dev;
2505250661Sdavidcs	int i, ret;
2506250661Sdavidcs	uint8_t *src = NULL, *dst = NULL;
2507250661Sdavidcs	uint8_t frame_hdr[QL_FRAME_HDR_SIZE];
2508250661Sdavidcs	uint32_t op_code = 0;
2509250661Sdavidcs	uint32_t tcp_hdr_off = 0;
2510250661Sdavidcs
2511250661Sdavidcs	dev = ha->pci_dev;
2512250661Sdavidcs
2513250661Sdavidcs	/*
2514250661Sdavidcs	 * Always make sure there is atleast one empty slot in the tx_ring
2515250661Sdavidcs	 * tx_ring is considered full when there only one entry available
2516250661Sdavidcs	 */
2517250661Sdavidcs        num_tx_cmds = (nsegs + (Q8_TX_CMD_MAX_SEGMENTS - 1)) >> 2;
2518250661Sdavidcs
2519250661Sdavidcs	total_length = mp->m_pkthdr.len;
2520250661Sdavidcs	if (total_length > QLA_MAX_TSO_FRAME_SIZE) {
2521250661Sdavidcs		device_printf(dev, "%s: total length exceeds maxlen(%d)\n",
2522250661Sdavidcs			__func__, total_length);
2523324029Sdavidcs		return (EINVAL);
2524250661Sdavidcs	}
2525250661Sdavidcs	eh = mtod(mp, struct ether_vlan_header *);
2526250661Sdavidcs
2527250661Sdavidcs	if (mp->m_pkthdr.csum_flags & CSUM_TSO) {
2528250661Sdavidcs
2529250661Sdavidcs		bzero((void *)&tso_cmd, sizeof(q80_tx_cmd_t));
2530250661Sdavidcs
2531250661Sdavidcs		src = frame_hdr;
2532250661Sdavidcs		ret = qla_tx_tso(ha, mp, &tso_cmd, src);
2533250661Sdavidcs
2534250661Sdavidcs		if (!(ret & ~1)) {
2535250661Sdavidcs			/* find the additional tx_cmd descriptors required */
2536250661Sdavidcs
2537250661Sdavidcs			if (mp->m_flags & M_VLANTAG)
2538250661Sdavidcs				tso_cmd.total_hdr_len += ETHER_VLAN_ENCAP_LEN;
2539250661Sdavidcs
2540250661Sdavidcs			hdr_len = tso_cmd.total_hdr_len;
2541250661Sdavidcs
2542250661Sdavidcs			bytes = sizeof(q80_tx_cmd_t) - Q8_TX_CMD_TSO_ALIGN;
2543250661Sdavidcs			bytes = QL_MIN(bytes, hdr_len);
2544250661Sdavidcs
2545250661Sdavidcs			num_tx_cmds++;
2546250661Sdavidcs			hdr_len -= bytes;
2547250661Sdavidcs
2548250661Sdavidcs			while (hdr_len) {
2549250661Sdavidcs				bytes = QL_MIN((sizeof(q80_tx_cmd_t)), hdr_len);
2550250661Sdavidcs				hdr_len -= bytes;
2551250661Sdavidcs				num_tx_cmds++;
2552250661Sdavidcs			}
2553250661Sdavidcs			hdr_len = tso_cmd.total_hdr_len;
2554250661Sdavidcs
2555250661Sdavidcs			if (ret == 0)
2556250661Sdavidcs				src = (uint8_t *)eh;
2557250661Sdavidcs		} else
2558250661Sdavidcs			return (EINVAL);
2559250661Sdavidcs	} else {
2560250661Sdavidcs		(void)qla_tx_chksum(ha, mp, &op_code, &tcp_hdr_off);
2561250661Sdavidcs	}
2562250661Sdavidcs
2563250661Sdavidcs	if (hw->tx_cntxt[txr_idx].txr_free <= (num_tx_cmds + QLA_TX_MIN_FREE)) {
2564313070Sdavidcs		ql_hw_tx_done_locked(ha, txr_idx);
2565250661Sdavidcs		if (hw->tx_cntxt[txr_idx].txr_free <=
2566250661Sdavidcs				(num_tx_cmds + QLA_TX_MIN_FREE)) {
2567250661Sdavidcs        		QL_DPRINT8(ha, (dev, "%s: (hw->txr_free <= "
2568250661Sdavidcs				"(num_tx_cmds + QLA_TX_MIN_FREE))\n",
2569250661Sdavidcs				__func__));
2570250661Sdavidcs			return (-1);
2571250661Sdavidcs		}
2572250661Sdavidcs	}
2573250661Sdavidcs
2574324761Sdavidcs	for (i = 0; i < num_tx_cmds; i++) {
2575324761Sdavidcs		int j;
2576324761Sdavidcs
2577324761Sdavidcs		j = (tx_idx+i) & (NUM_TX_DESCRIPTORS - 1);
2578324761Sdavidcs
2579324761Sdavidcs		if (NULL != ha->tx_ring[txr_idx].tx_buf[j].m_head) {
2580324761Sdavidcs			QL_ASSERT(ha, 0, \
2581324761Sdavidcs				("%s [%d]: txr_idx = %d tx_idx = %d mbuf = %p\n",\
2582324761Sdavidcs				__func__, __LINE__, txr_idx, j,\
2583324761Sdavidcs				ha->tx_ring[txr_idx].tx_buf[j].m_head));
2584324761Sdavidcs			return (EINVAL);
2585324761Sdavidcs		}
2586324761Sdavidcs	}
2587324761Sdavidcs
2588250661Sdavidcs	tx_cmd = &hw->tx_cntxt[txr_idx].tx_ring_base[tx_idx];
2589250661Sdavidcs
2590250661Sdavidcs        if (!(mp->m_pkthdr.csum_flags & CSUM_TSO)) {
2591250661Sdavidcs
2592250661Sdavidcs                if (nsegs > ha->hw.max_tx_segs)
2593250661Sdavidcs                        ha->hw.max_tx_segs = nsegs;
2594250661Sdavidcs
2595250661Sdavidcs                bzero((void *)tx_cmd, sizeof(q80_tx_cmd_t));
2596250661Sdavidcs
2597250661Sdavidcs                if (op_code) {
2598250661Sdavidcs                        tx_cmd->flags_opcode = op_code;
2599250661Sdavidcs                        tx_cmd->tcp_hdr_off = tcp_hdr_off;
2600250661Sdavidcs
2601250661Sdavidcs                } else {
2602250661Sdavidcs                        tx_cmd->flags_opcode = Q8_TX_CMD_OP_XMT_ETHER;
2603250661Sdavidcs                }
2604250661Sdavidcs	} else {
2605250661Sdavidcs		bcopy(&tso_cmd, tx_cmd, sizeof(q80_tx_cmd_t));
2606250661Sdavidcs		ha->tx_tso_frames++;
2607250661Sdavidcs	}
2608250661Sdavidcs
2609250661Sdavidcs	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
2610250661Sdavidcs        	tx_cmd->flags_opcode |= Q8_TX_CMD_FLAGS_VLAN_TAGGED;
2611284741Sdavidcs
2612284741Sdavidcs		if (iscsi_pdu)
2613284741Sdavidcs			eh->evl_tag |= ha->hw.user_pri_iscsi << 13;
2614284741Sdavidcs
2615250661Sdavidcs	} else if (mp->m_flags & M_VLANTAG) {
2616250661Sdavidcs
2617250661Sdavidcs		if (hdr_len) { /* TSO */
2618250661Sdavidcs			tx_cmd->flags_opcode |= (Q8_TX_CMD_FLAGS_VLAN_TAGGED |
2619250661Sdavidcs						Q8_TX_CMD_FLAGS_HW_VLAN_ID);
2620250661Sdavidcs			tx_cmd->tcp_hdr_off += ETHER_VLAN_ENCAP_LEN;
2621250661Sdavidcs		} else
2622250661Sdavidcs			tx_cmd->flags_opcode |= Q8_TX_CMD_FLAGS_HW_VLAN_ID;
2623250661Sdavidcs
2624250661Sdavidcs		ha->hw_vlan_tx_frames++;
2625250661Sdavidcs		tx_cmd->vlan_tci = mp->m_pkthdr.ether_vtag;
2626284741Sdavidcs
2627284741Sdavidcs		if (iscsi_pdu) {
2628284741Sdavidcs			tx_cmd->vlan_tci |= ha->hw.user_pri_iscsi << 13;
2629284741Sdavidcs			mp->m_pkthdr.ether_vtag = tx_cmd->vlan_tci;
2630284741Sdavidcs		}
2631250661Sdavidcs	}
2632250661Sdavidcs
2633250661Sdavidcs
2634250661Sdavidcs        tx_cmd->n_bufs = (uint8_t)nsegs;
2635250661Sdavidcs        tx_cmd->data_len_lo = (uint8_t)(total_length & 0xFF);
2636250661Sdavidcs        tx_cmd->data_len_hi = qla_host_to_le16(((uint16_t)(total_length >> 8)));
2637250661Sdavidcs	tx_cmd->cntxtid = Q8_TX_CMD_PORT_CNXTID(ha->pci_func);
2638250661Sdavidcs
2639250661Sdavidcs	c_seg = segs;
2640250661Sdavidcs
2641250661Sdavidcs	while (1) {
2642250661Sdavidcs		for (i = 0; ((i < Q8_TX_CMD_MAX_SEGMENTS) && nsegs); i++) {
2643250661Sdavidcs
2644250661Sdavidcs			switch (i) {
2645250661Sdavidcs			case 0:
2646250661Sdavidcs				tx_cmd->buf1_addr = c_seg->ds_addr;
2647250661Sdavidcs				tx_cmd->buf1_len = c_seg->ds_len;
2648250661Sdavidcs				break;
2649250661Sdavidcs
2650250661Sdavidcs			case 1:
2651250661Sdavidcs				tx_cmd->buf2_addr = c_seg->ds_addr;
2652250661Sdavidcs				tx_cmd->buf2_len = c_seg->ds_len;
2653250661Sdavidcs				break;
2654250661Sdavidcs
2655250661Sdavidcs			case 2:
2656250661Sdavidcs				tx_cmd->buf3_addr = c_seg->ds_addr;
2657250661Sdavidcs				tx_cmd->buf3_len = c_seg->ds_len;
2658250661Sdavidcs				break;
2659250661Sdavidcs
2660250661Sdavidcs			case 3:
2661250661Sdavidcs				tx_cmd->buf4_addr = c_seg->ds_addr;
2662250661Sdavidcs				tx_cmd->buf4_len = c_seg->ds_len;
2663250661Sdavidcs				break;
2664250661Sdavidcs			}
2665250661Sdavidcs
2666250661Sdavidcs			c_seg++;
2667250661Sdavidcs			nsegs--;
2668250661Sdavidcs		}
2669250661Sdavidcs
2670250661Sdavidcs		txr_next = hw->tx_cntxt[txr_idx].txr_next =
2671250661Sdavidcs			(hw->tx_cntxt[txr_idx].txr_next + 1) &
2672250661Sdavidcs				(NUM_TX_DESCRIPTORS - 1);
2673250661Sdavidcs		tx_cmd_count++;
2674250661Sdavidcs
2675250661Sdavidcs		if (!nsegs)
2676250661Sdavidcs			break;
2677250661Sdavidcs
2678250661Sdavidcs		tx_cmd = &hw->tx_cntxt[txr_idx].tx_ring_base[txr_next];
2679250661Sdavidcs		bzero((void *)tx_cmd, sizeof(q80_tx_cmd_t));
2680250661Sdavidcs	}
2681250661Sdavidcs
2682250661Sdavidcs	if (mp->m_pkthdr.csum_flags & CSUM_TSO) {
2683250661Sdavidcs
2684250661Sdavidcs		/* TSO : Copy the header in the following tx cmd descriptors */
2685250661Sdavidcs
2686250661Sdavidcs		txr_next = hw->tx_cntxt[txr_idx].txr_next;
2687250661Sdavidcs
2688250661Sdavidcs		tx_cmd = &hw->tx_cntxt[txr_idx].tx_ring_base[txr_next];
2689250661Sdavidcs		bzero((void *)tx_cmd, sizeof(q80_tx_cmd_t));
2690250661Sdavidcs
2691250661Sdavidcs		bytes = sizeof(q80_tx_cmd_t) - Q8_TX_CMD_TSO_ALIGN;
2692250661Sdavidcs		bytes = QL_MIN(bytes, hdr_len);
2693250661Sdavidcs
2694250661Sdavidcs		dst = (uint8_t *)tx_cmd + Q8_TX_CMD_TSO_ALIGN;
2695250661Sdavidcs
2696250661Sdavidcs		if (mp->m_flags & M_VLANTAG) {
2697250661Sdavidcs			/* first copy the src/dst MAC addresses */
2698250661Sdavidcs			bcopy(src, dst, (ETHER_ADDR_LEN * 2));
2699250661Sdavidcs			dst += (ETHER_ADDR_LEN * 2);
2700250661Sdavidcs			src += (ETHER_ADDR_LEN * 2);
2701250661Sdavidcs
2702250661Sdavidcs			*((uint16_t *)dst) = htons(ETHERTYPE_VLAN);
2703250661Sdavidcs			dst += 2;
2704250661Sdavidcs			*((uint16_t *)dst) = htons(mp->m_pkthdr.ether_vtag);
2705250661Sdavidcs			dst += 2;
2706250661Sdavidcs
2707250661Sdavidcs			/* bytes left in src header */
2708250661Sdavidcs			hdr_len -= ((ETHER_ADDR_LEN * 2) +
2709250661Sdavidcs					ETHER_VLAN_ENCAP_LEN);
2710250661Sdavidcs
2711250661Sdavidcs			/* bytes left in TxCmd Entry */
2712250661Sdavidcs			bytes -= ((ETHER_ADDR_LEN * 2) + ETHER_VLAN_ENCAP_LEN);
2713250661Sdavidcs
2714250661Sdavidcs
2715250661Sdavidcs			bcopy(src, dst, bytes);
2716250661Sdavidcs			src += bytes;
2717250661Sdavidcs			hdr_len -= bytes;
2718250661Sdavidcs		} else {
2719250661Sdavidcs			bcopy(src, dst, bytes);
2720250661Sdavidcs			src += bytes;
2721250661Sdavidcs			hdr_len -= bytes;
2722250661Sdavidcs		}
2723250661Sdavidcs
2724250661Sdavidcs		txr_next = hw->tx_cntxt[txr_idx].txr_next =
2725250661Sdavidcs				(hw->tx_cntxt[txr_idx].txr_next + 1) &
2726250661Sdavidcs					(NUM_TX_DESCRIPTORS - 1);
2727250661Sdavidcs		tx_cmd_count++;
2728250661Sdavidcs
2729250661Sdavidcs		while (hdr_len) {
2730250661Sdavidcs			tx_cmd = &hw->tx_cntxt[txr_idx].tx_ring_base[txr_next];
2731250661Sdavidcs			bzero((void *)tx_cmd, sizeof(q80_tx_cmd_t));
2732250661Sdavidcs
2733250661Sdavidcs			bytes = QL_MIN((sizeof(q80_tx_cmd_t)), hdr_len);
2734250661Sdavidcs
2735250661Sdavidcs			bcopy(src, tx_cmd, bytes);
2736250661Sdavidcs			src += bytes;
2737250661Sdavidcs			hdr_len -= bytes;
2738250661Sdavidcs
2739250661Sdavidcs			txr_next = hw->tx_cntxt[txr_idx].txr_next =
2740250661Sdavidcs				(hw->tx_cntxt[txr_idx].txr_next + 1) &
2741250661Sdavidcs					(NUM_TX_DESCRIPTORS - 1);
2742250661Sdavidcs			tx_cmd_count++;
2743250661Sdavidcs		}
2744250661Sdavidcs	}
2745250661Sdavidcs
2746250661Sdavidcs	hw->tx_cntxt[txr_idx].txr_free =
2747250661Sdavidcs		hw->tx_cntxt[txr_idx].txr_free - tx_cmd_count;
2748250661Sdavidcs
2749250661Sdavidcs	QL_UPDATE_TX_PRODUCER_INDEX(ha, hw->tx_cntxt[txr_idx].txr_next,\
2750250661Sdavidcs		txr_idx);
2751250661Sdavidcs       	QL_DPRINT8(ha, (dev, "%s: return\n", __func__));
2752250661Sdavidcs
2753250661Sdavidcs	return (0);
2754250661Sdavidcs}
2755250661Sdavidcs
2756250661Sdavidcs
2757284741Sdavidcs
2758284741Sdavidcs#define Q8_CONFIG_IND_TBL_SIZE	32 /* < Q8_RSS_IND_TBL_SIZE and power of 2 */
2759250661Sdavidcsstatic int
2760250661Sdavidcsqla_config_rss_ind_table(qla_host_t *ha)
2761250661Sdavidcs{
2762250661Sdavidcs	uint32_t i, count;
2763284741Sdavidcs	uint8_t rss_ind_tbl[Q8_CONFIG_IND_TBL_SIZE];
2764250661Sdavidcs
2765250661Sdavidcs
2766284741Sdavidcs	for (i = 0; i < Q8_CONFIG_IND_TBL_SIZE; i++) {
2767250661Sdavidcs		rss_ind_tbl[i] = i % ha->hw.num_sds_rings;
2768250661Sdavidcs	}
2769250661Sdavidcs
2770284741Sdavidcs	for (i = 0; i <= Q8_RSS_IND_TBL_MAX_IDX ;
2771284741Sdavidcs		i = i + Q8_CONFIG_IND_TBL_SIZE) {
2772250661Sdavidcs
2773284741Sdavidcs		if ((i + Q8_CONFIG_IND_TBL_SIZE) > Q8_RSS_IND_TBL_MAX_IDX) {
2774250661Sdavidcs			count = Q8_RSS_IND_TBL_MAX_IDX - i + 1;
2775250661Sdavidcs		} else {
2776284741Sdavidcs			count = Q8_CONFIG_IND_TBL_SIZE;
2777250661Sdavidcs		}
2778250661Sdavidcs
2779250661Sdavidcs		if (qla_set_rss_ind_table(ha, i, count, ha->hw.rcv_cntxt_id,
2780250661Sdavidcs			rss_ind_tbl))
2781250661Sdavidcs			return (-1);
2782250661Sdavidcs	}
2783250661Sdavidcs
2784250661Sdavidcs	return (0);
2785250661Sdavidcs}
2786250661Sdavidcs
2787317109Sdavidcsstatic int
2788317109Sdavidcsqla_config_soft_lro(qla_host_t *ha)
2789317109Sdavidcs{
2790317109Sdavidcs        int i;
2791317109Sdavidcs        qla_hw_t *hw = &ha->hw;
2792317109Sdavidcs        struct lro_ctrl *lro;
2793317109Sdavidcs
2794317109Sdavidcs        for (i = 0; i < hw->num_sds_rings; i++) {
2795317109Sdavidcs                lro = &hw->sds[i].lro;
2796317109Sdavidcs
2797317109Sdavidcs		bzero(lro, sizeof(struct lro_ctrl));
2798317109Sdavidcs
2799317109Sdavidcs#if (__FreeBSD_version >= 1100101)
2800317109Sdavidcs                if (tcp_lro_init_args(lro, ha->ifp, 0, NUM_RX_DESCRIPTORS)) {
2801317109Sdavidcs                        device_printf(ha->pci_dev,
2802317109Sdavidcs				"%s: tcp_lro_init_args [%d] failed\n",
2803317109Sdavidcs                                __func__, i);
2804317109Sdavidcs                        return (-1);
2805317109Sdavidcs                }
2806317109Sdavidcs#else
2807317109Sdavidcs                if (tcp_lro_init(lro)) {
2808317109Sdavidcs                        device_printf(ha->pci_dev,
2809317109Sdavidcs				"%s: tcp_lro_init [%d] failed\n",
2810317109Sdavidcs                                __func__, i);
2811317109Sdavidcs                        return (-1);
2812317109Sdavidcs                }
2813317109Sdavidcs#endif /* #if (__FreeBSD_version >= 1100101) */
2814317109Sdavidcs
2815317109Sdavidcs                lro->ifp = ha->ifp;
2816317109Sdavidcs        }
2817317109Sdavidcs
2818317109Sdavidcs        QL_DPRINT2(ha, (ha->pci_dev, "%s: LRO initialized\n", __func__));
2819317109Sdavidcs        return (0);
2820317109Sdavidcs}
2821317109Sdavidcs
2822317109Sdavidcsstatic void
2823317109Sdavidcsqla_drain_soft_lro(qla_host_t *ha)
2824317109Sdavidcs{
2825317109Sdavidcs        int i;
2826317109Sdavidcs        qla_hw_t *hw = &ha->hw;
2827317109Sdavidcs        struct lro_ctrl *lro;
2828317109Sdavidcs
2829317109Sdavidcs       	for (i = 0; i < hw->num_sds_rings; i++) {
2830317109Sdavidcs               	lro = &hw->sds[i].lro;
2831317109Sdavidcs
2832317109Sdavidcs#if (__FreeBSD_version >= 1100101)
2833317109Sdavidcs		tcp_lro_flush_all(lro);
2834317109Sdavidcs#else
2835317109Sdavidcs                struct lro_entry *queued;
2836317109Sdavidcs
2837317109Sdavidcs		while ((!SLIST_EMPTY(&lro->lro_active))) {
2838317109Sdavidcs			queued = SLIST_FIRST(&lro->lro_active);
2839317109Sdavidcs			SLIST_REMOVE_HEAD(&lro->lro_active, next);
2840317109Sdavidcs			tcp_lro_flush(lro, queued);
2841317109Sdavidcs		}
2842317109Sdavidcs#endif /* #if (__FreeBSD_version >= 1100101) */
2843317109Sdavidcs	}
2844317109Sdavidcs
2845317109Sdavidcs	return;
2846317109Sdavidcs}
2847317109Sdavidcs
2848317109Sdavidcsstatic void
2849317109Sdavidcsqla_free_soft_lro(qla_host_t *ha)
2850317109Sdavidcs{
2851317109Sdavidcs        int i;
2852317109Sdavidcs        qla_hw_t *hw = &ha->hw;
2853317109Sdavidcs        struct lro_ctrl *lro;
2854317109Sdavidcs
2855317109Sdavidcs        for (i = 0; i < hw->num_sds_rings; i++) {
2856317109Sdavidcs               	lro = &hw->sds[i].lro;
2857317109Sdavidcs		tcp_lro_free(lro);
2858317109Sdavidcs	}
2859317109Sdavidcs
2860317109Sdavidcs	return;
2861317109Sdavidcs}
2862317109Sdavidcs
2863317109Sdavidcs
2864250661Sdavidcs/*
2865250661Sdavidcs * Name: ql_del_hw_if
2866250661Sdavidcs * Function: Destroys the hardware specific entities corresponding to an
2867250661Sdavidcs *	Ethernet Interface
2868250661Sdavidcs */
2869250661Sdavidcsvoid
2870250661Sdavidcsql_del_hw_if(qla_host_t *ha)
2871250661Sdavidcs{
2872284741Sdavidcs	uint32_t i;
2873284741Sdavidcs	uint32_t num_msix;
2874250661Sdavidcs
2875284741Sdavidcs	(void)qla_stop_nic_func(ha);
2876284741Sdavidcs
2877250661Sdavidcs	qla_del_rcv_cntxt(ha);
2878307524Sdavidcs
2879330555Sdavidcs	if(qla_del_xmt_cntxt(ha))
2880330555Sdavidcs		goto ql_del_hw_if_exit;
2881250661Sdavidcs
2882250661Sdavidcs	if (ha->hw.flags.init_intr_cnxt) {
2883284741Sdavidcs		for (i = 0; i < ha->hw.num_sds_rings; ) {
2884284741Sdavidcs
2885284741Sdavidcs			if ((i + Q8_MAX_INTR_VECTORS) < ha->hw.num_sds_rings)
2886284741Sdavidcs				num_msix = Q8_MAX_INTR_VECTORS;
2887284741Sdavidcs			else
2888284741Sdavidcs				num_msix = ha->hw.num_sds_rings - i;
2889284741Sdavidcs
2890330555Sdavidcs			if (qla_config_intr_cntxt(ha, i, num_msix, 0))
2891330555Sdavidcs				break;
2892330555Sdavidcs
2893284741Sdavidcs			i += num_msix;
2894284741Sdavidcs		}
2895284741Sdavidcs
2896250661Sdavidcs		ha->hw.flags.init_intr_cnxt = 0;
2897250661Sdavidcs	}
2898307524Sdavidcs
2899330555Sdavidcsql_del_hw_if_exit:
2900317109Sdavidcs	if (ha->hw.enable_soft_lro) {
2901317109Sdavidcs		qla_drain_soft_lro(ha);
2902317109Sdavidcs		qla_free_soft_lro(ha);
2903317109Sdavidcs	}
2904317109Sdavidcs
2905284741Sdavidcs	return;
2906250661Sdavidcs}
2907250661Sdavidcs
2908284741Sdavidcsvoid
2909284741Sdavidcsqla_confirm_9kb_enable(qla_host_t *ha)
2910284741Sdavidcs{
2911332052Sdavidcs//	uint32_t supports_9kb = 0;
2912284741Sdavidcs
2913284741Sdavidcs	ha->hw.mbx_intr_mask_offset = READ_REG32(ha, Q8_MBOX_INT_MASK_MSIX);
2914284741Sdavidcs
2915284741Sdavidcs	/* Use MSI-X vector 0; Enable Firmware Mailbox Interrupt */
2916284741Sdavidcs	WRITE_REG32(ha, Q8_MBOX_INT_ENABLE, BIT_2);
2917284741Sdavidcs	WRITE_REG32(ha, ha->hw.mbx_intr_mask_offset, 0x0);
2918284741Sdavidcs
2919332052Sdavidcs#if 0
2920284741Sdavidcs	qla_get_nic_partition(ha, &supports_9kb, NULL);
2921284741Sdavidcs
2922284741Sdavidcs	if (!supports_9kb)
2923332052Sdavidcs#endif
2924332052Sdavidcs	ha->hw.enable_9kb = 0;
2925284741Sdavidcs
2926284741Sdavidcs	return;
2927284741Sdavidcs}
2928284741Sdavidcs
2929250661Sdavidcs/*
2930250661Sdavidcs * Name: ql_init_hw_if
2931250661Sdavidcs * Function: Creates the hardware specific entities corresponding to an
2932250661Sdavidcs *	Ethernet Interface - Transmit and Receive Contexts. Sets the MAC Address
2933250661Sdavidcs *	corresponding to the interface. Enables LRO if allowed.
2934250661Sdavidcs */
2935250661Sdavidcsint
2936250661Sdavidcsql_init_hw_if(qla_host_t *ha)
2937250661Sdavidcs{
2938250661Sdavidcs	device_t	dev;
2939250661Sdavidcs	uint32_t	i;
2940250661Sdavidcs	uint8_t		bcast_mac[6];
2941250661Sdavidcs	qla_rdesc_t	*rdesc;
2942284741Sdavidcs	uint32_t	num_msix;
2943250661Sdavidcs
2944250661Sdavidcs	dev = ha->pci_dev;
2945250661Sdavidcs
2946250661Sdavidcs	for (i = 0; i < ha->hw.num_sds_rings; i++) {
2947250661Sdavidcs		bzero(ha->hw.dma_buf.sds_ring[i].dma_b,
2948250661Sdavidcs			ha->hw.dma_buf.sds_ring[i].size);
2949250661Sdavidcs	}
2950250661Sdavidcs
2951284741Sdavidcs	for (i = 0; i < ha->hw.num_sds_rings; ) {
2952250661Sdavidcs
2953284741Sdavidcs		if ((i + Q8_MAX_INTR_VECTORS) < ha->hw.num_sds_rings)
2954284741Sdavidcs			num_msix = Q8_MAX_INTR_VECTORS;
2955284741Sdavidcs		else
2956284741Sdavidcs			num_msix = ha->hw.num_sds_rings - i;
2957250661Sdavidcs
2958284741Sdavidcs		if (qla_config_intr_cntxt(ha, i, num_msix, 1)) {
2959250661Sdavidcs
2960284741Sdavidcs			if (i > 0) {
2961284741Sdavidcs
2962284741Sdavidcs				num_msix = i;
2963284741Sdavidcs
2964284741Sdavidcs				for (i = 0; i < num_msix; ) {
2965284741Sdavidcs					qla_config_intr_cntxt(ha, i,
2966284741Sdavidcs						Q8_MAX_INTR_VECTORS, 0);
2967284741Sdavidcs					i += Q8_MAX_INTR_VECTORS;
2968284741Sdavidcs				}
2969284741Sdavidcs			}
2970284741Sdavidcs			return (-1);
2971284741Sdavidcs		}
2972284741Sdavidcs
2973284741Sdavidcs		i = i + num_msix;
2974284741Sdavidcs	}
2975284741Sdavidcs
2976284741Sdavidcs        ha->hw.flags.init_intr_cnxt = 1;
2977284741Sdavidcs
2978250661Sdavidcs	/*
2979250661Sdavidcs	 * Create Receive Context
2980250661Sdavidcs	 */
2981250661Sdavidcs	if (qla_init_rcv_cntxt(ha)) {
2982250661Sdavidcs		return (-1);
2983250661Sdavidcs	}
2984250661Sdavidcs
2985250661Sdavidcs	for (i = 0; i < ha->hw.num_rds_rings; i++) {
2986250661Sdavidcs		rdesc = &ha->hw.rds[i];
2987250661Sdavidcs		rdesc->rx_next = NUM_RX_DESCRIPTORS - 2;
2988250661Sdavidcs		rdesc->rx_in = 0;
2989250661Sdavidcs		/* Update the RDS Producer Indices */
2990250661Sdavidcs		QL_UPDATE_RDS_PRODUCER_INDEX(ha, rdesc->prod_std,\
2991250661Sdavidcs			rdesc->rx_next);
2992250661Sdavidcs	}
2993250661Sdavidcs
2994250661Sdavidcs	/*
2995250661Sdavidcs	 * Create Transmit Context
2996250661Sdavidcs	 */
2997250661Sdavidcs	if (qla_init_xmt_cntxt(ha)) {
2998250661Sdavidcs		qla_del_rcv_cntxt(ha);
2999250661Sdavidcs		return (-1);
3000250661Sdavidcs	}
3001250661Sdavidcs	ha->hw.max_tx_segs = 0;
3002250661Sdavidcs
3003307524Sdavidcs	if (qla_config_mac_addr(ha, ha->hw.mac_addr, 1, 1))
3004250661Sdavidcs		return(-1);
3005250661Sdavidcs
3006250661Sdavidcs	ha->hw.flags.unicast_mac = 1;
3007250661Sdavidcs
3008250661Sdavidcs	bcast_mac[0] = 0xFF; bcast_mac[1] = 0xFF; bcast_mac[2] = 0xFF;
3009250661Sdavidcs	bcast_mac[3] = 0xFF; bcast_mac[4] = 0xFF; bcast_mac[5] = 0xFF;
3010250661Sdavidcs
3011307524Sdavidcs	if (qla_config_mac_addr(ha, bcast_mac, 1, 1))
3012250661Sdavidcs		return (-1);
3013250661Sdavidcs
3014250661Sdavidcs	ha->hw.flags.bcast_mac = 1;
3015250661Sdavidcs
3016250661Sdavidcs	/*
3017250661Sdavidcs	 * program any cached multicast addresses
3018250661Sdavidcs	 */
3019250661Sdavidcs	if (qla_hw_add_all_mcast(ha))
3020250661Sdavidcs		return (-1);
3021250661Sdavidcs
3022321494Sdavidcs	if (ql_set_max_mtu(ha, ha->max_frame_size, ha->hw.rcv_cntxt_id))
3023321494Sdavidcs		return (-1);
3024321494Sdavidcs
3025250661Sdavidcs	if (qla_config_rss(ha, ha->hw.rcv_cntxt_id))
3026250661Sdavidcs		return (-1);
3027250661Sdavidcs
3028250661Sdavidcs	if (qla_config_rss_ind_table(ha))
3029250661Sdavidcs		return (-1);
3030250661Sdavidcs
3031284741Sdavidcs	if (qla_config_intr_coalesce(ha, ha->hw.rcv_cntxt_id, 0, 1))
3032250661Sdavidcs		return (-1);
3033250661Sdavidcs
3034250661Sdavidcs	if (qla_link_event_req(ha, ha->hw.rcv_cntxt_id))
3035250661Sdavidcs		return (-1);
3036250661Sdavidcs
3037317109Sdavidcs	if (ha->ifp->if_capenable & IFCAP_LRO) {
3038317109Sdavidcs		if (ha->hw.enable_hw_lro) {
3039317109Sdavidcs			ha->hw.enable_soft_lro = 0;
3040250661Sdavidcs
3041317109Sdavidcs			if (qla_config_fw_lro(ha, ha->hw.rcv_cntxt_id))
3042317109Sdavidcs				return (-1);
3043317109Sdavidcs		} else {
3044317109Sdavidcs			ha->hw.enable_soft_lro = 1;
3045317109Sdavidcs
3046317109Sdavidcs			if (qla_config_soft_lro(ha))
3047317109Sdavidcs				return (-1);
3048317109Sdavidcs		}
3049317109Sdavidcs	}
3050317109Sdavidcs
3051284741Sdavidcs        if (qla_init_nic_func(ha))
3052284741Sdavidcs                return (-1);
3053284741Sdavidcs
3054284741Sdavidcs        if (qla_query_fw_dcbx_caps(ha))
3055284741Sdavidcs                return (-1);
3056284741Sdavidcs
3057250661Sdavidcs	for (i = 0; i < ha->hw.num_sds_rings; i++)
3058250661Sdavidcs		QL_ENABLE_INTERRUPTS(ha, i);
3059250661Sdavidcs
3060250661Sdavidcs	return (0);
3061250661Sdavidcs}
3062250661Sdavidcs
3063250661Sdavidcsstatic int
3064284741Sdavidcsqla_map_sds_to_rds(qla_host_t *ha, uint32_t start_idx, uint32_t num_idx)
3065250661Sdavidcs{
3066250661Sdavidcs        device_t                dev = ha->pci_dev;
3067250661Sdavidcs        q80_rq_map_sds_to_rds_t *map_rings;
3068284741Sdavidcs	q80_rsp_map_sds_to_rds_t *map_rings_rsp;
3069250661Sdavidcs        uint32_t                i, err;
3070250661Sdavidcs        qla_hw_t                *hw = &ha->hw;
3071250661Sdavidcs
3072250661Sdavidcs        map_rings = (q80_rq_map_sds_to_rds_t *)ha->hw.mbox;
3073250661Sdavidcs        bzero(map_rings, sizeof(q80_rq_map_sds_to_rds_t));
3074250661Sdavidcs
3075250661Sdavidcs        map_rings->opcode = Q8_MBX_MAP_SDS_TO_RDS;
3076250661Sdavidcs        map_rings->count_version = (sizeof (q80_rq_map_sds_to_rds_t) >> 2);
3077250661Sdavidcs        map_rings->count_version |= Q8_MBX_CMD_VERSION;
3078250661Sdavidcs
3079250661Sdavidcs        map_rings->cntxt_id = hw->rcv_cntxt_id;
3080284741Sdavidcs        map_rings->num_rings = num_idx;
3081250661Sdavidcs
3082284741Sdavidcs	for (i = 0; i < num_idx; i++) {
3083284741Sdavidcs		map_rings->sds_rds[i].sds_ring = i + start_idx;
3084284741Sdavidcs		map_rings->sds_rds[i].rds_ring = i + start_idx;
3085284741Sdavidcs	}
3086250661Sdavidcs
3087250661Sdavidcs        if (qla_mbx_cmd(ha, (uint32_t *)map_rings,
3088250661Sdavidcs                (sizeof (q80_rq_map_sds_to_rds_t) >> 2),
3089250661Sdavidcs                ha->hw.mbox, (sizeof(q80_rsp_add_rcv_rings_t) >> 2), 0)) {
3090250661Sdavidcs                device_printf(dev, "%s: failed0\n", __func__);
3091250661Sdavidcs                return (-1);
3092250661Sdavidcs        }
3093250661Sdavidcs
3094284741Sdavidcs        map_rings_rsp = (q80_rsp_map_sds_to_rds_t *)ha->hw.mbox;
3095250661Sdavidcs
3096250661Sdavidcs        err = Q8_MBX_RSP_STATUS(map_rings_rsp->regcnt_status);
3097250661Sdavidcs
3098250661Sdavidcs        if (err) {
3099250661Sdavidcs                device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err);
3100250661Sdavidcs                return (-1);
3101250661Sdavidcs        }
3102250661Sdavidcs
3103250661Sdavidcs        return (0);
3104250661Sdavidcs}
3105250661Sdavidcs
3106250661Sdavidcs/*
3107250661Sdavidcs * Name: qla_init_rcv_cntxt
3108250661Sdavidcs * Function: Creates the Receive Context.
3109250661Sdavidcs */
3110250661Sdavidcsstatic int
3111250661Sdavidcsqla_init_rcv_cntxt(qla_host_t *ha)
3112250661Sdavidcs{
3113250661Sdavidcs	q80_rq_rcv_cntxt_t	*rcntxt;
3114250661Sdavidcs	q80_rsp_rcv_cntxt_t	*rcntxt_rsp;
3115250661Sdavidcs	q80_stat_desc_t		*sdesc;
3116250661Sdavidcs	int			i, j;
3117250661Sdavidcs        qla_hw_t		*hw = &ha->hw;
3118250661Sdavidcs	device_t		dev;
3119250661Sdavidcs	uint32_t		err;
3120250661Sdavidcs	uint32_t		rcntxt_sds_rings;
3121250661Sdavidcs	uint32_t		rcntxt_rds_rings;
3122284741Sdavidcs	uint32_t		max_idx;
3123250661Sdavidcs
3124250661Sdavidcs	dev = ha->pci_dev;
3125250661Sdavidcs
3126250661Sdavidcs	/*
3127250661Sdavidcs	 * Create Receive Context
3128250661Sdavidcs	 */
3129250661Sdavidcs
3130250661Sdavidcs	for (i = 0; i < hw->num_sds_rings; i++) {
3131250661Sdavidcs		sdesc = (q80_stat_desc_t *)&hw->sds[i].sds_ring_base[0];
3132250661Sdavidcs
3133250661Sdavidcs		for (j = 0; j < NUM_STATUS_DESCRIPTORS; j++) {
3134250661Sdavidcs			sdesc->data[0] = 1ULL;
3135250661Sdavidcs			sdesc->data[1] = 1ULL;
3136250661Sdavidcs		}
3137250661Sdavidcs	}
3138250661Sdavidcs
3139250661Sdavidcs	rcntxt_sds_rings = hw->num_sds_rings;
3140250661Sdavidcs	if (hw->num_sds_rings > MAX_RCNTXT_SDS_RINGS)
3141250661Sdavidcs		rcntxt_sds_rings = MAX_RCNTXT_SDS_RINGS;
3142250661Sdavidcs
3143250661Sdavidcs	rcntxt_rds_rings = hw->num_rds_rings;
3144250661Sdavidcs
3145250661Sdavidcs	if (hw->num_rds_rings > MAX_RDS_RING_SETS)
3146250661Sdavidcs		rcntxt_rds_rings = MAX_RDS_RING_SETS;
3147250661Sdavidcs
3148250661Sdavidcs	rcntxt = (q80_rq_rcv_cntxt_t *)ha->hw.mbox;
3149250661Sdavidcs	bzero(rcntxt, (sizeof (q80_rq_rcv_cntxt_t)));
3150250661Sdavidcs
3151250661Sdavidcs	rcntxt->opcode = Q8_MBX_CREATE_RX_CNTXT;
3152250661Sdavidcs	rcntxt->count_version = (sizeof (q80_rq_rcv_cntxt_t) >> 2);
3153250661Sdavidcs	rcntxt->count_version |= Q8_MBX_CMD_VERSION;
3154250661Sdavidcs
3155250661Sdavidcs	rcntxt->cap0 = Q8_RCV_CNTXT_CAP0_BASEFW |
3156250661Sdavidcs			Q8_RCV_CNTXT_CAP0_LRO |
3157250661Sdavidcs			Q8_RCV_CNTXT_CAP0_HW_LRO |
3158250661Sdavidcs			Q8_RCV_CNTXT_CAP0_RSS |
3159250661Sdavidcs			Q8_RCV_CNTXT_CAP0_SGL_LRO;
3160250661Sdavidcs
3161284741Sdavidcs	if (ha->hw.enable_9kb)
3162284741Sdavidcs		rcntxt->cap0 |= Q8_RCV_CNTXT_CAP0_SINGLE_JUMBO;
3163284741Sdavidcs	else
3164284741Sdavidcs		rcntxt->cap0 |= Q8_RCV_CNTXT_CAP0_SGL_JUMBO;
3165284741Sdavidcs
3166250661Sdavidcs	if (ha->hw.num_rds_rings > 1) {
3167250661Sdavidcs		rcntxt->nrds_sets_rings = rcntxt_rds_rings | (1 << 5);
3168250661Sdavidcs		rcntxt->cap0 |= Q8_RCV_CNTXT_CAP0_MULTI_RDS;
3169250661Sdavidcs	} else
3170250661Sdavidcs		rcntxt->nrds_sets_rings = 0x1 | (1 << 5);
3171250661Sdavidcs
3172250661Sdavidcs	rcntxt->nsds_rings = rcntxt_sds_rings;
3173250661Sdavidcs
3174250661Sdavidcs	rcntxt->rds_producer_mode = Q8_RCV_CNTXT_RDS_PROD_MODE_UNIQUE;
3175250661Sdavidcs
3176250661Sdavidcs	rcntxt->rcv_vpid = 0;
3177250661Sdavidcs
3178250661Sdavidcs	for (i = 0; i <  rcntxt_sds_rings; i++) {
3179250661Sdavidcs		rcntxt->sds[i].paddr =
3180250661Sdavidcs			qla_host_to_le64(hw->dma_buf.sds_ring[i].dma_addr);
3181250661Sdavidcs		rcntxt->sds[i].size =
3182250661Sdavidcs			qla_host_to_le32(NUM_STATUS_DESCRIPTORS);
3183313070Sdavidcs		rcntxt->sds[i].intr_id = qla_host_to_le16(hw->intr_id[i]);
3184313070Sdavidcs		rcntxt->sds[i].intr_src_bit = qla_host_to_le16(0);
3185250661Sdavidcs	}
3186250661Sdavidcs
3187250661Sdavidcs	for (i = 0; i <  rcntxt_rds_rings; i++) {
3188250661Sdavidcs		rcntxt->rds[i].paddr_std =
3189250661Sdavidcs			qla_host_to_le64(hw->dma_buf.rds_ring[i].dma_addr);
3190284741Sdavidcs
3191284741Sdavidcs		if (ha->hw.enable_9kb)
3192284741Sdavidcs			rcntxt->rds[i].std_bsize =
3193284741Sdavidcs				qla_host_to_le64(MJUM9BYTES);
3194284741Sdavidcs		else
3195284741Sdavidcs			rcntxt->rds[i].std_bsize = qla_host_to_le64(MCLBYTES);
3196284741Sdavidcs
3197250661Sdavidcs		rcntxt->rds[i].std_nentries =
3198250661Sdavidcs			qla_host_to_le32(NUM_RX_DESCRIPTORS);
3199250661Sdavidcs	}
3200250661Sdavidcs
3201250661Sdavidcs        if (qla_mbx_cmd(ha, (uint32_t *)rcntxt,
3202250661Sdavidcs		(sizeof (q80_rq_rcv_cntxt_t) >> 2),
3203250661Sdavidcs                ha->hw.mbox, (sizeof(q80_rsp_rcv_cntxt_t) >> 2), 0)) {
3204250661Sdavidcs                device_printf(dev, "%s: failed0\n", __func__);
3205250661Sdavidcs                return (-1);
3206250661Sdavidcs        }
3207250661Sdavidcs
3208250661Sdavidcs        rcntxt_rsp = (q80_rsp_rcv_cntxt_t *)ha->hw.mbox;
3209250661Sdavidcs
3210250661Sdavidcs        err = Q8_MBX_RSP_STATUS(rcntxt_rsp->regcnt_status);
3211250661Sdavidcs
3212250661Sdavidcs        if (err) {
3213250661Sdavidcs                device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err);
3214250661Sdavidcs                return (-1);
3215250661Sdavidcs        }
3216250661Sdavidcs
3217250661Sdavidcs	for (i = 0; i <  rcntxt_sds_rings; i++) {
3218250661Sdavidcs		hw->sds[i].sds_consumer = rcntxt_rsp->sds_cons[i];
3219250661Sdavidcs	}
3220250661Sdavidcs
3221250661Sdavidcs	for (i = 0; i <  rcntxt_rds_rings; i++) {
3222250661Sdavidcs		hw->rds[i].prod_std = rcntxt_rsp->rds[i].prod_std;
3223250661Sdavidcs	}
3224250661Sdavidcs
3225250661Sdavidcs	hw->rcv_cntxt_id = rcntxt_rsp->cntxt_id;
3226250661Sdavidcs
3227250661Sdavidcs	ha->hw.flags.init_rx_cnxt = 1;
3228250661Sdavidcs
3229250661Sdavidcs	if (hw->num_sds_rings > MAX_RCNTXT_SDS_RINGS) {
3230284741Sdavidcs
3231284741Sdavidcs		for (i = MAX_RCNTXT_SDS_RINGS; i < hw->num_sds_rings;) {
3232284741Sdavidcs
3233284741Sdavidcs			if ((i + MAX_RCNTXT_SDS_RINGS) < hw->num_sds_rings)
3234284741Sdavidcs				max_idx = MAX_RCNTXT_SDS_RINGS;
3235284741Sdavidcs			else
3236284741Sdavidcs				max_idx = hw->num_sds_rings - i;
3237284741Sdavidcs
3238284741Sdavidcs			err = qla_add_rcv_rings(ha, i, max_idx);
3239284741Sdavidcs			if (err)
3240284741Sdavidcs				return -1;
3241284741Sdavidcs
3242284741Sdavidcs			i += max_idx;
3243284741Sdavidcs		}
3244250661Sdavidcs	}
3245250661Sdavidcs
3246284741Sdavidcs	if (hw->num_rds_rings > 1) {
3247284741Sdavidcs
3248284741Sdavidcs		for (i = 0; i < hw->num_rds_rings; ) {
3249284741Sdavidcs
3250284741Sdavidcs			if ((i + MAX_SDS_TO_RDS_MAP) < hw->num_rds_rings)
3251284741Sdavidcs				max_idx = MAX_SDS_TO_RDS_MAP;
3252284741Sdavidcs			else
3253284741Sdavidcs				max_idx = hw->num_rds_rings - i;
3254284741Sdavidcs
3255284741Sdavidcs			err = qla_map_sds_to_rds(ha, i, max_idx);
3256284741Sdavidcs			if (err)
3257284741Sdavidcs				return -1;
3258284741Sdavidcs
3259284741Sdavidcs			i += max_idx;
3260284741Sdavidcs		}
3261250661Sdavidcs	}
3262250661Sdavidcs
3263250661Sdavidcs	return (0);
3264250661Sdavidcs}
3265250661Sdavidcs
3266250661Sdavidcsstatic int
3267284741Sdavidcsqla_add_rcv_rings(qla_host_t *ha, uint32_t sds_idx, uint32_t nsds)
3268250661Sdavidcs{
3269250661Sdavidcs	device_t		dev = ha->pci_dev;
3270250661Sdavidcs	q80_rq_add_rcv_rings_t	*add_rcv;
3271250661Sdavidcs	q80_rsp_add_rcv_rings_t	*add_rcv_rsp;
3272250661Sdavidcs	uint32_t		i,j, err;
3273250661Sdavidcs        qla_hw_t		*hw = &ha->hw;
3274250661Sdavidcs
3275250661Sdavidcs	add_rcv = (q80_rq_add_rcv_rings_t *)ha->hw.mbox;
3276250661Sdavidcs	bzero(add_rcv, sizeof (q80_rq_add_rcv_rings_t));
3277250661Sdavidcs
3278250661Sdavidcs	add_rcv->opcode = Q8_MBX_ADD_RX_RINGS;
3279250661Sdavidcs	add_rcv->count_version = (sizeof (q80_rq_add_rcv_rings_t) >> 2);
3280250661Sdavidcs	add_rcv->count_version |= Q8_MBX_CMD_VERSION;
3281250661Sdavidcs
3282284741Sdavidcs	add_rcv->nrds_sets_rings = nsds | (1 << 5);
3283250661Sdavidcs	add_rcv->nsds_rings = nsds;
3284250661Sdavidcs	add_rcv->cntxt_id = hw->rcv_cntxt_id;
3285250661Sdavidcs
3286250661Sdavidcs        for (i = 0; i <  nsds; i++) {
3287250661Sdavidcs
3288250661Sdavidcs		j = i + sds_idx;
3289250661Sdavidcs
3290250661Sdavidcs                add_rcv->sds[i].paddr =
3291250661Sdavidcs                        qla_host_to_le64(hw->dma_buf.sds_ring[j].dma_addr);
3292250661Sdavidcs
3293250661Sdavidcs                add_rcv->sds[i].size =
3294250661Sdavidcs                        qla_host_to_le32(NUM_STATUS_DESCRIPTORS);
3295250661Sdavidcs
3296313070Sdavidcs                add_rcv->sds[i].intr_id = qla_host_to_le16(hw->intr_id[j]);
3297313070Sdavidcs                add_rcv->sds[i].intr_src_bit = qla_host_to_le16(0);
3298250661Sdavidcs
3299250661Sdavidcs        }
3300313070Sdavidcs
3301284741Sdavidcs        for (i = 0; (i <  nsds); i++) {
3302250661Sdavidcs                j = i + sds_idx;
3303284741Sdavidcs
3304250661Sdavidcs                add_rcv->rds[i].paddr_std =
3305250661Sdavidcs                        qla_host_to_le64(hw->dma_buf.rds_ring[j].dma_addr);
3306284741Sdavidcs
3307284741Sdavidcs		if (ha->hw.enable_9kb)
3308284741Sdavidcs			add_rcv->rds[i].std_bsize =
3309284741Sdavidcs				qla_host_to_le64(MJUM9BYTES);
3310284741Sdavidcs		else
3311284741Sdavidcs                	add_rcv->rds[i].std_bsize = qla_host_to_le64(MCLBYTES);
3312284741Sdavidcs
3313250661Sdavidcs                add_rcv->rds[i].std_nentries =
3314250661Sdavidcs                        qla_host_to_le32(NUM_RX_DESCRIPTORS);
3315250661Sdavidcs        }
3316250661Sdavidcs
3317250661Sdavidcs
3318250661Sdavidcs        if (qla_mbx_cmd(ha, (uint32_t *)add_rcv,
3319250661Sdavidcs		(sizeof (q80_rq_add_rcv_rings_t) >> 2),
3320250661Sdavidcs                ha->hw.mbox, (sizeof(q80_rsp_add_rcv_rings_t) >> 2), 0)) {
3321250661Sdavidcs                device_printf(dev, "%s: failed0\n", __func__);
3322250661Sdavidcs                return (-1);
3323250661Sdavidcs        }
3324250661Sdavidcs
3325250661Sdavidcs        add_rcv_rsp = (q80_rsp_add_rcv_rings_t *)ha->hw.mbox;
3326250661Sdavidcs
3327250661Sdavidcs        err = Q8_MBX_RSP_STATUS(add_rcv_rsp->regcnt_status);
3328250661Sdavidcs
3329250661Sdavidcs        if (err) {
3330250661Sdavidcs                device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err);
3331250661Sdavidcs                return (-1);
3332250661Sdavidcs        }
3333250661Sdavidcs
3334284741Sdavidcs	for (i = 0; i < nsds; i++) {
3335284741Sdavidcs		hw->sds[(i + sds_idx)].sds_consumer = add_rcv_rsp->sds_cons[i];
3336250661Sdavidcs	}
3337284741Sdavidcs
3338284741Sdavidcs	for (i = 0; i < nsds; i++) {
3339284741Sdavidcs		hw->rds[(i + sds_idx)].prod_std = add_rcv_rsp->rds[i].prod_std;
3340250661Sdavidcs	}
3341284741Sdavidcs
3342250661Sdavidcs	return (0);
3343250661Sdavidcs}
3344250661Sdavidcs
3345250661Sdavidcs/*
3346250661Sdavidcs * Name: qla_del_rcv_cntxt
3347250661Sdavidcs * Function: Destroys the Receive Context.
3348250661Sdavidcs */
3349250661Sdavidcsstatic void
3350250661Sdavidcsqla_del_rcv_cntxt(qla_host_t *ha)
3351250661Sdavidcs{
3352250661Sdavidcs	device_t			dev = ha->pci_dev;
3353250661Sdavidcs	q80_rcv_cntxt_destroy_t		*rcntxt;
3354250661Sdavidcs	q80_rcv_cntxt_destroy_rsp_t	*rcntxt_rsp;
3355250661Sdavidcs	uint32_t			err;
3356250661Sdavidcs	uint8_t				bcast_mac[6];
3357250661Sdavidcs
3358250661Sdavidcs	if (!ha->hw.flags.init_rx_cnxt)
3359250661Sdavidcs		return;
3360250661Sdavidcs
3361250661Sdavidcs	if (qla_hw_del_all_mcast(ha))
3362250661Sdavidcs		return;
3363250661Sdavidcs
3364250661Sdavidcs	if (ha->hw.flags.bcast_mac) {
3365250661Sdavidcs
3366250661Sdavidcs		bcast_mac[0] = 0xFF; bcast_mac[1] = 0xFF; bcast_mac[2] = 0xFF;
3367250661Sdavidcs		bcast_mac[3] = 0xFF; bcast_mac[4] = 0xFF; bcast_mac[5] = 0xFF;
3368250661Sdavidcs
3369307524Sdavidcs		if (qla_config_mac_addr(ha, bcast_mac, 0, 1))
3370250661Sdavidcs			return;
3371250661Sdavidcs		ha->hw.flags.bcast_mac = 0;
3372250661Sdavidcs
3373250661Sdavidcs	}
3374250661Sdavidcs
3375250661Sdavidcs	if (ha->hw.flags.unicast_mac) {
3376307524Sdavidcs		if (qla_config_mac_addr(ha, ha->hw.mac_addr, 0, 1))
3377250661Sdavidcs			return;
3378250661Sdavidcs		ha->hw.flags.unicast_mac = 0;
3379250661Sdavidcs	}
3380250661Sdavidcs
3381250661Sdavidcs	rcntxt = (q80_rcv_cntxt_destroy_t *)ha->hw.mbox;
3382250661Sdavidcs	bzero(rcntxt, (sizeof (q80_rcv_cntxt_destroy_t)));
3383250661Sdavidcs
3384250661Sdavidcs	rcntxt->opcode = Q8_MBX_DESTROY_RX_CNTXT;
3385250661Sdavidcs	rcntxt->count_version = (sizeof (q80_rcv_cntxt_destroy_t) >> 2);
3386250661Sdavidcs	rcntxt->count_version |= Q8_MBX_CMD_VERSION;
3387250661Sdavidcs
3388250661Sdavidcs	rcntxt->cntxt_id = ha->hw.rcv_cntxt_id;
3389250661Sdavidcs
3390250661Sdavidcs        if (qla_mbx_cmd(ha, (uint32_t *)rcntxt,
3391250661Sdavidcs		(sizeof (q80_rcv_cntxt_destroy_t) >> 2),
3392250661Sdavidcs                ha->hw.mbox, (sizeof(q80_rcv_cntxt_destroy_rsp_t) >> 2), 0)) {
3393250661Sdavidcs                device_printf(dev, "%s: failed0\n", __func__);
3394250661Sdavidcs                return;
3395250661Sdavidcs        }
3396250661Sdavidcs        rcntxt_rsp = (q80_rcv_cntxt_destroy_rsp_t *)ha->hw.mbox;
3397250661Sdavidcs
3398250661Sdavidcs        err = Q8_MBX_RSP_STATUS(rcntxt_rsp->regcnt_status);
3399250661Sdavidcs
3400250661Sdavidcs        if (err) {
3401250661Sdavidcs                device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err);
3402250661Sdavidcs        }
3403250661Sdavidcs
3404250661Sdavidcs	ha->hw.flags.init_rx_cnxt = 0;
3405250661Sdavidcs	return;
3406250661Sdavidcs}
3407250661Sdavidcs
3408250661Sdavidcs/*
3409250661Sdavidcs * Name: qla_init_xmt_cntxt
3410250661Sdavidcs * Function: Creates the Transmit Context.
3411250661Sdavidcs */
3412250661Sdavidcsstatic int
3413250661Sdavidcsqla_init_xmt_cntxt_i(qla_host_t *ha, uint32_t txr_idx)
3414250661Sdavidcs{
3415250661Sdavidcs	device_t		dev;
3416250661Sdavidcs        qla_hw_t		*hw = &ha->hw;
3417250661Sdavidcs	q80_rq_tx_cntxt_t	*tcntxt;
3418250661Sdavidcs	q80_rsp_tx_cntxt_t	*tcntxt_rsp;
3419250661Sdavidcs	uint32_t		err;
3420250661Sdavidcs	qla_hw_tx_cntxt_t       *hw_tx_cntxt;
3421313070Sdavidcs	uint32_t		intr_idx;
3422250661Sdavidcs
3423250661Sdavidcs	hw_tx_cntxt = &hw->tx_cntxt[txr_idx];
3424250661Sdavidcs
3425250661Sdavidcs	dev = ha->pci_dev;
3426250661Sdavidcs
3427250661Sdavidcs	/*
3428250661Sdavidcs	 * Create Transmit Context
3429250661Sdavidcs	 */
3430250661Sdavidcs	tcntxt = (q80_rq_tx_cntxt_t *)ha->hw.mbox;
3431250661Sdavidcs	bzero(tcntxt, (sizeof (q80_rq_tx_cntxt_t)));
3432250661Sdavidcs
3433250661Sdavidcs	tcntxt->opcode = Q8_MBX_CREATE_TX_CNTXT;
3434250661Sdavidcs	tcntxt->count_version = (sizeof (q80_rq_tx_cntxt_t) >> 2);
3435250661Sdavidcs	tcntxt->count_version |= Q8_MBX_CMD_VERSION;
3436250661Sdavidcs
3437313070Sdavidcs	intr_idx = txr_idx;
3438313070Sdavidcs
3439284741Sdavidcs#ifdef QL_ENABLE_ISCSI_TLV
3440284741Sdavidcs
3441284741Sdavidcs	tcntxt->cap0 = Q8_TX_CNTXT_CAP0_BASEFW | Q8_TX_CNTXT_CAP0_LSO |
3442284741Sdavidcs				Q8_TX_CNTXT_CAP0_TC;
3443284741Sdavidcs
3444284741Sdavidcs	if (txr_idx >= (ha->hw.num_tx_rings >> 1)) {
3445284741Sdavidcs		tcntxt->traffic_class = 1;
3446284741Sdavidcs	}
3447284741Sdavidcs
3448313070Sdavidcs	intr_idx = txr_idx % (ha->hw.num_tx_rings >> 1);
3449313070Sdavidcs
3450284741Sdavidcs#else
3451250661Sdavidcs	tcntxt->cap0 = Q8_TX_CNTXT_CAP0_BASEFW | Q8_TX_CNTXT_CAP0_LSO;
3452250661Sdavidcs
3453284741Sdavidcs#endif /* #ifdef QL_ENABLE_ISCSI_TLV */
3454284741Sdavidcs
3455250661Sdavidcs	tcntxt->ntx_rings = 1;
3456250661Sdavidcs
3457250661Sdavidcs	tcntxt->tx_ring[0].paddr =
3458250661Sdavidcs		qla_host_to_le64(hw_tx_cntxt->tx_ring_paddr);
3459250661Sdavidcs	tcntxt->tx_ring[0].tx_consumer =
3460250661Sdavidcs		qla_host_to_le64(hw_tx_cntxt->tx_cons_paddr);
3461250661Sdavidcs	tcntxt->tx_ring[0].nentries = qla_host_to_le16(NUM_TX_DESCRIPTORS);
3462250661Sdavidcs
3463313070Sdavidcs	tcntxt->tx_ring[0].intr_id = qla_host_to_le16(hw->intr_id[intr_idx]);
3464250661Sdavidcs	tcntxt->tx_ring[0].intr_src_bit = qla_host_to_le16(0);
3465250661Sdavidcs
3466250661Sdavidcs	hw_tx_cntxt->txr_free = NUM_TX_DESCRIPTORS;
3467250661Sdavidcs	hw_tx_cntxt->txr_next = hw_tx_cntxt->txr_comp = 0;
3468324325Sdavidcs	*hw_tx_cntxt->tx_cons = 0;
3469250661Sdavidcs
3470250661Sdavidcs        if (qla_mbx_cmd(ha, (uint32_t *)tcntxt,
3471250661Sdavidcs		(sizeof (q80_rq_tx_cntxt_t) >> 2),
3472250661Sdavidcs                ha->hw.mbox,
3473250661Sdavidcs		(sizeof(q80_rsp_tx_cntxt_t) >> 2), 0)) {
3474250661Sdavidcs                device_printf(dev, "%s: failed0\n", __func__);
3475250661Sdavidcs                return (-1);
3476250661Sdavidcs        }
3477250661Sdavidcs        tcntxt_rsp = (q80_rsp_tx_cntxt_t *)ha->hw.mbox;
3478250661Sdavidcs
3479250661Sdavidcs        err = Q8_MBX_RSP_STATUS(tcntxt_rsp->regcnt_status);
3480250661Sdavidcs
3481250661Sdavidcs        if (err) {
3482250661Sdavidcs                device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err);
3483250661Sdavidcs		return -1;
3484250661Sdavidcs        }
3485250661Sdavidcs
3486250661Sdavidcs	hw_tx_cntxt->tx_prod_reg = tcntxt_rsp->tx_ring[0].prod_index;
3487250661Sdavidcs	hw_tx_cntxt->tx_cntxt_id = tcntxt_rsp->tx_ring[0].cntxt_id;
3488250661Sdavidcs
3489284741Sdavidcs	if (qla_config_intr_coalesce(ha, hw_tx_cntxt->tx_cntxt_id, 0, 0))
3490284741Sdavidcs		return (-1);
3491284741Sdavidcs
3492250661Sdavidcs	return (0);
3493250661Sdavidcs}
3494250661Sdavidcs
3495250661Sdavidcs
3496250661Sdavidcs/*
3497250661Sdavidcs * Name: qla_del_xmt_cntxt
3498250661Sdavidcs * Function: Destroys the Transmit Context.
3499250661Sdavidcs */
3500250661Sdavidcsstatic int
3501250661Sdavidcsqla_del_xmt_cntxt_i(qla_host_t *ha, uint32_t txr_idx)
3502250661Sdavidcs{
3503250661Sdavidcs	device_t			dev = ha->pci_dev;
3504250661Sdavidcs	q80_tx_cntxt_destroy_t		*tcntxt;
3505250661Sdavidcs	q80_tx_cntxt_destroy_rsp_t	*tcntxt_rsp;
3506250661Sdavidcs	uint32_t			err;
3507250661Sdavidcs
3508250661Sdavidcs	tcntxt = (q80_tx_cntxt_destroy_t *)ha->hw.mbox;
3509250661Sdavidcs	bzero(tcntxt, (sizeof (q80_tx_cntxt_destroy_t)));
3510250661Sdavidcs
3511250661Sdavidcs	tcntxt->opcode = Q8_MBX_DESTROY_TX_CNTXT;
3512250661Sdavidcs	tcntxt->count_version = (sizeof (q80_tx_cntxt_destroy_t) >> 2);
3513250661Sdavidcs	tcntxt->count_version |= Q8_MBX_CMD_VERSION;
3514250661Sdavidcs
3515250661Sdavidcs	tcntxt->cntxt_id = ha->hw.tx_cntxt[txr_idx].tx_cntxt_id;
3516250661Sdavidcs
3517250661Sdavidcs        if (qla_mbx_cmd(ha, (uint32_t *)tcntxt,
3518250661Sdavidcs		(sizeof (q80_tx_cntxt_destroy_t) >> 2),
3519250661Sdavidcs                ha->hw.mbox, (sizeof (q80_tx_cntxt_destroy_rsp_t) >> 2), 0)) {
3520250661Sdavidcs                device_printf(dev, "%s: failed0\n", __func__);
3521250661Sdavidcs                return (-1);
3522250661Sdavidcs        }
3523250661Sdavidcs        tcntxt_rsp = (q80_tx_cntxt_destroy_rsp_t *)ha->hw.mbox;
3524250661Sdavidcs
3525250661Sdavidcs        err = Q8_MBX_RSP_STATUS(tcntxt_rsp->regcnt_status);
3526250661Sdavidcs
3527250661Sdavidcs        if (err) {
3528250661Sdavidcs                device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err);
3529250661Sdavidcs		return (-1);
3530250661Sdavidcs        }
3531250661Sdavidcs
3532250661Sdavidcs	return (0);
3533250661Sdavidcs}
3534330555Sdavidcsstatic int
3535250661Sdavidcsqla_del_xmt_cntxt(qla_host_t *ha)
3536250661Sdavidcs{
3537250661Sdavidcs	uint32_t i;
3538330555Sdavidcs	int ret = 0;
3539250661Sdavidcs
3540250661Sdavidcs	if (!ha->hw.flags.init_tx_cnxt)
3541330555Sdavidcs		return (ret);
3542250661Sdavidcs
3543250661Sdavidcs	for (i = 0; i < ha->hw.num_tx_rings; i++) {
3544330555Sdavidcs		if ((ret = qla_del_xmt_cntxt_i(ha, i)) != 0)
3545250661Sdavidcs			break;
3546250661Sdavidcs	}
3547250661Sdavidcs	ha->hw.flags.init_tx_cnxt = 0;
3548330555Sdavidcs
3549330555Sdavidcs	return (ret);
3550250661Sdavidcs}
3551250661Sdavidcs
3552250661Sdavidcsstatic int
3553250661Sdavidcsqla_init_xmt_cntxt(qla_host_t *ha)
3554250661Sdavidcs{
3555250661Sdavidcs	uint32_t i, j;
3556250661Sdavidcs
3557250661Sdavidcs	for (i = 0; i < ha->hw.num_tx_rings; i++) {
3558250661Sdavidcs		if (qla_init_xmt_cntxt_i(ha, i) != 0) {
3559330555Sdavidcs			for (j = 0; j < i; j++) {
3560330555Sdavidcs				if (qla_del_xmt_cntxt_i(ha, j))
3561330555Sdavidcs					break;
3562330555Sdavidcs			}
3563250661Sdavidcs			return (-1);
3564250661Sdavidcs		}
3565250661Sdavidcs	}
3566250661Sdavidcs	ha->hw.flags.init_tx_cnxt = 1;
3567250661Sdavidcs	return (0);
3568250661Sdavidcs}
3569250661Sdavidcs
3570250661Sdavidcsstatic int
3571307524Sdavidcsqla_hw_all_mcast(qla_host_t *ha, uint32_t add_mcast)
3572250661Sdavidcs{
3573250661Sdavidcs	int i, nmcast;
3574307524Sdavidcs	uint32_t count = 0;
3575307524Sdavidcs	uint8_t *mcast;
3576250661Sdavidcs
3577250661Sdavidcs	nmcast = ha->hw.nmcast;
3578250661Sdavidcs
3579307524Sdavidcs	QL_DPRINT2(ha, (ha->pci_dev,
3580307524Sdavidcs		"%s:[0x%x] enter nmcast = %d \n", __func__, add_mcast, nmcast));
3581307524Sdavidcs
3582307524Sdavidcs	mcast = ha->hw.mac_addr_arr;
3583307524Sdavidcs	memset(mcast, 0, (Q8_MAX_MAC_ADDRS * ETHER_ADDR_LEN));
3584307524Sdavidcs
3585250661Sdavidcs	for (i = 0 ; ((i < Q8_MAX_NUM_MULTICAST_ADDRS) && nmcast); i++) {
3586250661Sdavidcs		if ((ha->hw.mcast[i].addr[0] != 0) ||
3587250661Sdavidcs			(ha->hw.mcast[i].addr[1] != 0) ||
3588250661Sdavidcs			(ha->hw.mcast[i].addr[2] != 0) ||
3589250661Sdavidcs			(ha->hw.mcast[i].addr[3] != 0) ||
3590250661Sdavidcs			(ha->hw.mcast[i].addr[4] != 0) ||
3591250661Sdavidcs			(ha->hw.mcast[i].addr[5] != 0)) {
3592250661Sdavidcs
3593307524Sdavidcs			bcopy(ha->hw.mcast[i].addr, mcast, ETHER_ADDR_LEN);
3594307524Sdavidcs			mcast = mcast + ETHER_ADDR_LEN;
3595307524Sdavidcs			count++;
3596332052Sdavidcs
3597332052Sdavidcs			device_printf(ha->pci_dev,
3598332052Sdavidcs				"%s: %x:%x:%x:%x:%x:%x \n",
3599332052Sdavidcs				__func__, ha->hw.mcast[i].addr[0],
3600332052Sdavidcs				ha->hw.mcast[i].addr[1], ha->hw.mcast[i].addr[2],
3601332052Sdavidcs				ha->hw.mcast[i].addr[3], ha->hw.mcast[i].addr[4],
3602332052Sdavidcs				ha->hw.mcast[i].addr[5]);
3603307524Sdavidcs
3604307524Sdavidcs			if (count == Q8_MAX_MAC_ADDRS) {
3605307524Sdavidcs				if (qla_config_mac_addr(ha, ha->hw.mac_addr_arr,
3606307524Sdavidcs					add_mcast, count)) {
3607307524Sdavidcs                			device_printf(ha->pci_dev,
3608307524Sdavidcs						"%s: failed\n", __func__);
3609307524Sdavidcs					return (-1);
3610307524Sdavidcs				}
3611307524Sdavidcs
3612307524Sdavidcs				count = 0;
3613307524Sdavidcs				mcast = ha->hw.mac_addr_arr;
3614307524Sdavidcs				memset(mcast, 0,
3615307524Sdavidcs					(Q8_MAX_MAC_ADDRS * ETHER_ADDR_LEN));
3616250661Sdavidcs			}
3617250661Sdavidcs
3618250661Sdavidcs			nmcast--;
3619250661Sdavidcs		}
3620250661Sdavidcs	}
3621307524Sdavidcs
3622307524Sdavidcs	if (count) {
3623307524Sdavidcs		if (qla_config_mac_addr(ha, ha->hw.mac_addr_arr, add_mcast,
3624307524Sdavidcs			count)) {
3625307524Sdavidcs                	device_printf(ha->pci_dev, "%s: failed\n", __func__);
3626307524Sdavidcs			return (-1);
3627307524Sdavidcs		}
3628307524Sdavidcs	}
3629307524Sdavidcs	QL_DPRINT2(ha, (ha->pci_dev,
3630307524Sdavidcs		"%s:[0x%x] exit nmcast = %d \n", __func__, add_mcast, nmcast));
3631307524Sdavidcs
3632250661Sdavidcs	return 0;
3633250661Sdavidcs}
3634250661Sdavidcs
3635250661Sdavidcsstatic int
3636307524Sdavidcsqla_hw_add_all_mcast(qla_host_t *ha)
3637307524Sdavidcs{
3638307524Sdavidcs	int ret;
3639307524Sdavidcs
3640307524Sdavidcs	ret = qla_hw_all_mcast(ha, 1);
3641307524Sdavidcs
3642307524Sdavidcs	return (ret);
3643307524Sdavidcs}
3644307524Sdavidcs
3645324324Sdavidcsint
3646250661Sdavidcsqla_hw_del_all_mcast(qla_host_t *ha)
3647250661Sdavidcs{
3648307524Sdavidcs	int ret;
3649250661Sdavidcs
3650307524Sdavidcs	ret = qla_hw_all_mcast(ha, 0);
3651250661Sdavidcs
3652307524Sdavidcs	bzero(ha->hw.mcast, (sizeof (qla_mcast_t) * Q8_MAX_NUM_MULTICAST_ADDRS));
3653307524Sdavidcs	ha->hw.nmcast = 0;
3654250661Sdavidcs
3655307524Sdavidcs	return (ret);
3656250661Sdavidcs}
3657250661Sdavidcs
3658250661Sdavidcsstatic int
3659307524Sdavidcsqla_hw_mac_addr_present(qla_host_t *ha, uint8_t *mta)
3660250661Sdavidcs{
3661250661Sdavidcs	int i;
3662250661Sdavidcs
3663250661Sdavidcs	for (i = 0; i < Q8_MAX_NUM_MULTICAST_ADDRS; i++) {
3664250661Sdavidcs		if (QL_MAC_CMP(ha->hw.mcast[i].addr, mta) == 0)
3665307524Sdavidcs			return (0); /* its been already added */
3666250661Sdavidcs	}
3667307524Sdavidcs	return (-1);
3668307524Sdavidcs}
3669250661Sdavidcs
3670307524Sdavidcsstatic int
3671307524Sdavidcsqla_hw_add_mcast(qla_host_t *ha, uint8_t *mta, uint32_t nmcast)
3672307524Sdavidcs{
3673307524Sdavidcs	int i;
3674307524Sdavidcs
3675250661Sdavidcs	for (i = 0; i < Q8_MAX_NUM_MULTICAST_ADDRS; i++) {
3676250661Sdavidcs
3677250661Sdavidcs		if ((ha->hw.mcast[i].addr[0] == 0) &&
3678250661Sdavidcs			(ha->hw.mcast[i].addr[1] == 0) &&
3679250661Sdavidcs			(ha->hw.mcast[i].addr[2] == 0) &&
3680250661Sdavidcs			(ha->hw.mcast[i].addr[3] == 0) &&
3681250661Sdavidcs			(ha->hw.mcast[i].addr[4] == 0) &&
3682250661Sdavidcs			(ha->hw.mcast[i].addr[5] == 0)) {
3683250661Sdavidcs
3684250661Sdavidcs			bcopy(mta, ha->hw.mcast[i].addr, Q8_MAC_ADDR_LEN);
3685250661Sdavidcs			ha->hw.nmcast++;
3686250661Sdavidcs
3687307524Sdavidcs			mta = mta + ETHER_ADDR_LEN;
3688307524Sdavidcs			nmcast--;
3689307524Sdavidcs
3690307524Sdavidcs			if (nmcast == 0)
3691307524Sdavidcs				break;
3692250661Sdavidcs		}
3693307524Sdavidcs
3694250661Sdavidcs	}
3695250661Sdavidcs	return 0;
3696250661Sdavidcs}
3697250661Sdavidcs
3698250661Sdavidcsstatic int
3699307524Sdavidcsqla_hw_del_mcast(qla_host_t *ha, uint8_t *mta, uint32_t nmcast)
3700250661Sdavidcs{
3701250661Sdavidcs	int i;
3702250661Sdavidcs
3703250661Sdavidcs	for (i = 0; i < Q8_MAX_NUM_MULTICAST_ADDRS; i++) {
3704250661Sdavidcs		if (QL_MAC_CMP(ha->hw.mcast[i].addr, mta) == 0) {
3705250661Sdavidcs
3706250661Sdavidcs			ha->hw.mcast[i].addr[0] = 0;
3707250661Sdavidcs			ha->hw.mcast[i].addr[1] = 0;
3708250661Sdavidcs			ha->hw.mcast[i].addr[2] = 0;
3709250661Sdavidcs			ha->hw.mcast[i].addr[3] = 0;
3710250661Sdavidcs			ha->hw.mcast[i].addr[4] = 0;
3711250661Sdavidcs			ha->hw.mcast[i].addr[5] = 0;
3712250661Sdavidcs
3713250661Sdavidcs			ha->hw.nmcast--;
3714250661Sdavidcs
3715307524Sdavidcs			mta = mta + ETHER_ADDR_LEN;
3716307524Sdavidcs			nmcast--;
3717307524Sdavidcs
3718307524Sdavidcs			if (nmcast == 0)
3719307524Sdavidcs				break;
3720250661Sdavidcs		}
3721250661Sdavidcs	}
3722250661Sdavidcs	return 0;
3723250661Sdavidcs}
3724250661Sdavidcs
3725250661Sdavidcs/*
3726250661Sdavidcs * Name: ql_hw_set_multi
3727307524Sdavidcs * Function: Sets the Multicast Addresses provided by the host O.S into the
3728250661Sdavidcs *	hardware (for the given interface)
3729250661Sdavidcs */
3730250661Sdavidcsint
3731307524Sdavidcsql_hw_set_multi(qla_host_t *ha, uint8_t *mcast_addr, uint32_t mcnt,
3732250661Sdavidcs	uint32_t add_mac)
3733250661Sdavidcs{
3734307524Sdavidcs	uint8_t *mta = mcast_addr;
3735250661Sdavidcs	int i;
3736250661Sdavidcs	int ret = 0;
3737307524Sdavidcs	uint32_t count = 0;
3738307524Sdavidcs	uint8_t *mcast;
3739250661Sdavidcs
3740307524Sdavidcs	mcast = ha->hw.mac_addr_arr;
3741307524Sdavidcs	memset(mcast, 0, (Q8_MAX_MAC_ADDRS * ETHER_ADDR_LEN));
3742307524Sdavidcs
3743250661Sdavidcs	for (i = 0; i < mcnt; i++) {
3744307524Sdavidcs		if (mta[0] || mta[1] || mta[2] || mta[3] || mta[4] || mta[5]) {
3745307524Sdavidcs			if (add_mac) {
3746307524Sdavidcs				if (qla_hw_mac_addr_present(ha, mta) != 0) {
3747307524Sdavidcs					bcopy(mta, mcast, ETHER_ADDR_LEN);
3748307524Sdavidcs					mcast = mcast + ETHER_ADDR_LEN;
3749307524Sdavidcs					count++;
3750307524Sdavidcs				}
3751307524Sdavidcs			} else {
3752307524Sdavidcs				if (qla_hw_mac_addr_present(ha, mta) == 0) {
3753307524Sdavidcs					bcopy(mta, mcast, ETHER_ADDR_LEN);
3754307524Sdavidcs					mcast = mcast + ETHER_ADDR_LEN;
3755307524Sdavidcs					count++;
3756307524Sdavidcs				}
3757307524Sdavidcs			}
3758250661Sdavidcs		}
3759307524Sdavidcs		if (count == Q8_MAX_MAC_ADDRS) {
3760307524Sdavidcs			if (qla_config_mac_addr(ha, ha->hw.mac_addr_arr,
3761307524Sdavidcs				add_mac, count)) {
3762307524Sdavidcs                		device_printf(ha->pci_dev, "%s: failed\n",
3763307524Sdavidcs					__func__);
3764307524Sdavidcs				return (-1);
3765307524Sdavidcs			}
3766307524Sdavidcs
3767307524Sdavidcs			if (add_mac) {
3768307524Sdavidcs				qla_hw_add_mcast(ha, ha->hw.mac_addr_arr,
3769307524Sdavidcs					count);
3770307524Sdavidcs			} else {
3771307524Sdavidcs				qla_hw_del_mcast(ha, ha->hw.mac_addr_arr,
3772307524Sdavidcs					count);
3773307524Sdavidcs			}
3774307524Sdavidcs
3775307524Sdavidcs			count = 0;
3776307524Sdavidcs			mcast = ha->hw.mac_addr_arr;
3777307524Sdavidcs			memset(mcast, 0, (Q8_MAX_MAC_ADDRS * ETHER_ADDR_LEN));
3778307524Sdavidcs		}
3779250661Sdavidcs
3780250661Sdavidcs		mta += Q8_MAC_ADDR_LEN;
3781250661Sdavidcs	}
3782307524Sdavidcs
3783307524Sdavidcs	if (count) {
3784307524Sdavidcs		if (qla_config_mac_addr(ha, ha->hw.mac_addr_arr, add_mac,
3785307524Sdavidcs			count)) {
3786307524Sdavidcs                	device_printf(ha->pci_dev, "%s: failed\n", __func__);
3787307524Sdavidcs			return (-1);
3788307524Sdavidcs		}
3789307524Sdavidcs		if (add_mac) {
3790307524Sdavidcs			qla_hw_add_mcast(ha, ha->hw.mac_addr_arr, count);
3791307524Sdavidcs		} else {
3792307524Sdavidcs			qla_hw_del_mcast(ha, ha->hw.mac_addr_arr, count);
3793307524Sdavidcs		}
3794307524Sdavidcs	}
3795307524Sdavidcs
3796250661Sdavidcs	return (ret);
3797250661Sdavidcs}
3798250661Sdavidcs
3799250661Sdavidcs/*
3800313070Sdavidcs * Name: ql_hw_tx_done_locked
3801250661Sdavidcs * Function: Handle Transmit Completions
3802250661Sdavidcs */
3803313070Sdavidcsvoid
3804313070Sdavidcsql_hw_tx_done_locked(qla_host_t *ha, uint32_t txr_idx)
3805250661Sdavidcs{
3806250661Sdavidcs	qla_tx_buf_t *txb;
3807250661Sdavidcs        qla_hw_t *hw = &ha->hw;
3808250661Sdavidcs	uint32_t comp_idx, comp_count = 0;
3809250661Sdavidcs	qla_hw_tx_cntxt_t *hw_tx_cntxt;
3810250661Sdavidcs
3811250661Sdavidcs	hw_tx_cntxt = &hw->tx_cntxt[txr_idx];
3812250661Sdavidcs
3813250661Sdavidcs	/* retrieve index of last entry in tx ring completed */
3814250661Sdavidcs	comp_idx = qla_le32_to_host(*(hw_tx_cntxt->tx_cons));
3815250661Sdavidcs
3816250661Sdavidcs	while (comp_idx != hw_tx_cntxt->txr_comp) {
3817250661Sdavidcs
3818250661Sdavidcs		txb = &ha->tx_ring[txr_idx].tx_buf[hw_tx_cntxt->txr_comp];
3819250661Sdavidcs
3820250661Sdavidcs		hw_tx_cntxt->txr_comp++;
3821250661Sdavidcs		if (hw_tx_cntxt->txr_comp == NUM_TX_DESCRIPTORS)
3822250661Sdavidcs			hw_tx_cntxt->txr_comp = 0;
3823250661Sdavidcs
3824250661Sdavidcs		comp_count++;
3825250661Sdavidcs
3826250661Sdavidcs		if (txb->m_head) {
3827271849Sglebius			if_inc_counter(ha->ifp, IFCOUNTER_OPACKETS, 1);
3828250661Sdavidcs
3829250661Sdavidcs			bus_dmamap_sync(ha->tx_tag, txb->map,
3830250661Sdavidcs				BUS_DMASYNC_POSTWRITE);
3831250661Sdavidcs			bus_dmamap_unload(ha->tx_tag, txb->map);
3832250661Sdavidcs			m_freem(txb->m_head);
3833250661Sdavidcs
3834250661Sdavidcs			txb->m_head = NULL;
3835250661Sdavidcs		}
3836250661Sdavidcs	}
3837250661Sdavidcs
3838250661Sdavidcs	hw_tx_cntxt->txr_free += comp_count;
3839332052Sdavidcs
3840332052Sdavidcs	if (hw_tx_cntxt->txr_free > NUM_TX_DESCRIPTORS)
3841332052Sdavidcs		device_printf(ha->pci_dev, "%s [%d]: txr_idx = %d txr_free = %d"
3842332052Sdavidcs			"txr_next = %d txr_comp = %d\n", __func__, __LINE__,
3843332052Sdavidcs			txr_idx, hw_tx_cntxt->txr_free,
3844332052Sdavidcs			hw_tx_cntxt->txr_next, hw_tx_cntxt->txr_comp);
3845332052Sdavidcs
3846332052Sdavidcs	QL_ASSERT(ha, (hw_tx_cntxt->txr_free <= NUM_TX_DESCRIPTORS), \
3847332052Sdavidcs		("%s [%d]: txr_idx = %d txr_free = %d txr_next = %d txr_comp = %d\n",\
3848332052Sdavidcs		__func__, __LINE__, txr_idx, hw_tx_cntxt->txr_free, \
3849332052Sdavidcs		hw_tx_cntxt->txr_next, hw_tx_cntxt->txr_comp));
3850332052Sdavidcs
3851250661Sdavidcs	return;
3852250661Sdavidcs}
3853250661Sdavidcs
3854250661Sdavidcsvoid
3855250661Sdavidcsql_update_link_state(qla_host_t *ha)
3856250661Sdavidcs{
3857330555Sdavidcs	uint32_t link_state = 0;
3858250661Sdavidcs	uint32_t prev_link_state;
3859250661Sdavidcs
3860330555Sdavidcs	prev_link_state =  ha->hw.link_up;
3861330555Sdavidcs
3862330555Sdavidcs	if (ha->ifp->if_drv_flags & IFF_DRV_RUNNING) {
3863330555Sdavidcs		link_state = READ_REG32(ha, Q8_LINK_STATE);
3864330555Sdavidcs
3865330555Sdavidcs		if (ha->pci_func == 0) {
3866330555Sdavidcs			link_state = (((link_state & 0xF) == 1)? 1 : 0);
3867330555Sdavidcs		} else {
3868330555Sdavidcs			link_state = ((((link_state >> 4)& 0xF) == 1)? 1 : 0);
3869330555Sdavidcs		}
3870250661Sdavidcs	}
3871250661Sdavidcs
3872330555Sdavidcs	atomic_store_rel_8(&ha->hw.link_up, (uint8_t)link_state);
3873250661Sdavidcs
3874250661Sdavidcs	if (prev_link_state !=  ha->hw.link_up) {
3875250661Sdavidcs		if (ha->hw.link_up) {
3876250661Sdavidcs			if_link_state_change(ha->ifp, LINK_STATE_UP);
3877250661Sdavidcs		} else {
3878250661Sdavidcs			if_link_state_change(ha->ifp, LINK_STATE_DOWN);
3879250661Sdavidcs		}
3880250661Sdavidcs	}
3881250661Sdavidcs	return;
3882250661Sdavidcs}
3883250661Sdavidcs
3884250661Sdavidcsint
3885250661Sdavidcsql_hw_check_health(qla_host_t *ha)
3886250661Sdavidcs{
3887250661Sdavidcs	uint32_t val;
3888250661Sdavidcs
3889250661Sdavidcs	ha->hw.health_count++;
3890250661Sdavidcs
3891321496Sdavidcs	if (ha->hw.health_count < 500)
3892250661Sdavidcs		return 0;
3893250661Sdavidcs
3894250661Sdavidcs	ha->hw.health_count = 0;
3895250661Sdavidcs
3896250661Sdavidcs	val = READ_REG32(ha, Q8_ASIC_TEMPERATURE);
3897250661Sdavidcs
3898250661Sdavidcs	if (((val & 0xFFFF) == 2) || ((val & 0xFFFF) == 3) ||
3899250661Sdavidcs		(QL_ERR_INJECT(ha, INJCT_TEMPERATURE_FAILURE))) {
3900330555Sdavidcs		device_printf(ha->pci_dev, "%s: Temperature Alert"
3901330555Sdavidcs			" at ts_usecs %ld ts_reg = 0x%08x\n",
3902330555Sdavidcs			__func__, qla_get_usec_timestamp(), val);
3903330555Sdavidcs
3904330555Sdavidcs		if (ha->hw.sp_log_stop_events & Q8_SP_LOG_STOP_TEMP_FAILURE)
3905330555Sdavidcs			ha->hw.sp_log_stop = -1;
3906330555Sdavidcs
3907330555Sdavidcs		QL_INITIATE_RECOVERY(ha);
3908250661Sdavidcs		return -1;
3909250661Sdavidcs	}
3910250661Sdavidcs
3911250661Sdavidcs	val = READ_REG32(ha, Q8_FIRMWARE_HEARTBEAT);
3912250661Sdavidcs
3913250661Sdavidcs	if ((val != ha->hw.hbeat_value) &&
3914289635Sdavidcs		(!(QL_ERR_INJECT(ha, INJCT_HEARTBEAT_FAILURE)))) {
3915250661Sdavidcs		ha->hw.hbeat_value = val;
3916321496Sdavidcs		ha->hw.hbeat_failure = 0;
3917250661Sdavidcs		return 0;
3918250661Sdavidcs	}
3919250661Sdavidcs
3920321496Sdavidcs	ha->hw.hbeat_failure++;
3921321496Sdavidcs
3922322972Sdavidcs
3923322972Sdavidcs	if ((ha->dbg_level & 0x8000) && (ha->hw.hbeat_failure == 1))
3924322972Sdavidcs		device_printf(ha->pci_dev, "%s: Heartbeat Failue 1[0x%08x]\n",
3925322972Sdavidcs			__func__, val);
3926321496Sdavidcs	if (ha->hw.hbeat_failure < 2) /* we ignore the first failure */
3927321496Sdavidcs		return 0;
3928330555Sdavidcs	else {
3929330555Sdavidcs		uint32_t peg_halt_status1;
3930330555Sdavidcs		uint32_t peg_halt_status2;
3931321496Sdavidcs
3932330555Sdavidcs		peg_halt_status1 = READ_REG32(ha, Q8_PEG_HALT_STATUS1);
3933330555Sdavidcs		peg_halt_status2 = READ_REG32(ha, Q8_PEG_HALT_STATUS2);
3934330555Sdavidcs
3935330555Sdavidcs		device_printf(ha->pci_dev,
3936330555Sdavidcs			"%s: Heartbeat Failue at ts_usecs = %ld "
3937330555Sdavidcs			"fw_heart_beat = 0x%08x "
3938330555Sdavidcs			"peg_halt_status1 = 0x%08x "
3939330555Sdavidcs			"peg_halt_status2 = 0x%08x\n",
3940330555Sdavidcs			__func__, qla_get_usec_timestamp(), val,
3941330555Sdavidcs			peg_halt_status1, peg_halt_status2);
3942330555Sdavidcs
3943330555Sdavidcs		if (ha->hw.sp_log_stop_events & Q8_SP_LOG_STOP_HBEAT_FAILURE)
3944330555Sdavidcs			ha->hw.sp_log_stop = -1;
3945330555Sdavidcs	}
3946330555Sdavidcs	QL_INITIATE_RECOVERY(ha);
3947330555Sdavidcs
3948250661Sdavidcs	return -1;
3949250661Sdavidcs}
3950250661Sdavidcs
3951250661Sdavidcsstatic int
3952284741Sdavidcsqla_init_nic_func(qla_host_t *ha)
3953284741Sdavidcs{
3954284741Sdavidcs        device_t                dev;
3955284741Sdavidcs        q80_init_nic_func_t     *init_nic;
3956284741Sdavidcs        q80_init_nic_func_rsp_t *init_nic_rsp;
3957284741Sdavidcs        uint32_t                err;
3958284741Sdavidcs
3959284741Sdavidcs        dev = ha->pci_dev;
3960284741Sdavidcs
3961284741Sdavidcs        init_nic = (q80_init_nic_func_t *)ha->hw.mbox;
3962284741Sdavidcs        bzero(init_nic, sizeof(q80_init_nic_func_t));
3963284741Sdavidcs
3964284741Sdavidcs        init_nic->opcode = Q8_MBX_INIT_NIC_FUNC;
3965284741Sdavidcs        init_nic->count_version = (sizeof (q80_init_nic_func_t) >> 2);
3966284741Sdavidcs        init_nic->count_version |= Q8_MBX_CMD_VERSION;
3967284741Sdavidcs
3968284741Sdavidcs        init_nic->options = Q8_INIT_NIC_REG_DCBX_CHNG_AEN;
3969284741Sdavidcs        init_nic->options |= Q8_INIT_NIC_REG_SFP_CHNG_AEN;
3970284741Sdavidcs        init_nic->options |= Q8_INIT_NIC_REG_IDC_AEN;
3971284741Sdavidcs
3972284741Sdavidcs//qla_dump_buf8(ha, __func__, init_nic, sizeof (q80_init_nic_func_t));
3973284741Sdavidcs        if (qla_mbx_cmd(ha, (uint32_t *)init_nic,
3974284741Sdavidcs                (sizeof (q80_init_nic_func_t) >> 2),
3975284741Sdavidcs                ha->hw.mbox, (sizeof (q80_init_nic_func_rsp_t) >> 2), 0)) {
3976284741Sdavidcs                device_printf(dev, "%s: failed\n", __func__);
3977284741Sdavidcs                return -1;
3978284741Sdavidcs        }
3979284741Sdavidcs
3980284741Sdavidcs        init_nic_rsp = (q80_init_nic_func_rsp_t *)ha->hw.mbox;
3981284741Sdavidcs// qla_dump_buf8(ha, __func__, init_nic_rsp, sizeof (q80_init_nic_func_rsp_t));
3982284741Sdavidcs
3983284741Sdavidcs        err = Q8_MBX_RSP_STATUS(init_nic_rsp->regcnt_status);
3984284741Sdavidcs
3985284741Sdavidcs        if (err) {
3986284741Sdavidcs                device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
3987332052Sdavidcs        } else {
3988332052Sdavidcs                device_printf(dev, "%s: successful\n", __func__);
3989332052Sdavidcs	}
3990284741Sdavidcs
3991284741Sdavidcs        return 0;
3992284741Sdavidcs}
3993284741Sdavidcs
3994284741Sdavidcsstatic int
3995284741Sdavidcsqla_stop_nic_func(qla_host_t *ha)
3996284741Sdavidcs{
3997284741Sdavidcs        device_t                dev;
3998284741Sdavidcs        q80_stop_nic_func_t     *stop_nic;
3999284741Sdavidcs        q80_stop_nic_func_rsp_t *stop_nic_rsp;
4000284741Sdavidcs        uint32_t                err;
4001284741Sdavidcs
4002284741Sdavidcs        dev = ha->pci_dev;
4003284741Sdavidcs
4004284741Sdavidcs        stop_nic = (q80_stop_nic_func_t *)ha->hw.mbox;
4005284741Sdavidcs        bzero(stop_nic, sizeof(q80_stop_nic_func_t));
4006284741Sdavidcs
4007284741Sdavidcs        stop_nic->opcode = Q8_MBX_STOP_NIC_FUNC;
4008284741Sdavidcs        stop_nic->count_version = (sizeof (q80_stop_nic_func_t) >> 2);
4009284741Sdavidcs        stop_nic->count_version |= Q8_MBX_CMD_VERSION;
4010284741Sdavidcs
4011284741Sdavidcs        stop_nic->options = Q8_STOP_NIC_DEREG_DCBX_CHNG_AEN;
4012284741Sdavidcs        stop_nic->options |= Q8_STOP_NIC_DEREG_SFP_CHNG_AEN;
4013284741Sdavidcs
4014284741Sdavidcs//qla_dump_buf8(ha, __func__, stop_nic, sizeof (q80_stop_nic_func_t));
4015284741Sdavidcs        if (qla_mbx_cmd(ha, (uint32_t *)stop_nic,
4016284741Sdavidcs                (sizeof (q80_stop_nic_func_t) >> 2),
4017284741Sdavidcs                ha->hw.mbox, (sizeof (q80_stop_nic_func_rsp_t) >> 2), 0)) {
4018284741Sdavidcs                device_printf(dev, "%s: failed\n", __func__);
4019284741Sdavidcs                return -1;
4020284741Sdavidcs        }
4021284741Sdavidcs
4022284741Sdavidcs        stop_nic_rsp = (q80_stop_nic_func_rsp_t *)ha->hw.mbox;
4023284741Sdavidcs//qla_dump_buf8(ha, __func__, stop_nic_rsp, sizeof (q80_stop_nic_func_rsp_ t));
4024284741Sdavidcs
4025284741Sdavidcs        err = Q8_MBX_RSP_STATUS(stop_nic_rsp->regcnt_status);
4026284741Sdavidcs
4027284741Sdavidcs        if (err) {
4028284741Sdavidcs                device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
4029284741Sdavidcs        }
4030284741Sdavidcs
4031284741Sdavidcs        return 0;
4032284741Sdavidcs}
4033284741Sdavidcs
4034284741Sdavidcsstatic int
4035284741Sdavidcsqla_query_fw_dcbx_caps(qla_host_t *ha)
4036284741Sdavidcs{
4037284741Sdavidcs        device_t                        dev;
4038284741Sdavidcs        q80_query_fw_dcbx_caps_t        *fw_dcbx;
4039284741Sdavidcs        q80_query_fw_dcbx_caps_rsp_t    *fw_dcbx_rsp;
4040284741Sdavidcs        uint32_t                        err;
4041284741Sdavidcs
4042284741Sdavidcs        dev = ha->pci_dev;
4043284741Sdavidcs
4044284741Sdavidcs        fw_dcbx = (q80_query_fw_dcbx_caps_t *)ha->hw.mbox;
4045284741Sdavidcs        bzero(fw_dcbx, sizeof(q80_query_fw_dcbx_caps_t));
4046284741Sdavidcs
4047284741Sdavidcs        fw_dcbx->opcode = Q8_MBX_GET_FW_DCBX_CAPS;
4048284741Sdavidcs        fw_dcbx->count_version = (sizeof (q80_query_fw_dcbx_caps_t) >> 2);
4049284741Sdavidcs        fw_dcbx->count_version |= Q8_MBX_CMD_VERSION;
4050284741Sdavidcs
4051284741Sdavidcs        ql_dump_buf8(ha, __func__, fw_dcbx, sizeof (q80_query_fw_dcbx_caps_t));
4052284741Sdavidcs        if (qla_mbx_cmd(ha, (uint32_t *)fw_dcbx,
4053284741Sdavidcs                (sizeof (q80_query_fw_dcbx_caps_t) >> 2),
4054284741Sdavidcs                ha->hw.mbox, (sizeof (q80_query_fw_dcbx_caps_rsp_t) >> 2), 0)) {
4055284741Sdavidcs                device_printf(dev, "%s: failed\n", __func__);
4056284741Sdavidcs                return -1;
4057284741Sdavidcs        }
4058284741Sdavidcs
4059284741Sdavidcs        fw_dcbx_rsp = (q80_query_fw_dcbx_caps_rsp_t *)ha->hw.mbox;
4060284741Sdavidcs        ql_dump_buf8(ha, __func__, fw_dcbx_rsp,
4061284741Sdavidcs                sizeof (q80_query_fw_dcbx_caps_rsp_t));
4062284741Sdavidcs
4063284741Sdavidcs        err = Q8_MBX_RSP_STATUS(fw_dcbx_rsp->regcnt_status);
4064284741Sdavidcs
4065284741Sdavidcs        if (err) {
4066284741Sdavidcs                device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
4067284741Sdavidcs        }
4068284741Sdavidcs
4069284741Sdavidcs        return 0;
4070284741Sdavidcs}
4071284741Sdavidcs
4072284741Sdavidcsstatic int
4073284741Sdavidcsqla_idc_ack(qla_host_t *ha, uint32_t aen_mb1, uint32_t aen_mb2,
4074284741Sdavidcs        uint32_t aen_mb3, uint32_t aen_mb4)
4075284741Sdavidcs{
4076284741Sdavidcs        device_t                dev;
4077284741Sdavidcs        q80_idc_ack_t           *idc_ack;
4078284741Sdavidcs        q80_idc_ack_rsp_t       *idc_ack_rsp;
4079284741Sdavidcs        uint32_t                err;
4080284741Sdavidcs        int                     count = 300;
4081284741Sdavidcs
4082284741Sdavidcs        dev = ha->pci_dev;
4083284741Sdavidcs
4084284741Sdavidcs        idc_ack = (q80_idc_ack_t *)ha->hw.mbox;
4085284741Sdavidcs        bzero(idc_ack, sizeof(q80_idc_ack_t));
4086284741Sdavidcs
4087284741Sdavidcs        idc_ack->opcode = Q8_MBX_IDC_ACK;
4088284741Sdavidcs        idc_ack->count_version = (sizeof (q80_idc_ack_t) >> 2);
4089284741Sdavidcs        idc_ack->count_version |= Q8_MBX_CMD_VERSION;
4090284741Sdavidcs
4091284741Sdavidcs        idc_ack->aen_mb1 = aen_mb1;
4092284741Sdavidcs        idc_ack->aen_mb2 = aen_mb2;
4093284741Sdavidcs        idc_ack->aen_mb3 = aen_mb3;
4094284741Sdavidcs        idc_ack->aen_mb4 = aen_mb4;
4095284741Sdavidcs
4096284741Sdavidcs        ha->hw.imd_compl= 0;
4097284741Sdavidcs
4098284741Sdavidcs        if (qla_mbx_cmd(ha, (uint32_t *)idc_ack,
4099284741Sdavidcs                (sizeof (q80_idc_ack_t) >> 2),
4100284741Sdavidcs                ha->hw.mbox, (sizeof (q80_idc_ack_rsp_t) >> 2), 0)) {
4101284741Sdavidcs                device_printf(dev, "%s: failed\n", __func__);
4102284741Sdavidcs                return -1;
4103284741Sdavidcs        }
4104284741Sdavidcs
4105284741Sdavidcs        idc_ack_rsp = (q80_idc_ack_rsp_t *)ha->hw.mbox;
4106284741Sdavidcs
4107284741Sdavidcs        err = Q8_MBX_RSP_STATUS(idc_ack_rsp->regcnt_status);
4108284741Sdavidcs
4109284741Sdavidcs        if (err) {
4110284741Sdavidcs                device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
4111284741Sdavidcs                return(-1);
4112284741Sdavidcs        }
4113284741Sdavidcs
4114284741Sdavidcs        while (count && !ha->hw.imd_compl) {
4115284741Sdavidcs                qla_mdelay(__func__, 100);
4116284741Sdavidcs                count--;
4117284741Sdavidcs        }
4118284741Sdavidcs
4119284741Sdavidcs        if (!count)
4120284741Sdavidcs                return -1;
4121284741Sdavidcs        else
4122284741Sdavidcs                device_printf(dev, "%s: count %d\n", __func__, count);
4123284741Sdavidcs
4124284741Sdavidcs        return (0);
4125284741Sdavidcs}
4126284741Sdavidcs
4127284741Sdavidcsstatic int
4128284741Sdavidcsqla_set_port_config(qla_host_t *ha, uint32_t cfg_bits)
4129284741Sdavidcs{
4130284741Sdavidcs        device_t                dev;
4131284741Sdavidcs        q80_set_port_cfg_t      *pcfg;
4132284741Sdavidcs        q80_set_port_cfg_rsp_t  *pfg_rsp;
4133284741Sdavidcs        uint32_t                err;
4134284741Sdavidcs        int                     count = 300;
4135284741Sdavidcs
4136284741Sdavidcs        dev = ha->pci_dev;
4137284741Sdavidcs
4138284741Sdavidcs        pcfg = (q80_set_port_cfg_t *)ha->hw.mbox;
4139284741Sdavidcs        bzero(pcfg, sizeof(q80_set_port_cfg_t));
4140284741Sdavidcs
4141284741Sdavidcs        pcfg->opcode = Q8_MBX_SET_PORT_CONFIG;
4142284741Sdavidcs        pcfg->count_version = (sizeof (q80_set_port_cfg_t) >> 2);
4143284741Sdavidcs        pcfg->count_version |= Q8_MBX_CMD_VERSION;
4144284741Sdavidcs
4145284741Sdavidcs        pcfg->cfg_bits = cfg_bits;
4146284741Sdavidcs
4147284741Sdavidcs        device_printf(dev, "%s: cfg_bits"
4148284741Sdavidcs                " [STD_PAUSE_DIR, PAUSE_TYPE, DCBX]"
4149284741Sdavidcs                " [0x%x, 0x%x, 0x%x]\n", __func__,
4150284741Sdavidcs                ((cfg_bits & Q8_PORT_CFG_BITS_STDPAUSE_DIR_MASK)>>20),
4151284741Sdavidcs                ((cfg_bits & Q8_PORT_CFG_BITS_PAUSE_CFG_MASK) >> 5),
4152284741Sdavidcs                ((cfg_bits & Q8_PORT_CFG_BITS_DCBX_ENABLE) ? 1: 0));
4153284741Sdavidcs
4154284741Sdavidcs        ha->hw.imd_compl= 0;
4155284741Sdavidcs
4156284741Sdavidcs        if (qla_mbx_cmd(ha, (uint32_t *)pcfg,
4157284741Sdavidcs                (sizeof (q80_set_port_cfg_t) >> 2),
4158284741Sdavidcs                ha->hw.mbox, (sizeof (q80_set_port_cfg_rsp_t) >> 2), 0)) {
4159284741Sdavidcs                device_printf(dev, "%s: failed\n", __func__);
4160284741Sdavidcs                return -1;
4161284741Sdavidcs        }
4162284741Sdavidcs
4163284741Sdavidcs        pfg_rsp = (q80_set_port_cfg_rsp_t *)ha->hw.mbox;
4164284741Sdavidcs
4165284741Sdavidcs        err = Q8_MBX_RSP_STATUS(pfg_rsp->regcnt_status);
4166284741Sdavidcs
4167284741Sdavidcs        if (err == Q8_MBX_RSP_IDC_INTRMD_RSP) {
4168284741Sdavidcs                while (count && !ha->hw.imd_compl) {
4169284741Sdavidcs                        qla_mdelay(__func__, 100);
4170284741Sdavidcs                        count--;
4171284741Sdavidcs                }
4172284741Sdavidcs                if (count) {
4173284741Sdavidcs                        device_printf(dev, "%s: count %d\n", __func__, count);
4174284741Sdavidcs
4175284741Sdavidcs                        err = 0;
4176284741Sdavidcs                }
4177284741Sdavidcs        }
4178284741Sdavidcs
4179284741Sdavidcs        if (err) {
4180284741Sdavidcs                device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
4181284741Sdavidcs                return(-1);
4182284741Sdavidcs        }
4183284741Sdavidcs
4184284741Sdavidcs        return (0);
4185284741Sdavidcs}
4186284741Sdavidcs
4187284741Sdavidcs
4188284741Sdavidcsstatic int
4189250661Sdavidcsqla_get_minidump_tmplt_size(qla_host_t *ha, uint32_t *size)
4190250661Sdavidcs{
4191250661Sdavidcs	uint32_t			err;
4192250661Sdavidcs	device_t			dev = ha->pci_dev;
4193250661Sdavidcs	q80_config_md_templ_size_t	*md_size;
4194250661Sdavidcs	q80_config_md_templ_size_rsp_t	*md_size_rsp;
4195250661Sdavidcs
4196305487Sdavidcs#ifndef QL_LDFLASH_FW
4197284741Sdavidcs
4198305487Sdavidcs	ql_minidump_template_hdr_t *hdr;
4199305487Sdavidcs
4200305487Sdavidcs	hdr = (ql_minidump_template_hdr_t *)ql83xx_minidump;
4201305487Sdavidcs	*size = hdr->size_of_template;
4202284741Sdavidcs	return (0);
4203284741Sdavidcs
4204284741Sdavidcs#endif /* #ifdef QL_LDFLASH_FW */
4205284741Sdavidcs
4206250661Sdavidcs	md_size = (q80_config_md_templ_size_t *) ha->hw.mbox;
4207250661Sdavidcs	bzero(md_size, sizeof(q80_config_md_templ_size_t));
4208250661Sdavidcs
4209250661Sdavidcs	md_size->opcode = Q8_MBX_GET_MINIDUMP_TMPLT_SIZE;
4210250661Sdavidcs	md_size->count_version = (sizeof (q80_config_md_templ_size_t) >> 2);
4211250661Sdavidcs	md_size->count_version |= Q8_MBX_CMD_VERSION;
4212250661Sdavidcs
4213250661Sdavidcs	if (qla_mbx_cmd(ha, (uint32_t *) md_size,
4214250661Sdavidcs		(sizeof(q80_config_md_templ_size_t) >> 2), ha->hw.mbox,
4215250661Sdavidcs		(sizeof(q80_config_md_templ_size_rsp_t) >> 2), 0)) {
4216250661Sdavidcs
4217250661Sdavidcs		device_printf(dev, "%s: failed\n", __func__);
4218250661Sdavidcs
4219250661Sdavidcs		return (-1);
4220250661Sdavidcs	}
4221250661Sdavidcs
4222250661Sdavidcs	md_size_rsp = (q80_config_md_templ_size_rsp_t *) ha->hw.mbox;
4223250661Sdavidcs
4224250661Sdavidcs	err = Q8_MBX_RSP_STATUS(md_size_rsp->regcnt_status);
4225250661Sdavidcs
4226250661Sdavidcs        if (err) {
4227250661Sdavidcs		device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
4228250661Sdavidcs		return(-1);
4229250661Sdavidcs        }
4230250661Sdavidcs
4231250661Sdavidcs	*size = md_size_rsp->templ_size;
4232250661Sdavidcs
4233250661Sdavidcs	return (0);
4234250661Sdavidcs}
4235250661Sdavidcs
4236250661Sdavidcsstatic int
4237284741Sdavidcsqla_get_port_config(qla_host_t *ha, uint32_t *cfg_bits)
4238284741Sdavidcs{
4239284741Sdavidcs        device_t                dev;
4240284741Sdavidcs        q80_get_port_cfg_t      *pcfg;
4241284741Sdavidcs        q80_get_port_cfg_rsp_t  *pcfg_rsp;
4242284741Sdavidcs        uint32_t                err;
4243284741Sdavidcs
4244284741Sdavidcs        dev = ha->pci_dev;
4245284741Sdavidcs
4246284741Sdavidcs        pcfg = (q80_get_port_cfg_t *)ha->hw.mbox;
4247284741Sdavidcs        bzero(pcfg, sizeof(q80_get_port_cfg_t));
4248284741Sdavidcs
4249284741Sdavidcs        pcfg->opcode = Q8_MBX_GET_PORT_CONFIG;
4250284741Sdavidcs        pcfg->count_version = (sizeof (q80_get_port_cfg_t) >> 2);
4251284741Sdavidcs        pcfg->count_version |= Q8_MBX_CMD_VERSION;
4252284741Sdavidcs
4253284741Sdavidcs        if (qla_mbx_cmd(ha, (uint32_t *)pcfg,
4254284741Sdavidcs                (sizeof (q80_get_port_cfg_t) >> 2),
4255284741Sdavidcs                ha->hw.mbox, (sizeof (q80_get_port_cfg_rsp_t) >> 2), 0)) {
4256284741Sdavidcs                device_printf(dev, "%s: failed\n", __func__);
4257284741Sdavidcs                return -1;
4258284741Sdavidcs        }
4259284741Sdavidcs
4260284741Sdavidcs        pcfg_rsp = (q80_get_port_cfg_rsp_t *)ha->hw.mbox;
4261284741Sdavidcs
4262284741Sdavidcs        err = Q8_MBX_RSP_STATUS(pcfg_rsp->regcnt_status);
4263284741Sdavidcs
4264284741Sdavidcs        if (err) {
4265284741Sdavidcs                device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
4266284741Sdavidcs                return(-1);
4267284741Sdavidcs        }
4268284741Sdavidcs
4269284741Sdavidcs        device_printf(dev, "%s: [cfg_bits, port type]"
4270284741Sdavidcs                " [0x%08x, 0x%02x] [STD_PAUSE_DIR, PAUSE_TYPE, DCBX]"
4271284741Sdavidcs                " [0x%x, 0x%x, 0x%x]\n", __func__,
4272284741Sdavidcs                pcfg_rsp->cfg_bits, pcfg_rsp->phys_port_type,
4273284741Sdavidcs                ((pcfg_rsp->cfg_bits & Q8_PORT_CFG_BITS_STDPAUSE_DIR_MASK)>>20),
4274284741Sdavidcs                ((pcfg_rsp->cfg_bits & Q8_PORT_CFG_BITS_PAUSE_CFG_MASK) >> 5),
4275284741Sdavidcs                ((pcfg_rsp->cfg_bits & Q8_PORT_CFG_BITS_DCBX_ENABLE) ? 1: 0)
4276284741Sdavidcs                );
4277284741Sdavidcs
4278284741Sdavidcs        *cfg_bits = pcfg_rsp->cfg_bits;
4279284741Sdavidcs
4280284741Sdavidcs        return (0);
4281284741Sdavidcs}
4282284741Sdavidcs
4283284741Sdavidcsint
4284313070Sdavidcsql_iscsi_pdu(qla_host_t *ha, struct mbuf *mp)
4285284741Sdavidcs{
4286284741Sdavidcs        struct ether_vlan_header        *eh;
4287284741Sdavidcs        uint16_t                        etype;
4288284741Sdavidcs        struct ip                       *ip = NULL;
4289284741Sdavidcs        struct ip6_hdr                  *ip6 = NULL;
4290284741Sdavidcs        struct tcphdr                   *th = NULL;
4291284741Sdavidcs        uint32_t                        hdrlen;
4292284741Sdavidcs        uint32_t                        offset;
4293284741Sdavidcs        uint8_t                         buf[sizeof(struct ip6_hdr)];
4294284741Sdavidcs
4295284741Sdavidcs        eh = mtod(mp, struct ether_vlan_header *);
4296284741Sdavidcs
4297284741Sdavidcs        if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
4298284741Sdavidcs                hdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
4299284741Sdavidcs                etype = ntohs(eh->evl_proto);
4300284741Sdavidcs        } else {
4301284741Sdavidcs                hdrlen = ETHER_HDR_LEN;
4302284741Sdavidcs                etype = ntohs(eh->evl_encap_proto);
4303284741Sdavidcs        }
4304284741Sdavidcs
4305284741Sdavidcs	if (etype == ETHERTYPE_IP) {
4306284741Sdavidcs
4307284741Sdavidcs		offset = (hdrlen + sizeof (struct ip));
4308284741Sdavidcs
4309284741Sdavidcs		if (mp->m_len >= offset) {
4310284741Sdavidcs                        ip = (struct ip *)(mp->m_data + hdrlen);
4311284741Sdavidcs		} else {
4312284741Sdavidcs			m_copydata(mp, hdrlen, sizeof (struct ip), buf);
4313284741Sdavidcs                        ip = (struct ip *)buf;
4314284741Sdavidcs		}
4315284741Sdavidcs
4316284741Sdavidcs                if (ip->ip_p == IPPROTO_TCP) {
4317284741Sdavidcs
4318284741Sdavidcs			hdrlen += ip->ip_hl << 2;
4319284741Sdavidcs			offset = hdrlen + 4;
4320284741Sdavidcs
4321284741Sdavidcs			if (mp->m_len >= offset) {
4322305487Sdavidcs				th = (struct tcphdr *)(mp->m_data + hdrlen);;
4323284741Sdavidcs			} else {
4324284741Sdavidcs                                m_copydata(mp, hdrlen, 4, buf);
4325284741Sdavidcs				th = (struct tcphdr *)buf;
4326284741Sdavidcs			}
4327284741Sdavidcs                }
4328284741Sdavidcs
4329284741Sdavidcs	} else if (etype == ETHERTYPE_IPV6) {
4330284741Sdavidcs
4331284741Sdavidcs		offset = (hdrlen + sizeof (struct ip6_hdr));
4332284741Sdavidcs
4333284741Sdavidcs		if (mp->m_len >= offset) {
4334284741Sdavidcs                        ip6 = (struct ip6_hdr *)(mp->m_data + hdrlen);
4335284741Sdavidcs		} else {
4336284741Sdavidcs                        m_copydata(mp, hdrlen, sizeof (struct ip6_hdr), buf);
4337284741Sdavidcs                        ip6 = (struct ip6_hdr *)buf;
4338284741Sdavidcs		}
4339284741Sdavidcs
4340284741Sdavidcs                if (ip6->ip6_nxt == IPPROTO_TCP) {
4341284741Sdavidcs
4342284741Sdavidcs			hdrlen += sizeof(struct ip6_hdr);
4343284741Sdavidcs			offset = hdrlen + 4;
4344284741Sdavidcs
4345284741Sdavidcs			if (mp->m_len >= offset) {
4346305487Sdavidcs				th = (struct tcphdr *)(mp->m_data + hdrlen);;
4347284741Sdavidcs			} else {
4348284741Sdavidcs				m_copydata(mp, hdrlen, 4, buf);
4349284741Sdavidcs				th = (struct tcphdr *)buf;
4350284741Sdavidcs			}
4351284741Sdavidcs                }
4352284741Sdavidcs	}
4353284741Sdavidcs
4354284741Sdavidcs        if (th != NULL) {
4355284741Sdavidcs                if ((th->th_sport == htons(3260)) ||
4356284741Sdavidcs                        (th->th_dport == htons(3260)))
4357284741Sdavidcs                        return 0;
4358284741Sdavidcs        }
4359284741Sdavidcs        return (-1);
4360284741Sdavidcs}
4361284741Sdavidcs
4362284741Sdavidcsvoid
4363284741Sdavidcsqla_hw_async_event(qla_host_t *ha)
4364284741Sdavidcs{
4365284741Sdavidcs        switch (ha->hw.aen_mb0) {
4366284741Sdavidcs        case 0x8101:
4367284741Sdavidcs                (void)qla_idc_ack(ha, ha->hw.aen_mb1, ha->hw.aen_mb2,
4368284741Sdavidcs                        ha->hw.aen_mb3, ha->hw.aen_mb4);
4369284741Sdavidcs
4370284741Sdavidcs                break;
4371284741Sdavidcs
4372284741Sdavidcs        default:
4373284741Sdavidcs                break;
4374284741Sdavidcs        }
4375284741Sdavidcs
4376284741Sdavidcs        return;
4377284741Sdavidcs}
4378284741Sdavidcs
4379284741Sdavidcs#ifdef QL_LDFLASH_FW
4380284741Sdavidcsstatic int
4381305487Sdavidcsql_get_minidump_template(qla_host_t *ha)
4382250661Sdavidcs{
4383250661Sdavidcs	uint32_t			err;
4384250661Sdavidcs	device_t			dev = ha->pci_dev;
4385250661Sdavidcs	q80_config_md_templ_cmd_t	*md_templ;
4386250661Sdavidcs	q80_config_md_templ_cmd_rsp_t	*md_templ_rsp;
4387250661Sdavidcs
4388250661Sdavidcs	md_templ = (q80_config_md_templ_cmd_t *) ha->hw.mbox;
4389250661Sdavidcs	bzero(md_templ, (sizeof (q80_config_md_templ_cmd_t)));
4390250661Sdavidcs
4391250661Sdavidcs	md_templ->opcode = Q8_MBX_GET_MINIDUMP_TMPLT;
4392250661Sdavidcs	md_templ->count_version = ( sizeof(q80_config_md_templ_cmd_t) >> 2);
4393250661Sdavidcs	md_templ->count_version |= Q8_MBX_CMD_VERSION;
4394250661Sdavidcs
4395250661Sdavidcs	md_templ->buf_addr = ha->hw.dma_buf.minidump.dma_addr;
4396250661Sdavidcs	md_templ->buff_size = ha->hw.dma_buf.minidump.size;
4397250661Sdavidcs
4398250661Sdavidcs	if (qla_mbx_cmd(ha, (uint32_t *) md_templ,
4399250661Sdavidcs		(sizeof(q80_config_md_templ_cmd_t) >> 2),
4400250661Sdavidcs		 ha->hw.mbox,
4401250661Sdavidcs		(sizeof(q80_config_md_templ_cmd_rsp_t) >> 2), 0)) {
4402250661Sdavidcs
4403250661Sdavidcs		device_printf(dev, "%s: failed\n", __func__);
4404250661Sdavidcs
4405250661Sdavidcs		return (-1);
4406250661Sdavidcs	}
4407250661Sdavidcs
4408250661Sdavidcs	md_templ_rsp = (q80_config_md_templ_cmd_rsp_t *) ha->hw.mbox;
4409250661Sdavidcs
4410250661Sdavidcs	err = Q8_MBX_RSP_STATUS(md_templ_rsp->regcnt_status);
4411250661Sdavidcs
4412250661Sdavidcs	if (err) {
4413250661Sdavidcs		device_printf(dev, "%s: failed [0x%08x]\n", __func__, err);
4414250661Sdavidcs		return (-1);
4415250661Sdavidcs	}
4416250661Sdavidcs
4417250661Sdavidcs	return (0);
4418250661Sdavidcs
4419250661Sdavidcs}
4420284741Sdavidcs#endif /* #ifdef QL_LDFLASH_FW */
4421250661Sdavidcs
4422305487Sdavidcs/*
4423305487Sdavidcs * Minidump related functionality
4424305487Sdavidcs */
4425305487Sdavidcs
4426305487Sdavidcsstatic int ql_parse_template(qla_host_t *ha);
4427305487Sdavidcs
4428305487Sdavidcsstatic uint32_t ql_rdcrb(qla_host_t *ha,
4429305487Sdavidcs			ql_minidump_entry_rdcrb_t *crb_entry,
4430305487Sdavidcs			uint32_t * data_buff);
4431305487Sdavidcs
4432305487Sdavidcsstatic uint32_t ql_pollrd(qla_host_t *ha,
4433305487Sdavidcs			ql_minidump_entry_pollrd_t *entry,
4434305487Sdavidcs			uint32_t * data_buff);
4435305487Sdavidcs
4436305487Sdavidcsstatic uint32_t ql_pollrd_modify_write(qla_host_t *ha,
4437305487Sdavidcs			ql_minidump_entry_rd_modify_wr_with_poll_t *entry,
4438305487Sdavidcs			uint32_t *data_buff);
4439305487Sdavidcs
4440305487Sdavidcsstatic uint32_t ql_L2Cache(qla_host_t *ha,
4441305487Sdavidcs			ql_minidump_entry_cache_t *cacheEntry,
4442305487Sdavidcs			uint32_t * data_buff);
4443305487Sdavidcs
4444305487Sdavidcsstatic uint32_t ql_L1Cache(qla_host_t *ha,
4445305487Sdavidcs			ql_minidump_entry_cache_t *cacheEntry,
4446305487Sdavidcs			uint32_t *data_buff);
4447305487Sdavidcs
4448305487Sdavidcsstatic uint32_t ql_rdocm(qla_host_t *ha,
4449305487Sdavidcs			ql_minidump_entry_rdocm_t *ocmEntry,
4450305487Sdavidcs			uint32_t *data_buff);
4451305487Sdavidcs
4452305487Sdavidcsstatic uint32_t ql_rdmem(qla_host_t *ha,
4453305487Sdavidcs			ql_minidump_entry_rdmem_t *mem_entry,
4454305487Sdavidcs			uint32_t *data_buff);
4455305487Sdavidcs
4456305487Sdavidcsstatic uint32_t ql_rdrom(qla_host_t *ha,
4457305487Sdavidcs			ql_minidump_entry_rdrom_t *romEntry,
4458305487Sdavidcs			uint32_t *data_buff);
4459305487Sdavidcs
4460305487Sdavidcsstatic uint32_t ql_rdmux(qla_host_t *ha,
4461305487Sdavidcs			ql_minidump_entry_mux_t *muxEntry,
4462305487Sdavidcs			uint32_t *data_buff);
4463305487Sdavidcs
4464305487Sdavidcsstatic uint32_t ql_rdmux2(qla_host_t *ha,
4465305487Sdavidcs			ql_minidump_entry_mux2_t *muxEntry,
4466305487Sdavidcs			uint32_t *data_buff);
4467305487Sdavidcs
4468305487Sdavidcsstatic uint32_t ql_rdqueue(qla_host_t *ha,
4469305487Sdavidcs			ql_minidump_entry_queue_t *queueEntry,
4470305487Sdavidcs			uint32_t *data_buff);
4471305487Sdavidcs
4472305487Sdavidcsstatic uint32_t ql_cntrl(qla_host_t *ha,
4473305487Sdavidcs			ql_minidump_template_hdr_t *template_hdr,
4474305487Sdavidcs			ql_minidump_entry_cntrl_t *crbEntry);
4475305487Sdavidcs
4476305487Sdavidcs
4477305487Sdavidcsstatic uint32_t
4478305487Sdavidcsql_minidump_size(qla_host_t *ha)
4479305487Sdavidcs{
4480305487Sdavidcs	uint32_t i, k;
4481305487Sdavidcs	uint32_t size = 0;
4482305487Sdavidcs	ql_minidump_template_hdr_t *hdr;
4483305487Sdavidcs
4484305487Sdavidcs	hdr = (ql_minidump_template_hdr_t *)ha->hw.dma_buf.minidump.dma_b;
4485305487Sdavidcs
4486305487Sdavidcs	i = 0x2;
4487305487Sdavidcs
4488305487Sdavidcs	for (k = 1; k < QL_DBG_CAP_SIZE_ARRAY_LEN; k++) {
4489305487Sdavidcs		if (i & ha->hw.mdump_capture_mask)
4490305487Sdavidcs			size += hdr->capture_size_array[k];
4491305487Sdavidcs		i = i << 1;
4492305487Sdavidcs	}
4493305487Sdavidcs	return (size);
4494305487Sdavidcs}
4495305487Sdavidcs
4496305487Sdavidcsstatic void
4497305487Sdavidcsql_free_minidump_buffer(qla_host_t *ha)
4498305487Sdavidcs{
4499305487Sdavidcs	if (ha->hw.mdump_buffer != NULL) {
4500305487Sdavidcs		free(ha->hw.mdump_buffer, M_QLA83XXBUF);
4501305487Sdavidcs		ha->hw.mdump_buffer = NULL;
4502305487Sdavidcs		ha->hw.mdump_buffer_size = 0;
4503305487Sdavidcs	}
4504305487Sdavidcs	return;
4505305487Sdavidcs}
4506305487Sdavidcs
4507250661Sdavidcsstatic int
4508305487Sdavidcsql_alloc_minidump_buffer(qla_host_t *ha)
4509250661Sdavidcs{
4510305487Sdavidcs	ha->hw.mdump_buffer_size = ql_minidump_size(ha);
4511305487Sdavidcs
4512305487Sdavidcs	if (!ha->hw.mdump_buffer_size)
4513305487Sdavidcs		return (-1);
4514305487Sdavidcs
4515305487Sdavidcs	ha->hw.mdump_buffer = malloc(ha->hw.mdump_buffer_size, M_QLA83XXBUF,
4516305487Sdavidcs					M_NOWAIT);
4517305487Sdavidcs
4518305487Sdavidcs	if (ha->hw.mdump_buffer == NULL)
4519305487Sdavidcs		return (-1);
4520305487Sdavidcs
4521305487Sdavidcs	return (0);
4522305487Sdavidcs}
4523305487Sdavidcs
4524305487Sdavidcsstatic void
4525305487Sdavidcsql_free_minidump_template_buffer(qla_host_t *ha)
4526305487Sdavidcs{
4527305487Sdavidcs	if (ha->hw.mdump_template != NULL) {
4528305487Sdavidcs		free(ha->hw.mdump_template, M_QLA83XXBUF);
4529305487Sdavidcs		ha->hw.mdump_template = NULL;
4530305487Sdavidcs		ha->hw.mdump_template_size = 0;
4531305487Sdavidcs	}
4532305487Sdavidcs	return;
4533305487Sdavidcs}
4534305487Sdavidcs
4535305487Sdavidcsstatic int
4536305487Sdavidcsql_alloc_minidump_template_buffer(qla_host_t *ha)
4537305487Sdavidcs{
4538305487Sdavidcs	ha->hw.mdump_template_size = ha->hw.dma_buf.minidump.size;
4539305487Sdavidcs
4540305487Sdavidcs	ha->hw.mdump_template = malloc(ha->hw.mdump_template_size,
4541305487Sdavidcs					M_QLA83XXBUF, M_NOWAIT);
4542305487Sdavidcs
4543305487Sdavidcs	if (ha->hw.mdump_template == NULL)
4544305487Sdavidcs		return (-1);
4545305487Sdavidcs
4546305487Sdavidcs	return (0);
4547305487Sdavidcs}
4548305487Sdavidcs
4549305487Sdavidcsstatic int
4550305487Sdavidcsql_alloc_minidump_buffers(qla_host_t *ha)
4551305487Sdavidcs{
4552305487Sdavidcs	int ret;
4553305487Sdavidcs
4554305487Sdavidcs	ret = ql_alloc_minidump_template_buffer(ha);
4555305487Sdavidcs
4556305487Sdavidcs	if (ret)
4557305487Sdavidcs		return (ret);
4558305487Sdavidcs
4559305487Sdavidcs	ret = ql_alloc_minidump_buffer(ha);
4560305487Sdavidcs
4561305487Sdavidcs	if (ret)
4562305487Sdavidcs		ql_free_minidump_template_buffer(ha);
4563305487Sdavidcs
4564305487Sdavidcs	return (ret);
4565305487Sdavidcs}
4566305487Sdavidcs
4567305487Sdavidcs
4568305487Sdavidcsstatic uint32_t
4569305487Sdavidcsql_validate_minidump_checksum(qla_host_t *ha)
4570305487Sdavidcs{
4571305487Sdavidcs        uint64_t sum = 0;
4572305487Sdavidcs	int count;
4573305487Sdavidcs	uint32_t *template_buff;
4574305487Sdavidcs
4575305487Sdavidcs	count = ha->hw.dma_buf.minidump.size / sizeof (uint32_t);
4576305487Sdavidcs	template_buff = ha->hw.dma_buf.minidump.dma_b;
4577305487Sdavidcs
4578305487Sdavidcs	while (count-- > 0) {
4579305487Sdavidcs		sum += *template_buff++;
4580305487Sdavidcs	}
4581305487Sdavidcs
4582305487Sdavidcs	while (sum >> 32) {
4583305487Sdavidcs		sum = (sum & 0xFFFFFFFF) + (sum >> 32);
4584305487Sdavidcs	}
4585305487Sdavidcs
4586305487Sdavidcs	return (~sum);
4587305487Sdavidcs}
4588305487Sdavidcs
4589305487Sdavidcsint
4590305487Sdavidcsql_minidump_init(qla_host_t *ha)
4591305487Sdavidcs{
4592284741Sdavidcs	int		ret = 0;
4593250661Sdavidcs	uint32_t	template_size = 0;
4594250661Sdavidcs	device_t	dev = ha->pci_dev;
4595250661Sdavidcs
4596250661Sdavidcs	/*
4597250661Sdavidcs	 * Get Minidump Template Size
4598250661Sdavidcs 	 */
4599250661Sdavidcs	ret = qla_get_minidump_tmplt_size(ha, &template_size);
4600250661Sdavidcs
4601250661Sdavidcs	if (ret || (template_size == 0)) {
4602250661Sdavidcs		device_printf(dev, "%s: failed [%d, %d]\n", __func__, ret,
4603250661Sdavidcs			template_size);
4604250661Sdavidcs		return (-1);
4605250661Sdavidcs	}
4606250661Sdavidcs
4607250661Sdavidcs	/*
4608250661Sdavidcs	 * Allocate Memory for Minidump Template
4609250661Sdavidcs	 */
4610250661Sdavidcs
4611250661Sdavidcs	ha->hw.dma_buf.minidump.alignment = 8;
4612250661Sdavidcs	ha->hw.dma_buf.minidump.size = template_size;
4613250661Sdavidcs
4614284741Sdavidcs#ifdef QL_LDFLASH_FW
4615250661Sdavidcs	if (ql_alloc_dmabuf(ha, &ha->hw.dma_buf.minidump)) {
4616250661Sdavidcs
4617250661Sdavidcs		device_printf(dev, "%s: minidump dma alloc failed\n", __func__);
4618250661Sdavidcs
4619250661Sdavidcs		return (-1);
4620250661Sdavidcs	}
4621250661Sdavidcs	ha->hw.dma_buf.flags.minidump = 1;
4622250661Sdavidcs
4623250661Sdavidcs	/*
4624250661Sdavidcs	 * Retrieve Minidump Template
4625250661Sdavidcs	 */
4626305487Sdavidcs	ret = ql_get_minidump_template(ha);
4627284741Sdavidcs#else
4628284741Sdavidcs	ha->hw.dma_buf.minidump.dma_b = ql83xx_minidump;
4629305487Sdavidcs
4630284741Sdavidcs#endif /* #ifdef QL_LDFLASH_FW */
4631250661Sdavidcs
4632305487Sdavidcs	if (ret == 0) {
4633305487Sdavidcs
4634305487Sdavidcs		ret = ql_validate_minidump_checksum(ha);
4635305487Sdavidcs
4636305487Sdavidcs		if (ret == 0) {
4637305487Sdavidcs
4638305487Sdavidcs			ret = ql_alloc_minidump_buffers(ha);
4639305487Sdavidcs
4640305487Sdavidcs			if (ret == 0)
4641305487Sdavidcs		ha->hw.mdump_init = 1;
4642305487Sdavidcs			else
4643305487Sdavidcs				device_printf(dev,
4644305487Sdavidcs					"%s: ql_alloc_minidump_buffers"
4645305487Sdavidcs					" failed\n", __func__);
4646305487Sdavidcs		} else {
4647305487Sdavidcs			device_printf(dev, "%s: ql_validate_minidump_checksum"
4648305487Sdavidcs				" failed\n", __func__);
4649305487Sdavidcs		}
4650250661Sdavidcs	} else {
4651305487Sdavidcs		device_printf(dev, "%s: ql_get_minidump_template failed\n",
4652305487Sdavidcs			 __func__);
4653250661Sdavidcs	}
4654250661Sdavidcs
4655305487Sdavidcs	if (ret)
4656305487Sdavidcs		ql_minidump_free(ha);
4657305487Sdavidcs
4658250661Sdavidcs	return (ret);
4659250661Sdavidcs}
4660250661Sdavidcs
4661250661Sdavidcsstatic void
4662305487Sdavidcsql_minidump_free(qla_host_t *ha)
4663250661Sdavidcs{
4664250661Sdavidcs	ha->hw.mdump_init = 0;
4665250661Sdavidcs	if (ha->hw.dma_buf.flags.minidump) {
4666250661Sdavidcs		ha->hw.dma_buf.flags.minidump = 0;
4667250661Sdavidcs		ql_free_dmabuf(ha, &ha->hw.dma_buf.minidump);
4668250661Sdavidcs	}
4669305487Sdavidcs
4670305487Sdavidcs	ql_free_minidump_template_buffer(ha);
4671305487Sdavidcs	ql_free_minidump_buffer(ha);
4672305487Sdavidcs
4673250661Sdavidcs	return;
4674250661Sdavidcs}
4675250661Sdavidcs
4676250661Sdavidcsvoid
4677250661Sdavidcsql_minidump(qla_host_t *ha)
4678250661Sdavidcs{
4679250661Sdavidcs	if (!ha->hw.mdump_init)
4680250661Sdavidcs		return;
4681250661Sdavidcs
4682305487Sdavidcs	if (ha->hw.mdump_done)
4683250661Sdavidcs		return;
4684330555Sdavidcs	ha->hw.mdump_usec_ts = qla_get_usec_timestamp();
4685330555Sdavidcs	ha->hw.mdump_start_seq_index = ql_stop_sequence(ha);
4686250661Sdavidcs
4687305487Sdavidcs	bzero(ha->hw.mdump_buffer, ha->hw.mdump_buffer_size);
4688305487Sdavidcs	bzero(ha->hw.mdump_template, ha->hw.mdump_template_size);
4689305487Sdavidcs
4690305487Sdavidcs	bcopy(ha->hw.dma_buf.minidump.dma_b, ha->hw.mdump_template,
4691305487Sdavidcs		ha->hw.mdump_template_size);
4692305487Sdavidcs
4693305487Sdavidcs	ql_parse_template(ha);
4694305487Sdavidcs
4695250661Sdavidcs	ql_start_sequence(ha, ha->hw.mdump_start_seq_index);
4696250661Sdavidcs
4697305487Sdavidcs	ha->hw.mdump_done = 1;
4698305487Sdavidcs
4699250661Sdavidcs	return;
4700250661Sdavidcs}
4701305487Sdavidcs
4702305487Sdavidcs
4703305487Sdavidcs/*
4704305487Sdavidcs * helper routines
4705305487Sdavidcs */
4706305487Sdavidcsstatic void
4707305487Sdavidcsql_entry_err_chk(ql_minidump_entry_t *entry, uint32_t esize)
4708305487Sdavidcs{
4709305487Sdavidcs	if (esize != entry->hdr.entry_capture_size) {
4710305487Sdavidcs		entry->hdr.entry_capture_size = esize;
4711305487Sdavidcs		entry->hdr.driver_flags |= QL_DBG_SIZE_ERR_FLAG;
4712305487Sdavidcs	}
4713305487Sdavidcs	return;
4714305487Sdavidcs}
4715305487Sdavidcs
4716305487Sdavidcs
4717305487Sdavidcsstatic int
4718305487Sdavidcsql_parse_template(qla_host_t *ha)
4719305487Sdavidcs{
4720305487Sdavidcs	uint32_t num_of_entries, buff_level, e_cnt, esize;
4721305487Sdavidcs	uint32_t end_cnt, rv = 0;
4722305487Sdavidcs	char *dump_buff, *dbuff;
4723305487Sdavidcs	int sane_start = 0, sane_end = 0;
4724305487Sdavidcs	ql_minidump_template_hdr_t *template_hdr;
4725305487Sdavidcs	ql_minidump_entry_t *entry;
4726305487Sdavidcs	uint32_t capture_mask;
4727305487Sdavidcs	uint32_t dump_size;
4728305487Sdavidcs
4729305487Sdavidcs	/* Setup parameters */
4730305487Sdavidcs	template_hdr = (ql_minidump_template_hdr_t *)ha->hw.mdump_template;
4731305487Sdavidcs
4732305487Sdavidcs	if (template_hdr->entry_type == TLHDR)
4733305487Sdavidcs		sane_start = 1;
4734305487Sdavidcs
4735305487Sdavidcs	dump_buff = (char *) ha->hw.mdump_buffer;
4736305487Sdavidcs
4737305487Sdavidcs	num_of_entries = template_hdr->num_of_entries;
4738305487Sdavidcs
4739305487Sdavidcs	entry = (ql_minidump_entry_t *) ((char *)template_hdr
4740305487Sdavidcs			+ template_hdr->first_entry_offset );
4741305487Sdavidcs
4742305487Sdavidcs	template_hdr->saved_state_array[QL_OCM0_ADDR_INDX] =
4743305487Sdavidcs		template_hdr->ocm_window_array[ha->pci_func];
4744305487Sdavidcs	template_hdr->saved_state_array[QL_PCIE_FUNC_INDX] = ha->pci_func;
4745305487Sdavidcs
4746305487Sdavidcs	capture_mask = ha->hw.mdump_capture_mask;
4747305487Sdavidcs	dump_size = ha->hw.mdump_buffer_size;
4748305487Sdavidcs
4749305487Sdavidcs	template_hdr->driver_capture_mask = capture_mask;
4750305487Sdavidcs
4751305487Sdavidcs	QL_DPRINT80(ha, (ha->pci_dev,
4752305487Sdavidcs		"%s: sane_start = %d num_of_entries = %d "
4753305487Sdavidcs		"capture_mask = 0x%x dump_size = %d \n",
4754305487Sdavidcs		__func__, sane_start, num_of_entries, capture_mask, dump_size));
4755305487Sdavidcs
4756305487Sdavidcs	for (buff_level = 0, e_cnt = 0; e_cnt < num_of_entries; e_cnt++) {
4757305487Sdavidcs
4758305487Sdavidcs		/*
4759305487Sdavidcs		 * If the capture_mask of the entry does not match capture mask
4760305487Sdavidcs		 * skip the entry after marking the driver_flags indicator.
4761305487Sdavidcs		 */
4762305487Sdavidcs
4763305487Sdavidcs		if (!(entry->hdr.entry_capture_mask & capture_mask)) {
4764305487Sdavidcs
4765305487Sdavidcs			entry->hdr.driver_flags |= QL_DBG_SKIPPED_FLAG;
4766305487Sdavidcs			entry = (ql_minidump_entry_t *) ((char *) entry
4767305487Sdavidcs					+ entry->hdr.entry_size);
4768305487Sdavidcs			continue;
4769305487Sdavidcs		}
4770305487Sdavidcs
4771305487Sdavidcs		/*
4772305487Sdavidcs		 * This is ONLY needed in implementations where
4773305487Sdavidcs		 * the capture buffer allocated is too small to capture
4774305487Sdavidcs		 * all of the required entries for a given capture mask.
4775305487Sdavidcs		 * We need to empty the buffer contents to a file
4776305487Sdavidcs		 * if possible, before processing the next entry
4777305487Sdavidcs		 * If the buff_full_flag is set, no further capture will happen
4778305487Sdavidcs		 * and all remaining non-control entries will be skipped.
4779305487Sdavidcs		 */
4780305487Sdavidcs		if (entry->hdr.entry_capture_size != 0) {
4781305487Sdavidcs			if ((buff_level + entry->hdr.entry_capture_size) >
4782305487Sdavidcs				dump_size) {
4783305487Sdavidcs				/*  Try to recover by emptying buffer to file */
4784305487Sdavidcs				entry->hdr.driver_flags |= QL_DBG_SKIPPED_FLAG;
4785305487Sdavidcs				entry = (ql_minidump_entry_t *) ((char *) entry
4786305487Sdavidcs						+ entry->hdr.entry_size);
4787305487Sdavidcs				continue;
4788305487Sdavidcs			}
4789305487Sdavidcs		}
4790305487Sdavidcs
4791305487Sdavidcs		/*
4792305487Sdavidcs		 * Decode the entry type and process it accordingly
4793305487Sdavidcs		 */
4794305487Sdavidcs
4795305487Sdavidcs		switch (entry->hdr.entry_type) {
4796305487Sdavidcs		case RDNOP:
4797305487Sdavidcs			break;
4798305487Sdavidcs
4799305487Sdavidcs		case RDEND:
4800305487Sdavidcs			if (sane_end == 0) {
4801305487Sdavidcs				end_cnt = e_cnt;
4802305487Sdavidcs			}
4803305487Sdavidcs			sane_end++;
4804305487Sdavidcs			break;
4805305487Sdavidcs
4806305487Sdavidcs		case RDCRB:
4807305487Sdavidcs			dbuff = dump_buff + buff_level;
4808305487Sdavidcs			esize = ql_rdcrb(ha, (void *)entry, (void *)dbuff);
4809305487Sdavidcs			ql_entry_err_chk(entry, esize);
4810305487Sdavidcs			buff_level += esize;
4811305487Sdavidcs			break;
4812305487Sdavidcs
4813305487Sdavidcs                case POLLRD:
4814305487Sdavidcs                        dbuff = dump_buff + buff_level;
4815305487Sdavidcs                        esize = ql_pollrd(ha, (void *)entry, (void *)dbuff);
4816305487Sdavidcs                        ql_entry_err_chk(entry, esize);
4817305487Sdavidcs                        buff_level += esize;
4818305487Sdavidcs                        break;
4819305487Sdavidcs
4820305487Sdavidcs                case POLLRDMWR:
4821305487Sdavidcs                        dbuff = dump_buff + buff_level;
4822305487Sdavidcs                        esize = ql_pollrd_modify_write(ha, (void *)entry,
4823305487Sdavidcs					(void *)dbuff);
4824305487Sdavidcs                        ql_entry_err_chk(entry, esize);
4825305487Sdavidcs                        buff_level += esize;
4826305487Sdavidcs                        break;
4827305487Sdavidcs
4828305487Sdavidcs		case L2ITG:
4829305487Sdavidcs		case L2DTG:
4830305487Sdavidcs		case L2DAT:
4831305487Sdavidcs		case L2INS:
4832305487Sdavidcs			dbuff = dump_buff + buff_level;
4833305487Sdavidcs			esize = ql_L2Cache(ha, (void *)entry, (void *)dbuff);
4834305487Sdavidcs			if (esize == -1) {
4835305487Sdavidcs				entry->hdr.driver_flags |= QL_DBG_SKIPPED_FLAG;
4836305487Sdavidcs			} else {
4837305487Sdavidcs				ql_entry_err_chk(entry, esize);
4838305487Sdavidcs				buff_level += esize;
4839305487Sdavidcs			}
4840305487Sdavidcs			break;
4841305487Sdavidcs
4842305487Sdavidcs		case L1DAT:
4843305487Sdavidcs		case L1INS:
4844305487Sdavidcs			dbuff = dump_buff + buff_level;
4845305487Sdavidcs			esize = ql_L1Cache(ha, (void *)entry, (void *)dbuff);
4846305487Sdavidcs			ql_entry_err_chk(entry, esize);
4847305487Sdavidcs			buff_level += esize;
4848305487Sdavidcs			break;
4849305487Sdavidcs
4850305487Sdavidcs		case RDOCM:
4851305487Sdavidcs			dbuff = dump_buff + buff_level;
4852305487Sdavidcs			esize = ql_rdocm(ha, (void *)entry, (void *)dbuff);
4853305487Sdavidcs			ql_entry_err_chk(entry, esize);
4854305487Sdavidcs			buff_level += esize;
4855305487Sdavidcs			break;
4856305487Sdavidcs
4857305487Sdavidcs		case RDMEM:
4858305487Sdavidcs			dbuff = dump_buff + buff_level;
4859305487Sdavidcs			esize = ql_rdmem(ha, (void *)entry, (void *)dbuff);
4860305487Sdavidcs			ql_entry_err_chk(entry, esize);
4861305487Sdavidcs			buff_level += esize;
4862305487Sdavidcs			break;
4863305487Sdavidcs
4864305487Sdavidcs		case BOARD:
4865305487Sdavidcs		case RDROM:
4866305487Sdavidcs			dbuff = dump_buff + buff_level;
4867305487Sdavidcs			esize = ql_rdrom(ha, (void *)entry, (void *)dbuff);
4868305487Sdavidcs			ql_entry_err_chk(entry, esize);
4869305487Sdavidcs			buff_level += esize;
4870305487Sdavidcs			break;
4871305487Sdavidcs
4872305487Sdavidcs		case RDMUX:
4873305487Sdavidcs			dbuff = dump_buff + buff_level;
4874305487Sdavidcs			esize = ql_rdmux(ha, (void *)entry, (void *)dbuff);
4875305487Sdavidcs			ql_entry_err_chk(entry, esize);
4876305487Sdavidcs			buff_level += esize;
4877305487Sdavidcs			break;
4878305487Sdavidcs
4879305487Sdavidcs                case RDMUX2:
4880305487Sdavidcs                        dbuff = dump_buff + buff_level;
4881305487Sdavidcs                        esize = ql_rdmux2(ha, (void *)entry, (void *)dbuff);
4882305487Sdavidcs                        ql_entry_err_chk(entry, esize);
4883305487Sdavidcs                        buff_level += esize;
4884305487Sdavidcs                        break;
4885305487Sdavidcs
4886305487Sdavidcs		case QUEUE:
4887305487Sdavidcs			dbuff = dump_buff + buff_level;
4888305487Sdavidcs			esize = ql_rdqueue(ha, (void *)entry, (void *)dbuff);
4889305487Sdavidcs			ql_entry_err_chk(entry, esize);
4890305487Sdavidcs			buff_level += esize;
4891305487Sdavidcs			break;
4892305487Sdavidcs
4893305487Sdavidcs		case CNTRL:
4894305487Sdavidcs			if ((rv = ql_cntrl(ha, template_hdr, (void *)entry))) {
4895305487Sdavidcs				entry->hdr.driver_flags |= QL_DBG_SKIPPED_FLAG;
4896305487Sdavidcs			}
4897305487Sdavidcs			break;
4898305487Sdavidcs		default:
4899305487Sdavidcs			entry->hdr.driver_flags |= QL_DBG_SKIPPED_FLAG;
4900305487Sdavidcs			break;
4901305487Sdavidcs		}
4902305487Sdavidcs		/*  next entry in the template */
4903305487Sdavidcs		entry = (ql_minidump_entry_t *) ((char *) entry
4904305487Sdavidcs						+ entry->hdr.entry_size);
4905305487Sdavidcs	}
4906305487Sdavidcs
4907305487Sdavidcs	if (!sane_start || (sane_end > 1)) {
4908305487Sdavidcs		device_printf(ha->pci_dev,
4909305487Sdavidcs			"\n%s: Template configuration error. Check Template\n",
4910305487Sdavidcs			__func__);
4911305487Sdavidcs	}
4912305487Sdavidcs
4913305487Sdavidcs	QL_DPRINT80(ha, (ha->pci_dev, "%s: Minidump num of entries = %d\n",
4914305487Sdavidcs		__func__, template_hdr->num_of_entries));
4915305487Sdavidcs
4916305487Sdavidcs	return 0;
4917305487Sdavidcs}
4918305487Sdavidcs
4919305487Sdavidcs/*
4920305487Sdavidcs * Read CRB operation.
4921305487Sdavidcs */
4922305487Sdavidcsstatic uint32_t
4923305487Sdavidcsql_rdcrb(qla_host_t *ha, ql_minidump_entry_rdcrb_t * crb_entry,
4924305487Sdavidcs	uint32_t * data_buff)
4925305487Sdavidcs{
4926305487Sdavidcs	int loop_cnt;
4927305487Sdavidcs	int ret;
4928305487Sdavidcs	uint32_t op_count, addr, stride, value = 0;
4929305487Sdavidcs
4930305487Sdavidcs	addr = crb_entry->addr;
4931305487Sdavidcs	op_count = crb_entry->op_count;
4932305487Sdavidcs	stride = crb_entry->addr_stride;
4933305487Sdavidcs
4934305487Sdavidcs	for (loop_cnt = 0; loop_cnt < op_count; loop_cnt++) {
4935305487Sdavidcs
4936305487Sdavidcs		ret = ql_rdwr_indreg32(ha, addr, &value, 1);
4937305487Sdavidcs
4938305487Sdavidcs		if (ret)
4939305487Sdavidcs			return (0);
4940305487Sdavidcs
4941305487Sdavidcs		*data_buff++ = addr;
4942305487Sdavidcs		*data_buff++ = value;
4943305487Sdavidcs		addr = addr + stride;
4944305487Sdavidcs	}
4945305487Sdavidcs
4946305487Sdavidcs	/*
4947305487Sdavidcs	 * for testing purpose we return amount of data written
4948305487Sdavidcs	 */
4949305487Sdavidcs	return (op_count * (2 * sizeof(uint32_t)));
4950305487Sdavidcs}
4951305487Sdavidcs
4952305487Sdavidcs/*
4953305487Sdavidcs * Handle L2 Cache.
4954305487Sdavidcs */
4955305487Sdavidcs
4956305487Sdavidcsstatic uint32_t
4957305487Sdavidcsql_L2Cache(qla_host_t *ha, ql_minidump_entry_cache_t *cacheEntry,
4958305487Sdavidcs	uint32_t * data_buff)
4959305487Sdavidcs{
4960305487Sdavidcs	int i, k;
4961305487Sdavidcs	int loop_cnt;
4962305487Sdavidcs	int ret;
4963305487Sdavidcs
4964305487Sdavidcs	uint32_t read_value;
4965305487Sdavidcs	uint32_t addr, read_addr, cntrl_addr, tag_reg_addr, cntl_value_w;
4966305487Sdavidcs	uint32_t tag_value, read_cnt;
4967305487Sdavidcs	volatile uint8_t cntl_value_r;
4968305487Sdavidcs	long timeout;
4969305487Sdavidcs	uint32_t data;
4970305487Sdavidcs
4971305487Sdavidcs	loop_cnt = cacheEntry->op_count;
4972305487Sdavidcs
4973305487Sdavidcs	read_addr = cacheEntry->read_addr;
4974305487Sdavidcs	cntrl_addr = cacheEntry->control_addr;
4975305487Sdavidcs	cntl_value_w = (uint32_t) cacheEntry->write_value;
4976305487Sdavidcs
4977305487Sdavidcs	tag_reg_addr = cacheEntry->tag_reg_addr;
4978305487Sdavidcs
4979305487Sdavidcs	tag_value = cacheEntry->init_tag_value;
4980305487Sdavidcs	read_cnt = cacheEntry->read_addr_cnt;
4981305487Sdavidcs
4982305487Sdavidcs	for (i = 0; i < loop_cnt; i++) {
4983305487Sdavidcs
4984305487Sdavidcs		ret = ql_rdwr_indreg32(ha, tag_reg_addr, &tag_value, 0);
4985305487Sdavidcs		if (ret)
4986305487Sdavidcs			return (0);
4987305487Sdavidcs
4988305487Sdavidcs		if (cacheEntry->write_value != 0) {
4989305487Sdavidcs
4990305487Sdavidcs			ret = ql_rdwr_indreg32(ha, cntrl_addr,
4991305487Sdavidcs					&cntl_value_w, 0);
4992305487Sdavidcs			if (ret)
4993305487Sdavidcs				return (0);
4994305487Sdavidcs		}
4995305487Sdavidcs
4996305487Sdavidcs		if (cacheEntry->poll_mask != 0) {
4997305487Sdavidcs
4998305487Sdavidcs			timeout = cacheEntry->poll_wait;
4999305487Sdavidcs
5000305487Sdavidcs			ret = ql_rdwr_indreg32(ha, cntrl_addr, &data, 1);
5001305487Sdavidcs			if (ret)
5002305487Sdavidcs				return (0);
5003305487Sdavidcs
5004305487Sdavidcs			cntl_value_r = (uint8_t)data;
5005305487Sdavidcs
5006305487Sdavidcs			while ((cntl_value_r & cacheEntry->poll_mask) != 0) {
5007305487Sdavidcs
5008305487Sdavidcs				if (timeout) {
5009305487Sdavidcs					qla_mdelay(__func__, 1);
5010305487Sdavidcs					timeout--;
5011305487Sdavidcs				} else
5012305487Sdavidcs					break;
5013305487Sdavidcs
5014305487Sdavidcs				ret = ql_rdwr_indreg32(ha, cntrl_addr,
5015305487Sdavidcs						&data, 1);
5016305487Sdavidcs				if (ret)
5017305487Sdavidcs					return (0);
5018305487Sdavidcs
5019305487Sdavidcs				cntl_value_r = (uint8_t)data;
5020305487Sdavidcs			}
5021305487Sdavidcs			if (!timeout) {
5022305487Sdavidcs				/* Report timeout error.
5023305487Sdavidcs				 * core dump capture failed
5024305487Sdavidcs				 * Skip remaining entries.
5025305487Sdavidcs				 * Write buffer out to file
5026305487Sdavidcs				 * Use driver specific fields in template header
5027305487Sdavidcs				 * to report this error.
5028305487Sdavidcs				 */
5029305487Sdavidcs				return (-1);
5030305487Sdavidcs			}
5031305487Sdavidcs		}
5032305487Sdavidcs
5033305487Sdavidcs		addr = read_addr;
5034305487Sdavidcs		for (k = 0; k < read_cnt; k++) {
5035305487Sdavidcs
5036305487Sdavidcs			ret = ql_rdwr_indreg32(ha, addr, &read_value, 1);
5037305487Sdavidcs			if (ret)
5038305487Sdavidcs				return (0);
5039305487Sdavidcs
5040305487Sdavidcs			*data_buff++ = read_value;
5041305487Sdavidcs			addr += cacheEntry->read_addr_stride;
5042305487Sdavidcs		}
5043305487Sdavidcs
5044305487Sdavidcs		tag_value += cacheEntry->tag_value_stride;
5045305487Sdavidcs	}
5046305487Sdavidcs
5047305487Sdavidcs	return (read_cnt * loop_cnt * sizeof(uint32_t));
5048305487Sdavidcs}
5049305487Sdavidcs
5050305487Sdavidcs/*
5051305487Sdavidcs * Handle L1 Cache.
5052305487Sdavidcs */
5053305487Sdavidcs
5054305487Sdavidcsstatic uint32_t
5055305487Sdavidcsql_L1Cache(qla_host_t *ha,
5056305487Sdavidcs	ql_minidump_entry_cache_t *cacheEntry,
5057305487Sdavidcs	uint32_t *data_buff)
5058305487Sdavidcs{
5059305487Sdavidcs	int ret;
5060305487Sdavidcs	int i, k;
5061305487Sdavidcs	int loop_cnt;
5062305487Sdavidcs
5063305487Sdavidcs	uint32_t read_value;
5064305487Sdavidcs	uint32_t addr, read_addr, cntrl_addr, tag_reg_addr;
5065305487Sdavidcs	uint32_t tag_value, read_cnt;
5066305487Sdavidcs	uint32_t cntl_value_w;
5067305487Sdavidcs
5068305487Sdavidcs	loop_cnt = cacheEntry->op_count;
5069305487Sdavidcs
5070305487Sdavidcs	read_addr = cacheEntry->read_addr;
5071305487Sdavidcs	cntrl_addr = cacheEntry->control_addr;
5072305487Sdavidcs	cntl_value_w = (uint32_t) cacheEntry->write_value;
5073305487Sdavidcs
5074305487Sdavidcs	tag_reg_addr = cacheEntry->tag_reg_addr;
5075305487Sdavidcs
5076305487Sdavidcs	tag_value = cacheEntry->init_tag_value;
5077305487Sdavidcs	read_cnt = cacheEntry->read_addr_cnt;
5078305487Sdavidcs
5079305487Sdavidcs	for (i = 0; i < loop_cnt; i++) {
5080305487Sdavidcs
5081305487Sdavidcs		ret = ql_rdwr_indreg32(ha, tag_reg_addr, &tag_value, 0);
5082305487Sdavidcs		if (ret)
5083305487Sdavidcs			return (0);
5084305487Sdavidcs
5085305487Sdavidcs		ret = ql_rdwr_indreg32(ha, cntrl_addr, &cntl_value_w, 0);
5086305487Sdavidcs		if (ret)
5087305487Sdavidcs			return (0);
5088305487Sdavidcs
5089305487Sdavidcs		addr = read_addr;
5090305487Sdavidcs		for (k = 0; k < read_cnt; k++) {
5091305487Sdavidcs
5092305487Sdavidcs			ret = ql_rdwr_indreg32(ha, addr, &read_value, 1);
5093305487Sdavidcs			if (ret)
5094305487Sdavidcs				return (0);
5095305487Sdavidcs
5096305487Sdavidcs			*data_buff++ = read_value;
5097305487Sdavidcs			addr += cacheEntry->read_addr_stride;
5098305487Sdavidcs		}
5099305487Sdavidcs
5100305487Sdavidcs		tag_value += cacheEntry->tag_value_stride;
5101305487Sdavidcs	}
5102305487Sdavidcs
5103305487Sdavidcs	return (read_cnt * loop_cnt * sizeof(uint32_t));
5104305487Sdavidcs}
5105305487Sdavidcs
5106305487Sdavidcs/*
5107305487Sdavidcs * Reading OCM memory
5108305487Sdavidcs */
5109305487Sdavidcs
5110305487Sdavidcsstatic uint32_t
5111305487Sdavidcsql_rdocm(qla_host_t *ha,
5112305487Sdavidcs	ql_minidump_entry_rdocm_t *ocmEntry,
5113305487Sdavidcs	uint32_t *data_buff)
5114305487Sdavidcs{
5115305487Sdavidcs	int i, loop_cnt;
5116305487Sdavidcs	volatile uint32_t addr;
5117305487Sdavidcs	volatile uint32_t value;
5118305487Sdavidcs
5119305487Sdavidcs	addr = ocmEntry->read_addr;
5120305487Sdavidcs	loop_cnt = ocmEntry->op_count;
5121305487Sdavidcs
5122305487Sdavidcs	for (i = 0; i < loop_cnt; i++) {
5123305487Sdavidcs		value = READ_REG32(ha, addr);
5124305487Sdavidcs		*data_buff++ = value;
5125305487Sdavidcs		addr += ocmEntry->read_addr_stride;
5126305487Sdavidcs	}
5127305487Sdavidcs	return (loop_cnt * sizeof(value));
5128305487Sdavidcs}
5129305487Sdavidcs
5130305487Sdavidcs/*
5131305487Sdavidcs * Read memory
5132305487Sdavidcs */
5133305487Sdavidcs
5134305487Sdavidcsstatic uint32_t
5135305487Sdavidcsql_rdmem(qla_host_t *ha,
5136305487Sdavidcs	ql_minidump_entry_rdmem_t *mem_entry,
5137305487Sdavidcs	uint32_t *data_buff)
5138305487Sdavidcs{
5139305487Sdavidcs	int ret;
5140305487Sdavidcs        int i, loop_cnt;
5141305487Sdavidcs        volatile uint32_t addr;
5142305487Sdavidcs	q80_offchip_mem_val_t val;
5143305487Sdavidcs
5144305487Sdavidcs        addr = mem_entry->read_addr;
5145305487Sdavidcs
5146305487Sdavidcs	/* size in bytes / 16 */
5147305487Sdavidcs        loop_cnt = mem_entry->read_data_size / (sizeof(uint32_t) * 4);
5148305487Sdavidcs
5149305487Sdavidcs        for (i = 0; i < loop_cnt; i++) {
5150305487Sdavidcs
5151305487Sdavidcs		ret = ql_rdwr_offchip_mem(ha, (addr & 0x0ffffffff), &val, 1);
5152305487Sdavidcs		if (ret)
5153305487Sdavidcs			return (0);
5154305487Sdavidcs
5155305487Sdavidcs                *data_buff++ = val.data_lo;
5156305487Sdavidcs                *data_buff++ = val.data_hi;
5157305487Sdavidcs                *data_buff++ = val.data_ulo;
5158305487Sdavidcs                *data_buff++ = val.data_uhi;
5159305487Sdavidcs
5160305487Sdavidcs                addr += (sizeof(uint32_t) * 4);
5161305487Sdavidcs        }
5162305487Sdavidcs
5163305487Sdavidcs        return (loop_cnt * (sizeof(uint32_t) * 4));
5164305487Sdavidcs}
5165305487Sdavidcs
5166305487Sdavidcs/*
5167305487Sdavidcs * Read Rom
5168305487Sdavidcs */
5169305487Sdavidcs
5170305487Sdavidcsstatic uint32_t
5171305487Sdavidcsql_rdrom(qla_host_t *ha,
5172305487Sdavidcs	ql_minidump_entry_rdrom_t *romEntry,
5173305487Sdavidcs	uint32_t *data_buff)
5174305487Sdavidcs{
5175305487Sdavidcs	int ret;
5176305487Sdavidcs	int i, loop_cnt;
5177305487Sdavidcs	uint32_t addr;
5178305487Sdavidcs	uint32_t value;
5179305487Sdavidcs
5180305487Sdavidcs	addr = romEntry->read_addr;
5181305487Sdavidcs	loop_cnt = romEntry->read_data_size; /* This is size in bytes */
5182305487Sdavidcs	loop_cnt /= sizeof(value);
5183305487Sdavidcs
5184305487Sdavidcs	for (i = 0; i < loop_cnt; i++) {
5185305487Sdavidcs
5186305487Sdavidcs		ret = ql_rd_flash32(ha, addr, &value);
5187305487Sdavidcs		if (ret)
5188305487Sdavidcs			return (0);
5189305487Sdavidcs
5190305487Sdavidcs		*data_buff++ = value;
5191305487Sdavidcs		addr += sizeof(value);
5192305487Sdavidcs	}
5193305487Sdavidcs
5194305487Sdavidcs	return (loop_cnt * sizeof(value));
5195305487Sdavidcs}
5196305487Sdavidcs
5197305487Sdavidcs/*
5198305487Sdavidcs * Read MUX data
5199305487Sdavidcs */
5200305487Sdavidcs
5201305487Sdavidcsstatic uint32_t
5202305487Sdavidcsql_rdmux(qla_host_t *ha,
5203305487Sdavidcs	ql_minidump_entry_mux_t *muxEntry,
5204305487Sdavidcs	uint32_t *data_buff)
5205305487Sdavidcs{
5206305487Sdavidcs	int ret;
5207305487Sdavidcs	int loop_cnt;
5208305487Sdavidcs	uint32_t read_value, sel_value;
5209305487Sdavidcs	uint32_t read_addr, select_addr;
5210305487Sdavidcs
5211305487Sdavidcs	select_addr = muxEntry->select_addr;
5212305487Sdavidcs	sel_value = muxEntry->select_value;
5213305487Sdavidcs	read_addr = muxEntry->read_addr;
5214305487Sdavidcs
5215305487Sdavidcs	for (loop_cnt = 0; loop_cnt < muxEntry->op_count; loop_cnt++) {
5216305487Sdavidcs
5217305487Sdavidcs		ret = ql_rdwr_indreg32(ha, select_addr, &sel_value, 0);
5218305487Sdavidcs		if (ret)
5219305487Sdavidcs			return (0);
5220305487Sdavidcs
5221305487Sdavidcs		ret = ql_rdwr_indreg32(ha, read_addr, &read_value, 1);
5222305487Sdavidcs		if (ret)
5223305487Sdavidcs			return (0);
5224305487Sdavidcs
5225305487Sdavidcs		*data_buff++ = sel_value;
5226305487Sdavidcs		*data_buff++ = read_value;
5227305487Sdavidcs
5228305487Sdavidcs		sel_value += muxEntry->select_value_stride;
5229305487Sdavidcs	}
5230305487Sdavidcs
5231305487Sdavidcs	return (loop_cnt * (2 * sizeof(uint32_t)));
5232305487Sdavidcs}
5233305487Sdavidcs
5234305487Sdavidcsstatic uint32_t
5235305487Sdavidcsql_rdmux2(qla_host_t *ha,
5236305487Sdavidcs	ql_minidump_entry_mux2_t *muxEntry,
5237305487Sdavidcs	uint32_t *data_buff)
5238305487Sdavidcs{
5239305487Sdavidcs	int ret;
5240305487Sdavidcs        int loop_cnt;
5241305487Sdavidcs
5242305487Sdavidcs        uint32_t select_addr_1, select_addr_2;
5243305487Sdavidcs        uint32_t select_value_1, select_value_2;
5244305487Sdavidcs        uint32_t select_value_count, select_value_mask;
5245305487Sdavidcs        uint32_t read_addr, read_value;
5246305487Sdavidcs
5247305487Sdavidcs        select_addr_1 = muxEntry->select_addr_1;
5248305487Sdavidcs        select_addr_2 = muxEntry->select_addr_2;
5249305487Sdavidcs        select_value_1 = muxEntry->select_value_1;
5250305487Sdavidcs        select_value_2 = muxEntry->select_value_2;
5251305487Sdavidcs        select_value_count = muxEntry->select_value_count;
5252305487Sdavidcs        select_value_mask  = muxEntry->select_value_mask;
5253305487Sdavidcs
5254305487Sdavidcs        read_addr = muxEntry->read_addr;
5255305487Sdavidcs
5256305487Sdavidcs        for (loop_cnt = 0; loop_cnt < muxEntry->select_value_count;
5257305487Sdavidcs		loop_cnt++) {
5258305487Sdavidcs
5259305487Sdavidcs                uint32_t temp_sel_val;
5260305487Sdavidcs
5261305487Sdavidcs		ret = ql_rdwr_indreg32(ha, select_addr_1, &select_value_1, 0);
5262305487Sdavidcs		if (ret)
5263305487Sdavidcs			return (0);
5264305487Sdavidcs
5265305487Sdavidcs                temp_sel_val = select_value_1 & select_value_mask;
5266305487Sdavidcs
5267305487Sdavidcs		ret = ql_rdwr_indreg32(ha, select_addr_2, &temp_sel_val, 0);
5268305487Sdavidcs		if (ret)
5269305487Sdavidcs			return (0);
5270305487Sdavidcs
5271305487Sdavidcs		ret = ql_rdwr_indreg32(ha, read_addr, &read_value, 1);
5272305487Sdavidcs		if (ret)
5273305487Sdavidcs			return (0);
5274305487Sdavidcs
5275305487Sdavidcs                *data_buff++ = temp_sel_val;
5276305487Sdavidcs                *data_buff++ = read_value;
5277305487Sdavidcs
5278305487Sdavidcs		ret = ql_rdwr_indreg32(ha, select_addr_1, &select_value_2, 0);
5279305487Sdavidcs		if (ret)
5280305487Sdavidcs			return (0);
5281305487Sdavidcs
5282305487Sdavidcs                temp_sel_val = select_value_2 & select_value_mask;
5283305487Sdavidcs
5284305487Sdavidcs		ret = ql_rdwr_indreg32(ha, select_addr_2, &temp_sel_val, 0);
5285305487Sdavidcs		if (ret)
5286305487Sdavidcs			return (0);
5287305487Sdavidcs
5288305487Sdavidcs		ret = ql_rdwr_indreg32(ha, read_addr, &read_value, 1);
5289305487Sdavidcs		if (ret)
5290305487Sdavidcs			return (0);
5291305487Sdavidcs
5292305487Sdavidcs                *data_buff++ = temp_sel_val;
5293305487Sdavidcs                *data_buff++ = read_value;
5294305487Sdavidcs
5295305487Sdavidcs                select_value_1 += muxEntry->select_value_stride;
5296305487Sdavidcs                select_value_2 += muxEntry->select_value_stride;
5297305487Sdavidcs        }
5298305487Sdavidcs
5299305487Sdavidcs        return (loop_cnt * (4 * sizeof(uint32_t)));
5300305487Sdavidcs}
5301305487Sdavidcs
5302305487Sdavidcs/*
5303305487Sdavidcs * Handling Queue State Reads.
5304305487Sdavidcs */
5305305487Sdavidcs
5306305487Sdavidcsstatic uint32_t
5307305487Sdavidcsql_rdqueue(qla_host_t *ha,
5308305487Sdavidcs	ql_minidump_entry_queue_t *queueEntry,
5309305487Sdavidcs	uint32_t *data_buff)
5310305487Sdavidcs{
5311305487Sdavidcs	int ret;
5312305487Sdavidcs	int loop_cnt, k;
5313305487Sdavidcs	uint32_t read_value;
5314305487Sdavidcs	uint32_t read_addr, read_stride, select_addr;
5315305487Sdavidcs	uint32_t queue_id, read_cnt;
5316305487Sdavidcs
5317305487Sdavidcs	read_cnt = queueEntry->read_addr_cnt;
5318305487Sdavidcs	read_stride = queueEntry->read_addr_stride;
5319305487Sdavidcs	select_addr = queueEntry->select_addr;
5320305487Sdavidcs
5321305487Sdavidcs	for (loop_cnt = 0, queue_id = 0; loop_cnt < queueEntry->op_count;
5322305487Sdavidcs		loop_cnt++) {
5323305487Sdavidcs
5324305487Sdavidcs		ret = ql_rdwr_indreg32(ha, select_addr, &queue_id, 0);
5325305487Sdavidcs		if (ret)
5326305487Sdavidcs			return (0);
5327305487Sdavidcs
5328305487Sdavidcs		read_addr = queueEntry->read_addr;
5329305487Sdavidcs
5330305487Sdavidcs		for (k = 0; k < read_cnt; k++) {
5331305487Sdavidcs
5332305487Sdavidcs			ret = ql_rdwr_indreg32(ha, read_addr, &read_value, 1);
5333305487Sdavidcs			if (ret)
5334305487Sdavidcs				return (0);
5335305487Sdavidcs
5336305487Sdavidcs			*data_buff++ = read_value;
5337305487Sdavidcs			read_addr += read_stride;
5338305487Sdavidcs		}
5339305487Sdavidcs
5340305487Sdavidcs		queue_id += queueEntry->queue_id_stride;
5341305487Sdavidcs	}
5342305487Sdavidcs
5343305487Sdavidcs	return (loop_cnt * (read_cnt * sizeof(uint32_t)));
5344305487Sdavidcs}
5345305487Sdavidcs
5346305487Sdavidcs/*
5347305487Sdavidcs * Handling control entries.
5348305487Sdavidcs */
5349305487Sdavidcs
5350305487Sdavidcsstatic uint32_t
5351305487Sdavidcsql_cntrl(qla_host_t *ha,
5352305487Sdavidcs	ql_minidump_template_hdr_t *template_hdr,
5353305487Sdavidcs	ql_minidump_entry_cntrl_t *crbEntry)
5354305487Sdavidcs{
5355305487Sdavidcs	int ret;
5356305487Sdavidcs	int count;
5357305487Sdavidcs	uint32_t opcode, read_value, addr, entry_addr;
5358305487Sdavidcs	long timeout;
5359305487Sdavidcs
5360305487Sdavidcs	entry_addr = crbEntry->addr;
5361305487Sdavidcs
5362305487Sdavidcs	for (count = 0; count < crbEntry->op_count; count++) {
5363305487Sdavidcs		opcode = crbEntry->opcode;
5364305487Sdavidcs
5365305487Sdavidcs		if (opcode & QL_DBG_OPCODE_WR) {
5366305487Sdavidcs
5367305487Sdavidcs                	ret = ql_rdwr_indreg32(ha, entry_addr,
5368305487Sdavidcs					&crbEntry->value_1, 0);
5369305487Sdavidcs			if (ret)
5370305487Sdavidcs				return (0);
5371305487Sdavidcs
5372305487Sdavidcs			opcode &= ~QL_DBG_OPCODE_WR;
5373305487Sdavidcs		}
5374305487Sdavidcs
5375305487Sdavidcs		if (opcode & QL_DBG_OPCODE_RW) {
5376305487Sdavidcs
5377305487Sdavidcs                	ret = ql_rdwr_indreg32(ha, entry_addr, &read_value, 1);
5378305487Sdavidcs			if (ret)
5379305487Sdavidcs				return (0);
5380305487Sdavidcs
5381305487Sdavidcs                	ret = ql_rdwr_indreg32(ha, entry_addr, &read_value, 0);
5382305487Sdavidcs			if (ret)
5383305487Sdavidcs				return (0);
5384305487Sdavidcs
5385305487Sdavidcs			opcode &= ~QL_DBG_OPCODE_RW;
5386305487Sdavidcs		}
5387305487Sdavidcs
5388305487Sdavidcs		if (opcode & QL_DBG_OPCODE_AND) {
5389305487Sdavidcs
5390305487Sdavidcs                	ret = ql_rdwr_indreg32(ha, entry_addr, &read_value, 1);
5391305487Sdavidcs			if (ret)
5392305487Sdavidcs				return (0);
5393305487Sdavidcs
5394305487Sdavidcs			read_value &= crbEntry->value_2;
5395305487Sdavidcs			opcode &= ~QL_DBG_OPCODE_AND;
5396305487Sdavidcs
5397305487Sdavidcs			if (opcode & QL_DBG_OPCODE_OR) {
5398305487Sdavidcs				read_value |= crbEntry->value_3;
5399305487Sdavidcs				opcode &= ~QL_DBG_OPCODE_OR;
5400305487Sdavidcs			}
5401305487Sdavidcs
5402305487Sdavidcs                	ret = ql_rdwr_indreg32(ha, entry_addr, &read_value, 0);
5403305487Sdavidcs			if (ret)
5404305487Sdavidcs				return (0);
5405305487Sdavidcs		}
5406305487Sdavidcs
5407305487Sdavidcs		if (opcode & QL_DBG_OPCODE_OR) {
5408305487Sdavidcs
5409305487Sdavidcs                	ret = ql_rdwr_indreg32(ha, entry_addr, &read_value, 1);
5410305487Sdavidcs			if (ret)
5411305487Sdavidcs				return (0);
5412305487Sdavidcs
5413305487Sdavidcs			read_value |= crbEntry->value_3;
5414305487Sdavidcs
5415305487Sdavidcs                	ret = ql_rdwr_indreg32(ha, entry_addr, &read_value, 0);
5416305487Sdavidcs			if (ret)
5417305487Sdavidcs				return (0);
5418305487Sdavidcs
5419305487Sdavidcs			opcode &= ~QL_DBG_OPCODE_OR;
5420305487Sdavidcs		}
5421305487Sdavidcs
5422305487Sdavidcs		if (opcode & QL_DBG_OPCODE_POLL) {
5423305487Sdavidcs
5424305487Sdavidcs			opcode &= ~QL_DBG_OPCODE_POLL;
5425305487Sdavidcs			timeout = crbEntry->poll_timeout;
5426305487Sdavidcs			addr = entry_addr;
5427305487Sdavidcs
5428305487Sdavidcs                	ret = ql_rdwr_indreg32(ha, addr, &read_value, 1);
5429305487Sdavidcs			if (ret)
5430305487Sdavidcs				return (0);
5431305487Sdavidcs
5432305487Sdavidcs			while ((read_value & crbEntry->value_2)
5433305487Sdavidcs				!= crbEntry->value_1) {
5434305487Sdavidcs
5435305487Sdavidcs				if (timeout) {
5436305487Sdavidcs					qla_mdelay(__func__, 1);
5437305487Sdavidcs					timeout--;
5438305487Sdavidcs				} else
5439305487Sdavidcs					break;
5440305487Sdavidcs
5441305487Sdavidcs                		ret = ql_rdwr_indreg32(ha, addr,
5442305487Sdavidcs						&read_value, 1);
5443305487Sdavidcs				if (ret)
5444305487Sdavidcs					return (0);
5445305487Sdavidcs			}
5446305487Sdavidcs
5447305487Sdavidcs			if (!timeout) {
5448305487Sdavidcs				/*
5449305487Sdavidcs				 * Report timeout error.
5450305487Sdavidcs				 * core dump capture failed
5451305487Sdavidcs				 * Skip remaining entries.
5452305487Sdavidcs				 * Write buffer out to file
5453305487Sdavidcs				 * Use driver specific fields in template header
5454305487Sdavidcs				 * to report this error.
5455305487Sdavidcs				 */
5456305487Sdavidcs				return (-1);
5457305487Sdavidcs			}
5458305487Sdavidcs		}
5459305487Sdavidcs
5460305487Sdavidcs		if (opcode & QL_DBG_OPCODE_RDSTATE) {
5461305487Sdavidcs			/*
5462305487Sdavidcs			 * decide which address to use.
5463305487Sdavidcs			 */
5464305487Sdavidcs			if (crbEntry->state_index_a) {
5465305487Sdavidcs				addr = template_hdr->saved_state_array[
5466305487Sdavidcs						crbEntry-> state_index_a];
5467305487Sdavidcs			} else {
5468305487Sdavidcs				addr = entry_addr;
5469305487Sdavidcs			}
5470305487Sdavidcs
5471305487Sdavidcs                	ret = ql_rdwr_indreg32(ha, addr, &read_value, 1);
5472305487Sdavidcs			if (ret)
5473305487Sdavidcs				return (0);
5474305487Sdavidcs
5475305487Sdavidcs			template_hdr->saved_state_array[crbEntry->state_index_v]
5476305487Sdavidcs					= read_value;
5477305487Sdavidcs			opcode &= ~QL_DBG_OPCODE_RDSTATE;
5478305487Sdavidcs		}
5479305487Sdavidcs
5480305487Sdavidcs		if (opcode & QL_DBG_OPCODE_WRSTATE) {
5481305487Sdavidcs			/*
5482305487Sdavidcs			 * decide which value to use.
5483305487Sdavidcs			 */
5484305487Sdavidcs			if (crbEntry->state_index_v) {
5485305487Sdavidcs				read_value = template_hdr->saved_state_array[
5486305487Sdavidcs						crbEntry->state_index_v];
5487305487Sdavidcs			} else {
5488305487Sdavidcs				read_value = crbEntry->value_1;
5489305487Sdavidcs			}
5490305487Sdavidcs			/*
5491305487Sdavidcs			 * decide which address to use.
5492305487Sdavidcs			 */
5493305487Sdavidcs			if (crbEntry->state_index_a) {
5494305487Sdavidcs				addr = template_hdr->saved_state_array[
5495305487Sdavidcs						crbEntry-> state_index_a];
5496305487Sdavidcs			} else {
5497305487Sdavidcs				addr = entry_addr;
5498305487Sdavidcs			}
5499305487Sdavidcs
5500305487Sdavidcs                	ret = ql_rdwr_indreg32(ha, addr, &read_value, 0);
5501305487Sdavidcs			if (ret)
5502305487Sdavidcs				return (0);
5503305487Sdavidcs
5504305487Sdavidcs			opcode &= ~QL_DBG_OPCODE_WRSTATE;
5505305487Sdavidcs		}
5506305487Sdavidcs
5507305487Sdavidcs		if (opcode & QL_DBG_OPCODE_MDSTATE) {
5508305487Sdavidcs			/*  Read value from saved state using index */
5509305487Sdavidcs			read_value = template_hdr->saved_state_array[
5510305487Sdavidcs						crbEntry->state_index_v];
5511305487Sdavidcs
5512305487Sdavidcs			read_value <<= crbEntry->shl; /*Shift left operation */
5513305487Sdavidcs			read_value >>= crbEntry->shr; /*Shift right operation */
5514305487Sdavidcs
5515305487Sdavidcs			if (crbEntry->value_2) {
5516305487Sdavidcs				/* check if AND mask is provided */
5517305487Sdavidcs				read_value &= crbEntry->value_2;
5518305487Sdavidcs			}
5519305487Sdavidcs
5520305487Sdavidcs			read_value |= crbEntry->value_3; /* OR operation */
5521305487Sdavidcs			read_value += crbEntry->value_1; /* increment op */
5522305487Sdavidcs
5523305487Sdavidcs			/* Write value back to state area. */
5524305487Sdavidcs
5525305487Sdavidcs			template_hdr->saved_state_array[crbEntry->state_index_v]
5526305487Sdavidcs					= read_value;
5527305487Sdavidcs			opcode &= ~QL_DBG_OPCODE_MDSTATE;
5528305487Sdavidcs		}
5529305487Sdavidcs
5530305487Sdavidcs		entry_addr += crbEntry->addr_stride;
5531305487Sdavidcs	}
5532305487Sdavidcs
5533305487Sdavidcs	return (0);
5534305487Sdavidcs}
5535305487Sdavidcs
5536305487Sdavidcs/*
5537305487Sdavidcs * Handling rd poll entry.
5538305487Sdavidcs */
5539305487Sdavidcs
5540305487Sdavidcsstatic uint32_t
5541305487Sdavidcsql_pollrd(qla_host_t *ha, ql_minidump_entry_pollrd_t *entry,
5542305487Sdavidcs	uint32_t *data_buff)
5543305487Sdavidcs{
5544305487Sdavidcs        int ret;
5545305487Sdavidcs        int loop_cnt;
5546305487Sdavidcs        uint32_t op_count, select_addr, select_value_stride, select_value;
5547305487Sdavidcs        uint32_t read_addr, poll, mask, data_size, data;
5548305487Sdavidcs        uint32_t wait_count = 0;
5549305487Sdavidcs
5550305487Sdavidcs        select_addr            = entry->select_addr;
5551305487Sdavidcs        read_addr              = entry->read_addr;
5552305487Sdavidcs        select_value           = entry->select_value;
5553305487Sdavidcs        select_value_stride    = entry->select_value_stride;
5554305487Sdavidcs        op_count               = entry->op_count;
5555305487Sdavidcs        poll                   = entry->poll;
5556305487Sdavidcs        mask                   = entry->mask;
5557305487Sdavidcs        data_size              = entry->data_size;
5558305487Sdavidcs
5559305487Sdavidcs        for (loop_cnt = 0; loop_cnt < op_count; loop_cnt++) {
5560305487Sdavidcs
5561305487Sdavidcs                ret = ql_rdwr_indreg32(ha, select_addr, &select_value, 0);
5562305487Sdavidcs		if (ret)
5563305487Sdavidcs			return (0);
5564305487Sdavidcs
5565305487Sdavidcs                wait_count = 0;
5566305487Sdavidcs
5567305487Sdavidcs                while (wait_count < poll) {
5568305487Sdavidcs
5569305487Sdavidcs                        uint32_t temp;
5570305487Sdavidcs
5571305487Sdavidcs			ret = ql_rdwr_indreg32(ha, select_addr, &temp, 1);
5572305487Sdavidcs			if (ret)
5573305487Sdavidcs				return (0);
5574305487Sdavidcs
5575305487Sdavidcs                        if ( (temp & mask) != 0 ) {
5576305487Sdavidcs                                break;
5577305487Sdavidcs                        }
5578305487Sdavidcs                        wait_count++;
5579305487Sdavidcs                }
5580305487Sdavidcs
5581305487Sdavidcs                if (wait_count == poll) {
5582305487Sdavidcs                        device_printf(ha->pci_dev,
5583305487Sdavidcs				"%s: Error in processing entry\n", __func__);
5584305487Sdavidcs                        device_printf(ha->pci_dev,
5585305487Sdavidcs				"%s: wait_count <0x%x> poll <0x%x>\n",
5586305487Sdavidcs				__func__, wait_count, poll);
5587305487Sdavidcs                        return 0;
5588305487Sdavidcs                }
5589305487Sdavidcs
5590305487Sdavidcs		ret = ql_rdwr_indreg32(ha, read_addr, &data, 1);
5591305487Sdavidcs		if (ret)
5592305487Sdavidcs			return (0);
5593305487Sdavidcs
5594305487Sdavidcs                *data_buff++ = select_value;
5595305487Sdavidcs                *data_buff++ = data;
5596305487Sdavidcs                select_value = select_value + select_value_stride;
5597305487Sdavidcs        }
5598305487Sdavidcs
5599305487Sdavidcs        /*
5600305487Sdavidcs         * for testing purpose we return amount of data written
5601305487Sdavidcs         */
5602305487Sdavidcs        return (loop_cnt * (2 * sizeof(uint32_t)));
5603305487Sdavidcs}
5604305487Sdavidcs
5605305487Sdavidcs
5606305487Sdavidcs/*
5607305487Sdavidcs * Handling rd modify write poll entry.
5608305487Sdavidcs */
5609305487Sdavidcs
5610305487Sdavidcsstatic uint32_t
5611305487Sdavidcsql_pollrd_modify_write(qla_host_t *ha,
5612305487Sdavidcs	ql_minidump_entry_rd_modify_wr_with_poll_t *entry,
5613305487Sdavidcs	uint32_t *data_buff)
5614305487Sdavidcs{
5615305487Sdavidcs	int ret;
5616305487Sdavidcs        uint32_t addr_1, addr_2, value_1, value_2, data;
5617305487Sdavidcs        uint32_t poll, mask, data_size, modify_mask;
5618305487Sdavidcs        uint32_t wait_count = 0;
5619305487Sdavidcs
5620305487Sdavidcs        addr_1		= entry->addr_1;
5621305487Sdavidcs        addr_2		= entry->addr_2;
5622305487Sdavidcs        value_1		= entry->value_1;
5623305487Sdavidcs        value_2		= entry->value_2;
5624305487Sdavidcs
5625305487Sdavidcs        poll		= entry->poll;
5626305487Sdavidcs        mask		= entry->mask;
5627305487Sdavidcs        modify_mask	= entry->modify_mask;
5628305487Sdavidcs        data_size	= entry->data_size;
5629305487Sdavidcs
5630305487Sdavidcs
5631305487Sdavidcs	ret = ql_rdwr_indreg32(ha, addr_1, &value_1, 0);
5632305487Sdavidcs	if (ret)
5633305487Sdavidcs		return (0);
5634305487Sdavidcs
5635305487Sdavidcs        wait_count = 0;
5636305487Sdavidcs        while (wait_count < poll) {
5637305487Sdavidcs
5638305487Sdavidcs		uint32_t temp;
5639305487Sdavidcs
5640305487Sdavidcs		ret = ql_rdwr_indreg32(ha, addr_1, &temp, 1);
5641305487Sdavidcs		if (ret)
5642305487Sdavidcs			return (0);
5643305487Sdavidcs
5644305487Sdavidcs                if ( (temp & mask) != 0 ) {
5645305487Sdavidcs                        break;
5646305487Sdavidcs                }
5647305487Sdavidcs                wait_count++;
5648305487Sdavidcs        }
5649305487Sdavidcs
5650305487Sdavidcs        if (wait_count == poll) {
5651305487Sdavidcs                device_printf(ha->pci_dev, "%s Error in processing entry\n",
5652305487Sdavidcs			__func__);
5653305487Sdavidcs        } else {
5654305487Sdavidcs
5655305487Sdavidcs		ret = ql_rdwr_indreg32(ha, addr_2, &data, 1);
5656305487Sdavidcs		if (ret)
5657305487Sdavidcs			return (0);
5658305487Sdavidcs
5659305487Sdavidcs                data = (data & modify_mask);
5660305487Sdavidcs
5661305487Sdavidcs		ret = ql_rdwr_indreg32(ha, addr_2, &data, 0);
5662305487Sdavidcs		if (ret)
5663305487Sdavidcs			return (0);
5664305487Sdavidcs
5665305487Sdavidcs		ret = ql_rdwr_indreg32(ha, addr_1, &value_2, 0);
5666305487Sdavidcs		if (ret)
5667305487Sdavidcs			return (0);
5668305487Sdavidcs
5669305487Sdavidcs                /* Poll again */
5670305487Sdavidcs                wait_count = 0;
5671305487Sdavidcs                while (wait_count < poll) {
5672305487Sdavidcs
5673305487Sdavidcs                        uint32_t temp;
5674305487Sdavidcs
5675305487Sdavidcs			ret = ql_rdwr_indreg32(ha, addr_1, &temp, 1);
5676305487Sdavidcs			if (ret)
5677305487Sdavidcs				return (0);
5678305487Sdavidcs
5679305487Sdavidcs                        if ( (temp & mask) != 0 ) {
5680305487Sdavidcs                                break;
5681305487Sdavidcs                        }
5682305487Sdavidcs                        wait_count++;
5683305487Sdavidcs                }
5684305487Sdavidcs                *data_buff++ = addr_2;
5685305487Sdavidcs                *data_buff++ = data;
5686305487Sdavidcs        }
5687305487Sdavidcs
5688305487Sdavidcs        /*
5689305487Sdavidcs         * for testing purpose we return amount of data written
5690305487Sdavidcs         */
5691305487Sdavidcs        return (2 * sizeof(uint32_t));
5692305487Sdavidcs}
5693305487Sdavidcs
5694305487Sdavidcs
5695